# 库存平均单价计算逻辑说明 ## 概述 采用**加权平均成本法(Weighted Average Cost Method)**来计算库存的平均单价,用于出库计价。 ## 核心原则 1. **入库时**:根据当前平均单价和入库单价,计算新的平均单价 2. **出库时**:使用当前平均单价,出库后平均单价不变 3. **平均单价维护**:存储在 `lq_product.F_AveragePrice` 字段中 ## 计算公式 ### 入库时计算新平均单价 ``` 新平均单价 = (当前平均单价 × 当前可用库存数量 + 入库单价 × 入库数量) / (当前可用库存数量 + 入库数量) ``` 其中: - **当前可用库存数量** = 总库存数量 - 已领取数量 - **入库单价**: - 采购入库:使用采购单价(`F_PurchaseUnitPrice`) - 普通入库:使用产品价格(`F_Price`) ### 出库时使用平均单价 ``` 出库单价 = 产品平均单价(F_AveragePrice) 出库总金额 = 出库单价 × 出库数量 ``` **注意**:出库后,平均单价不变(因为已经领取的库存已经按照当时的平均单价计价了) ## 示例说明 ### 示例1:基本流程 **初始状态**: - 商品A:当前平均单价 = 150 - 库存A:数量1,单价100 - 库存B:数量1,单价200 **步骤1:领取1个** - 使用平均单价:150 - 领取后剩余:1个库存 - 平均单价不变:150 **步骤2:再次入库1个,单价50** - 当前可用库存数量:1 - 当前库存总金额:150 × 1 = 150 - 入库金额:50 × 1 = 50 - **新平均单价** = (150 + 50) / (1 + 1) = **100** ### 示例2:多次入库 **初始状态**: - 商品B:当前平均单价 = 100,当前可用库存 = 10 **步骤1:采购入库5个,单价120** - 当前库存总金额:100 × 10 = 1000 - 入库金额:120 × 5 = 600 - **新平均单价** = (1000 + 600) / (10 + 5) = **106.67** **步骤2:领取3个** - 使用平均单价:106.67 - 领取后剩余:12个库存 - 平均单价不变:106.67 **步骤3:再次采购入库8个,单价110** - 当前可用库存数量:12 - 当前库存总金额:106.67 × 12 = 1280.04 - 入库金额:110 × 8 = 880 - **新平均单价** = (1280.04 + 880) / (12 + 8) = **108.00** ## 数据库字段 ### 产品表(lq_product) - `F_AveragePrice`:平均单价(加权平均成本,用于出库计价) ### 库存表(lq_inventory) - `F_PurchaseUnitPrice`:采购单价(采购入库时使用) - `F_FinalAmount`:产品最终金额(优先用于计算单价) - `F_Quantity`:库存数量 ### 库存使用记录表(lq_inventory_usage) - `F_UnitPrice`:使用时的单价(从产品平均单价获取) - `F_TotalAmount`:使用总金额(单价 × 数量) ## 实现逻辑 ### 1. 入库时(LqInventoryService.CreateAsync / UpdateAsync) ```csharp // 计算当前可用库存数量 var currentAvailableQuantity = totalInventoryQuantity - totalUsageQuantity; // 确定入库单价 decimal incomingPrice = stockInType == 2 && purchaseUnitPrice.HasValue ? purchaseUnitPrice.Value // 采购入库 : product.Price; // 普通入库 // 计算新平均单价 if (currentAvailableQuantity <= 0) { newAveragePrice = incomingPrice; // 没有库存时,直接使用入库单价 } else { var currentTotalAmount = product.AveragePrice * currentAvailableQuantity; var incomingAmount = incomingPrice * incomingQuantity; newAveragePrice = (currentTotalAmount + incomingAmount) / (currentAvailableQuantity + incomingQuantity); } // 更新产品平均单价 product.AveragePrice = newAveragePrice; ``` ### 2. 出库时(LqInventoryUsageService.CreateAsync / ConfirmReceiveAsync) ```csharp // 使用产品的平均单价 var unitPrice = product.AveragePrice > 0 ? product.AveragePrice : product.Price; var totalAmount = unitPrice * usageQuantity; // 创建使用记录(平均单价不变) usageEntity.UnitPrice = unitPrice; usageEntity.TotalAmount = totalAmount; ``` ## 初始化历史数据 对于已有库存的产品,根据当前库存计算初始平均单价: ```sql 平均单价 = SUM(库存金额) / SUM(库存数量) ``` 其中,库存金额优先使用 `F_FinalAmount`,其次使用 `F_PurchaseUnitPrice × F_Quantity`。 ## 注意事项 1. **平均单价维护**:每次入库时自动更新,出库时不变 2. **可用库存计算**:需要考虑已领取的数量 3. **普通入库**:如果没有采购单价,使用产品价格作为入库单价 4. **历史数据初始化**:首次添加字段时,需要根据现有库存计算初始平均单价 5. **数据一致性**:确保入库和出库操作在事务中执行,保证平均单价的一致性