run_uat_s7_fqc_fact_seed.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #!/usr/bin/env python3
  2. """Seed tenant-scoped FQC tasks and results for the S7 formal KPI pipeline."""
  3. from __future__ import annotations
  4. import argparse
  5. import json
  6. from datetime import date, datetime, time, timedelta
  7. from typing import Any
  8. from apply_sql_file import connect
  9. DEFAULT_TENANT = 838257186181189
  10. TASK_PREFIX = "UAT-S7-FQCBJ-"
  11. RESULT_PREFIX = "UAT-S7-FQC-"
  12. def seed(tenant_id: int, dry_run: bool) -> dict[str, Any]:
  13. result: dict[str, Any] = {
  14. "tenantId": tenant_id,
  15. "dryRun": dry_run,
  16. "tasks": 0,
  17. "results": 0,
  18. }
  19. conn = connect()
  20. try:
  21. conn.begin()
  22. with conn.cursor() as cur:
  23. cur.execute(
  24. """
  25. SELECT WorkOrd, ItemNum, QtyOrded, DueDate
  26. FROM WorkOrdMaster
  27. WHERE tenant_id=%s AND WorkOrd LIKE 'UATA-WO-%%'
  28. ORDER BY WorkOrd
  29. """,
  30. (tenant_id,),
  31. )
  32. orders = cur.fetchall()
  33. if not orders:
  34. raise RuntimeError(f"tenant {tenant_id} has no UATA work orders")
  35. cur.execute("SELECT COALESCE(MAX(id),0) max_id FROM qms_fqcbj")
  36. task_id_base = int(cur.fetchone()["max_id"])
  37. cur.execute("SELECT COALESCE(MAX(id),0) max_id FROM qms_qcpp_inspbill")
  38. result_id_base = int(cur.fetchone()["max_id"])
  39. if not dry_run:
  40. cur.execute(
  41. "DELETE FROM qms_qcpp_inspbill WHERE tenant_id=%s AND FBILLNO LIKE %s",
  42. (tenant_id, f"{RESULT_PREFIX}%"),
  43. )
  44. cur.execute(
  45. "DELETE FROM qms_fqcbj WHERE tenant_id=%s AND FBILLNO LIKE %s",
  46. (tenant_id, f"{TASK_PREFIX}%"),
  47. )
  48. today = date.today()
  49. for index, order in enumerate(orders):
  50. seq = index + 1
  51. task_id = task_id_base + seq
  52. result_id = result_id_base + seq
  53. apply_day = today - timedelta(days=len(orders) - seq)
  54. apply_at = datetime.combine(apply_day, time(hour=8))
  55. start_at = apply_at + timedelta(hours=1 + index % 2)
  56. finish_at = start_at + timedelta(hours=2 + index % 7)
  57. task_no = f"{TASK_PREFIX}{seq:03d}"
  58. result_no = f"{RESULT_PREFIX}{seq:03d}"
  59. inspector = f"UAT-FQC-{index % 3 + 1:02d}"
  60. qty = float(order["QtyOrded"] or 100)
  61. rejected = round(qty * (0.01 if index % 4 == 0 else 0), 0)
  62. accepted = qty - rejected
  63. if not dry_run:
  64. cur.execute(
  65. """
  66. INSERT INTO qms_fqcbj
  67. (id,tenant_id,FBILLNO,FBILLSTATUS,FCREATETIME,FAPPLYUSER,FAPPLYTIME,
  68. FBILLTYPE,cpmc,scph,sl,wlbm,jyfzr,yxj,jykssj,jywcsj,
  69. FINSPECTSTATUS,sczld,sczldsl,lydjbh)
  70. VALUES
  71. (%s,%s,%s,'COMPLETED',%s,'UAT_GENERATOR',%s,
  72. 'FQC',%s,%s,%s,%s,%s,'正常',%s,%s,
  73. '检验完成',%s,%s,%s)
  74. """,
  75. (
  76. task_id,
  77. tenant_id,
  78. task_no,
  79. apply_at,
  80. apply_at,
  81. order["ItemNum"] or order["WorkOrd"],
  82. f"UAT-BATCH-{seq:03d}",
  83. qty,
  84. order["ItemNum"] or order["WorkOrd"],
  85. inspector,
  86. start_at,
  87. finish_at,
  88. order["WorkOrd"],
  89. qty,
  90. order["WorkOrd"],
  91. ),
  92. )
  93. cur.execute(
  94. """
  95. INSERT INTO qms_qcpp_inspbill
  96. (id,tenant_id,FBILLNO,FBILLSTATUS,FCREATETIME,FAUDITDATE,
  97. FINSPESTARTDATE,FINSPEENDDATE,FINSPECTORID,FBILLTYPE,
  98. FMATERIALCFG,FRINSQTY,pd,jyr,hid,lydjbh,scph,hgsl,bhgsl,sczld,sczldsl)
  99. VALUES
  100. (%s,%s,%s,'COMPLETED',%s,%s,
  101. %s,%s,%s,'FQC',
  102. %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
  103. """,
  104. (
  105. result_id,
  106. tenant_id,
  107. result_no,
  108. apply_at,
  109. finish_at,
  110. start_at,
  111. finish_at,
  112. 7000 + index % 3,
  113. order["ItemNum"] or order["WorkOrd"],
  114. qty,
  115. "合格" if rejected == 0 else "让步接收",
  116. inspector,
  117. task_id,
  118. task_no,
  119. f"UAT-BATCH-{seq:03d}",
  120. accepted,
  121. rejected,
  122. order["WorkOrd"],
  123. qty,
  124. ),
  125. )
  126. result["tasks"] += 1
  127. result["results"] += 1
  128. if dry_run:
  129. conn.rollback()
  130. else:
  131. conn.commit()
  132. except Exception:
  133. conn.rollback()
  134. raise
  135. finally:
  136. conn.close()
  137. return result
  138. def main() -> None:
  139. parser = argparse.ArgumentParser()
  140. parser.add_argument("--tenant", type=int, default=DEFAULT_TENANT)
  141. parser.add_argument("--dry-run", action="store_true")
  142. args = parser.parse_args()
  143. print(json.dumps(seed(args.tenant, args.dry_run), ensure_ascii=False, indent=2, default=str))
  144. if __name__ == "__main__":
  145. main()