run_uat_purchase_receipt_fact_seed.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #!/usr/bin/env python3
  2. """Create tenant-scoped UAT purchase receipt business documents."""
  3. from __future__ import annotations
  4. import argparse
  5. import json
  6. from collections import defaultdict
  7. from datetime import datetime, timedelta
  8. from decimal import Decimal
  9. from typing import Any
  10. from apply_sql_file import connect
  11. TENANTS = {
  12. 838257186181189: ("A", Decimal("0.85")),
  13. 838257212780613: ("B", Decimal("0.70")),
  14. 838257237606469: ("DEMO", Decimal("0.92")),
  15. }
  16. PREFIX = "UATRCT-"
  17. def load_po_lines(cursor: Any) -> dict[int, list[dict[str, Any]]]:
  18. tenant_ids = ",".join(str(x) for x in TENANTS)
  19. cursor.execute(
  20. f"""
  21. SELECT tenant_id,PurOrd,Line,ItemNum,QtyOrded,Potype,Domain,Site
  22. FROM PurOrdDetail
  23. WHERE tenant_id IN ({tenant_ids})
  24. AND IFNULL(PurOrd,'')<>'' AND IFNULL(ItemNum,'')<>'' AND IFNULL(QtyOrded,0)>0
  25. ORDER BY tenant_id,PurOrd,Line
  26. """
  27. )
  28. rows: dict[int, list[dict[str, Any]]] = defaultdict(list)
  29. for row in cursor.fetchall():
  30. rows[int(row["tenant_id"])].append(row)
  31. return rows
  32. def apply() -> dict[str, Any]:
  33. conn = connect()
  34. result: dict[str, Any] = {"masters": 0, "details": 0, "tenants": {}}
  35. try:
  36. conn.begin()
  37. with conn.cursor() as cursor:
  38. tenant_ids = tuple(TENANTS)
  39. placeholders = ",".join(["%s"] * len(tenant_ids))
  40. cursor.execute(
  41. f"DELETE FROM PurOrdRctDetail WHERE tenant_id IN ({placeholders}) AND Receiver LIKE %s",
  42. (*tenant_ids, f"{PREFIX}%"),
  43. )
  44. cursor.execute(
  45. f"DELETE FROM PurOrdRctMaster WHERE tenant_id IN ({placeholders}) AND Receiver LIKE %s",
  46. (*tenant_ids, f"{PREFIX}%"),
  47. )
  48. cursor.execute("SELECT GREATEST(IFNULL(MAX(RecID),0),0) AS max_id FROM PurOrdRctMaster")
  49. master_id = int(cursor.fetchone()["max_id"])
  50. cursor.execute("SELECT GREATEST(IFNULL(MAX(RecID),0),0) AS max_id FROM PurOrdRctDetail")
  51. detail_id = int(cursor.fetchone()["max_id"])
  52. lines_by_tenant = load_po_lines(cursor)
  53. now = datetime.now().replace(microsecond=0)
  54. for tenant_id, (code, ratio) in TENANTS.items():
  55. grouped: dict[str, list[dict[str, Any]]] = defaultdict(list)
  56. for line in lines_by_tenant.get(tenant_id, []):
  57. grouped[str(line["PurOrd"])].append(line)
  58. tenant_result = {"masters": 0, "details": 0}
  59. for order_index, (po_no, lines) in enumerate(grouped.items(), 1):
  60. master_id += 1
  61. receiver = f"{PREFIX}{code}-{order_index:04d}"
  62. receipt_date = now - timedelta(days=order_index % 3)
  63. first = lines[0]
  64. cursor.execute(
  65. """
  66. INSERT INTO PurOrdRctMaster
  67. (RecID,Domain,RctType,Receiver,RctDate,OrdNbr,PerformDate,Site,BusinessID,
  68. CreateUser,UpdateUser,CreateTime,UpdateTime,IsActive,IsConfirm,Print,
  69. IsChanged,TaxIn,IsExport,IsPlan,IsBackwash,Remark,tenant_id)
  70. VALUES
  71. (%s,%s,'RCT',%s,%s,%s,%s,%s,%s,
  72. 'UAT_GENERATOR','UAT_GENERATOR',NOW(),NOW(),1,1,0,
  73. 0,0,0,0,0,'UAT_GENERATOR:采购收货业务事实',%s)
  74. """,
  75. (
  76. master_id,
  77. first["Domain"],
  78. receiver,
  79. receipt_date,
  80. po_no,
  81. receipt_date,
  82. first["Site"],
  83. master_id,
  84. tenant_id,
  85. ),
  86. )
  87. result["masters"] += 1
  88. tenant_result["masters"] += 1
  89. for line_index, line in enumerate(lines, 1):
  90. detail_id += 1
  91. ordered = Decimal(str(line["QtyOrded"]))
  92. received = (ordered * ratio).quantize(Decimal("0.00001"))
  93. cursor.execute(
  94. """
  95. INSERT INTO PurOrdRctDetail
  96. (RecID,Domain,RctType,Receiver,Line,ItemNum,Dimension1,Dimension2,
  97. OrdNbr,OrdLine,RctDate,POCost,QtyOrded,RctQty,QtyReceived,Site,
  98. Location,Potype,BusinessID,CreateUser,UpdateUser,CreateTime,UpdateTime,
  99. IsActive,IsConfirm,IsChanged,TaxIn,UMConversion,IsClosed,IsRounding,
  100. BlanketLine,ProjectLine,RctLine,QtyReturn,PurOrdRctRecID,QcQty,QC,
  101. Remark,tenant_id)
  102. VALUES
  103. (%s,%s,'RCT',%s,%s,%s,'','',%s,%s,%s,1,%s,%s,%s,%s,
  104. 'UAT',%s,%s,'UAT_GENERATOR','UAT_GENERATOR',NOW(),NOW(),
  105. 1,1,0,0,1,0,0,0,0,%s,0,%s,%s,'PASS',
  106. 'UAT_GENERATOR:采购收货明细',%s)
  107. """,
  108. (
  109. detail_id,
  110. line["Domain"],
  111. receiver,
  112. line_index,
  113. line["ItemNum"],
  114. po_no,
  115. int(line["Line"] or line_index),
  116. receipt_date,
  117. ordered,
  118. received,
  119. received,
  120. line["Site"],
  121. line["Potype"] or "PO",
  122. detail_id,
  123. line_index,
  124. master_id,
  125. received,
  126. tenant_id,
  127. ),
  128. )
  129. result["details"] += 1
  130. tenant_result["details"] += 1
  131. result["tenants"][code] = tenant_result
  132. conn.commit()
  133. except Exception:
  134. conn.rollback()
  135. raise
  136. finally:
  137. conn.close()
  138. return result
  139. def main() -> int:
  140. parser = argparse.ArgumentParser()
  141. parser.add_argument("--apply", action="store_true")
  142. args = parser.parse_args()
  143. result: dict[str, Any] = {"mode": "dry-run", "tenants": TENANTS}
  144. if args.apply:
  145. result = {"mode": "apply", **apply()}
  146. print(json.dumps(result, ensure_ascii=False, indent=2, default=str))
  147. return 0
  148. if __name__ == "__main__":
  149. raise SystemExit(main())