record_wp3_execution.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #!/usr/bin/env python3
  2. """Record evidence-backed WP3 B00-B14 status without overstating completion."""
  3. from __future__ import annotations
  4. import json
  5. import re
  6. from datetime import datetime
  7. from pathlib import Path
  8. import pymysql
  9. from pymysql.cursors import DictCursor
  10. ROOT = Path(__file__).resolve().parents[4]
  11. DATABASE_JSON = (
  12. ROOT / "server" / "Admin.NET.Application" / "Configuration" / "Database.json"
  13. )
  14. EVIDENCE = Path(__file__).with_name("WP3-B00-B14-evidence.json")
  15. TENANT_ID = 838257212780613
  16. def connect() -> pymysql.Connection:
  17. raw = DATABASE_JSON.read_text(encoding="utf-8-sig")
  18. connection_string = next(
  19. value
  20. for value in re.findall(
  21. r'(?m)^\s*"ConnectionString"\s*:\s*"([^"]+)"', raw
  22. )
  23. if "Database=aidopdev" in value
  24. )
  25. parts = {
  26. item.split("=", 1)[0].strip().lower(): item.split("=", 1)[1].strip()
  27. for item in connection_string.split(";")
  28. if "=" in item
  29. }
  30. return pymysql.connect(
  31. host=parts["server"],
  32. port=int(parts["port"]),
  33. user=parts["uid"],
  34. password=parts["pwd"],
  35. database=parts["database"],
  36. charset="utf8mb4",
  37. autocommit=True,
  38. cursorclass=DictCursor,
  39. )
  40. def scalar(cur: DictCursor, sql: str, args: tuple = ()) -> int:
  41. cur.execute(sql, args)
  42. return int(next(iter(cur.fetchone().values())))
  43. def main() -> None:
  44. conn = connect()
  45. try:
  46. with conn.cursor() as cur:
  47. cur.execute(
  48. """
  49. CREATE TABLE IF NOT EXISTS uat_step_execution (
  50. id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  51. tenant_id BIGINT NOT NULL,
  52. work_package VARCHAR(20) NOT NULL,
  53. step_code VARCHAR(20) NOT NULL,
  54. status VARCHAR(30) NOT NULL,
  55. evidence_json JSON NULL,
  56. verified_at DATETIME(3) NOT NULL,
  57. UNIQUE KEY uk_uat_step (tenant_id,work_package,step_code)
  58. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
  59. """
  60. )
  61. facts = {
  62. "users": scalar(
  63. cur,
  64. "SELECT COUNT(*) FROM SysUser WHERE TenantId=%s",
  65. (TENANT_ID,),
  66. ),
  67. "items": scalar(
  68. cur,
  69. "SELECT COUNT(*) FROM ItemMaster WHERE tenant_id=%s",
  70. (TENANT_ID,),
  71. ),
  72. "bom_headers": scalar(
  73. cur,
  74. "SELECT COUNT(*) FROM ProductStructureMaster WHERE tenant_id=%s",
  75. (TENANT_ID,),
  76. ),
  77. "routing_ops": scalar(
  78. cur,
  79. "SELECT COUNT(*) FROM RoutingOpDetail WHERE tenant_id=%s",
  80. (TENANT_ID,),
  81. ),
  82. "sales_orders": scalar(
  83. cur,
  84. "SELECT COUNT(*) FROM crm_seorder WHERE tenant_id=%s",
  85. (TENANT_ID,),
  86. ),
  87. "work_orders": scalar(
  88. cur,
  89. "SELECT COUNT(*) FROM WorkOrdMaster WHERE tenant_id=%s",
  90. (TENANT_ID,),
  91. ),
  92. "purchase_requests": scalar(
  93. cur,
  94. "SELECT COUNT(*) FROM srm_pr_main WHERE tenant_id=%s",
  95. (TENANT_ID,),
  96. ),
  97. "purchase_orders": scalar(
  98. cur,
  99. "SELECT COUNT(*) FROM PurOrdMaster WHERE tenant_id=%s",
  100. (TENANT_ID,),
  101. ),
  102. "supplier_shipments": scalar(
  103. cur,
  104. "SELECT COUNT(*) FROM scm_shd WHERE tenant_id=%s",
  105. (TENANT_ID,),
  106. ),
  107. "iqc_closed": scalar(
  108. cur,
  109. """
  110. SELECT COUNT(*) FROM ApprovalFlowInstance
  111. WHERE BizId IN (
  112. SELECT id FROM qms_qcp_inspbill
  113. WHERE tenant_id=%s AND FBILLNO='UATB-B11-IQC-001'
  114. ) AND Status=2
  115. """,
  116. (TENANT_ID,),
  117. ),
  118. "ipqc_closed": scalar(
  119. cur,
  120. """
  121. SELECT COUNT(*) FROM ApprovalFlowInstance
  122. WHERE BizId IN (
  123. SELECT id FROM qms_gcjyd
  124. WHERE tenant_id=%s AND djbh='UATB-B12-IPQC-001'
  125. ) AND Status=2
  126. """,
  127. (TENANT_ID,),
  128. ),
  129. "fqc_closed": scalar(
  130. cur,
  131. """
  132. SELECT COUNT(*) FROM ApprovalFlowInstance
  133. WHERE BizId IN (
  134. SELECT id FROM qms_qcpp_inspbill
  135. WHERE tenant_id=%s AND FBILLNO='UATB-B12-FQC-001'
  136. ) AND Status=2
  137. """,
  138. (TENANT_ID,),
  139. ),
  140. "s8_exceptions": scalar(
  141. cur,
  142. "SELECT COUNT(*) FROM ado_s8_exception WHERE tenant_id=%s",
  143. (TENANT_ID,),
  144. ),
  145. "successful_modules": scalar(
  146. cur,
  147. """
  148. SELECT COUNT(DISTINCT module_code)
  149. FROM ado_module_dashboard_rebuild_job
  150. WHERE tenant_id=%s AND status='SUCCESS'
  151. AND module_code IN ('S1','S2','S3','S4','S5','S6','S7')
  152. """,
  153. (TENANT_ID,),
  154. ),
  155. }
  156. steps = {
  157. "B00": ("PASSED" if facts["users"] >= 4 else "BLOCKED", {"users": facts["users"]}),
  158. "B01": ("PASSED" if facts["items"] >= 20 else "BLOCKED", {"items": facts["items"]}),
  159. "B02": (
  160. "PASSED"
  161. if facts["bom_headers"] > 0 and facts["routing_ops"] > 0
  162. else "BLOCKED",
  163. {"bom_headers": facts["bom_headers"], "routing_ops": facts["routing_ops"]},
  164. ),
  165. "B03": ("CHECKPOINT_READY", {"sales_orders": facts["sales_orders"]}),
  166. "B04": ("CHECKPOINT_READY", {"sales_orders": facts["sales_orders"]}),
  167. "B05": ("CHECKPOINT_READY", {"work_orders": facts["work_orders"]}),
  168. "B06": ("CHECKPOINT_READY", {"work_orders": facts["work_orders"]}),
  169. "B07": ("CHECKPOINT_READY", {"purchase_requests": facts["purchase_requests"]}),
  170. "B08": ("CHECKPOINT_READY", {"purchase_orders": facts["purchase_orders"]}),
  171. "B09": ("CHECKPOINT_READY", {"supplier_shipments": facts["supplier_shipments"]}),
  172. "B10": ("CHECKPOINT_READY", {"supplier_shipments": facts["supplier_shipments"]}),
  173. "B11": (
  174. "API_VERIFIED" if facts["iqc_closed"] else "PENDING_EXECUTION",
  175. {"iqc_closed": facts["iqc_closed"]},
  176. ),
  177. "B12": (
  178. "API_VERIFIED"
  179. if facts["ipqc_closed"] and facts["fqc_closed"]
  180. else "PENDING_EXECUTION",
  181. {
  182. "ipqc_closed": facts["ipqc_closed"],
  183. "fqc_closed": facts["fqc_closed"],
  184. },
  185. ),
  186. "B13": (
  187. "API_VERIFIED" if facts["s8_exceptions"] else "PENDING_EXECUTION",
  188. {"s8_exceptions": facts["s8_exceptions"]},
  189. ),
  190. "B14": (
  191. "PASSED" if facts["successful_modules"] == 7 else "BLOCKED",
  192. {"successful_modules": facts["successful_modules"]},
  193. ),
  194. }
  195. for step_code, (status, evidence) in steps.items():
  196. cur.execute(
  197. """
  198. INSERT INTO uat_step_execution
  199. (tenant_id,work_package,step_code,status,evidence_json,verified_at)
  200. VALUES(%s,'WP3',%s,%s,%s,NOW(3))
  201. ON DUPLICATE KEY UPDATE
  202. status=VALUES(status),
  203. evidence_json=VALUES(evidence_json),
  204. verified_at=VALUES(verified_at)
  205. """,
  206. (TENANT_ID, step_code, status, json.dumps(evidence)),
  207. )
  208. finally:
  209. conn.close()
  210. payload = {
  211. "generated_at": datetime.now().isoformat(timespec="seconds"),
  212. "tenant_id": str(TENANT_ID),
  213. "facts": facts,
  214. "steps": {
  215. code: {"status": status, "evidence": evidence}
  216. for code, (status, evidence) in steps.items()
  217. },
  218. }
  219. EVIDENCE.write_text(
  220. json.dumps(payload, ensure_ascii=False, indent=2),
  221. encoding="utf-8",
  222. )
  223. print(json.dumps(payload, ensure_ascii=False, indent=2))
  224. if __name__ == "__main__":
  225. main()