From 2c5fda33e77136dc0af2cfc700e40d79c95e3f60 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Mon, 7 Sep 2026 14:03:00 +0800 Subject: [PATCH] fix: complete overseas fulfillment acceptance --- .../service/DeliveryTransferService.java | 12 +++++++++++- .../service/DeliveryTransferServiceTest.java | 19 +++++++++++++++++++ ...overseas-client-services-contract.test.mjs | 2 ++ .../phase4-overseas-client-services.mjs | 2 ++ ...-overseas-pda-operations-contract.test.mjs | 3 ++- .../phase4-overseas-pda-operations.mjs | 4 +++- ...s-wallet-and-pallet-cost-contract.test.mjs | 2 ++ ...phase4-overseas-wallet-and-pallet-cost.mjs | 4 +++- 8 files changed, 44 insertions(+), 4 deletions(-) diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/service/DeliveryTransferService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/service/DeliveryTransferService.java index 2d139ea87..de4652049 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/service/DeliveryTransferService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/service/DeliveryTransferService.java @@ -128,7 +128,7 @@ public class DeliveryTransferService { outbound.setOutboundNo(orderNoGenerator.next("OUTBOUND", dispatch.getOverseasWarehouseId(), outbound.getId())); outbound.setDispatchOrderId(dispatch.getId()); outbound.setDispatchNo(dispatch.getDispatchNo()); outbound.setOverseasWarehouseId(dispatch.getOverseasWarehouseId()); outbound.setStatus("WAIT_OUTBOUND"); outbound.setOutboundType("DISPATCH_DELIVERY"); - outbound.setLxCodes(items.stream().map(DispatchItem::getInboundCode).filter(StringUtils::hasText).map(code -> tailOrders.selectOne(new LambdaQueryWrapper().eq(LastlegOrder::getCustomerId, customerId).eq(LastlegOrder::getInboundCode, code))).filter(Objects::nonNull).map(LastlegOrder::getLxCode).filter(StringUtils::hasText).distinct().collect(java.util.stream.Collectors.joining(","))); + outbound.setLxCodes(resolveLxCodes(customerId, items)); outbound.setPackageCount(items.stream().map(DispatchItem::getPackageCount).filter(Objects::nonNull).mapToInt(Integer::intValue).sum()); outbound.setPalletCount(items.size()); outbound.setIdempotencyKey(request.idempotencyKey().trim()); outbound.setCreatedBy(operatorId); outbound.setCreatedAt(now); outbound.setUpdatedAt(now); @@ -562,6 +562,16 @@ public class DeliveryTransferService { private DeliveryResponses.DeliveryOperationRow operationRow(DeliveryOperation o) { return new DeliveryResponses.DeliveryOperationRow(o.getId(), o.getCreatedAt(), o.getOperationNode(), firstText(o.getOperatorName(), o.getOperatorId()), o.getResult()); } private void recordOperation(String customerId, Long deliveryId, String operatorId, String node, String result, LocalDateTime now) { DeliveryOperation operation = new DeliveryOperation(); operation.setCustomerId(customerId); operation.setDeliveryOrderId(deliveryId); operation.setOperationNode(node); operation.setOperatorId(operatorId); operation.setOperatorName(operatorId); operation.setResult(result); operation.setCreatedAt(now); deliveryOperations.insert(operation); } private LastlegOrder firstTailOrder(String customerId, List items) { return items.stream().map(DispatchItem::getOrderId).filter(Objects::nonNull).map(tailOrders::selectById).filter(Objects::nonNull).filter(order -> customerId.equals(order.getCustomerId())).findFirst().orElse(null); } + private String resolveLxCodes(String customerId, List items) { + List inboundCodes = items.stream().map(DispatchItem::getInboundCode) + .filter(StringUtils::hasText).map(String::trim).distinct().toList(); + if (inboundCodes.isEmpty()) return ""; + return tailOrders.selectList(new LambdaQueryWrapper() + .eq(LastlegOrder::getCustomerId, customerId) + .in(LastlegOrder::getInboundCode, inboundCodes)) + .stream().map(LastlegOrder::getLxCode).filter(StringUtils::hasText) + .map(String::trim).distinct().collect(java.util.stream.Collectors.joining(",")); + } private BigDecimal totalWeight(String customerId, List items) { List ids = items.stream().map(DispatchItem::getOrderId).filter(Objects::nonNull).distinct().toList(); if (ids.isEmpty()) return BigDecimal.ZERO; return tailOrderDetails.selectList(new LambdaQueryWrapper().eq(LastlegOrderDetail::getCustomerId, customerId).in(LastlegOrderDetail::getOrderId, ids)).stream().map(LastlegOrderDetail::getGrossWeightKg).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); } private static String trim(String value) { return StringUtils.hasText(value) ? value.trim() : null; } private static String required(String value, String message) { diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/delivery/service/DeliveryTransferServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/delivery/service/DeliveryTransferServiceTest.java index be897d926..45efda206 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/delivery/service/DeliveryTransferServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/delivery/service/DeliveryTransferServiceTest.java @@ -140,6 +140,25 @@ class DeliveryTransferServiceTest { assertTrue(!result.replayed()); } + @Test + void transferCollectsLxCodesWhenAnInboundCodeBelongsToMultipleTailOrders() { + DispatchOrder dispatch = dispatch(101L, "DSP-101", "TENANT-A"); + when(dispatchOrders.lockGlobalByDispatchNo("DSP-101")).thenReturn(dispatch); + when(dispatchItems.findByDispatchOrder("TENANT-A", 101L)).thenReturn(List.of( + item(201L, 501L, "PLT-501", "ONT8", "Ontario", "IN-A", 12))); + LastlegOrder primary = new LastlegOrder(); + primary.setCustomerId("TENANT-A"); primary.setInboundCode("IN-A"); primary.setLxCode("LX-1"); + LastlegOrder derived = new LastlegOrder(); + derived.setCustomerId("TENANT-A"); derived.setInboundCode("IN-A"); derived.setLxCode(null); + when(tailOrders.selectList(any())).thenReturn(List.of(primary, derived), List.of()); + + service.platformTransfer("DSP-101", "U-1", transferRequest("transfer-duplicate-inbound", null)); + + ArgumentCaptor outbound = ArgumentCaptor.forClass(OutboundOrder.class); + verify(outboundOrders).insert(outbound.capture()); + assertEquals("LX-1", outbound.getValue().getLxCodes()); + } + @Test void sameIdempotencyKeyReturnsExistingDocumentsWithoutWrites() { DispatchOrder dispatch = dispatch(101L, "DSP-101", "TENANT-A"); diff --git a/scripts/admin-test-env-modules/phase4-overseas-client-services-contract.test.mjs b/scripts/admin-test-env-modules/phase4-overseas-client-services-contract.test.mjs index 7c1e3fb22..69bc6e35d 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-client-services-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-client-services-contract.test.mjs @@ -30,6 +30,8 @@ test('module never borrows historical order or inventory candidates', () => { test('relabel transfer and discard cover create replay conflict list detail and legal initial states', () => { assert.match(source, /chargeAmount: 0\.01/) + assert.match(source, /cartonMark:/) + assert.match(source, /fbaCartonMark:/) for (const token of [ '客户创建贴标申请', '客户贴标申请幂等重放', '贴标同幂等键异载荷返回A0409', '客户查询自身贴标申请列表', '客户查询自身贴标申请详情', 'PENDING_PROCESSING', diff --git a/scripts/admin-test-env-modules/phase4-overseas-client-services.mjs b/scripts/admin-test-env-modules/phase4-overseas-client-services.mjs index 3b01ca857..c9490fe62 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-client-services.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-client-services.mjs @@ -101,6 +101,8 @@ async function verifyRelabel(context, token, order) { shipmentNo: cargo.shipmentNo || `${context.marker}-RELABEL-SHIP`, trackingCode: cargo.fbaTrackingNo || null, newSkuCode: `${cargo.skuCode}-NEW`.slice(0, 128), labelRequirement: context.marker, relabelFileId: null, relabelFileName: null, relabelFileUrl: null, + cartonMark: `CM-${String(context.marker).slice(-32)}`, + fbaCartonMark: `FBA-${String(context.marker).slice(-32)}`, }], } const created = await merchant(context, token, 'POST', '客户创建贴标申请', RELABEL, body) diff --git a/scripts/admin-test-env-modules/phase4-overseas-pda-operations-contract.test.mjs b/scripts/admin-test-env-modules/phase4-overseas-pda-operations-contract.test.mjs index 440fdc203..28fb043bb 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-pda-operations-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-pda-operations-contract.test.mjs @@ -46,7 +46,8 @@ test('P2 to P5 cover all frozen endpoints, replays and conflict boundaries witho ]) assert.ok(source.includes(endpoint), endpoint) for (const marker of ['按原数计数', '同键重放', '同键异载荷A0409', '旧版本A0409', 'SUBMITTED', '移回原库位', 'WAIT_REVIEW', 'REWORK', 'APPROVE', 'COMPLETED', - 'chargeAmount: 0.01', 'P5换标费用冻结后开放PDA作业', 'P5换标完成后钱包结算收敛']) { + 'chargeAmount: 0.01', 'cartonMark:', 'fbaCartonMark:', + 'P5换标费用冻结后开放PDA作业', 'P5换标完成后钱包结算收敛']) { assert.ok(source.includes(marker), marker) } for (const forbidden of ['/outbound', '/returns/outbound', '/dispatch', '/delivery', '/internal/']) { diff --git a/scripts/admin-test-env-modules/phase4-overseas-pda-operations.mjs b/scripts/admin-test-env-modules/phase4-overseas-pda-operations.mjs index 7044ab273..3a173ffd3 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-pda-operations.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-pda-operations.mjs @@ -333,7 +333,9 @@ async function verifyRelabel(context, token, fixture) { idempotencyKey: key(context, 'RELABEL-CREATE'), items: [{ skuCode: inventory.skuCode, productNameZh: inventory.productName || '本轮库存商品', totalPackageCount: 3, notifiedPackageCount: 3, shipmentNo: `SHIP-${context.marker}`.slice(0, 128), - newSkuCode: newSku, labelRequirement: context.marker }], + newSkuCode: newSku, labelRequirement: context.marker, + cartonMark: `CM-${String(context.marker).slice(-32)}`, + fbaCartonMark: `FBA-${String(context.marker).slice(-32)}` }], } const createdResponse = await context.requestOverseas('POST', query(relabelBase, { customerId }), createBody) diff --git a/scripts/admin-test-env-modules/phase4-overseas-wallet-and-pallet-cost-contract.test.mjs b/scripts/admin-test-env-modules/phase4-overseas-wallet-and-pallet-cost-contract.test.mjs index c9f633df0..e6027aaed 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-wallet-and-pallet-cost-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-wallet-and-pallet-cost-contract.test.mjs @@ -30,6 +30,8 @@ test('钱包闭环覆盖充值、授信、采购冻结结算和换标结算释 "terminalStatus === 'COMPLETED'", "'CANCELLED'", 'relabelPayload(context, warehouseId, suffix, 0.01)', + 'cartonMark:', + 'fbaCartonMark:', ]) assert.ok(source.includes(token), token) assert.match(source, /actualBalance[\s\S]*frozenBalance[\s\S]*availableBalance[\s\S]*creditLimit[\s\S]*creditUsed[\s\S]*availableCredit/) assert.match(source, /voucherFileId: id\(files\.find\(\(item\) => item\.category === 'VOUCHER'\)\?\.fileId\)/) diff --git a/scripts/admin-test-env-modules/phase4-overseas-wallet-and-pallet-cost.mjs b/scripts/admin-test-env-modules/phase4-overseas-wallet-and-pallet-cost.mjs index 761526154..93e37ce3f 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-wallet-and-pallet-cost.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-wallet-and-pallet-cost.mjs @@ -178,7 +178,9 @@ function relabelPayload(context, warehouseId, suffix, chargeAmount) { remark: context.marker, idempotencyKey: `${context.marker}-${suffix}`.slice(0, 255), items: [{ skuCode: `OLD-${value}-${suffix}`.slice(0, 128), productNameZh: `${context.marker} 换标商品`, totalPackageCount: 1, notifiedPackageCount: 1, shipmentNo: `SHIP-${value}-${suffix}`.slice(0, 128), - newSkuCode: `NEW-${value}-${suffix}`.slice(0, 128), labelRequirement: context.marker }], + newSkuCode: `NEW-${value}-${suffix}`.slice(0, 128), labelRequirement: context.marker, + cartonMark: `CM-${value}-${suffix}`.slice(0, 255), + fbaCartonMark: `FBA-${value}-${suffix}`.slice(0, 255) }], } }