InboundNeutralProjectionService.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. using SqlSugar;
  2. namespace Admin.NET.Plugin.AiDOP.DataPlatform;
  3. /// <summary>
  4. /// 第三方推送贴源行进入中立层。只投影已登记来源,未登记的实体直接跳过。
  5. /// </summary>
  6. public sealed class InboundNeutralProjectionService : ITransient
  7. {
  8. private readonly ISqlSugarClient _db;
  9. private readonly MdpNeutralSourceGate _gate;
  10. public InboundNeutralProjectionService(ISqlSugarClient db, MdpNeutralSourceGate gate)
  11. {
  12. _db = db;
  13. _gate = gate;
  14. }
  15. public async Task ProjectAsync(string entityCode, long tenantId, string sourceCode, CancellationToken cancellationToken = default)
  16. => await ProjectAsync(
  17. entityCode, tenantId, sourceCode, MdpSourceIdentity.ApiInbound, cancellationToken);
  18. public async Task ProjectAsync(
  19. string entityCode,
  20. long tenantId,
  21. string sourceCode,
  22. string writtenBy,
  23. CancellationToken cancellationToken = default)
  24. {
  25. cancellationToken.ThrowIfCancellationRequested();
  26. var code = (entityCode ?? "").Trim().ToUpperInvariant();
  27. var neutral = MdpSourceIdentity.NeutralCode(null, sourceCode);
  28. writtenBy = string.IsNullOrWhiteSpace(writtenBy) ? MdpSourceIdentity.ApiInbound : writtenBy.Trim();
  29. switch (code)
  30. {
  31. case "S6_WORK_ORDER_LINE":
  32. if (await _gate.AllowsAsync(tenantId, "WO_LINE_PROD", neutral, cancellationToken: cancellationToken))
  33. await ProjectWorkOrderAsync(tenantId, neutral, writtenBy, "PROD_TASK", "mdp_stg_wo_line", cancellationToken);
  34. break;
  35. case "S7_SALES_ORDER_LINE":
  36. if (await _gate.AllowsAsync(tenantId, "WO_LINE_SALES", neutral, cancellationToken: cancellationToken))
  37. await ProjectWorkOrderAsync(tenantId, neutral, writtenBy, "SALES_ORDER", "mdp_stg_wo_line", cancellationToken);
  38. break;
  39. case "S6_REPORT_TXN":
  40. if (await _gate.AllowsAsync(tenantId, "S6_REPORT", neutral, cancellationToken: cancellationToken))
  41. await ProjectReportAsync(tenantId, neutral, writtenBy, cancellationToken);
  42. break;
  43. case "S5_WORK_ORDER_BOM":
  44. if (await _gate.AllowsAsync(tenantId, "WO_BOM", neutral, cancellationToken: cancellationToken))
  45. await ProjectBomAsync(tenantId, neutral, writtenBy, cancellationToken);
  46. break;
  47. case "S7_FQC_TASK_TXN":
  48. if (await _gate.AllowsAsync(tenantId, "FQC_TASK", neutral, cancellationToken: cancellationToken))
  49. await ProjectFqcAsync(tenantId, neutral, writtenBy, cancellationToken);
  50. break;
  51. case "S5_INVENTORY_BALANCE_MONTHLY":
  52. if (await _gate.AllowsAsync(tenantId, "INV_BAL_MONTHLY", neutral, cancellationToken: cancellationToken))
  53. await ProjectBalanceMonthlyAsync(tenantId, neutral, writtenBy, cancellationToken);
  54. break;
  55. case "S2_WORK_ORDER_SCHEDULE":
  56. if (await _gate.AllowsAsync(tenantId, "WO_SCHEDULE", neutral, cancellationToken: cancellationToken))
  57. await ProjectScheduleAsync(tenantId, neutral, cancellationToken);
  58. break;
  59. case "S3_PURCHASE_ORDER":
  60. if (await _gate.AllowsAsync(tenantId, "PURCHASE", neutral, cancellationToken: cancellationToken))
  61. await ProjectPurchaseOrderAsync(tenantId, neutral, cancellationToken);
  62. break;
  63. case "S3_PURCHASE_RECEIPT":
  64. if (await _gate.AllowsAsync(tenantId, "PURCHASE", neutral, cancellationToken: cancellationToken))
  65. await ProjectPurchaseReceiptAsync(tenantId, neutral, cancellationToken);
  66. break;
  67. case "S4_SHIPMENT":
  68. case "S4_IQC":
  69. case "S4_RETURN":
  70. case "S4_SHORTAGE":
  71. if (await _gate.AllowsAsync(tenantId, "SUPPLIER_DELIVERY", neutral, cancellationToken: cancellationToken))
  72. await ProjectSupplierDeliveryAsync(code, tenantId, neutral, cancellationToken);
  73. break;
  74. case "S5_INVENTORY_TXN":
  75. if (await _gate.AllowsAsync(tenantId, "INV_TRANS", neutral, cancellationToken: cancellationToken))
  76. await _db.Ado.ExecuteCommandAsync(
  77. ProjectApiInventorySql(),
  78. new SugarParameter("@tid", tenantId),
  79. new SugarParameter("@src", neutral),
  80. new SugarParameter("@writtenBy", writtenBy),
  81. new SugarParameter("@now", DateTime.Now));
  82. break;
  83. }
  84. }
  85. private async Task ProjectWorkOrderAsync(long tenantId, string source, string writtenBy, string docType, string staging, CancellationToken cancellationToken)
  86. {
  87. cancellationToken.ThrowIfCancellationRequested();
  88. if (!await TableExistsAsync(staging)) return;
  89. await _db.Ado.ExecuteCommandAsync(
  90. $"""
  91. INSERT INTO mdp_std_work_order_line
  92. (tenant_id, factory_id, source_system, written_by, domain, doc_type, src_doc_type_raw,
  93. order_no, line_no, task_no, item_code, qty_planned, plan_finish_date,
  94. closed_flag, void_flag, approved_flag, source_row_id, source_biz_key, sync_batch_id, sync_time)
  95. SELECT @tid, 1, @src, @writtenBy,
  96. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Domain')),'null'),''),
  97. @doc, @doc,
  98. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.OrderNo')),'null'),
  99. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.LineNo')),'null') AS SIGNED),
  100. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.OrderNo')),'null'),
  101. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),
  102. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.QtyPlanned')),'null') AS DECIMAL(18,6)),
  103. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PlanFinishDate')),'null'),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  104. IF(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ClosedFlag')),'0') IN ('1','true'), 1, 0),
  105. IF(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.VoidFlag')),'0') IN ('1','true'), 1, 0),
  106. 1,
  107. IFNULL(s.source_row_id, s.source_biz_key), s.source_biz_key, IFNULL(s.sync_batch_id,''), NOW()
  108. FROM {staging} s
  109. WHERE s.tenant_id=@tid AND IFNULL(s.process_status,'PENDING')<>'DONE'
  110. ON DUPLICATE KEY UPDATE
  111. source_system=VALUES(source_system), item_code=VALUES(item_code),
  112. qty_planned=VALUES(qty_planned), sync_time=VALUES(sync_time)
  113. """,
  114. new SugarParameter("@tid", tenantId),
  115. new SugarParameter("@src", source),
  116. new SugarParameter("@writtenBy", writtenBy),
  117. new SugarParameter("@doc", docType));
  118. }
  119. private async Task ProjectReportAsync(long tenantId, string source, string writtenBy, CancellationToken cancellationToken)
  120. {
  121. cancellationToken.ThrowIfCancellationRequested();
  122. if (!await TableExistsAsync("mdp_stg_s6_report")) return;
  123. await _db.Ado.ExecuteCommandAsync(
  124. """
  125. INSERT INTO mdp_std_s6_report
  126. (tenant_id, factory_id, source_system, written_by, work_order_no, report_date, report_qty,
  127. source_row_id, source_biz_key, sync_batch_id, sync_time)
  128. SELECT @tid, 1, @src, @writtenBy,
  129. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.WorkOrderNo')),'null'),
  130. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ReportDate')),'null'),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  131. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ReportQty')),'null') AS DECIMAL(18,6)),
  132. IFNULL(s.source_row_id, s.source_biz_key), s.source_biz_key, IFNULL(s.sync_batch_id,''), NOW()
  133. FROM mdp_stg_s6_report s
  134. WHERE s.tenant_id=@tid AND s.source_table='S6_REPORT_TXN'
  135. ON DUPLICATE KEY UPDATE source_system=VALUES(source_system),
  136. report_qty=VALUES(report_qty), sync_time=VALUES(sync_time)
  137. """,
  138. new SugarParameter("@tid", tenantId),
  139. new SugarParameter("@src", source),
  140. new SugarParameter("@writtenBy", writtenBy));
  141. }
  142. private async Task ProjectScheduleAsync(long tenantId, string source, CancellationToken cancellationToken)
  143. {
  144. cancellationToken.ThrowIfCancellationRequested();
  145. if (!await TableExistsAsync("mdp_stg_schedule")) return;
  146. await _db.Ado.ExecuteCommandAsync(
  147. """
  148. INSERT INTO mdp_std_work_order_schedule
  149. (tenant_id, factory_id, source_system, doc_type, work_order, item_code,
  150. qty_ordered, qty_completed, due_date, status, prod_line,
  151. source_biz_key, sync_batch_id, sync_time)
  152. SELECT @tid, 1, @src,
  153. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.DocType')),'null'),'PROD_TASK'),
  154. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.WorkOrder')),'null'),
  155. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),
  156. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.QtyOrdered')),'null') AS DECIMAL(18,6)),
  157. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.QtyCompleted')),'null') AS DECIMAL(18,6)),
  158. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.DueDate')),'null'),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  159. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Status')),'null'),
  160. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ProdLine')),'null'),
  161. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')),
  162. IFNULL(s.sync_batch_id,''), NOW()
  163. FROM mdp_stg_schedule s
  164. WHERE s.tenant_id=@tid AND s.source_table='S2_WORK_ORDER_SCHEDULE'
  165. AND IFNULL(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.WorkOrder')),'') NOT IN ('','null')
  166. ON DUPLICATE KEY UPDATE
  167. source_system=VALUES(source_system), item_code=VALUES(item_code),
  168. qty_ordered=VALUES(qty_ordered), qty_completed=VALUES(qty_completed),
  169. due_date=VALUES(due_date), sync_time=VALUES(sync_time)
  170. """,
  171. new SugarParameter("@tid", tenantId),
  172. new SugarParameter("@src", source));
  173. }
  174. private async Task ProjectPurchaseOrderAsync(long tenantId, string source, CancellationToken cancellationToken)
  175. {
  176. cancellationToken.ThrowIfCancellationRequested();
  177. if (!await TableExistsAsync("mdp_stg_purchase_order")) return;
  178. await _db.Ado.ExecuteCommandAsync(
  179. """
  180. INSERT INTO mdp_std_purchase_order
  181. (tenant_id, factory_id, source_system, po_no, po_line, supplier_code, item_code,
  182. order_qty, due_date, order_date, status, source_biz_key, sync_batch_id, sync_time)
  183. SELECT @tid, 1, @src,
  184. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PoNo')),'null'),
  185. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PoLine')),'null'),
  186. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.SupplierCode')),'null'),
  187. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),
  188. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.OrderQty')),'null') AS DECIMAL(18,6)),
  189. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.DueDate')),'null'),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  190. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.OrderDate')),'null'),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  191. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Status')),'null'),
  192. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')),
  193. IFNULL(s.sync_batch_id,''), NOW()
  194. FROM mdp_stg_purchase_order s
  195. WHERE s.tenant_id=@tid AND s.source_table='S3_PURCHASE_ORDER'
  196. ON DUPLICATE KEY UPDATE
  197. source_system=VALUES(source_system), order_qty=VALUES(order_qty),
  198. status=VALUES(status), sync_time=VALUES(sync_time)
  199. """,
  200. new SugarParameter("@tid", tenantId),
  201. new SugarParameter("@src", source));
  202. }
  203. private async Task ProjectPurchaseReceiptAsync(long tenantId, string source, CancellationToken cancellationToken)
  204. {
  205. cancellationToken.ThrowIfCancellationRequested();
  206. if (!await TableExistsAsync("mdp_stg_purchase_receipt")) return;
  207. await _db.Ado.ExecuteCommandAsync(
  208. """
  209. INSERT INTO mdp_std_purchase_receipt
  210. (tenant_id, factory_id, source_system, domain, receiver, line, item_num,
  211. qty_received, pur_ord, supp, rct_date, source_biz_key, sync_batch_id, sync_time)
  212. SELECT @tid, 1, @src,
  213. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Domain')),'null'),''),
  214. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Receiver')),'null'),
  215. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Line')),'null') AS SIGNED),
  216. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),
  217. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.QtyReceived')),'null') AS DECIMAL(18,6)),
  218. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PoNo')),'null'),
  219. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.SupplierCode')),'null'),
  220. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ReceiptDate')),'null'),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  221. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')),
  222. IFNULL(s.sync_batch_id,''), NOW()
  223. FROM mdp_stg_purchase_receipt s
  224. WHERE s.tenant_id=@tid AND s.source_table='S3_PURCHASE_RECEIPT'
  225. ON DUPLICATE KEY UPDATE
  226. source_system=VALUES(source_system), qty_received=VALUES(qty_received),
  227. sync_time=VALUES(sync_time)
  228. """,
  229. new SugarParameter("@tid", tenantId),
  230. new SugarParameter("@src", source));
  231. }
  232. private async Task ProjectSupplierDeliveryAsync(string entityCode, long tenantId, string source, CancellationToken cancellationToken)
  233. {
  234. cancellationToken.ThrowIfCancellationRequested();
  235. var (table, std, sql) = entityCode switch
  236. {
  237. "S4_IQC" => ("mdp_stg_s4_iqc", "mdp_std_s4_iqc", """
  238. INSERT INTO mdp_std_s4_iqc
  239. (tenant_id, factory_id, source_system, po_no, po_line, supplier_code, item_code,
  240. receipt_qty, defect_qty, qc_result, receipt_date, source_biz_key, sync_batch_id, sync_time)
  241. SELECT @tid, 1, @src,
  242. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PoNo')),'null'),
  243. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PoLine')),'null'),
  244. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.SupplierCode')),'null'),''),
  245. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),''),
  246. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ReceiptQty')),'null') AS DECIMAL(18,6)),
  247. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.DefectQty')),'null') AS DECIMAL(18,6)),
  248. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.QcResult')),'null'),
  249. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ReceiptDate')),'null'),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  250. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')), IFNULL(s.sync_batch_id,''), NOW()
  251. FROM mdp_stg_s4_iqc s
  252. WHERE s.tenant_id=@tid AND s.source_table='S4_IQC'
  253. ON DUPLICATE KEY UPDATE
  254. source_system=VALUES(source_system), receipt_qty=VALUES(receipt_qty),
  255. defect_qty=VALUES(defect_qty), sync_time=VALUES(sync_time)
  256. """),
  257. "S4_RETURN" => ("mdp_stg_s4_return", "mdp_std_s4_return", """
  258. INSERT INTO mdp_std_s4_return
  259. (tenant_id, factory_id, source_system, po_no, po_line, supplier_code, item_code,
  260. return_qty, return_reason, return_status, source_biz_key, sync_batch_id, sync_time)
  261. SELECT @tid, 1, @src,
  262. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PoNo')),'null'),
  263. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PoLine')),'null'),
  264. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.SupplierCode')),'null'),''),
  265. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),''),
  266. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ReturnQty')),'null') AS DECIMAL(18,6)),
  267. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ReturnReason')),'null'),
  268. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ReturnStatus')),'null'),
  269. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')), IFNULL(s.sync_batch_id,''), NOW()
  270. FROM mdp_stg_s4_return s
  271. WHERE s.tenant_id=@tid AND s.source_table='S4_RETURN'
  272. ON DUPLICATE KEY UPDATE
  273. source_system=VALUES(source_system), return_qty=VALUES(return_qty),
  274. sync_time=VALUES(sync_time)
  275. """),
  276. "S4_SHORTAGE" => ("mdp_stg_s4_shortage", "mdp_std_s4_shortage", """
  277. INSERT INTO mdp_std_s4_shortage
  278. (tenant_id, factory_id, source_system, work_order, supplier_code, item_code,
  279. shortage_qty, risk_level, need_date, source_biz_key, sync_batch_id, sync_time)
  280. SELECT @tid, 1, @src,
  281. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.WorkOrder')),'null'),
  282. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.SupplierCode')),'null'),''),
  283. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),''),
  284. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ShortageQty')),'null') AS DECIMAL(18,6)),
  285. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.RiskLevel')),'null'),'MEDIUM'),
  286. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.NeedDate')),'null'),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  287. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')), IFNULL(s.sync_batch_id,''), NOW()
  288. FROM mdp_stg_s4_shortage s
  289. WHERE s.tenant_id=@tid AND s.source_table='S4_SHORTAGE'
  290. ON DUPLICATE KEY UPDATE
  291. source_system=VALUES(source_system), shortage_qty=VALUES(shortage_qty),
  292. sync_time=VALUES(sync_time)
  293. """),
  294. _ => ("mdp_stg_s4_shipment", "mdp_std_s4_shipment", """
  295. INSERT INTO mdp_std_s4_shipment
  296. (tenant_id, factory_id, source_system, shipment_no, po_no, po_line, supplier_code, item_code,
  297. ship_qty, ship_date, source_biz_key, sync_batch_id, sync_time)
  298. SELECT @tid, 1, @src,
  299. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ShipmentNo')),'null'),
  300. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PoNo')),'null'),
  301. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PoLine')),'null'),
  302. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.SupplierCode')),'null'),''),
  303. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),''),
  304. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ShipQty')),'null') AS DECIMAL(18,6)),
  305. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ShipDate')),'null'),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  306. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')), IFNULL(s.sync_batch_id,''), NOW()
  307. FROM mdp_stg_s4_shipment s
  308. WHERE s.tenant_id=@tid AND s.source_table='S4_SHIPMENT'
  309. ON DUPLICATE KEY UPDATE
  310. source_system=VALUES(source_system), ship_qty=VALUES(ship_qty),
  311. ship_date=VALUES(ship_date), sync_time=VALUES(sync_time)
  312. """)
  313. };
  314. _ = std;
  315. if (!await TableExistsAsync(table)) return;
  316. await _db.Ado.ExecuteCommandAsync(sql, new SugarParameter("@tid", tenantId), new SugarParameter("@src", source));
  317. }
  318. private async Task ProjectBomAsync(long tenantId, string source, string writtenBy, CancellationToken cancellationToken)
  319. {
  320. cancellationToken.ThrowIfCancellationRequested();
  321. if (!await TableExistsAsync("mdp_stg_wo_bom")) return;
  322. await _db.Ado.ExecuteCommandAsync(
  323. """
  324. INSERT INTO mdp_std_work_order_bom
  325. (tenant_id, factory_id, source_system, written_by, domain, order_no, order_line_no,
  326. item_code, qty_required, unit, source_row_id, source_biz_key, sync_batch_id, sync_time)
  327. SELECT @tid, 1, @src, @writtenBy,
  328. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Domain')),'null'),''),
  329. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.OrderNo')),'null'),
  330. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.LineNo')),'null'),
  331. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),
  332. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.QtyRequired')),'null') AS DECIMAL(18,6)),
  333. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Unit')),'null'),
  334. IFNULL(s.source_row_id, s.source_biz_key),
  335. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')),
  336. IFNULL(s.sync_batch_id,''), NOW()
  337. FROM mdp_stg_wo_bom s
  338. WHERE s.tenant_id=@tid AND s.source_table='S5_WORK_ORDER_BOM'
  339. AND IFNULL(s.process_status,'PENDING')<>'DONE'
  340. ON DUPLICATE KEY UPDATE
  341. source_system=VALUES(source_system), item_code=VALUES(item_code), qty_required=VALUES(qty_required),
  342. unit=VALUES(unit), sync_time=VALUES(sync_time)
  343. """,
  344. new SugarParameter("@tid", tenantId),
  345. new SugarParameter("@src", source),
  346. new SugarParameter("@writtenBy", writtenBy));
  347. }
  348. private async Task ProjectFqcAsync(long tenantId, string source, string writtenBy, CancellationToken cancellationToken)
  349. {
  350. cancellationToken.ThrowIfCancellationRequested();
  351. if (!await TableExistsAsync("mdp_stg_fqc_pull")) return;
  352. await _db.Ado.ExecuteCommandAsync(
  353. """
  354. INSERT INTO mdp_std_fqc_task
  355. (tenant_id, source_system, written_by, bill_no, production_order_no, material_code, qty,
  356. sales_order_no, domain, source_row_id, source_biz_key, sync_batch_id, sync_time)
  357. SELECT @tid, @src, @writtenBy,
  358. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.BillNo')),'null'),
  359. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ProductionOrderNo')),'null'),
  360. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.MaterialCode')),'null'),
  361. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Qty')),'null') AS DECIMAL(18,6)),
  362. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.SalesOrderNo')),'null'),
  363. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Domain')),'null'),
  364. IFNULL(s.source_row_id, s.source_biz_key),
  365. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')),
  366. IFNULL(s.sync_batch_id,''), NOW()
  367. FROM mdp_stg_fqc_pull s
  368. WHERE s.tenant_id=@tid AND s.source_table='S7_FQC_TASK_TXN'
  369. AND IFNULL(s.process_status,'PENDING')<>'DONE'
  370. ON DUPLICATE KEY UPDATE
  371. source_system=VALUES(source_system), material_code=VALUES(material_code),
  372. qty=VALUES(qty), sync_time=VALUES(sync_time)
  373. """,
  374. new SugarParameter("@tid", tenantId),
  375. new SugarParameter("@src", source),
  376. new SugarParameter("@writtenBy", writtenBy));
  377. }
  378. private async Task ProjectBalanceMonthlyAsync(long tenantId, string source, string writtenBy, CancellationToken cancellationToken)
  379. {
  380. cancellationToken.ThrowIfCancellationRequested();
  381. if (!await TableExistsAsync("mdp_stg_inv_bal_monthly")) return;
  382. await _db.Ado.ExecuteCommandAsync(
  383. """
  384. INSERT INTO mdp_std_inventory_balance_monthly
  385. (tenant_id, factory_id, source_system, written_by, period_ym,
  386. category_code, category_name, warehouse_code, warehouse_name, item_code,
  387. avg_balance_amount, issue_cost_amount, source_biz_key, sync_batch_id, sync_time)
  388. SELECT @tid, 1, @src, @writtenBy,
  389. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.PeriodYm')),'null'),
  390. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.CategoryCode')),'null'),''),
  391. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.CategoryName')),'null'),
  392. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.WarehouseCode')),'null'),''),
  393. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.WarehouseName')),'null'),
  394. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'),''),
  395. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.AvgBalanceAmount')),'null') AS DECIMAL(18,6)),
  396. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.IssueCostAmount')),'null') AS DECIMAL(18,6)),
  397. IFNULL(s.source_biz_key, IFNULL(s.source_row_id,'')),
  398. IFNULL(s.sync_batch_id,''), NOW()
  399. FROM mdp_stg_inv_bal_monthly s
  400. WHERE s.tenant_id=@tid AND s.source_table='S5_INVENTORY_BALANCE_MONTHLY'
  401. AND IFNULL(s.process_status,'PENDING')<>'DONE'
  402. ON DUPLICATE KEY UPDATE
  403. source_system=VALUES(source_system), avg_balance_amount=VALUES(avg_balance_amount),
  404. issue_cost_amount=VALUES(issue_cost_amount),
  405. sync_time=VALUES(sync_time)
  406. """,
  407. new SugarParameter("@tid", tenantId),
  408. new SugarParameter("@src", source),
  409. new SugarParameter("@writtenBy", writtenBy));
  410. }
  411. private static string ProjectApiInventorySql()
  412. {
  413. const string biz = "NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.BizDocType')),'null')";
  414. const string trans = "NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.TransType')),'null')";
  415. const string src = "COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.SrcTransType')),'null'), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.BizDocType')),'null'))";
  416. return $"""
  417. INSERT INTO mdp_std_inv_trans
  418. (tenant_id, source_system, written_by, domain, src_rec_id, item_num, qty_change, location,
  419. lot_serial, create_user, begin_balance, end_balance, doc_qty, line_closed_flag,
  420. trans_time, eff_date, approved_time, approved_flag, void_flag, summary_flag,
  421. biz_doc_type, src_biz_doc_type_raw, trans_type, src_trans_type_raw, ref_task_no,
  422. history_from, as_of, sync_batch_id, dimension1, dimension2)
  423. SELECT
  424. @tid, @src, @writtenBy,
  425. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Domain')),'null'),''),
  426. s.source_row_id,
  427. COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemCode')),'null'), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.code')),'null')),
  428. CAST(COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Qty')),'null'), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.sl')),'null')) AS DECIMAL(18,6)),
  429. COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Location')),'null'), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Loc')),'null')),
  430. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.LotSerial')),'null'),
  431. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.CreateUser')),'null'),
  432. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.BeginBalance')),'null') AS DECIMAL(18,6)),
  433. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.EndBalance')),'null') AS DECIMAL(18,6)),
  434. CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.DocQty')),'null') AS DECIMAL(18,6)),
  435. IFNULL(CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.LineClosedFlag')),'null') AS SIGNED), 0),
  436. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.TransTime')),'null'), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.addtime')),'null')),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  437. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.DocDate')),'null'), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.date0')),'null')),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  438. IFNULL(
  439. STR_TO_DATE(SUBSTRING_INDEX(REPLACE(COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ApprovedTime')),'null'), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.shtime')),'null')),'T',' '),'.',1),'%Y-%m-%d %H:%i:%s'),
  440. @now),
  441. IFNULL(CAST(COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ApprovedFlag')),'null'), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.shyn')),'null')) AS SIGNED), 1),
  442. IFNULL(CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.VoidFlag')),'null') AS SIGNED), 0),
  443. IFNULL(CAST(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.SummaryFlag')),'null') AS SIGNED), 0),
  444. {NeutralTransTypeCodes.KnownBizDocCase(biz)},
  445. {biz},
  446. {NeutralTransTypeCodes.ApiTransTypeCase(trans, biz)},
  447. {src},
  448. COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.RefTaskNo')),'null'), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.rwnoid')),'null')),
  449. @now, @now, IFNULL(s.sync_batch_id,''),
  450. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Dimension1')),'null'), ''),
  451. IFNULL(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Dimension2')),'null'), '')
  452. FROM mdp_stg_inv_trans_inbound s
  453. WHERE s.tenant_id=@tid
  454. AND s.source_table='S5_INVENTORY_TXN'
  455. AND s.source_row_id IS NOT NULL AND s.source_row_id<>''
  456. ON DUPLICATE KEY UPDATE
  457. source_system=VALUES(source_system), written_by=VALUES(written_by),
  458. item_num=VALUES(item_num), qty_change=VALUES(qty_change), location=VALUES(location),
  459. lot_serial=VALUES(lot_serial), create_user=VALUES(create_user),
  460. begin_balance=VALUES(begin_balance), end_balance=VALUES(end_balance),
  461. doc_qty=VALUES(doc_qty), line_closed_flag=VALUES(line_closed_flag),
  462. dimension1=VALUES(dimension1), dimension2=VALUES(dimension2),
  463. approved_time=VALUES(approved_time), approved_flag=VALUES(approved_flag),
  464. void_flag=VALUES(void_flag), summary_flag=VALUES(summary_flag),
  465. biz_doc_type=VALUES(biz_doc_type), src_biz_doc_type_raw=VALUES(src_biz_doc_type_raw),
  466. trans_type=VALUES(trans_type), src_trans_type_raw=VALUES(src_trans_type_raw),
  467. ref_task_no=VALUES(ref_task_no), sync_batch_id=VALUES(sync_batch_id), as_of=VALUES(as_of)
  468. """;
  469. }
  470. private async Task<bool> TableExistsAsync(string table)
  471. {
  472. var n = await _db.Ado.GetIntAsync(
  473. "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=@t",
  474. new SugarParameter("@t", table));
  475. return n > 0;
  476. }
  477. }