Merge remote-tracking branch 'origin/test' into dev
This commit is contained in:
@@ -9,10 +9,12 @@ import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.entity.OrderCargoEntity;
|
||||
import com.baiyue.order.repository.OrderRepository;
|
||||
import com.baiyue.order.service.OrderApplicationService;
|
||||
import com.baiyue.order.service.PrintableInboundSnapshotService;
|
||||
import com.baiyue.order.client.FirstlegInboundClient;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -29,6 +31,7 @@ import java.util.stream.Collectors;
|
||||
@RequestMapping("/internal/order/v1/cargoes")
|
||||
public class InternalOrderCargoController {
|
||||
@Resource private OrderRepository orders;
|
||||
@Resource private PrintableInboundSnapshotService printableInboundSnapshots;
|
||||
@Value("${baiyue.security.internal-service-token}") private String internalToken;
|
||||
private byte[] expectedToken;
|
||||
|
||||
@@ -112,6 +115,18 @@ public class InternalOrderCargoController {
|
||||
return ApiResponse.success(OrderApplicationService.inboundCommand(order, packageCount));
|
||||
}
|
||||
|
||||
@PostMapping("/{tenantId}/{orderId}/printable-inbound-snapshot")
|
||||
public ApiResponse<FirstlegInboundClient.OrderApprovedInboundCommand> printableInboundSnapshot(
|
||||
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||
@PathVariable long tenantId,
|
||||
@PathVariable long orderId) {
|
||||
requireToken(token);
|
||||
if (tenantId <= 0 || orderId <= 0) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "租户和订单ID必须大于0");
|
||||
}
|
||||
return ApiResponse.success(printableInboundSnapshots.reserve(tenantId, orderId));
|
||||
}
|
||||
|
||||
@GetMapping("/{tenantId}/{orderId}/measurement-declaration")
|
||||
public ApiResponse<MeasurementDeclarationSnapshot> measurementDeclaration(
|
||||
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||
|
||||
+37
-3
@@ -6,6 +6,7 @@ import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.order.dto.BatchOrderReviewResponse;
|
||||
import com.baiyue.order.dto.BatchOrderReviewPreviewResponse;
|
||||
import com.baiyue.order.dto.OrderDetailResponse;
|
||||
import com.baiyue.order.dto.OrderRequests;
|
||||
import com.baiyue.order.dto.InboundCodePolicyResponse;
|
||||
@@ -17,6 +18,7 @@ import com.baiyue.order.entity.OrderStatus;
|
||||
import com.baiyue.order.service.OrderApplicationService;
|
||||
import com.baiyue.order.service.OrderScopeGuard;
|
||||
import com.baiyue.order.service.InboundCodeAssociationService;
|
||||
import com.baiyue.order.service.BatchOrderReviewPreviewService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
@@ -51,6 +53,8 @@ public class PlatformFirstLegOrderController {
|
||||
private OrderApplicationService service;
|
||||
@Resource
|
||||
private InboundCodeAssociationService inboundCodeAssociations;
|
||||
@Resource
|
||||
private BatchOrderReviewPreviewService batchReviewPreview;
|
||||
|
||||
@GetMapping("/inbound-code-policy")
|
||||
@PreAuthorize("hasAnyAuthority('platform:order:list', 'platform:order:create', 'platform:order:edit', 'platform:order:submit')")
|
||||
@@ -192,15 +196,26 @@ public class PlatformFirstLegOrderController {
|
||||
}
|
||||
|
||||
@BusinessAudit(event = "ORDER_BATCH_APPROVE", resourceType = "FIRST_LEG_ORDER_BATCH",
|
||||
resourceId = "#request.orderIds", tenantId = "#tenantId", description = "批量审核通过订单")
|
||||
@Operation(summary = "批量审核通过订单", description = "单租户模式下逐单独立审核,返回成功和失败明细。")
|
||||
resourceId = "#request.items", tenantId = "#tenantId", description = "批量审核通过订单")
|
||||
@Operation(summary = "批量审核通过订单", description = "单租户模式下逐票校验权限、状态及预览版本并独立提交;允许部分成功,返回成功和失败明细。")
|
||||
@PostMapping("/batch-approve")
|
||||
@PreAuthorize("hasAuthority('platform:order:approve')")
|
||||
public ApiResponse<BatchOrderReviewResponse> batchApprove(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam long tenantId,
|
||||
@Valid @RequestBody OrderRequests.BatchReviewRequest request) {
|
||||
return batchTransit(user, tenantId, request.orderIds(), OrderStatus.APPROVED, null);
|
||||
return batchApproveTransit(user, tenantId, request.items());
|
||||
}
|
||||
|
||||
@Operation(summary = "批量审核预览", description = "一次批量查询返回审核弹窗所需订单与中文货物摘要,固定两次数据库查询,不逐票读取详情。")
|
||||
@PostMapping("/batch-review-preview")
|
||||
@PreAuthorize("hasAuthority('platform:order:approve')")
|
||||
public ApiResponse<BatchOrderReviewPreviewResponse> batchReviewPreview(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam long tenantId,
|
||||
@Valid @RequestBody OrderRequests.BatchReviewRequest request) {
|
||||
long scopedTenantId = OrderScopeGuard.platform(user, tenantId);
|
||||
return ApiResponse.success(batchReviewPreview.preview(scopedTenantId, request.items()));
|
||||
}
|
||||
|
||||
@BusinessAudit(event = "ORDER_REJECT", resourceType = "FIRST_LEG_ORDER", resourceId = "#id", description = "Reject order / 驳回订单")
|
||||
@@ -320,4 +335,23 @@ public class PlatformFirstLegOrderController {
|
||||
return ApiResponse.success(new BatchOrderReviewResponse(orderIds.size(), successOrderIds.size(),
|
||||
failedOrders.size(), List.copyOf(successOrderIds), List.copyOf(failedOrders)));
|
||||
}
|
||||
|
||||
private ApiResponse<BatchOrderReviewResponse> batchApproveTransit(
|
||||
AuthenticatedUser user, long tenantId, List<OrderRequests.BatchReviewItem> items) {
|
||||
long scopedTenantId = OrderScopeGuard.platform(user, tenantId);
|
||||
List<Long> successOrderIds = new ArrayList<>();
|
||||
List<BatchOrderReviewResponse.FailedOrder> failedOrders = new ArrayList<>();
|
||||
for (OrderRequests.BatchReviewItem item : items) {
|
||||
try {
|
||||
service.transit(scopedTenantId, user.userId(), user.username(), item.orderId(),
|
||||
OrderStatus.APPROVED, null, item.orderVersion());
|
||||
successOrderIds.add(item.orderId());
|
||||
} catch (BizException exception) {
|
||||
failedOrders.add(new BatchOrderReviewResponse.FailedOrder(
|
||||
item.orderId(), exception.getResultCode().code(), exception.getMessage()));
|
||||
}
|
||||
}
|
||||
return ApiResponse.success(new BatchOrderReviewResponse(items.size(), successOrderIds.size(),
|
||||
failedOrders.size(), List.copyOf(successOrderIds), List.copyOf(failedOrders)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.baiyue.order.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** 平台批量审核前的一次性稳定展示快照。 */
|
||||
@Schema(description = "订单批量审核预览")
|
||||
public record BatchOrderReviewPreviewResponse(
|
||||
int total,
|
||||
int approvableCount,
|
||||
List<Item> items
|
||||
) {
|
||||
public record Item(
|
||||
Long orderId,
|
||||
Integer orderVersion,
|
||||
String inboundCode,
|
||||
Long customerId,
|
||||
String customerName,
|
||||
List<String> chineseGoodsNames,
|
||||
String channelCode,
|
||||
String channelName,
|
||||
String destinationWarehouseCode,
|
||||
String destinationWarehouseName,
|
||||
boolean canApprove,
|
||||
String blockReason
|
||||
) {}
|
||||
}
|
||||
@@ -268,15 +268,22 @@ public final class OrderRequests {
|
||||
|
||||
@Schema(name = "FirstLegOrderBatchReviewRequest", description = "单租户订单批量审核请求")
|
||||
public record BatchReviewRequest(
|
||||
@Schema(description = "订单 ID 列表,单次最多 100 条", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty @Size(max = 100) List<@NotNull @Min(1) Long> orderIds
|
||||
@Schema(description = "订单及列表快照版本,单次最多 100 条", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty @Size(max = 100) List<@Valid @NotNull BatchReviewItem> items
|
||||
) {
|
||||
@AssertTrue(message = "订单 ID 不能重复")
|
||||
public boolean hasDistinctOrderIds() {
|
||||
return orderIds == null || orderIds.size() == orderIds.stream().distinct().count();
|
||||
return items == null || items.size() == items.stream()
|
||||
.map(item -> item == null ? null : item.orderId()).distinct().count();
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(name = "FirstLegOrderBatchReviewItem", description = "批量审核订单及其列表快照版本")
|
||||
public record BatchReviewItem(
|
||||
@NotNull @Min(1) Long orderId,
|
||||
@NotNull @Min(0) Integer orderVersion
|
||||
) {}
|
||||
|
||||
@Schema(name = "FirstLegOrderBatchRejectRequest", description = "单租户订单批量驳回请求")
|
||||
public record BatchRejectRequest(
|
||||
@Schema(description = "订单 ID 列表,单次最多 100 条", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
|
||||
@@ -54,6 +54,17 @@ public class OrderRepository {
|
||||
.eq(OrderEntity::getId, order.getId())
|
||||
.eq(OrderEntity::getTenantId, tenantId));
|
||||
}
|
||||
public int assignInboundCodeIfBlank(long tenantId, long orderId, String inboundCode) {
|
||||
return orderMapper.update(null, new LambdaUpdateWrapper<OrderEntity>()
|
||||
.eq(OrderEntity::getTenantId, tenantId)
|
||||
.eq(OrderEntity::getId, orderId)
|
||||
.eq(OrderEntity::getDeleted, false)
|
||||
.and(wrapper -> wrapper.isNull(OrderEntity::getInboundCode)
|
||||
.or().eq(OrderEntity::getInboundCode, ""))
|
||||
.set(OrderEntity::getInboundCode, inboundCode)
|
||||
.set(OrderEntity::getUpdatedAt, LocalDateTime.now())
|
||||
.setSql("version = version + 1"));
|
||||
}
|
||||
public int updateDeclarationHeader(long tenantId, long orderId, int expectedVersion, long operatorId,
|
||||
String customerRemark, LocalDateTime expectedArrivalAt,
|
||||
java.math.BigDecimal estimatedVolumeCbm,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.baiyue.order.service;
|
||||
|
||||
import com.baiyue.order.dto.BatchOrderReviewPreviewResponse;
|
||||
import com.baiyue.order.dto.OrderRequests;
|
||||
import com.baiyue.order.entity.OrderCargoEntity;
|
||||
import com.baiyue.order.entity.OrderEntity;
|
||||
import com.baiyue.order.entity.OrderStatus;
|
||||
import com.baiyue.order.repository.OrderRepository;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/** 用固定两次批量查询生成审核弹窗快照,禁止前端逐票查询详情。 */
|
||||
@Service
|
||||
public class BatchOrderReviewPreviewService {
|
||||
@Resource
|
||||
private OrderRepository orders;
|
||||
|
||||
public BatchOrderReviewPreviewResponse preview(long tenantId, List<OrderRequests.BatchReviewItem> requested) {
|
||||
List<Long> orderIds = requested.stream().map(OrderRequests.BatchReviewItem::orderId).toList();
|
||||
Map<Long, OrderEntity> byId = new LinkedHashMap<>();
|
||||
orders.findByIds(tenantId, orderIds).forEach(order -> byId.put(order.getId(), order));
|
||||
|
||||
Map<Long, List<String>> goodsNames = new LinkedHashMap<>();
|
||||
for (OrderCargoEntity cargo : orders.findCargoByOrderIds(tenantId, orderIds)) {
|
||||
String name = cargo.getCargoName() == null ? null : cargo.getCargoName().trim();
|
||||
if (name == null || name.isEmpty()) continue;
|
||||
List<String> names = goodsNames.computeIfAbsent(cargo.getOrderId(), ignored -> new ArrayList<>());
|
||||
if (!names.contains(name)) names.add(name);
|
||||
}
|
||||
|
||||
List<BatchOrderReviewPreviewResponse.Item> items = requested.stream()
|
||||
.map(item -> toItem(item, byId.get(item.orderId()), goodsNames.getOrDefault(item.orderId(), List.of())))
|
||||
.toList();
|
||||
int approvableCount = (int) items.stream().filter(BatchOrderReviewPreviewResponse.Item::canApprove).count();
|
||||
return new BatchOrderReviewPreviewResponse(items.size(), approvableCount, items);
|
||||
}
|
||||
|
||||
private static BatchOrderReviewPreviewResponse.Item toItem(OrderRequests.BatchReviewItem requested,
|
||||
OrderEntity order,
|
||||
List<String> goodsNames) {
|
||||
if (order == null) {
|
||||
return new BatchOrderReviewPreviewResponse.Item(requested.orderId(), requested.orderVersion(),
|
||||
null, null, null, List.of(), null, null, null, null, false,
|
||||
"订单不存在或不属于当前客户");
|
||||
}
|
||||
String blockReason = null;
|
||||
if (order.getStatus() != OrderStatus.SUBMITTED) {
|
||||
blockReason = "当前订单状态不可审核";
|
||||
} else if (!Objects.equals(order.getVersion(), requested.orderVersion())) {
|
||||
blockReason = "订单版本已变化,请刷新后重试";
|
||||
}
|
||||
return new BatchOrderReviewPreviewResponse.Item(order.getId(), order.getVersion(), order.getInboundCode(),
|
||||
order.getCustomerId(), order.getCustomerName(), List.copyOf(goodsNames), order.getChannelCode(),
|
||||
order.getChannelName(), order.getAmazonWarehouseCode(), order.getDestinationWarehouseName(),
|
||||
blockReason == null, blockReason);
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,16 @@ public class OrderApplicationService {
|
||||
|
||||
@Transactional
|
||||
public void transit(long tenantId, long userId, String username, long id, OrderStatus target, String reason) {
|
||||
transit(tenantId, userId, username, id, target, reason, null);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void transit(long tenantId, long userId, String username, long id, OrderStatus target, String reason,
|
||||
Integer expectedVersion) {
|
||||
OrderEntity order = require(tenantId, id);
|
||||
if (expectedVersion != null && !expectedVersion.equals(order.getVersion())) {
|
||||
throw new BizException(ResultCode.CONFLICT, "订单版本已变化,请刷新后重试");
|
||||
}
|
||||
if (target == OrderStatus.SUBMITTED) eligibilityGuard.requireApproved(tenantId);
|
||||
OrderStatus from = order.getStatus();
|
||||
if (!allowed(from, target)) throw new BizException(com.baiyue.common.core.api.ResultCode.CONFLICT,
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.baiyue.order.service;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.client.FirstlegInboundClient;
|
||||
import com.baiyue.order.config.InboundCodeModeProvider;
|
||||
import com.baiyue.order.entity.OrderCargoEntity;
|
||||
import com.baiyue.order.entity.OrderEntity;
|
||||
import com.baiyue.order.repository.OrderRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/** 为草稿箱唛打印预留稳定入仓码;订单提交时继续复用该码。 */
|
||||
@Service
|
||||
public class PrintableInboundSnapshotService {
|
||||
private final OrderRepository orders;
|
||||
private final OrderPricingChannelGuard pricingChannels;
|
||||
private final InboundCodeModeProvider inboundCodeMode;
|
||||
private final OrderApplicationService orderApplication;
|
||||
|
||||
public PrintableInboundSnapshotService(OrderRepository orders,
|
||||
OrderPricingChannelGuard pricingChannels,
|
||||
InboundCodeModeProvider inboundCodeMode,
|
||||
OrderApplicationService orderApplication) {
|
||||
this.orders = orders;
|
||||
this.pricingChannels = pricingChannels;
|
||||
this.inboundCodeMode = inboundCodeMode;
|
||||
this.orderApplication = orderApplication;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public FirstlegInboundClient.OrderApprovedInboundCommand reserve(long tenantId, long orderId) {
|
||||
OrderEntity order = requireOwned(tenantId, orderId);
|
||||
if (!StringUtils.hasText(order.getInboundCode())) {
|
||||
if (inboundCodeMode.legacyManual()) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "当前系统使用旧系统入仓码,请先填写入仓码");
|
||||
}
|
||||
String prefix = pricingChannels.requireAvailable(tenantId, order.getReceivingWarehouseId(),
|
||||
order.getChannelCode(), order.getDestinationType());
|
||||
String allocated = orderApplication.nextInboundCode(prefix);
|
||||
if (orders.assignInboundCodeIfBlank(tenantId, orderId, allocated) == 1) {
|
||||
order.setInboundCode(allocated);
|
||||
} else {
|
||||
order = requireOwned(tenantId, orderId);
|
||||
if (!StringUtils.hasText(order.getInboundCode())) {
|
||||
throw new BizException(ResultCode.CONFLICT, "入仓码预留冲突,请刷新后重试");
|
||||
}
|
||||
}
|
||||
}
|
||||
int packageCount = orders.findCargoInheritedByOrder(tenantId, orderId).stream()
|
||||
.map(OrderCargoEntity::getPackageCount).filter(java.util.Objects::nonNull)
|
||||
.mapToInt(Integer::intValue).sum();
|
||||
return OrderApplicationService.inboundCommand(order, packageCount);
|
||||
}
|
||||
|
||||
private OrderEntity requireOwned(long tenantId, long orderId) {
|
||||
OrderEntity order = orders.findOwned(tenantId, orderId);
|
||||
if (order == null) {
|
||||
throw new BizException(ResultCode.NOT_FOUND, "订单不存在或不属于当前客户");
|
||||
}
|
||||
return order;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,23 @@ paths:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/CargoLabelBindingListEnvelope'}
|
||||
'403': {description: 内部服务令牌无效}
|
||||
/internal/order/v1/cargoes/{tenantId}/{orderId}/printable-inbound-snapshot:
|
||||
post:
|
||||
security: []
|
||||
summary: 为 Firstleg 箱唛打印读取并预留稳定入仓快照
|
||||
description: >-
|
||||
仅接受内部服务令牌。若 AUTO 模式草稿尚无入仓码,则按订单渠道原子预留全局唯一入仓码;
|
||||
并发重放返回已胜出的同一码,后续订单提交继续复用,避免已打印二维码失效。
|
||||
parameters:
|
||||
- name: X-Internal-Service-Token
|
||||
in: header
|
||||
required: true
|
||||
schema: {type: string}
|
||||
- {name: tenantId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: orderId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
responses:
|
||||
'200': {description: 返回带稳定入仓码及总箱数的订单快照}
|
||||
'403': {description: 内部服务令牌无效}
|
||||
/internal/order/v1/pending-review-orders:
|
||||
get:
|
||||
security: []
|
||||
@@ -491,6 +508,45 @@ paths:
|
||||
responses:
|
||||
'200': {description: 成功或业务失败,按响应体 code 判断}
|
||||
'403': {description: 需要 platform:order:create 权限}
|
||||
/api/platform/v1/orders/first-leg/batch-review-preview:
|
||||
post:
|
||||
tags: [Platform first-leg orders]
|
||||
summary: 批量审核预览
|
||||
description: >-
|
||||
在一个 HTTP 请求中按目标客户批量返回审核弹窗所需稳定快照。服务端固定使用订单与货物两次批量查询,
|
||||
中文品名按货物 itemNo 顺序去重;不得由前端逐票请求详情。orderId 仅供路由,主要展示使用 inboundCode;
|
||||
canApprove=false 时必须展示 blockReason。请求中的 orderVersion 用于识别列表快照是否过期。
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/BatchReviewRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: 返回请求顺序一致的批量审核预览
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/BatchReviewPreviewEnvelope'}
|
||||
'403': {description: 需要平台身份和 platform:order:approve 权限}
|
||||
/api/platform/v1/orders/first-leg/batch-approve:
|
||||
post:
|
||||
tags: [Platform first-leg orders]
|
||||
summary: 批量审核通过订单
|
||||
description: >-
|
||||
单客户范围内逐票重新校验权限、状态和 orderVersion,每票独立事务;允许部分成功,
|
||||
failedOrders 返回未成功订单及业务原因,成功订单不会因其他订单失败而回滚。
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/BatchReviewRequest'}
|
||||
responses:
|
||||
'200': {description: 返回部分成功语义的逐票处理汇总}
|
||||
'403': {description: 需要平台身份和 platform:order:approve 权限}
|
||||
/api/platform/v1/orders/first-leg/tenant-statistics:
|
||||
get:
|
||||
tags: [Platform first-leg orders]
|
||||
@@ -635,6 +691,54 @@ components:
|
||||
widthCm: {type: number, nullable: true}
|
||||
heightCm: {type: number, nullable: true}
|
||||
shipmentId: {type: string, nullable: true, description: 当前货物行的 FBA 货件号快照,不以订单级字段回退}
|
||||
BatchReviewRequest:
|
||||
type: object
|
||||
required: [items]
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
minItems: 1
|
||||
maxItems: 100
|
||||
uniqueItems: true
|
||||
items: {$ref: '#/components/schemas/BatchReviewRequestItem'}
|
||||
BatchReviewRequestItem:
|
||||
type: object
|
||||
required: [orderId, orderVersion]
|
||||
properties:
|
||||
orderId: {type: string, pattern: '^[1-9][0-9]*$', description: 仅供路由关联,不作为主要展示键}
|
||||
orderVersion: {type: integer, minimum: 0, description: 统一订单列表返回的 Order 乐观锁版本}
|
||||
BatchReviewPreviewEnvelope:
|
||||
type: object
|
||||
required: [code, data]
|
||||
properties:
|
||||
code: {type: string, example: "200"}
|
||||
message: {type: string, nullable: true}
|
||||
data: {$ref: '#/components/schemas/BatchReviewPreview'}
|
||||
BatchReviewPreview:
|
||||
type: object
|
||||
required: [total, approvableCount, items]
|
||||
properties:
|
||||
total: {type: integer, minimum: 1, maximum: 100}
|
||||
approvableCount: {type: integer, minimum: 0, maximum: 100}
|
||||
items:
|
||||
type: array
|
||||
items: {$ref: '#/components/schemas/BatchReviewPreviewItem'}
|
||||
BatchReviewPreviewItem:
|
||||
type: object
|
||||
required: [orderId, orderVersion, chineseGoodsNames, canApprove]
|
||||
properties:
|
||||
orderId: {type: string, pattern: '^[1-9][0-9]*$', description: 仅供路由关联,不作为主要展示键}
|
||||
orderVersion: {type: integer, minimum: 0}
|
||||
inboundCode: {type: string, nullable: true, description: 权威入仓码;缺失时为 null,不以内部 ID 回退}
|
||||
customerId: {type: string, nullable: true, pattern: '^[1-9][0-9]*$'}
|
||||
customerName: {type: string, nullable: true}
|
||||
chineseGoodsNames: {type: array, items: {type: string}, description: 按订单货物顺序去重的中文品名}
|
||||
channelCode: {type: string, nullable: true}
|
||||
channelName: {type: string, nullable: true}
|
||||
destinationWarehouseCode: {type: string, nullable: true, description: Order 保存的目的仓业务编码;缺失时不以内部 ID 回退}
|
||||
destinationWarehouseName: {type: string, nullable: true}
|
||||
canApprove: {type: boolean}
|
||||
blockReason: {type: string, nullable: true}
|
||||
DomesticWarehouseOrderExportBatchRequest:
|
||||
type: object
|
||||
required: [taskId, tenantId, appCode, requestedBy, dispatchVersion, parameters, limit]
|
||||
|
||||
Reference in New Issue
Block a user