diff --git a/deploy/sql/头程数据库统一增量-MySQL8.sql b/deploy/sql/头程数据库统一增量-MySQL8.sql index 7383de6ed..fa3648501 100644 --- a/deploy/sql/头程数据库统一增量-MySQL8.sql +++ b/deploy/sql/头程数据库统一增量-MySQL8.sql @@ -2528,14 +2528,38 @@ CREATE TABLE IF NOT EXISTS fl_inbound_order ( ) ENGINE=InnoDB COMMENT='二期头程入库单聚合根和列表查询快照'; UPDATE baiyue_order.ord_order o -LEFT JOIN baiyue_firstleg.fl_inbound_order i +JOIN baiyue_firstleg.fl_inbound_order i ON i.tenant_id = o.tenant_id AND i.order_id = o.id AND i.deleted = 0 - SET o.inbound_code = COALESCE(i.inbound_code, CONCAT('RK-', o.id)) + SET o.inbound_code = i.inbound_code WHERE o.deleted = 0 AND o.status <> 'DRAFT' AND (o.submitted_at IS NOT NULL OR o.status IN ('SUBMITTED', 'APPROVED', 'ACCEPTED', 'PROCESSING', 'COMPLETED')) - AND o.inbound_code IS NULL; + AND o.inbound_code IS NULL + AND i.inbound_code IS NOT NULL + AND TRIM(i.inbound_code) <> ''; + +-- 非草稿订单若既无订单入仓码也无 Firstleg 权威入仓码,禁止用内部 ID 伪造业务键。 +DROP PROCEDURE IF EXISTS assert_submitted_order_inbound_code; +DELIMITER $$ +CREATE PROCEDURE assert_submitted_order_inbound_code() +BEGIN + IF EXISTS ( + SELECT 1 + FROM baiyue_order.ord_order o + WHERE o.deleted = 0 + AND o.status <> 'DRAFT' + AND (o.submitted_at IS NOT NULL + OR o.status IN ('SUBMITTED', 'APPROVED', 'ACCEPTED', 'PROCESSING', 'COMPLETED')) + AND (o.inbound_code IS NULL OR TRIM(o.inbound_code) = '') + ) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '存在已提交订单缺少权威入仓码,请先修复订单/Firstleg业务事实后重跑'; + END IF; +END$$ +DELIMITER ; +CALL assert_submitted_order_inbound_code(); +DROP PROCEDURE IF EXISTS assert_submitted_order_inbound_code; -- 从未提交的草稿或由草稿直接取消的订单不应拥有入仓码。 UPDATE baiyue_order.ord_order diff --git a/firstleg/src/main/java/com/baiyue/firstleg/controller/InternalInboundOrderController.java b/firstleg/src/main/java/com/baiyue/firstleg/controller/InternalInboundOrderController.java index 3f8f4dbc8..651269bd1 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/controller/InternalInboundOrderController.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/controller/InternalInboundOrderController.java @@ -9,6 +9,7 @@ import com.baiyue.common.core.exception.BizException; import com.baiyue.firstleg.dto.OrderApprovedInboundCommand; import com.baiyue.firstleg.dto.InboundOrderReference; import com.baiyue.firstleg.service.InboundOrderCreationService; +import com.baiyue.firstleg.service.InboundCartonLabelService; import com.baiyue.firstleg.service.UnifiedInboundQueryService; import com.baiyue.firstleg.dto.UnifiedInboundDetail; import com.baiyue.firstleg.dto.UnifiedInboundQuery; @@ -35,6 +36,8 @@ public class InternalInboundOrderController { @Resource private InboundOrderCreationService service; @Resource + private InboundCartonLabelService cartonLabels; + @Resource private UnifiedInboundQueryService unifiedQueryService; @Value("${baiyue.security.internal-service-token}") private String internalToken; @@ -59,7 +62,9 @@ public class InternalInboundOrderController { || command.totalPackageCount() != null && command.totalPackageCount() < 1) { throw new BizException(ResultCode.BAD_REQUEST, "订单入库快照不完整"); } - return ApiResponse.success(service.createFromApprovedOrder(command)); + long inboundId = service.createFromApprovedOrder(command); + cartonLabels.getOrCreate(command.tenantId(), inboundId); + return ApiResponse.success(inboundId); } @PostMapping("/order-preparing") diff --git a/firstleg/src/test/java/com/baiyue/firstleg/controller/InternalInboundOrderReferenceControllerTest.java b/firstleg/src/test/java/com/baiyue/firstleg/controller/InternalInboundOrderReferenceControllerTest.java index 2522afe1a..f84cebd7c 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/controller/InternalInboundOrderReferenceControllerTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/controller/InternalInboundOrderReferenceControllerTest.java @@ -4,6 +4,7 @@ import com.baiyue.common.core.exception.BizException; import com.baiyue.firstleg.dto.InboundOrderReference; import com.baiyue.firstleg.dto.OrderApprovedInboundCommand; import com.baiyue.firstleg.service.InboundOrderCreationService; +import com.baiyue.firstleg.service.InboundCartonLabelService; import com.baiyue.firstleg.service.UnifiedInboundQueryService; import com.baiyue.firstleg.dto.UnifiedInboundQuery; import com.baiyue.common.core.api.PageResult; @@ -27,6 +28,8 @@ class InternalInboundOrderReferenceControllerTest { @MockBean private InboundOrderCreationService service; @MockBean + private InboundCartonLabelService cartonLabels; + @MockBean private UnifiedInboundQueryService unifiedQueryService; @Resource private InternalInboundOrderController controller; @@ -79,6 +82,7 @@ class InternalInboundOrderReferenceControllerTest { assertThat(controller.createFromApprovedOrder("internal-token", command).data()).isEqualTo(88L); verify(service).createFromApprovedOrder(command); + verify(cartonLabels).getOrCreate(10001L, 88L); } private static OrderApprovedInboundCommand approvedCommand(String inboundCode, Long carrierId) { diff --git a/order/src/main/java/com/baiyue/order/service/OrderApplicationService.java b/order/src/main/java/com/baiyue/order/service/OrderApplicationService.java index 849d73b00..a57065c0f 100644 --- a/order/src/main/java/com/baiyue/order/service/OrderApplicationService.java +++ b/order/src/main/java/com/baiyue/order/service/OrderApplicationService.java @@ -64,19 +64,17 @@ public class OrderApplicationService { private Long createDraftInternal(long tenantId, long userId, OrderRequests.SaveRequest request) { productImageGuard.requireOwned(tenantId, request.cargoes()); var snapshots = masterDataGuard.validate(tenantId, request); - String inboundCodePrefix = pricingChannelGuard.requireAvailable(tenantId, request.receivingWarehouseId(), + pricingChannelGuard.requireAvailable(tenantId, request.receivingWarehouseId(), request.channelCode(), request.destinationType()); OrderEntity order = new OrderEntity(); long orderId = IdWorker.getId(); order.setId(orderId); order.setTenantId(tenantId); order.setOrderNo(nextNo(orderId)); order.setStatus(OrderStatus.DRAFT); apply(order, tenantId, request, snapshots); - order.setInboundCode(nextInboundCode(inboundCodePrefix)); order.setCreatedBy(userId); order.setUpdatedBy(userId); repository.insertOrder(order); saveChildren(tenantId, userId, order.getId(), request); record(tenantId, order.getId(), null, OrderStatus.DRAFT, "CREATE", null, userId, null); - prepareDraftInbound(order, request); return order.getId(); } @@ -116,7 +114,7 @@ public class OrderApplicationService { repository.replaceDraftChildren(tenantId, id); saveChildren(tenantId, userId, id, request); record(tenantId, id, before, order.getStatus(), "UPDATE", null, userId, null); - prepareDraftInbound(order, request); + if (before == OrderStatus.SUBMITTED) prepareDraftInbound(order, request); } @Transactional diff --git a/order/src/test/java/com/baiyue/order/repository/OrderPickupSqlContractTest.java b/order/src/test/java/com/baiyue/order/repository/OrderPickupSqlContractTest.java index 3bd9b5e34..88ada5c72 100644 --- a/order/src/test/java/com/baiyue/order/repository/OrderPickupSqlContractTest.java +++ b/order/src/test/java/com/baiyue/order/repository/OrderPickupSqlContractTest.java @@ -29,6 +29,9 @@ class OrderPickupSqlContractTest { assertThat(relax).isGreaterThanOrEqualTo(0).isLessThan(clearDraft); assertThat(sql).contains( "column_name = 'requested_pickup_at'", - "ALTER TABLE baiyue_order.ord_order ADD COLUMN requested_pickup_at DATETIME(3) NULL"); + "ALTER TABLE baiyue_order.ord_order ADD COLUMN requested_pickup_at DATETIME(3) NULL", + "CREATE PROCEDURE assert_submitted_order_inbound_code()", + "SIGNAL SQLSTATE '45000'"); + assertThat(sql).doesNotContain("CONCAT('RK-', o.id)"); } } diff --git a/order/src/test/java/com/baiyue/order/service/OrderApplicationServiceStateTest.java b/order/src/test/java/com/baiyue/order/service/OrderApplicationServiceStateTest.java index 761f1168f..a161f7a92 100644 --- a/order/src/test/java/com/baiyue/order/service/OrderApplicationServiceStateTest.java +++ b/order/src/test/java/com/baiyue/order/service/OrderApplicationServiceStateTest.java @@ -58,7 +58,7 @@ class OrderApplicationServiceStateTest { assertThat(orderId).isNotNull(); verify(eligibility, never()).requireApproved(anyLong()); verify(repository).insertOrder(argThat(order -> order.getStatus() == OrderStatus.DRAFT - && order.getInboundCode().matches("PCHWK\\d{6}0001"))); + && order.getInboundCode() == null)); } @Test