feat(mat): 添加入库记录时同步更新库存和价格历史功能
- 在 MatPurchaseInDetailService 中新增 insertByBoWithInventoryAndPriceHistory 方法 - 在 MatPurchaseInDetailService 中新增 deleteWithValidByIdsWithInventoryAndPriceHistory 方法 - 扩展 MatPriceHistory 实体类添加 purchaseInDetailId 关联字段 - 更新 MatPriceHistoryMapper.xml 映射文件包含新的关联字段 - 修改控制器方法调用新的带库存和价格历史更新的入库接口 - 实现库存数量更新逻辑和价格历史记录管理功能 - 添加入库记录删除时还原库存和价格历史的功能
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
package com.gear.mat.controller;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.gear.mat.domain.bo.MatMaterialBo;
|
||||
import com.gear.mat.domain.bo.MatPriceHistoryBo;
|
||||
import com.gear.mat.domain.vo.MatMaterialVo;
|
||||
import com.gear.mat.domain.vo.MatPriceHistoryVo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.*;
|
||||
@@ -25,6 +30,8 @@ import com.gear.mat.domain.bo.MatPurchaseInDetailBo;
|
||||
import com.gear.mat.service.IMatPurchaseInDetailService;
|
||||
import com.gear.common.core.page.TableDataInfo;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 入库记录
|
||||
*
|
||||
@@ -75,7 +82,7 @@ public class MatPurchaseInDetailController extends BaseController {
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody MatPurchaseInDetailBo bo) {
|
||||
return toAjax(iMatPurchaseInDetailService.insertByBo(bo));
|
||||
return toAjax(iMatPurchaseInDetailService.insertByBoWithInventoryAndPriceHistory(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,6 +104,6 @@ public class MatPurchaseInDetailController extends BaseController {
|
||||
@DeleteMapping("/{detailIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] detailIds) {
|
||||
return toAjax(iMatPurchaseInDetailService.deleteWithValidByIds(Arrays.asList(detailIds), true));
|
||||
return toAjax(iMatPurchaseInDetailService.deleteWithValidByIdsWithInventoryAndPriceHistory(Arrays.asList(detailIds), true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,4 +52,6 @@ public class MatPriceHistory extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
// 关联入库记录id purchase_in_detail_id
|
||||
private Long purchaseInDetailId;
|
||||
}
|
||||
|
||||
@@ -48,4 +48,7 @@ public class MatPriceHistoryBo extends BaseEntity {
|
||||
private String remark;
|
||||
|
||||
|
||||
// 关联入库记录id purchase_in_detail_id
|
||||
private Long purchaseInDetailId;
|
||||
|
||||
}
|
||||
|
||||
@@ -91,4 +91,6 @@ public class MatPriceHistoryVo {
|
||||
private BigDecimal currentStock;
|
||||
|
||||
|
||||
// 关联入库记录id purchase_in_detail_id
|
||||
private Long purchaseInDetailId;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,11 @@ public interface IMatPurchaseInDetailService {
|
||||
*/
|
||||
Boolean insertByBo(MatPurchaseInDetailBo bo);
|
||||
|
||||
/**
|
||||
* 新增入库记录并更新库存和价格历史
|
||||
*/
|
||||
Boolean insertByBoWithInventoryAndPriceHistory(MatPurchaseInDetailBo bo);
|
||||
|
||||
/**
|
||||
* 修改入库记录
|
||||
*/
|
||||
@@ -46,4 +51,9 @@ public interface IMatPurchaseInDetailService {
|
||||
* 校验并批量删除入库记录信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 校验并批量删除入库记录信息,并还原库存和价格历史
|
||||
*/
|
||||
Boolean deleteWithValidByIdsWithInventoryAndPriceHistory(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
|
||||
@@ -15,10 +15,17 @@ import com.gear.mat.domain.vo.MatPurchaseInDetailVo;
|
||||
import com.gear.mat.domain.MatPurchaseInDetail;
|
||||
import com.gear.mat.mapper.MatPurchaseInDetailMapper;
|
||||
import com.gear.mat.service.IMatPurchaseInDetailService;
|
||||
import com.gear.mat.service.IMatMaterialService;
|
||||
import com.gear.mat.service.IMatPriceHistoryService;
|
||||
import com.gear.mat.domain.vo.MatMaterialVo;
|
||||
import com.gear.mat.domain.vo.MatPriceHistoryVo;
|
||||
import com.gear.mat.domain.bo.MatMaterialBo;
|
||||
import com.gear.mat.domain.bo.MatPriceHistoryBo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 入库记录Service业务层处理
|
||||
@@ -31,6 +38,8 @@ import java.util.Collection;
|
||||
public class MatPurchaseInDetailServiceImpl implements IMatPurchaseInDetailService {
|
||||
|
||||
private final MatPurchaseInDetailMapper baseMapper;
|
||||
private final IMatMaterialService matMaterialService;
|
||||
private final IMatPriceHistoryService matPriceHistoryService;
|
||||
|
||||
/**
|
||||
* 查询入库记录
|
||||
@@ -131,4 +140,174 @@ public class MatPurchaseInDetailServiceImpl implements IMatPurchaseInDetailServi
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBoWithInventoryAndPriceHistory(MatPurchaseInDetailBo bo) {
|
||||
boolean success = insertByBo(bo);
|
||||
|
||||
if (success && bo.getMaterialId() != null && bo.getInNum() != null && bo.getInPrice() != null) {
|
||||
// 更新库存数量
|
||||
updateInventory(bo.getMaterialId(), bo.getInNum());
|
||||
|
||||
// 插入价格历史记录
|
||||
insertPriceHistory(bo.getMaterialId(), bo.getInPrice(), bo.getInNum(), bo.getDetailId());
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIdsWithInventoryAndPriceHistory(Collection<Long> ids, Boolean isValid) {
|
||||
// 获取待删除的入库记录信息,以便后续还原库存和价格历史
|
||||
List<MatPurchaseInDetailVo> recordsToDelete = new ArrayList<>();
|
||||
for (Long detailId : ids) {
|
||||
MatPurchaseInDetailVo record = queryById(detailId);
|
||||
if (record != null) {
|
||||
recordsToDelete.add(record);
|
||||
}
|
||||
}
|
||||
|
||||
boolean success = deleteWithValidByIds(ids, isValid);
|
||||
|
||||
if (success) {
|
||||
// 对于每个被删除的入库记录,还原库存并删除对应的价格历史记录
|
||||
for (MatPurchaseInDetailVo record : recordsToDelete) {
|
||||
// 还原库存数量
|
||||
revertInventory(record.getMaterialId(), record.getInNum());
|
||||
|
||||
// 删除对应的价格历史记录
|
||||
deletePriceHistory(record.getMaterialId(), record.getDetailId());
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新库存数量
|
||||
*/
|
||||
private void updateInventory(Long materialId, BigDecimal quantity) {
|
||||
MatMaterialVo material = matMaterialService.queryById(materialId);
|
||||
if (material != null) {
|
||||
MatMaterialBo materialBo = new MatMaterialBo();
|
||||
materialBo.setMaterialId(materialId);
|
||||
|
||||
// 计算新的库存数量
|
||||
BigDecimal newStock = material.getCurrentStock().add(quantity);
|
||||
materialBo.setCurrentStock(newStock);
|
||||
|
||||
matMaterialService.updateByBo(materialBo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入价格历史记录
|
||||
*/
|
||||
private void insertPriceHistory(Long materialId, BigDecimal price, BigDecimal quantity, Long detailId) {
|
||||
// 获取当前库存和平均价格信息
|
||||
MatMaterialVo material = matMaterialService.queryById(materialId);
|
||||
if (material != null) {
|
||||
// 计算新的平均价格
|
||||
BigDecimal avgPrice = calculateAveragePrice(materialId, price, quantity);
|
||||
|
||||
// 创建价格历史记录
|
||||
MatPriceHistoryBo priceHistoryBo = new MatPriceHistoryBo();
|
||||
priceHistoryBo.setMaterialId(materialId);
|
||||
priceHistoryBo.setPrice(price);
|
||||
priceHistoryBo.setAvgPrice(avgPrice);
|
||||
priceHistoryBo.setQuantity(quantity);
|
||||
priceHistoryBo.setPurchaseInDetailId(detailId); // 关联入库明细ID
|
||||
|
||||
matPriceHistoryService.insertByBo(priceHistoryBo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算平均价格
|
||||
*/
|
||||
private BigDecimal calculateAveragePrice(Long materialId, BigDecimal newPrice, BigDecimal newQuantity) {
|
||||
// 获取最新的价格历史记录来计算平均价格
|
||||
MatPriceHistoryBo condition = new MatPriceHistoryBo();
|
||||
condition.setMaterialId(materialId);
|
||||
|
||||
List<MatPriceHistoryVo> historyList = matPriceHistoryService.queryList(condition);
|
||||
|
||||
// 如果没有历史记录,则平均价格就是当前价格
|
||||
if (historyList == null || historyList.isEmpty()) {
|
||||
return newPrice;
|
||||
}
|
||||
|
||||
// 获取最近一次的平均价格和库存信息
|
||||
MatPriceHistoryVo lastHistory = historyList.get(0); // 最近的一条记录
|
||||
|
||||
// 获取当前物料的现有库存
|
||||
MatMaterialVo material = matMaterialService.queryById(materialId);
|
||||
if (material == null) {
|
||||
return newPrice;
|
||||
}
|
||||
|
||||
BigDecimal existingStock = material.getCurrentStock().subtract(newQuantity); // 扣除本次入库的数量
|
||||
BigDecimal existingAvgPrice = lastHistory.getAvgPrice();
|
||||
|
||||
// 计算加权平均价格
|
||||
if (existingStock.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
// 如果之前没有库存,则直接使用新价格
|
||||
return newPrice;
|
||||
} else {
|
||||
// 加权平均 = (原库存数量 * 原平均价 + 新入库数量 * 新价格) / (原库存数量 + 新入库数量)
|
||||
BigDecimal totalValue = existingStock.multiply(existingAvgPrice).add(newQuantity.multiply(newPrice));
|
||||
BigDecimal totalQuantity = existingStock.add(newQuantity);
|
||||
|
||||
if (totalQuantity.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return newPrice;
|
||||
}
|
||||
|
||||
return totalValue.divide(totalQuantity, 6, BigDecimal.ROUND_HALF_UP); // 保留6位小数
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 还原库存数量(减少库存)
|
||||
*/
|
||||
private void revertInventory(Long materialId, BigDecimal quantity) {
|
||||
MatMaterialVo material = matMaterialService.queryById(materialId);
|
||||
if (material != null) {
|
||||
MatMaterialBo materialBo = new MatMaterialBo();
|
||||
materialBo.setMaterialId(materialId);
|
||||
materialBo.setMaterialName(material.getMaterialName());
|
||||
materialBo.setSpec(material.getSpec());
|
||||
materialBo.setModel(material.getModel());
|
||||
materialBo.setFactory(material.getFactory());
|
||||
materialBo.setUnit(material.getUnit());
|
||||
|
||||
// 计算还原后的库存数量(减去本次入库的数量)
|
||||
BigDecimal newStock = material.getCurrentStock().subtract(quantity);
|
||||
if (newStock.compareTo(BigDecimal.ZERO) < 0) {
|
||||
newStock = BigDecimal.ZERO; // 库存不能为负数
|
||||
}
|
||||
materialBo.setCurrentStock(newStock);
|
||||
|
||||
materialBo.setRemark(material.getRemark());
|
||||
matMaterialService.updateByBo(materialBo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除对应的价格历史记录
|
||||
*/
|
||||
private void deletePriceHistory(Long materialId, Long purchaseInDetailId) {
|
||||
MatPriceHistoryBo condition = new MatPriceHistoryBo();
|
||||
condition.setMaterialId(materialId);
|
||||
condition.setPurchaseInDetailId(purchaseInDetailId); // 使用精确的入库明细ID进行匹配
|
||||
|
||||
// 精确删除对应的记录
|
||||
List<MatPriceHistoryVo> historyList = matPriceHistoryService.queryList(condition);
|
||||
|
||||
if (historyList != null && !historyList.isEmpty()) {
|
||||
List<Long> historyIdsToDelete = historyList.stream()
|
||||
.map(MatPriceHistoryVo::getHistoryId)
|
||||
.collect(Collectors.toList());
|
||||
matPriceHistoryService.deleteWithValidByIds(historyIdsToDelete, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="purchaseInDetailId" column="purchase_in_detail_id"/>
|
||||
</resultMap>
|
||||
<select id="selectVoPagePlus" resultType="com.gear.mat.domain.vo.MatPriceHistoryVo">
|
||||
SELECT
|
||||
@@ -29,6 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
t.update_time AS updateTime,
|
||||
t.update_by AS updateBy,
|
||||
t.remark AS remark,
|
||||
t.purchase_in_detail_id AS purchaseInDetailId,
|
||||
mm.material_name AS materialName,
|
||||
mm.spec AS spec,
|
||||
mm.model AS model,
|
||||
|
||||
Reference in New Issue
Block a user