InoutQueryService.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using Admin.NET.Plugin.AiDOP.MaterialWarehouse.Dto;
  2. namespace Admin.NET.Plugin.AiDOP.MaterialWarehouse;
  3. /// <summary>
  4. /// S5 进出存查询 只读 list 服务。
  5. ///
  6. /// 数据源:aidopdev.InvTransHist(库存交易流水),忠实复刻证据 sql.txt:
  7. /// LEFT JOIN GeneralizedCodeMaster(TransType→名称)、LocationMaster(货位名)、ItemMaster(物料名/单位),
  8. /// 过滤 a.Domain=@Domain。进出存口径由 SQL 内定义(非脑补):
  9. /// 期初 = BeginBalance;入库 = QtyChange&gt;0?QtyChange:0;出库 = QtyChange&lt;0?abs(QtyChange):0;
  10. /// 期末(结存) = BeginBalance+QtyChange。逐笔交易流水,BeginBalance 按行存储。
  11. /// Domain 由 GeneralizedCodeMaster(SystemConfig/CompanyCode) 解析,默认 8010。
  12. /// 排序 a.RecID DESC(PK,近似交易时间倒序,兼顾 1M 行分页性能与稳定)。
  13. ///
  14. /// 本服务仅 SELECT:无新增/编辑/删除/库存事务/状态流转;InvTransHist 无 tenant_id,不做租户过滤。
  15. /// </summary>
  16. [ApiDescriptionSettings(Order = 303, Description = "进出存查询")]
  17. [Route("api/S5InoutQuery")]
  18. [AllowAnonymous]
  19. [NonUnify]
  20. public class InoutQueryService : IDynamicApiController, ITransient
  21. {
  22. private readonly ISqlSugarClient _db;
  23. public InoutQueryService(ISqlSugarClient db)
  24. {
  25. _db = db;
  26. }
  27. /// <summary>解析公司域(GeneralizedCodeMaster SystemConfig/CompanyCode,默认 8010)。</summary>
  28. private async Task<string> ResolveDomainAsync()
  29. {
  30. var list = await _db.Ado.SqlQueryAsync<string>(
  31. "SELECT Domain FROM GeneralizedCodeMaster WHERE FldName='SystemConfig' AND Val='CompanyCode' ORDER BY RecID LIMIT 1");
  32. var domain = list.FirstOrDefault();
  33. return string.IsNullOrWhiteSpace(domain) ? "8010" : domain;
  34. }
  35. /// <summary>
  36. /// 进出存查询列表(只读分页查询)。
  37. /// </summary>
  38. [DisplayName("进出存查询列表")]
  39. [HttpGet("list")]
  40. public async Task<object> GetList([FromQuery] InoutQueryListInput input)
  41. {
  42. var page = input.Page <= 0 ? 1 : input.Page;
  43. var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
  44. var offset = (page - 1) * pageSize;
  45. var domain = await ResolveDomainAsync();
  46. var where = new List<string> { "a.Domain = @Domain" };
  47. var pars = new List<SugarParameter> { new("@Domain", domain) };
  48. if (!string.IsNullOrWhiteSpace(input.MaterialCode))
  49. {
  50. where.Add("a.ItemNum LIKE @MaterialCode");
  51. pars.Add(new SugarParameter("@MaterialCode", $"%{input.MaterialCode.Trim()}%"));
  52. }
  53. if (!string.IsNullOrWhiteSpace(input.Location))
  54. {
  55. where.Add("a.Loc = @Location");
  56. pars.Add(new SugarParameter("@Location", input.Location.Trim()));
  57. }
  58. if (!string.IsNullOrWhiteSpace(input.BatchNo))
  59. {
  60. where.Add("a.LotSerial LIKE @BatchNo");
  61. pars.Add(new SugarParameter("@BatchNo", $"%{input.BatchNo.Trim()}%"));
  62. }
  63. if (!string.IsNullOrWhiteSpace(input.WorkOrderNo))
  64. {
  65. where.Add("a.WorkOrd LIKE @WorkOrderNo");
  66. pars.Add(new SugarParameter("@WorkOrderNo", $"%{input.WorkOrderNo.Trim()}%"));
  67. }
  68. if (!string.IsNullOrWhiteSpace(input.TransType))
  69. {
  70. where.Add("a.TransType = @TransType");
  71. pars.Add(new SugarParameter("@TransType", input.TransType.Trim()));
  72. }
  73. if (!string.IsNullOrWhiteSpace(input.CreateTime))
  74. {
  75. where.Add("a.CreateTime >= @CreateFrom AND a.CreateTime < DATE_ADD(@CreateFrom, INTERVAL 1 DAY)");
  76. pars.Add(new SugarParameter("@CreateFrom", $"{input.CreateTime.Trim()} 00:00:00"));
  77. }
  78. if (!string.IsNullOrWhiteSpace(input.CreateUser))
  79. {
  80. where.Add("a.CreateUser LIKE @CreateUser");
  81. pars.Add(new SugarParameter("@CreateUser", $"%{input.CreateUser.Trim()}%"));
  82. }
  83. var whereSql = string.Join(" AND ", where);
  84. var total = await _db.Ado.GetIntAsync($"SELECT COUNT(1) FROM InvTransHist a WHERE {whereSql}", pars);
  85. var list = await _db.Ado.SqlQueryAsync<InoutQueryListRow>(
  86. $"""
  87. SELECT
  88. a.CreateTime AS TransTime,
  89. a.ItemNum AS MaterialCode,
  90. i.Descr AS MaterialName,
  91. a.Loc AS Location,
  92. IFNULL(l.descr,'') AS LocationName,
  93. a.LotSerial AS BatchNo,
  94. a.BeginBalance AS BeginQty,
  95. (CASE WHEN a.QtyChange > 0 THEN a.QtyChange ELSE 0 END) AS InQty,
  96. (CASE WHEN a.QtyChange < 0 THEN ABS(a.QtyChange) ELSE 0 END) AS OutQty,
  97. (a.BeginBalance + a.QtyChange) AS EndQty,
  98. i.UM AS Unit,
  99. COALESCE(b.Comments, a.TransType) AS TransType,
  100. a.WorkOrd AS WorkOrderNo,
  101. a.ShipperNum AS DeliveryNo,
  102. a.ShipType AS DeliveryType,
  103. a.Remark AS Remark,
  104. a.CreateUser AS CreateUser
  105. FROM InvTransHist a
  106. LEFT JOIN GeneralizedCodeMaster b ON a.Domain = b.Domain AND a.TransType = b.Val AND b.FldName = 'TransType'
  107. LEFT JOIN LocationMaster l ON a.Domain = l.Domain AND a.Loc = l.location
  108. LEFT JOIN ItemMaster i ON a.Domain = i.Domain AND a.ItemNum = i.ItemNum
  109. WHERE {whereSql}
  110. ORDER BY a.RecID DESC
  111. LIMIT {pageSize} OFFSET {offset}
  112. """,
  113. pars);
  114. return new { total, page, pageSize, list };
  115. }
  116. /// <summary>
  117. /// 货位下拉选项(LocationMaster.Location + Descr,只读)。
  118. /// </summary>
  119. [DisplayName("进出存查询货位选项")]
  120. [HttpGet("loc-options")]
  121. public async Task<object> GetLocationOptions()
  122. {
  123. var domain = await ResolveDomainAsync();
  124. var list = await _db.Ado.SqlQueryAsync<InoutQueryLocationOption>(
  125. """
  126. SELECT location AS Val, descr AS Label
  127. FROM LocationMaster
  128. WHERE Domain = @Domain AND IFNULL(location,'') <> ''
  129. ORDER BY location
  130. """,
  131. new List<SugarParameter> { new("@Domain", domain) });
  132. return list;
  133. }
  134. /// <summary>
  135. /// 交易类型下拉选项(GeneralizedCodeMaster TransType:代码 + 名称,只读)。
  136. /// </summary>
  137. [DisplayName("进出存查询交易类型选项")]
  138. [HttpGet("transtype-options")]
  139. public async Task<object> GetTransTypeOptions()
  140. {
  141. var domain = await ResolveDomainAsync();
  142. var list = await _db.Ado.SqlQueryAsync<InoutQueryTransTypeOption>(
  143. """
  144. SELECT Val AS Val, Comments AS Label
  145. FROM GeneralizedCodeMaster
  146. WHERE FldName = 'TransType' AND Domain = @Domain AND IFNULL(Val,'') <> ''
  147. ORDER BY Val
  148. """,
  149. new List<SugarParameter> { new("@Domain", domain) });
  150. return list;
  151. }
  152. }