Update wehago matching logic and exclude reports
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sqlite3
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from runtime_config import DB_PATH
|
||||
|
||||
|
||||
DEFAULT_STATUSES = (
|
||||
"voucher_matched",
|
||||
"voucher_unmatched",
|
||||
"voucher_recheck",
|
||||
"voucher_excepted",
|
||||
)
|
||||
|
||||
|
||||
def latest_signature(conn: sqlite3.Connection, start_year: int, end_year: int) -> str:
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT signature
|
||||
FROM wehago_compare_query_groups
|
||||
WHERE start_year = ?
|
||||
AND end_year = ?
|
||||
GROUP BY signature
|
||||
ORDER BY MAX(updated_at) DESC
|
||||
LIMIT 1
|
||||
""",
|
||||
(start_year, end_year),
|
||||
).fetchone()
|
||||
return str(row[0] or "") if row else ""
|
||||
|
||||
|
||||
def status_summary(
|
||||
conn: sqlite3.Connection,
|
||||
start_year: int,
|
||||
end_year: int,
|
||||
signature: str,
|
||||
status_key: str,
|
||||
) -> dict[str, int | float]:
|
||||
row = conn.execute(
|
||||
"""
|
||||
WITH per_group AS (
|
||||
SELECT
|
||||
g.group_index,
|
||||
COUNT(DISTINCT CASE
|
||||
WHEN COALESCE(r.ledger_account_name, '') <> ''
|
||||
OR COALESCE(r.ledger_desc, '') <> ''
|
||||
OR ABS(COALESCE(r.ledger_debit, 0)) >= 0.5
|
||||
OR ABS(COALESCE(r.ledger_credit, 0)) >= 0.5
|
||||
THEN COALESCE(r.ledger_date, '') || '|' || COALESCE(r.voucher_no, '')
|
||||
END) AS wehago_keys,
|
||||
COUNT(DISTINCT CASE
|
||||
WHEN COALESCE(r.voucher_account_name, '') <> ''
|
||||
OR COALESCE(r.voucher_desc, '') <> ''
|
||||
OR ABS(COALESCE(r.voucher_debit, 0)) >= 0.5
|
||||
OR ABS(COALESCE(r.voucher_credit, 0)) >= 0.5
|
||||
THEN COALESCE(r.draft_no, '')
|
||||
END) AS erp_drafts,
|
||||
COUNT(*) AS row_count
|
||||
FROM wehago_compare_query_groups g
|
||||
LEFT JOIN wehago_compare_query_rows r
|
||||
ON r.start_year = g.start_year
|
||||
AND r.end_year = g.end_year
|
||||
AND r.signature = g.signature
|
||||
AND r.status_key = g.status_key
|
||||
AND r.group_index = g.group_index
|
||||
WHERE g.start_year = ?
|
||||
AND g.end_year = ?
|
||||
AND g.signature = ?
|
||||
AND g.status_key = ?
|
||||
GROUP BY g.group_index
|
||||
)
|
||||
SELECT
|
||||
COUNT(*) AS groups,
|
||||
SUM(CASE WHEN wehago_keys > 1 THEN 1 ELSE 0 END) AS mixed_wehago_groups,
|
||||
SUM(CASE WHEN erp_drafts > 1 THEN 1 ELSE 0 END) AS multi_erp_groups,
|
||||
COALESCE(MAX(wehago_keys), 0) AS max_wehago_keys,
|
||||
COALESCE(MAX(erp_drafts), 0) AS max_erp_drafts,
|
||||
COALESCE(MAX(row_count), 0) AS max_rows,
|
||||
COALESCE(AVG(row_count), 0) AS avg_rows
|
||||
FROM per_group
|
||||
""",
|
||||
(start_year, end_year, signature, status_key),
|
||||
).fetchone()
|
||||
return {
|
||||
"groups": int(row["groups"] or 0),
|
||||
"mixed_wehago_groups": int(row["mixed_wehago_groups"] or 0),
|
||||
"multi_erp_groups": int(row["multi_erp_groups"] or 0),
|
||||
"max_wehago_keys": int(row["max_wehago_keys"] or 0),
|
||||
"max_erp_drafts": int(row["max_erp_drafts"] or 0),
|
||||
"max_rows": int(row["max_rows"] or 0),
|
||||
"avg_rows": round(float(row["avg_rows"] or 0), 2),
|
||||
}
|
||||
|
||||
|
||||
def sample_mixed_groups(
|
||||
conn: sqlite3.Connection,
|
||||
start_year: int,
|
||||
end_year: int,
|
||||
signature: str,
|
||||
status_key: str,
|
||||
limit: int,
|
||||
) -> list[dict[str, object]]:
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
g.group_index,
|
||||
g.ledger_date,
|
||||
g.voucher_no,
|
||||
COUNT(DISTINCT CASE
|
||||
WHEN COALESCE(r.ledger_account_name, '') <> ''
|
||||
OR COALESCE(r.ledger_desc, '') <> ''
|
||||
OR ABS(COALESCE(r.ledger_debit, 0)) >= 0.5
|
||||
OR ABS(COALESCE(r.ledger_credit, 0)) >= 0.5
|
||||
THEN COALESCE(r.ledger_date, '') || '|' || COALESCE(r.voucher_no, '')
|
||||
END) AS wehago_keys,
|
||||
COUNT(*) AS row_count
|
||||
FROM wehago_compare_query_groups g
|
||||
JOIN wehago_compare_query_rows r
|
||||
ON r.start_year = g.start_year
|
||||
AND r.end_year = g.end_year
|
||||
AND r.signature = g.signature
|
||||
AND r.status_key = g.status_key
|
||||
AND r.group_index = g.group_index
|
||||
WHERE g.start_year = ?
|
||||
AND g.end_year = ?
|
||||
AND g.signature = ?
|
||||
AND g.status_key = ?
|
||||
GROUP BY g.group_index
|
||||
HAVING wehago_keys > 1
|
||||
ORDER BY wehago_keys DESC, row_count DESC, g.group_index ASC
|
||||
LIMIT ?
|
||||
""",
|
||||
(start_year, end_year, signature, status_key, limit),
|
||||
).fetchall()
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Validate WEHAGO voucher projection anchoring.")
|
||||
parser.add_argument("--start-year", type=int, default=2025)
|
||||
parser.add_argument("--end-year", type=int, default=2025)
|
||||
parser.add_argument("--signature", default="")
|
||||
parser.add_argument("--sample", type=int, default=5)
|
||||
parser.add_argument("--statuses", nargs="*", default=list(DEFAULT_STATUSES))
|
||||
args = parser.parse_args()
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.row_factory = sqlite3.Row
|
||||
signature = args.signature or latest_signature(conn, args.start_year, args.end_year)
|
||||
if not signature:
|
||||
raise SystemExit("No query projection signature found.")
|
||||
print({"db": str(DB_PATH), "signature": signature})
|
||||
for status_key in args.statuses:
|
||||
summary = status_summary(conn, args.start_year, args.end_year, signature, status_key)
|
||||
print({status_key: summary})
|
||||
samples = sample_mixed_groups(
|
||||
conn,
|
||||
args.start_year,
|
||||
args.end_year,
|
||||
signature,
|
||||
status_key,
|
||||
args.sample,
|
||||
)
|
||||
if samples:
|
||||
print({"mixed_samples": status_key, "rows": samples})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user