Commit 5121aa323e20299a39ffa1c179219049dd587812

Authored by “wangming”
1 parent caf75b4a

feat: 完善采购入库功能,支持记录采购金额和产品最终金额

- 添加采购入库相关字段(入库类型、采购单号、采购单价、采购总金额、产品最终金额)
- 实现采购单号自动生成逻辑,当单据规则不存在时使用时间戳fallback
- 完善采购入库的创建和更新逻辑,支持采购金额计算和验证
- 更新查询接口,返回所有采购金额相关字段
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventory/LqInventoryCrInput.cs
... ... @@ -49,5 +49,40 @@ namespace NCC.Extend.Entitys.Dto.LqInventory
49 49 [StringLength(100, ErrorMessage = "批次号长度不能超过100个字符")]
50 50 [Display(Name = "批次号")]
51 51 public string BatchNumber { get; set; }
  52 +
  53 + /// <summary>
  54 + /// 入库类型(1:普通入库 2:采购入库)
  55 + /// </summary>
  56 + [Range(1, 2, ErrorMessage = "入库类型必须在1-2之间")]
  57 + [Display(Name = "入库类型")]
  58 + public int? StockInType { get; set; } = 1;
  59 +
  60 + /// <summary>
  61 + /// 采购单号
  62 + /// </summary>
  63 + [StringLength(50, ErrorMessage = "采购单号长度不能超过50个字符")]
  64 + [Display(Name = "采购单号")]
  65 + public string PurchaseOrderNo { get; set; }
  66 +
  67 + /// <summary>
  68 + /// 采购单价
  69 + /// </summary>
  70 + [Range(0, double.MaxValue, ErrorMessage = "采购单价不能小于0")]
  71 + [Display(Name = "采购单价")]
  72 + public decimal? PurchaseUnitPrice { get; set; }
  73 +
  74 + /// <summary>
  75 + /// 采购总金额(采购单价 × 数量,系统自动计算)
  76 + /// </summary>
  77 + [Range(0, double.MaxValue, ErrorMessage = "采购总金额不能小于0")]
  78 + [Display(Name = "采购总金额")]
  79 + public decimal? PurchaseAmount { get; set; }
  80 +
  81 + /// <summary>
  82 + /// 产品最终金额(采购金额或其他成本)
  83 + /// </summary>
  84 + [Range(0, double.MaxValue, ErrorMessage = "产品最终金额不能小于0")]
  85 + [Display(Name = "产品最终金额")]
  86 + public decimal? FinalAmount { get; set; }
52 87 }
53 88 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqInventory/LqInventoryListOutput.cs
... ... @@ -75,6 +75,36 @@ namespace NCC.Extend.Entitys.Dto.LqInventory
75 75 public string batchNumber { get; set; }
76 76  
77 77 /// <summary>
  78 + /// 入库类型(1:普通入库 2:采购入库)
  79 + /// </summary>
  80 + [Display(Name = "入库类型")]
  81 + public int? stockInType { get; set; }
  82 +
  83 + /// <summary>
  84 + /// 采购单号
  85 + /// </summary>
  86 + [Display(Name = "采购单号")]
  87 + public string purchaseOrderNo { get; set; }
  88 +
  89 + /// <summary>
  90 + /// 采购单价
  91 + /// </summary>
  92 + [Display(Name = "采购单价")]
  93 + public decimal? purchaseUnitPrice { get; set; }
  94 +
  95 + /// <summary>
  96 + /// 采购总金额
  97 + /// </summary>
  98 + [Display(Name = "采购总金额")]
  99 + public decimal? purchaseAmount { get; set; }
  100 +
  101 + /// <summary>
  102 + /// 产品最终金额
  103 + /// </summary>
  104 + [Display(Name = "产品最终金额")]
  105 + public decimal? finalAmount { get; set; }
  106 +
  107 + /// <summary>
78 108 /// 创建人ID
79 109 /// </summary>
80 110 [Display(Name = "创建人ID")]
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_inventory/LqInventoryEntity.cs
... ... @@ -54,6 +54,36 @@ namespace NCC.Extend.Entitys.lq_inventory
54 54 public string BatchNumber { get; set; }
55 55  
56 56 /// <summary>
  57 + /// 入库类型(1:普通入库 2:采购入库)
  58 + /// </summary>
  59 + [SugarColumn(ColumnName = "F_StockInType")]
  60 + public int? StockInType { get; set; } = 1;
  61 +
  62 + /// <summary>
  63 + /// 采购单号
  64 + /// </summary>
  65 + [SugarColumn(ColumnName = "F_PurchaseOrderNo")]
  66 + public string PurchaseOrderNo { get; set; }
  67 +
  68 + /// <summary>
  69 + /// 采购单价
  70 + /// </summary>
  71 + [SugarColumn(ColumnName = "F_PurchaseUnitPrice")]
  72 + public decimal? PurchaseUnitPrice { get; set; } = 0;
  73 +
  74 + /// <summary>
  75 + /// 采购总金额(采购单价 × 数量)
  76 + /// </summary>
  77 + [SugarColumn(ColumnName = "F_PurchaseAmount")]
  78 + public decimal? PurchaseAmount { get; set; } = 0;
  79 +
  80 + /// <summary>
  81 + /// 产品最终金额(采购金额或其他成本)
  82 + /// </summary>
  83 + [SugarColumn(ColumnName = "F_FinalAmount")]
  84 + public decimal? FinalAmount { get; set; } = 0;
  85 +
  86 + /// <summary>
57 87 /// 是否有效(1:有效 0:无效)
58 88 /// </summary>
59 89 [SugarColumn(ColumnName = "F_IsEffective")]
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqInventoryService.cs
... ... @@ -16,6 +16,7 @@ using NCC.Extend.Entitys.lq_product;
16 16 using NCC.Extend.Interfaces.LqInventory;
17 17 using NCC.FriendlyException;
18 18 using NCC.System.Entitys.Permission;
  19 +using NCC.System.Interfaces.System;
19 20 using SqlSugar;
20 21 using Yitter.IdGenerator;
21 22  
... ... @@ -31,6 +32,7 @@ namespace NCC.Extend
31 32 private readonly IUserManager _userManager;
32 33 private readonly ILogger<LqInventoryService> _logger;
33 34 private readonly ISqlSugarClient _db;
  35 + private readonly IBillRullService _billRuleService;
34 36  
35 37 /// <summary>
36 38 /// 构造函数
... ... @@ -38,11 +40,13 @@ namespace NCC.Extend
38 40 /// <param name="userManager">用户管理器</param>
39 41 /// <param name="logger">日志记录器</param>
40 42 /// <param name="db">数据库客户端</param>
41   - public LqInventoryService(IUserManager userManager, ILogger<LqInventoryService> logger, ISqlSugarClient db)
  43 + /// <param name="billRuleService">单据规则服务</param>
  44 + public LqInventoryService(IUserManager userManager, ILogger<LqInventoryService> logger, ISqlSugarClient db, IBillRullService billRuleService)
42 45 {
43 46 _userManager = userManager;
44 47 _logger = logger;
45 48 _db = db;
  49 + _billRuleService = billRuleService;
46 50 }
47 51  
48 52 #region 添加库存信息
... ... @@ -50,9 +54,22 @@ namespace NCC.Extend
50 54 /// 添加库存信息
51 55 /// </summary>
52 56 /// <remarks>
53   - /// 针对某个产品添加库存记录
  57 + /// 针对某个产品添加库存记录,支持普通入库和采购入库
54 58 ///
55   - /// 示例请求:
  59 + /// 示例请求(普通入库):
  60 + /// ```json
  61 + /// {
  62 + /// "productId": "产品ID",
  63 + /// "quantity": 100,
  64 + /// "stockInTime": "2024-01-01",
  65 + /// "productionDate": "2023-12-01",
  66 + /// "shelfLife": 365,
  67 + /// "batchNumber": "批次号001",
  68 + /// "stockInType": 1
  69 + /// }
  70 + /// ```
  71 + ///
  72 + /// 示例请求(采购入库):
56 73 /// ```json
57 74 /// {
58 75 /// "productId": "产品ID",
... ... @@ -60,9 +77,21 @@ namespace NCC.Extend
60 77 /// "stockInTime": "2024-01-01",
61 78 /// "productionDate": "2023-12-01",
62 79 /// "shelfLife": 365,
63   - /// "batchNumber": "批次号001"
  80 + /// "batchNumber": "批次号001",
  81 + /// "stockInType": 2,
  82 + /// "purchaseUnitPrice": 50.00,
  83 + /// "finalAmount": 5000.00
64 84 /// }
65 85 /// ```
  86 + ///
  87 + /// 参数说明:
  88 + /// - productId: 产品ID(必填)
  89 + /// - quantity: 数量(必填,大于0)
  90 + /// - stockInType: 入库类型(1:普通入库 2:采购入库,默认1)
  91 + /// - purchaseUnitPrice: 采购单价(采购入库时必填)
  92 + /// - purchaseAmount: 采购总金额(系统自动计算:采购单价 × 数量)
  93 + /// - finalAmount: 产品最终金额(采购入库时建议填写)
  94 + /// - purchaseOrderNo: 采购单号(采购入库时自动生成)
66 95 /// </remarks>
67 96 /// <param name="input">创建输入</param>
68 97 /// <returns>创建结果</returns>
... ... @@ -84,6 +113,56 @@ namespace NCC.Extend
84 113 throw NCCException.Oh("产品不存在");
85 114 }
86 115  
  116 + // 验证数量
  117 + if (input.Quantity <= 0)
  118 + {
  119 + throw NCCException.Oh("库存数量必须大于0");
  120 + }
  121 +
  122 + // 入库类型,默认为普通入库
  123 + var stockInType = input.StockInType ?? 1;
  124 +
  125 + // 如果是采购入库,验证采购金额相关字段
  126 + string purchaseOrderNo = null;
  127 + decimal? purchaseUnitPrice = null;
  128 + decimal? purchaseAmount = null;
  129 + decimal? finalAmount = null;
  130 +
  131 + if (stockInType == 2) // 采购入库
  132 + {
  133 + // 验证采购单价
  134 + if (input.PurchaseUnitPrice == null || input.PurchaseUnitPrice <= 0)
  135 + {
  136 + throw NCCException.Oh("采购入库时,采购单价必须大于0");
  137 + }
  138 +
  139 + purchaseUnitPrice = input.PurchaseUnitPrice;
  140 +
  141 + // 计算采购总金额(采购单价 × 数量)
  142 + purchaseAmount = purchaseUnitPrice.Value * input.Quantity;
  143 +
  144 + // 产品最终金额:如果用户提供了,使用用户提供的;否则使用采购总金额
  145 + finalAmount = input.FinalAmount ?? purchaseAmount;
  146 +
  147 + // 生成采购单号(使用单据规则服务)
  148 + try
  149 + {
  150 + purchaseOrderNo = await _billRuleService.GetBillNumber("PurchaseOrder", false);
  151 + // 如果返回的是错误信息,也使用fallback
  152 + if (string.IsNullOrEmpty(purchaseOrderNo) || purchaseOrderNo == "单据规则不存在")
  153 + {
  154 + _logger.LogWarning("采购单号生成失败(单据规则不存在),使用时间戳作为单号");
  155 + purchaseOrderNo = $"CG{DateTime.Now:yyyyMMddHHmmss}";
  156 + }
  157 + }
  158 + catch (Exception ex)
  159 + {
  160 + _logger.LogWarning(ex, "生成采购单号失败,使用时间戳作为单号");
  161 + // 如果生成失败,使用时间戳作为单号
  162 + purchaseOrderNo = $"CG{DateTime.Now:yyyyMMddHHmmss}";
  163 + }
  164 + }
  165 +
87 166 // 创建库存记录
88 167 var inventoryEntity = new LqInventoryEntity
89 168 {
... ... @@ -94,6 +173,11 @@ namespace NCC.Extend
94 173 ProductionDate = input.ProductionDate,
95 174 ShelfLife = input.ShelfLife,
96 175 BatchNumber = input.BatchNumber,
  176 + StockInType = stockInType,
  177 + PurchaseOrderNo = purchaseOrderNo,
  178 + PurchaseUnitPrice = purchaseUnitPrice,
  179 + PurchaseAmount = purchaseAmount,
  180 + FinalAmount = finalAmount,
97 181 IsEffective = StatusEnum.有效.GetHashCode(),
98 182 CreateUser = _userManager.UserId,
99 183 CreateTime = DateTime.Now
... ... @@ -114,8 +198,26 @@ namespace NCC.Extend
114 198 /// <summary>
115 199 /// 更新库存信息
116 200 /// </summary>
  201 + /// <remarks>
  202 + /// 更新库存记录,支持普通入库和采购入库的金额更新
  203 + ///
  204 + /// 示例请求(采购入库更新):
  205 + /// ```json
  206 + /// {
  207 + /// "id": "库存ID",
  208 + /// "productId": "产品ID",
  209 + /// "quantity": 100,
  210 + /// "stockInType": 2,
  211 + /// "purchaseUnitPrice": 50.00,
  212 + /// "finalAmount": 5000.00
  213 + /// }
  214 + /// ```
  215 + /// </remarks>
117 216 /// <param name="input">更新输入</param>
118 217 /// <returns>更新结果</returns>
  218 + /// <response code="200">更新成功</response>
  219 + /// <response code="400">库存记录不存在或参数错误</response>
  220 + /// <response code="500">服务器错误</response>
119 221 [HttpPut("Update")]
120 222 public async Task UpdateAsync([FromBody] LqInventoryUpInput input)
121 223 {
... ... @@ -140,6 +242,57 @@ namespace NCC.Extend
140 242 throw NCCException.Oh("产品不存在");
141 243 }
142 244  
  245 + // 验证数量
  246 + if (input.Quantity <= 0)
  247 + {
  248 + throw NCCException.Oh("库存数量必须大于0");
  249 + }
  250 +
  251 + // 入库类型,默认为普通入库
  252 + var stockInType = input.StockInType ?? 1;
  253 +
  254 + // 如果是采购入库,验证和计算采购金额
  255 + decimal? purchaseUnitPrice = null;
  256 + decimal? purchaseAmount = null;
  257 + decimal? finalAmount = null;
  258 +
  259 + if (stockInType == 2) // 采购入库
  260 + {
  261 + // 验证采购单价
  262 + if (input.PurchaseUnitPrice == null || input.PurchaseUnitPrice <= 0)
  263 + {
  264 + throw NCCException.Oh("采购入库时,采购单价必须大于0");
  265 + }
  266 +
  267 + purchaseUnitPrice = input.PurchaseUnitPrice;
  268 +
  269 + // 计算采购总金额(采购单价 × 数量)
  270 + purchaseAmount = purchaseUnitPrice.Value * input.Quantity;
  271 +
  272 + // 产品最终金额:如果用户提供了,使用用户提供的;否则使用采购总金额
  273 + finalAmount = input.FinalAmount ?? purchaseAmount;
  274 +
  275 + // 如果原来没有采购单号,生成新的采购单号
  276 + if (string.IsNullOrEmpty(existingInventory.PurchaseOrderNo) || existingInventory.PurchaseOrderNo == "单据规则不存在")
  277 + {
  278 + try
  279 + {
  280 + existingInventory.PurchaseOrderNo = await _billRuleService.GetBillNumber("PurchaseOrder", false);
  281 + // 如果返回的是错误信息,也使用fallback
  282 + if (string.IsNullOrEmpty(existingInventory.PurchaseOrderNo) || existingInventory.PurchaseOrderNo == "单据规则不存在")
  283 + {
  284 + _logger.LogWarning("采购单号生成失败(单据规则不存在),使用时间戳作为单号");
  285 + existingInventory.PurchaseOrderNo = $"CG{DateTime.Now:yyyyMMddHHmmss}";
  286 + }
  287 + }
  288 + catch (Exception ex)
  289 + {
  290 + _logger.LogWarning(ex, "生成采购单号失败,使用时间戳作为单号");
  291 + existingInventory.PurchaseOrderNo = $"CG{DateTime.Now:yyyyMMddHHmmss}";
  292 + }
  293 + }
  294 + }
  295 +
143 296 // 更新库存记录
144 297 existingInventory.ProductId = input.ProductId;
145 298 existingInventory.Quantity = input.Quantity;
... ... @@ -147,6 +300,10 @@ namespace NCC.Extend
147 300 existingInventory.ProductionDate = input.ProductionDate;
148 301 existingInventory.ShelfLife = input.ShelfLife;
149 302 existingInventory.BatchNumber = input.BatchNumber;
  303 + existingInventory.StockInType = stockInType;
  304 + existingInventory.PurchaseUnitPrice = purchaseUnitPrice;
  305 + existingInventory.PurchaseAmount = purchaseAmount;
  306 + existingInventory.FinalAmount = finalAmount;
150 307 existingInventory.UpdateUser = _userManager.UserId;
151 308 existingInventory.UpdateTime = DateTime.Now;
152 309  
... ... @@ -200,6 +357,11 @@ namespace NCC.Extend
200 357 productionDate = inv.ProductionDate,
201 358 shelfLife = inv.ShelfLife,
202 359 batchNumber = inv.BatchNumber,
  360 + stockInType = inv.StockInType,
  361 + purchaseOrderNo = inv.PurchaseOrderNo,
  362 + purchaseUnitPrice = inv.PurchaseUnitPrice,
  363 + purchaseAmount = inv.PurchaseAmount,
  364 + finalAmount = inv.FinalAmount,
203 365 createUser = inv.CreateUser,
204 366 createUserName = "",
205 367 createTime = inv.CreateTime,
... ... @@ -309,6 +471,11 @@ namespace NCC.Extend
309 471 productionDate = inv.ProductionDate,
310 472 shelfLife = inv.ShelfLife,
311 473 batchNumber = inv.BatchNumber,
  474 + stockInType = inv.StockInType,
  475 + purchaseOrderNo = inv.PurchaseOrderNo,
  476 + purchaseUnitPrice = inv.PurchaseUnitPrice,
  477 + purchaseAmount = inv.PurchaseAmount,
  478 + finalAmount = inv.FinalAmount,
312 479 createUser = inv.CreateUser,
313 480 createUserName = "",
314 481 createTime = inv.CreateTime,
... ...
sql/添加采购入库金额字段.sql 0 → 100644
  1 +-- ============================================
  2 +-- 在库存表中添加采购入库金额相关字段
  3 +-- ============================================
  4 +-- 说明:为采购入库功能添加金额记录字段
  5 +-- ============================================
  6 +
  7 +-- 1. 添加入库类型字段(1:普通入库 2:采购入库)
  8 +ALTER TABLE lq_inventory
  9 +ADD COLUMN F_StockInType INT NULL DEFAULT 1 COMMENT '入库类型(1:普通入库 2:采购入库)' AFTER F_BatchNumber;
  10 +
  11 +-- 2. 添加采购单号字段
  12 +ALTER TABLE lq_inventory
  13 +ADD COLUMN F_PurchaseOrderNo VARCHAR(50) NULL COMMENT '采购单号' AFTER F_StockInType;
  14 +
  15 +-- 3. 添加采购单价字段
  16 +ALTER TABLE lq_inventory
  17 +ADD COLUMN F_PurchaseUnitPrice DECIMAL(18,2) NULL DEFAULT 0.00 COMMENT '采购单价' AFTER F_PurchaseOrderNo;
  18 +
  19 +-- 4. 添加采购总金额字段(采购单价 × 数量)
  20 +ALTER TABLE lq_inventory
  21 +ADD COLUMN F_PurchaseAmount DECIMAL(18,2) NULL DEFAULT 0.00 COMMENT '采购总金额(采购单价 × 数量)' AFTER F_PurchaseUnitPrice;
  22 +
  23 +-- 5. 添加产品最终金额字段(可能是采购金额,或者采购金额+其他成本)
  24 +ALTER TABLE lq_inventory
  25 +ADD COLUMN F_FinalAmount DECIMAL(18,2) NULL DEFAULT 0.00 COMMENT '产品最终金额(采购金额或其他成本)' AFTER F_PurchaseAmount;
  26 +
  27 +-- 6. 添加索引
  28 +ALTER TABLE lq_inventory
  29 +ADD INDEX idx_stock_in_type (F_StockInType) COMMENT '入库类型索引';
  30 +
  31 +ALTER TABLE lq_inventory
  32 +ADD INDEX idx_purchase_order_no (F_PurchaseOrderNo) COMMENT '采购单号索引';
... ...