fix: complete overseas fulfillment acceptance
This commit is contained in:
+11
-1
@@ -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<LastlegOrder>().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<DispatchItem> 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<DispatchItem> items) {
|
||||
List<String> inboundCodes = items.stream().map(DispatchItem::getInboundCode)
|
||||
.filter(StringUtils::hasText).map(String::trim).distinct().toList();
|
||||
if (inboundCodes.isEmpty()) return "";
|
||||
return tailOrders.selectList(new LambdaQueryWrapper<LastlegOrder>()
|
||||
.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<DispatchItem> items) { List<Long> ids = items.stream().map(DispatchItem::getOrderId).filter(Objects::nonNull).distinct().toList(); if (ids.isEmpty()) return BigDecimal.ZERO; return tailOrderDetails.selectList(new LambdaQueryWrapper<LastlegOrderDetail>().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) {
|
||||
|
||||
+19
@@ -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<OutboundOrder> 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");
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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/']) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
+2
@@ -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\)/)
|
||||
|
||||
@@ -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) }],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user