ResourceCheckResultWriter.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. using Yitter.IdGenerator;
  2. namespace Admin.NET.Plugin.AiDOP.Order;
  3. /// <summary>将资源检查结果写入 b_examine_result / b_bom_child_examine。</summary>
  4. public class ResourceCheckResultWriter : ITransient
  5. {
  6. private readonly ISqlSugarClient _db;
  7. private readonly CapacityDateCalculator _capacityCalc;
  8. public ResourceCheckResultWriter(ISqlSugarClient db, CapacityDateCalculator capacityCalc)
  9. {
  10. _db = db;
  11. _capacityCalc = capacityCalc;
  12. }
  13. public async Task<OrderResourceCheckResult> WriteAsync(
  14. OrderWorkOrderGenerationService.OrderHeader order,
  15. OrderWorkOrderGenerationService.OrderEntryLine entry,
  16. string workOrd,
  17. long? morderId,
  18. IReadOnlyList<ResourceCheckBomLine> lines,
  19. string account,
  20. DateTime now,
  21. long bangId = 0,
  22. string checkScope = "REVIEW")
  23. {
  24. await InvalidatePreviousAsync(entry.Id, entry.TenantId, workOrd, now);
  25. var examineId = YitIdHelper.NextId();
  26. var needQty = entry.Qty ?? 0;
  27. var needTime = entry.SysCapacityDate ?? entry.PlanDate ?? now;
  28. // 对根行(Level=1)执行产能计算,更新 KittingTime
  29. var rootLine = lines.FirstOrDefault(x => x.Level == 1 && x.IsUse == 1 && x.LackQty > 0);
  30. if (rootLine != null)
  31. {
  32. var planDate = entry.PlanDate ?? now;
  33. rootLine.KittingTime = await _capacityCalc.CalculateAsync(
  34. rootLine.ItemNumber, rootLine.LackQty, needTime, planDate, entry.TenantId);
  35. }
  36. var kittingTime = lines
  37. .Where(x => x.IsUse == 1 && x.LackQty > 0)
  38. .Select(x => x.KittingTime)
  39. .DefaultIfEmpty(needTime)
  40. .Max();
  41. var factoryId = entry.FactoryId ?? order.FactoryId ?? entry.TenantId;
  42. var companyId = entry.CompanyId ?? factoryId;
  43. await _db.Ado.ExecuteCommandAsync(
  44. """
  45. INSERT INTO b_examine_result (
  46. Id, sorderid, bill_no, sentry_id, entry_seq, morder_id, morder_no, bom_number,
  47. need_qty, need_time, earliest_times, latest_times, order_statr_time, kitting_times,
  48. sys_capacity_date, sys_material_date,
  49. bangid, check_scope, net_scope,
  50. create_by_name, create_time, update_by_name, update_time,
  51. tenant_id, factory_id, company_id, IsDeleted
  52. ) VALUES (
  53. @Id, @SorderId, @BillNo, @SentryId, @EntrySeq, @MorderId, @MorderNo, @BomNumber,
  54. @NeedQty, @NeedTime, @NeedTime, @NeedTime, @NeedTime, @KittingTime,
  55. @NeedTime, @KittingTime,
  56. @BangId, @CheckScope, @NetScope,
  57. @User, @Now, @User, @Now,
  58. @TenantId, @FactoryId, @CompanyId, 0
  59. )
  60. """,
  61. new SugarParameter("@Id", examineId),
  62. new SugarParameter("@SorderId", order.Id),
  63. new SugarParameter("@BillNo", order.BillNo ?? entry.BillNo ?? string.Empty),
  64. new SugarParameter("@SentryId", entry.Id),
  65. new SugarParameter("@EntrySeq", entry.EntrySeq ?? 0),
  66. new SugarParameter("@MorderId", morderId ?? (object)DBNull.Value),
  67. new SugarParameter("@MorderNo", workOrd),
  68. new SugarParameter("@BomNumber", entry.BomNumber ?? (object)DBNull.Value),
  69. new SugarParameter("@NeedQty", needQty),
  70. new SugarParameter("@NeedTime", needTime),
  71. new SugarParameter("@KittingTime", kittingTime ?? needTime),
  72. new SugarParameter("@BangId", bangId > 0 ? bangId : (object)DBNull.Value),
  73. new SugarParameter("@CheckScope", string.IsNullOrWhiteSpace(checkScope) ? "REVIEW" : checkScope.Trim()),
  74. new SugarParameter("@NetScope", bangId > 0 ? 1 : 0),
  75. new SugarParameter("@User", account),
  76. new SugarParameter("@Now", now),
  77. new SugarParameter("@TenantId", entry.TenantId),
  78. new SugarParameter("@FactoryId", factoryId),
  79. new SugarParameter("@CompanyId", companyId));
  80. var activeLines = lines.Where(x => x.IsUse == 1).ToList();
  81. foreach (var line in lines)
  82. {
  83. var childId = YitIdHelper.NextId();
  84. await _db.Ado.ExecuteCommandAsync(
  85. """
  86. INSERT INTO b_bom_child_examine (
  87. Id, examine_id, fid, parent_id, bom_child_id, bom_number, item_number, level, sentry_id,
  88. num, type, item_name, model, unit, erp_cls, erp_cls_name, backflush,
  89. qty, sqty, use_qty, self_lack_qty, lack_qty, mo_qty, make_qty, purchase_qty, purchase_occupy_qty,
  90. kitting_time, satisfy_time, isbom, haveicsubs, substitute_code, needCount, needCountNoloss,
  91. wastage, scrap, is_use, Op,
  92. create_by_name, create_time, update_by_name, update_time,
  93. tenant_id, factory_id, company_id, IsDeleted
  94. ) VALUES (
  95. @Id, @ExamineId, @Fid, @ParentId, @BomChildId, @BomNumber, @ItemNumber, @Level, @SentryId,
  96. @Num, @Type, @ItemName, @Model, @Unit, @ErpCls, @ErpClsName, @Backflush,
  97. @Qty, @Sqty, @UseQty, @SelfLackQty, @LackQty, @MoQty, @MakeQty, @PurchaseQty, @PurchaseOccupyQty,
  98. @KittingTime, @SatisfyTime, @IsBom, @HaveIcSubs, @SubstituteCode, @NeedCount, @NeedCountNoLoss,
  99. @Wastage, @Scrap, @IsUse, 0,
  100. @User, @Now, @User, @Now,
  101. @TenantId, @FactoryId, @CompanyId, 0
  102. )
  103. """,
  104. new SugarParameter("@Id", childId),
  105. new SugarParameter("@ExamineId", examineId),
  106. new SugarParameter("@Fid", line.Fid),
  107. new SugarParameter("@ParentId", line.ParentFid ?? (object)DBNull.Value),
  108. new SugarParameter("@BomChildId", line.BomChildId ?? (object)DBNull.Value),
  109. new SugarParameter("@BomNumber", line.BomNumber ?? (object)DBNull.Value),
  110. new SugarParameter("@ItemNumber", line.ItemNumber),
  111. new SugarParameter("@Level", line.Level),
  112. new SugarParameter("@SentryId", entry.Id),
  113. new SugarParameter("@Num", line.Num),
  114. new SugarParameter("@Type", line.Type),
  115. new SugarParameter("@ItemName", line.ItemName ?? (object)DBNull.Value),
  116. new SugarParameter("@Model", line.Model ?? (object)DBNull.Value),
  117. new SugarParameter("@Unit", line.Unit ?? (object)DBNull.Value),
  118. new SugarParameter("@ErpCls", line.ErpCls),
  119. new SugarParameter("@ErpClsName", line.ErpClsName ?? (object)DBNull.Value),
  120. new SugarParameter("@Backflush", line.Backflush),
  121. new SugarParameter("@Qty", line.Qty),
  122. new SugarParameter("@Sqty", line.Sqty),
  123. new SugarParameter("@UseQty", line.UseQty),
  124. new SugarParameter("@SelfLackQty", line.SelfLackQty),
  125. new SugarParameter("@LackQty", line.LackQty),
  126. new SugarParameter("@MoQty", line.MoQty),
  127. new SugarParameter("@MakeQty", line.MakeQty),
  128. new SugarParameter("@PurchaseQty", line.PurchaseQty),
  129. new SugarParameter("@PurchaseOccupyQty", line.PurchaseOccupyQty),
  130. new SugarParameter("@KittingTime", line.KittingTime ?? needTime),
  131. new SugarParameter("@SatisfyTime", line.SatisfyTime ?? needTime),
  132. new SugarParameter("@IsBom", line.IsBom),
  133. new SugarParameter("@HaveIcSubs", line.HaveIcSubs),
  134. new SugarParameter("@SubstituteCode", line.SubstituteCode ?? (object)DBNull.Value),
  135. new SugarParameter("@NeedCount", line.NeedCount),
  136. new SugarParameter("@NeedCountNoLoss", line.NeedCountNoLoss),
  137. new SugarParameter("@Wastage", line.Wastage),
  138. new SugarParameter("@Scrap", line.Scrap),
  139. new SugarParameter("@IsUse", line.IsUse),
  140. new SugarParameter("@User", account),
  141. new SugarParameter("@Now", now),
  142. new SugarParameter("@TenantId", entry.TenantId),
  143. new SugarParameter("@FactoryId", factoryId),
  144. new SugarParameter("@CompanyId", companyId));
  145. }
  146. var hasShortage = activeLines.Any(x => x.LackQty > 0);
  147. await UpdateMesMorderMaterialSituationAsync(workOrd, entry.TenantId, hasShortage, account, now);
  148. return new OrderResourceCheckResult
  149. {
  150. ExamineId = examineId,
  151. LineCount = activeLines.Count,
  152. HasShortage = hasShortage,
  153. KittingTime = kittingTime
  154. };
  155. }
  156. /// <summary>
  157. /// 让同一工单(或同一订单明细行)的历史齐套结果失效。
  158. ///
  159. /// 两个要点:
  160. /// 1) 以 morder_no 为主条件。sentry_id 只在 &gt; 0 时追加——工单不挂订单明细行时 entry.Id = 0,
  161. /// 若按 sentry_id = 0 失效会命中所有同类历史结果,把别的工单的结论一起标删。
  162. /// 2) SELECT 与 UPDATE 必须用同一套条件,否则会出现"子表明细已失效、头还是有效"的半失效状态。
  163. /// </summary>
  164. private async Task InvalidatePreviousAsync(long entryId, long tenantId, string morderNo, DateTime now)
  165. {
  166. var mo = (morderNo ?? "").Trim();
  167. if (mo.Length == 0 && entryId <= 0)
  168. return;
  169. var conds = new List<string>();
  170. var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
  171. if (mo.Length > 0)
  172. {
  173. conds.Add("morder_no = @MorderNo");
  174. pars.Add(new SugarParameter("@MorderNo", mo));
  175. }
  176. if (entryId > 0)
  177. {
  178. conds.Add("sentry_id = @EntryId");
  179. pars.Add(new SugarParameter("@EntryId", entryId));
  180. }
  181. var scope = $"tenant_id = @TenantId AND IsDeleted = 0 AND ({string.Join(" OR ", conds)})";
  182. var oldIds = await _db.Ado.SqlQueryAsync<long>(
  183. $"SELECT Id FROM b_examine_result WHERE {scope}", pars);
  184. if (oldIds.Count == 0)
  185. return;
  186. foreach (var examineId in oldIds)
  187. {
  188. await _db.Ado.ExecuteCommandAsync(
  189. """
  190. UPDATE b_bom_child_examine
  191. SET is_use = 0, update_time = @Now
  192. WHERE examine_id = @ExamineId
  193. """,
  194. new SugarParameter("@ExamineId", examineId),
  195. new SugarParameter("@Now", now));
  196. }
  197. var updPars = new List<SugarParameter>(pars) { new("@Now", now) };
  198. await _db.Ado.ExecuteCommandAsync(
  199. $"UPDATE b_examine_result SET IsDeleted = 1, update_time = @Now WHERE {scope}",
  200. updPars);
  201. }
  202. private async Task UpdateMesMorderMaterialSituationAsync(
  203. string workOrd,
  204. long tenantId,
  205. bool hasShortage,
  206. string account,
  207. DateTime now)
  208. {
  209. var situation = hasShortage ? "缺料" : "齐套";
  210. await _db.Ado.ExecuteCommandAsync(
  211. """
  212. UPDATE mes_morder
  213. SET MaterialSituation = @Situation,
  214. update_by_name = @User,
  215. update_time = @Now
  216. WHERE morder_no = @WorkOrd AND tenant_id = @TenantId AND IsDeleted = 0
  217. """,
  218. new SugarParameter("@Situation", situation),
  219. new SugarParameter("@User", account),
  220. new SugarParameter("@Now", now),
  221. new SugarParameter("@WorkOrd", workOrd),
  222. new SugarParameter("@TenantId", tenantId));
  223. }
  224. }