| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- using System.Text.Json;
- using Admin.NET.Plugin.AiDOP.DataPlatform.Executors;
- using Admin.NET.Plugin.AiDOP.DataPlatform.Sequence;
- using Admin.NET.Plugin.AiDOP.Entity.DataPlatform;
- using Admin.NET.Plugin.AiDOP.WorkOrder;
- using Microsoft.Extensions.Logging;
- using SqlSugar;
- namespace Admin.NET.Plugin.AiDOP.DataPlatform.Wms;
- /// <summary>
- /// WP4 · 下达建领料单。移植基准:旧 DOP ResourceExamineAppService.CreatePickBill / GenerateNbr。
- /// <list type="bullet">
- /// <item>本库更新工单状态;165 经 Outbox 回写 Status/Batch(及里程碑工序 Status→r)</item>
- /// <item>NbrMaster/NbrDetail 在 165 直写(需 identity RecID 回填明细 NbrRecID,与旧 UoW 一致;单号走 WP2)</item>
- /// <item>不做 MobileTask / QadTracking / 外协 PO / 库存占用(任务书本轮裁剪)</item>
- /// <item>D1:本动作不写 WorkOrdRouting C→W</item>
- /// </list>
- /// </summary>
- [ApiDescriptionSettings(Order = 327, Description = "下达建领料单")]
- [Route("api/aidop/wms-pick")]
- [AllowAnonymous]
- [NonUnify]
- public class CreatePickBillService : IDynamicApiController, ITransient
- {
- public const string TargetSource = "DOPDEMORQ_SQLSERVER";
- private const string NbrTypeBill = "SM";
- private const string NbrTypeAllocate = "sm";
- private readonly ISqlSugarClient _db;
- private readonly MdpSourceScopeFactory _scopeFactory;
- private readonly INbrSequenceService _seq;
- private readonly KeeperResolveService _keeper;
- private readonly MdpOutboxEnqueueService _enqueue;
- private readonly ILogger<CreatePickBillService> _logger;
- public CreatePickBillService(
- ISqlSugarClient db,
- MdpSourceScopeFactory scopeFactory,
- INbrSequenceService seq,
- KeeperResolveService keeper,
- MdpOutboxEnqueueService enqueue,
- ILogger<CreatePickBillService> logger)
- {
- _db = db;
- _scopeFactory = scopeFactory;
- _seq = seq;
- _keeper = keeper;
- _enqueue = enqueue;
- _logger = logger;
- }
- public sealed class CreatePickBillInput
- {
- /// <summary>工单号,逗号分隔;空则按 OrdDate 窗口取 Status=p</summary>
- public string? WorkOrd { get; set; }
- public string Domain { get; set; } = "8010";
- public string UserAccount { get; set; } = "aidop";
- public long TenantId { get; set; }
- }
- [DisplayName("下达生成领料单")]
- [HttpPost("create")]
- public async Task<object> Create([FromBody] CreatePickBillInput input, CancellationToken ct = default)
- {
- if (input == null) throw Oops.Oh("body 不能为空");
- var domain = string.IsNullOrWhiteSpace(input.Domain) ? "8010" : input.Domain.Trim();
- var user = string.IsNullOrWhiteSpace(input.UserAccount) ? "aidop" : input.UserAccount.Trim();
- var masters = await LoadCandidatesAsync(domain, input.WorkOrd, ct);
- if (masters.Count == 0)
- return new { ok = false, message = "没有需要下达的工单。" };
- var ss = await _scopeFactory.GetScopeAsync(TargetSource, ct);
- var already = await ss.Ado.SqlQueryAsync<string>(
- "SELECT DISTINCT WorkOrd FROM NbrMaster WHERE Domain=@d AND Type=@t",
- new SugarParameter("@d", domain),
- new SugarParameter("@t", NbrTypeBill));
- var alreadySet = new HashSet<string>(already.Where(x => !string.IsNullOrWhiteSpace(x)), StringComparer.OrdinalIgnoreCase);
- masters = masters.Where(m => !alreadySet.Contains(m.WorkOrd ?? "")).ToList();
- if (masters.Count == 0)
- return new { ok = false, message = "当前选择的工单包含已生成领料单。" };
- var workOrds = masters.Select(m => m.WorkOrd!).Distinct().ToList();
- var details = await _db.Queryable<WorkOrdDetail>()
- .Where(d => d.IsActive && workOrds.Contains(d.WorkOrd!))
- .ToListAsync(ct);
- if (details.Count == 0)
- return new { ok = false, message = "工单无物料明细,无法建领料单。" };
- var itemNums = details.Select(d => d.ItemNum!).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct().ToList();
- var itemMap = new Dictionary<string, ItemLite>(StringComparer.OrdinalIgnoreCase);
- if (itemNums.Count > 0)
- {
- // Universal.ItemMaster 实体列与本库不完全一致,只取建单所需字段
- var inSql = string.Join(",", itemNums.Select((_, k) => "@i" + k));
- var pars = itemNums.Select((n, k) => new SugarParameter("@i" + k, n)).ToArray();
- var items = await _db.Ado.SqlQueryAsync<ItemLite>(
- $"SELECT ItemNum, Descr, UM, Location FROM ItemMaster WHERE ItemNum IN ({inSql})", pars);
- foreach (var it in items)
- {
- if (!string.IsNullOrWhiteSpace(it.ItemNum) && !itemMap.ContainsKey(it.ItemNum))
- itemMap[it.ItemNum] = it;
- }
- }
- var keeperHits = await _keeper.ResolveByItemsAsync(domain, itemNums, ct);
- var keeperByItem = keeperHits.GroupBy(h => h.ItemNum, StringComparer.OrdinalIgnoreCase)
- .ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
- var draftMasters = new List<DraftNbrMaster>();
- var draftDetails = new List<DraftNbrDetail>();
- foreach (var wo in masters)
- {
- var wods = details.Where(d => string.Equals(d.WorkOrd, wo.WorkOrd, StringComparison.OrdinalIgnoreCase)).ToList();
- if (wods.Count == 0) continue;
- BuildOne(wo, wods, itemMap, keeperByItem, user, draftMasters, draftDetails);
- }
- if (draftMasters.Count == 0)
- return new { ok = false, message = "未生成任何领料单(明细为空或物料无效)。" };
- var nbrs = await _seq.AllocateAsync(NbrTypeAllocate, draftMasters.Count, domain, user, ct);
- if (nbrs.Count < draftMasters.Count)
- throw Oops.Oh($"取号不足:需要 {draftMasters.Count},得到 {nbrs.Count}");
- for (var i = 0; i < draftMasters.Count; i++)
- {
- var nbr = nbrs[i];
- draftMasters[i].Nbr = nbr;
- var woTail = Tail(draftMasters[i].WorkOrd);
- draftMasters[i].Address = woTail;
- draftMasters[i].Ufld1 = woTail;
- foreach (var d in draftDetails.Where(x => x.TempKey == draftMasters[i].TempKey))
- {
- d.Nbr = nbr;
- d.Address = woTail;
- d.OrdNbr = woTail;
- d.ERPfld1 = woTail;
- d.OrdLine = d.Line;
- d.ERPfld2 = d.Line.ToString();
- }
- }
- // 165 直写领料主从(拿 RecID)
- await InsertNbrOn165Async(ss, draftMasters, draftDetails, ct);
- // 本库工单状态
- var touchedOrds = draftMasters.Select(x => x.WorkOrd).Distinct().ToList();
- var now = DateTime.Now;
- foreach (var wo in masters.Where(m => touchedOrds.Contains(m.WorkOrd!)))
- {
- var batch = Tail(wo.WorkOrd!);
- await _db.Updateable<WorkOrdMaster>()
- .SetColumns(m => new WorkOrdMaster
- {
- Status = "r",
- Batch = batch,
- UpdateUser = user,
- UpdateTime = now
- })
- .Where(m => m.WorkOrd == wo.WorkOrd)
- .ExecuteCommandAsync(ct);
- }
- await _db.Updateable<WorkOrdRouting>()
- .SetColumns(r => new WorkOrdRouting { Status = "r", UpdateUser = user, UpdateTime = now })
- .Where(r => touchedOrds.Contains(r.WorkOrd!) && r.IsActive
- && r.Status != null && r.Status.ToLower() != "c" && r.Status.ToUpper() != "W")
- .ExecuteCommandAsync(ct);
- // Outbox:165 工单头 UPSERT(无则插入计划侧最小集,有则只改 Status/Batch)
- var trace = $"pick|{domain}|{DateTime.Now:yyyyMMddHHmmss}|{Guid.NewGuid():N}"[..48];
- var enqueued = 0;
- var masterByOrd = masters.Where(m => touchedOrds.Contains(m.WorkOrd!))
- .GroupBy(m => m.WorkOrd!, StringComparer.OrdinalIgnoreCase)
- .ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
- foreach (var wo in touchedOrds)
- {
- var batch = Tail(wo);
- masterByOrd.TryGetValue(wo, out var local);
- var insert = BuildWorkOrdInsert(domain, wo, batch, user, now, local);
- var update = new Dictionary<string, object?>
- {
- ["Status"] = "r",
- ["Batch"] = batch,
- ["UpdateUser"] = Trunc(user, 24),
- ["UpdateTime"] = now.ToString("yyyy-MM-dd HH:mm:ss")
- };
- if (await EnqueueAsync(input.TenantId, $"{trace}|wom|{wo}", "PICK_WOM_UPSERT", new
- {
- op = "UPSERT",
- table = "WorkOrdMaster",
- keys = new Dictionary<string, object?> { ["Domain"] = domain, ["WorkOrd"] = wo },
- update,
- expect = new Dictionary<string, object?>(),
- insert
- }, ct)) enqueued++;
- }
- // WorkOrdRouting 多行 UPDATE:Outbox 执行器按全 keys 等值,不适合「WorkOrd 下多工序」。
- // 与 Nbr 相同,里程碑工序在 165 直写(仅 MilestoneOp=1 且 Status<>C)。
- await ss.Ado.ExecuteCommandAsync(
- @"UPDATE WorkOrdRouting
- SET Status='r', UpdateUser=@u, UpdateTime=@t
- WHERE Domain=@d AND WorkOrd IN (" + string.Join(",", touchedOrds.Select((_, i) => "@w" + i)) + @")
- AND ISNULL(MilestoneOp,0)=1
- AND ISNULL(Status,'') <> 'C'
- AND ISNULL(Status,'') <> 'c'",
- BuildInParams(domain, user, now, touchedOrds));
- _logger.LogInformation(
- "[CreatePickBill] domain={Domain} workOrds={Count} nbrs={Nbrs} outbox={Outbox} trace={Trace}",
- domain, touchedOrds.Count, draftMasters.Count, enqueued, trace);
- return new
- {
- ok = true,
- message = "ok",
- trace,
- workOrds = touchedOrds,
- nbrs = draftMasters.Select(m => new { m.WorkOrd, m.Nbr, m.User1, detailCount = draftDetails.Count(d => d.Nbr == m.Nbr) }),
- outboxEnqueued = enqueued
- };
- }
- private async Task<List<WorkOrdMaster>> LoadCandidatesAsync(string domain, string? workOrdCsv, CancellationToken ct)
- {
- if (string.IsNullOrWhiteSpace(workOrdCsv))
- {
- var from = DateTime.Now.Date.AddDays(1);
- var to = DateTime.Now.Date.AddDays(4);
- return await _db.Queryable<WorkOrdMaster>()
- .Where(m => m.Domain == domain
- && m.OrdDate >= from && m.OrdDate < to
- && m.Status != null && m.Status.ToLower() == "p")
- .ToListAsync(ct);
- }
- var list = workOrdCsv.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
- if (list.Length == 0) return new List<WorkOrdMaster>();
- // 显式工单号:不强制 Domain/本库仍为 p(本库 Domain 可能是租户号;下达可能已置 r)
- return await _db.Queryable<WorkOrdMaster>()
- .Where(m => list.Contains(m.WorkOrd!)
- && m.Status != null
- && m.Status.ToLower() != "c"
- && m.Status.ToLower() != "w")
- .ToListAsync(ct);
- }
- private static Dictionary<string, object?> BuildWorkOrdInsert(
- string domain, string workOrd, string batch, string user, DateTime now, WorkOrdMaster? local)
- {
- var insert = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase)
- {
- ["Domain"] = domain,
- ["WorkOrd"] = workOrd,
- ["ID"] = workOrd,
- ["Status"] = "r",
- ["Batch"] = batch,
- ["ItemNum"] = local?.ItemNum ?? "",
- ["Site"] = local?.Site ?? "",
- ["Typed"] = local?.Typed ?? "",
- ["QtyOrded"] = local?.QtyOrded ?? 0m,
- ["ProdLine"] = local?.ProdLine ?? "",
- ["Location"] = local?.Location ?? "",
- ["Priority"] = local?.Priority ?? 0m,
- ["Urgent"] = local?.Urgent ?? 0,
- ["ItemName"] = local?.ItemName ?? "",
- ["Department"] = local?.Department ?? "",
- ["RoutingCode"] = local?.RoutingCode ?? "",
- ["BOMFormula"] = local?.BOMFormula ?? "",
- ["Project"] = local?.Project ?? "",
- ["Drawing"] = local?.Drawing ?? "",
- ["Rev"] = local?.Rev ?? "",
- ["CustNo"] = local?.CustNo ?? "",
- ["BusinessID"] = local?.BusinessID ?? 0L,
- ["IsActive"] = true,
- ["IsConfirm"] = local?.IsConfirm ?? false,
- ["CreateUser"] = Trunc(local?.CreateUser ?? user, 24),
- ["UpdateUser"] = Trunc(user, 24),
- ["CreateTime"] = (local?.CreateTime ?? now).ToString("yyyy-MM-dd HH:mm:ss"),
- ["UpdateTime"] = now.ToString("yyyy-MM-dd HH:mm:ss")
- };
- if (local?.OrdDate != null)
- insert["OrdDate"] = local.OrdDate.Value.ToString("yyyy-MM-dd HH:mm:ss");
- if (local?.DueDate != null)
- insert["DueDate"] = local.DueDate.Value.ToString("yyyy-MM-dd HH:mm:ss");
- if (local?.ReleaseDate != null)
- insert["ReleaseDate"] = local.ReleaseDate.Value.ToString("yyyy-MM-dd HH:mm:ss");
- return insert;
- }
- private static void BuildOne(
- WorkOrdMaster wo,
- List<WorkOrdDetail> wods,
- Dictionary<string, ItemLite> itemMap,
- Dictionary<string, KeeperResolveService.KeeperHit> keeperByItem,
- string userAccount,
- List<DraftNbrMaster> masters,
- List<DraftNbrDetail> details)
- {
- var today = DateTime.Now.Date;
- var ord = (wo.OrdDate ?? today).Date;
- var eff = ord.AddDays(-1);
- if (eff < today) eff = today;
- var start = eff;
- var temp = Guid.NewGuid().ToString("N");
- var keepers = new List<string>();
- short line = 1;
- var agg = new Dictionary<string, DraftNbrDetail>(StringComparer.OrdinalIgnoreCase);
- foreach (var a in wods)
- {
- if (string.IsNullOrWhiteSpace(a.ItemNum)) continue;
- itemMap.TryGetValue(a.ItemNum, out var im);
- var locFrom = !string.IsNullOrWhiteSpace(a.Location)
- ? a.Location!
- : (im?.Location ?? "");
- if (keeperByItem.TryGetValue(a.ItemNum, out var kh) && !string.IsNullOrWhiteSpace(kh.Employee))
- keepers.Add(kh.Employee);
- if (agg.TryGetValue(a.ItemNum, out var exist))
- {
- exist.QtyOrd += a.QtyRequired;
- exist.CurrQtyOpened += a.QtyRequired;
- continue;
- }
- var d = new DraftNbrDetail
- {
- TempKey = temp,
- Domain = wo.Domain ?? "8010",
- Type = NbrTypeBill,
- ItemNum = a.ItemNum,
- QtyFrom = 0,
- QtyTo = 0,
- LocationFrom = locFrom,
- LocationTo = wo.Location ?? "",
- WorkOrd = wo.WorkOrd ?? "",
- QtyOrd = a.QtyRequired,
- CurrQtyOpened = a.QtyRequired,
- Line = line++,
- UM = im?.UM ?? "",
- LotSerial = a.LotSerial ?? "",
- ItemName = im?.Descr ?? "",
- Status = "",
- CreateUser = userAccount,
- UpdateUser = userAccount,
- CreateTime = DateTime.Now,
- UpdateTime = DateTime.Now
- };
- agg[a.ItemNum] = d;
- details.Add(d);
- }
- if (agg.Count == 0) return;
- var (user1, user2) = KeeperResolveService.FormatKeeperUsers(
- keepers.Distinct().Select(e => new KeeperResolveService.KeeperHit { Employee = e, ItemNum = "" }));
- masters.Add(new DraftNbrMaster
- {
- TempKey = temp,
- Domain = wo.Domain ?? "8010",
- Type = NbrTypeBill,
- Remark = "下达自动领料",
- ProdLine = wo.ProdLine ?? "",
- EffDate = eff,
- Date = start,
- Status = "",
- WorkOrd = wo.WorkOrd ?? "",
- QtyOrd = wo.QtyOrded,
- IsActive = true,
- IsChanged = true,
- Name = userAccount.Length > 12 ? userAccount[..12] : userAccount,
- Department = "101",
- CreateUser = userAccount,
- UpdateUser = userAccount,
- CreateTime = DateTime.Now,
- UpdateTime = DateTime.Now,
- TransType = "",
- User1 = user1,
- User2 = user2
- });
- }
- private static async Task InsertNbrOn165Async(
- ISqlSugarClient ss,
- List<DraftNbrMaster> masters,
- List<DraftNbrDetail> details,
- CancellationToken ct)
- {
- foreach (var m in masters)
- {
- var recIdObj = await ss.Ado.SqlQuerySingleAsync<int?>(
- @"INSERT INTO NbrMaster
- (Domain, Type, Nbr, [Print], Status, Remark, Date, User1, User2,
- ProdLine, EffDate, WorkOrd, QtyOrd, QtyRec, Address, BusinessID,
- CreateUser, UpdateUser, CreateTime, UpdateTime, IsActive, IsConfirm,
- IsChanged, Department, Name, TransType, Ufld1, IsGP12Checked, IsPlan, IsReturn, Op)
- OUTPUT INSERTED.RecID
- VALUES
- (@Domain, @Type, @Nbr, 0, @Status, @Remark, @Date, @User1, @User2,
- @ProdLine, @EffDate, @WorkOrd, @QtyOrd, 0, @Address, 0,
- @CreateUser, @UpdateUser, @CreateTime, @UpdateTime, 1, 0,
- 1, @Department, @Name, @TransType, @Ufld1, 0, 0, 0, 0)",
- new SugarParameter("@Domain", m.Domain),
- new SugarParameter("@Type", m.Type),
- new SugarParameter("@Nbr", m.Nbr),
- new SugarParameter("@Status", m.Status ?? ""),
- new SugarParameter("@Remark", m.Remark ?? ""),
- new SugarParameter("@Date", m.Date),
- new SugarParameter("@User1", m.User1 ?? ""),
- new SugarParameter("@User2", m.User2 ?? "[]"),
- new SugarParameter("@ProdLine", m.ProdLine ?? ""),
- new SugarParameter("@EffDate", m.EffDate),
- new SugarParameter("@WorkOrd", m.WorkOrd),
- new SugarParameter("@QtyOrd", m.QtyOrd),
- new SugarParameter("@Address", m.Address ?? ""),
- new SugarParameter("@CreateUser", Trunc(m.CreateUser, 24)),
- new SugarParameter("@UpdateUser", Trunc(m.UpdateUser, 24)),
- new SugarParameter("@CreateTime", m.CreateTime),
- new SugarParameter("@UpdateTime", m.UpdateTime),
- new SugarParameter("@Department", m.Department ?? ""),
- new SugarParameter("@Name", m.Name ?? ""),
- new SugarParameter("@TransType", m.TransType ?? ""),
- new SugarParameter("@Ufld1", m.Ufld1 ?? ""));
- if (recIdObj is null or 0)
- throw new InvalidOperationException($"NbrMaster 插入未返回 RecID:{m.Nbr}");
- var recId = recIdObj.Value;
- foreach (var d in details.Where(x => x.TempKey == m.TempKey))
- {
- await ss.Ado.ExecuteCommandAsync(
- @"INSERT INTO NbrDetail
- (Domain, Type, Nbr, Line, ItemNum, Dimension1, Dimension2,
- LocationFrom, LocationTo, QtyFrom, QtyTo, UM, [Print], Status, LotSerial,
- WorkOrd, QtyOrd, QtyRec, Address, BusinessID, CreateUser, UpdateUser,
- CreateTime, UpdateTime, IsActive, IsConfirm, QtyCache, CurrQtyOpened,
- IsChanged, NbrRecID, OrdNbr, ItemName, ERPfld1, ERPfld2, OrdLine,
- IsGP12Demand, IsGP12Checked, Material, SeqID)
- VALUES
- (@Domain, @Type, @Nbr, @Line, @ItemNum, '', '',
- @LocationFrom, @LocationTo, 0, 0, @UM, 0, @Status, @LotSerial,
- @WorkOrd, @QtyOrd, 0, @Address, 0, @CreateUser, @UpdateUser,
- @CreateTime, @UpdateTime, 1, 0, 0, @CurrQtyOpened,
- 1, @NbrRecID, @OrdNbr, @ItemName, @ERPfld1, @ERPfld2, @OrdLine,
- 0, 0, 0, 0)",
- new SugarParameter("@Domain", d.Domain),
- new SugarParameter("@Type", d.Type),
- new SugarParameter("@Nbr", d.Nbr),
- new SugarParameter("@Line", d.Line),
- new SugarParameter("@ItemNum", d.ItemNum),
- new SugarParameter("@LocationFrom", Trunc(d.LocationFrom, 8)),
- new SugarParameter("@LocationTo", Trunc(d.LocationTo, 8)),
- new SugarParameter("@UM", Trunc(d.UM, 8)),
- new SugarParameter("@Status", d.Status ?? ""),
- new SugarParameter("@LotSerial", d.LotSerial ?? ""),
- new SugarParameter("@WorkOrd", d.WorkOrd),
- new SugarParameter("@QtyOrd", d.QtyOrd),
- new SugarParameter("@Address", Trunc(d.Address, 60)),
- new SugarParameter("@CreateUser", Trunc(d.CreateUser, 24)),
- new SugarParameter("@UpdateUser", Trunc(d.UpdateUser, 24)),
- new SugarParameter("@CreateTime", d.CreateTime),
- new SugarParameter("@UpdateTime", d.UpdateTime),
- new SugarParameter("@CurrQtyOpened", d.CurrQtyOpened),
- new SugarParameter("@NbrRecID", recId),
- new SugarParameter("@OrdNbr", Trunc(d.OrdNbr, 48)),
- new SugarParameter("@ItemName", Trunc(d.ItemName, 1000)),
- new SugarParameter("@ERPfld1", Trunc(d.ERPfld1, 200)),
- new SugarParameter("@ERPfld2", Trunc(d.ERPfld2, 200)),
- new SugarParameter("@OrdLine", d.OrdLine));
- }
- }
- }
- private async Task<bool> EnqueueAsync(long tenantId, string idem, string action, object payload, CancellationToken ct)
- {
- var json = JsonSerializer.Serialize(payload);
- var item = new MdpOutbox
- {
- TenantId = tenantId,
- TargetSourceCode = TargetSource,
- ActionCode = action,
- IdemKey = idem.Length > 200 ? idem[..200] : idem,
- PayloadJson = json
- };
- return await _enqueue.TryEnqueueAsync(item, ct);
- }
- private static SugarParameter[] BuildInParams(string domain, string user, DateTime now, List<string> workOrds)
- {
- var pars = new List<SugarParameter>
- {
- new("@d", domain),
- new("@u", Trunc(user, 24)),
- new("@t", now)
- };
- for (var i = 0; i < workOrds.Count; i++)
- pars.Add(new SugarParameter("@w" + i, workOrds[i]));
- return pars.ToArray();
- }
- private static string Tail(string workOrd) =>
- workOrd.Length > 1 ? workOrd[1..] : workOrd;
-
- private sealed class ItemLite
- {
- public string ItemNum { get; set; } = "";
- public string? Descr { get; set; }
- public string? UM { get; set; }
- public string? Location { get; set; }
- }
- private static string Trunc(string? s, int max) =>
- string.IsNullOrEmpty(s) ? "" : (s.Length <= max ? s : s[..max]);
- private sealed class DraftNbrMaster
- {
- public string TempKey { get; set; } = "";
- public string Domain { get; set; } = "";
- public string Type { get; set; } = "";
- public string Nbr { get; set; } = "";
- public string? Remark { get; set; }
- public string? ProdLine { get; set; }
- public DateTime EffDate { get; set; }
- public DateTime Date { get; set; }
- public string? Status { get; set; }
- public string WorkOrd { get; set; } = "";
- public decimal QtyOrd { get; set; }
- public bool IsActive { get; set; }
- public bool IsChanged { get; set; }
- public string? Name { get; set; }
- public string? Department { get; set; }
- public string? CreateUser { get; set; }
- public string? UpdateUser { get; set; }
- public DateTime CreateTime { get; set; }
- public DateTime UpdateTime { get; set; }
- public string? TransType { get; set; }
- public string? User1 { get; set; }
- public string? User2 { get; set; }
- public string? Address { get; set; }
- public string? Ufld1 { get; set; }
- }
- private sealed class DraftNbrDetail
- {
- public string TempKey { get; set; } = "";
- public string Domain { get; set; } = "";
- public string Type { get; set; } = "";
- public string Nbr { get; set; } = "";
- public string ItemNum { get; set; } = "";
- public decimal QtyFrom { get; set; }
- public decimal QtyTo { get; set; }
- public string LocationFrom { get; set; } = "";
- public string LocationTo { get; set; } = "";
- public string WorkOrd { get; set; } = "";
- public decimal QtyOrd { get; set; }
- public decimal CurrQtyOpened { get; set; }
- public short Line { get; set; }
- public string UM { get; set; } = "";
- public string LotSerial { get; set; } = "";
- public string ItemName { get; set; } = "";
- public string Status { get; set; } = "";
- public string? CreateUser { get; set; }
- public string? UpdateUser { get; set; }
- public DateTime CreateTime { get; set; }
- public DateTime UpdateTime { get; set; }
- public string? Address { get; set; }
- public string? OrdNbr { get; set; }
- public string? ERPfld1 { get; set; }
- public string? ERPfld2 { get; set; }
- public short OrdLine { get; set; }
- }
- }
|