From 32b13838f2e73e69b0b67c2b2d66c7de552fa2b0 Mon Sep 17 00:00:00 2001 From: "AzureAD\\SylvainDUVERNAY" Date: Sat, 28 Mar 2026 17:11:52 +0100 Subject: [PATCH] Commit --- .../loaders/Contract_Update - Copy.csv | 60 ++++++ .../loaders/Contract_Update.csv | 60 ++++++ .../scripts/update_estimated_bl_dates.py | 179 ++++++++++++++++++ 3 files changed, 299 insertions(+) create mode 100644 Reference Data/python_project/loaders/Contract_Update - Copy.csv create mode 100644 Reference Data/python_project/loaders/Contract_Update.csv create mode 100644 Reference Data/python_project/scripts/update_estimated_bl_dates.py diff --git a/Reference Data/python_project/loaders/Contract_Update - Copy.csv b/Reference Data/python_project/loaders/Contract_Update - Copy.csv new file mode 100644 index 0000000..4657458 --- /dev/null +++ b/Reference Data/python_project/loaders/Contract_Update - Copy.csv @@ -0,0 +1,60 @@ +ContractType,ContractNumber,EstimatedBlDate +P,2086,2026-04-01 +S,2081,2026-04-01 +S,2102,2026-04-01 +S,2179,2026-04-01 +P,2133,2026-04-08 +S,2134,2026-04-08 +P,2061,2026-04-15 +P,2128,2026-04-27 +S,2170,2026-04-27 +P,2095,2026-05-01 +P,2111,2026-05-01 +P,2135,2026-05-01 +S,2112,2026-05-01 +S,2120,2026-05-01 +S,2136,2026-05-01 +S,2168,2026-05-01 +P,2087,2026-06-01 +P,2137,2026-06-01 +S,2068,2026-06-01 +S,2103,2026-06-01 +S,2138,2026-06-01 +P,2065,2026-06-03 +S,2066,2026-06-03 +P,2063,2026-06-12 +S,2064,2026-06-12 +P,2067,2026-07-01 +P,2113,2026-07-01 +P,2139,2026-07-01 +S,2079,2026-07-01 +S,2114,2026-07-01 +S,2140,2026-07-01 +P,2090,2026-07-12 +P,2088,2026-08-01 +P,2141,2026-08-01 +S,2082,2026-08-01 +S,2142,2026-08-01 +P,2073,2026-08-05 +P,2094,2026-09-01 +P,2115,2026-09-01 +P,2129,2026-09-01 +P,2143,2026-09-01 +S,2116,2026-09-01 +S,2121,2026-09-01 +S,2144,2026-09-01 +P,2069,2026-09-05 +S,2070,2026-09-05 +P,2145,2026-10-01 +S,2080,2026-10-01 +S,2146,2026-10-01 +P,2062,2026-10-05 +P,2096,2026-11-01 +P,2117,2026-11-01 +P,2147,2026-11-01 +S,2083,2026-11-01 +S,2118,2026-11-01 +S,2148,2026-11-01 +P,2149,2026-12-01 +S,2104,2026-12-01 +S,2150,2026-12-01 diff --git a/Reference Data/python_project/loaders/Contract_Update.csv b/Reference Data/python_project/loaders/Contract_Update.csv new file mode 100644 index 0000000..fd55fe0 --- /dev/null +++ b/Reference Data/python_project/loaders/Contract_Update.csv @@ -0,0 +1,60 @@ +ContractType,ContractNumber,EstimatedBlDate +P,2086,4/1/2026 +S,2081,4/1/2026 +S,2102,4/1/2026 +S,2179,4/1/2026 +P,2133,4/8/2026 +S,2134,4/8/2026 +P,2061,4/15/2026 +P,2128,4/27/2026 +S,2170,4/27/2026 +P,2095,5/1/2026 +P,2111,5/1/2026 +P,2135,5/1/2026 +S,2112,5/1/2026 +S,2120,5/1/2026 +S,2136,5/1/2026 +S,2168,5/1/2026 +P,2087,6/1/2026 +P,2137,6/1/2026 +S,2068,6/1/2026 +S,2103,6/1/2026 +S,2138,6/1/2026 +P,2065,6/3/2026 +S,2066,6/3/2026 +P,2063,6/12/2026 +S,2064,6/12/2026 +P,2067,7/1/2026 +P,2113,7/1/2026 +P,2139,7/1/2026 +S,2079,7/1/2026 +S,2114,7/1/2026 +S,2140,7/1/2026 +P,2090,7/12/2026 +P,2088,8/1/2026 +P,2141,8/1/2026 +S,2082,8/1/2026 +S,2142,8/1/2026 +P,2073,8/5/2026 +P,2094,9/1/2026 +P,2115,9/1/2026 +P,2129,9/1/2026 +P,2143,9/1/2026 +S,2116,9/1/2026 +S,2121,9/1/2026 +S,2144,9/1/2026 +P,2069,9/5/2026 +S,2070,9/5/2026 +P,2145,10/1/2026 +S,2080,10/1/2026 +S,2146,10/1/2026 +P,2062,10/5/2026 +P,2096,11/1/2026 +P,2117,11/1/2026 +P,2147,11/1/2026 +S,2083,11/1/2026 +S,2118,11/1/2026 +S,2148,11/1/2026 +P,2149,12/1/2026 +S,2104,12/1/2026 +S,2150,12/1/2026 diff --git a/Reference Data/python_project/scripts/update_estimated_bl_dates.py b/Reference Data/python_project/scripts/update_estimated_bl_dates.py new file mode 100644 index 0000000..bd80ac2 --- /dev/null +++ b/Reference Data/python_project/scripts/update_estimated_bl_dates.py @@ -0,0 +1,179 @@ +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)