| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockMoveReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmStockSummaryRespVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.*; |
| | | import java.util.function.BiConsumer; |
| | | import java.util.function.Function; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<MesWmStockSummaryRespVO> getStockSummaryByItem(MesWmMaterialStockListReqVO reqVO) { |
| | | List<MesWmMaterialStockDO> stocks = getMaterialStockList(reqVO); |
| | | List<MesWmStockSummaryRespVO> list = buildStockSummary(stocks, |
| | | stock -> String.valueOf(stock.getItemId()), |
| | | (vo, stock) -> vo.setItemId(stock.getItemId())); |
| | | Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap( |
| | | convertSet(stocks, MesWmMaterialStockDO::getItemId)); |
| | | list.forEach(vo -> { |
| | | MesMdmItemDO item = itemMap.get(vo.getItemId()); |
| | | if (item != null) { |
| | | vo.setItemCode(item.getCode()).setItemName(item.getName()); |
| | | } |
| | | }); |
| | | return list; |
| | | } |
| | | |
| | | @Override |
| | | public List<MesWmStockSummaryRespVO> getStockSummaryByBatch(MesWmMaterialStockListReqVO reqVO) { |
| | | List<MesWmMaterialStockDO> stocks = getMaterialStockList(reqVO); |
| | | return buildStockSummary(stocks, |
| | | stock -> stock.getBatchId() + "|" + (stock.getBatchCode() != null ? stock.getBatchCode() : ""), |
| | | (vo, stock) -> vo.setBatchId(stock.getBatchId()).setBatchCode(stock.getBatchCode())); |
| | | } |
| | | |
| | | @Override |
| | | public List<MesWmStockSummaryRespVO> getStockSummaryByWarehouse(MesWmMaterialStockListReqVO reqVO) { |
| | | List<MesWmMaterialStockDO> stocks = getMaterialStockList(reqVO); |
| | | List<MesWmStockSummaryRespVO> list = buildStockSummary(stocks, |
| | | stock -> String.valueOf(stock.getWarehouseId()), |
| | | (vo, stock) -> vo.setWarehouseId(stock.getWarehouseId())); |
| | | Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap( |
| | | convertSet(stocks, MesWmMaterialStockDO::getWarehouseId)); |
| | | list.forEach(vo -> { |
| | | MesWmWarehouseDO warehouse = warehouseMap.get(vo.getWarehouseId()); |
| | | if (warehouse != null) { |
| | | vo.setWarehouseName(warehouse.getName()); |
| | | } |
| | | }); |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * 内存聚合库存数量:按维度键 + 库存状态分组,累加在库数量 |
| | | */ |
| | | private List<MesWmStockSummaryRespVO> buildStockSummary(List<MesWmMaterialStockDO> stocks, |
| | | Function<MesWmMaterialStockDO, String> dimKeyFn, |
| | | BiConsumer<MesWmStockSummaryRespVO, MesWmMaterialStockDO> dimSetter) { |
| | | if (CollUtil.isEmpty(stocks)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | Map<String, MesWmStockSummaryRespVO> map = new LinkedHashMap<>(); |
| | | for (MesWmMaterialStockDO stock : stocks) { |
| | | String key = dimKeyFn.apply(stock) + "|" + stock.getStockState(); |
| | | MesWmStockSummaryRespVO vo = map.computeIfAbsent(key, k -> { |
| | | MesWmStockSummaryRespVO newVo = new MesWmStockSummaryRespVO(); |
| | | dimSetter.accept(newVo, stock); |
| | | newVo.setStockState(stock.getStockState()); |
| | | newVo.setStockStateName(stockStateName(stock.getStockState())); |
| | | newVo.setTotalQuantity(BigDecimal.ZERO); |
| | | return newVo; |
| | | }); |
| | | BigDecimal qty = stock.getQuantity() != null ? stock.getQuantity() : BigDecimal.ZERO; |
| | | vo.setTotalQuantity(vo.getTotalQuantity().add(qty)); |
| | | } |
| | | return new ArrayList<>(map.values()); |
| | | } |
| | | |
| | | private String stockStateName(Integer state) { |
| | | if (state == null) { |
| | | return ""; |
| | | } |
| | | for (MesWmStockStateEnum e : MesWmStockStateEnum.values()) { |
| | | if (e.getState().equals(state)) { |
| | | return e.getName(); |
| | | } |
| | | } |
| | | return String.valueOf(state); |
| | | } |
| | | |
| | | @Override |
| | | public MesWmMaterialStockDO getOrCreateMaterialStock(Long itemId, Long warehouseId, Long locationId, Long areaId, |
| | | Long batchId, String batchCode, Long vendorId, LocalDateTime receiptTime) { |
| | | // 1. 查找已有库存记录(vendorId 参与唯一键) |
| | |
| | | .batchId(batchId).batchCode(batchCode).vendorId(vendorId) |
| | | .quantity(BigDecimal.ZERO) // 初始数量为 0,由 updateMaterialStockQuantity 更新 |
| | | .receiptTime(receiptTime != null ? receiptTime : LocalDateTime.now()) |
| | | .stockState(MesWmStockStateEnum.TEMP.getState()) |
| | | .frozen(false) |
| | | .build(); |
| | | materialStockMapper.insert(newStock); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<MesWmMaterialStockDO> getMaterialStockListByItemAndBatch(Long itemId, Long batchId) { |
| | | return materialStockMapper.selectListByItemAndBatch(itemId, batchId); |
| | | } |
| | | |
| | | @Override |
| | | public void updateMaterialStockQuantity(Long id, BigDecimal quantity, boolean checkFlag) { |
| | | // 更新库存数量(Mapper 层 CAS 防负库存;checkFlag=false 时允许负数) |
| | | int updatedRows = materialStockMapper.updateQuantity(id, quantity, checkFlag); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void updateMaterialStockState(Long id, Integer stockState) { |
| | | materialStockMapper.updateById(new MesWmMaterialStockDO().setId(id).setStockState(stockState)); |
| | | } |
| | | |
| | | @Override |
| | | public int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState) { |
| | | return materialStockMapper.updateStockStateByBatchId(batchId, toState, fromState); |
| | | } |
| | | |
| | | @Override |
| | | public void checkAreaMixingRule(Long areaId, Long itemId, Long batchId) { |
| | | // 1.1 校验库位必须存在 |
| | | MesWmWarehouseAreaDO area = areaService.validateWarehouseAreaExists(areaId); |