| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- #!/usr/bin/env python3
- """Remove reconstructible invalid-tenant DWD/KPI rows and add hard guards."""
- from __future__ import annotations
- import json
- import re
- from datetime import datetime
- from pathlib import Path
- import pymysql
- ROOT = Path(__file__).resolve().parents[4]
- CONFIG = ROOT / "server" / "Admin.NET.Application" / "Configuration" / "Database.json"
- TABLES = (
- "dwd_material_readiness",
- "dwd_material_shortage",
- "dwd_order_schedule_trans",
- "dwd_supplier_delivery",
- "dwd_supplier_risk",
- "dwd_supply_demand",
- "ado_s9_kpi_value_l1_day",
- "ado_s9_kpi_value_l2_day",
- "ado_s9_kpi_value_l3_day",
- "ado_s9_kpi_value_l4_day",
- )
- def connect() -> pymysql.Connection:
- raw = CONFIG.read_text(encoding="utf-8-sig")
- value = next(
- item
- for item in re.findall(
- r'(?m)^\s*"ConnectionString"\s*:\s*"([^"]+)"', raw
- )
- if "Database=aidopdev" in item
- )
- parts = {
- item.split("=", 1)[0].strip().lower(): item.split("=", 1)[1].strip()
- for item in value.split(";")
- if "=" in item
- }
- return pymysql.connect(
- host=parts["server"],
- port=int(parts["port"]),
- user=parts["uid"],
- password=parts["pwd"],
- database=parts["database"],
- charset="utf8mb4",
- autocommit=True,
- )
- def main() -> None:
- conn = connect()
- results: list[dict[str, object]] = []
- try:
- with conn.cursor() as cur:
- cur.execute(
- """
- CREATE TABLE IF NOT EXISTS uat_data_cleanup_audit (
- id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
- batch_code VARCHAR(100) NOT NULL,
- table_name VARCHAR(128) NOT NULL,
- invalid_rows_before BIGINT NOT NULL,
- deleted_rows BIGINT NOT NULL,
- invalid_rows_after BIGINT NOT NULL,
- executed_at DATETIME(3) NOT NULL
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
- """
- )
- for index, table in enumerate(TABLES, 1):
- constraint = f"ck_wp5_valid_tenant_{index:02d}"
- invalid = "tenant_id IS NULL OR tenant_id IN (0,1,1300000000001)"
- cur.execute(f"SELECT COUNT(*) FROM `{table}` WHERE {invalid}")
- before = int(cur.fetchone()[0])
- cur.execute(f"DELETE FROM `{table}` WHERE {invalid}")
- deleted = int(cur.rowcount)
- cur.execute(f"SELECT COUNT(*) FROM `{table}` WHERE {invalid}")
- after = int(cur.fetchone()[0])
- cur.execute(
- """
- INSERT INTO uat_data_cleanup_audit
- (batch_code,table_name,invalid_rows_before,deleted_rows,
- invalid_rows_after,executed_at)
- VALUES('WP5_INVALID_TENANT_20260817',%s,%s,%s,%s,NOW(3))
- """,
- (table, before, deleted, after),
- )
- cur.execute(
- """
- SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS
- WHERE CONSTRAINT_SCHEMA=DATABASE()
- AND TABLE_NAME=%s AND CONSTRAINT_NAME=%s
- """,
- (table, constraint),
- )
- if int(cur.fetchone()[0]) == 0:
- cur.execute(
- f"""
- ALTER TABLE `{table}`
- ADD CONSTRAINT `{constraint}`
- CHECK (tenant_id IS NOT NULL
- AND tenant_id NOT IN (0,1,1300000000001))
- """
- )
- results.append(
- {
- "table": table,
- "before": before,
- "deleted": deleted,
- "after": after,
- "constraint": constraint,
- }
- )
- finally:
- conn.close()
- payload = {
- "executed_at": datetime.now().isoformat(timespec="seconds"),
- "results": results,
- }
- Path(__file__).with_name("WP5-pollution-cleanup-evidence.json").write_text(
- json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8"
- )
- print(json.dumps(payload, ensure_ascii=False, indent=2))
- if __name__ == "__main__":
- main()
|