diff --git a/order/src/main/java/com/baiyue/order/service/OrderFulfillmentSplitService.java b/order/src/main/java/com/baiyue/order/service/OrderFulfillmentSplitService.java index e5fffe608..fdc9520ed 100644 --- a/order/src/main/java/com/baiyue/order/service/OrderFulfillmentSplitService.java +++ b/order/src/main/java/com/baiyue/order/service/OrderFulfillmentSplitService.java @@ -142,6 +142,7 @@ public class OrderFulfillmentSplitService { child.setReceivingWarehouseName(root.getReceivingWarehouseName()); child.setChannelCode(root.getChannelCode()); child.setChannelName(root.getChannelName()); child.setDestinationType(root.getDestinationType()); child.setFulfillmentType(root.getFulfillmentType()); + child.setTaxMode(root.getTaxMode()); child.setInboundCode(remainderInboundCode(root, sequence)); child.setCreatedBy(operatorId); child.setUpdatedBy(operatorId); if (orders.insert(child) != 1) throw new BizException(ResultCode.CONFLICT, "余量子订单创建失败"); diff --git a/order/src/test/java/com/baiyue/order/repository/UnifiedOrderTaxModePaginationTest.java b/order/src/test/java/com/baiyue/order/repository/UnifiedOrderTaxModePaginationTest.java index 7d53ae1ac..756055ee9 100644 --- a/order/src/test/java/com/baiyue/order/repository/UnifiedOrderTaxModePaginationTest.java +++ b/order/src/test/java/com/baiyue/order/repository/UnifiedOrderTaxModePaginationTest.java @@ -24,11 +24,13 @@ import static org.assertj.core.api.Assertions.assertThat; /** Real mapper + pagination interceptor: tax filtering applies to COUNT and records before LIMIT. */ class UnifiedOrderTaxModePaginationTest { private OrderRepository repository; + private JdbcTemplate jdbc; + private OrderMapper mapper; @BeforeEach void setup() throws Exception { var dataSource = new JdbcDataSource(); dataSource.setURL("jdbc:h2:mem:tax-page-" + UUID.randomUUID() + ";MODE=MySQL;DB_CLOSE_DELAY=-1"); - var jdbc = new JdbcTemplate(dataSource); + jdbc = new JdbcTemplate(dataSource); var columns = new ArrayList(); for (Class type = OrderEntity.class; type != Object.class; type = type.getSuperclass()) { for (var field : type.getDeclaredFields()) { @@ -41,7 +43,9 @@ class UnifiedOrderTaxModePaginationTest { : valueType == java.math.BigDecimal.class ? "DECIMAL(20,6)" : valueType == java.time.LocalDateTime.class ? "TIMESTAMP" : valueType == java.time.LocalDate.class ? "DATE" : "VARCHAR(2000)"; - columns.add(name + " " + sqlType + (name.equals("id") ? " PRIMARY KEY" : "")); + columns.add(name + " " + sqlType + (name.equals("id") ? " PRIMARY KEY" + : name.equals("deleted") || name.equals("version") ? " DEFAULT 0" + : name.equals("created_at") ? " DEFAULT CURRENT_TIMESTAMP" : "")); } } jdbc.execute("CREATE TABLE ord_order (" + String.join(",", columns) + ")"); @@ -58,7 +62,8 @@ class UnifiedOrderTaxModePaginationTest { factory.setDataSource(dataSource); factory.setConfiguration(config); factory.setPlugins(pagination); var session = new SqlSessionTemplate(factory.getObject()); repository = new OrderRepository(); - ReflectionTestUtils.setField(repository, "orderMapper", session.getMapper(OrderMapper.class)); + mapper = session.getMapper(OrderMapper.class); + ReflectionTestUtils.setField(repository, "orderMapper", mapper); } @Test void taxModeFiltersCountsAndPagesWithoutLeakingAnotherCustomerOrDeletedRows() { @@ -69,6 +74,41 @@ class UnifiedOrderTaxModePaginationTest { assertPage(null, 1, 4, 6); assertPage(null, 2, 4, 4); } + + @org.junit.jupiter.params.ParameterizedTest + @org.junit.jupiter.params.provider.ValueSource(strings = {"TAX_REFUND", "BUY_DECLARATION"}) + void realSplitChildIsPersistedAndIncludedInTaxFilteredParentChildPages(String taxMode) { + jdbc.update("UPDATE ord_order SET tax_mode=?,order_role='MASTER',order_no='TAX-PARENT',inbound_code='TAX-INBOUND',version=0 WHERE id=6", taxMode); + var root = mapper.findOwned(11L, 6L); + var ledger = org.mockito.Mockito.mock(com.baiyue.order.mapper.OrderFulfillmentSplitMapper.class); + org.mockito.Mockito.when(ledger.findByIdempotency(11L, 6L, "tax-split")).thenReturn(List.of()); + org.mockito.Mockito.when(ledger.lockOrder(11L, 6L)).thenReturn(root); + org.mockito.Mockito.when(ledger.insert(org.mockito.ArgumentMatchers.any(com.baiyue.order.entity.OrderFulfillmentSplitEntity.class))).thenReturn(1); + org.mockito.Mockito.when(ledger.incrementParentVersion(11L, 6L, 0, 9L)).thenReturn(1); + var splitter = new com.baiyue.order.service.OrderFulfillmentSplitService(); + ReflectionTestUtils.setField(splitter, "splits", ledger); + ReflectionTestUtils.setField(splitter, "orders", mapper); + ReflectionTestUtils.setField(splitter, "json", new com.fasterxml.jackson.databind.ObjectMapper()); + var result = splitter.split(new com.baiyue.order.dto.OrderSplitDtos.CreateRequest( + 11L, 6L, 6L, 701L, 801L, 2, 1, 1, 0, "tax-split", "op-tax-split", + List.of(new com.baiyue.order.dto.OrderSplitDtos.QuantityLine(99L, 2)), "operator"), 9L); + long childId = result.remainderChild().orderId(); + assertThat(mapper.findOwned(11L, childId).getTaxMode()).isEqualTo(taxMode); + var pageIds = new ArrayList(); + for (long page = 1; page <= 2; page++) { + var query = new UnifiedOrderQuery(null, "TAX-PARENT", null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, page, 1, taxMode); + var filtered = repository.unifiedPage(11L, query, List.of(com.baiyue.order.entity.OrderStatus.APPROVED)); + assertThat(filtered.total()).isEqualTo(2); + assertThat(filtered.records()).singleElement().satisfies(row -> { + pageIds.add(row.getId()); + assertThat(row.getTaxMode()).isEqualTo(taxMode); + assertThat(row.getTenantId()).isEqualTo(11L); + }); + } + assertThat(pageIds).containsExactlyInAnyOrder(childId, 6L); + assertThat(mapper.findOwned(22L, childId)).isNull(); + } private void assertPage(String taxMode, long page, long total, long expectedId) { var query = new UnifiedOrderQuery(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, page, 1, taxMode); var result = repository.unifiedPage(11L, query, List.of(com.baiyue.order.entity.OrderStatus.APPROVED)); diff --git a/order/src/test/java/com/baiyue/order/service/OrderFulfillmentSplitServiceTest.java b/order/src/test/java/com/baiyue/order/service/OrderFulfillmentSplitServiceTest.java index 7636a6b38..3b5e7a483 100644 --- a/order/src/test/java/com/baiyue/order/service/OrderFulfillmentSplitServiceTest.java +++ b/order/src/test/java/com/baiyue/order/service/OrderFulfillmentSplitServiceTest.java @@ -68,6 +68,25 @@ class OrderFulfillmentSplitServiceTest { verify(splits).incrementParentVersion(10, 100, 3, 9); } + @org.junit.jupiter.params.ParameterizedTest + @org.junit.jupiter.params.provider.ValueSource(strings = {"TAX_REFUND", "BUY_DECLARATION"}) + void remainderInheritsRootTaxModeThroughRealSplitCommand(String taxMode) { + OrderEntity parent = parent(); + parent.setTaxMode(taxMode); + when(splits.findByIdempotency(10, 100, "tax-child")).thenReturn(List.of()); + when(splits.lockOrder(10, 100)).thenReturn(parent); + when(orders.insert(any(OrderEntity.class))).thenReturn(1); + when(splits.insert(any(OrderFulfillmentSplitEntity.class))).thenReturn(1); + when(splits.incrementParentVersion(10, 100, 3, 9)).thenReturn(1); + var result = service.split(request(100L, 20, 8, 12, "tax-child"), 9); + ArgumentCaptor child = ArgumentCaptor.forClass(OrderEntity.class); + verify(orders).insert(child.capture()); + assertThat(child.getValue().getId()).isEqualTo(result.remainderChild().orderId()); + assertThat(child.getValue().getTaxMode()).isEqualTo(taxMode); + assertThat(child.getValue().getTenantId()).isEqualTo(parent.getTenantId()); + assertThat(child.getValue().getRootOrderId()).isEqualTo(parent.getId()); + } + @Test void rejectsConcurrentParentVersionChangeWithoutPublishingNextVersion() { OrderEntity parent = parent();