#!/usr/bin/env python3 """ Verifică regula adrese PJ/PF pe comenzile importate din SQLite. Logica: PF (cod_fiscal_gomag IS NULL): id_adresa_facturare = id_adresa_livrare PJ (cod_fiscal_gomag IS NOT NULL): adresa_facturare_roa se potriveste cu GoMag billing (nu cu GoMag shipping) Rulare: python3 scripts/verify_address_rules.py python3 scripts/verify_address_rules.py --days 7 # ultimele 7 zile python3 scripts/verify_address_rules.py --all # toate comenzile python3 scripts/verify_address_rules.py --status IMPORTED """ import argparse import json import os import sqlite3 import sys from pathlib import Path # Add api/ to path for app imports _repo_root = Path(__file__).resolve().parent.parent sys.path.insert(0, str(_repo_root / "api")) from dotenv import load_dotenv load_dotenv(_repo_root / "api" / ".env") from app.services.sync_service import _addr_match def main(): parser = argparse.ArgumentParser(description="Verifică regula adrese PJ/PF în SQLite") parser.add_argument("--days", type=int, default=30, help="Număr de zile în urmă (default: 30)") parser.add_argument("--all", action="store_true", help="Toate comenzile, indiferent de dată") parser.add_argument("--status", default=None, help="Filtrează după status (ex: IMPORTED)") args = parser.parse_args() _raw_path = os.environ.get("SQLITE_DB_PATH", "data/import.db") db_path = _raw_path if os.path.isabs(_raw_path) else str(_repo_root / "api" / _raw_path) if not Path(db_path).exists(): print(f"EROARE: SQLite DB nu există: {db_path}") sys.exit(1) conn = sqlite3.connect(db_path) conn.row_factory = sqlite3.Row # Build query where_clauses = ["id_adresa_facturare IS NOT NULL", "id_adresa_livrare IS NOT NULL"] params = [] if not args.all: where_clauses.append("first_seen_at >= datetime('now', ?)") params.append(f"-{args.days} days") if args.status: where_clauses.append("status = ?") params.append(args.status) where_sql = " AND ".join(where_clauses) rows = conn.execute(f""" SELECT order_number, status, cod_fiscal_gomag, id_adresa_facturare, id_adresa_livrare, adresa_facturare_gomag, adresa_livrare_gomag, adresa_facturare_roa, adresa_livrare_roa, first_seen_at FROM orders WHERE {where_sql} ORDER BY first_seen_at DESC """, params).fetchall() conn.close() if not rows: scope = "toate comenzile" if args.all else f"ultimele {args.days} zile" print(f"Nicio comandă cu adrese populate ({scope}).") sys.exit(0) pf_ok = pf_err = pj_ok = pj_err = pj_skip = 0 violations = [] for r in rows: is_pj = bool(r["cod_fiscal_gomag"]) id_fact = r["id_adresa_facturare"] id_livr = r["id_adresa_livrare"] order = r["order_number"] date = (r["first_seen_at"] or "")[:10] if not is_pj: # PF: id_facturare trebuie = id_livrare if id_fact == id_livr: pf_ok += 1 else: pf_err += 1 violations.append({ "order": order, "date": date, "type": "PF", "issue": f"id_fact={id_fact} != id_livr={id_livr}", "detail": None, }) else: # PJ: adresa_facturare_roa trebuie sa se potriveasca cu GoMag billing fact_roa = r["adresa_facturare_roa"] fact_gomag = r["adresa_facturare_gomag"] livr_gomag = r["adresa_livrare_gomag"] if not fact_roa or not fact_gomag: pj_skip += 1 continue # Check 1: billing ROA matches GoMag billing billing_match = _addr_match(fact_gomag, fact_roa) # Check 2: billing ROA does NOT match GoMag shipping (wrong old behavior) shipping_match = _addr_match(livr_gomag, fact_roa) if livr_gomag else False if billing_match: pj_ok += 1 else: pj_err += 1 detail = "billing_ROA matches shipping GoMag" if shipping_match else "billing_ROA mismatch" violations.append({ "order": order, "date": date, "type": "PJ", "issue": detail, "detail": f"billing_gomag={_short(fact_gomag)} | fact_roa={fact_roa}", }) # Output total = len(rows) print(f"\n{'='*60}") scope = "toate" if args.all else f"ultimele {args.days} zile" print(f" Verificare adrese PJ/PF ({scope}, {total} comenzi cu adrese)") print(f"{'='*60}") print(f" PF (fara CUI): {pf_ok:4d} OK | {pf_err:4d} ERORI") print(f" PJ (cu CUI): {pj_ok:4d} OK | {pj_err:4d} ERORI | {pj_skip:4d} skip (date lipsa)") print(f"{'='*60}") if not violations: print(" ✓ Toate comenzile respecta regula PJ/PF.\n") else: print(f"\n VIOLARI ({len(violations)}):\n") for v in violations[:20]: print(f" [{v['date']}] {v['order']:25s} {v['type']} {v['issue']}") if v["detail"]: print(f" {v['detail']}") if len(violations) > 20: print(f" ... si inca {len(violations)-20} violari.") print() sys.exit(1 if violations else 0) def _short(json_str): """Returnează un rezumat scurt al unui JSON de adresă.""" if not json_str: return "(null)" try: d = json.loads(json_str) return f"{d.get('address','?')}, {d.get('city','?')}" except Exception: return json_str[:40] if __name__ == "__main__": main()