暂存提交
This commit is contained in:
+44
-2
@@ -16,7 +16,24 @@ public record FirstLegLoadingPlanCompletedV1(
|
|||||||
String destinationWarehouseCode, String destinationWarehouseName,
|
String destinationWarehouseCode, String destinationWarehouseName,
|
||||||
int packageCount, Integer productQuantity, Integer palletCount,
|
int packageCount, Integer productQuantity, Integer palletCount,
|
||||||
BigDecimal grossWeightKg, BigDecimal netWeightKg, BigDecimal volumeCbm,
|
BigDecimal grossWeightKg, BigDecimal netWeightKg, BigDecimal volumeCbm,
|
||||||
List<Item> items) {
|
List<Item> items, String customerId, String orderType, List<PalletSnapshot> pallets) {
|
||||||
|
public Order {
|
||||||
|
items = items == null ? List.of() : items;
|
||||||
|
orderType = orderType == null || orderType.isBlank() ? "FIRST_LEG" : orderType;
|
||||||
|
pallets = pallets == null ? List.of() : pallets;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
this(sourceInboundId, rootInboundId, sourceOrderId, sourceOrderNo, rootOrderId,
|
||||||
|
inboundCode, destinationWarehouseId, destinationWarehouseCode,
|
||||||
|
destinationWarehouseName, packageCount, productQuantity, palletCount,
|
||||||
|
grossWeightKg, netWeightKg, volumeCbm, items, null, "FIRST_LEG", List.of());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Item(
|
public record Item(
|
||||||
@@ -27,6 +44,31 @@ public record FirstLegLoadingPlanCompletedV1(
|
|||||||
BigDecimal dimensionalWeightKg, BigDecimal volumeCbm,
|
BigDecimal dimensionalWeightKg, BigDecimal volumeCbm,
|
||||||
String destinationWarehouseId, String destinationWarehouseCode,
|
String destinationWarehouseId, String destinationWarehouseCode,
|
||||||
String destinationWarehouseName, String fbaTrackingNo,
|
String destinationWarehouseName, String fbaTrackingNo,
|
||||||
String shipmentNo, String shippingMark) {
|
String shipmentNo, String shippingMark, String palletNo, List<String> cartonMarks) {
|
||||||
|
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) {
|
||||||
|
this(sourceInboundDetailId, skuCode, productNameZh, productNameEn, packageCount,
|
||||||
|
productQuantity, palletCount, grossWeightKg, netWeightKg,
|
||||||
|
dimensionalWeightKg, volumeCbm, destinationWarehouseId,
|
||||||
|
destinationWarehouseCode, destinationWarehouseName, fbaTrackingNo,
|
||||||
|
shipmentNo, shippingMark, null, List.of());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 一键代发入仓单的托盘冻结快照。 */
|
||||||
|
public record PalletSnapshot(String palletNo, List<SkuPackageSnapshot> skuPackages) {}
|
||||||
|
|
||||||
|
/** 托盘下 SKU、箱数、数量及箱唛冻结快照。 */
|
||||||
|
public record SkuPackageSnapshot(String skuCode, String productName,
|
||||||
|
int packageCount, int productQuantity,
|
||||||
|
List<String> cartonMarks) {}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
@@ -26,4 +26,25 @@ class FirstLegLoadingPlanCompletedV1Test {
|
|||||||
assertThat(mapper.readValue(json, FirstLegLoadingPlanCompletedV1.class)).isEqualTo(payload);
|
assertThat(mapper.readValue(json, FirstLegLoadingPlanCompletedV1.class)).isEqualTo(payload);
|
||||||
assertThat(json).contains("2088000000000000003", "sourceInboundDetailId");
|
assertThat(json).contains("2088000000000000003", "sourceInboundDetailId");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void dropshipPayloadKeepsMultiplePalletsAndCartonMarks() throws Exception {
|
||||||
|
var sku1 = new FirstLegLoadingPlanCompletedV1.SkuPackageSnapshot(
|
||||||
|
"SKU-1", "产品1", 2, 20, List.of("BOX-001", "BOX-002"));
|
||||||
|
var sku2 = new FirstLegLoadingPlanCompletedV1.SkuPackageSnapshot(
|
||||||
|
"SKU-2", "产品2", 1, 5, List.of("BOX-003"));
|
||||||
|
var order = new FirstLegLoadingPlanCompletedV1.Order("100", "100", "200", "FL-200", "200",
|
||||||
|
"RK-100", "300", "ONT8", "ONT8", 3, 25, 2, BigDecimal.ONE,
|
||||||
|
BigDecimal.ONE, BigDecimal.ONE, List.of(), "9001", "ONE_CLICK_DROPSHIP",
|
||||||
|
List.of(new FirstLegLoadingPlanCompletedV1.PalletSnapshot("PLT-01", List.of(sku1)),
|
||||||
|
new FirstLegLoadingPlanCompletedV1.PalletSnapshot("PLT-02", List.of(sku2))));
|
||||||
|
var payload = new FirstLegLoadingPlanCompletedV1("1", "LP-1", "2", "CONT-1", null,
|
||||||
|
"3", "海外仓", List.of(order));
|
||||||
|
|
||||||
|
String json = mapper.writeValueAsString(payload);
|
||||||
|
FirstLegLoadingPlanCompletedV1 restored = mapper.readValue(json, FirstLegLoadingPlanCompletedV1.class);
|
||||||
|
|
||||||
|
assertThat(restored).isEqualTo(payload);
|
||||||
|
assertThat(json).contains("ONE_CLICK_DROPSHIP", "PLT-01", "BOX-003", "customerId");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public interface LoadingCompletedEventMapper {
|
|||||||
COALESCE(o.root_inbound_id, o.id) AS root_inbound_id,
|
COALESCE(o.root_inbound_id, o.id) AS root_inbound_id,
|
||||||
o.order_id AS source_order_id, o.order_no AS source_order_no,
|
o.order_id AS source_order_id, o.order_no AS source_order_no,
|
||||||
COALESCE(root_order.order_id, o.order_id) AS root_order_id,
|
COALESCE(root_order.order_id, o.order_id) AS root_order_id,
|
||||||
o.inbound_code, o.destination_warehouse_id, o.destination_code AS destination_warehouse_code,
|
o.inbound_code, o.business_type, o.destination_warehouse_id, o.destination_code AS destination_warehouse_code,
|
||||||
o.destination_name AS destination_warehouse_name,
|
o.destination_name AS destination_warehouse_name,
|
||||||
i.inbound_detail_id AS source_inbound_detail_id, i.sku_code,
|
i.inbound_detail_id AS source_inbound_detail_id, i.sku_code,
|
||||||
i.product_name_zh, i.product_name_en, i.package_count, i.product_quantity,
|
i.product_name_zh, i.product_name_en, i.package_count, i.product_quantity,
|
||||||
@@ -36,6 +36,27 @@ public interface LoadingCompletedEventMapper {
|
|||||||
""")
|
""")
|
||||||
List<Row> rows(@Param("planId") long planId);
|
List<Row> rows(@Param("planId") long planId);
|
||||||
|
|
||||||
|
/** 读取一键代发托盘及其箱唛快照;普通订单不会使用该结果。 */
|
||||||
|
@Select("""
|
||||||
|
SELECT i.account_id, i.inbound_id AS source_inbound_id,
|
||||||
|
a.pallet_code, a.allocation_no, a.picked_package_count AS allocated_package_count,
|
||||||
|
i.inbound_detail_id AS source_inbound_detail_id, i.sku_code,
|
||||||
|
i.product_name_zh, i.package_count, i.product_quantity,
|
||||||
|
label.box_code
|
||||||
|
FROM fl_loading_plan_item i
|
||||||
|
JOIN fl_inbound_pallet_allocation a
|
||||||
|
ON a.tenant_id = i.account_id AND a.inbound_id = i.inbound_id
|
||||||
|
AND a.allocation_status IN ('CONFIRMED','TRANSFERRED','RELEASED')
|
||||||
|
AND a.picked_package_count > 0
|
||||||
|
LEFT JOIN fl_inbound_carton_label label
|
||||||
|
ON label.tenant_id = i.account_id AND label.inbound_id = i.inbound_id
|
||||||
|
AND label.inbound_detail_id = i.inbound_detail_id AND label.batch_status = 'ACTIVE'
|
||||||
|
WHERE i.loading_plan_id = #{planId} AND i.deleted = 0
|
||||||
|
ORDER BY i.account_id, i.inbound_id, a.allocation_no,
|
||||||
|
i.inbound_detail_id, label.carton_index, label.id
|
||||||
|
""")
|
||||||
|
List<PalletRow> palletRows(@Param("planId") long planId);
|
||||||
|
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
class Row {
|
class Row {
|
||||||
private Long loadingPlanId; private String planNo; private Long containerBookingId;
|
private Long loadingPlanId; private String planNo; private Long containerBookingId;
|
||||||
@@ -49,5 +70,14 @@ public interface LoadingCompletedEventMapper {
|
|||||||
private Integer productQuantity; private Integer palletCount; private BigDecimal grossWeightKg;
|
private Integer productQuantity; private Integer palletCount; private BigDecimal grossWeightKg;
|
||||||
private BigDecimal netWeightKg; private BigDecimal dimensionalWeightKg; private BigDecimal volumeCbm;
|
private BigDecimal netWeightKg; private BigDecimal dimensionalWeightKg; private BigDecimal volumeCbm;
|
||||||
private String fbaTrackingNo; private String shipmentNo; private String shippingMark;
|
private String fbaTrackingNo; private String shipmentNo; private String shippingMark;
|
||||||
|
private String businessType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter @Setter
|
||||||
|
class PalletRow {
|
||||||
|
private Long accountId; private Long sourceInboundId; private String palletCode;
|
||||||
|
private Integer allocationNo; private Integer allocatedPackageCount;
|
||||||
|
private Long sourceInboundDetailId; private String skuCode; private String productNameZh;
|
||||||
|
private Integer packageCount; private Integer productQuantity; private String boxCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+78
-6
@@ -14,6 +14,7 @@ import com.baiyue.firstleg.entity.InboundOutboxEntity;
|
|||||||
import com.baiyue.firstleg.mapper.InboundOutboxMapper;
|
import com.baiyue.firstleg.mapper.InboundOutboxMapper;
|
||||||
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper;
|
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper;
|
||||||
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper.Row;
|
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper.Row;
|
||||||
|
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper.PalletRow;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
@@ -29,6 +30,7 @@ import java.util.Comparator;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/** 在装柜完成事务内按客户写跨区业务 Outbox。 */
|
/** 在装柜完成事务内按客户写跨区业务 Outbox。 */
|
||||||
@Service
|
@Service
|
||||||
@@ -41,17 +43,20 @@ public class LoadingCompletedOutboxService {
|
|||||||
public void publish(long planId) {
|
public void publish(long planId) {
|
||||||
List<Row> rows = snapshotMapper.rows(planId);
|
List<Row> rows = snapshotMapper.rows(planId);
|
||||||
if (rows.isEmpty()) throw new BizException(ResultCode.CONFLICT, "装柜计划没有最终实装入仓单,不能生成尾程交接事件");
|
if (rows.isEmpty()) throw new BizException(ResultCode.CONFLICT, "装柜计划没有最终实装入仓单,不能生成尾程交接事件");
|
||||||
|
List<PalletRow> palletRows = snapshotMapper.palletRows(planId);
|
||||||
rows.stream().collect(java.util.stream.Collectors.groupingBy(Row::getAccountId,
|
rows.stream().collect(java.util.stream.Collectors.groupingBy(Row::getAccountId,
|
||||||
java.util.TreeMap::new, java.util.stream.Collectors.toList()))
|
java.util.TreeMap::new, java.util.stream.Collectors.toList()))
|
||||||
.forEach((accountId, accountRows) -> insert(envelope(accountId, accountRows)));
|
.forEach((accountId, accountRows) -> insert(envelope(accountId, accountRows,
|
||||||
|
palletRows.stream().filter(item -> accountId.equals(item.getAccountId())).toList())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private EventEnvelope envelope(long accountId, List<Row> rows) {
|
private EventEnvelope envelope(long accountId, List<Row> rows, List<PalletRow> palletRows) {
|
||||||
Row first = rows.get(0);
|
Row first = rows.get(0);
|
||||||
Map<Long, List<Row>> byInbound = rows.stream().collect(java.util.stream.Collectors.groupingBy(
|
Map<Long, List<Row>> byInbound = rows.stream().collect(java.util.stream.Collectors.groupingBy(
|
||||||
Row::getSourceInboundId, java.util.TreeMap::new, java.util.stream.Collectors.toList()));
|
Row::getSourceInboundId, java.util.TreeMap::new, java.util.stream.Collectors.toList()));
|
||||||
List<FirstLegLoadingPlanCompletedV1.Order> orders = byInbound.values().stream()
|
List<FirstLegLoadingPlanCompletedV1.Order> orders = byInbound.values().stream()
|
||||||
.map(this::order).toList();
|
.map(value -> order(value, palletRows.stream()
|
||||||
|
.filter(item -> Objects.equals(item.getSourceInboundId(), value.get(0).getSourceInboundId())).toList())).toList();
|
||||||
var payload = new FirstLegLoadingPlanCompletedV1(String.valueOf(first.getLoadingPlanId()),
|
var payload = new FirstLegLoadingPlanCompletedV1(String.valueOf(first.getLoadingPlanId()),
|
||||||
first.getPlanNo(), string(first.getContainerBookingId()), first.getContainerNo(), first.getCabinetNo(),
|
first.getPlanNo(), string(first.getContainerBookingId()), first.getContainerNo(), first.getCabinetNo(),
|
||||||
string(first.getWarehouseId()), first.getWarehouseName(), orders);
|
string(first.getWarehouseId()), first.getWarehouseName(), orders);
|
||||||
@@ -65,7 +70,7 @@ public class LoadingCompletedOutboxService {
|
|||||||
traceId, eventKey, null, payloadNode, hash).requireValid();
|
traceId, eventKey, null, payloadNode, hash).requireValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
private FirstLegLoadingPlanCompletedV1.Order order(List<Row> values) {
|
private FirstLegLoadingPlanCompletedV1.Order order(List<Row> values, List<PalletRow> palletRows) {
|
||||||
List<Row> sorted = values.stream().sorted(Comparator.comparing(Row::getSourceInboundDetailId)).toList();
|
List<Row> sorted = values.stream().sorted(Comparator.comparing(Row::getSourceInboundDetailId)).toList();
|
||||||
Row first = sorted.get(0);
|
Row first = sorted.get(0);
|
||||||
List<FirstLegLoadingPlanCompletedV1.Item> items = sorted.stream().map(row ->
|
List<FirstLegLoadingPlanCompletedV1.Item> items = sorted.stream().map(row ->
|
||||||
@@ -75,14 +80,81 @@ public class LoadingCompletedOutboxService {
|
|||||||
row.getVolumeCbm(), string(row.getDestinationWarehouseId()), row.getDestinationWarehouseCode(),
|
row.getVolumeCbm(), string(row.getDestinationWarehouseId()), row.getDestinationWarehouseCode(),
|
||||||
row.getDestinationWarehouseName(), row.getFbaTrackingNo(), row.getShipmentNo(), row.getShippingMark()))
|
row.getDestinationWarehouseName(), row.getFbaTrackingNo(), row.getShipmentNo(), row.getShippingMark()))
|
||||||
.toList();
|
.toList();
|
||||||
|
String orderType = dropship(first.getBusinessType()) ? "ONE_CLICK_DROPSHIP" : "FIRST_LEG";
|
||||||
|
List<FirstLegLoadingPlanCompletedV1.PalletSnapshot> pallets = dropship(first.getBusinessType())
|
||||||
|
? palletSnapshots(sorted, palletRows) : List.of();
|
||||||
|
if ("ONE_CLICK_DROPSHIP".equals(orderType) && pallets.isEmpty()) {
|
||||||
|
throw new BizException(ResultCode.CONFLICT, "一键代发入仓单缺少托盘冻结快照");
|
||||||
|
}
|
||||||
return new FirstLegLoadingPlanCompletedV1.Order(string(first.getSourceInboundId()),
|
return new FirstLegLoadingPlanCompletedV1.Order(string(first.getSourceInboundId()),
|
||||||
string(first.getRootInboundId()), string(first.getSourceOrderId()), first.getSourceOrderNo(),
|
string(first.getRootInboundId()), string(first.getSourceOrderId()), first.getSourceOrderNo(),
|
||||||
string(first.getRootOrderId()), first.getInboundCode(), string(first.getDestinationWarehouseId()),
|
string(first.getRootOrderId()), first.getInboundCode(), string(first.getDestinationWarehouseId()),
|
||||||
first.getDestinationWarehouseCode(), first.getDestinationWarehouseName(), sumInt(sorted, Row::getPackageCount),
|
first.getDestinationWarehouseCode(), first.getDestinationWarehouseName(), sumInt(sorted, Row::getPackageCount),
|
||||||
sumNullableInt(sorted, Row::getProductQuantity), sumNullableInt(sorted, Row::getPalletCount),
|
sumNullableInt(sorted, Row::getProductQuantity), "ONE_CLICK_DROPSHIP".equals(orderType)
|
||||||
sum(sorted, Row::getGrossWeightKg), sum(sorted, Row::getNetWeightKg), sum(sorted, Row::getVolumeCbm), items);
|
? pallets.size() : 0, sum(sorted, Row::getGrossWeightKg), sum(sorted, Row::getNetWeightKg),
|
||||||
|
sum(sorted, Row::getVolumeCbm), items, string(first.getAccountId()), orderType, pallets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<FirstLegLoadingPlanCompletedV1.PalletSnapshot> palletSnapshots(List<Row> values, List<PalletRow> source) {
|
||||||
|
if (source.isEmpty()) return List.of();
|
||||||
|
Map<String, List<PalletRow>> byPallet = source.stream().collect(java.util.stream.Collectors.groupingBy(
|
||||||
|
p -> (p.getAllocationNo() == null ? "" : p.getAllocationNo()) + "|" + p.getPalletCode(),
|
||||||
|
LinkedHashMap::new, java.util.stream.Collectors.toList()));
|
||||||
|
int loadedPackages = byPallet.values().stream().map(list -> list.get(0)).map(PalletRow::getAllocatedPackageCount)
|
||||||
|
.filter(Objects::nonNull).mapToInt(Integer::intValue).sum();
|
||||||
|
if (loadedPackages != sumInt(values, Row::getPackageCount)) {
|
||||||
|
throw new BizException(ResultCode.CONFLICT, "一键代发实装箱数与托盘已拣箱数不一致");
|
||||||
|
}
|
||||||
|
Map<Long, DetailSnapshot> details = new LinkedHashMap<>();
|
||||||
|
values.stream().sorted(Comparator.comparing(Row::getSourceInboundDetailId)).forEach(row ->
|
||||||
|
details.putIfAbsent(row.getSourceInboundDetailId(), new DetailSnapshot(row.getSourceInboundDetailId(),
|
||||||
|
row.getSkuCode(), row.getProductNameZh(), row.getPackageCount(), row.getProductQuantity(), new ArrayList<>())));
|
||||||
|
source.stream().filter(item -> item.getBoxCode() != null).forEach(item -> {
|
||||||
|
DetailSnapshot detail = details.get(item.getSourceInboundDetailId());
|
||||||
|
if (detail != null && !detail.marks().contains(item.getBoxCode())) detail.marks().add(item.getBoxCode());
|
||||||
|
});
|
||||||
|
Map<Long, Integer> remainingPackages = details.values().stream().collect(java.util.stream.Collectors.toMap(
|
||||||
|
DetailSnapshot::detailId, DetailSnapshot::packageCount, (a,b)->a, LinkedHashMap::new));
|
||||||
|
Map<Long, Integer> remainingMarks = details.values().stream().collect(java.util.stream.Collectors.toMap(
|
||||||
|
DetailSnapshot::detailId, ignored -> 0, (a,b)->a, LinkedHashMap::new));
|
||||||
|
List<FirstLegLoadingPlanCompletedV1.PalletSnapshot> result = new ArrayList<>();
|
||||||
|
for (List<PalletRow> palletRows : byPallet.values()) {
|
||||||
|
PalletRow first = palletRows.get(0);
|
||||||
|
int capacity = first.getAllocatedPackageCount() == null ? 0 : first.getAllocatedPackageCount();
|
||||||
|
List<FirstLegLoadingPlanCompletedV1.SkuPackageSnapshot> sku = new ArrayList<>();
|
||||||
|
for (DetailSnapshot detail : details.values()) {
|
||||||
|
int remaining = remainingPackages.getOrDefault(detail.detailId(), 0);
|
||||||
|
if (capacity <= 0 || remaining <= 0) continue;
|
||||||
|
int count = Math.min(capacity, remaining);
|
||||||
|
int totalQuantity = detail.productQuantity() == null ? count
|
||||||
|
: (int) Math.round((double) detail.productQuantity() * count / Math.max(1, detail.packageCount()));
|
||||||
|
int markStart = remainingMarks.getOrDefault(detail.detailId(), 0);
|
||||||
|
int markEnd = Math.min(detail.marks().size(), markStart + count);
|
||||||
|
List<String> marks = new ArrayList<>(detail.marks().subList(markStart, markEnd));
|
||||||
|
if (marks.size() != count) throw new BizException(ResultCode.CONFLICT, "一键代发箱唛数量与托盘箱数不一致");
|
||||||
|
sku.add(new FirstLegLoadingPlanCompletedV1.SkuPackageSnapshot(detail.skuCode(),
|
||||||
|
detail.productName(), count, totalQuantity, marks));
|
||||||
|
remainingPackages.put(detail.detailId(), remaining - count);
|
||||||
|
remainingMarks.put(detail.detailId(), markEnd);
|
||||||
|
capacity -= count;
|
||||||
|
}
|
||||||
|
if (!sku.isEmpty()) result.add(new FirstLegLoadingPlanCompletedV1.PalletSnapshot(
|
||||||
|
first.getPalletCode() == null ? "PALLET-" + first.getAllocationNo() : first.getPalletCode(), sku));
|
||||||
|
}
|
||||||
|
if (remainingPackages.values().stream().mapToInt(Integer::intValue).sum() != 0) {
|
||||||
|
throw new BizException(ResultCode.CONFLICT, "一键代发托盘未覆盖全部实装货物明细");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean dropship(String value) {
|
||||||
|
return value != null && ("ONE_CLICK_DROPSHIP".equalsIgnoreCase(value)
|
||||||
|
|| value.toUpperCase(java.util.Locale.ROOT).contains("DROPSHIP"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private record DetailSnapshot(Long detailId, String skuCode, String productName,
|
||||||
|
Integer packageCount, Integer productQuantity, List<String> marks) {}
|
||||||
|
|
||||||
private void insert(EventEnvelope envelope) {
|
private void insert(EventEnvelope envelope) {
|
||||||
InboundOutboxEntity value = new InboundOutboxEntity();
|
InboundOutboxEntity value = new InboundOutboxEntity();
|
||||||
value.setId(IdWorker.getId()); value.setTenantId(Long.valueOf(envelope.tenantId()));
|
value.setId(IdWorker.getId()); value.setTenantId(Long.valueOf(envelope.tenantId()));
|
||||||
|
|||||||
+32
@@ -6,6 +6,7 @@ import com.baiyue.firstleg.entity.InboundOutboxEntity;
|
|||||||
import com.baiyue.firstleg.mapper.InboundOutboxMapper;
|
import com.baiyue.firstleg.mapper.InboundOutboxMapper;
|
||||||
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper;
|
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper;
|
||||||
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper.Row;
|
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper.Row;
|
||||||
|
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper.PalletRow;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -48,6 +49,29 @@ class LoadingCompletedOutboxServiceTest {
|
|||||||
assertThat(rows.get(0).getEventKey()).isEqualTo("FIRSTLEG_LOADING_COMPLETED:90:11:1");
|
assertThat(rows.get(0).getEventKey()).isEqualTo("FIRSTLEG_LOADING_COMPLETED:90:11:1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test void publishesDropshipPalletSkuAndCartonSnapshots() throws Exception {
|
||||||
|
Row first = row(11, 100, 101); first.setBusinessType("ONE_CLICK_DROPSHIP");
|
||||||
|
first.setPackageCount(2); first.setProductQuantity(20); first.setSkuCode("SKU-A");
|
||||||
|
Row second = row(11, 100, 102); second.setBusinessType("ONE_CLICK_DROPSHIP");
|
||||||
|
second.setPackageCount(1); second.setProductQuantity(5); second.setSkuCode("SKU-B");
|
||||||
|
when(snapshots.rows(90L)).thenReturn(List.of(first, second));
|
||||||
|
when(snapshots.palletRows(90L)).thenReturn(List.of(
|
||||||
|
pallet(11,100,1,"PLT-01",2,101,"SKU-A",2,20,"BOX-001"),
|
||||||
|
pallet(11,100,1,"PLT-01",2,101,"SKU-A",2,20,"BOX-002"),
|
||||||
|
pallet(11,100,2,"PLT-02",1,102,"SKU-B",1,5,"BOX-003")));
|
||||||
|
|
||||||
|
service.publish(90L);
|
||||||
|
|
||||||
|
ArgumentCaptor<InboundOutboxEntity> captor = ArgumentCaptor.forClass(InboundOutboxEntity.class);
|
||||||
|
verify(outbox).insert(captor.capture());
|
||||||
|
EventEnvelope event = mapper.readValue(captor.getValue().getPayloadJson(), EventEnvelope.class);
|
||||||
|
assertThat(event.payload().at("/orders/0/orderType").asText()).isEqualTo("ONE_CLICK_DROPSHIP");
|
||||||
|
assertThat(event.payload().at("/orders/0/customerId").asText()).isEqualTo("11");
|
||||||
|
assertThat(event.payload().at("/orders/0/pallets")).hasSize(2);
|
||||||
|
assertThat(event.payload().at("/orders/0/pallets/0/skuPackages/0/cartonMarks")).hasSize(2);
|
||||||
|
assertThat(event.payload().at("/orders/0/palletCount").asInt()).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
private Row row(long account,long inbound,long detail) {
|
private Row row(long account,long inbound,long detail) {
|
||||||
Row r=new Row(); r.setLoadingPlanId(90L); r.setPlanNo("P90"); r.setContainerBookingId(91L);
|
Row r=new Row(); r.setLoadingPlanId(90L); r.setPlanNo("P90"); r.setContainerBookingId(91L);
|
||||||
r.setAggregateVersion(8); r.setContainerNo("CONT"); r.setCabinetNo("CAB"); r.setWarehouseId(92L);
|
r.setAggregateVersion(8); r.setContainerNo("CONT"); r.setCabinetNo("CAB"); r.setWarehouseId(92L);
|
||||||
@@ -58,4 +82,12 @@ class LoadingCompletedOutboxServiceTest {
|
|||||||
r.setPackageCount(1); r.setProductQuantity(10); r.setPalletCount(1); r.setGrossWeightKg(BigDecimal.ONE);
|
r.setPackageCount(1); r.setProductQuantity(10); r.setPalletCount(1); r.setGrossWeightKg(BigDecimal.ONE);
|
||||||
r.setNetWeightKg(BigDecimal.ONE); r.setVolumeCbm(BigDecimal.ONE); return r;
|
r.setNetWeightKg(BigDecimal.ONE); r.setVolumeCbm(BigDecimal.ONE); return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PalletRow pallet(long account,long inbound,int allocation,String palletNo,int allocated,
|
||||||
|
long detail,String sku,int packages,int quantity,String boxCode) {
|
||||||
|
PalletRow row = new PalletRow(); row.setAccountId(account); row.setSourceInboundId(inbound);
|
||||||
|
row.setAllocationNo(allocation); row.setPalletCode(palletNo); row.setAllocatedPackageCount(allocated);
|
||||||
|
row.setSourceInboundDetailId(detail); row.setSkuCode(sku); row.setProductNameZh("产品");
|
||||||
|
row.setPackageCount(packages); row.setProductQuantity(quantity); row.setBoxCode(boxCode); return row;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user