修改提交
This commit is contained in:
@@ -34,7 +34,7 @@ public record OrderApprovedInboundCommand(
|
||||
Integer totalPackageCount,
|
||||
String pickupMethod,
|
||||
LocalDateTime requestedPickupAt,
|
||||
String fulfillmentType
|
||||
String fulfillmentType, String lxCodes
|
||||
) {
|
||||
public OrderApprovedInboundCommand(
|
||||
long tenantId, long orderId, String orderNo, String inboundCode, Long customerId, String customerName,
|
||||
@@ -49,7 +49,7 @@ public record OrderApprovedInboundCommand(
|
||||
deliveryWarehouseId, deliveryWarehouseName, expectedArrivalAt, businessType, channelCode, channelName,
|
||||
carrierId, carrierName, taxMode, pricingTaxMode, containerMode, customsInspection, destinationType,
|
||||
destinationWarehouseId, destinationCode, destinationName, publicRemark, expressCompanyName,
|
||||
expressTrackingNo, totalPackageCount, null, null, "STANDARD");
|
||||
expressTrackingNo, totalPackageCount, null, null, "STANDARD", null);
|
||||
}
|
||||
/** 兼容尚未携带订单总箱数的历史事件。 */
|
||||
public OrderApprovedInboundCommand(
|
||||
@@ -64,7 +64,7 @@ public record OrderApprovedInboundCommand(
|
||||
deliveryWarehouseId, deliveryWarehouseName, expectedArrivalAt, businessType, channelCode, channelName,
|
||||
carrierId, carrierName, taxMode, pricingTaxMode, containerMode, customsInspection, destinationType,
|
||||
destinationWarehouseId, destinationCode, destinationName, publicRemark, expressCompanyName,
|
||||
expressTrackingNo, null, null, null, "STANDARD");
|
||||
expressTrackingNo, null, null, null, "STANDARD", null);
|
||||
}
|
||||
|
||||
/** 兼容未携带报价包税维度的历史调用方。 */
|
||||
@@ -80,6 +80,6 @@ public record OrderApprovedInboundCommand(
|
||||
deliveryWarehouseId, deliveryWarehouseName, expectedArrivalAt, businessType, channelCode, channelName,
|
||||
carrierId, carrierName, taxMode, null, containerMode, customsInspection, destinationType,
|
||||
destinationWarehouseId, destinationCode, destinationName, publicRemark, expressCompanyName,
|
||||
expressTrackingNo, null, null, null, "STANDARD");
|
||||
expressTrackingNo, null, null, null, "STANDARD", null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ public class InboundOrderEntity extends BaseEntity {
|
||||
private String deliveryWarehouseName;
|
||||
private String businessType;
|
||||
private String fulfillmentType;
|
||||
private String lxCodes;
|
||||
private String channelCode;
|
||||
private String channelName;
|
||||
private Long carrierId;
|
||||
|
||||
@@ -69,6 +69,7 @@ public class InboundOrderCreationService {
|
||||
inbound.setDeliveryWarehouseName(command.deliveryWarehouseName());
|
||||
inbound.setBusinessType(command.businessType());
|
||||
inbound.setFulfillmentType(fulfillmentType(command.fulfillmentType()));
|
||||
inbound.setLxCodes("ONE_CLICK_DROPSHIP".equals(inbound.getFulfillmentType()) ? command.lxCodes() : null);
|
||||
inbound.setChannelCode(command.channelCode());
|
||||
inbound.setChannelName(command.channelName());
|
||||
inbound.setCarrierId(command.carrierId());
|
||||
@@ -221,6 +222,7 @@ public class InboundOrderCreationService {
|
||||
inbound.setDeliveryWarehouseName(command.deliveryWarehouseName());
|
||||
inbound.setBusinessType(command.businessType());
|
||||
inbound.setFulfillmentType(fulfillmentType(command.fulfillmentType()));
|
||||
inbound.setLxCodes("ONE_CLICK_DROPSHIP".equals(inbound.getFulfillmentType()) ? command.lxCodes() : null);
|
||||
inbound.setChannelCode(command.channelCode());
|
||||
inbound.setChannelName(command.channelName());
|
||||
inbound.setCarrierId(command.carrierId());
|
||||
|
||||
@@ -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:
|
||||
|
||||
+74
-1
@@ -40,6 +40,7 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class RelabelApplicationServiceTest {
|
||||
@@ -98,7 +99,7 @@ class RelabelApplicationServiceTest {
|
||||
assertEquals("RELABEL:PENDING_PROCESSING", tailOrder.getValue().getSubOrderStatus());
|
||||
assertEquals("CUSTOMER", tailOrder.getValue().getSourceRegion());
|
||||
assertTrue(tailOrder.getValue().getOrderNo().matches("RL-WH-\\d{8}-\\d{6}"));
|
||||
assertEquals(tailOrder.getValue().getInboundCode(), tailOrder.getValue().getSourceInboundId());
|
||||
assertEquals(tailOrder.getValue().getInboundCode() + ":WH-1", tailOrder.getValue().getSourceInboundId());
|
||||
assertEquals(tailOrder.getValue().getInboundCode(), application.getValue().getRelabelNo());
|
||||
assertTrue(tailOrder.getValue().getInboundCode().startsWith("RL-"));
|
||||
assertEquals(10, tailOrder.getValue().getPackageCount());
|
||||
@@ -120,6 +121,71 @@ class RelabelApplicationServiceTest {
|
||||
verify(items, never()).insert(any(RelabelItem.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createPersistsCartonMarkBinding() {
|
||||
RelabelRequests.Item attachedItem = new RelabelRequests.Item("SKU-A", null, null, null,
|
||||
"Chinese name", 2, 2, "SHP-1", null, "SKU-NEW", null, null, null, null, null,
|
||||
"BOX-1", "FBA-BOX-1", "WH-1");
|
||||
RelabelRequests.Create request = new RelabelRequests.Create("CUSTOMER-1", "WH-1",
|
||||
LocalDateTime.of(2026, 8, 20, 10, 0), "Li", "13800000000", BigDecimal.ONE, null, "key-marks",
|
||||
List.of(attachedItem));
|
||||
RelabelApplication persisted = application(11L, "FBR-1", "100", "key-files", null,
|
||||
RelabelApplicationService.PENDING_PROCESSING);
|
||||
persisted.setLastlegOrderId(21L); persisted.setItemCount(1); persisted.setTotalPackageCount(2);
|
||||
persisted.setNotifiedPackageCount(2);
|
||||
when(applications.findNo(eq("100"), any())).thenReturn(persisted);
|
||||
when(items.selectList(any())).thenReturn(List.of(item(31L, 11L, "SKU-A", 2, 2)));
|
||||
when(histories.selectList(any())).thenReturn(List.of());
|
||||
when(orders.selectById(21L)).thenReturn(order(21L, "100", "LMO-RELABEL-1",
|
||||
RelabelApplicationService.PENDING_PROCESSING));
|
||||
|
||||
service.create("100", "operator-1", request);
|
||||
|
||||
ArgumentCaptor<RelabelItem> saved = ArgumentCaptor.forClass(RelabelItem.class);
|
||||
verify(items).insert(saved.capture());
|
||||
assertEquals("BOX-1", saved.getValue().getCartonMark());
|
||||
assertEquals("FBA-BOX-1", saved.getValue().getFbaCartonMark());
|
||||
assertEquals("WH-1", saved.getValue().getDestinationWarehouseId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createGroupsCartonsIntoOneTailOrderPerDestinationWarehouse() {
|
||||
RelabelRequests.Item west = carton("SKU-A", "BOX-1", "FBA-1", "ONT8");
|
||||
RelabelRequests.Item east = carton("SKU-B", "BOX-2", "FBA-2", "ABE8");
|
||||
RelabelRequests.Create request = new RelabelRequests.Create("CUSTOMER-1", null,
|
||||
LocalDateTime.of(2026, 8, 20, 10, 0), "Li", "13800000000", BigDecimal.ONE, null, "key-multi",
|
||||
List.of(west, east));
|
||||
RelabelApplication persisted = application(11L, "FBR-1", "10001", "key-multi", null,
|
||||
RelabelApplicationService.PENDING_PROCESSING);
|
||||
persisted.setLastlegOrderId(21L);
|
||||
when(applications.findNo(eq("10001"), any())).thenReturn(persisted);
|
||||
when(items.selectList(any())).thenReturn(List.of(item(31L, 11L, "SKU-A", 1, 1)));
|
||||
when(histories.selectList(any())).thenReturn(List.of());
|
||||
when(orders.selectById(21L)).thenReturn(order(21L, "10001", "LMO-RELABEL-1",
|
||||
RelabelApplicationService.PENDING_PROCESSING));
|
||||
|
||||
service.create("10001", "operator-1", request);
|
||||
|
||||
ArgumentCaptor<LastlegOrder> created = ArgumentCaptor.forClass(LastlegOrder.class);
|
||||
verify(orders, times(2)).insert(created.capture());
|
||||
assertEquals(List.of("ONT8", "ABE8"), created.getAllValues().stream()
|
||||
.map(LastlegOrder::getOverseasWarehouseId).toList());
|
||||
assertTrue(created.getAllValues().stream().allMatch(value -> value.getPackageCount() == 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createRejectsCartonWithoutDetailOrDefaultDestinationWarehouse() {
|
||||
RelabelRequests.Create request = new RelabelRequests.Create("CUSTOMER-1", null,
|
||||
LocalDateTime.of(2026, 8, 20, 10, 0), "Li", "13800000000", BigDecimal.ONE, null, "key-no-destination",
|
||||
List.of(carton("SKU-A", "BOX-1", "FBA-1", null)));
|
||||
|
||||
ResponseStatusException exception = assertThrows(ResponseStatusException.class,
|
||||
() -> service.create("10001", "operator-1", request));
|
||||
|
||||
assertEquals(400, exception.getStatusCode().value());
|
||||
verify(orders, never()).insert(any(LastlegOrder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sameIdempotencyKeyAndPayloadReturnsExistingApplicationWithoutWrites() {
|
||||
RelabelRequests.Create request = request("key-1", 10, 6);
|
||||
@@ -224,6 +290,13 @@ class RelabelApplicationServiceTest {
|
||||
"SKU-NEW", "Label on carton", "file-1", "relabel.pdf", "https://files/relabel.pdf")));
|
||||
}
|
||||
|
||||
private static RelabelRequests.Item carton(String sku, String cartonMark, String fbaCartonMark,
|
||||
String destinationWarehouseId) {
|
||||
return new RelabelRequests.Item(sku, null, null, null, "Chinese name", 1, 1,
|
||||
"SHP-1", null, sku + "-NEW", null, null, null, null, null,
|
||||
cartonMark, fbaCartonMark, destinationWarehouseId);
|
||||
}
|
||||
|
||||
private static RelabelApplication application(long id, String no, String customerId, String key, String requestHash,
|
||||
String status) {
|
||||
RelabelApplication value = new RelabelApplication();
|
||||
|
||||
@@ -60,7 +60,7 @@ public interface FirstlegInboundClient {
|
||||
Boolean customsInspection, String destinationType, Long destinationWarehouseId,
|
||||
String destinationCode, String destinationName, String publicRemark,
|
||||
String expressCompanyName, String expressTrackingNo, Integer totalPackageCount,
|
||||
String pickupMethod, LocalDateTime requestedPickupAt, String fulfillmentType
|
||||
String pickupMethod, LocalDateTime requestedPickupAt, String fulfillmentType, String lxCodes
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ public final class OrderRequests {
|
||||
@Size(max = 40) @Pattern(regexp = "[A-Za-z0-9._:-]+") String inboundCode,
|
||||
@Schema(description = "Fulfillment type; omitted means STANDARD / 履约类型;省略时为普通头程", allowableValues = {"STANDARD", "ONE_CLICK_DROPSHIP"}, defaultValue = "STANDARD")
|
||||
@Pattern(regexp = "STANDARD|ONE_CLICK_DROPSHIP") String fulfillmentType,
|
||||
@Schema(description = "Lingxing inbound codes for one-click dropship; multiple values separated by comma, space or newline", maxLength = 1000)
|
||||
@Size(max = 1000) String lxCodes,
|
||||
@Schema(description = "Selected customer pickup address ID; required for PICKUP / 已选客户取货地址 ID;PICKUP 时必填")
|
||||
@Min(1) Long senderAddressId,
|
||||
@Schema(description = "Selected private destination address ID; required for PRIVATE / 已选私人目的仓地址 ID;PRIVATE 时必填")
|
||||
@@ -96,7 +98,7 @@ public final class OrderRequests {
|
||||
sender, receiver, cargoes, pickupMethod, requestedPickupAt, receivingWarehouseId,
|
||||
receivingWarehouseName, channelCode, channelName, carrierId, carrierName, taxMode,
|
||||
pricingTaxMode, containerMode, customsInspection, destinationType, amazonWarehouseCode,
|
||||
shipmentId, referenceId, inboundCode, fulfillmentType, null, null);
|
||||
shipmentId, referenceId, inboundCode, fulfillmentType, null, null, null);
|
||||
}
|
||||
|
||||
public SaveRequest(Long customerId, String customerName, String transportMode, String tradeTerm,
|
||||
@@ -114,7 +116,7 @@ public final class OrderRequests {
|
||||
sender, receiver, cargoes, pickupMethod, requestedPickupAt, receivingWarehouseId,
|
||||
receivingWarehouseName, channelCode, channelName, carrierId, carrierName, taxMode,
|
||||
pricingTaxMode, containerMode, customsInspection, destinationType, amazonWarehouseCode,
|
||||
shipmentId, referenceId, inboundCode, null, null, null);
|
||||
shipmentId, referenceId, inboundCode, null, null, null, null);
|
||||
}
|
||||
|
||||
public SaveRequest(Long customerId, String customerName, String transportMode, String tradeTerm,
|
||||
@@ -131,7 +133,7 @@ public final class OrderRequests {
|
||||
sender, receiver, cargoes, pickupMethod, requestedPickupAt, receivingWarehouseId,
|
||||
receivingWarehouseName, channelCode, channelName, carrierId, carrierName, taxMode,
|
||||
pricingTaxMode, containerMode, customsInspection, destinationType, amazonWarehouseCode,
|
||||
shipmentId, referenceId, null, null, null, null);
|
||||
shipmentId, referenceId, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public SaveRequest(Long customerId, String customerName, String transportMode, String tradeTerm,
|
||||
@@ -148,7 +150,7 @@ public final class OrderRequests {
|
||||
sender, receiver, cargoes, pickupMethod, null, receivingWarehouseId,
|
||||
receivingWarehouseName, channelCode, channelName, carrierId, carrierName, taxMode,
|
||||
pricingTaxMode, containerMode, customsInspection, destinationType, amazonWarehouseCode,
|
||||
shipmentId, referenceId, null, null, null, null);
|
||||
shipmentId, referenceId, null, null, null, null, null);
|
||||
}
|
||||
|
||||
@AssertTrue(message = "承运商 ID 和名称必须同时填写或同时留空")
|
||||
|
||||
@@ -52,6 +52,7 @@ public class OrderEntity extends BaseEntity {
|
||||
private Boolean customsInspection;
|
||||
private String destinationType;
|
||||
private String fulfillmentType;
|
||||
private String lxCodes;
|
||||
private String amazonWarehouseCode;
|
||||
private String shipmentId;
|
||||
private String referenceId;
|
||||
|
||||
@@ -488,6 +488,7 @@ public class OrderApplicationService {
|
||||
order.setContainerMode(request.containerMode()); order.setCustomsInspection(request.customsInspection());
|
||||
order.setDestinationType(request.destinationType());
|
||||
order.setFulfillmentType(fulfillmentType(request.fulfillmentType()));
|
||||
order.setLxCodes("ONE_CLICK_DROPSHIP".equals(order.getFulfillmentType()) ? normalizeLxCodes(request.lxCodes()) : null);
|
||||
order.setAmazonWarehouseCode("FBA".equals(request.destinationType()) && snapshots.destination() != null
|
||||
? snapshots.destination().warehouse().warehouseCode() : request.amazonWarehouseCode());
|
||||
order.setShipmentId(request.shipmentId()); order.setReferenceId(request.referenceId());
|
||||
@@ -519,6 +520,11 @@ public class OrderApplicationService {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED,
|
||||
"履约类型必须为 STANDARD 或 ONE_CLICK_DROPSHIP");
|
||||
}
|
||||
private static String normalizeLxCodes(String value) {
|
||||
if (value == null || value.isBlank()) return null;
|
||||
return java.util.Arrays.stream(value.trim().split("[,,\\s]+"))
|
||||
.map(String::trim).filter(item -> !item.isEmpty()).distinct().collect(java.util.stream.Collectors.joining(","));
|
||||
}
|
||||
private boolean legacyManualMode() {
|
||||
return inboundCodeModeProvider.legacyManual();
|
||||
}
|
||||
@@ -683,7 +689,7 @@ public class OrderApplicationService {
|
||||
order.getDestinationWarehouseId(), order.getAmazonWarehouseCode(), order.getDestinationWarehouseName(),
|
||||
order.getCustomerRemark(), order.getExpressCompany(), order.getExpressTrackingNo(), totalPackageCount,
|
||||
order.getPickupMethod(), order.getRequestedPickupAt(),
|
||||
order.getFulfillmentType() == null ? "STANDARD" : order.getFulfillmentType());
|
||||
order.getFulfillmentType() == null ? "STANDARD" : order.getFulfillmentType(), order.getLxCodes());
|
||||
}
|
||||
private void prepareDraftInbound(OrderEntity order, OrderRequests.SaveRequest request) {
|
||||
FirstlegInboundClient client = firstlegProvider == null ? null : firstlegProvider.getIfAvailable();
|
||||
|
||||
@@ -1049,8 +1049,9 @@ CREATE TABLE IF NOT EXISTS ll_relabel_item (
|
||||
product_image_file_name VARCHAR(255) NULL COMMENT '产品图片文件名', product_image_url VARCHAR(1000) NULL COMMENT '产品图片地址',
|
||||
product_name_zh VARCHAR(255) NOT NULL COMMENT '产品中文名称', total_package_count INT NOT NULL COMMENT '总箱数', notified_package_count INT NOT NULL COMMENT '已通知箱数',
|
||||
shipment_no VARCHAR(128) NOT NULL COMMENT '货件编号', tracking_code VARCHAR(255) NULL COMMENT '物流跟踪编码', new_sku_code VARCHAR(128) NOT NULL COMMENT '换标后SKU编码',
|
||||
label_requirement VARCHAR(1000) NULL COMMENT '换标要求', relabel_file_id VARCHAR(128) NULL COMMENT '换标文件ID',
|
||||
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) NULL COMMENT '该箱目的海外仓ID',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB COMMENT='换标货物冻结明细';
|
||||
|
||||
@@ -2911,6 +2912,16 @@ SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE tab
|
||||
PREPARE schema_comments_025 FROM @ddl; EXECUTE schema_comments_025; DEALLOCATE PREPARE schema_comments_025;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='label_requirement' AND COALESCE(column_comment,'') <> '换标要求'), 'ALTER TABLE ll_relabel_item MODIFY COLUMN label_requirement VARCHAR(1000) NULL COMMENT ''换标要求''', 'SELECT 1'));
|
||||
PREPARE schema_comments_025 FROM @ddl; EXECUTE schema_comments_025; DEALLOCATE PREPARE schema_comments_025;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='remark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN remark VARCHAR(1000) NULL COMMENT ''货物明细备注'' AFTER label_requirement'));
|
||||
PREPARE schema_comments_025 FROM @ddl; EXECUTE schema_comments_025; DEALLOCATE PREPARE schema_comments_025;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN carton_mark VARCHAR(255) NULL COMMENT ''客户自有箱唛'' AFTER relabel_file_url'));
|
||||
PREPARE schema_comments_025 FROM @ddl; EXECUTE schema_comments_025; DEALLOCATE PREPARE schema_comments_025;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='fba_carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN fba_carton_mark VARCHAR(255) NULL COMMENT ''关联FBA箱唛'' AFTER carton_mark'));
|
||||
PREPARE schema_comments_025 FROM @ddl; EXECUTE schema_comments_025; DEALLOCATE PREPARE schema_comments_025;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='destination_warehouse_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT ''该箱目的海外仓ID'' AFTER fba_carton_mark'));
|
||||
PREPARE schema_comments_025 FROM @ddl; EXECUTE schema_comments_025; DEALLOCATE PREPARE schema_comments_025;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND index_name='idx_ll_relabel_item_destination'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD KEY idx_ll_relabel_item_destination (customer_id,destination_warehouse_id,application_id)'));
|
||||
PREPARE schema_comments_025 FROM @ddl; EXECUTE schema_comments_025; DEALLOCATE PREPARE schema_comments_025;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='relabel_file_id' AND COALESCE(column_comment,'') <> '换标文件ID'), 'ALTER TABLE ll_relabel_item MODIFY COLUMN relabel_file_id VARCHAR(128) NULL COMMENT ''换标文件ID''', 'SELECT 1'));
|
||||
PREPARE schema_comments_025 FROM @ddl; EXECUTE schema_comments_025; DEALLOCATE PREPARE schema_comments_025;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='relabel_file_name' AND COALESCE(column_comment,'') <> '换标文件名'), 'ALTER TABLE ll_relabel_item MODIFY COLUMN relabel_file_name VARCHAR(255) NULL COMMENT ''换标文件名''', 'SELECT 1'));
|
||||
|
||||
Reference in New Issue
Block a user