namespace Admin.NET.Plugin.AiDOP.WorkOrder; /// 从资源检查结果同步工单物料明细(WorkOrdDetail)。 public class WorkOrderMaterialDetailSyncService : ITransient { private readonly ISqlSugarClient _db; public WorkOrderMaterialDetailSyncService(ISqlSugarClient db) { _db = db; } public async Task EnsureFromResourceCheckAsync(long tenantId, string workOrd, string account) { var existing = await _db.Ado.GetIntAsync( """ SELECT COUNT(*) FROM WorkOrdDetail WHERE tenant_id = @TenantId AND WorkOrd = @WorkOrd AND IFNULL(IsActive, 0) = 1 """, new SugarParameter("@TenantId", tenantId), new SugarParameter("@WorkOrd", workOrd)); if (existing > 0) return 0; var wo = await LoadWorkOrderAsync(tenantId, workOrd); if (wo is null) return 0; var components = await LoadResourceCheckComponentsAsync(tenantId, workOrd); if (components.Count == 0) return 0; var now = DateTime.Now; var line = 1; foreach (var c in components) { await _db.Ado.ExecuteCommandAsync( """ INSERT INTO WorkOrdDetail ( WorkOrdMasterRecID, `Domain`, WorkOrd, LineNum, ItemNum, Op, Location, QtyRequired, QtyPosted, UM, IsActive, IsConfirm, CreateUser, CreateTime, UpdateUser, UpdateTime, tenant_id ) VALUES ( @MasterRecId, @Domain, @WorkOrd, @LineNum, @ItemNum, @Op, @Location, @QtyRequired, 0, @UM, 1, 0, @User, @Now, @User, @Now, @TenantId ) """, new SugarParameter("@MasterRecId", wo.RecId), new SugarParameter("@Domain", wo.Domain ?? tenantId.ToString()), new SugarParameter("@WorkOrd", workOrd), new SugarParameter("@LineNum", line), new SugarParameter("@ItemNum", c.ItemNumber), new SugarParameter("@Op", c.Op), new SugarParameter("@Location", c.Location ?? (object)DBNull.Value), new SugarParameter("@QtyRequired", c.QtyRequired), new SugarParameter("@UM", c.Unit ?? (object)DBNull.Value), new SugarParameter("@User", account), new SugarParameter("@Now", now), new SugarParameter("@TenantId", tenantId)); line++; } return components.Count; } private async Task LoadWorkOrderAsync(long tenantId, string workOrd) { var rows = await _db.Ado.SqlQueryAsync( """ SELECT RecID AS RecId, `Domain`, ItemNum FROM WorkOrdMaster WHERE tenant_id = @TenantId AND WorkOrd = @WorkOrd LIMIT 1 """, new SugarParameter("@TenantId", tenantId), new SugarParameter("@WorkOrd", workOrd)); return rows.FirstOrDefault(); } private async Task> LoadResourceCheckComponentsAsync(long tenantId, string workOrd) { return await _db.Ado.SqlQueryAsync( """ SELECT bce.item_number AS ItemNumber, CASE WHEN IFNULL(bce.use_qty, 0) > 0 THEN bce.use_qty ELSE IFNULL(bce.needCount, 0) END AS QtyRequired, IFNULL(bce.unit, im.Um) AS Unit, IFNULL(im.Location, '') AS Location, IFNULL(bce.Op, 0) AS Op FROM b_examine_result ber INNER JOIN b_bom_child_examine bce ON ber.Id = bce.examine_id AND bce.is_use = 1 LEFT JOIN ItemMaster im ON bce.item_number = im.ItemNum WHERE ber.tenant_id = @TenantId AND ber.IsDeleted = 0 AND ber.morder_no = @WorkOrd AND ber.Id = ( SELECT br.Id FROM b_examine_result br WHERE br.tenant_id = @TenantId AND br.morder_no = @WorkOrd AND br.IsDeleted = 0 ORDER BY br.create_time DESC LIMIT 1 ) AND IFNULL(bce.num, '') <> '1' AND IFNULL(bce.backflush, 0) = 0 AND IFNULL(bce.erp_cls, 3) <> 4 AND ( IFNULL(bce.use_qty, 0) > 0 OR IFNULL(bce.needCount, 0) > 0 ) ORDER BY bce.id """, new SugarParameter("@TenantId", tenantId), new SugarParameter("@WorkOrd", workOrd)); } private sealed class WorkOrderRow { public long RecId { get; set; } public string? Domain { get; set; } public string? ItemNum { get; set; } } private sealed class ComponentRow { public string ItemNumber { get; set; } = string.Empty; public decimal QtyRequired { get; set; } public string? Unit { get; set; } public string? Location { get; set; } public int Op { get; set; } } }