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 | 14 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| 15 | 15 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| 16 | 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 | 17 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; |
| 19 | 18 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; |
| 20 | 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 | 21 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| 23 | 22 | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; |
| 24 | 23 | import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService; |
| 25 | -import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; | |
| 26 | 24 | import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; |
| 27 | 25 | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; |
| 28 | 26 | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService; |
| ... | ... | @@ -73,9 +71,6 @@ public class MesWmMaterialStockController { |
| 73 | 71 | @Resource |
| 74 | 72 | private MesMdVendorService vendorService; |
| 75 | 73 | |
| 76 | - @Resource | |
| 77 | - private MesProWorkOrderService workOrderService; | |
| 78 | - | |
| 79 | 74 | @GetMapping("/get") |
| 80 | 75 | @Operation(summary = "获得库存记录") |
| 81 | 76 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| ... | ... | @@ -128,7 +123,7 @@ public class MesWmMaterialStockController { |
| 128 | 123 | Map<Long, MesMdItemDO> itemMap = itemService.getItemMap( |
| 129 | 124 | convertSet(list, MesWmMaterialStockDO::getItemId)); |
| 130 | 125 | Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap( |
| 131 | - convertSet(list, MesWmMaterialStockDO::getUnitMeasureId)); | |
| 126 | + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); | |
| 132 | 127 | Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap( |
| 133 | 128 | convertSet(list, MesWmMaterialStockDO::getWarehouseId)); |
| 134 | 129 | Map<Long, MesWmWarehouseLocationDO> locationMap = locationService.getWarehouseLocationMap( |
| ... | ... | @@ -137,16 +132,13 @@ public class MesWmMaterialStockController { |
| 137 | 132 | convertSet(list, MesWmMaterialStockDO::getAreaId)); |
| 138 | 133 | Map<Long, MesMdVendorDO> vendorMap = vendorService.getVendorMap( |
| 139 | 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 | 135 | // 2. 构建结果 |
| 145 | 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 | 142 | MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), |
| 151 | 143 | warehouse -> vo.setWarehouseName(warehouse.getName())); |
| 152 | 144 | MapUtils.findAndThen(locationMap, vo.getLocationId(), |
| ... | ... | @@ -155,8 +147,6 @@ public class MesWmMaterialStockController { |
| 155 | 147 | area -> vo.setAreaName(area.getName())); |
| 156 | 148 | MapUtils.findAndThen(vendorMap, vo.getVendorId(), |
| 157 | 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 | 4 | import jakarta.validation.constraints.NotNull; |
| 5 | 5 | import lombok.Data; |
| 6 | 6 | |
| 7 | -// TODO DONE @AI:已重命名为 FreezeReqVO,语义与冻结/解冻操作一致 | |
| 8 | 7 | @Schema(description = "管理后台 - MES 库存台账冻结/解冻 Request VO") |
| 9 | 8 | @Data |
| 10 | 9 | public class MesWmMaterialStockFreezeReqVO { |
| ... | ... | @@ -15,6 +14,7 @@ public class MesWmMaterialStockFreezeReqVO { |
| 15 | 14 | |
| 16 | 15 | @Schema(description = "是否冻结", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") |
| 17 | 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 | 35 | @ExcelProperty("规格型号") |
| 36 | 36 | private String specification; |
| 37 | 37 | |
| 38 | - @Schema(description = "计量单位编号", example = "1") | |
| 39 | - private Long unitMeasureId; | |
| 40 | - | |
| 41 | 38 | @Schema(description = "计量单位名称", example = "千克") |
| 42 | 39 | @ExcelProperty("计量单位") |
| 43 | 40 | private String unitMeasureName; |
| ... | ... | @@ -77,32 +74,17 @@ public class MesWmMaterialStockRespVO { |
| 77 | 74 | @ExcelProperty("供应商") |
| 78 | 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 | 77 | @Schema(description = "在库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.0000") |
| 88 | 78 | @ExcelProperty("在库数量") |
| 89 | - private BigDecimal quantityOnhand; | |
| 79 | + private BigDecimal quantity; | |
| 90 | 80 | |
| 91 | 81 | @Schema(description = "入库时间") |
| 92 | 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 | 85 | @Schema(description = "是否冻结", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") |
| 104 | 86 | @ExcelProperty("是否冻结") |
| 105 | - private Boolean frozen; | |
| 87 | + private Boolean frozenFlag; | |
| 106 | 88 | |
| 107 | 89 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 108 | 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 | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | 4 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| 5 | 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 | 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 | 8 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; |
| 10 | 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; |
| 11 | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; |
| ... | ... | @@ -17,7 +16,6 @@ import lombok.*; |
| 17 | 16 | import java.math.BigDecimal; |
| 18 | 17 | import java.time.LocalDateTime; |
| 19 | 18 | |
| 20 | -// TODO DONE @芋艿:当前包名 materialstock 与表名 mes_wm_material_stock 保持一致,语义清晰,暂不调整 | |
| 21 | 19 | /** |
| 22 | 20 | * MES 库存台账(仓库现有量)DO |
| 23 | 21 | */ |
| ... | ... | @@ -36,6 +34,25 @@ public class MesWmMaterialStockDO extends BaseDO { |
| 36 | 34 | */ |
| 37 | 35 | @TableId |
| 38 | 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 | 66 | */ |
| 50 | 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 | 98 | * 关联 {@link MesWmWarehouseAreaDO#getId()} |
| 79 | 99 | */ |
| 80 | 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 | 7 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeLineDO; |
| 8 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 9 | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 10 | 12 | /** |
| 11 | 13 | * MES 物料消耗记录行 Mapper |
| 12 | 14 | * |
| ... | ... | @@ -22,4 +24,8 @@ public interface MesWmItemConsumeLineMapper extends BaseMapperX<MesWmItemConsume |
| 22 | 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 | 27 | .inIfPresent(MesWmMaterialStockDO::getItemId, itemIds) |
| 28 | 28 | .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId()) |
| 29 | 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 | 35 | default Long selectCountByWarehouseId(Long warehouseId) { |
| ... | ... | @@ -48,11 +48,21 @@ public interface MesWmMaterialStockMapper extends BaseMapperX<MesWmMaterialStock |
| 48 | 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 | 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 | 68 | default MesWmMaterialStockDO selectByCompositeKey(Long itemId, Long warehouseId, Long locationId, |
| ... | ... | @@ -74,8 +84,8 @@ public interface MesWmMaterialStockMapper extends BaseMapperX<MesWmMaterialStock |
| 74 | 84 | .eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId()) |
| 75 | 85 | .geIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getStartTime()) |
| 76 | 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 | 355 | // ========== MES 仓库管理-库存(1-040-703-000) ========== |
| 356 | 356 | ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在"); |
| 357 | 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 | 360 | // ========== MES 仓库管理-到货通知单(1-040-704-000) ========== |
| 360 | 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 | 8 | import jakarta.validation.Valid; |
| 9 | 9 | |
| 10 | 10 | import java.math.BigDecimal; |
| 11 | -import java.time.LocalDateTime; | |
| 12 | 11 | import java.util.Collection; |
| 13 | 12 | import java.util.List; |
| 14 | 13 | import java.util.Map; |
| ... | ... | @@ -99,7 +98,7 @@ public interface MesWmMaterialStockService { |
| 99 | 98 | * 增加库存 |
| 100 | 99 | * |
| 101 | 100 | * 按 itemId + warehouseId + locationId + areaId + batchId 查找已有库存, |
| 102 | - * 存在则增加 quantityOnhand;不存在则新建记录。 | |
| 101 | + * 存在则增加 quantity;不存在则新建记录。 | |
| 103 | 102 | * |
| 104 | 103 | * @param itemId 物料编号 |
| 105 | 104 | * @param warehouseId 仓库编号 |
| ... | ... | @@ -108,11 +107,19 @@ public interface MesWmMaterialStockService { |
| 108 | 107 | * @param batchId 批次编号 |
| 109 | 108 | * @param quantity 增加数量 |
| 110 | 109 | * @param vendorId 供应商编号 |
| 111 | - * @param productionDate 生产日期 | |
| 112 | - * @param expireDate 过期日期 | |
| 113 | 110 | */ |
| 114 | 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 | 22 | |
| 23 | 23 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 24 | 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 | 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 | 82 | // 更新冻结状态 |
| 82 | 83 | MesWmMaterialStockDO updateObj = new MesWmMaterialStockDO(); |
| 83 | 84 | updateObj.setId(updateReqVO.getId()); |
| 84 | - updateObj.setFrozen(updateReqVO.getFrozen()); | |
| 85 | + updateObj.setFrozenFlag(updateReqVO.getFrozenFlag()); | |
| 85 | 86 | materialStockMapper.updateById(updateObj); |
| 86 | 87 | } |
| 87 | 88 | |
| ... | ... | @@ -113,30 +114,40 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService |
| 113 | 114 | return materialStockMapper.selectListForStockTaking(reqVO); |
| 114 | 115 | } |
| 115 | 116 | |
| 116 | - // TODO DONE @AI:increaseStock 方法命名合理,语义清晰 | |
| 117 | 117 | @Override |
| 118 | 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 | 120 | // 1. 查找已有库存记录 |
| 122 | 121 | MesWmMaterialStockDO stock = materialStockMapper.selectByCompositeKey( |
| 123 | 122 | itemId, warehouseId, locationId, areaId, batchId); |
| 124 | 123 | |
| 125 | 124 | // 2a. 存在则增加数量 |
| 126 | 125 | if (stock != null) { |
| 127 | - materialStockMapper.incrQuantityOnhand(stock.getId(), quantity); | |
| 126 | + materialStockMapper.updateQuantity(stock.getId(), quantity); | |
| 128 | 127 | return; |
| 129 | 128 | } |
| 130 | 129 | |
| 131 | - // 2. 不存在则新建 | |
| 130 | + // 2b. 不存在则新建 | |
| 132 | 131 | MesMdItemDO item = itemService.validateItemExists(itemId); |
| 133 | 132 | MesWmMaterialStockDO newStock = MesWmMaterialStockDO.builder() |
| 134 | - .itemId(itemId).itemTypeId(item.getItemTypeId()).unitMeasureId(item.getUnitMeasureId()) | |
| 133 | + .itemId(itemId).itemTypeId(item.getItemTypeId()) | |
| 135 | 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 | 137 | .build(); |
| 139 | 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 | } | ... | ... |