| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockAdjustReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO; |
| | | 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.dal.dataobject.md.item.MesMdItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | |
| | | 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; |
| | |
| | | .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); |
| | | if (updatedRows == 0) { |
| | | throw exception(WM_MATERIAL_STOCK_INSUFFICIENT); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void updateMaterialStockState(Long id, Integer stockState) { |
| | | materialStockMapper.updateById(new MesWmMaterialStockDO().setId(id).setStockState(stockState)); |
| | | } |
| | | |
| | | @Override |
| | |
| | | throw new IllegalArgumentException("无效的质量状态类型: " + qualityStatus.getClass().getName()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void moveMaterialStock(MesWmMaterialStockMoveReqVO reqVO) { |
| | | // 1. 查询原库存记录 |
| | | MesWmMaterialStockDO sourceStock = validateMaterialStockExists(reqVO.getMaterialStockId()); |
| | | |
| | | // 2. 校验库存数量充足(可用量 = 在库数量 - 冻结数量 - 占用量) |
| | | BigDecimal availableQty = sourceStock.getQuantity() != null ? sourceStock.getQuantity() : BigDecimal.ZERO; |
| | | if (sourceStock.getFrozenQuantity() != null) { |
| | | availableQty = availableQty.subtract(sourceStock.getFrozenQuantity()); |
| | | } |
| | | if (sourceStock.getReservedQuantity() != null) { |
| | | availableQty = availableQty.subtract(sourceStock.getReservedQuantity()); |
| | | } |
| | | if (availableQty.compareTo(reqVO.getQuantity()) < 0) { |
| | | throw exception(WM_MATERIAL_STOCK_INSUFFICIENT); |
| | | } |
| | | |
| | | // 3. 校验库存未冻结 |
| | | if (Boolean.TRUE.equals(sourceStock.getFrozen())) { |
| | | throw exception(WM_MATERIAL_STOCK_FROZEN); |
| | | } |
| | | |
| | | // 4. 校验目标库位混放规则 |
| | | checkAreaMixingRule(reqVO.getToAreaId(), sourceStock.getItemId(), sourceStock.getBatchId()); |
| | | |
| | | // 5. 生成移库单号 |
| | | String moveCode = "MOVE_" + System.currentTimeMillis(); |
| | | |
| | | // 6. 创建调拨移出事务(负数) |
| | | MesWmTransactionSaveReqDTO outTransaction = new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.MOVE_OUT.getType()) |
| | | .setBizType(MesBizTypeConstants.WM_TRANSFER_OUT) |
| | | .setBizId(sourceStock.getId()) |
| | | .setBizCode(moveCode) |
| | | .setBizLineId(sourceStock.getId()) |
| | | .setItemId(sourceStock.getItemId()) |
| | | .setQuantity(reqVO.getQuantity().negate()) |
| | | .setBatchId(sourceStock.getBatchId()) |
| | | .setBatchCode(sourceStock.getBatchCode()) |
| | | .setWarehouseId(sourceStock.getWarehouseId()) |
| | | .setLocationId(sourceStock.getLocationId()) |
| | | .setAreaId(sourceStock.getAreaId()) |
| | | .setVendorId(sourceStock.getVendorId()) |
| | | .setMaterialStockId(sourceStock.getId()) |
| | | .setCheckFlag(true); |
| | | Long outTransactionId = wmTransactionService.createTransaction(outTransaction); |
| | | |
| | | // 7. 查找目标库位的库存记录(忽略供应商),用于合并库存 |
| | | MesWmMaterialStockDO targetStock = materialStockMapper.selectByCompositeKeyIgnoreVendor( |
| | | sourceStock.getItemId(), |
| | | reqVO.getToWarehouseId(), |
| | | reqVO.getToLocationId(), |
| | | reqVO.getToAreaId(), |
| | | sourceStock.getBatchId() |
| | | ); |
| | | |
| | | // 8. 创建调拨移入事务(正数),关联出库事务 |
| | | // 使用目标库位已有库存记录的 vendorId(如果有),否则不传 |
| | | MesWmTransactionSaveReqDTO inTransaction = new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.MOVE_IN.getType()) |
| | | .setBizType(MesBizTypeConstants.WM_TRANSFER_IN) |
| | | .setBizId(sourceStock.getId()) |
| | | .setBizCode(moveCode) |
| | | .setBizLineId(sourceStock.getId()) |
| | | .setItemId(sourceStock.getItemId()) |
| | | .setQuantity(reqVO.getQuantity()) |
| | | .setBatchId(sourceStock.getBatchId()) |
| | | .setBatchCode(sourceStock.getBatchCode()) |
| | | .setWarehouseId(reqVO.getToWarehouseId()) |
| | | .setLocationId(reqVO.getToLocationId()) |
| | | .setAreaId(reqVO.getToAreaId()) |
| | | .setVendorId(targetStock != null ? targetStock.getVendorId() : null) |
| | | .setRelatedTransactionId(outTransactionId) |
| | | .setCheckFlag(false); |
| | | wmTransactionService.createTransaction(inTransaction); |
| | | } |
| | | |
| | | } |