2026-08-18 16:03:42 +08:00
|
|
|
package com.baiyue.common.event;
|
|
|
|
|
|
2026-08-31 12:13:20 +08:00
|
|
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
2026-08-18 16:03:42 +08:00
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
2026-08-24 11:19:33 +08:00
|
|
|
/** 装柜完成交接快照,包含三类逐货物备注、推荐托数和可复用的头程托盘编号快照。 */
|
2026-08-18 16:03:42 +08:00
|
|
|
public record FirstLegLoadingPlanCompletedV2(
|
2026-08-31 12:13:20 +08:00
|
|
|
String loadingPlanId, String planNo,
|
|
|
|
|
@JsonProperty("sourceContainerBookingId") String containerBookingId,
|
2026-08-18 16:03:42 +08:00
|
|
|
String containerNo, String cabinetNo, String warehouseId, String warehouseName,
|
2026-08-27 16:42:27 +08:00
|
|
|
String estimatedPortArrivalAt, String actualPortArrivalAt, String estimatedWarehouseArrivalAt,
|
2026-08-18 16:03:42 +08:00
|
|
|
List<Order> orders) {
|
2026-08-31 12:13:20 +08:00
|
|
|
public FirstLegLoadingPlanCompletedV2 {
|
|
|
|
|
if (loadingPlanId == null || loadingPlanId.isBlank()
|
|
|
|
|
|| containerBookingId == null || containerBookingId.isBlank()) {
|
|
|
|
|
throw new IllegalArgumentException("loadingPlanId and sourceContainerBookingId are required");
|
|
|
|
|
}
|
|
|
|
|
containerNo = ContainerNumbers.requireCanonical(containerNo);
|
|
|
|
|
orders = orders == null ? List.of() : List.copyOf(orders);
|
|
|
|
|
if (orders.isEmpty()) throw new IllegalArgumentException("orders are required");
|
2026-09-01 11:06:26 +08:00
|
|
|
Order owner = orders.get(0);
|
|
|
|
|
if (orders.stream().anyMatch(order -> !owner.customerId().equals(order.customerId())
|
|
|
|
|
|| !owner.customerName().equals(order.customerName()))) {
|
|
|
|
|
throw new IllegalArgumentException("orders must share one immutable customerId/customerName snapshot");
|
|
|
|
|
}
|
2026-08-31 12:13:20 +08:00
|
|
|
}
|
|
|
|
|
|
2026-08-27 16:42:27 +08:00
|
|
|
public FirstLegLoadingPlanCompletedV2(String loadingPlanId, String planNo, String containerBookingId,
|
|
|
|
|
String containerNo, String cabinetNo, String warehouseId,
|
|
|
|
|
String warehouseName, List<Order> orders) {
|
|
|
|
|
this(loadingPlanId, planNo, containerBookingId, containerNo, cabinetNo, warehouseId,
|
|
|
|
|
warehouseName, null, null, null, orders);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-19 14:02:11 +08:00
|
|
|
public record Order(
|
|
|
|
|
String sourceInboundId, String rootInboundId,
|
|
|
|
|
String sourceOrderId, String sourceOrderNo, String rootOrderId,
|
|
|
|
|
String inboundCode, String destinationWarehouseId,
|
|
|
|
|
String destinationWarehouseCode, String destinationWarehouseName,
|
|
|
|
|
int packageCount, Integer productQuantity, Integer palletCount,
|
|
|
|
|
BigDecimal grossWeightKg, BigDecimal netWeightKg, BigDecimal volumeCbm,
|
2026-08-27 16:42:27 +08:00
|
|
|
BigDecimal volumeWeightKg,
|
2026-08-27 15:56:14 +08:00
|
|
|
List<Item> items, String customerId, String customerName, String orderType, List<PalletSnapshot> pallets,
|
2026-08-24 17:15:48 +08:00
|
|
|
/** 目的类型:FBA 可按箱数收货,OVERSEAS 必须逐箱扫码。 */
|
2026-09-06 16:02:11 +08:00
|
|
|
String destinationType, String lxCode) {
|
2026-08-19 14:02:11 +08:00
|
|
|
public Order {
|
|
|
|
|
items = items == null ? List.of() : items;
|
2026-08-27 15:56:14 +08:00
|
|
|
if (customerId == null || customerId.isBlank()) {
|
|
|
|
|
throw new IllegalArgumentException("customerId is required");
|
|
|
|
|
}
|
|
|
|
|
if (customerName == null || customerName.isBlank()) {
|
|
|
|
|
throw new IllegalArgumentException("customerName is required");
|
|
|
|
|
}
|
2026-09-01 11:06:26 +08:00
|
|
|
customerId = customerId.trim();
|
|
|
|
|
customerName = customerName.trim();
|
|
|
|
|
if (customerId.length() > 128 || customerName.length() > 128) {
|
|
|
|
|
throw new IllegalArgumentException("customerId/customerName snapshot is too long");
|
|
|
|
|
}
|
2026-08-19 14:02:11 +08:00
|
|
|
orderType = orderType == null || orderType.isBlank() ? "FIRST_LEG" : orderType;
|
|
|
|
|
pallets = pallets == null ? List.of() : pallets;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-24 17:15:48 +08:00
|
|
|
public Order(String sourceInboundId, String rootInboundId,
|
|
|
|
|
String sourceOrderId, String sourceOrderNo, String rootOrderId,
|
|
|
|
|
String inboundCode, String destinationWarehouseId,
|
|
|
|
|
String destinationWarehouseCode, String destinationWarehouseName,
|
|
|
|
|
int packageCount, Integer productQuantity, Integer palletCount,
|
|
|
|
|
BigDecimal grossWeightKg, BigDecimal netWeightKg, BigDecimal volumeCbm,
|
2026-08-27 15:56:14 +08:00
|
|
|
List<Item> items, String customerId, String customerName,
|
|
|
|
|
String orderType, List<PalletSnapshot> pallets) {
|
2026-08-24 17:15:48 +08:00
|
|
|
this(sourceInboundId, rootInboundId, sourceOrderId, sourceOrderNo, rootOrderId,
|
|
|
|
|
inboundCode, destinationWarehouseId, destinationWarehouseCode,
|
|
|
|
|
destinationWarehouseName, packageCount, productQuantity, palletCount,
|
2026-08-27 16:42:27 +08:00
|
|
|
grossWeightKg, netWeightKg, volumeCbm, null, items, customerId, customerName,
|
2026-09-06 16:02:11 +08:00
|
|
|
orderType, pallets, null, null);
|
2026-08-19 14:02:11 +08:00
|
|
|
}
|
2026-08-27 16:42:27 +08:00
|
|
|
|
|
|
|
|
public Order(String sourceInboundId, String rootInboundId,
|
|
|
|
|
String sourceOrderId, String sourceOrderNo, String rootOrderId,
|
|
|
|
|
String inboundCode, String destinationWarehouseId,
|
|
|
|
|
String destinationWarehouseCode, String destinationWarehouseName,
|
|
|
|
|
int packageCount, Integer productQuantity, Integer palletCount,
|
|
|
|
|
BigDecimal grossWeightKg, BigDecimal netWeightKg, BigDecimal volumeCbm,
|
|
|
|
|
List<Item> items, String customerId, String customerName,
|
|
|
|
|
String orderType, List<PalletSnapshot> pallets, String destinationType) {
|
|
|
|
|
this(sourceInboundId, rootInboundId, sourceOrderId, sourceOrderNo, rootOrderId,
|
|
|
|
|
inboundCode, destinationWarehouseId, destinationWarehouseCode,
|
|
|
|
|
destinationWarehouseName, packageCount, productQuantity, palletCount,
|
|
|
|
|
grossWeightKg, netWeightKg, volumeCbm, null, items, customerId, customerName,
|
2026-09-06 16:02:11 +08:00
|
|
|
orderType, pallets, destinationType, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Order(String sourceInboundId, String rootInboundId,
|
|
|
|
|
String sourceOrderId, String sourceOrderNo, String rootOrderId,
|
|
|
|
|
String inboundCode, String destinationWarehouseId,
|
|
|
|
|
String destinationWarehouseCode, String destinationWarehouseName,
|
|
|
|
|
int packageCount, Integer productQuantity, Integer palletCount,
|
|
|
|
|
BigDecimal grossWeightKg, BigDecimal netWeightKg, BigDecimal volumeCbm,
|
|
|
|
|
BigDecimal volumeWeightKg, List<Item> items, String customerId, String customerName,
|
|
|
|
|
String orderType, List<PalletSnapshot> pallets, String destinationType) {
|
|
|
|
|
this(sourceInboundId, rootInboundId, sourceOrderId, sourceOrderNo, rootOrderId,
|
|
|
|
|
inboundCode, destinationWarehouseId, destinationWarehouseCode, destinationWarehouseName,
|
|
|
|
|
packageCount, productQuantity, palletCount, grossWeightKg, netWeightKg, volumeCbm,
|
|
|
|
|
volumeWeightKg, items, customerId, customerName, orderType, pallets, destinationType, null);
|
2026-08-27 16:42:27 +08:00
|
|
|
}
|
2026-08-19 14:02:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public record Item(
|
|
|
|
|
String sourceInboundDetailId, String skuCode,
|
|
|
|
|
String productNameZh, String productNameEn,
|
|
|
|
|
int packageCount, Integer productQuantity, Integer palletCount,
|
|
|
|
|
BigDecimal grossWeightKg, BigDecimal netWeightKg,
|
|
|
|
|
BigDecimal dimensionalWeightKg, BigDecimal volumeCbm,
|
|
|
|
|
String destinationWarehouseId, String destinationWarehouseCode,
|
|
|
|
|
String destinationWarehouseName, String fbaTrackingNo,
|
|
|
|
|
String shipmentNo, String shippingMark,
|
|
|
|
|
String customerRemark, String internalRemark, String warehouseRemark,
|
2026-08-20 16:45:47 +08:00
|
|
|
String palletNo,
|
2026-08-22 10:16:45 +08:00
|
|
|
/** 按实装箱数稳定随机冻结的头程箱号;数量与 packageCount 相等且均对应本明细 SKU。 */
|
2026-08-20 16:45:47 +08:00
|
|
|
List<String> cartonMarks) {
|
2026-08-19 14:02:11 +08:00
|
|
|
public Item {
|
|
|
|
|
cartonMarks = cartonMarks == null ? List.of() : cartonMarks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Item(String sourceInboundDetailId, String skuCode,
|
|
|
|
|
String productNameZh, String productNameEn,
|
|
|
|
|
int packageCount, Integer productQuantity, Integer palletCount,
|
|
|
|
|
BigDecimal grossWeightKg, BigDecimal netWeightKg,
|
|
|
|
|
BigDecimal dimensionalWeightKg, BigDecimal volumeCbm,
|
|
|
|
|
String destinationWarehouseId, String destinationWarehouseCode,
|
|
|
|
|
String destinationWarehouseName, String fbaTrackingNo,
|
|
|
|
|
String shipmentNo, String shippingMark,
|
|
|
|
|
String customerRemark, String internalRemark, String warehouseRemark) {
|
|
|
|
|
this(sourceInboundDetailId, skuCode, productNameZh, productNameEn, packageCount,
|
|
|
|
|
productQuantity, palletCount, grossWeightKg, netWeightKg,
|
|
|
|
|
dimensionalWeightKg, volumeCbm, destinationWarehouseId,
|
|
|
|
|
destinationWarehouseCode, destinationWarehouseName, fbaTrackingNo,
|
|
|
|
|
shipmentNo, shippingMark, customerRemark, internalRemark, warehouseRemark,
|
|
|
|
|
null, List.of());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-10 22:43:11 +08:00
|
|
|
/** 普通 FBA 只复用 palletNo;一件代发还携带同一物理 DP 的完整清单摘要。 */
|
|
|
|
|
public record PalletSnapshot(String palletNo, List<SkuPackageSnapshot> skuPackages,
|
|
|
|
|
Integer manifestVersion, Integer manifestPackageCount,
|
|
|
|
|
Integer manifestFragmentCount, String manifestHash) {
|
|
|
|
|
public PalletSnapshot {
|
|
|
|
|
skuPackages = skuPackages == null ? List.of() : List.copyOf(skuPackages);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public PalletSnapshot(String palletNo, List<SkuPackageSnapshot> skuPackages) {
|
|
|
|
|
this(palletNo, skuPackages, null, null, null, null);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-19 14:02:11 +08:00
|
|
|
|
2026-09-09 13:20:11 +08:00
|
|
|
/** 托盘下来源入库明细、SKU、箱数、数量及箱号冻结快照;同 SKU 多明细按 sourceInboundDetailId 精确区分。 */
|
|
|
|
|
public record SkuPackageSnapshot(String sourceInboundDetailId, String skuCode, String productName,
|
2026-08-19 14:02:11 +08:00
|
|
|
int packageCount, int productQuantity,
|
2026-09-09 13:20:11 +08:00
|
|
|
List<String> cartonMarks) {
|
|
|
|
|
public SkuPackageSnapshot {
|
|
|
|
|
if (sourceInboundDetailId == null || sourceInboundDetailId.isBlank()) {
|
|
|
|
|
throw new IllegalArgumentException("sourceInboundDetailId is required for each pallet SKU snapshot");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-18 16:03:42 +08:00
|
|
|
}
|