feat(selfop): sync versioned owner and product directories
This commit is contained in:
+18
@@ -88,6 +88,24 @@ public class LingxingInternalController {
|
||||
return ApiResponse.success(client.queryInventory(request, context(context)));
|
||||
}
|
||||
|
||||
@PostMapping("/customers/query")
|
||||
public ApiResponse<QueryPage<Customer>> customers(
|
||||
@RequestHeader(value="X-Internal-Service-Token",required=false) String token,
|
||||
@RequestHeader(value="X-Lingxing-Egress-Context",required=false) String context,
|
||||
@Valid @RequestBody WarehouseQueryRequest request) {
|
||||
tokenGuard.verify(token);
|
||||
return ApiResponse.success(client.queryCustomers(request,context(context)));
|
||||
}
|
||||
|
||||
@PostMapping("/products/query")
|
||||
public ApiResponse<QueryPage<Product>> products(
|
||||
@RequestHeader(value="X-Internal-Service-Token",required=false) String token,
|
||||
@RequestHeader(value="X-Lingxing-Egress-Context",required=false) String context,
|
||||
@Valid @RequestBody ProductQueryRequest request) {
|
||||
tokenGuard.verify(token);
|
||||
return ApiResponse.success(client.queryProducts(request,context(context)));
|
||||
}
|
||||
|
||||
private EgressContext context(String header) {
|
||||
if (header == null || header.isBlank() || header.length() > 2048 || !header.chars().allMatch(c -> c >= 32 && c <= 126))
|
||||
throw invalidContext();
|
||||
|
||||
+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 }
|
||||
public enum Operation { WAREHOUSES, OUTBOUND_QUERY, OUTBOUND_LOCATE, OUTBOUND_DETAIL, PRODUCT_INVENTORY, CUSTOMERS, PRODUCTS }
|
||||
public record EgressContext(String sourceAccount, CollectionMode executionPurpose, String rootTaskId,
|
||||
String sessionId, String attemptId, String exclusiveGrantId) {
|
||||
public boolean wellFormed() {
|
||||
|
||||
+5
@@ -19,6 +19,11 @@ public final class LingxingWmsDtos {
|
||||
@Min(1) int current, @Min(1) @Max(100) int size) { }
|
||||
|
||||
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 Customer(String customerCode, String customerName, String status) { }
|
||||
public record Product(String customerCode, String sku, String productName,
|
||||
BigDecimal length, BigDecimal width, BigDecimal height, String sizeUnit,
|
||||
BigDecimal wmsLength, BigDecimal wmsWidth, BigDecimal wmsHeight, String wmsSizeUnit) { }
|
||||
public record LocateRequest(@NotBlank @Size(max=128) String deliveryNo,
|
||||
@Min(1) int current, @Min(1) @Max(1000) int size) { }
|
||||
public record DetailRequest(@NotBlank @Size(max=64) String warehouseCode,
|
||||
|
||||
+18
@@ -133,6 +133,24 @@ public final class LingxingWmsClient {
|
||||
optionalText(data, "outboundTime"), lines, 200, clock.instant(), metadata);
|
||||
}
|
||||
|
||||
public QueryPage<Customer> queryCustomers(WarehouseQueryRequest request, EgressContext context) {
|
||||
if (request == null) throw badRequest();
|
||||
validatePagination(request.current(), request.size(), 1000);
|
||||
return execute("/openapi/v2/customer/list", pagination(request.current(), request.size()), context, Operation.CUSTOMERS,
|
||||
(data, metadata) -> mappedPage(data, request.current(), request.size(), "current", "size", false, metadata,
|
||||
row -> new Customer(requiredText(row,"customerCode",64), optionalText(row,"customerName"), optionalText(row,"status"))));
|
||||
}
|
||||
|
||||
public QueryPage<Product> queryProducts(ProductQueryRequest request, EgressContext context) {
|
||||
if (request == null) throw badRequest();
|
||||
validatePagination(request.current(), request.size(), 100);
|
||||
return execute("/openapi/v2/product/page", pagination(request.current(), request.size()), context, Operation.PRODUCTS,
|
||||
(data, metadata) -> mappedPage(data, request.current(), request.size(), "current", "size", false, metadata,
|
||||
row -> new Product(requiredText(row,"customerCode",64), requiredText(row,"sku",128), optionalText(row,"productName"),
|
||||
quantity(row.get("length")),quantity(row.get("width")),quantity(row.get("height")),optionalText(row,"sizeUnit"),
|
||||
quantity(row.get("wmsLength")),quantity(row.get("wmsWidth")),quantity(row.get("wmsHeight")),optionalText(row,"wmsSizeUnit"))));
|
||||
}
|
||||
|
||||
public QueryPage<ProductStock> queryInventory(InventoryQueryRequest request, EgressContext context) {
|
||||
if (request == null) throw badRequest();
|
||||
requireInput(request.warehouseCode(), 64);
|
||||
|
||||
@@ -51,6 +51,40 @@ x-lastleg-egress-coordination:
|
||||
security:
|
||||
- InternalServiceToken: []
|
||||
paths:
|
||||
/internal/integrations/lingxing/wms/customers/query:
|
||||
post:
|
||||
summary: Query one page of customers using the existing account egress permit
|
||||
description: Calls /openapi/v2/customer/list. BUSINESS MASTER_DATA tasks only; no retries or separate egress path. Dimensions and units remain separate; blanks are null.
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/WarehouseQueryRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: Standard envelope with one page or sanitized ProviderFailure.
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/CustomerResponse'}
|
||||
/internal/integrations/lingxing/wms/products/query:
|
||||
post:
|
||||
summary: Query one page of products using the existing account egress permit
|
||||
description: Calls /openapi/v2/product/page. BUSINESS MASTER_DATA tasks only; no retries or separate egress path. Dimensions and units remain separate; blanks are null.
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/ProductQueryRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: Standard envelope with one page or sanitized ProviderFailure.
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/ProductResponse'}
|
||||
/internal/integrations/lingxing/wms/egress/runtime:
|
||||
get:
|
||||
operationId: lingxingEgressRuntime
|
||||
@@ -175,6 +209,68 @@ components:
|
||||
in: header
|
||||
name: X-Internal-Service-Token
|
||||
schemas:
|
||||
CustomerPage:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Pagination'}
|
||||
- type: object
|
||||
required: [records]
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/Customer'}}
|
||||
CustomerResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Envelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
nullable: true
|
||||
oneOf:
|
||||
- {$ref: '#/components/schemas/CustomerPage'}
|
||||
- {$ref: '#/components/schemas/ProviderFailure'}
|
||||
ProductPage:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Pagination'}
|
||||
- type: object
|
||||
required: [records]
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/Product'}}
|
||||
ProductResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Envelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
nullable: true
|
||||
oneOf:
|
||||
- {$ref: '#/components/schemas/ProductPage'}
|
||||
- {$ref: '#/components/schemas/ProviderFailure'}
|
||||
ProductQueryRequest:
|
||||
type: object
|
||||
required: [current, size]
|
||||
properties:
|
||||
current: {type: integer, minimum: 1}
|
||||
size: {type: integer, minimum: 1, maximum: 100}
|
||||
Customer:
|
||||
type: object
|
||||
required: [customerCode]
|
||||
properties:
|
||||
customerCode: {type: string}
|
||||
customerName: {type: string, nullable: true}
|
||||
status: {type: string, nullable: true}
|
||||
Product:
|
||||
type: object
|
||||
required: [customerCode, sku]
|
||||
properties:
|
||||
customerCode: {type: string}
|
||||
sku: {type: string}
|
||||
productName: {type: string, nullable: true}
|
||||
length: {type: number, nullable: true}
|
||||
width: {type: number, nullable: true}
|
||||
height: {type: number, nullable: true}
|
||||
wmsLength: {type: number, nullable: true}
|
||||
wmsWidth: {type: number, nullable: true}
|
||||
wmsHeight: {type: number, nullable: true}
|
||||
sizeUnit: {type: string, nullable: true}
|
||||
wmsSizeUnit: {type: string, nullable: true}
|
||||
EgressRuntimeSnapshot:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -219,7 +315,7 @@ components:
|
||||
{"current":1,"size":2,"whCode":"WH-DEMO","isHideInventory":0}
|
||||
EgressOperation:
|
||||
type: string
|
||||
enum: [WAREHOUSES, OUTBOUND_QUERY, OUTBOUND_LOCATE, OUTBOUND_DETAIL, PRODUCT_INVENTORY]
|
||||
enum: [WAREHOUSES, OUTBOUND_QUERY, OUTBOUND_LOCATE, OUTBOUND_DETAIL, PRODUCT_INVENTORY, CUSTOMERS, PRODUCTS]
|
||||
EgressMetadata:
|
||||
type: object
|
||||
required: [attemptId, actualHttpAttempts, accountPaused]
|
||||
|
||||
Reference in New Issue
Block a user