import sys import csv from pathlib import Path # Add parent directory to Python path so we can import helpers parent_dir = Path(__file__).parent.parent sys.path.insert(0, str(parent_dir)) from helpers.config import get_db_connection CSV_PATH = parent_dir / "loaders" / "Contract_Update.csv" def check_contract_number_format(cur): """Show sample contract numbers from DB to confirm expected format.""" cur.execute("SELECT number FROM purchase_purchase ORDER BY id LIMIT 3") pur_samples = [r[0] for r in cur.fetchall()] cur.execute("SELECT number FROM sale_sale ORDER BY id LIMIT 3") sale_samples = [r[0] for r in cur.fetchall()] print(f" Sample purchase numbers : {pur_samples}") print(f" Sample sale numbers : {sale_samples}") print() def update_estimated_bl_dates(dry_run=False): conn = get_db_connection() cur = conn.cursor() print("=== Contract BL Date Update ===") print(f"CSV : {CSV_PATH}") print(f"Mode : {'DRY RUN (no changes will be saved)' if dry_run else 'LIVE UPDATE'}\n") print("DB contract number format check:") check_contract_number_format(cur) # Read CSV rows = [] with open(CSV_PATH, newline="", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: contract_type = row["ContractType"].strip().upper() contract_number = row["ContractNumber"].strip() bl_date = row["EstimatedBlDate"].strip() if contract_type and contract_number and bl_date: rows.append((contract_type, contract_number, bl_date)) print(f"Rows loaded from CSV: {len(rows)}\n") updated_count = 0 skipped_count = 0 not_found_count = 0 for contract_type, contract_number, bl_date in rows: if contract_type == "P": # Resolve purchase_line IDs for this purchase number # Try both raw number (e.g. "2086") and P- prefix (e.g. "P-2086") cur.execute( """ SELECT pl.id FROM purchase_line pl JOIN purchase_purchase pp ON pp.id = pl.purchase WHERE pp.number IN (%s, %s) AND pl.type = 'line' ORDER BY pl.id """, (contract_number, f"P-{contract_number}"), ) line_ids = [r[0] for r in cur.fetchall()] if not line_ids: print(f" [NOT FOUND] Purchase {contract_number} — no matching purchase_line rows") not_found_count += 1 continue # Update pricing_estimated rows linked to those lines with trigger = bldate cur.execute( """ UPDATE pricing_estimated SET estimated_date = %s, write_date = NOW(), write_uid = 1 WHERE line = ANY(%s) AND trigger = 'bldate' RETURNING id, line, estimated_date """, (bl_date, line_ids), ) updated_rows = cur.fetchall() if updated_rows: for pe_id, line_id, new_date in updated_rows: print( f" [{'DRY' if dry_run else 'OK '}] Purchase {contract_number}" f" | purchase_line={line_id} | pricing_estimated.id={pe_id}" f" | estimated_date -> {new_date}" ) updated_count += len(updated_rows) else: print( f" [SKIP] Purchase {contract_number} — lines {line_ids} found" f" but no pricing_estimated row with trigger='bldate'" ) skipped_count += 1 elif contract_type == "S": # Resolve sale_line IDs for this sale number # Try both raw number (e.g. "2086") and S- prefix (e.g. "S-2086") cur.execute( """ SELECT sl.id FROM sale_line sl JOIN sale_sale ss ON ss.id = sl.sale WHERE ss.number IN (%s, %s) AND sl.type = 'line' ORDER BY sl.id """, (contract_number, f"S-{contract_number}"), ) line_ids = [r[0] for r in cur.fetchall()] if not line_ids: print(f" [NOT FOUND] Sale {contract_number} — no matching sale_line rows") not_found_count += 1 continue # Update pricing_estimated rows linked to those sale lines with trigger = bldate cur.execute( """ UPDATE pricing_estimated SET estimated_date = %s, write_date = NOW(), write_uid = 1 WHERE sale_line = ANY(%s) AND trigger = 'bldate' RETURNING id, sale_line, estimated_date """, (bl_date, line_ids), ) updated_rows = cur.fetchall() if updated_rows: for pe_id, sale_line_id, new_date in updated_rows: print( f" [{'DRY' if dry_run else 'OK '}] Sale {contract_number}" f" | sale_line={sale_line_id} | pricing_estimated.id={pe_id}" f" | estimated_date -> {new_date}" ) updated_count += len(updated_rows) else: print( f" [SKIP] Sale {contract_number} — lines {line_ids} found" f" but no pricing_estimated row with trigger='bldate'" ) skipped_count += 1 else: print(f" [WARN] Unknown ContractType '{contract_type}' for contract {contract_number} — skipped") skipped_count += 1 print("\n--- Summary ---") print(f" Updated : {updated_count} pricing_estimated rows") print(f" Skipped : {skipped_count} contracts (no bldate row in pricing_estimated)") print(f" Not found: {not_found_count} contracts (contract number not in DB)") if dry_run: conn.rollback() print("\nDry run — all changes rolled back, nothing saved.") else: conn.commit() print("\nAll changes committed to database.") cur.close() conn.close() if __name__ == "__main__": dry_run = "--dry-run" in sys.argv update_estimated_bl_dates(dry_run=dry_run)