wip: ops admin panel + migration sync + crud/rbac phase-5 snapshot
Working-tree checkpoint of in-progress work carried across prior sessions on the feat/crud-rbac branch, committed so it lands on the remote alongside the CI changes. - Operaciones admin panel: apps/api/src/ops (ingest upload, backup / restore / re-import jobs) wired into app.module + RBAC abilities, and the apps/web/src/app/operaciones page. docker-compose gets INGEST_DIR / BACKUP_DIR volumes; .gitignore excludes migration/ingest + backups. - migration/sync.py plus transform_*.py / run_all / config / dbenv / blob_extract adjustments for the additive sync path. - crud/rbac phase-5 web bits: AppShell, api/labels/types libs, globals. - schema.prisma + PLAN/RESUME doc updates. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@ from pathlib import Path
|
||||
import pandas as pd
|
||||
|
||||
from dbenv import connect, env_arg
|
||||
from sync import delete_missing, existing_ids, parse_mode
|
||||
|
||||
STG = Path(__file__).parent / "output" / "stg_utilities"
|
||||
NULL = "∅"
|
||||
@@ -100,8 +101,8 @@ def jkey(numer, casa, direc):
|
||||
])
|
||||
|
||||
|
||||
def main() -> None:
|
||||
env = env_arg()
|
||||
def main():
|
||||
env, sync_mode = parse_mode()
|
||||
conn = connect(env)
|
||||
print(f"[properties] target env: {env}")
|
||||
cur = conn.cursor()
|
||||
@@ -119,6 +120,7 @@ def main() -> None:
|
||||
flags[jkey(r["numerid"], r["casa"], r["direccion"])] = r
|
||||
|
||||
props, services, trusts = [], [], []
|
||||
prop_keys: set[tuple] = set()
|
||||
skipped_no_customer = 0
|
||||
matched_profile = 0
|
||||
|
||||
@@ -129,6 +131,8 @@ def main() -> None:
|
||||
skipped_no_customer += 1
|
||||
continue
|
||||
|
||||
legacy_id = str(int(row["_row_num"]))
|
||||
prop_keys.add(("DATMEX", legacy_id))
|
||||
pid = str(uuid.uuid4())
|
||||
addr2_parts = []
|
||||
for lbl, col in (("CASA", "casa"), ("MZ", "manzana"), ("LOTE", "lote")):
|
||||
@@ -137,7 +141,8 @@ def main() -> None:
|
||||
props.append((
|
||||
pid, cust_id, s(row["direccion"]), ", ".join(addr2_parts) or None,
|
||||
s(row["telefono"]), s(row["telefono2"]), s(row["telefono3"]),
|
||||
s(row["zona"]), "DATMEX", nid,
|
||||
s(row["zona"]), "DATMEX", legacy_id,
|
||||
|
||||
))
|
||||
|
||||
pfrow = flags.get(jkey(row["numer_id"], row["casa"], row["direccion"]))
|
||||
@@ -199,21 +204,28 @@ def main() -> None:
|
||||
trusts.append((str(uuid.uuid4()), pid, bank, s(row["trust_num"]),
|
||||
as_dec(row["bfee"]), as_date(row["vence1"]), as_date(row["vence2"])))
|
||||
|
||||
# Fresh rebuild (children first).
|
||||
cur.execute("SET FOREIGN_KEY_CHECKS=0")
|
||||
for t in ("property_services", "service_documents", "trust_accounts", "properties"):
|
||||
cur.execute(f"TRUNCATE TABLE {t}")
|
||||
cur.execute("SET FOREIGN_KEY_CHECKS=1")
|
||||
|
||||
cur.executemany(
|
||||
"INSERT INTO properties (id,customerId,addressLine1,addressLine2,phone1,phone2,"
|
||||
"phone3,zone,legacySourceTable,legacyId) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", props)
|
||||
cur.executemany(
|
||||
"INSERT INTO property_services (id,propertyId,kind,accountNumber,meterNumber,route,"
|
||||
"dueDay,active,notes) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)", services)
|
||||
cur.executemany(
|
||||
"INSERT INTO trust_accounts (id,propertyId,bankName,trustNumber,bankFee,dueDate1,dueDate2)"
|
||||
" VALUES (%s,%s,%s,%s,%s,%s,%s)", trusts)
|
||||
# Fresh rebuild (children first), or additive upsert for legacy-owned rows.
|
||||
if sync_mode:
|
||||
existing = existing_ids(cur, "properties", ("legacySourceTable", "legacyId"), "WHERE legacyId IS NOT NULL")
|
||||
for row in props:
|
||||
key = (row[8], row[9])
|
||||
if key in existing:
|
||||
row = list(row); row[0] = existing[key]
|
||||
cur.execute(
|
||||
"INSERT INTO properties (id,customerId,addressLine1,addressLine2,phone1,phone2,phone3,zone,legacySourceTable,legacyId) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ON DUPLICATE KEY UPDATE customerId=VALUES(customerId),addressLine1=VALUES(addressLine1),addressLine2=VALUES(addressLine2),phone1=VALUES(phone1),phone2=VALUES(phone2),phone3=VALUES(phone3),zone=VALUES(zone),archivedAt=NULL", tuple(row))
|
||||
delete_missing(cur, "properties", ("legacySourceTable", "legacyId"), prop_keys, "WHERE legacyId IS NOT NULL")
|
||||
cur.execute("DELETE ps FROM property_services ps JOIN properties p ON p.id=ps.propertyId WHERE p.legacyId IS NOT NULL")
|
||||
cur.execute("DELETE ta FROM trust_accounts ta JOIN properties p ON p.id=ta.propertyId WHERE p.legacyId IS NOT NULL")
|
||||
cur.executemany("INSERT INTO property_services (id,propertyId,kind,accountNumber,meterNumber,route,dueDay,active,notes) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)", services)
|
||||
cur.executemany("INSERT INTO trust_accounts (id,propertyId,bankName,trustNumber,bankFee,dueDate1,dueDate2) VALUES (%s,%s,%s,%s,%s,%s,%s)", trusts)
|
||||
else:
|
||||
cur.execute("SET FOREIGN_KEY_CHECKS=0")
|
||||
for t in ("property_services", "service_documents", "trust_accounts", "properties"):
|
||||
cur.execute(f"TRUNCATE TABLE {t}")
|
||||
cur.execute("SET FOREIGN_KEY_CHECKS=1")
|
||||
cur.executemany("INSERT INTO properties (id,customerId,addressLine1,addressLine2,phone1,phone2,phone3,zone,legacySourceTable,legacyId) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", props)
|
||||
cur.executemany("INSERT INTO property_services (id,propertyId,kind,accountNumber,meterNumber,route,dueDay,active,notes) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)", services)
|
||||
cur.executemany("INSERT INTO trust_accounts (id,propertyId,bankName,trustNumber,bankFee,dueDate1,dueDate2) VALUES (%s,%s,%s,%s,%s,%s,%s)", trusts)
|
||||
conn.commit()
|
||||
|
||||
cur.execute("SELECT COUNT(*) FROM properties"); n_p = cur.fetchone()[0]
|
||||
|
||||
Reference in New Issue
Block a user