feat(selfop): add bounded inventory flow diagnostic through account egress
This commit is contained in:
+9
@@ -78,6 +78,15 @@ public class LingxingInternalController {
|
||||
return ApiResponse.success(client.queryDetail(request, context(context)));
|
||||
}
|
||||
|
||||
@Operation(summary = "单SKU最多31日库存流水诊断,仅第一页最多1000条")
|
||||
@PostMapping("/inventory-flow/query")
|
||||
public ApiResponse<QueryPage<InventoryFlow>> inventoryFlow(
|
||||
@RequestHeader(value="X-Internal-Service-Token",required=false) String token,
|
||||
@RequestHeader(value="X-Lingxing-Egress-Context",required=false) String context,
|
||||
@Valid @RequestBody InventoryFlowRequest request) {
|
||||
tokenGuard.verify(token);return ApiResponse.success(client.queryInventoryFlow(request,context(context)));
|
||||
}
|
||||
|
||||
@Operation(summary = "读取单仓全部货主、全部品质且保留零库存的产品库存单页")
|
||||
@PostMapping("/product-inventory/query")
|
||||
public ApiResponse<QueryPage<ProductStock>> inventory(
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import java.time.Instant;
|
||||
public final class LingxingEgressDtos {
|
||||
private LingxingEgressDtos() { }
|
||||
public enum CollectionMode { OFF, VALIDATION, BUSINESS }
|
||||
public enum Operation { WAREHOUSES, OUTBOUND_QUERY, OUTBOUND_LOCATE, OUTBOUND_DETAIL, PRODUCT_INVENTORY, CUSTOMERS, PRODUCTS }
|
||||
public enum Operation { WAREHOUSES, OUTBOUND_QUERY, OUTBOUND_LOCATE, OUTBOUND_DETAIL, PRODUCT_INVENTORY, CUSTOMERS, PRODUCTS, INVENTORY_FLOW }
|
||||
public record EgressContext(String sourceAccount, CollectionMode executionPurpose, String rootTaskId,
|
||||
String sessionId, String attemptId, String exclusiveGrantId) {
|
||||
public boolean wellFormed() {
|
||||
|
||||
+6
@@ -20,6 +20,12 @@ public final class LingxingWmsDtos {
|
||||
|
||||
public record WarehouseQueryRequest(@Min(1) int current, @Min(1) @Max(1000) int size) { }
|
||||
public record ProductQueryRequest(@Min(1) int current, @Min(1) @Max(100) int size) { }
|
||||
public record InventoryFlowRequest(@NotBlank @Size(max=64) String warehouseCode,
|
||||
@NotBlank @Size(max=64) String customerCode, @NotBlank @Size(max=128) String sku,
|
||||
@NotNull LocalDateTime startTime, @NotNull LocalDateTime endTime) { }
|
||||
public record InventoryFlow(String id, String customerCode, String whCode, String productSku,
|
||||
String cellNo, String innerBatchNo, String billNo, String billType, Integer productQuality,
|
||||
BigDecimal bookQty, String bookChangQty, BigDecimal closeQty, String createTime) { }
|
||||
public record Customer(String customerCode, String customerName, String status) { }
|
||||
public record Product(String customerCode, String sku, String productName,
|
||||
BigDecimal length, BigDecimal width, BigDecimal height, String sizeUnit,
|
||||
|
||||
+27
@@ -162,6 +162,30 @@ public final class LingxingWmsClient {
|
||||
(data, metadata) -> inventory(data, request, metadata));
|
||||
}
|
||||
|
||||
/** Single bounded diagnostic page; never changes the current-inventory collection protocol. */
|
||||
public QueryPage<InventoryFlow> queryInventoryFlow(InventoryFlowRequest request, EgressContext context) {
|
||||
if(request==null)throw badRequest();
|
||||
requireInput(request.warehouseCode(),64);requireInput(request.customerCode(),64);requireInput(request.sku(),128);
|
||||
if(request.startTime()==null||request.endTime()==null||!request.startTime().isBefore(request.endTime())
|
||||
||request.endTime().isAfter(request.startTime().plusDays(31)))throw badRequest();
|
||||
Map<String,Object> body=pagination(1,1000);
|
||||
body.put("whCode",request.warehouseCode());body.put("customerCode",request.customerCode());
|
||||
body.put("barcodeAccurate",request.sku());body.put("startTime",SOURCE_TIME.format(request.startTime()));
|
||||
body.put("endTime",SOURCE_TIME.format(request.endTime()));body.put("sortName","createTime");body.put("sortOrder","asc");
|
||||
return execute("/openapi/v2/stock/stockCellBook/page",body,context,Operation.INVENTORY_FLOW,
|
||||
(data,metadata)->mappedPage(data,1,1000,"current","size",false,metadata,row->{
|
||||
if(!request.warehouseCode().equals(requiredText(row,"whCode",64))
|
||||
||!request.customerCode().equals(requiredText(row,"customerCode",64))
|
||||
||!request.sku().equals(requiredText(row,"productSku",128)))throw invalidResponse("FLOW_IDENTITY_MISMATCH",200);
|
||||
JsonNode id=row.get("id");
|
||||
if(id==null||!id.isIntegralNumber())throw invalidResponse("FLOW_ID_MISSING",200);
|
||||
return new InventoryFlow(id.asText(),request.customerCode(),request.warehouseCode(),request.sku(),
|
||||
optionalText(row,"cellNo"),optionalText(row,"innerBatchNo"),optionalText(row,"billNo"),optionalText(row,"billType"),
|
||||
requiredInt(row.get("productQuality"),"PRODUCT_QUALITY"),quantity(row.get("bookQty")),
|
||||
optionalText(row,"bookChangQty"),quantity(row.get("closeQty")),optionalText(row,"createTime"));
|
||||
}));
|
||||
}
|
||||
|
||||
private QueryPage<ProductStock> inventory(JsonNode data, InventoryQueryRequest request, AttemptMetadata metadata) {
|
||||
Set<List<Object>> keys = new HashSet<>();
|
||||
return mappedPage(data, request.current(), request.size(), "current", "size", false, metadata, row -> {
|
||||
@@ -203,6 +227,9 @@ public final class LingxingWmsClient {
|
||||
JsonNode json;
|
||||
try { json = envelope(response.body()); }
|
||||
catch (LingxingWmsException error) {
|
||||
// This optional endpoint may lack permission while ordinary collection remains authorized.
|
||||
if(operation==Operation.INVENTORY_FLOW&&Integer.valueOf(11008).equals(error.sourceCode()))
|
||||
throw upstreamFailure("FLOW_PERMISSION_DENIED","当前账号没有库存流水接口权限",false,200,11008);
|
||||
if (Integer.valueOf(31001).equals(error.sourceCode()) || Integer.valueOf(429).equals(error.sourceCode())) {
|
||||
handle.rateLimited(retryAfter(response));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user