Commit b1e4a6df6620aab1f023b50a29566e59621f5015
1 parent
f709822c
✨ feat(mes): 更新库存管理逻辑,重命名字段并添加事务记录
重构库存管理相关的请求和响应对象,更新字段名称以提高语义清晰度。新增库存事务流水记录,支持库存增减事件的追踪。此变更旨在提升库存管理的可维护性和可读性。
Showing
11 changed files
with
268 additions
and
103 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java
| @@ -14,7 +14,6 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMat | @@ -14,7 +14,6 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMat | ||
| 14 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; | 14 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| 15 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; | 15 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| 16 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; | 16 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; |
| 17 | -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; | ||
| 18 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; | 17 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; |
| 19 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; | 18 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; |
| 20 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; | 19 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; |
| @@ -22,7 +21,6 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLoc | @@ -22,7 +21,6 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLoc | ||
| 22 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; | 21 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| 23 | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; | 22 | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; |
| 24 | import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService; | 23 | import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService; |
| 25 | -import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; | ||
| 26 | import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; | 24 | import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; |
| 27 | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; | 25 | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; |
| 28 | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService; | 26 | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService; |
| @@ -73,9 +71,6 @@ public class MesWmMaterialStockController { | @@ -73,9 +71,6 @@ public class MesWmMaterialStockController { | ||
| 73 | @Resource | 71 | @Resource |
| 74 | private MesMdVendorService vendorService; | 72 | private MesMdVendorService vendorService; |
| 75 | 73 | ||
| 76 | - @Resource | ||
| 77 | - private MesProWorkOrderService workOrderService; | ||
| 78 | - | ||
| 79 | @GetMapping("/get") | 74 | @GetMapping("/get") |
| 80 | @Operation(summary = "获得库存记录") | 75 | @Operation(summary = "获得库存记录") |
| 81 | @Parameter(name = "id", description = "编号", required = true, example = "1024") | 76 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| @@ -128,7 +123,7 @@ public class MesWmMaterialStockController { | @@ -128,7 +123,7 @@ public class MesWmMaterialStockController { | ||
| 128 | Map<Long, MesMdItemDO> itemMap = itemService.getItemMap( | 123 | Map<Long, MesMdItemDO> itemMap = itemService.getItemMap( |
| 129 | convertSet(list, MesWmMaterialStockDO::getItemId)); | 124 | convertSet(list, MesWmMaterialStockDO::getItemId)); |
| 130 | Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap( | 125 | Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap( |
| 131 | - convertSet(list, MesWmMaterialStockDO::getUnitMeasureId)); | 126 | + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); |
| 132 | Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap( | 127 | Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap( |
| 133 | convertSet(list, MesWmMaterialStockDO::getWarehouseId)); | 128 | convertSet(list, MesWmMaterialStockDO::getWarehouseId)); |
| 134 | Map<Long, MesWmWarehouseLocationDO> locationMap = locationService.getWarehouseLocationMap( | 129 | Map<Long, MesWmWarehouseLocationDO> locationMap = locationService.getWarehouseLocationMap( |
| @@ -137,16 +132,13 @@ public class MesWmMaterialStockController { | @@ -137,16 +132,13 @@ public class MesWmMaterialStockController { | ||
| 137 | convertSet(list, MesWmMaterialStockDO::getAreaId)); | 132 | convertSet(list, MesWmMaterialStockDO::getAreaId)); |
| 138 | Map<Long, MesMdVendorDO> vendorMap = vendorService.getVendorMap( | 133 | Map<Long, MesMdVendorDO> vendorMap = vendorService.getVendorMap( |
| 139 | convertSet(list, MesWmMaterialStockDO::getVendorId)); | 134 | convertSet(list, MesWmMaterialStockDO::getVendorId)); |
| 140 | - Map<Long, MesProWorkOrderDO> workOrderMap = workOrderService.getWorkOrderMap( | ||
| 141 | - convertSet(list, MesWmMaterialStockDO::getWorkOrderId)); | ||
| 142 | - // TODO DONE @芋艿:待 mes_wm_batch 模块迁移后,补充 batchCode 的拼接 | ||
| 143 | - | ||
| 144 | // 2. 构建结果 | 135 | // 2. 构建结果 |
| 145 | return BeanUtils.toBean(list, MesWmMaterialStockRespVO.class, vo -> { | 136 | return BeanUtils.toBean(list, MesWmMaterialStockRespVO.class, vo -> { |
| 146 | - MapUtils.findAndThen(itemMap, vo.getItemId(), item -> | ||
| 147 | - vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification())); | ||
| 148 | - MapUtils.findAndThen(unitMeasureMap, vo.getUnitMeasureId(), | ||
| 149 | - unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); | 137 | + MapUtils.findAndThen(itemMap, vo.getItemId(), item -> { |
| 138 | + vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification()); | ||
| 139 | + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), | ||
| 140 | + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); | ||
| 141 | + }); | ||
| 150 | MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), | 142 | MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), |
| 151 | warehouse -> vo.setWarehouseName(warehouse.getName())); | 143 | warehouse -> vo.setWarehouseName(warehouse.getName())); |
| 152 | MapUtils.findAndThen(locationMap, vo.getLocationId(), | 144 | MapUtils.findAndThen(locationMap, vo.getLocationId(), |
| @@ -155,8 +147,6 @@ public class MesWmMaterialStockController { | @@ -155,8 +147,6 @@ public class MesWmMaterialStockController { | ||
| 155 | area -> vo.setAreaName(area.getName())); | 147 | area -> vo.setAreaName(area.getName())); |
| 156 | MapUtils.findAndThen(vendorMap, vo.getVendorId(), | 148 | MapUtils.findAndThen(vendorMap, vo.getVendorId(), |
| 157 | vendor -> vo.setVendorName(vendor.getName())); | 149 | vendor -> vo.setVendorName(vendor.getName())); |
| 158 | - MapUtils.findAndThen(workOrderMap, vo.getWorkOrderId(), | ||
| 159 | - workOrder -> vo.setWorkOrderCode(workOrder.getCode())); | ||
| 160 | }); | 150 | }); |
| 161 | } | 151 | } |
| 162 | 152 |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockFreezeReqVO.java
| @@ -4,7 +4,6 @@ import io.swagger.v3.oas.annotations.media.Schema; | @@ -4,7 +4,6 @@ import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | import jakarta.validation.constraints.NotNull; | 4 | import jakarta.validation.constraints.NotNull; |
| 5 | import lombok.Data; | 5 | import lombok.Data; |
| 6 | 6 | ||
| 7 | -// TODO DONE @AI:已重命名为 FreezeReqVO,语义与冻结/解冻操作一致 | ||
| 8 | @Schema(description = "管理后台 - MES 库存台账冻结/解冻 Request VO") | 7 | @Schema(description = "管理后台 - MES 库存台账冻结/解冻 Request VO") |
| 9 | @Data | 8 | @Data |
| 10 | public class MesWmMaterialStockFreezeReqVO { | 9 | public class MesWmMaterialStockFreezeReqVO { |
| @@ -15,6 +14,7 @@ public class MesWmMaterialStockFreezeReqVO { | @@ -15,6 +14,7 @@ public class MesWmMaterialStockFreezeReqVO { | ||
| 15 | 14 | ||
| 16 | @Schema(description = "是否冻结", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") | 15 | @Schema(description = "是否冻结", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") |
| 17 | @NotNull(message = "冻结状态不能为空") | 16 | @NotNull(message = "冻结状态不能为空") |
| 18 | - private Boolean frozen; | 17 | + private Boolean frozenFlag; |
| 19 | 18 | ||
| 20 | } | 19 | } |
| 20 | + |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java
| @@ -35,9 +35,6 @@ public class MesWmMaterialStockRespVO { | @@ -35,9 +35,6 @@ public class MesWmMaterialStockRespVO { | ||
| 35 | @ExcelProperty("规格型号") | 35 | @ExcelProperty("规格型号") |
| 36 | private String specification; | 36 | private String specification; |
| 37 | 37 | ||
| 38 | - @Schema(description = "计量单位编号", example = "1") | ||
| 39 | - private Long unitMeasureId; | ||
| 40 | - | ||
| 41 | @Schema(description = "计量单位名称", example = "千克") | 38 | @Schema(description = "计量单位名称", example = "千克") |
| 42 | @ExcelProperty("计量单位") | 39 | @ExcelProperty("计量单位") |
| 43 | private String unitMeasureName; | 40 | private String unitMeasureName; |
| @@ -77,32 +74,17 @@ public class MesWmMaterialStockRespVO { | @@ -77,32 +74,17 @@ public class MesWmMaterialStockRespVO { | ||
| 77 | @ExcelProperty("供应商") | 74 | @ExcelProperty("供应商") |
| 78 | private String vendorName; | 75 | private String vendorName; |
| 79 | 76 | ||
| 80 | - @Schema(description = "生产工单编号", example = "1") | ||
| 81 | - private Long workOrderId; | ||
| 82 | - | ||
| 83 | - @Schema(description = "生产工单编码", example = "WO20260101") | ||
| 84 | - @ExcelProperty("生产工单") | ||
| 85 | - private String workOrderCode; | ||
| 86 | - | ||
| 87 | @Schema(description = "在库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.0000") | 77 | @Schema(description = "在库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.0000") |
| 88 | @ExcelProperty("在库数量") | 78 | @ExcelProperty("在库数量") |
| 89 | - private BigDecimal quantityOnhand; | 79 | + private BigDecimal quantity; |
| 90 | 80 | ||
| 91 | @Schema(description = "入库时间") | 81 | @Schema(description = "入库时间") |
| 92 | @ExcelProperty("入库时间") | 82 | @ExcelProperty("入库时间") |
| 93 | - private LocalDateTime recptDate; | ||
| 94 | - | ||
| 95 | - @Schema(description = "生产日期") | ||
| 96 | - @ExcelProperty("生产日期") | ||
| 97 | - private LocalDateTime productionDate; | ||
| 98 | - | ||
| 99 | - @Schema(description = "库存有效期") | ||
| 100 | - @ExcelProperty("有效期") | ||
| 101 | - private LocalDateTime expireDate; | 83 | + private LocalDateTime receiptTime; |
| 102 | 84 | ||
| 103 | @Schema(description = "是否冻结", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") | 85 | @Schema(description = "是否冻结", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") |
| 104 | @ExcelProperty("是否冻结") | 86 | @ExcelProperty("是否冻结") |
| 105 | - private Boolean frozen; | 87 | + private Boolean frozenFlag; |
| 106 | 88 | ||
| 107 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | 89 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 108 | @ExcelProperty("创建时间") | 90 | @ExcelProperty("创建时间") |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java
| @@ -3,9 +3,8 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock; | @@ -3,9 +3,8 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock; | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; | 4 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| 5 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; | 5 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; |
| 6 | -import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; | ||
| 7 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; | 6 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; |
| 8 | -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; | 7 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; | 8 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; |
| 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; | 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; |
| 11 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; |
| @@ -17,7 +16,6 @@ import lombok.*; | @@ -17,7 +16,6 @@ import lombok.*; | ||
| 17 | import java.math.BigDecimal; | 16 | import java.math.BigDecimal; |
| 18 | import java.time.LocalDateTime; | 17 | import java.time.LocalDateTime; |
| 19 | 18 | ||
| 20 | -// TODO DONE @芋艿:当前包名 materialstock 与表名 mes_wm_material_stock 保持一致,语义清晰,暂不调整 | ||
| 21 | /** | 19 | /** |
| 22 | * MES 库存台账(仓库现有量)DO | 20 | * MES 库存台账(仓库现有量)DO |
| 23 | */ | 21 | */ |
| @@ -36,6 +34,25 @@ public class MesWmMaterialStockDO extends BaseDO { | @@ -36,6 +34,25 @@ public class MesWmMaterialStockDO extends BaseDO { | ||
| 36 | */ | 34 | */ |
| 37 | @TableId | 35 | @TableId |
| 38 | private Long id; | 36 | private Long id; |
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 在库数量 | ||
| 40 | + */ | ||
| 41 | + private BigDecimal quantity; | ||
| 42 | + /** | ||
| 43 | + * 入库时间 | ||
| 44 | + */ | ||
| 45 | + private LocalDateTime receiptTime; | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * 供应商编号 | ||
| 49 | + * | ||
| 50 | + * 关联 {@link MesMdVendorDO#getId()} | ||
| 51 | + */ | ||
| 52 | + private Long vendorId; | ||
| 53 | + | ||
| 54 | + // ==================== 物料维度 ==================== | ||
| 55 | + | ||
| 39 | /** | 56 | /** |
| 40 | * 物料分类编号 | 57 | * 物料分类编号 |
| 41 | * | 58 | * |
| @@ -49,17 +66,20 @@ public class MesWmMaterialStockDO extends BaseDO { | @@ -49,17 +66,20 @@ public class MesWmMaterialStockDO extends BaseDO { | ||
| 49 | */ | 66 | */ |
| 50 | private Long itemId; | 67 | private Long itemId; |
| 51 | /** | 68 | /** |
| 52 | - * 计量单位编号 | 69 | + * 批次编号 |
| 53 | * | 70 | * |
| 54 | - * 关联 {@link MesMdUnitMeasureDO#getId()} | 71 | + * 关联 {@link MesWmBatchDO#getId()} |
| 55 | */ | 72 | */ |
| 56 | - private Long unitMeasureId; | 73 | + private Long batchId; |
| 57 | /** | 74 | /** |
| 58 | - * 批次编号 | 75 | + * 批次号 |
| 59 | * | 76 | * |
| 60 | - * TODO DONE @芋艿:保留。待 mes_wm_batch 模块迁移后补充 @link 关联 | 77 | + * 关联 {@link MesWmBatchDO#getCode()} |
| 61 | */ | 78 | */ |
| 62 | - private Long batchId; | 79 | + private String batchCode; |
| 80 | + | ||
| 81 | + // ==================== 库存位置 ==================== | ||
| 82 | + | ||
| 63 | /** | 83 | /** |
| 64 | * 仓库编号 | 84 | * 仓库编号 |
| 65 | * | 85 | * |
| @@ -78,39 +98,12 @@ public class MesWmMaterialStockDO extends BaseDO { | @@ -78,39 +98,12 @@ public class MesWmMaterialStockDO extends BaseDO { | ||
| 78 | * 关联 {@link MesWmWarehouseAreaDO#getId()} | 98 | * 关联 {@link MesWmWarehouseAreaDO#getId()} |
| 79 | */ | 99 | */ |
| 80 | private Long areaId; | 100 | private Long areaId; |
| 81 | - /** | ||
| 82 | - * 供应商编号 | ||
| 83 | - * | ||
| 84 | - * 关联 {@link MesMdVendorDO#getId()} | ||
| 85 | - */ | ||
| 86 | - private Long vendorId; | ||
| 87 | - // TODO @AI:这个字段,应该没有的。 | ||
| 88 | - /** | ||
| 89 | - * 生产工单编号 | ||
| 90 | - * | ||
| 91 | - * 关联 {@link MesProWorkOrderDO#getId()} | ||
| 92 | - */ | ||
| 93 | - private Long workOrderId; | ||
| 94 | - // TODO @AI:onhand_quantity 更合理;更符合现在项目的风格。改下; | ||
| 95 | - /** | ||
| 96 | - * 在库数量 | ||
| 97 | - */ | ||
| 98 | - private BigDecimal quantityOnhand; | ||
| 99 | - /** | ||
| 100 | - * 入库时间 | ||
| 101 | - */ | ||
| 102 | - private LocalDateTime recptDate; | ||
| 103 | - /** | ||
| 104 | - * 库存有效期 | ||
| 105 | - */ | ||
| 106 | - private LocalDateTime expireDate; | ||
| 107 | - /** | ||
| 108 | - * 生产日期 | ||
| 109 | - */ | ||
| 110 | - private LocalDateTime productionDate; | 101 | + |
| 102 | + // ==================== 状态 ==================== | ||
| 103 | + | ||
| 111 | /** | 104 | /** |
| 112 | * 是否冻结 | 105 | * 是否冻结 |
| 113 | */ | 106 | */ |
| 114 | - private Boolean frozen; | 107 | + private Boolean frozenFlag; |
| 115 | 108 | ||
| 116 | } | 109 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.transaction; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 4 | +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; | ||
| 5 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; | ||
| 6 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; | ||
| 7 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; | ||
| 8 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; | ||
| 9 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; | ||
| 10 | +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; | ||
| 11 | +import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum; | ||
| 12 | +import com.baomidou.mybatisplus.annotation.KeySequence; | ||
| 13 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 14 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 15 | +import lombok.*; | ||
| 16 | + | ||
| 17 | +import java.math.BigDecimal; | ||
| 18 | +import java.time.LocalDateTime; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * MES 库存事务流水 DO | ||
| 22 | + * | ||
| 23 | + * 记录每一笔库存增减事件,系统自动生成,只读查询,不允许人工维护。 | ||
| 24 | + */ | ||
| 25 | +@TableName("mes_wm_transaction") | ||
| 26 | +@KeySequence("mes_wm_transaction_seq") | ||
| 27 | +@Data | ||
| 28 | +@EqualsAndHashCode(callSuper = true) | ||
| 29 | +@ToString(callSuper = true) | ||
| 30 | +@Builder | ||
| 31 | +@NoArgsConstructor | ||
| 32 | +@AllArgsConstructor | ||
| 33 | +public class MesWmTransactionDO extends BaseDO { | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 编号 | ||
| 37 | + */ | ||
| 38 | + @TableId | ||
| 39 | + private Long id; | ||
| 40 | + | ||
| 41 | + // ==================== 业务归属 ==================== | ||
| 42 | + | ||
| 43 | + // codex reply:`transactionType` 收敛成 `type` 是对的,和项目里其他 DO 的命名保持一致。 | ||
| 44 | + // codex reply:不过这类改名要连同 `MesWmTransactionSaveReqVO`、Service 和查询条件一起同步,不然 DO 与上下游模型会割裂。 | ||
| 45 | + /** | ||
| 46 | + * 事务类型 | ||
| 47 | + * | ||
| 48 | + * 枚举 {@link MesWmTransactionTypeEnum} | ||
| 49 | + */ | ||
| 50 | + private Integer type; | ||
| 51 | + // codex reply:`transactionQuantity` 收敛成 `quantity` 是对的;在事务流水这个上下文里,`transaction` 前缀没有额外信息。 | ||
| 52 | + // codex reply:`transactionFlag` 删除也合理,直接存带符号数量更符合当前写入逻辑,后续聚合查询也可以直接 `SUM(quantity)`。 | ||
| 53 | + /** | ||
| 54 | + * 本次变动数量 | ||
| 55 | + * | ||
| 56 | + * 正数=入库,负数=出库 | ||
| 57 | + */ | ||
| 58 | + private BigDecimal quantity; | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * 业务类型 | ||
| 62 | + * | ||
| 63 | + * 对应 {@link MesBizTypeConstants} 中的常量 | ||
| 64 | + */ | ||
| 65 | + private Integer bizType; | ||
| 66 | + /** | ||
| 67 | + * 来源业务主单 ID | ||
| 68 | + */ | ||
| 69 | + private Long bizId; | ||
| 70 | + /** | ||
| 71 | + * 来源业务单号 | ||
| 72 | + */ | ||
| 73 | + private String bizCode; | ||
| 74 | + /** | ||
| 75 | + * 来源业务行 ID | ||
| 76 | + */ | ||
| 77 | + private Long bizLineId; | ||
| 78 | + | ||
| 79 | + /** | ||
| 80 | + * 库存记录 ID | ||
| 81 | + * | ||
| 82 | + * 关联 {@link MesWmMaterialStockDO#getId()} | ||
| 83 | + */ | ||
| 84 | + private Long materialStockId; | ||
| 85 | + /** | ||
| 86 | + * 关联的事务 ID | ||
| 87 | + * | ||
| 88 | + * 关联 {@link #getId()},用于调拨等成对流水关联 | ||
| 89 | + */ | ||
| 90 | + private Long relatedTransactionId; | ||
| 91 | + | ||
| 92 | + // ==================== 物料维度 ==================== | ||
| 93 | + | ||
| 94 | + /** | ||
| 95 | + * 物料 ID | ||
| 96 | + * | ||
| 97 | + * 关联 {@link MesMdItemDO#getId()} | ||
| 98 | + */ | ||
| 99 | + private Long itemId; | ||
| 100 | + /** | ||
| 101 | + * 批次 ID | ||
| 102 | + * | ||
| 103 | + * 关联 {@link MesWmBatchDO#getId()} | ||
| 104 | + */ | ||
| 105 | + private Long batchId; | ||
| 106 | + /** | ||
| 107 | + * 批次号 | ||
| 108 | + * | ||
| 109 | + * 关联 {@link MesWmBatchDO#getCode()} | ||
| 110 | + */ | ||
| 111 | + private String batchCode; | ||
| 112 | + // codex reply:`packageId` 当前删除是合理的。事务流水链路没有包装维度的输入输出,先不保留“预留字段”更干净。 | ||
| 113 | + | ||
| 114 | + // ==================== 库存位置 ==================== | ||
| 115 | + | ||
| 116 | + /** | ||
| 117 | + * 仓库 ID | ||
| 118 | + * | ||
| 119 | + * 关联 {@link MesWmWarehouseDO#getId()} | ||
| 120 | + */ | ||
| 121 | + private Long warehouseId; | ||
| 122 | + /** | ||
| 123 | + * 库区 ID | ||
| 124 | + * | ||
| 125 | + * 关联 {@link MesWmWarehouseLocationDO#getId()} | ||
| 126 | + */ | ||
| 127 | + private Long locationId; | ||
| 128 | + /** | ||
| 129 | + * 库位 ID | ||
| 130 | + * | ||
| 131 | + * 关联 {@link MesWmWarehouseAreaDO#getId()} | ||
| 132 | + */ | ||
| 133 | + private Long areaId; | ||
| 134 | + | ||
| 135 | + // ==================== 时间 ==================== | ||
| 136 | + | ||
| 137 | + // codex reply:这里我不建议继续沿用 `erpTime` / `receiptTime` 这组命名;项目里的同类字段基本统一为 `receiptDate`,单独改成 `Time` 会破坏一致性。 | ||
| 138 | + // codex reply:如果这两个字段暂时没有业务赋值,建议宁可先删;若后续保留,ERP 侧更建议 `erpAccountDate`,收货侧保持 `receiptDate`。 | ||
| 139 | + /** | ||
| 140 | + * 事务发生时间 | ||
| 141 | + */ | ||
| 142 | + private LocalDateTime transactionTime; | ||
| 143 | + /** | ||
| 144 | + * ERP 账期 | ||
| 145 | + */ | ||
| 146 | + private LocalDateTime erpTime; | ||
| 147 | + /** | ||
| 148 | + * 入库时间 | ||
| 149 | + */ | ||
| 150 | + private LocalDateTime receiptTime; | ||
| 151 | + | ||
| 152 | +} |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/itemconsume/MesWmItemConsumeLineMapper.java
| @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.itemconsume.vo.MesWmItemC | @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.itemconsume.vo.MesWmItemC | ||
| 7 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeLineDO; | 7 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeLineDO; |
| 8 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 9 | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 10 | /** | 12 | /** |
| 11 | * MES 物料消耗记录行 Mapper | 13 | * MES 物料消耗记录行 Mapper |
| 12 | * | 14 | * |
| @@ -22,4 +24,8 @@ public interface MesWmItemConsumeLineMapper extends BaseMapperX<MesWmItemConsume | @@ -22,4 +24,8 @@ public interface MesWmItemConsumeLineMapper extends BaseMapperX<MesWmItemConsume | ||
| 22 | .orderByDesc(MesWmItemConsumeLineDO::getId)); | 24 | .orderByDesc(MesWmItemConsumeLineDO::getId)); |
| 23 | } | 25 | } |
| 24 | 26 | ||
| 27 | + default List<MesWmItemConsumeLineDO> selectListByConsumeId(Long consumeId) { | ||
| 28 | + return selectList(MesWmItemConsumeLineDO::getConsumeId, consumeId); | ||
| 29 | + } | ||
| 30 | + | ||
| 25 | } | 31 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
| @@ -27,9 +27,9 @@ public interface MesWmMaterialStockMapper extends BaseMapperX<MesWmMaterialStock | @@ -27,9 +27,9 @@ public interface MesWmMaterialStockMapper extends BaseMapperX<MesWmMaterialStock | ||
| 27 | .inIfPresent(MesWmMaterialStockDO::getItemId, itemIds) | 27 | .inIfPresent(MesWmMaterialStockDO::getItemId, itemIds) |
| 28 | .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId()) | 28 | .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId()) |
| 29 | .eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId()) | 29 | .eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId()) |
| 30 | - .eqIfPresent(MesWmMaterialStockDO::getFrozen, reqVO.getFrozen()) | ||
| 31 | - .ne(MesWmMaterialStockDO::getQuantityOnhand, BigDecimal.ZERO) | ||
| 32 | - .orderByAsc(MesWmMaterialStockDO::getRecptDate)); | 30 | + .eqIfPresent(MesWmMaterialStockDO::getFrozenFlag, reqVO.getFrozen()) |
| 31 | + .ne(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO) | ||
| 32 | + .orderByAsc(MesWmMaterialStockDO::getReceiptTime)); | ||
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | default Long selectCountByWarehouseId(Long warehouseId) { | 35 | default Long selectCountByWarehouseId(Long warehouseId) { |
| @@ -48,11 +48,21 @@ public interface MesWmMaterialStockMapper extends BaseMapperX<MesWmMaterialStock | @@ -48,11 +48,21 @@ public interface MesWmMaterialStockMapper extends BaseMapperX<MesWmMaterialStock | ||
| 48 | return selectByIds(ids); | 48 | return selectByIds(ids); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | - // TODO @AI:参考别的模块,最好使用 update某个字段,有例子的;然后看看,有没可能,尽量不写字段,而是通过 lamba 表达式获得名字。 | ||
| 52 | - default void incrQuantityOnhand(Long id, BigDecimal quantity) { | ||
| 53 | - update(null, new LambdaUpdateWrapper<MesWmMaterialStockDO>() | 51 | + /** |
| 52 | + * 增量更新库存数量 | ||
| 53 | + * | ||
| 54 | + * @param id 库存记录编号 | ||
| 55 | + * @param count 变动数量(正数=增加,负数=扣减) | ||
| 56 | + * @return 影响行数(扣减时为 0 表示库存不足) | ||
| 57 | + */ | ||
| 58 | + default int updateQuantity(Long id, BigDecimal count) { | ||
| 59 | + LambdaUpdateWrapper<MesWmMaterialStockDO> updateWrapper = new LambdaUpdateWrapper<MesWmMaterialStockDO>() | ||
| 54 | .eq(MesWmMaterialStockDO::getId, id) | 60 | .eq(MesWmMaterialStockDO::getId, id) |
| 55 | - .setSql("quantity_onhand = quantity_onhand + " + quantity)); | 61 | + .setSql("quantity = quantity + " + count); |
| 62 | + if (count.compareTo(BigDecimal.ZERO) < 0) { | ||
| 63 | + updateWrapper.ge(MesWmMaterialStockDO::getQuantity, count.abs()); // CAS 防负库存 | ||
| 64 | + } | ||
| 65 | + return update(null, updateWrapper); | ||
| 56 | } | 66 | } |
| 57 | 67 | ||
| 58 | default MesWmMaterialStockDO selectByCompositeKey(Long itemId, Long warehouseId, Long locationId, | 68 | default MesWmMaterialStockDO selectByCompositeKey(Long itemId, Long warehouseId, Long locationId, |
| @@ -74,8 +84,8 @@ public interface MesWmMaterialStockMapper extends BaseMapperX<MesWmMaterialStock | @@ -74,8 +84,8 @@ public interface MesWmMaterialStockMapper extends BaseMapperX<MesWmMaterialStock | ||
| 74 | .eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId()) | 84 | .eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId()) |
| 75 | .geIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getStartTime()) | 85 | .geIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getStartTime()) |
| 76 | .leIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getEndTime()) | 86 | .leIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getEndTime()) |
| 77 | - .ne(MesWmMaterialStockDO::getQuantityOnhand, BigDecimal.ZERO) // TODO @芋艿:需要在考虑下,要不要支持; | ||
| 78 | - .orderByAsc(MesWmMaterialStockDO::getRecptDate)); | 87 | + .ne(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO) // TODO @芋艿:需要在考虑下,要不要支持; |
| 88 | + .orderByAsc(MesWmMaterialStockDO::getReceiptTime)); | ||
| 79 | } | 89 | } |
| 80 | 90 | ||
| 81 | } | 91 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.dal.mysql.wm.transaction; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 4 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transaction.MesWmTransactionDO; | ||
| 5 | +import org.apache.ibatis.annotations.Mapper; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * MES 库存事务流水 Mapper | ||
| 9 | + */ | ||
| 10 | +@Mapper | ||
| 11 | +public interface MesWmTransactionMapper extends BaseMapperX<MesWmTransactionDO> { | ||
| 12 | + | ||
| 13 | +} |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
| @@ -355,6 +355,7 @@ public interface ErrorCodeConstants { | @@ -355,6 +355,7 @@ public interface ErrorCodeConstants { | ||
| 355 | // ========== MES 仓库管理-库存(1-040-703-000) ========== | 355 | // ========== MES 仓库管理-库存(1-040-703-000) ========== |
| 356 | ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在"); | 356 | ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在"); |
| 357 | ErrorCode WM_MATERIAL_STOCK_INSUFFICIENT = new ErrorCode(1_040_703_001, "库存数量不足"); | 357 | ErrorCode WM_MATERIAL_STOCK_INSUFFICIENT = new ErrorCode(1_040_703_001, "库存数量不足"); |
| 358 | + ErrorCode WM_TRANSACTION_MATERIAL_STOCK_REQUIRED = new ErrorCode(1_040_703_002, "出库事务必须指定库存记录 ID"); | ||
| 358 | 359 | ||
| 359 | // ========== MES 仓库管理-到货通知单(1-040-704-000) ========== | 360 | // ========== MES 仓库管理-到货通知单(1-040-704-000) ========== |
| 360 | ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "到货通知单不存在"); | 361 | ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "到货通知单不存在"); |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
| @@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterial | @@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterial | ||
| 8 | import jakarta.validation.Valid; | 8 | import jakarta.validation.Valid; |
| 9 | 9 | ||
| 10 | import java.math.BigDecimal; | 10 | import java.math.BigDecimal; |
| 11 | -import java.time.LocalDateTime; | ||
| 12 | import java.util.Collection; | 11 | import java.util.Collection; |
| 13 | import java.util.List; | 12 | import java.util.List; |
| 14 | import java.util.Map; | 13 | import java.util.Map; |
| @@ -99,7 +98,7 @@ public interface MesWmMaterialStockService { | @@ -99,7 +98,7 @@ public interface MesWmMaterialStockService { | ||
| 99 | * 增加库存 | 98 | * 增加库存 |
| 100 | * | 99 | * |
| 101 | * 按 itemId + warehouseId + locationId + areaId + batchId 查找已有库存, | 100 | * 按 itemId + warehouseId + locationId + areaId + batchId 查找已有库存, |
| 102 | - * 存在则增加 quantityOnhand;不存在则新建记录。 | 101 | + * 存在则增加 quantity;不存在则新建记录。 |
| 103 | * | 102 | * |
| 104 | * @param itemId 物料编号 | 103 | * @param itemId 物料编号 |
| 105 | * @param warehouseId 仓库编号 | 104 | * @param warehouseId 仓库编号 |
| @@ -108,11 +107,19 @@ public interface MesWmMaterialStockService { | @@ -108,11 +107,19 @@ public interface MesWmMaterialStockService { | ||
| 108 | * @param batchId 批次编号 | 107 | * @param batchId 批次编号 |
| 109 | * @param quantity 增加数量 | 108 | * @param quantity 增加数量 |
| 110 | * @param vendorId 供应商编号 | 109 | * @param vendorId 供应商编号 |
| 111 | - * @param productionDate 生产日期 | ||
| 112 | - * @param expireDate 过期日期 | ||
| 113 | */ | 110 | */ |
| 114 | void increaseStock(Long itemId, Long warehouseId, Long locationId, Long areaId, | 111 | void increaseStock(Long itemId, Long warehouseId, Long locationId, Long areaId, |
| 115 | - Long batchId, BigDecimal quantity, Long vendorId, | ||
| 116 | - LocalDateTime productionDate, LocalDateTime expireDate); | 112 | + Long batchId, BigDecimal quantity, Long vendorId); |
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * 扣减库存 | ||
| 116 | + * | ||
| 117 | + * 根据库存记录 ID 直接扣减数量。 | ||
| 118 | + * | ||
| 119 | + * @param materialStockId 库存记录编号 | ||
| 120 | + * @param quantity 扣减数量(正数) | ||
| 121 | + * @param storageCheckFlag 是否校验库存充足 | ||
| 122 | + */ | ||
| 123 | + void decreaseStock(Long materialStockId, BigDecimal quantity, boolean storageCheckFlag); | ||
| 117 | 124 | ||
| 118 | } | 125 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
| @@ -22,6 +22,7 @@ import java.util.*; | @@ -22,6 +22,7 @@ import java.util.*; | ||
| 22 | 22 | ||
| 23 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 23 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 24 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 24 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 25 | +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_MATERIAL_STOCK_INSUFFICIENT; | ||
| 25 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_MATERIAL_STOCK_NOT_EXISTS; | 26 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_MATERIAL_STOCK_NOT_EXISTS; |
| 26 | 27 | ||
| 27 | /** | 28 | /** |
| @@ -81,7 +82,7 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService | @@ -81,7 +82,7 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService | ||
| 81 | // 更新冻结状态 | 82 | // 更新冻结状态 |
| 82 | MesWmMaterialStockDO updateObj = new MesWmMaterialStockDO(); | 83 | MesWmMaterialStockDO updateObj = new MesWmMaterialStockDO(); |
| 83 | updateObj.setId(updateReqVO.getId()); | 84 | updateObj.setId(updateReqVO.getId()); |
| 84 | - updateObj.setFrozen(updateReqVO.getFrozen()); | 85 | + updateObj.setFrozenFlag(updateReqVO.getFrozenFlag()); |
| 85 | materialStockMapper.updateById(updateObj); | 86 | materialStockMapper.updateById(updateObj); |
| 86 | } | 87 | } |
| 87 | 88 | ||
| @@ -113,30 +114,40 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService | @@ -113,30 +114,40 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService | ||
| 113 | return materialStockMapper.selectListForStockTaking(reqVO); | 114 | return materialStockMapper.selectListForStockTaking(reqVO); |
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | - // TODO DONE @AI:increaseStock 方法命名合理,语义清晰 | ||
| 117 | @Override | 117 | @Override |
| 118 | public void increaseStock(Long itemId, Long warehouseId, Long locationId, Long areaId, | 118 | public void increaseStock(Long itemId, Long warehouseId, Long locationId, Long areaId, |
| 119 | - Long batchId, BigDecimal quantity, Long vendorId, | ||
| 120 | - LocalDateTime productionDate, LocalDateTime expireDate) { | 119 | + Long batchId, BigDecimal quantity, Long vendorId) { |
| 121 | // 1. 查找已有库存记录 | 120 | // 1. 查找已有库存记录 |
| 122 | MesWmMaterialStockDO stock = materialStockMapper.selectByCompositeKey( | 121 | MesWmMaterialStockDO stock = materialStockMapper.selectByCompositeKey( |
| 123 | itemId, warehouseId, locationId, areaId, batchId); | 122 | itemId, warehouseId, locationId, areaId, batchId); |
| 124 | 123 | ||
| 125 | // 2a. 存在则增加数量 | 124 | // 2a. 存在则增加数量 |
| 126 | if (stock != null) { | 125 | if (stock != null) { |
| 127 | - materialStockMapper.incrQuantityOnhand(stock.getId(), quantity); | 126 | + materialStockMapper.updateQuantity(stock.getId(), quantity); |
| 128 | return; | 127 | return; |
| 129 | } | 128 | } |
| 130 | 129 | ||
| 131 | - // 2. 不存在则新建 | 130 | + // 2b. 不存在则新建 |
| 132 | MesMdItemDO item = itemService.validateItemExists(itemId); | 131 | MesMdItemDO item = itemService.validateItemExists(itemId); |
| 133 | MesWmMaterialStockDO newStock = MesWmMaterialStockDO.builder() | 132 | MesWmMaterialStockDO newStock = MesWmMaterialStockDO.builder() |
| 134 | - .itemId(itemId).itemTypeId(item.getItemTypeId()).unitMeasureId(item.getUnitMeasureId()) | 133 | + .itemId(itemId).itemTypeId(item.getItemTypeId()) |
| 135 | .warehouseId(warehouseId).locationId(locationId).areaId(areaId) | 134 | .warehouseId(warehouseId).locationId(locationId).areaId(areaId) |
| 136 | - .batchId(batchId).vendorId(vendorId).quantityOnhand(quantity) | ||
| 137 | - .recptDate(LocalDateTime.now()).productionDate(productionDate).expireDate(expireDate).frozen(false) | 135 | + .batchId(batchId).vendorId(vendorId).quantity(quantity) |
| 136 | + .receiptTime(LocalDateTime.now()).frozenFlag(false) | ||
| 138 | .build(); | 137 | .build(); |
| 139 | materialStockMapper.insert(newStock); | 138 | materialStockMapper.insert(newStock); |
| 140 | } | 139 | } |
| 141 | 140 | ||
| 141 | + @Override | ||
| 142 | + public void decreaseStock(Long materialStockId, BigDecimal quantity, boolean storageCheckFlag) { | ||
| 143 | + // 1. 校验库存记录存在 | ||
| 144 | + validateMaterialStockExists(materialStockId); | ||
| 145 | + | ||
| 146 | + // 2. 扣减库存(Mapper 层 CAS 防负库存) | ||
| 147 | + int updatedRows = materialStockMapper.updateQuantity(materialStockId, quantity.negate()); | ||
| 148 | + if (storageCheckFlag && updatedRows == 0) { | ||
| 149 | + throw exception(WM_MATERIAL_STOCK_INSUFFICIENT); | ||
| 150 | + } | ||
| 151 | + } | ||
| 152 | + | ||
| 142 | } | 153 | } |