From d9e0205da1593b6286c018e0cc10508a49fa8675 Mon Sep 17 00:00:00 2001 From: Joshi <3040996759@qq.com> Date: Fri, 30 Jan 2026 16:13:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(mat):=20=E6=B7=BB=E5=8A=A0=E5=85=A5?= =?UTF-8?q?=E5=BA=93=E8=AE=B0=E5=BD=95=E6=97=B6=E5=90=8C=E6=AD=A5=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=BA=93=E5=AD=98=E5=92=8C=E4=BB=B7=E6=A0=BC=E5=8E=86?= =?UTF-8?q?=E5=8F=B2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 MatPurchaseInDetailService 中新增 insertByBoWithInventoryAndPriceHistory 方法 - 在 MatPurchaseInDetailService 中新增 deleteWithValidByIdsWithInventoryAndPriceHistory 方法 - 扩展 MatPriceHistory 实体类添加 purchaseInDetailId 关联字段 - 更新 MatPriceHistoryMapper.xml 映射文件包含新的关联字段 - 修改控制器方法调用新的带库存和价格历史更新的入库接口 - 实现库存数量更新逻辑和价格历史记录管理功能 - 添加入库记录删除时还原库存和价格历史的功能 --- .../MatPurchaseInDetailController.java | 11 +- .../com/gear/mat/domain/MatPriceHistory.java | 2 + .../gear/mat/domain/bo/MatPriceHistoryBo.java | 3 + .../gear/mat/domain/vo/MatPriceHistoryVo.java | 2 + .../service/IMatPurchaseInDetailService.java | 10 + .../impl/MatPurchaseInDetailServiceImpl.java | 185 +++++++++++++++++- .../mapper/MatPriceHistoryMapper.xml | 2 + 7 files changed, 210 insertions(+), 5 deletions(-) diff --git a/gear-mat/src/main/java/com/gear/mat/controller/MatPurchaseInDetailController.java b/gear-mat/src/main/java/com/gear/mat/controller/MatPurchaseInDetailController.java index 0d282ce..ad0e14d 100644 --- a/gear-mat/src/main/java/com/gear/mat/controller/MatPurchaseInDetailController.java +++ b/gear-mat/src/main/java/com/gear/mat/controller/MatPurchaseInDetailController.java @@ -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 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 remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] detailIds) { - return toAjax(iMatPurchaseInDetailService.deleteWithValidByIds(Arrays.asList(detailIds), true)); + return toAjax(iMatPurchaseInDetailService.deleteWithValidByIdsWithInventoryAndPriceHistory(Arrays.asList(detailIds), true)); } } diff --git a/gear-mat/src/main/java/com/gear/mat/domain/MatPriceHistory.java b/gear-mat/src/main/java/com/gear/mat/domain/MatPriceHistory.java index 1423a03..78f4473 100644 --- a/gear-mat/src/main/java/com/gear/mat/domain/MatPriceHistory.java +++ b/gear-mat/src/main/java/com/gear/mat/domain/MatPriceHistory.java @@ -52,4 +52,6 @@ public class MatPriceHistory extends BaseEntity { */ private String remark; + // 关联入库记录id purchase_in_detail_id + private Long purchaseInDetailId; } diff --git a/gear-mat/src/main/java/com/gear/mat/domain/bo/MatPriceHistoryBo.java b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatPriceHistoryBo.java index c311503..2f81dbf 100644 --- a/gear-mat/src/main/java/com/gear/mat/domain/bo/MatPriceHistoryBo.java +++ b/gear-mat/src/main/java/com/gear/mat/domain/bo/MatPriceHistoryBo.java @@ -48,4 +48,7 @@ public class MatPriceHistoryBo extends BaseEntity { private String remark; + // 关联入库记录id purchase_in_detail_id + private Long purchaseInDetailId; + } diff --git a/gear-mat/src/main/java/com/gear/mat/domain/vo/MatPriceHistoryVo.java b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatPriceHistoryVo.java index 61e940e..eb144d7 100644 --- a/gear-mat/src/main/java/com/gear/mat/domain/vo/MatPriceHistoryVo.java +++ b/gear-mat/src/main/java/com/gear/mat/domain/vo/MatPriceHistoryVo.java @@ -91,4 +91,6 @@ public class MatPriceHistoryVo { private BigDecimal currentStock; + // 关联入库记录id purchase_in_detail_id + private Long purchaseInDetailId; } diff --git a/gear-mat/src/main/java/com/gear/mat/service/IMatPurchaseInDetailService.java b/gear-mat/src/main/java/com/gear/mat/service/IMatPurchaseInDetailService.java index 6679816..f74e494 100644 --- a/gear-mat/src/main/java/com/gear/mat/service/IMatPurchaseInDetailService.java +++ b/gear-mat/src/main/java/com/gear/mat/service/IMatPurchaseInDetailService.java @@ -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 ids, Boolean isValid); + + /** + * 校验并批量删除入库记录信息,并还原库存和价格历史 + */ + Boolean deleteWithValidByIdsWithInventoryAndPriceHistory(Collection ids, Boolean isValid); } diff --git a/gear-mat/src/main/java/com/gear/mat/service/impl/MatPurchaseInDetailServiceImpl.java b/gear-mat/src/main/java/com/gear/mat/service/impl/MatPurchaseInDetailServiceImpl.java index 57b5710..fbd91b7 100644 --- a/gear-mat/src/main/java/com/gear/mat/service/impl/MatPurchaseInDetailServiceImpl.java +++ b/gear-mat/src/main/java/com/gear/mat/service/impl/MatPurchaseInDetailServiceImpl.java @@ -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 ids, Boolean isValid) { + // 获取待删除的入库记录信息,以便后续还原库存和价格历史 + List 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 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 historyList = matPriceHistoryService.queryList(condition); + + if (historyList != null && !historyList.isEmpty()) { + List historyIdsToDelete = historyList.stream() + .map(MatPriceHistoryVo::getHistoryId) + .collect(Collectors.toList()); + matPriceHistoryService.deleteWithValidByIds(historyIdsToDelete, true); + } + } } diff --git a/gear-mat/src/main/resources/mapper/MatPriceHistoryMapper.xml b/gear-mat/src/main/resources/mapper/MatPriceHistoryMapper.xml index cbeaf03..10d2b5a 100644 --- a/gear-mat/src/main/resources/mapper/MatPriceHistoryMapper.xml +++ b/gear-mat/src/main/resources/mapper/MatPriceHistoryMapper.xml @@ -16,6 +16,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +