Commit 8bbd1d9ca73ba295ccf9ef1fcb3e6587486b37be

Authored by YunaiV
1 parent 5159b19e

fix(wms): 完善单据状态保护与金额精度处理

- 后端补充商品、往来企业唯一性校验
- 单据更新改为按草稿状态条件更新,避免覆盖已完成单据
- 补充 WMS 金额、规格精度迁移 SQL 与测试表结构
- 前端统一明细金额兜底计算,优化完成/作废取消处理
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemMapper.java
... ... @@ -43,6 +43,10 @@ public interface WmsItemMapper extends BaseMapperX<WmsItemDO> {
43 43 return selectOne(WmsItemDO::getName, name);
44 44 }
45 45  
  46 + default WmsItemDO selectByCode(String code) {
  47 + return selectOne(WmsItemDO::getCode, code);
  48 + }
  49 +
46 50 default Long selectCountByCategoryId(Long categoryId) {
47 51 return selectCount(WmsItemDO::getCategoryId, categoryId);
48 52 }
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/merchant/WmsMerchantMapper.java
... ... @@ -36,4 +36,12 @@ public interface WmsMerchantMapper extends BaseMapperX<WmsMerchantDO> {
36 36 .orderByDesc(WmsMerchantDO::getId));
37 37 }
38 38  
  39 + default WmsMerchantDO selectByCode(String code) {
  40 + return selectOne(WmsMerchantDO::getCode, code);
  41 + }
  42 +
  43 + default WmsMerchantDO selectByName(String name) {
  44 + return selectOne(WmsMerchantDO::getName, name);
  45 + }
  46 +
39 47 }
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java
... ... @@ -35,6 +35,7 @@ public interface ErrorCodeConstants {
35 35 // ========== WMS 基础数据-商品 1-060-104-000 ==========
36 36 ErrorCode ITEM_NOT_EXISTS = new ErrorCode(1_060_104_000, "商品不存在");
37 37 ErrorCode ITEM_NAME_DUPLICATE = new ErrorCode(1_060_104_001, "商品名称重复");
  38 + ErrorCode ITEM_CODE_DUPLICATE = new ErrorCode(1_060_104_007, "商品编号重复");
38 39 ErrorCode ITEM_SKU_REQUIRED = new ErrorCode(1_060_104_002, "至少包含一个商品规格");
39 40 ErrorCode ITEM_SKU_NAME_DUPLICATE = new ErrorCode(1_060_104_003, "商品规格名称【{}】重复");
40 41 ErrorCode ITEM_SKU_NOT_EXISTS = new ErrorCode(1_060_104_004, "商品规格不存在");
... ... @@ -46,6 +47,8 @@ public interface ErrorCodeConstants {
46 47 ErrorCode MERCHANT_NOT_SUPPLIER = new ErrorCode(1_060_105_001, "往来企业必须是供应商或客户/供应商类型");
47 48 ErrorCode MERCHANT_NOT_CUSTOMER = new ErrorCode(1_060_105_002, "往来企业必须是客户或客户/供应商类型");
48 49 ErrorCode MERCHANT_HAS_ORDER = new ErrorCode(1_060_105_003, "删除失败!往来企业已被{}使用!");
  50 + ErrorCode MERCHANT_CODE_DUPLICATE = new ErrorCode(1_060_105_004, "往来企业编号重复");
  51 + ErrorCode MERCHANT_NAME_DUPLICATE = new ErrorCode(1_060_105_005, "往来企业名称重复");
49 52  
50 53 // ========== WMS 入库单 1-060-200-000 ==========
51 54 ErrorCode RECEIPT_ORDER_NOT_EXISTS = new ErrorCode(1_060_200_000, "入库单不存在");
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java
... ... @@ -72,6 +72,8 @@ public class WmsItemServiceImpl implements WmsItemService {
72 72 }
73 73  
74 74 private void validateItemSaveData(WmsItemSaveReqVO reqVO) {
  75 + // 校验商品编号唯一
  76 + validateItemCodeUnique(reqVO.getId(), reqVO.getCode());
75 77 // 校验商品名称唯一
76 78 validateItemNameUnique(reqVO.getId(), reqVO.getName());
77 79 // 校验商品分类存在
... ... @@ -80,6 +82,16 @@ public class WmsItemServiceImpl implements WmsItemService {
80 82 validateBrandExists(reqVO.getBrandId());
81 83 }
82 84  
  85 + private void validateItemCodeUnique(Long id, String code) {
  86 + WmsItemDO item = itemMapper.selectByCode(code);
  87 + if (item == null) {
  88 + return;
  89 + }
  90 + if (id == null || ObjectUtil.notEqual(item.getId(), id)) {
  91 + throw exception(ITEM_CODE_DUPLICATE);
  92 + }
  93 + }
  94 +
83 95 private void validateItemNameUnique(Long id, String name) {
84 96 WmsItemDO item = itemMapper.selectByName(name);
85 97 if (item == null) {
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/merchant/WmsMerchantServiceImpl.java
... ... @@ -45,6 +45,9 @@ public class WmsMerchantServiceImpl implements WmsMerchantService {
45 45  
46 46 @Override
47 47 public Long createMerchant(WmsMerchantSaveReqVO createReqVO) {
  48 + validateMerchantSaveData(null, createReqVO);
  49 +
  50 + // 新增
48 51 WmsMerchantDO merchant = BeanUtils.toBean(createReqVO, WmsMerchantDO.class);
49 52 merchantMapper.insert(merchant);
50 53 return merchant.getId();
... ... @@ -54,12 +57,40 @@ public class WmsMerchantServiceImpl implements WmsMerchantService {
54 57 public void updateMerchant(WmsMerchantSaveReqVO updateReqVO) {
55 58 // 校验存在
56 59 validateMerchantExists(updateReqVO.getId());
  60 + validateMerchantSaveData(updateReqVO.getId(), updateReqVO);
57 61  
58 62 // 更新
59 63 WmsMerchantDO updateObj = BeanUtils.toBean(updateReqVO, WmsMerchantDO.class);
60 64 merchantMapper.updateById(updateObj);
61 65 }
62 66  
  67 + private void validateMerchantSaveData(Long id, WmsMerchantSaveReqVO reqVO) {
  68 + // 校验 code 唯一
  69 + validateMerchantCodeUnique(id, reqVO.getCode());
  70 + // 校验 name 唯一
  71 + validateMerchantNameUnique(id, reqVO.getName());
  72 + }
  73 +
  74 + private void validateMerchantCodeUnique(Long id, String code) {
  75 + WmsMerchantDO merchant = merchantMapper.selectByCode(code);
  76 + if (merchant == null) {
  77 + return;
  78 + }
  79 + if (id == null || ObjectUtil.notEqual(merchant.getId(), id)) {
  80 + throw exception(MERCHANT_CODE_DUPLICATE);
  81 + }
  82 + }
  83 +
  84 + private void validateMerchantNameUnique(Long id, String name) {
  85 + WmsMerchantDO merchant = merchantMapper.selectByName(name);
  86 + if (merchant == null) {
  87 + return;
  88 + }
  89 + if (id == null || ObjectUtil.notEqual(merchant.getId(), id)) {
  90 + throw exception(MERCHANT_NAME_DUPLICATE);
  91 + }
  92 + }
  93 +
63 94 @Override
64 95 public void deleteMerchant(Long id) {
65 96 // 校验存在
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/check/WmsCheckOrderServiceImpl.java
... ... @@ -72,7 +72,11 @@ public class WmsCheckOrderServiceImpl implements WmsCheckOrderService {
72 72 WmsCheckOrderDO updateObj = BeanUtils.toBean(updateReqVO, WmsCheckOrderDO.class)
73 73 .setStatus(WmsOrderStatusEnum.PREPARE.getStatus());
74 74 fillCheckOrderTotal(updateObj, updateReqVO);
75   - checkOrderMapper.updateById(updateObj);
  75 + int updateCount = checkOrderMapper.updateByIdAndStatus(updateReqVO.getId(),
  76 + WmsOrderStatusEnum.PREPARE.getStatus(), updateObj);
  77 + if (updateCount == 0) {
  78 + throw exception(CHECK_ORDER_STATUS_NOT_PREPARE);
  79 + }
76 80 // 2.2 更新盘库单明细
77 81 checkOrderDetailService.updateCheckOrderDetailList(updateReqVO.getId(), updateReqVO);
78 82 }
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/movement/WmsMovementOrderServiceImpl.java
... ... @@ -73,7 +73,11 @@ public class WmsMovementOrderServiceImpl implements WmsMovementOrderService {
73 73 WmsMovementOrderDO updateObj = BeanUtils.toBean(updateReqVO, WmsMovementOrderDO.class)
74 74 .setStatus(WmsOrderStatusEnum.PREPARE.getStatus());
75 75 fillMovementOrderTotal(updateObj, updateReqVO);
76   - movementOrderMapper.updateById(updateObj);
  76 + int updateCount = movementOrderMapper.updateByIdAndStatus(updateReqVO.getId(),
  77 + WmsOrderStatusEnum.PREPARE.getStatus(), updateObj);
  78 + if (updateCount == 0) {
  79 + throw exception(MOVEMENT_ORDER_STATUS_NOT_PREPARE);
  80 + }
77 81 // 2.2 更新移库单明细
78 82 movementOrderDetailService.updateMovementOrderDetailList(updateReqVO.getId(), updateReqVO);
79 83 }
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderServiceImpl.java
... ... @@ -76,7 +76,11 @@ public class WmsReceiptOrderServiceImpl implements WmsReceiptOrderService {
76 76 WmsReceiptOrderDO updateObj = BeanUtils.toBean(updateReqVO, WmsReceiptOrderDO.class)
77 77 .setStatus(WmsOrderStatusEnum.PREPARE.getStatus());
78 78 fillReceiptOrderTotal(updateObj, updateReqVO);
79   - receiptOrderMapper.updateById(updateObj);
  79 + int updateCount = receiptOrderMapper.updateByIdAndStatus(updateReqVO.getId(),
  80 + WmsOrderStatusEnum.PREPARE.getStatus(), updateObj);
  81 + if (updateCount == 0) {
  82 + throw exception(RECEIPT_ORDER_STATUS_NOT_PREPARE);
  83 + }
80 84 // 2.2 更新入库单明细
81 85 receiptOrderDetailService.updateReceiptOrderDetailList(updateReqVO.getId(), updateReqVO);
82 86 }
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/shipment/WmsShipmentOrderServiceImpl.java
... ... @@ -76,7 +76,11 @@ public class WmsShipmentOrderServiceImpl implements WmsShipmentOrderService {
76 76 WmsShipmentOrderDO updateObj = BeanUtils.toBean(updateReqVO, WmsShipmentOrderDO.class)
77 77 .setStatus(WmsOrderStatusEnum.PREPARE.getStatus());
78 78 fillShipmentOrderTotal(updateObj, updateReqVO);
79   - shipmentOrderMapper.updateById(updateObj);
  79 + int updateCount = shipmentOrderMapper.updateByIdAndStatus(updateReqVO.getId(),
  80 + WmsOrderStatusEnum.PREPARE.getStatus(), updateObj);
  81 + if (updateCount == 0) {
  82 + throw exception(SHIPMENT_ORDER_STATUS_NOT_PREPARE);
  83 + }
80 84 // 2.2 更新出库单明细
81 85 shipmentOrderDetailService.updateShipmentOrderDetailList(updateReqVO.getId(), updateReqVO);
82 86 }
... ...
yudao-module-wms/src/test/resources/sql/create_tables.sql
... ... @@ -15,17 +15,17 @@ CREATE TABLE IF NOT EXISTS "wms_warehouse" (
15 15  
16 16 CREATE TABLE IF NOT EXISTS "wms_merchant" (
17 17 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
18   - "code" varchar(20) DEFAULT NULL,
19   - "name" varchar(50) NOT NULL,
20   - "type" int NOT NULL,
21   - "level" varchar(20) DEFAULT NULL,
22   - "bank_name" varchar(50) DEFAULT NULL,
23   - "bank_account" varchar(50) DEFAULT NULL,
24   - "address" varchar(255) DEFAULT NULL,
25   - "mobile" varchar(20) DEFAULT NULL,
26   - "telephone" varchar(20) DEFAULT NULL,
27   - "contact" varchar(20) DEFAULT NULL,
28   - "email" varchar(64) DEFAULT NULL,
  18 + "code" varchar(20) NOT NULL,
  19 + "name" varchar(60) NOT NULL,
  20 + "type" tinyint NOT NULL,
  21 + "level" varchar(10) DEFAULT NULL,
  22 + "bank_name" varchar(255) DEFAULT NULL,
  23 + "bank_account" varchar(40) DEFAULT NULL,
  24 + "address" varchar(200) DEFAULT NULL,
  25 + "mobile" varchar(13) DEFAULT NULL,
  26 + "telephone" varchar(13) DEFAULT NULL,
  27 + "contact" varchar(30) DEFAULT NULL,
  28 + "email" varchar(50) DEFAULT NULL,
29 29 "remark" varchar(255) DEFAULT NULL,
30 30 "creator" varchar(64) DEFAULT '',
31 31 "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
... ... @@ -39,7 +39,7 @@ CREATE TABLE IF NOT EXISTS "wms_merchant" (
39 39 CREATE TABLE IF NOT EXISTS "wms_item_brand" (
40 40 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
41 41 "code" varchar(20) NOT NULL,
42   - "name" varchar(60) NOT NULL,
  42 + "name" varchar(30) NOT NULL,
43 43 "creator" varchar(64) DEFAULT '',
44 44 "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
45 45 "updater" varchar(64) DEFAULT '',
... ... @@ -53,9 +53,9 @@ CREATE TABLE IF NOT EXISTS "wms_item_category" (
53 53 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
54 54 "parent_id" bigint NOT NULL DEFAULT '0',
55 55 "code" varchar(20) NOT NULL,
56   - "name" varchar(60) NOT NULL,
  56 + "name" varchar(30) NOT NULL,
57 57 "sort" int DEFAULT '0',
58   - "status" tinyint NOT NULL DEFAULT '0',
  58 + "status" tinyint NOT NULL DEFAULT '1',
59 59 "creator" varchar(64) DEFAULT '',
60 60 "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
61 61 "updater" varchar(64) DEFAULT '',
... ... @@ -67,10 +67,10 @@ CREATE TABLE IF NOT EXISTS "wms_item_category" (
67 67  
68 68 CREATE TABLE IF NOT EXISTS "wms_item" (
69 69 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
70   - "code" varchar(20) NOT NULL,
  70 + "code" varchar(20) DEFAULT NULL,
71 71 "name" varchar(60) NOT NULL,
72   - "unit" varchar(20) DEFAULT NULL,
73 72 "category_id" bigint NOT NULL,
  73 + "unit" varchar(20) DEFAULT NULL,
74 74 "brand_id" bigint DEFAULT NULL,
75 75 "remark" varchar(255) DEFAULT NULL,
76 76 "creator" varchar(64) DEFAULT '',
... ... @@ -108,6 +108,7 @@ CREATE TABLE IF NOT EXISTS "wms_inventory" (
108 108 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
109 109 "sku_id" bigint NOT NULL,
110 110 "warehouse_id" bigint NOT NULL,
  111 + "area_id" bigint NOT NULL DEFAULT '0',
111 112 "quantity" decimal(20, 2) NOT NULL DEFAULT '0',
112 113 "remark" varchar(255) DEFAULT NULL,
113 114 "creator" varchar(64) DEFAULT '',
... ... @@ -117,22 +118,26 @@ CREATE TABLE IF NOT EXISTS "wms_inventory" (
117 118 "deleted" bit NOT NULL DEFAULT FALSE,
118 119 "tenant_id" bigint NOT NULL DEFAULT '0',
119 120 PRIMARY KEY ("id"),
120   - CONSTRAINT "uk_wms_inventory_sku_warehouse" UNIQUE ("sku_id", "warehouse_id", "tenant_id", "deleted")
  121 + CONSTRAINT "uk_sku_id_warehouse_id" UNIQUE ("sku_id", "warehouse_id")
121 122 ) COMMENT 'WMS 库存表';
122 123  
123 124 CREATE TABLE IF NOT EXISTS "wms_inventory_history" (
124 125 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
125 126 "warehouse_id" bigint NOT NULL,
  127 + "area_id" bigint NOT NULL DEFAULT '0',
126 128 "sku_id" bigint NOT NULL,
127 129 "quantity" decimal(20, 2) NOT NULL DEFAULT '0',
128 130 "before_quantity" decimal(20, 2) DEFAULT NULL,
129 131 "after_quantity" decimal(20, 2) DEFAULT NULL,
  132 + "batch_no" varchar(64) DEFAULT NULL,
  133 + "production_date" timestamp DEFAULT NULL,
  134 + "expiration_date" timestamp DEFAULT NULL,
130 135 "price" decimal(16, 2) DEFAULT NULL,
131 136 "total_price" decimal(16, 2) DEFAULT NULL,
132 137 "remark" varchar(255) DEFAULT NULL,
133 138 "order_id" bigint DEFAULT NULL,
134 139 "order_no" varchar(64) DEFAULT NULL,
135   - "order_type" tinyint DEFAULT NULL,
  140 + "order_type" int DEFAULT NULL,
136 141 "creator" varchar(64) DEFAULT '',
137 142 "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
138 143 "updater" varchar(64) DEFAULT '',
... ... @@ -152,6 +157,7 @@ CREATE TABLE IF NOT EXISTS "wms_receipt_order" (
152 157 "merchant_id" bigint DEFAULT NULL,
153 158 "remark" varchar(255) DEFAULT NULL,
154 159 "warehouse_id" bigint NOT NULL,
  160 + "area_id" bigint NOT NULL DEFAULT '0',
155 161 "total_quantity" decimal(20, 2) NOT NULL DEFAULT '0',
156 162 "total_price" decimal(16, 2) DEFAULT NULL,
157 163 "creator" varchar(64) DEFAULT '',
... ... @@ -168,6 +174,10 @@ CREATE TABLE IF NOT EXISTS "wms_receipt_order_detail" (
168 174 "order_id" bigint NOT NULL,
169 175 "sku_id" bigint NOT NULL,
170 176 "warehouse_id" bigint NOT NULL,
  177 + "area_id" bigint NOT NULL DEFAULT '0',
  178 + "batch_no" varchar(64) DEFAULT NULL,
  179 + "production_date" timestamp DEFAULT NULL,
  180 + "expiration_date" timestamp DEFAULT NULL,
171 181 "quantity" decimal(20, 2) NOT NULL DEFAULT '0',
172 182 "price" decimal(16, 2) DEFAULT NULL,
173 183 "total_price" decimal(16, 2) DEFAULT NULL,
... ... @@ -190,6 +200,7 @@ CREATE TABLE IF NOT EXISTS "wms_shipment_order" (
190 200 "merchant_id" bigint DEFAULT NULL,
191 201 "remark" varchar(255) DEFAULT NULL,
192 202 "warehouse_id" bigint NOT NULL,
  203 + "area_id" bigint NOT NULL DEFAULT '0',
193 204 "total_quantity" decimal(20, 2) NOT NULL DEFAULT '0',
194 205 "total_price" decimal(16, 2) DEFAULT NULL,
195 206 "creator" varchar(64) DEFAULT '',
... ... @@ -206,6 +217,11 @@ CREATE TABLE IF NOT EXISTS "wms_shipment_order_detail" (
206 217 "order_id" bigint NOT NULL,
207 218 "sku_id" bigint NOT NULL,
208 219 "warehouse_id" bigint NOT NULL,
  220 + "area_id" bigint NOT NULL DEFAULT '0',
  221 + "inventory_detail_id" bigint DEFAULT NULL,
  222 + "batch_no" varchar(64) DEFAULT NULL,
  223 + "production_date" timestamp DEFAULT NULL,
  224 + "expiration_date" timestamp DEFAULT NULL,
209 225 "quantity" decimal(20, 2) NOT NULL DEFAULT '0',
210 226 "price" decimal(16, 2) DEFAULT NULL,
211 227 "total_price" decimal(16, 2) DEFAULT NULL,
... ... @@ -243,6 +259,10 @@ CREATE TABLE IF NOT EXISTS "wms_movement_order_detail" (
243 259 "sku_id" bigint NOT NULL,
244 260 "source_warehouse_id" bigint NOT NULL,
245 261 "target_warehouse_id" bigint NOT NULL,
  262 + "inventory_detail_id" bigint DEFAULT NULL,
  263 + "batch_no" varchar(64) DEFAULT NULL,
  264 + "production_date" timestamp DEFAULT NULL,
  265 + "expiration_date" timestamp DEFAULT NULL,
246 266 "quantity" decimal(20, 2) NOT NULL DEFAULT '0',
247 267 "price" decimal(16, 2) DEFAULT NULL,
248 268 "total_price" decimal(16, 2) DEFAULT NULL,
... ... @@ -262,6 +282,7 @@ CREATE TABLE IF NOT EXISTS "wms_check_order" (
262 282 "status" int NOT NULL DEFAULT '0',
263 283 "remark" varchar(255) DEFAULT NULL,
264 284 "warehouse_id" bigint NOT NULL,
  285 + "area_id" bigint NOT NULL DEFAULT '0',
265 286 "total_quantity" decimal(20, 2) NOT NULL DEFAULT '0',
266 287 "total_price" decimal(16, 2) DEFAULT NULL,
267 288 "actual_price" decimal(16, 2) DEFAULT NULL,
... ... @@ -279,7 +300,12 @@ CREATE TABLE IF NOT EXISTS "wms_check_order_detail" (
279 300 "order_id" bigint NOT NULL,
280 301 "sku_id" bigint NOT NULL,
281 302 "warehouse_id" bigint NOT NULL,
  303 + "area_id" bigint NOT NULL DEFAULT '0',
282 304 "inventory_id" bigint DEFAULT NULL,
  305 + "inventory_detail_id" bigint DEFAULT NULL,
  306 + "batch_no" varchar(64) DEFAULT NULL,
  307 + "production_date" timestamp DEFAULT NULL,
  308 + "expiration_date" timestamp DEFAULT NULL,
283 309 "receipt_time" timestamp DEFAULT NULL,
284 310 "quantity" decimal(20, 2) NOT NULL DEFAULT '0',
285 311 "check_quantity" decimal(20, 2) NOT NULL DEFAULT '0',
... ...