PurchaseRequestService.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. using Yitter.IdGenerator;
  2. namespace Admin.NET.Plugin.AiDOP.Supply;
  3. /// <summary>
  4. /// 物料采购申请服务
  5. /// </summary>
  6. [ApiDescriptionSettings(Order = 308, Description = "物料采购申请")]
  7. [Route("api/Supply")]
  8. [AllowAnonymous]
  9. [NonUnify]
  10. public class PurchaseRequestService : IDynamicApiController, ITransient
  11. {
  12. private readonly ISqlSugarClient _db;
  13. private readonly UserManager _userManager;
  14. public PurchaseRequestService(ISqlSugarClient db, UserManager userManager)
  15. {
  16. _db = db;
  17. _userManager = userManager;
  18. }
  19. [DisplayName("物料采购申请列表")]
  20. [HttpGet("purchase-request/list")]
  21. public async Task<object> GetList([FromQuery] PurchaseRequestListInput input)
  22. {
  23. var page = input.Page <= 0 ? 1 : input.Page;
  24. var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
  25. var offset = (page - 1) * pageSize;
  26. var pars = new List<SugarParameter>();
  27. var where = new List<string>
  28. {
  29. "IFNULL(pm.IsDeleted,0)=0",
  30. "IFNULL(pm.state,0)<>0",
  31. "IFNULL(pm.analogcalcversion,'')=''"
  32. };
  33. if (_userManager.TenantId > 0)
  34. {
  35. where.Add("pm.tenant_id=@TenantId");
  36. pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
  37. }
  38. if (!string.IsNullOrWhiteSpace(input.PrBillNo))
  39. {
  40. where.Add("pm.pr_billno LIKE @PrBillNo");
  41. pars.Add(new SugarParameter("@PrBillNo", $"%{input.PrBillNo.Trim()}%"));
  42. }
  43. if (!string.IsNullOrWhiteSpace(input.ItemNumber))
  44. {
  45. where.Add("ic.number LIKE @ItemNumber");
  46. pars.Add(new SugarParameter("@ItemNumber", $"%{input.ItemNumber.Trim()}%"));
  47. }
  48. if (!string.IsNullOrWhiteSpace(input.SupplierName))
  49. {
  50. where.Add("pm.pr_purchasename LIKE @SupplierName");
  51. pars.Add(new SugarParameter("@SupplierName", $"%{input.SupplierName.Trim()}%"));
  52. }
  53. if (input.State.HasValue)
  54. {
  55. where.Add("pm.state=@State");
  56. pars.Add(new SugarParameter("@State", input.State.Value));
  57. }
  58. var orderBy = BuildOrderBy(input.SortField, input.SortOrder);
  59. var fromSql = $"""
  60. FROM srm_pr_main pm
  61. LEFT JOIN ic_item ic ON pm.icitem_id=ic.Id
  62. LEFT JOIN srm_purchase pur ON pm.icitem_id=pur.icitem_id AND pm.pr_purchaseid = pur.supplier_id AND pur.tenant_id=pm.tenant_id
  63. LEFT JOIN ic_item_stock its ON ic.Id=its.icitem_id
  64. LEFT JOIN PurOrdDetail pod ON (pm.pr_billno=pod.Req OR pm.SAP_pr_billno=pod.Req) AND pod.tenant_id=pm.tenant_id
  65. WHERE {string.Join(" AND ", where)}
  66. """;
  67. var total = await _db.Ado.GetIntAsync($"SELECT COUNT(1) FROM (SELECT DISTINCT pm.Id {fromSql}) t", pars);
  68. var list = await _db.Ado.SqlQueryAsync<PurchaseRequestListRow>(
  69. $"""
  70. SELECT
  71. pm.id AS Id,
  72. pm.pr_billno AS PrBillNo,
  73. pod.PurOrd AS PurOrd,
  74. pm.pr_type AS PrType,
  75. pm.supplier_type AS SupplierType,
  76. pm.IsRequireGoods AS IsRequireGoods,
  77. pm.state AS State,
  78. ic.number AS Number,
  79. ic.name AS Name,
  80. ic.model AS Model,
  81. pm.pr_unit AS PrUnit,
  82. pm.pr_purchasenumber AS PrPurchaseNumber,
  83. pm.pr_purchasename AS PrPurchaseName,
  84. pm.pr_sqty AS PrSqty,
  85. pm.pr_aqty AS PrAqty,
  86. its.sqty AS StockQty,
  87. pm.pr_ssend_date AS PrSsendDate,
  88. pm.pr_sarrive_date AS PrSarriveDate,
  89. pm.pr_purchaser AS PrPurchaser,
  90. pm.create_time AS CreateTime
  91. {fromSql}
  92. ORDER BY {orderBy}
  93. LIMIT {pageSize} OFFSET {offset}
  94. """,
  95. pars);
  96. return new { total, page, pageSize, list };
  97. }
  98. [DisplayName("获取物料采购申请详情")]
  99. [HttpGet("purchase-request/{id:long}")]
  100. public async Task<object> GetDetail(long id)
  101. {
  102. var tenantId = _userManager.TenantId;
  103. var tenantWhere = tenantId > 0 ? " AND pm.tenant_id=@TenantId" : string.Empty;
  104. var pars = new List<SugarParameter> { new("@Id", id) };
  105. if (tenantId > 0) pars.Add(new SugarParameter("@TenantId", tenantId));
  106. var row = (await _db.Ado.SqlQueryAsync<PurchaseRequestDetailRow>(
  107. $"""
  108. SELECT
  109. pm.id AS Id,
  110. pm.pr_billno AS PrBillNo,
  111. CAST(pm.icitem_id AS CHAR(30)) AS IcitemId,
  112. pm.icitem_name AS IcitemName,
  113. pm.pr_unit AS PrUnit,
  114. pm.pr_purchasenumber AS PrPurchaseNumber,
  115. pm.pr_purchasename AS PrPurchaseName,
  116. pm.supplier_type AS SupplierType,
  117. pm.pr_aqty AS PrAqty,
  118. pm.pr_ssend_date AS PrSsendDate,
  119. pm.pr_sarrive_date AS PrSarriveDate,
  120. pm.pr_type AS PrType,
  121. pm.state AS State,
  122. pm.pr_purchaseid AS PrPurchaseId,
  123. pm.IsRequireGoods AS IsRequireGoods,
  124. pm.pr_purchaser_num AS PrPurchaserNum,
  125. pm.pr_purchaser AS PrPurchaser,
  126. pm.currencytype AS CurrencyType
  127. FROM srm_pr_main pm
  128. WHERE pm.Id=@Id AND IFNULL(pm.IsDeleted,0)=0{tenantWhere}
  129. LIMIT 1
  130. """,
  131. pars)).FirstOrDefault();
  132. return row ?? throw Oops.Oh("记录不存在");
  133. }
  134. [DisplayName("保存物料采购申请")]
  135. [ApiDescriptionSettings(Name = "SavePurchaseRequest"), HttpPost("purchase-request/save")]
  136. public async Task<object> Save([FromBody] PurchaseRequestSaveInput input)
  137. {
  138. // icitem_id 为雪花ID,前端以字符串传递避免 JS Number 精度丢失,这里解析回 long
  139. if (!long.TryParse(input.IcitemId?.Trim(), out var icitemId) || icitemId <= 0) throw Oops.Oh("请选择物料");
  140. if (input.PrPurchaseId is null or <= 0) throw Oops.Oh("请选择供应商");
  141. if (!input.PrAqty.HasValue || input.PrAqty.Value <= 0) throw Oops.Oh("申请数量必须大于0");
  142. var now = DateTime.Now;
  143. var aqty = input.PrAqty.Value;
  144. var prSsendDate = ParseDate(input.PrSsendDate) ?? now.Date;
  145. var prSarriveDate = ParseDate(input.PrSarriveDate);
  146. var prType = input.PrType ?? 3;
  147. var state = input.State ?? 1;
  148. var currency = input.CurrencyType ?? 1;
  149. var companyId = _userManager.OrgId > 0 ? _userManager.OrgId : 1000;
  150. if (input.Id is null or 0)
  151. {
  152. var newId = YitIdHelper.NextId();
  153. var billNo = string.IsNullOrWhiteSpace(input.PrBillNo) ? GenerateBillNo() : input.PrBillNo.Trim();
  154. await _db.Ado.ExecuteCommandAsync(
  155. """
  156. INSERT INTO srm_pr_main
  157. (Id,pr_billno,pr_purchaseid,pr_purchasenumber,pr_purchasename,pr_purchaser,pr_purchaser_num,
  158. pr_rqty,pr_aqty,pr_sqty,icitem_id,icitem_name,pr_ssend_date,pr_sarrive_date,pr_unit,state,pr_type,currencytype,
  159. create_by,create_by_name,create_time,update_by,update_by_name,update_time,tenant_id,factory_id,org_id,IsDeleted,company_id,IsRequireGoods,supplier_type)
  160. VALUES
  161. (@Id,@PrBillNo,@PrPurchaseId,@PrPurchaseNumber,@PrPurchaseName,@PrPurchaser,@PrPurchaserNum,
  162. @PrRqty,@PrAqty,@PrSqty,@IcitemId,@IcitemName,@PrSsendDate,@PrSarriveDate,@PrUnit,@State,@PrType,@CurrencyType,
  163. @CreateBy,@CreateByName,@CreateTime,@UpdateBy,@UpdateByName,@UpdateTime,@TenantId,@FactoryId,@OrgId,@IsDeleted,@CompanyId,@IsRequireGoods,@SupplierType)
  164. """,
  165. new SugarParameter("@Id", newId),
  166. new SugarParameter("@PrBillNo", billNo),
  167. new SugarParameter("@PrPurchaseId", input.PrPurchaseId!.Value),
  168. new SugarParameter("@PrPurchaseNumber", input.PrPurchaseNumber?.Trim()),
  169. new SugarParameter("@PrPurchaseName", input.PrPurchaseName?.Trim()),
  170. new SugarParameter("@PrPurchaser", input.PrPurchaser?.Trim()),
  171. new SugarParameter("@PrPurchaserNum", input.PrPurchaserNum?.Trim()),
  172. new SugarParameter("@PrRqty", aqty),
  173. new SugarParameter("@PrAqty", aqty),
  174. new SugarParameter("@PrSqty", aqty),
  175. new SugarParameter("@IcitemId", icitemId),
  176. new SugarParameter("@IcitemName", input.IcitemName?.Trim()),
  177. new SugarParameter("@PrSsendDate", prSsendDate),
  178. new SugarParameter("@PrSarriveDate", prSarriveDate),
  179. new SugarParameter("@PrUnit", input.PrUnit?.Trim()),
  180. new SugarParameter("@State", state),
  181. new SugarParameter("@PrType", prType),
  182. new SugarParameter("@CurrencyType", currency),
  183. new SugarParameter("@CreateBy", _userManager.UserId),
  184. new SugarParameter("@CreateByName", _userManager.Account),
  185. new SugarParameter("@CreateTime", now),
  186. new SugarParameter("@UpdateBy", _userManager.UserId),
  187. new SugarParameter("@UpdateByName", _userManager.Account),
  188. new SugarParameter("@UpdateTime", now),
  189. new SugarParameter("@TenantId", _userManager.TenantId),
  190. new SugarParameter("@FactoryId", _userManager.OrgId),
  191. new SugarParameter("@OrgId", _userManager.OrgId),
  192. new SugarParameter("@IsDeleted", 0),
  193. new SugarParameter("@CompanyId", companyId),
  194. new SugarParameter("@IsRequireGoods", input.IsRequireGoods ?? 0),
  195. new SugarParameter("@SupplierType", input.SupplierType?.Trim())
  196. );
  197. return new { id = newId, prBillNo = billNo, message = "新增成功" };
  198. }
  199. else
  200. {
  201. var tenantId = _userManager.TenantId;
  202. var tenantSuffix = tenantId > 0 ? " AND tenant_id=@TenantId" : string.Empty;
  203. var existPars = new List<SugarParameter> { new("@Id", input.Id.Value) };
  204. if (tenantId > 0) existPars.Add(new SugarParameter("@TenantId", tenantId));
  205. var exist = await _db.Ado.GetIntAsync(
  206. $"SELECT COUNT(1) FROM srm_pr_main WHERE Id=@Id AND IFNULL(IsDeleted,0)=0{tenantSuffix}",
  207. existPars);
  208. if (exist <= 0) throw Oops.Oh("记录不存在");
  209. await _db.Ado.ExecuteCommandAsync(
  210. $"""
  211. UPDATE srm_pr_main
  212. SET
  213. pr_purchaseid=@PrPurchaseId,
  214. pr_purchasenumber=@PrPurchaseNumber,
  215. pr_purchasename=@PrPurchaseName,
  216. pr_purchaser=@PrPurchaser,
  217. pr_purchaser_num=@PrPurchaserNum,
  218. pr_rqty=@PrRqty,
  219. pr_aqty=@PrAqty,
  220. pr_sqty=@PrSqty,
  221. icitem_id=@IcitemId,
  222. icitem_name=@IcitemName,
  223. pr_ssend_date=@PrSsendDate,
  224. pr_sarrive_date=@PrSarriveDate,
  225. pr_unit=@PrUnit,
  226. state=@State,
  227. pr_type=@PrType,
  228. currencytype=@CurrencyType,
  229. update_by=@UpdateBy,
  230. update_by_name=@UpdateByName,
  231. update_time=@UpdateTime,
  232. IsRequireGoods=@IsRequireGoods,
  233. supplier_type=@SupplierType
  234. WHERE Id=@Id AND IFNULL(IsDeleted,0)=0{tenantSuffix}
  235. """,
  236. new SugarParameter("@Id", input.Id.Value),
  237. new SugarParameter("@PrPurchaseId", input.PrPurchaseId!.Value),
  238. new SugarParameter("@PrPurchaseNumber", input.PrPurchaseNumber?.Trim()),
  239. new SugarParameter("@PrPurchaseName", input.PrPurchaseName?.Trim()),
  240. new SugarParameter("@PrPurchaser", input.PrPurchaser?.Trim()),
  241. new SugarParameter("@PrPurchaserNum", input.PrPurchaserNum?.Trim()),
  242. new SugarParameter("@PrRqty", aqty),
  243. new SugarParameter("@PrAqty", aqty),
  244. new SugarParameter("@PrSqty", aqty),
  245. new SugarParameter("@IcitemId", icitemId),
  246. new SugarParameter("@IcitemName", input.IcitemName?.Trim()),
  247. new SugarParameter("@PrSsendDate", prSsendDate),
  248. new SugarParameter("@PrSarriveDate", prSarriveDate),
  249. new SugarParameter("@PrUnit", input.PrUnit?.Trim()),
  250. new SugarParameter("@State", state),
  251. new SugarParameter("@PrType", prType),
  252. new SugarParameter("@CurrencyType", currency),
  253. new SugarParameter("@UpdateBy", _userManager.UserId),
  254. new SugarParameter("@UpdateByName", _userManager.Account),
  255. new SugarParameter("@UpdateTime", now),
  256. new SugarParameter("@IsRequireGoods", input.IsRequireGoods ?? 0),
  257. new SugarParameter("@SupplierType", input.SupplierType?.Trim()),
  258. new SugarParameter("@TenantId", tenantId)
  259. );
  260. return new { id = input.Id, message = "编辑成功" };
  261. }
  262. }
  263. [DisplayName("删除物料采购申请")]
  264. [HttpPost("purchase-request/delete/{id:long}")]
  265. public async Task<object> Delete(long id)
  266. {
  267. var tenantId = _userManager.TenantId;
  268. var tenantSuffix = tenantId > 0 ? " AND tenant_id=@TenantId" : string.Empty;
  269. var pars = new List<SugarParameter>
  270. {
  271. new("@Id", id),
  272. new("@UpdateBy", _userManager.UserId),
  273. new("@UpdateByName", _userManager.Account),
  274. new("@UpdateTime", DateTime.Now)
  275. };
  276. if (tenantId > 0) pars.Add(new SugarParameter("@TenantId", tenantId));
  277. var affected = await _db.Ado.ExecuteCommandAsync(
  278. $"""
  279. UPDATE srm_pr_main
  280. SET IsDeleted=1,state=0,update_by=@UpdateBy,update_by_name=@UpdateByName,update_time=@UpdateTime
  281. WHERE Id=@Id AND IFNULL(IsDeleted,0)=0{tenantSuffix}
  282. """,
  283. pars);
  284. if (affected <= 0) throw Oops.Oh("记录不存在");
  285. return new { message = "删除成功" };
  286. }
  287. private static string BuildOrderBy(string? sortField, string? sortOrder)
  288. {
  289. var dir = string.Equals(sortOrder, "asc", StringComparison.OrdinalIgnoreCase) ? "ASC" : "DESC";
  290. return sortField?.ToLowerInvariant() switch
  291. {
  292. "prbillno" => $"pm.pr_billno {dir}",
  293. "purord" => $"pod.PurOrd {dir}",
  294. "prtype" => $"pm.pr_type {dir}",
  295. "state" => $"pm.state {dir}",
  296. "number" => $"ic.number {dir}",
  297. "name" => $"ic.name {dir}",
  298. "prpurchasename" => $"pm.pr_purchasename {dir}",
  299. "prsqty" => $"pm.pr_sqty {dir}",
  300. "praqty" => $"pm.pr_aqty {dir}",
  301. "stockqty" => $"its.sqty {dir}",
  302. "prssenddate" => $"pm.pr_ssend_date {dir}",
  303. "prsarrivedate" => $"pm.pr_sarrive_date {dir}",
  304. "createtime" => $"pm.create_time {dir}",
  305. _ => "pm.create_time DESC"
  306. };
  307. }
  308. private static DateTime? ParseDate(string? value) => DateTime.TryParse(value, out var dt) ? dt : null;
  309. private static string GenerateBillNo()
  310. {
  311. return $"PR{DateTime.Now:yyyyMMddHHmmssfff}";
  312. }
  313. private sealed class PurchaseRequestListRow
  314. {
  315. public long Id { get; set; }
  316. public string? PrBillNo { get; set; }
  317. public string? PurOrd { get; set; }
  318. public int? PrType { get; set; }
  319. public string? SupplierType { get; set; }
  320. public int? IsRequireGoods { get; set; }
  321. public int? State { get; set; }
  322. public string? Number { get; set; }
  323. public string? Name { get; set; }
  324. public string? Model { get; set; }
  325. public string? PrUnit { get; set; }
  326. public string? PrPurchaseNumber { get; set; }
  327. public string? PrPurchaseName { get; set; }
  328. public decimal? PrSqty { get; set; }
  329. public decimal? PrAqty { get; set; }
  330. public decimal? StockQty { get; set; }
  331. public DateTime? PrSsendDate { get; set; }
  332. public DateTime? PrSarriveDate { get; set; }
  333. public string? PrPurchaser { get; set; }
  334. public DateTime? CreateTime { get; set; }
  335. }
  336. private sealed class PurchaseRequestDetailRow
  337. {
  338. public long Id { get; set; }
  339. public string? PrBillNo { get; set; }
  340. public string? IcitemId { get; set; }
  341. public string? IcitemName { get; set; }
  342. public string? PrUnit { get; set; }
  343. public string? PrPurchaseNumber { get; set; }
  344. public string? PrPurchaseName { get; set; }
  345. public string? SupplierType { get; set; }
  346. public decimal? PrAqty { get; set; }
  347. public DateTime? PrSsendDate { get; set; }
  348. public DateTime? PrSarriveDate { get; set; }
  349. public int? PrType { get; set; }
  350. public int? State { get; set; }
  351. public long? PrPurchaseId { get; set; }
  352. public int? IsRequireGoods { get; set; }
  353. public string? PrPurchaserNum { get; set; }
  354. public string? PrPurchaser { get; set; }
  355. public long? CurrencyType { get; set; }
  356. }
  357. }