修改提交
This commit is contained in:
@@ -19,7 +19,7 @@ public final class RelabelRequests {
|
||||
|
||||
public record Create(
|
||||
@NotBlank @Size(max = 128) String customerOrderNo,
|
||||
@NotBlank @Size(max = 128) String overseasWarehouseId,
|
||||
@Size(max = 128) String overseasWarehouseId,
|
||||
@NotNull LocalDateTime labelDeadline,
|
||||
@NotBlank @Size(max = 128) String contactName,
|
||||
@NotBlank @Size(max = 64) String contactPhone,
|
||||
@@ -41,10 +41,23 @@ public final class RelabelRequests {
|
||||
@Size(max = 255) String trackingCode,
|
||||
@NotBlank @Size(max = 128) String newSkuCode,
|
||||
@Size(max = 1000) String labelRequirement,
|
||||
@Size(max = 1000) String remark,
|
||||
@Size(max = 128) String relabelFileId,
|
||||
@Size(max = 255) String relabelFileName,
|
||||
@Size(max = 1000) String relabelFileUrl
|
||||
) {}
|
||||
@Size(max = 1000) String relabelFileUrl,
|
||||
@NotBlank @Size(max = 255) String cartonMark,
|
||||
@NotBlank @Size(max = 255) String fbaCartonMark,
|
||||
@Size(max = 128) String destinationWarehouseId
|
||||
) {
|
||||
public Item(String skuCode, String productImageFileId, String productImageFileName,
|
||||
String productImageUrl, String productNameZh, int totalPackageCount,
|
||||
int notifiedPackageCount, String shipmentNo, String trackingCode, String newSkuCode,
|
||||
String labelRequirement, String relabelFileId, String relabelFileName, String relabelFileUrl) {
|
||||
this(skuCode, productImageFileId, productImageFileName, productImageUrl, productNameZh,
|
||||
totalPackageCount, notifiedPackageCount, shipmentNo, trackingCode, newSkuCode,
|
||||
labelRequirement, null, relabelFileId, relabelFileName, relabelFileUrl, skuCode, shipmentNo, null);
|
||||
}
|
||||
}
|
||||
|
||||
public record Query(@Min(1) long page, @Min(1) @Max(200) long size, String relabelNo,
|
||||
String customerOrderNo, String skuCode, String status,
|
||||
|
||||
@@ -17,9 +17,13 @@ public final class RelabelResponses {
|
||||
public record Item(Long id, String skuCode, String productImageFileId, String productImageFileName,
|
||||
String productImageUrl, String productNameZh, int totalPackageCount,
|
||||
int notifiedPackageCount, String shipmentNo, String trackingCode,
|
||||
String newSkuCode, String labelRequirement, String relabelFileId,
|
||||
String relabelFileName, String relabelFileUrl) {}
|
||||
String newSkuCode, String labelRequirement, String remark, String relabelFileId,
|
||||
String relabelFileName, String relabelFileUrl,
|
||||
String cartonMark, String fbaCartonMark, String destinationWarehouseId) {}
|
||||
public record TailOrder(Long id, String orderNo, String overseasWarehouseId, int packageCount,
|
||||
String status) {}
|
||||
public record History(String fromStatus, String toStatus, String operatorId,
|
||||
String remark, LocalDateTime createdAt) {}
|
||||
public record Detail(Summary application, String remark, List<Item> items, List<History> history) {}
|
||||
public record Detail(Summary application, String remark, List<Item> items, List<History> history,
|
||||
List<TailOrder> tailOrders) {}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,12 @@ public class RelabelItem {
|
||||
private String trackingCode;
|
||||
private String newSkuCode;
|
||||
private String labelRequirement;
|
||||
private String remark;
|
||||
private String relabelFileId;
|
||||
private String relabelFileName;
|
||||
private String relabelFileUrl;
|
||||
private String cartonMark;
|
||||
private String fbaCartonMark;
|
||||
private String destinationWarehouseId;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
|
||||
+95
-57
@@ -33,7 +33,9 @@ import java.security.MessageDigest;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HexFormat;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -56,12 +58,15 @@ public class RelabelApplicationService implements WalletResultHandler {
|
||||
public RelabelResponses.Detail create(String customerId, String operatorId, RelabelRequests.Create request) {
|
||||
int total = 0;
|
||||
int notified = 0;
|
||||
Map<String, Integer> packagesByWarehouse = new LinkedHashMap<>();
|
||||
for (RelabelRequests.Item item : request.items()) {
|
||||
if (item.notifiedPackageCount() > item.totalPackageCount()) {
|
||||
throw badRequest("Notified relocation packages cannot exceed total packages for SKU " + item.skuCode());
|
||||
}
|
||||
total = Math.addExact(total, item.totalPackageCount());
|
||||
notified = Math.addExact(notified, item.notifiedPackageCount());
|
||||
String warehouseId = destination(item, request.overseasWarehouseId());
|
||||
packagesByWarehouse.merge(warehouseId, item.totalPackageCount(), Math::addExact);
|
||||
}
|
||||
String requestHash = hash(request);
|
||||
RelabelApplication replay = applications.findKey(customerId, request.idempotencyKey().trim());
|
||||
@@ -71,40 +76,20 @@ public class RelabelApplicationService implements WalletResultHandler {
|
||||
}
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
long applicationId = IdWorker.getId();
|
||||
String relabelNo = orderNoGenerator.next("RELABEL", request.overseasWarehouseId(), applicationId);
|
||||
LastlegOrder order = new LastlegOrder();
|
||||
order.setId(IdWorker.getId());
|
||||
order.setOrderNo(orderNoGenerator.next("RELABEL", request.overseasWarehouseId(), order.getId()));
|
||||
order.setCustomerId(customerId);
|
||||
order.setOrderType("RELABEL_APPLICATION");
|
||||
order.setInboundCode(relabelNo);
|
||||
order.setSourceRegion("CUSTOMER");
|
||||
order.setSourceInboundId(relabelNo);
|
||||
order.setSourceOrderNo(request.customerOrderNo().trim());
|
||||
order.setOverseasWarehouseId(request.overseasWarehouseId().trim());
|
||||
order.setPalletCount(0);
|
||||
order.setPackageCount(total);
|
||||
order.setPickedPackageCount(0);
|
||||
order.setShippedPackageCount(0);
|
||||
order.setCurrentStatus("PENDING_ASSIGNMENT");
|
||||
order.setSubOrderStatus("RELABEL:" + PENDING_PROCESSING);
|
||||
order.setRelabelOrderNo(relabelNo);
|
||||
order.setRelabelStatus(PENDING_PROCESSING);
|
||||
order.setCustomerRemark(trim(request.remark()));
|
||||
order.setSourceEventId("CUSTOMER_RELABEL:" + relabelNo);
|
||||
order.setSourceLoadingPlanId("RELABEL_APPLICATION");
|
||||
order.setSourcePayloadHash("sha256:" + requestHash);
|
||||
order.setCreatedAt(now);
|
||||
order.setUpdatedAt(now);
|
||||
orders.insert(order);
|
||||
String primaryWarehouseId = packagesByWarehouse.keySet().iterator().next();
|
||||
String relabelNo = orderNoGenerator.next("RELABEL", primaryWarehouseId, applicationId);
|
||||
List<LastlegOrder> tailOrders = packagesByWarehouse.entrySet().stream()
|
||||
.map(entry -> insertTailOrder(customerId, request, requestHash, relabelNo,
|
||||
entry.getKey(), entry.getValue(), now))
|
||||
.toList();
|
||||
|
||||
RelabelApplication application = new RelabelApplication();
|
||||
application.setId(applicationId);
|
||||
application.setCustomerId(customerId);
|
||||
application.setRelabelNo(relabelNo);
|
||||
application.setLastlegOrderId(order.getId());
|
||||
application.setLastlegOrderId(tailOrders.get(0).getId());
|
||||
application.setCustomerOrderNo(request.customerOrderNo().trim());
|
||||
application.setOverseasWarehouseId(request.overseasWarehouseId().trim());
|
||||
application.setOverseasWarehouseId(primaryWarehouseId);
|
||||
application.setLabelDeadline(request.labelDeadline());
|
||||
application.setContactName(request.contactName().trim());
|
||||
application.setContactPhone(request.contactPhone().trim());
|
||||
@@ -128,10 +113,12 @@ public class RelabelApplicationService implements WalletResultHandler {
|
||||
application.setWalletCommandEventId(walletEventId);
|
||||
applications.updateById(application);
|
||||
|
||||
for (RelabelRequests.Item source : request.items()) insertItem(customerId, applicationId, source, now);
|
||||
for (RelabelRequests.Item source : request.items()) {
|
||||
insertItem(customerId, applicationId, source, request.overseasWarehouseId(), now);
|
||||
}
|
||||
insertHistory(customerId, applicationId, null, PENDING_PROCESSING, operatorId, "Relabel application submitted", now);
|
||||
insertOrderHistory(customerId, order.getId(), null, order.getCurrentStatus(),
|
||||
"Relabel application submitted", now);
|
||||
tailOrders.forEach(order -> insertOrderHistory(customerId, order.getId(), null,
|
||||
order.getCurrentStatus(), "Relabel application submitted", now));
|
||||
return detail(customerId, relabelNo);
|
||||
}
|
||||
|
||||
@@ -145,7 +132,9 @@ public class RelabelApplicationService implements WalletResultHandler {
|
||||
.like(StringUtils.hasText(query.relabelNo()), RelabelApplication::getRelabelNo, query.relabelNo())
|
||||
.like(StringUtils.hasText(query.customerOrderNo()), RelabelApplication::getCustomerOrderNo, query.customerOrderNo())
|
||||
.eq(StringUtils.hasText(query.status()), RelabelApplication::getStatus, query.status())
|
||||
.eq(StringUtils.hasText(query.overseasWarehouseId()), RelabelApplication::getOverseasWarehouseId, query.overseasWarehouseId())
|
||||
.apply(StringUtils.hasText(query.overseasWarehouseId()),
|
||||
"EXISTS (SELECT 1 FROM ll_relabel_item rw WHERE rw.application_id=ll_relabel_application.id AND rw.customer_id=ll_relabel_application.customer_id AND rw.destination_warehouse_id={0})",
|
||||
query.overseasWarehouseId())
|
||||
.ge(query.createdFrom() != null, RelabelApplication::getCreatedAt, query.createdFrom())
|
||||
.le(query.createdTo() != null, RelabelApplication::getCreatedAt, query.createdTo())
|
||||
.apply(StringUtils.hasText(query.skuCode()),
|
||||
@@ -166,10 +155,13 @@ public class RelabelApplicationService implements WalletResultHandler {
|
||||
.eq(RelabelStatusHistory::getCustomerId, recordCustomerId)
|
||||
.eq(RelabelStatusHistory::getApplicationId, application.getId())
|
||||
.orderByAsc(RelabelStatusHistory::getCreatedAt));
|
||||
List<LastlegOrder> tailOrders = tailOrders(application);
|
||||
return new RelabelResponses.Detail(summary(application, detailItems), application.getRemark(),
|
||||
detailItems.stream().map(this::item).toList(), statusHistory.stream().map(value ->
|
||||
new RelabelResponses.History(value.getFromStatus(), value.getToStatus(), value.getOperatorId(),
|
||||
value.getRemark(), value.getCreatedAt())).toList());
|
||||
value.getRemark(), value.getCreatedAt())).toList(), tailOrders.stream().map(value ->
|
||||
new RelabelResponses.TailOrder(value.getId(), value.getOrderNo(), value.getOverseasWarehouseId(),
|
||||
Objects.requireNonNullElse(value.getPackageCount(), 0), value.getCurrentStatus())).toList());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -201,30 +193,32 @@ public class RelabelApplicationService implements WalletResultHandler {
|
||||
"换标取消,释放冻结", 2L);
|
||||
application.setWalletStatus("RELEASE_PENDING"); applications.updateById(application);
|
||||
}
|
||||
LastlegOrder order = orders.selectById(application.getLastlegOrderId());
|
||||
if (order == null || !customerId.equals(order.getCustomerId())) throw conflict("Linked tail-leg order is missing");
|
||||
String orderBefore = order.getCurrentStatus();
|
||||
String mainStatus = STATUSES.contains(orderBefore) ? "PENDING_ASSIGNMENT" : orderBefore;
|
||||
// A return-relabel tail order joins the normal inbound queue after labels are finished.
|
||||
String orderStatus = switch (next) {
|
||||
case "COMPLETED" -> "RETURN_RELABEL".equals(order.getOrderType())
|
||||
? "PENDING_ASSIGNMENT" : "COMPLETED";
|
||||
case "REJECTED", "CANCELLED" -> "CANCELLED";
|
||||
default -> mainStatus;
|
||||
};
|
||||
order.setCurrentStatus(orderStatus);
|
||||
order.setSubOrderStatus("RELABEL:" + next);
|
||||
order.setRelabelStatus(next);
|
||||
order.setUpdatedAt(now);
|
||||
orders.updateById(order);
|
||||
insertHistory(customerId, application.getId(), before, next, operatorId, request.remark(), now);
|
||||
if (!Objects.equals(orderBefore, orderStatus)) {
|
||||
insertOrderHistory(customerId, order.getId(), orderBefore, orderStatus, request.remark(), now);
|
||||
List<LastlegOrder> linkedOrders = tailOrders(application);
|
||||
if (linkedOrders.isEmpty()) throw conflict("Linked tail-leg order is missing");
|
||||
for (LastlegOrder order : linkedOrders) {
|
||||
String orderBefore = order.getCurrentStatus();
|
||||
String mainStatus = STATUSES.contains(orderBefore) ? "PENDING_ASSIGNMENT" : orderBefore;
|
||||
String orderStatus = switch (next) {
|
||||
case "COMPLETED" -> "RETURN_RELABEL".equals(order.getOrderType())
|
||||
? "PENDING_ASSIGNMENT" : "COMPLETED";
|
||||
case "REJECTED", "CANCELLED" -> "CANCELLED";
|
||||
default -> mainStatus;
|
||||
};
|
||||
order.setCurrentStatus(orderStatus);
|
||||
order.setSubOrderStatus("RELABEL:" + next);
|
||||
order.setRelabelStatus(next);
|
||||
order.setUpdatedAt(now);
|
||||
orders.updateById(order);
|
||||
if (!Objects.equals(orderBefore, orderStatus)) {
|
||||
insertOrderHistory(customerId, order.getId(), orderBefore, orderStatus, request.remark(), now);
|
||||
}
|
||||
}
|
||||
insertHistory(customerId, application.getId(), before, next, operatorId, request.remark(), now);
|
||||
return detail(customerId, relabelNo);
|
||||
}
|
||||
|
||||
private void insertItem(String customerId, long applicationId, RelabelRequests.Item source, LocalDateTime now) {
|
||||
private void insertItem(String customerId, long applicationId, RelabelRequests.Item source,
|
||||
String defaultWarehouseId, LocalDateTime now) {
|
||||
RelabelItem item = new RelabelItem();
|
||||
item.setId(IdWorker.getId()); item.setApplicationId(applicationId); item.setCustomerId(customerId);
|
||||
item.setSkuCode(source.skuCode().trim()); item.setProductImageFileId(trim(source.productImageFileId()));
|
||||
@@ -232,16 +226,21 @@ public class RelabelApplicationService implements WalletResultHandler {
|
||||
item.setProductNameZh(source.productNameZh().trim()); item.setTotalPackageCount(source.totalPackageCount());
|
||||
item.setNotifiedPackageCount(source.notifiedPackageCount()); item.setShipmentNo(source.shipmentNo().trim());
|
||||
item.setTrackingCode(trim(source.trackingCode())); item.setNewSkuCode(source.newSkuCode().trim());
|
||||
item.setLabelRequirement(trim(source.labelRequirement())); item.setRelabelFileId(trim(source.relabelFileId()));
|
||||
item.setLabelRequirement(trim(source.labelRequirement())); item.setRemark(trim(source.remark())); item.setRelabelFileId(trim(source.relabelFileId()));
|
||||
item.setRelabelFileName(trim(source.relabelFileName())); item.setRelabelFileUrl(trim(source.relabelFileUrl()));
|
||||
item.setCartonMark(source.cartonMark().trim()); item.setFbaCartonMark(source.fbaCartonMark().trim());
|
||||
item.setDestinationWarehouseId(destination(source, defaultWarehouseId));
|
||||
item.setCreatedAt(now); items.insert(item);
|
||||
}
|
||||
|
||||
private RelabelResponses.Summary summary(RelabelApplication value, List<RelabelItem> detailItems) {
|
||||
LastlegOrder order = orders.selectById(value.getLastlegOrderId());
|
||||
String skuCodes = detailItems.stream().map(RelabelItem::getSkuCode).filter(Objects::nonNull).distinct().collect(Collectors.joining(","));
|
||||
String warehouses = detailItems.stream().map(RelabelItem::getDestinationWarehouseId)
|
||||
.filter(StringUtils::hasText).distinct().collect(Collectors.joining(","));
|
||||
return new RelabelResponses.Summary(value.getId(), value.getRelabelNo(), value.getLastlegOrderId(),
|
||||
order == null ? null : order.getOrderNo(), value.getCustomerOrderNo(), value.getOverseasWarehouseId(),
|
||||
order == null ? null : order.getOrderNo(), value.getCustomerOrderNo(),
|
||||
StringUtils.hasText(warehouses) ? warehouses : value.getOverseasWarehouseId(),
|
||||
value.getLabelDeadline(), value.getContactName(), value.getContactPhone(), value.getStatus(),
|
||||
Objects.requireNonNullElse(value.getItemCount(), detailItems.size()),
|
||||
Objects.requireNonNullElse(value.getTotalPackageCount(), 0),
|
||||
@@ -276,8 +275,47 @@ public class RelabelApplicationService implements WalletResultHandler {
|
||||
return new RelabelResponses.Item(value.getId(), value.getSkuCode(), value.getProductImageFileId(),
|
||||
value.getProductImageFileName(), value.getProductImageUrl(), value.getProductNameZh(),
|
||||
value.getTotalPackageCount(), value.getNotifiedPackageCount(), value.getShipmentNo(),
|
||||
value.getTrackingCode(), value.getNewSkuCode(), value.getLabelRequirement(), value.getRelabelFileId(),
|
||||
value.getRelabelFileName(), value.getRelabelFileUrl());
|
||||
value.getTrackingCode(), value.getNewSkuCode(), value.getLabelRequirement(), value.getRemark(), value.getRelabelFileId(),
|
||||
value.getRelabelFileName(), value.getRelabelFileUrl(), value.getCartonMark(), value.getFbaCartonMark(),
|
||||
value.getDestinationWarehouseId());
|
||||
}
|
||||
|
||||
private LastlegOrder insertTailOrder(String customerId, RelabelRequests.Create request, String requestHash,
|
||||
String relabelNo, String warehouseId, int packageCount,
|
||||
LocalDateTime now) {
|
||||
LastlegOrder order = new LastlegOrder();
|
||||
order.setId(IdWorker.getId());
|
||||
order.setOrderNo(orderNoGenerator.next("RELABEL", warehouseId, order.getId()));
|
||||
order.setCustomerId(customerId); order.setOrderType("RELABEL_APPLICATION");
|
||||
order.setInboundCode(relabelNo); order.setSourceRegion("CUSTOMER");
|
||||
order.setSourceInboundId(relabelNo + ":" + warehouseId);
|
||||
order.setSourceOrderNo(request.customerOrderNo().trim()); order.setOverseasWarehouseId(warehouseId);
|
||||
order.setPalletCount(0); order.setPackageCount(packageCount); order.setPickedPackageCount(0);
|
||||
order.setShippedPackageCount(0); order.setCurrentStatus("PENDING_ASSIGNMENT");
|
||||
order.setSubOrderStatus("RELABEL:" + PENDING_PROCESSING); order.setRelabelOrderNo(relabelNo);
|
||||
order.setRelabelStatus(PENDING_PROCESSING); order.setCustomerRemark(trim(request.remark()));
|
||||
order.setSourceEventId("CUSTOMER_RELABEL:" + relabelNo + ":" + warehouseId);
|
||||
order.setSourceLoadingPlanId("RELABEL_APPLICATION"); order.setSourcePayloadHash("sha256:" + requestHash);
|
||||
order.setCreatedAt(now); order.setUpdatedAt(now); orders.insert(order);
|
||||
return order;
|
||||
}
|
||||
|
||||
private List<LastlegOrder> tailOrders(RelabelApplication application) {
|
||||
List<LastlegOrder> linked = orders.selectList(new LambdaQueryWrapper<LastlegOrder>()
|
||||
.eq(LastlegOrder::getCustomerId, application.getCustomerId())
|
||||
.eq(LastlegOrder::getRelabelOrderNo, application.getRelabelNo())
|
||||
.orderByAsc(LastlegOrder::getId));
|
||||
if (!linked.isEmpty()) return linked;
|
||||
LastlegOrder legacy = orders.selectById(application.getLastlegOrderId());
|
||||
return legacy == null ? List.of() : List.of(legacy);
|
||||
}
|
||||
|
||||
private static String destination(RelabelRequests.Item item, String fallback) {
|
||||
String value = StringUtils.hasText(item.destinationWarehouseId())
|
||||
? item.destinationWarehouseId().trim()
|
||||
: trim(fallback);
|
||||
if (!StringUtils.hasText(value)) throw badRequest("Destination warehouse is required for every carton");
|
||||
return value;
|
||||
}
|
||||
|
||||
private List<RelabelItem> itemList(Long applicationId) {
|
||||
|
||||
@@ -1456,9 +1456,13 @@ CREATE TABLE IF NOT EXISTS ll_relabel_item (
|
||||
tracking_code VARCHAR(255) NULL COMMENT '物流跟踪编码',
|
||||
new_sku_code VARCHAR(128) NOT NULL COMMENT '换标后SKU编码',
|
||||
label_requirement VARCHAR(1000) NULL COMMENT '换标要求',
|
||||
remark VARCHAR(1000) NULL COMMENT '货物明细备注',
|
||||
relabel_file_id VARCHAR(128) NULL COMMENT '换标文件ID',
|
||||
relabel_file_name VARCHAR(255) NULL COMMENT '换标文件名',
|
||||
relabel_file_url VARCHAR(1000) NULL COMMENT '换标文件地址',
|
||||
carton_mark VARCHAR(255) NULL COMMENT '客户自有箱唛',
|
||||
fba_carton_mark VARCHAR(255) NULL COMMENT '关联FBA箱唛',
|
||||
destination_warehouse_id VARCHAR(128) NOT NULL COMMENT '该箱目的海外仓ID',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_ll_relabel_item_application (customer_id,application_id),
|
||||
|
||||
@@ -678,27 +678,6 @@ paths:
|
||||
required: true
|
||||
content: { application/json: { schema: { $ref: '#/components/schemas/ProcurementReview' } } }
|
||||
responses: { '200': { description: 统一 ApiResponse 包装的采购订单详情 } }
|
||||
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/files/{category}:
|
||||
post:
|
||||
summary: 上传采购签收文件或费用凭证
|
||||
description: 权限 platform:overseas-business:purchase:edit;category 仅允许 RECEIPT 或 VOUCHER。
|
||||
security: [{ bearerAuth: [] }]
|
||||
parameters:
|
||||
- { name: orderNo, in: path, required: true, schema: { type: string } }
|
||||
- { name: category, in: path, required: true, schema: { type: string, enum: [RECEIPT, VOUCHER] } }
|
||||
- { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } }
|
||||
requestBody: { required: true, content: { multipart/form-data: { schema: { type: object, required: [file], properties: { file: { type: string, format: binary } } } } } }
|
||||
responses: { '200': { description: 已保存文件元数据 } }
|
||||
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/fees:
|
||||
post:
|
||||
summary: 登记采购费用并发起资金冻结
|
||||
description: 权限 platform:overseas-business:purchase:edit;订单必须已审核通过,费用凭证必须属于本订单。
|
||||
security: [{ bearerAuth: [] }]
|
||||
parameters:
|
||||
- { name: orderNo, in: path, required: true, schema: { type: string } }
|
||||
- { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } }
|
||||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ProcurementFeeCreate' } } } }
|
||||
responses: { '200': { description: 已创建费用并进入冻结流程 }, '409': { description: 订单状态或凭证不允许 } }
|
||||
/api/merchant/v1/last-leg/delivery-orders:
|
||||
get:
|
||||
summary: 客户分页查询自己的派送单
|
||||
@@ -1662,20 +1641,20 @@ components:
|
||||
RelabelStatus: { type: string, enum: [PENDING_PROCESSING, PROCESSING, COMPLETED, REJECTED, CANCELLED] }
|
||||
RelabelCreate:
|
||||
type: object
|
||||
required: [customerOrderNo, overseasWarehouseId, labelDeadline, contactName, contactPhone, chargeAmount, idempotencyKey, items]
|
||||
required: [customerOrderNo, labelDeadline, contactName, contactPhone, chargeAmount, idempotencyKey, items]
|
||||
properties:
|
||||
customerOrderNo: { type: string, maxLength: 128 }
|
||||
overseasWarehouseId: { type: string, maxLength: 128 }
|
||||
overseasWarehouseId: { type: string, nullable: true, maxLength: 128, description: 统一目的海外仓;明细未填写目的仓时使用 }
|
||||
labelDeadline: { type: string, format: date-time }
|
||||
contactName: { type: string, maxLength: 128 }
|
||||
contactPhone: { type: string, maxLength: 64 }
|
||||
chargeAmount: { type: number, minimum: 0.01, description: 换标费用,币种固定 CNY }
|
||||
chargeAmount: { type: number, minimum: 0.01, description: 本次贴标费用(CNY) }
|
||||
remark: { type: string, nullable: true, maxLength: 1000 }
|
||||
idempotencyKey: { type: string, maxLength: 255 }
|
||||
items: { type: array, minItems: 1, maxItems: 500, items: { $ref: '#/components/schemas/RelabelItem' } }
|
||||
RelabelItem:
|
||||
type: object
|
||||
required: [skuCode, productNameZh, totalPackageCount, notifiedPackageCount, shipmentNo, newSkuCode]
|
||||
required: [skuCode, productNameZh, totalPackageCount, notifiedPackageCount, shipmentNo, newSkuCode, cartonMark, fbaCartonMark]
|
||||
properties:
|
||||
skuCode: { type: string, maxLength: 128 }
|
||||
productImageFileId: { type: string, nullable: true, maxLength: 128 }
|
||||
@@ -1691,6 +1670,9 @@ components:
|
||||
relabelFileId: { type: string, nullable: true, maxLength: 128 }
|
||||
relabelFileName: { type: string, nullable: true, maxLength: 255 }
|
||||
relabelFileUrl: { type: string, nullable: true, maxLength: 1000 }
|
||||
cartonMark: { type: string, maxLength: 255, description: 客户自有箱唛(不在编辑列表展示) }
|
||||
fbaCartonMark: { type: string, maxLength: 255, description: 关联 FBA 箱唛 }
|
||||
destinationWarehouseId: { type: string, nullable: true, maxLength: 128, description: 该箱目的海外仓;为空时使用申请统一目的仓 }
|
||||
RelabelStatusChange:
|
||||
type: object
|
||||
required: [status]
|
||||
@@ -1786,7 +1768,7 @@ components:
|
||||
updatedAt: { type: string, format: date-time }
|
||||
ProcurementDetail:
|
||||
type: object
|
||||
required: [summary, histories, outboundDetails, files, fees]
|
||||
required: [summary, histories, outboundDetails]
|
||||
properties:
|
||||
summary: { $ref: '#/components/schemas/ProcurementSummary' }
|
||||
productUrl: { type: string, nullable: true }
|
||||
@@ -1805,42 +1787,6 @@ components:
|
||||
reviewedAt: { type: string, format: date-time, nullable: true }
|
||||
histories: { type: array, items: { $ref: '#/components/schemas/BusinessHistory' } }
|
||||
outboundDetails: { type: array, items: { $ref: '#/components/schemas/ProcurementOutboundDetail' } }
|
||||
files: { type: array, items: { $ref: '#/components/schemas/ProcurementFile' } }
|
||||
fees: { type: array, items: { $ref: '#/components/schemas/ProcurementFee' } }
|
||||
ProcurementFeeCreate:
|
||||
type: object
|
||||
required: [feeItemCode, feeItemName, amount, voucherFileId]
|
||||
properties:
|
||||
feeItemCode: { type: string, maxLength: 64 }
|
||||
feeItemName: { type: string, maxLength: 128 }
|
||||
amount: { type: number, minimum: 0.01 }
|
||||
voucherFileId: { type: string, pattern: '^[0-9]+$' }
|
||||
remark: { type: string, nullable: true, maxLength: 500 }
|
||||
ProcurementFile:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
category: { type: string, enum: [RECEIPT, VOUCHER] }
|
||||
fileId: { type: string }
|
||||
fileName: { type: string }
|
||||
contentType: { type: string, nullable: true }
|
||||
sizeBytes: { type: integer, format: int64 }
|
||||
createdAt: { type: string, format: date-time }
|
||||
ProcurementFee:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string }
|
||||
feeNo: { type: string }
|
||||
feeItemCode: { type: string }
|
||||
feeItemName: { type: string }
|
||||
amount: { type: number }
|
||||
currency: { type: string, enum: [CNY] }
|
||||
voucherFileId: { type: string }
|
||||
voucherFileName: { type: string }
|
||||
remark: { type: string, nullable: true }
|
||||
walletStatus: { type: string }
|
||||
walletErrorMessage: { type: string, nullable: true }
|
||||
createdAt: { type: string, format: date-time }
|
||||
ProcurementOutboundDetail:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
Reference in New Issue
Block a user