feat: complete dropship palletization workflow
This commit is contained in:
@@ -48,7 +48,8 @@ public interface FirstlegUnifiedOrderClient {
|
||||
Long deliveryWarehouseId, String deliveryWarehouseName, String channelCode, String channelName,
|
||||
Integer totalPackageCount, String locationCodes,
|
||||
LocalDateTime expectedArrivalAt, LocalDateTime requestedPickupAt, String feeReviewStatus,
|
||||
String companyName, String businessType, String taxMode, String containerMode,
|
||||
String companyName, String businessType, String fulfillmentType, String lxCode,
|
||||
String taxMode, String containerMode,
|
||||
Boolean customsInspection, String destinationType, String destinationCode,
|
||||
Boolean holdFlag, String currentHoldReason,
|
||||
BigDecimal actualGrossWeightKg, BigDecimal actualNetWeightKg, BigDecimal actualVolumeCbm,
|
||||
|
||||
@@ -72,13 +72,27 @@ public class InternalOrderCargoController {
|
||||
if (tenantId <= 0 || orderId <= 0) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "租户和订单ID必须大于0");
|
||||
}
|
||||
var order = orders.findOwned(tenantId, orderId);
|
||||
if (order == null) {
|
||||
throw new BizException(ResultCode.NOT_FOUND, "订单不存在或不属于当前客户");
|
||||
}
|
||||
boolean oneClickDropship = "ONE_CLICK_DROPSHIP".equals(order.getFulfillmentType());
|
||||
return ApiResponse.success(orders.findCargoInheritedByOrder(tenantId, orderId).stream()
|
||||
.map(cargo -> new CargoLabelBinding(cargo.getId(), orderId, cargo.getItemNo(),
|
||||
cargo.getCargoName(), cargo.getSkuNo(), cargo.getPackageCount(), cargo.getLengthCm(),
|
||||
cargo.getWidthCm(), cargo.getHeightCm()))
|
||||
cargo.getCargoName(), cargo.getSkuNo(), cargo.getPackageCount(),
|
||||
unitsPerCarton(cargo, oneClickDropship), cargo.getLengthCm(), cargo.getWidthCm(),
|
||||
cargo.getHeightCm()))
|
||||
.toList());
|
||||
}
|
||||
|
||||
private Integer unitsPerCarton(OrderCargoEntity cargo, boolean oneClickDropship) {
|
||||
Integer value = cargo.getUnitsPerPackage();
|
||||
if (oneClickDropship && (value == null || value <= 0)) {
|
||||
throw new BizException(ResultCode.INTERNAL_ERROR, "一件代发货物每箱件数缺失或无效");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@GetMapping("/{tenantId}/{orderId}/inbound-snapshot")
|
||||
public ApiResponse<FirstlegInboundClient.OrderApprovedInboundCommand> inboundSnapshot(
|
||||
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||
@@ -155,12 +169,20 @@ public class InternalOrderCargoController {
|
||||
}
|
||||
|
||||
public record CargoLabelBinding(Long cargoId, Long orderId, Integer itemNo, String cargoName,
|
||||
String skuNo, Integer packageCount, java.math.BigDecimal lengthCm,
|
||||
String skuNo, Integer packageCount, Integer unitsPerCarton,
|
||||
java.math.BigDecimal lengthCm,
|
||||
java.math.BigDecimal widthCm, java.math.BigDecimal heightCm) {
|
||||
public CargoLabelBinding(Long cargoId, Long orderId, Integer itemNo, String cargoName,
|
||||
Integer packageCount, java.math.BigDecimal lengthCm,
|
||||
java.math.BigDecimal widthCm, java.math.BigDecimal heightCm) {
|
||||
this(cargoId, orderId, itemNo, cargoName, null, packageCount, lengthCm, widthCm, heightCm);
|
||||
this(cargoId, orderId, itemNo, cargoName, null, packageCount, null,
|
||||
lengthCm, widthCm, heightCm);
|
||||
}
|
||||
public CargoLabelBinding(Long cargoId, Long orderId, Integer itemNo, String cargoName,
|
||||
String skuNo, Integer packageCount, java.math.BigDecimal lengthCm,
|
||||
java.math.BigDecimal widthCm, java.math.BigDecimal heightCm) {
|
||||
this(cargoId, orderId, itemNo, cargoName, skuNo, packageCount, null,
|
||||
lengthCm, widthCm, heightCm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class PlatformUnifiedOrderController {
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAuthority('platform:order:list')")
|
||||
@Operation(summary = "统一订单列表", description = "返回七态产品主状态及测量、预装、装柜、派送摘要。")
|
||||
@Operation(summary = "统一订单列表", description = "返回八态产品主状态及测量、组托、预装、装柜、派送摘要。")
|
||||
public ApiResponse<PageResult<UnifiedOrderResponse.Row>> page(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam(required = false) Long tenantId,
|
||||
|
||||
@@ -12,8 +12,8 @@ import java.time.LocalDateTime;
|
||||
public record UnifiedOrderQuery(
|
||||
@Size(max = 64) String keyword,
|
||||
@Size(max = 64) String orderNo,
|
||||
@Schema(allowableValues = {"PENDING_REVIEW", "WAIT_MEASURE", "INBOUNDED",
|
||||
"LOADING", "LOADED", "DELIVERED"})
|
||||
@Schema(allowableValues = {"PENDING_REVIEW", "WAIT_MEASURE", "WAIT_PALLETIZE", "INBOUNDED",
|
||||
"WAIT_SPLIT", "LOADING", "LOADED", "DELIVERED"})
|
||||
@Size(max = 32) String mainStatus,
|
||||
Long customerId,
|
||||
Long receivingWarehouseId,
|
||||
|
||||
@@ -24,7 +24,7 @@ public final class UnifiedOrderResponse {
|
||||
BigDecimal estimatedVolumeCbm, BigDecimal expectedVolumeCbm,
|
||||
BigDecimal actualGrossWeightKg, BigDecimal actualVolumeCbm,
|
||||
LocalDateTime expectedArrivalAt, String feeReviewStatus,
|
||||
String companyName, String businessType, String pickupMethod,
|
||||
String companyName, String businessType, String fulfillmentType, String lxCode, String pickupMethod,
|
||||
String taxMode, String containerMode, Boolean customsInspection,
|
||||
String destinationType, String destinationCode,
|
||||
Integer totalPalletCount, BigDecimal chargeableWeightKg, BigDecimal chargeableVolumeCbm,
|
||||
|
||||
@@ -38,7 +38,8 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class UnifiedOrderQueryService {
|
||||
private static final Set<String> MAIN_STATUSES = Set.of(
|
||||
"PENDING_REVIEW", "WAIT_MEASURE", "INBOUNDED", "WAIT_SPLIT", "LOADING", "LOADED", "DELIVERED");
|
||||
"PENDING_REVIEW", "WAIT_MEASURE", "WAIT_PALLETIZE", "INBOUNDED", "WAIT_SPLIT",
|
||||
"LOADING", "LOADED", "DELIVERED");
|
||||
private static final Set<String> REVIEW_STATUSES = Set.of("UNRECORDED", "PENDING", "APPROVED", "REJECTED");
|
||||
private static final List<OrderStatus> ACTIVE_ORDER_STATUSES = List.copyOf(EnumSet.of(
|
||||
OrderStatus.SUBMITTED, OrderStatus.APPROVED, OrderStatus.ACCEPTED,
|
||||
@@ -311,7 +312,8 @@ public class UnifiedOrderQueryService {
|
||||
order.getInboundCode(),
|
||||
order.getExpectedShipDate(), null, null, totalPackageCount(cargo), null, null,
|
||||
order.getEstimatedVolumeCbm(), volumeCbm(cargo), null, null,
|
||||
order.getExpectedArrivalAt(), null, null, null, order.getPickupMethod(), order.getTaxMode(), order.getContainerMode(),
|
||||
order.getExpectedArrivalAt(), null, null, null, order.getFulfillmentType(), order.getLxCode(),
|
||||
order.getPickupMethod(), order.getTaxMode(), order.getContainerMode(),
|
||||
order.getCustomsInspection(), order.getDestinationType(), order.getAmazonWarehouseCode(),
|
||||
null, null, null, null, null, null, null, order.getExpressCompany(), order.getExpressTrackingNo(),
|
||||
StringUtils.hasText(creatorName) ? creatorName : string(order.getCreatedBy()), skuNos(cargo), totalQuantity(cargo), shipmentId(order, cargo), referenceId(order, cargo),
|
||||
@@ -334,7 +336,8 @@ public class UnifiedOrderQueryService {
|
||||
order.getEstimatedVolumeCbm(), volumeCbm(cargo),
|
||||
inbound.actualGrossWeightKg(), inbound.actualVolumeCbm(),
|
||||
order.getExpectedArrivalAt() != null ? order.getExpectedArrivalAt() : inbound.expectedArrivalAt(), inbound.feeReviewStatus(),
|
||||
inbound.companyName(), inbound.businessType(), order.getPickupMethod(), inbound.taxMode(), inbound.containerMode(),
|
||||
inbound.companyName(), inbound.businessType(), inbound.fulfillmentType(), inbound.lxCode(),
|
||||
order.getPickupMethod(), inbound.taxMode(), inbound.containerMode(),
|
||||
inbound.customsInspection(), inbound.destinationType(), inbound.destinationCode(), inbound.palletCount(),
|
||||
inbound.chargeableWeightKg(), inbound.chargeableVolumeCbm(), inbound.volumeWeightKg(),
|
||||
inbound.actualNetWeightKg(),
|
||||
@@ -361,7 +364,8 @@ public class UnifiedOrderQueryService {
|
||||
order == null ? null : order.getEstimatedVolumeCbm(), volumeCbm(cargo),
|
||||
inbound.actualGrossWeightKg(), inbound.actualVolumeCbm(),
|
||||
order != null && order.getExpectedArrivalAt() != null ? order.getExpectedArrivalAt() : inbound.expectedArrivalAt(), inbound.feeReviewStatus(), inbound.companyName(),
|
||||
inbound.businessType(), order == null ? null : order.getPickupMethod(), inbound.taxMode(), inbound.containerMode(),
|
||||
inbound.businessType(), inbound.fulfillmentType(), inbound.lxCode(),
|
||||
order == null ? null : order.getPickupMethod(), inbound.taxMode(), inbound.containerMode(),
|
||||
inbound.customsInspection(), inbound.destinationType(), inbound.destinationCode(), inbound.palletCount(),
|
||||
inbound.chargeableWeightKg(), inbound.chargeableVolumeCbm(), inbound.volumeWeightKg(),
|
||||
inbound.actualNetWeightKg(),
|
||||
@@ -502,7 +506,7 @@ public class UnifiedOrderQueryService {
|
||||
return switch (status) {
|
||||
case "WAIT_MEASURE", "MEASURING", "MEASURE_PENDING", "MEASURE_REJECTED",
|
||||
"WAIT_PRICING", "FEE_CONFIRMING", "INBOUNDING" -> "WAIT_MEASURE";
|
||||
case "INBOUNDED", "WAIT_SPLIT", "LOADING", "LOADED", "DELIVERED" -> status;
|
||||
case "INBOUNDED", "WAIT_PALLETIZE", "WAIT_SPLIT", "LOADING", "LOADED", "DELIVERED" -> status;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ paths:
|
||||
get:
|
||||
summary: 平台统一订单列表
|
||||
description: >-
|
||||
统一返回七态产品主状态、下一步动作及测量/预装/装柜/派送摘要,需要 platform:order:list。
|
||||
统一返回八态产品主状态、下一步动作及测量/组托/预装/装柜/派送摘要,需要 platform:order:list。
|
||||
入仓码来源由全系统统一模式控制:AUTO 在订单提交时按物流渠道生成,格式为物流前缀+YYMMDD+当天全平台票序;
|
||||
LEGACY_MANUAL 在草稿中录入旧系统入仓码。两种模式下入仓码一经提交均固定;有入库单时同时返回
|
||||
inboundId、inboundVersion、loadingVersion、pickingVersion;inboundVersion
|
||||
@@ -617,7 +617,7 @@ components:
|
||||
tenantId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
keyword: {type: string, maxLength: 64}
|
||||
orderNo: {type: string, maxLength: 64}
|
||||
mainStatus: {type: string, enum: [PENDING_REVIEW, WAIT_MEASURE, INBOUNDED, WAIT_SPLIT, LOADING, LOADED, DELIVERED]}
|
||||
mainStatus: {type: string, enum: [PENDING_REVIEW, WAIT_MEASURE, WAIT_PALLETIZE, INBOUNDED, WAIT_SPLIT, LOADING, LOADED, DELIVERED]}
|
||||
customerId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
receivingWarehouseId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
destinationWarehouseId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
@@ -693,9 +693,10 @@ components:
|
||||
asOf: {type: string, format: date-time}
|
||||
UnifiedMainStatus:
|
||||
type: string
|
||||
enum: [PENDING_REVIEW, WAIT_MEASURE, INBOUNDED, WAIT_SPLIT, LOADING, LOADED, DELIVERED]
|
||||
enum: [PENDING_REVIEW, WAIT_MEASURE, WAIT_PALLETIZE, INBOUNDED, WAIT_SPLIT, LOADING, LOADED, DELIVERED]
|
||||
description: >-
|
||||
统一订单七态产品主状态。WAIT_SPLIT 为正式待分柜状态,INBOUNDED 仅兼容存量已入库记录。
|
||||
统一订单八态产品主状态。ONE_CLICK_DROPSHIP 测量计费完成后进入 WAIT_PALLETIZE,封托完成后进入 WAIT_SPLIT;
|
||||
STANDARD 保持既有流程,INBOUNDED 仅兼容存量已入库记录。
|
||||
UnifiedOrderPageEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
@@ -766,6 +767,8 @@ components:
|
||||
feeReviewStatus: {type: string, nullable: true, description: Firstleg 入仓费用审核快照;财务状态不在本字段表达}
|
||||
companyName: {type: string, nullable: true}
|
||||
businessType: {type: string, nullable: true}
|
||||
fulfillmentType: {type: string, enum: [STANDARD, ONE_CLICK_DROPSHIP], nullable: true, description: 独立履约类型,不复用计费业务类型}
|
||||
lxCode: {type: string, nullable: true, description: 一件代发可选 LX 编码;普通头程或未填写时为 null}
|
||||
pickupMethod: {type: string, nullable: true}
|
||||
requestedPickupAt: {type: string, format: date-time, nullable: true, description: Customer-requested pickup appointment from the pickup snapshot}
|
||||
taxMode: {type: string, nullable: true}
|
||||
@@ -961,13 +964,13 @@ components:
|
||||
fulfillmentType:
|
||||
type: string
|
||||
enum: [STANDARD, ONE_CLICK_DROPSHIP]
|
||||
default: STANDARD
|
||||
description: 独立履约类型;省略为普通头程,不复用业务/计费 businessType
|
||||
lxCode:
|
||||
type: string
|
||||
nullable: true
|
||||
maxLength: 128
|
||||
description: 一件代发绑定的领星入库单 LX 代码
|
||||
default: STANDARD
|
||||
description: 独立履约类型;省略为普通头程,不复用业务/计费 businessType
|
||||
inboundCode:
|
||||
type: string
|
||||
maxLength: 40
|
||||
@@ -1194,17 +1197,17 @@ components:
|
||||
name: mainStatus
|
||||
in: query
|
||||
required: false
|
||||
description: 统一订单七态主状态筛选;WAIT_SPLIT 与存量兼容状态 INBOUNDED 独立查询
|
||||
description: 统一订单八态主状态筛选;WAIT_PALLETIZE、WAIT_SPLIT 与存量兼容状态 INBOUNDED 独立查询
|
||||
schema:
|
||||
type: string
|
||||
enum: [PENDING_REVIEW, WAIT_MEASURE, INBOUNDED, LOADING, LOADED, DELIVERED, WAIT_SPLIT]
|
||||
enum: [PENDING_REVIEW, WAIT_MEASURE, WAIT_PALLETIZE, INBOUNDED, WAIT_SPLIT, LOADING, LOADED, DELIVERED]
|
||||
UnifiedInboundCode:
|
||||
{name: inboundCode, in: query, required: false, description: 订单创建时生成的入仓码,所有订单状态均可查询, schema: {type: string, maxLength: 40}}
|
||||
UnifiedInternalOrderStatus:
|
||||
name: internalOrderStatus
|
||||
in: query
|
||||
required: false
|
||||
description: Order 内部生命周期状态;不是七态产品主状态
|
||||
description: Order 内部生命周期状态;不是八态产品主状态
|
||||
schema: {type: string, enum: [DRAFT, SUBMITTED, APPROVED, ACCEPTED, REJECTED, CANCELLED, PROCESSING, COMPLETED]}
|
||||
UnifiedExpectedArrivalDate:
|
||||
{name: expectedArrivalDate, in: query, required: false, schema: {type: string, format: date}}
|
||||
|
||||
Reference in New Issue
Block a user