feat(selfop): prefer list SKU quantities with targeted detail fallback

This commit is contained in:
2026-10-14 08:15:16 +08:00
parent 4ae158c93e
commit c640fa2d0d
14 changed files with 220 additions and 31 deletions
@@ -45,8 +45,9 @@ public final class LingxingWmsDtos {
}
// Preserve source strings; the collector interprets confirmed Asia/Shanghai source time.
public record ListSku(String productSku, String productName, BigDecimal qty) { }
public record OrderSummary(String deliveryNo, String sourceNo, String customerCode, String whCode,
Integer status, String createTime, String outboundTime) { }
Integer status, String createTime, String outboundTime, List<ListSku> productList) { }
public record PageResult(List<OrderSummary> records, Long total, int current, int size,
int pages, int sourceCurrent, int sourceSize, int sourceCode, Instant observedAt, AttemptMetadata egress) {
@@ -304,12 +304,23 @@ public final class LingxingWmsClient {
int status = requiredInt(record.get("status"), "STATUS");
if (exactDeliveryNo == null && status != 100) throw invalidResponse("DISCOVERY_STATUS_MISMATCH", 200);
return new OrderSummary(deliveryNo, optionalText(record, "sourceNo"), requiredText(record, "customerCode", 64),
requiredText(record, "whCode", 64), status, optionalText(record, "createTime"), optionalText(record, "outboundTime"));
requiredText(record, "whCode", 64), status, optionalText(record, "createTime"), optionalText(record, "outboundTime"), listSkus(record.get("productList")));
});
return new PageResult(page.records(), page.total(), current, size, page.pages(), page.sourceCurrent(),
page.sourceSize(), 200, page.observedAt(), metadata);
}
private List<ListSku> listSkus(JsonNode products) {
if (products == null || products.isNull()) return null;
if (!products.isArray()) throw invalidResponse("PRODUCT_LIST_TYPE_INVALID", 200);
List<ListSku> items = new ArrayList<>();
for (JsonNode item : products) {
if (!item.isObject()) throw invalidResponse("PRODUCT_LIST_ROW_INVALID", 200);
items.add(new ListSku(optionalText(item, "productSku"), optionalText(item, "productName"), quantity(item.get("qty"))));
}
return List.copyOf(items);
}
private <T> QueryPage<T> mappedPage(JsonNode data, int current, int size, String currentField,
String sizeField, boolean outbound, AttemptMetadata metadata, Function<JsonNode, T> projection) {
JsonNode records = data.get("records");
@@ -349,6 +349,16 @@ components:
status: {type: integer}
createTime: {type: string, nullable: true}
outboundTime: {type: string, nullable: true}
productList:
type: array
nullable: true
description: Per-SKU list quantities; missing items, SKU or qty require one detail supplement for this order. Zero is a known quantity.
items:
type: object
properties:
productSku: {type: string, nullable: true}
productName: {type: string, nullable: true}
qty: {type: number, nullable: true}
Warehouse:
type: object
required: [whCode, warehouseType, status]