From 60a41ec3ea5ddc2af78e495e1fa4fc758f3c5df8 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Tue, 8 Sep 2026 17:33:23 +0800 Subject: [PATCH] fix: reserve stable inbound code for draft label printing --- .../client/PrintableOrderInboundClient.java | 18 +++ .../service/InboundCartonLabelService.java | 4 +- .../InboundCartonLabelServiceTest.java | 7 +- .../InternalOrderCargoController.java | 15 +++ .../order/repository/OrderRepository.java | 11 ++ .../PrintableInboundSnapshotService.java | 64 ++++++++++ .../src/main/resources/openapi/order-v1.yaml | 17 +++ .../InternalOrderCargoControllerTest.java | 22 ++++ ...bleInboundSnapshotOpenApiContractTest.java | 21 ++++ .../PrintableInboundSnapshotServiceTest.java | 113 ++++++++++++++++++ 10 files changed, 289 insertions(+), 3 deletions(-) create mode 100644 firstleg/src/main/java/com/baiyue/firstleg/client/PrintableOrderInboundClient.java create mode 100644 order/src/main/java/com/baiyue/order/service/PrintableInboundSnapshotService.java create mode 100644 order/src/test/java/com/baiyue/order/controller/PrintableInboundSnapshotOpenApiContractTest.java create mode 100644 order/src/test/java/com/baiyue/order/service/PrintableInboundSnapshotServiceTest.java diff --git a/firstleg/src/main/java/com/baiyue/firstleg/client/PrintableOrderInboundClient.java b/firstleg/src/main/java/com/baiyue/firstleg/client/PrintableOrderInboundClient.java new file mode 100644 index 000000000..b28eedff7 --- /dev/null +++ b/firstleg/src/main/java/com/baiyue/firstleg/client/PrintableOrderInboundClient.java @@ -0,0 +1,18 @@ +package com.baiyue.firstleg.client; + +import com.baiyue.common.core.api.ApiResponse; +import com.baiyue.firstleg.dto.OrderApprovedInboundCommand; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; + +@FeignClient(name = "order-service", contextId = "printableOrderInboundClient", + url = "${baiyue.clients.order.url:}", path = "/internal/order/v1/cargoes") +public interface PrintableOrderInboundClient { + @PostMapping("/{tenantId}/{orderId}/printable-inbound-snapshot") + ApiResponse reserve( + @RequestHeader("X-Internal-Service-Token") String token, + @PathVariable long tenantId, + @PathVariable long orderId); +} diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelService.java index b73623379..26f74f316 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelService.java @@ -5,6 +5,7 @@ import com.baiyue.common.core.api.ApiResponse; import com.baiyue.common.core.api.ResultCode; import com.baiyue.common.core.exception.BizException; import com.baiyue.firstleg.client.OrderCargoClient; +import com.baiyue.firstleg.client.PrintableOrderInboundClient; import com.baiyue.firstleg.dto.InboundCartonLabels; import com.baiyue.firstleg.entity.InboundCartonLabelEntity; import com.baiyue.firstleg.entity.InboundOrderEntity; @@ -35,6 +36,7 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver { @Resource private InboundCartonLabelRepository repository; @Resource private OrderCargoClient orderCargoClient; + @Resource private PrintableOrderInboundClient printableOrderInboundClient; @Resource private InboundOrderCreationService inboundOrderCreationService; @Value("${baiyue.security.internal-service-token}") private String internalToken; @@ -101,7 +103,7 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver { private InboundOrderEntity prepareMissingInbound(long tenantId, long orderId) { try { ApiResponse response = - orderCargoClient.inboundSnapshot(internalToken, tenantId, orderId); + printableOrderInboundClient.reserve(internalToken, tenantId, orderId); if (response == null || !response.successful() || response.data() == null) { throw new BizException(ResultCode.NOT_FOUND, "订单不存在或无法生成预入库单"); } diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelServiceTest.java index 868af9ece..a2a0b002a 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelServiceTest.java @@ -3,6 +3,7 @@ package com.baiyue.firstleg.service; import com.baiyue.common.core.api.ApiResponse; import com.baiyue.common.core.exception.BizException; import com.baiyue.firstleg.client.OrderCargoClient; +import com.baiyue.firstleg.client.PrintableOrderInboundClient; import com.baiyue.firstleg.entity.InboundCartonLabelEntity; import com.baiyue.firstleg.entity.InboundOrderEntity; import com.baiyue.firstleg.repository.InboundCartonLabelRepository; @@ -28,6 +29,7 @@ import static org.mockito.Mockito.when; class InboundCartonLabelServiceTest { @Mock private InboundCartonLabelRepository repository; @Mock private OrderCargoClient orderCargoClient; + @Mock private PrintableOrderInboundClient printableOrderInboundClient; @Mock private InboundOrderCreationService inboundOrderCreationService; private InboundCartonLabelService service; @@ -36,6 +38,7 @@ class InboundCartonLabelServiceTest { service = new InboundCartonLabelService(); ReflectionTestUtils.setField(service, "repository", repository); ReflectionTestUtils.setField(service, "orderCargoClient", orderCargoClient); + ReflectionTestUtils.setField(service, "printableOrderInboundClient", printableOrderInboundClient); ReflectionTestUtils.setField(service, "inboundOrderCreationService", inboundOrderCreationService); ReflectionTestUtils.setField(service, "internalToken", "internal-token"); } @@ -222,7 +225,7 @@ class InboundCartonLabelServiceTest { @Test void rejectsAnOrderWithoutAnOwnedPreparingInbound() { when(repository.findByOrder(10001L, 60001L)).thenReturn(null); - when(orderCargoClient.inboundSnapshot("internal-token", 10001L, 60001L)) + when(printableOrderInboundClient.reserve("internal-token", 10001L, 60001L)) .thenThrow(org.mockito.Mockito.mock(feign.FeignException.class)); assertThatThrownBy(() -> service.requireInboundIdByOrder(10001L, 60001L)) @@ -239,7 +242,7 @@ class InboundCartonLabelServiceTest { null, null, null, 2); InboundOrderEntity repaired = inbound(); when(repository.findByOrder(10001L, 60001L)).thenReturn(null, repaired); - when(orderCargoClient.inboundSnapshot("internal-token", 10001L, 60001L)) + when(printableOrderInboundClient.reserve("internal-token", 10001L, 60001L)) .thenReturn(ApiResponse.success(snapshot)); assertThat(service.requireInboundIdByOrder(10001L, 60001L)).isEqualTo(70001L); diff --git a/order/src/main/java/com/baiyue/order/controller/InternalOrderCargoController.java b/order/src/main/java/com/baiyue/order/controller/InternalOrderCargoController.java index 0f3d06b38..55e269500 100644 --- a/order/src/main/java/com/baiyue/order/controller/InternalOrderCargoController.java +++ b/order/src/main/java/com/baiyue/order/controller/InternalOrderCargoController.java @@ -9,10 +9,12 @@ import com.baiyue.common.core.exception.BizException; import com.baiyue.order.entity.OrderCargoEntity; import com.baiyue.order.repository.OrderRepository; import com.baiyue.order.service.OrderApplicationService; +import com.baiyue.order.service.PrintableInboundSnapshotService; import com.baiyue.order.client.FirstlegInboundClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -29,6 +31,7 @@ import java.util.stream.Collectors; @RequestMapping("/internal/order/v1/cargoes") public class InternalOrderCargoController { @Resource private OrderRepository orders; + @Resource private PrintableInboundSnapshotService printableInboundSnapshots; @Value("${baiyue.security.internal-service-token}") private String internalToken; private byte[] expectedToken; @@ -98,6 +101,18 @@ public class InternalOrderCargoController { return ApiResponse.success(OrderApplicationService.inboundCommand(order, packageCount)); } + @PostMapping("/{tenantId}/{orderId}/printable-inbound-snapshot") + public ApiResponse printableInboundSnapshot( + @RequestHeader(value = "X-Internal-Service-Token", required = false) String token, + @PathVariable long tenantId, + @PathVariable long orderId) { + requireToken(token); + if (tenantId <= 0 || orderId <= 0) { + throw new BizException(ResultCode.BAD_REQUEST, "租户和订单ID必须大于0"); + } + return ApiResponse.success(printableInboundSnapshots.reserve(tenantId, orderId)); + } + @GetMapping("/{tenantId}/{orderId}/measurement-declaration") public ApiResponse measurementDeclaration( @RequestHeader(value = "X-Internal-Service-Token", required = false) String token, diff --git a/order/src/main/java/com/baiyue/order/repository/OrderRepository.java b/order/src/main/java/com/baiyue/order/repository/OrderRepository.java index e9987383c..40c1b715a 100644 --- a/order/src/main/java/com/baiyue/order/repository/OrderRepository.java +++ b/order/src/main/java/com/baiyue/order/repository/OrderRepository.java @@ -54,6 +54,17 @@ public class OrderRepository { .eq(OrderEntity::getId, order.getId()) .eq(OrderEntity::getTenantId, tenantId)); } + public int assignInboundCodeIfBlank(long tenantId, long orderId, String inboundCode) { + return orderMapper.update(null, new LambdaUpdateWrapper() + .eq(OrderEntity::getTenantId, tenantId) + .eq(OrderEntity::getId, orderId) + .eq(OrderEntity::getDeleted, false) + .and(wrapper -> wrapper.isNull(OrderEntity::getInboundCode) + .or().eq(OrderEntity::getInboundCode, "")) + .set(OrderEntity::getInboundCode, inboundCode) + .set(OrderEntity::getUpdatedAt, LocalDateTime.now()) + .setSql("version = version + 1")); + } public int updateDeclarationHeader(long tenantId, long orderId, int expectedVersion, long operatorId, String customerRemark, LocalDateTime expectedArrivalAt, java.math.BigDecimal estimatedVolumeCbm, diff --git a/order/src/main/java/com/baiyue/order/service/PrintableInboundSnapshotService.java b/order/src/main/java/com/baiyue/order/service/PrintableInboundSnapshotService.java new file mode 100644 index 000000000..a789cf392 --- /dev/null +++ b/order/src/main/java/com/baiyue/order/service/PrintableInboundSnapshotService.java @@ -0,0 +1,64 @@ +package com.baiyue.order.service; + +import com.baiyue.common.core.api.ResultCode; +import com.baiyue.common.core.exception.BizException; +import com.baiyue.order.client.FirstlegInboundClient; +import com.baiyue.order.config.InboundCodeModeProvider; +import com.baiyue.order.entity.OrderCargoEntity; +import com.baiyue.order.entity.OrderEntity; +import com.baiyue.order.repository.OrderRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +/** 为草稿箱唛打印预留稳定入仓码;订单提交时继续复用该码。 */ +@Service +public class PrintableInboundSnapshotService { + private final OrderRepository orders; + private final OrderPricingChannelGuard pricingChannels; + private final InboundCodeModeProvider inboundCodeMode; + private final OrderApplicationService orderApplication; + + public PrintableInboundSnapshotService(OrderRepository orders, + OrderPricingChannelGuard pricingChannels, + InboundCodeModeProvider inboundCodeMode, + OrderApplicationService orderApplication) { + this.orders = orders; + this.pricingChannels = pricingChannels; + this.inboundCodeMode = inboundCodeMode; + this.orderApplication = orderApplication; + } + + @Transactional + public FirstlegInboundClient.OrderApprovedInboundCommand reserve(long tenantId, long orderId) { + OrderEntity order = requireOwned(tenantId, orderId); + if (!StringUtils.hasText(order.getInboundCode())) { + if (inboundCodeMode.legacyManual()) { + throw new BizException(ResultCode.VALIDATION_FAILED, "当前系统使用旧系统入仓码,请先填写入仓码"); + } + String prefix = pricingChannels.requireAvailable(tenantId, order.getReceivingWarehouseId(), + order.getChannelCode(), order.getDestinationType()); + String allocated = orderApplication.nextInboundCode(prefix); + if (orders.assignInboundCodeIfBlank(tenantId, orderId, allocated) == 1) { + order.setInboundCode(allocated); + } else { + order = requireOwned(tenantId, orderId); + if (!StringUtils.hasText(order.getInboundCode())) { + throw new BizException(ResultCode.CONFLICT, "入仓码预留冲突,请刷新后重试"); + } + } + } + int packageCount = orders.findCargoInheritedByOrder(tenantId, orderId).stream() + .map(OrderCargoEntity::getPackageCount).filter(java.util.Objects::nonNull) + .mapToInt(Integer::intValue).sum(); + return OrderApplicationService.inboundCommand(order, packageCount); + } + + private OrderEntity requireOwned(long tenantId, long orderId) { + OrderEntity order = orders.findOwned(tenantId, orderId); + if (order == null) { + throw new BizException(ResultCode.NOT_FOUND, "订单不存在或不属于当前客户"); + } + return order; + } +} diff --git a/order/src/main/resources/openapi/order-v1.yaml b/order/src/main/resources/openapi/order-v1.yaml index b69987464..baf544bcd 100644 --- a/order/src/main/resources/openapi/order-v1.yaml +++ b/order/src/main/resources/openapi/order-v1.yaml @@ -28,6 +28,23 @@ paths: application/json: schema: {$ref: '#/components/schemas/CargoLabelBindingListEnvelope'} '403': {description: 内部服务令牌无效} + /internal/order/v1/cargoes/{tenantId}/{orderId}/printable-inbound-snapshot: + post: + security: [] + summary: 为 Firstleg 箱唛打印读取并预留稳定入仓快照 + description: >- + 仅接受内部服务令牌。若 AUTO 模式草稿尚无入仓码,则按订单渠道原子预留全局唯一入仓码; + 并发重放返回已胜出的同一码,后续订单提交继续复用,避免已打印二维码失效。 + parameters: + - name: X-Internal-Service-Token + in: header + required: true + schema: {type: string} + - {name: tenantId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}} + - {name: orderId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}} + responses: + '200': {description: 返回带稳定入仓码及总箱数的订单快照} + '403': {description: 内部服务令牌无效} /internal/order/v1/pending-review-orders: get: security: [] diff --git a/order/src/test/java/com/baiyue/order/controller/InternalOrderCargoControllerTest.java b/order/src/test/java/com/baiyue/order/controller/InternalOrderCargoControllerTest.java index 0de14a34c..ccc5af982 100644 --- a/order/src/test/java/com/baiyue/order/controller/InternalOrderCargoControllerTest.java +++ b/order/src/test/java/com/baiyue/order/controller/InternalOrderCargoControllerTest.java @@ -5,6 +5,8 @@ import com.baiyue.order.entity.OrderCargoEntity; import com.baiyue.order.entity.OrderEntity; import com.baiyue.order.entity.OrderInternalNoteEntity; import com.baiyue.order.repository.OrderRepository; +import com.baiyue.order.service.OrderApplicationService; +import com.baiyue.order.service.PrintableInboundSnapshotService; import org.junit.jupiter.api.Test; import jakarta.annotation.Resource; import org.springframework.boot.test.mock.mockito.MockBean; @@ -23,11 +25,13 @@ import java.lang.reflect.Method; import java.util.List; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; @SpringJUnitConfig(InternalOrderCargoController.class) @TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token") class InternalOrderCargoControllerTest { @MockBean private OrderRepository orders; + @MockBean private PrintableInboundSnapshotService printableInboundSnapshots; @Resource private InternalOrderCargoController controller; @Test @@ -145,6 +149,24 @@ class InternalOrderCargoControllerTest { verify(orders).findOwned(11L, 21L); } + @Test + void reservesPrintableSnapshotThroughExplicitCommandRoute() throws Exception { + OrderEntity order = new OrderEntity(); + order.setTenantId(11L); order.setId(21L); order.setDestinationType("FBA"); + order.setTransportMode("SEA"); + var snapshot = OrderApplicationService.inboundCommand(order, 3); + when(printableInboundSnapshots.reserve(11L, 21L)).thenReturn(snapshot); + + var response = controller.printableInboundSnapshot("internal-token", 11L, 21L); + + assertThat(response.data()).isSameAs(snapshot); + verify(printableInboundSnapshots).reserve(11L, 21L); + Method route = InternalOrderCargoController.class.getMethod( + "printableInboundSnapshot", String.class, long.class, long.class); + assertThat(route.getAnnotation(PostMapping.class).value()) + .containsExactly("/{tenantId}/{orderId}/printable-inbound-snapshot"); + } + @Test void measurementDeclarationUsesOrderReferenceAndSumsCargoFacts() { OrderEntity order = new OrderEntity(); diff --git a/order/src/test/java/com/baiyue/order/controller/PrintableInboundSnapshotOpenApiContractTest.java b/order/src/test/java/com/baiyue/order/controller/PrintableInboundSnapshotOpenApiContractTest.java new file mode 100644 index 000000000..c9a8e9554 --- /dev/null +++ b/order/src/test/java/com/baiyue/order/controller/PrintableInboundSnapshotOpenApiContractTest.java @@ -0,0 +1,21 @@ +package com.baiyue.order.controller; + +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; + +import static org.assertj.core.api.Assertions.assertThat; + +class PrintableInboundSnapshotOpenApiContractTest { + @Test + void documentsTheMutatingInternalCommandAsPost() throws Exception { + try (var stream = getClass().getResourceAsStream("/openapi/order-v1.yaml")) { + assertThat(stream).isNotNull(); + String yaml = new String(stream.readAllBytes(), StandardCharsets.UTF_8); + assertThat(yaml).contains( + "/internal/order/v1/cargoes/{tenantId}/{orderId}/printable-inbound-snapshot:", + "若 AUTO 模式草稿尚无入仓码,则按订单渠道原子预留全局唯一入仓码", + "后续订单提交继续复用"); + } + } +} diff --git a/order/src/test/java/com/baiyue/order/service/PrintableInboundSnapshotServiceTest.java b/order/src/test/java/com/baiyue/order/service/PrintableInboundSnapshotServiceTest.java new file mode 100644 index 000000000..5676c6cf7 --- /dev/null +++ b/order/src/test/java/com/baiyue/order/service/PrintableInboundSnapshotServiceTest.java @@ -0,0 +1,113 @@ +package com.baiyue.order.service; + +import com.baiyue.common.core.exception.BizException; +import com.baiyue.order.config.InboundCodeModeProvider; +import com.baiyue.order.entity.OrderCargoEntity; +import com.baiyue.order.entity.OrderEntity; +import com.baiyue.order.repository.OrderRepository; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class PrintableInboundSnapshotServiceTest { + @Test + void reservesStableCodeForDraftAndReturnsPrintableSnapshot() { + OrderRepository orders = mock(OrderRepository.class); + OrderPricingChannelGuard pricing = mock(OrderPricingChannelGuard.class); + OrderApplicationService application = mock(OrderApplicationService.class); + OrderEntity order = draft(); + OrderCargoEntity cargo = new OrderCargoEntity(); + cargo.setPackageCount(3); + when(orders.findOwned(11L, 21L)).thenReturn(order); + when(pricing.requireAvailable(11L, 41L, "CH", "FBA")).thenReturn("PCHK"); + when(application.nextInboundCode("PCHK")).thenReturn("PCHK2609080001"); + when(orders.assignInboundCodeIfBlank(11L, 21L, "PCHK2609080001")).thenReturn(1); + when(orders.findCargoInheritedByOrder(11L, 21L)).thenReturn(List.of(cargo)); + + var result = service(orders, pricing, application, "AUTO").reserve(11L, 21L); + + assertThat(result.inboundCode()).isEqualTo("PCHK2609080001"); + assertThat(result.totalPackageCount()).isEqualTo(3); + verify(orders).assignInboundCodeIfBlank(11L, 21L, "PCHK2609080001"); + } + + @Test + void reusesCodeAlreadyReservedByAConcurrentRequest() { + OrderRepository orders = mock(OrderRepository.class); + OrderPricingChannelGuard pricing = mock(OrderPricingChannelGuard.class); + OrderApplicationService application = mock(OrderApplicationService.class); + OrderEntity initial = draft(); + OrderEntity winner = draft(); + winner.setInboundCode("PCHK2609080002"); + when(orders.findOwned(11L, 21L)).thenReturn(initial, winner); + when(pricing.requireAvailable(11L, 41L, "CH", "FBA")).thenReturn("PCHK"); + when(application.nextInboundCode("PCHK")).thenReturn("PCHK2609080001"); + when(orders.assignInboundCodeIfBlank(11L, 21L, "PCHK2609080001")).thenReturn(0); + when(orders.findCargoInheritedByOrder(11L, 21L)).thenReturn(List.of()); + + var result = service(orders, pricing, application, "AUTO").reserve(11L, 21L); + + assertThat(result.inboundCode()).isEqualTo("PCHK2609080002"); + } + + @Test + void existingCodeDoesNotAllocateAnotherSequence() { + OrderRepository orders = mock(OrderRepository.class); + OrderPricingChannelGuard pricing = mock(OrderPricingChannelGuard.class); + OrderApplicationService application = mock(OrderApplicationService.class); + OrderEntity order = draft(); + order.setInboundCode("PCHK2609080001"); + when(orders.findOwned(11L, 21L)).thenReturn(order); + when(orders.findCargoInheritedByOrder(11L, 21L)).thenReturn(List.of()); + + var result = service(orders, pricing, application, "AUTO").reserve(11L, 21L); + + assertThat(result.inboundCode()).isEqualTo("PCHK2609080001"); + verify(application, never()).nextInboundCode(org.mockito.ArgumentMatchers.anyString()); + } + + @Test + void legacyManualModeRejectsMissingCodeWithoutWriting() { + OrderRepository orders = mock(OrderRepository.class); + OrderPricingChannelGuard pricing = mock(OrderPricingChannelGuard.class); + OrderApplicationService application = mock(OrderApplicationService.class); + when(orders.findOwned(11L, 21L)).thenReturn(draft()); + + assertThatThrownBy(() -> service(orders, pricing, application, "LEGACY_MANUAL").reserve(11L, 21L)) + .isInstanceOf(BizException.class) + .hasMessage("当前系统使用旧系统入仓码,请先填写入仓码"); + + verify(orders, never()).assignInboundCodeIfBlank( + org.mockito.ArgumentMatchers.anyLong(), org.mockito.ArgumentMatchers.anyLong(), + org.mockito.ArgumentMatchers.anyString()); + } + + private PrintableInboundSnapshotService service(OrderRepository orders, + OrderPricingChannelGuard pricing, + OrderApplicationService application, + String mode) { + return new PrintableInboundSnapshotService( + orders, pricing, new InboundCodeModeProvider(mode), application); + } + + private OrderEntity draft() { + OrderEntity order = new OrderEntity(); + order.setId(21L); + order.setTenantId(11L); + order.setOrderNo("FL21"); + order.setCustomerId(11L); + order.setReceivingWarehouseId(41L); + order.setChannelCode("CH"); + order.setDestinationType("FBA"); + order.setTransportMode("SEA"); + order.setFulfillmentType("STANDARD"); + return order; + } +}