fix(dropship): project sealed carton identities into overseas receiving
This commit is contained in:
+56
-12
@@ -20,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Objects;
|
||||
import java.util.ArrayList;
|
||||
@@ -62,7 +63,7 @@ public class LoadingCompletedConsumer {
|
||||
String sourceContainerBookingId = sourceContainerBookingId(envelope, payload);
|
||||
if(payload.orders()==null||payload.orders().isEmpty()) throw new IllegalArgumentException("事件没有入仓单");
|
||||
OwnerSnapshot owner = requireOwnerSnapshot(payload.orders(), envelope.tenantId());
|
||||
if (envelope.eventVersion() == 2) validateCartonSkuMappings(payload);
|
||||
if (envelope.eventVersion() == 2) validateCartonSkuMappings(payload, envelope.payload());
|
||||
freezeContainerIdentity(envelope, sourceContainerBookingId, containerNo);
|
||||
LastlegEventInbox existing=inboxMapper.selectById(envelope.eventId());
|
||||
if(existing!=null) {
|
||||
@@ -102,8 +103,8 @@ public class LoadingCompletedConsumer {
|
||||
try {
|
||||
ObjectMapper compatibleMapper = objectMapper.copy()
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
// V2 only adds immutable item remarks; the current tail-leg snapshot model
|
||||
// intentionally ignores those fields until its schema exposes them.
|
||||
// The internal order model keeps the shared fields. V2 pallet source-detail
|
||||
// identity is validated separately from the original immutable payload.
|
||||
return compatibleMapper.treeToValue(envelope.payload(), FirstLegLoadingPlanCompletedV1.class);
|
||||
}
|
||||
catch(Exception exception) { throw new IllegalArgumentException("尾程事件负载无效",exception); }
|
||||
@@ -168,8 +169,9 @@ public class LoadingCompletedConsumer {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private void validateCartonSkuMappings(FirstLegLoadingPlanCompletedV1 payload) {
|
||||
for (FirstLegLoadingPlanCompletedV1.Order order : payload.orders()) {
|
||||
private void validateCartonSkuMappings(FirstLegLoadingPlanCompletedV1 payload, JsonNode rawPayload) {
|
||||
for (int index = 0; index < payload.orders().size(); index++) {
|
||||
FirstLegLoadingPlanCompletedV1.Order order = payload.orders().get(index);
|
||||
Set<String> orderCartonMarks = new HashSet<>();
|
||||
if ("ONE_CLICK_DROPSHIP".equals(order.orderType())) {
|
||||
for (FirstLegLoadingPlanCompletedV1.PalletSnapshot pallet : order.pallets()) {
|
||||
@@ -177,6 +179,7 @@ public class LoadingCompletedConsumer {
|
||||
requireSkuCartonMapping(sku.skuCode(), sku.packageCount(), sku.cartonMarks(), orderCartonMarks);
|
||||
}
|
||||
}
|
||||
dropshipReceivingLabels(order, rawPayload.path("orders").get(index));
|
||||
continue;
|
||||
}
|
||||
String destinationType = destinationType(payload, order);
|
||||
@@ -273,6 +276,8 @@ public class LoadingCompletedConsumer {
|
||||
}
|
||||
createInboundOrderSnapshot(event, payload, source, order, orderHash);
|
||||
|
||||
Map<String, List<String>> dropshipLabels = "ONE_CLICK_DROPSHIP".equals(orderType)
|
||||
&& "OVERSEAS".equals(destinationType) ? dropshipReceivingLabels(source, rawSource) : Map.of();
|
||||
for(var item:source.items()) {
|
||||
LastlegOrderDetail detail=new LastlegOrderDetail();
|
||||
detail.setCustomerId(customerId);
|
||||
@@ -283,7 +288,9 @@ public class LoadingCompletedConsumer {
|
||||
detail.setDestinationWarehouseId(item.destinationWarehouseId()); detail.setDestinationWarehouseCode(item.destinationWarehouseCode());
|
||||
detail.setDestinationWarehouseName(item.destinationWarehouseName()); detail.setFbaTrackingNo(item.fbaTrackingNo());
|
||||
detail.setShipmentNo(item.shipmentNo()); detail.setShippingMark(item.shippingMark()); detailMapper.insert(detail);
|
||||
createCartonLabels(customerId, order.getId(), destinationType, item);
|
||||
createCartonLabels(customerId, order.getId(), destinationType, item,
|
||||
"ONE_CLICK_DROPSHIP".equals(orderType) ? dropshipLabels.getOrDefault(item.sourceInboundDetailId(), List.of())
|
||||
: item.cartonMarks());
|
||||
}
|
||||
LastlegOrderStatusHistory history=new LastlegOrderStatusHistory(); history.setCustomerId(customerId);
|
||||
history.setOrderId(order.getId()); history.setToStatus("PENDING_ASSIGNMENT"); history.setEventId(event.eventId());
|
||||
@@ -353,10 +360,38 @@ public class LoadingCompletedConsumer {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, List<String>> dropshipReceivingLabels(FirstLegLoadingPlanCompletedV1.Order source, JsonNode rawSource) {
|
||||
Map<String, FirstLegLoadingPlanCompletedV1.Item> itemsByDetail = new java.util.LinkedHashMap<>();
|
||||
for (var item : source.items()) {
|
||||
if (item.sourceInboundDetailId() == null || item.sourceInboundDetailId().isBlank()
|
||||
|| itemsByDetail.putIfAbsent(item.sourceInboundDetailId(), item) != null) {
|
||||
throw new IllegalArgumentException("一件代发来源明细标识缺失或重复");
|
||||
}
|
||||
}
|
||||
Map<String, List<String>> marksByDetail = new java.util.LinkedHashMap<>();
|
||||
for (JsonNode pallet : rawSource.path("pallets")) {
|
||||
for (JsonNode sku : pallet.path("skuPackages")) {
|
||||
String detailId = sku.path("sourceInboundDetailId").asText(null);
|
||||
var item = itemsByDetail.get(detailId);
|
||||
if (item == null || !Objects.equals(item.skuCode(), sku.path("skuCode").asText(null))) {
|
||||
throw new IllegalArgumentException("一件代发托盘来源明细缺失或与 SKU 不一致");
|
||||
}
|
||||
List<String> marks = marksByDetail.computeIfAbsent(detailId, ignored -> new java.util.ArrayList<>());
|
||||
sku.path("cartonMarks").forEach(mark -> marks.add(mark.asText()));
|
||||
}
|
||||
}
|
||||
for (var item : source.items()) {
|
||||
if (marksByDetail.getOrDefault(item.sourceInboundDetailId(), List.of()).size() != item.packageCount()) {
|
||||
throw new IllegalArgumentException("一件代发托盘箱唛与来源明细箱数不一致");
|
||||
}
|
||||
}
|
||||
return marksByDetail;
|
||||
}
|
||||
|
||||
private void createCartonLabels(String customerId, Long orderId, String destinationType,
|
||||
FirstLegLoadingPlanCompletedV1.Item item) {
|
||||
FirstLegLoadingPlanCompletedV1.Item item, List<String> sourceMarks) {
|
||||
if (!"OVERSEAS".equals(destinationType)) return;
|
||||
List<String> marks = item.cartonMarks() == null ? List.of() : item.cartonMarks();
|
||||
List<String> marks = sourceMarks == null ? List.of() : sourceMarks;
|
||||
if (marks.isEmpty()) return;
|
||||
if (marks.stream().anyMatch(mark -> mark == null || mark.isBlank()) || marks.stream().distinct().count() != marks.size()) {
|
||||
throw new IllegalArgumentException("装柜事件的箱唛池不可包含空值或重复箱唛");
|
||||
@@ -409,10 +444,19 @@ public class LoadingCompletedConsumer {
|
||||
|
||||
private List<DropshipRequests.Pallet> pallets(FirstLegLoadingPlanCompletedV1.Order source, JsonNode rawSource) {
|
||||
if (source.pallets() != null && !source.pallets().isEmpty()) {
|
||||
return source.pallets().stream().map(pallet -> new DropshipRequests.Pallet(pallet.palletNo(),
|
||||
pallet.skuPackages().stream().map(sku -> new DropshipRequests.SkuPackages(
|
||||
sku.skuCode(), sku.productName(), sku.packageCount(), sku.productQuantity(),
|
||||
sku.cartonMarks())).toList())).toList();
|
||||
return source.pallets().stream().map(pallet -> {
|
||||
Map<String, DropshipRequests.SkuPackages> inventorySkus = new java.util.LinkedHashMap<>();
|
||||
for (var sku : pallet.skuPackages()) {
|
||||
inventorySkus.merge(sku.skuCode(), new DropshipRequests.SkuPackages(sku.skuCode(),
|
||||
sku.productName(), sku.packageCount(), sku.productQuantity(), sku.cartonMarks()), (left, right) -> {
|
||||
List<String> marks = new ArrayList<>(left.cartonMarks()); marks.addAll(right.cartonMarks());
|
||||
return new DropshipRequests.SkuPackages(left.skuCode(), left.productName(),
|
||||
Math.addExact(left.packageCount(), right.packageCount()),
|
||||
Math.addExact(left.productQuantity(), right.productQuantity()), List.copyOf(marks));
|
||||
});
|
||||
}
|
||||
return new DropshipRequests.Pallet(pallet.palletNo(), List.copyOf(inventorySkus.values()));
|
||||
}).toList();
|
||||
}
|
||||
return legacyPallets(rawSource);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user