AdoS0TaskAssignmentsController.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using Admin.NET.Plugin.AiDOP.Dto.S0.Warehouse;
  2. using Admin.NET.Plugin.AiDOP.Entity.S0.Sales;
  3. using Admin.NET.Plugin.AiDOP.Entity.S0.Warehouse;
  4. using Admin.NET.Plugin.AiDOP.Infrastructure;
  5. namespace Admin.NET.Plugin.AiDOP.Controllers.S0.Warehouse;
  6. /// <summary>
  7. /// S0 物料状态任务指派(wms_rwzp 语义)。
  8. /// 多租户隔离:所有读写显式限定当前请求租户(AdoS0TenantScope.TryResolveRequired),不依赖全局 AOP 兜底。
  9. /// </summary>
  10. [ApiController]
  11. [Route("api/s0/warehouse/task-assignments")]
  12. [NonUnify]
  13. public class AdoS0TaskAssignmentsController : ControllerBase
  14. {
  15. private readonly SqlSugarRepository<AdoS0TaskAssignment> _rep;
  16. public AdoS0TaskAssignmentsController(SqlSugarRepository<AdoS0TaskAssignment> rep)
  17. {
  18. _rep = rep;
  19. }
  20. [HttpGet]
  21. public async Task<IActionResult> GetPagedAsync([FromQuery] AdoS0TaskAssignmentQueryDto q)
  22. {
  23. if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!;
  24. (q.Page, q.PageSize) = PagingGuard.Normalize(q.Page, q.PageSize);
  25. var query = _rep.AsQueryable()
  26. .Where(x => x.TenantId == tenantId)
  27. .WhereIF(q.CompanyRefId.HasValue, x => x.CompanyRefId == q.CompanyRefId!.Value)
  28. .WhereIF(q.FactoryRefId.HasValue, x => x.FactoryRefId == q.FactoryRefId!.Value)
  29. .WhereIF(!string.IsNullOrWhiteSpace(q.DomainCode), x => x.DomainCode == q.DomainCode)
  30. .WhereIF(!string.IsNullOrWhiteSpace(q.Rwlx), x => x.Rwlx == q.Rwlx)
  31. .WhereIF(!string.IsNullOrWhiteSpace(q.Zt), x => x.Zt == q.Zt)
  32. .WhereIF(!string.IsNullOrWhiteSpace(q.Sqr), x => x.Sqr != null && x.Sqr.Contains(q.Sqr!))
  33. .WhereIF(!string.IsNullOrWhiteSpace(q.Keyword),
  34. x => (x.Wlbm != null && x.Wlbm.Contains(q.Keyword!)) || (x.Sqr != null && x.Sqr.Contains(q.Keyword!)));
  35. var total = await query.CountAsync();
  36. var list = await query
  37. .OrderByDescending(x => x.Tcrq)
  38. .Skip((q.Page - 1) * q.PageSize)
  39. .Take(q.PageSize)
  40. .ToListAsync();
  41. // 补显 ItemDescr:实体已按设计声明该 [SugarColumn(IsIgnore = true)] 展示字段
  42. //(注释即写明「来自 ItemMaster」),但此前 controller 从未填充,页面「物料名称」列恒为空。
  43. // 单次 ItemMaster 查询 + 字典映射,无 N+1;显式限定当前租户。
  44. await FillItemDisplayAsync(list, tenantId);
  45. return Ok(new { total, page = q.Page, pageSize = q.PageSize, list });
  46. }
  47. [HttpGet("{id:long}")]
  48. public async Task<IActionResult> GetAsync(long id)
  49. {
  50. if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!;
  51. var item = await _rep.AsQueryable().Where(x => x.Id == id && x.TenantId == tenantId).FirstAsync();
  52. return item == null ? NotFound() : Ok(item);
  53. }
  54. [HttpPost]
  55. public async Task<IActionResult> CreateAsync([FromBody] AdoS0TaskAssignmentUpsertDto dto)
  56. {
  57. if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!;
  58. if (string.IsNullOrWhiteSpace(dto.DomainCode))
  59. return AdoS0ApiErrors.InvalidRequest("请填写域编码");
  60. // 唯一口径对齐数据库 uk_wms_rwzp_tenant_org_task
  61. // (tenant_id, company_ref_id, factory_ref_id, domain_code, rwlx, wlbm, rqpc, yskw, mdkw)
  62. if (await IsDuplicateAsync(tenantId, dto, null))
  63. return AdoS0ApiErrors.Conflict(AdoS0ErrorCodes.DuplicateCode, "相同工厂域下该物料任务指派已存在");
  64. var entity = new AdoS0TaskAssignment
  65. {
  66. TenantId = tenantId,
  67. CompanyRefId = dto.CompanyRefId,
  68. FactoryRefId = dto.FactoryRefId,
  69. DomainCode = dto.DomainCode ?? string.Empty,
  70. Tcrq = dto.Tcrq,
  71. Sqr = dto.Sqr,
  72. Rwlx = dto.Rwlx,
  73. Wlbm = dto.Wlbm,
  74. Sl = dto.Sl,
  75. Rqpc = dto.Rqpc,
  76. Yskw = dto.Yskw,
  77. Mdkw = dto.Mdkw,
  78. Xqsj = dto.Xqsj,
  79. Clr = dto.Clr,
  80. Bz = dto.Bz,
  81. Zt = dto.Zt,
  82. CreateUser = dto.CreateUser,
  83. CreateTime = DateTime.Now
  84. };
  85. await _rep.AsInsertable(entity).ExecuteReturnEntityAsync();
  86. return Ok(entity);
  87. }
  88. [HttpPut("{id:long}")]
  89. public async Task<IActionResult> UpdateAsync(long id, [FromBody] AdoS0TaskAssignmentUpsertDto dto)
  90. {
  91. if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!;
  92. if (string.IsNullOrWhiteSpace(dto.DomainCode))
  93. return AdoS0ApiErrors.InvalidRequest("请填写域编码");
  94. var entity = await _rep.AsQueryable().Where(x => x.Id == id && x.TenantId == tenantId).FirstAsync();
  95. if (entity == null) return NotFound();
  96. if (await IsDuplicateAsync(tenantId, dto, id))
  97. return AdoS0ApiErrors.Conflict(AdoS0ErrorCodes.DuplicateCode, "相同工厂域下该物料任务指派已存在");
  98. // entity.TenantId 保持不变(== tenantId);不接受前端修改 tenant
  99. entity.CompanyRefId = dto.CompanyRefId;
  100. entity.FactoryRefId = dto.FactoryRefId;
  101. entity.DomainCode = dto.DomainCode ?? string.Empty;
  102. entity.Tcrq = dto.Tcrq;
  103. entity.Sqr = dto.Sqr;
  104. entity.Rwlx = dto.Rwlx;
  105. entity.Wlbm = dto.Wlbm;
  106. entity.Sl = dto.Sl;
  107. entity.Rqpc = dto.Rqpc;
  108. entity.Yskw = dto.Yskw;
  109. entity.Mdkw = dto.Mdkw;
  110. entity.Xqsj = dto.Xqsj;
  111. entity.Clr = dto.Clr;
  112. entity.Bz = dto.Bz;
  113. entity.Zt = dto.Zt;
  114. entity.UpdateUser = dto.UpdateUser;
  115. entity.UpdateTime = DateTime.Now;
  116. await _rep.AsUpdateable(entity).ExecuteCommandAsync();
  117. return Ok(entity);
  118. }
  119. [HttpDelete("{id:long}")]
  120. public async Task<IActionResult> DeleteAsync(long id)
  121. {
  122. if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!;
  123. var item = await _rep.AsQueryable().Where(x => x.Id == id && x.TenantId == tenantId).FirstAsync();
  124. if (item == null) return NotFound();
  125. await _rep.DeleteAsync(item);
  126. return Ok(new { message = "删除成功" });
  127. }
  128. /// <summary>
  129. /// 租户内业务唯一校验:对齐 uk_wms_rwzp_tenant_org_task
  130. /// (tenant_id, company_ref_id, factory_ref_id, domain_code, rwlx, wlbm, rqpc, yskw, mdkw)。
  131. /// excludeId 非空时排除自身(更新场景)。
  132. /// </summary>
  133. private async Task<bool> IsDuplicateAsync(long tenantId, AdoS0TaskAssignmentUpsertDto dto, long? excludeId)
  134. {
  135. var domainCode = dto.DomainCode ?? string.Empty;
  136. return await _rep.AsQueryable()
  137. .Where(x => x.TenantId == tenantId
  138. && x.CompanyRefId == dto.CompanyRefId
  139. && x.FactoryRefId == dto.FactoryRefId
  140. && x.DomainCode == domainCode
  141. && x.Rwlx == dto.Rwlx
  142. && x.Wlbm == dto.Wlbm
  143. && x.Rqpc == dto.Rqpc
  144. && x.Yskw == dto.Yskw
  145. && x.Mdkw == dto.Mdkw)
  146. .WhereIF(excludeId.HasValue, x => x.Id != excludeId!.Value)
  147. .AnyAsync();
  148. }
  149. /// <summary>批量补显物料名称:一次 ItemMaster 查询 + 字典映射(无 N+1),显式限定当前租户。</summary>
  150. private async Task FillItemDisplayAsync(List<AdoS0TaskAssignment> rows, long tenantId)
  151. {
  152. var itemNums = rows.Select(x => x.Wlbm)
  153. .Where(x => !string.IsNullOrWhiteSpace(x))
  154. .Select(x => x!)
  155. .Distinct()
  156. .ToList();
  157. if (itemNums.Count == 0) return;
  158. var items = await _rep.Context.Queryable<AdoS0ItemMaster>()
  159. .Where(m => m.TenantId == tenantId && itemNums.Contains(m.ItemNum))
  160. .OrderByDescending(m => m.IsActive)
  161. .OrderBy(m => m.Id)
  162. .Select(m => new { m.ItemNum, m.Descr })
  163. .ToListAsync();
  164. var map = items.GroupBy(x => x.ItemNum).ToDictionary(g => g.Key, g => g.First().Descr);
  165. foreach (var r in rows)
  166. if (r.Wlbm != null && map.TryGetValue(r.Wlbm, out var d)) r.ItemDescr = d;
  167. }
  168. }