feat(phase3): 收口父子单与全链路验收

This commit is contained in:
2026-08-10 12:23:43 +08:00
parent b294695169
commit 75d5fd4e26
55 changed files with 1110 additions and 115 deletions
@@ -115,7 +115,7 @@ public class PlatformInboundMeasurementController {
requirePlatformTenant(user, tenantId);
CartonMeasurementCommand command = new CartonMeasurementCommand(
request.boxCode(), request.length(), request.width(), request.height(), request.weight(),
request.machineNo(), request.measuredAt(), image);
request.machineNo(), request.measuredAt(), image, request.scannedShipmentId());
return ApiResponse.success(cartonMeasurements.upsertForInbound(
tenantId, user.userId(), inboundId, command));
}
@@ -14,6 +14,7 @@ public record CartonMeasurementCommand(
BigDecimal unitWeightKg,
String machineNo,
LocalDateTime measuredAt,
MultipartFile image
MultipartFile image,
String scannedShipmentId
) {
}
@@ -9,6 +9,7 @@ public record CartonMeasurementResult(
Integer measurementVersion,
Long itemId,
String boxCode,
String scannedShipmentId,
Integer confirmedPackageCount,
BigDecimal lengthCm,
BigDecimal widthCm,
@@ -71,6 +71,7 @@ public final class InboundMeasurementRequests {
@NotNull @DecimalMin("0.001") @Digits(integer = 9, fraction = 3) BigDecimal width,
@NotNull @DecimalMin("0.001") @Digits(integer = 9, fraction = 3) BigDecimal height,
@DecimalMin("0.001") @Digits(integer = 15, fraction = 3) BigDecimal weight,
@Size(max = 64) String scannedShipmentId,
@NotBlank @Size(max = 64) String machineNo,
@NotNull LocalDateTime measuredAt
) {
@@ -67,6 +67,7 @@ public final class InboundMeasurementResponses {
BigDecimal outerHeightCm,
String remark,
String boxCode,
String scannedShipmentId,
Integer confirmedPackageCount,
String machineNo,
LocalDateTime deviceMeasuredAt,
@@ -1,5 +1,7 @@
package com.baiyue.firstleg.dto;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
@@ -16,6 +18,8 @@ public final class MojiaMeasurementDtos {
public record UploadRequest(
@NotBlank @Size(max = 128) String boxCode,
@JsonProperty("shipment_id") @JsonAlias("shipmentId")
@NotBlank @Size(max = 64) String shipmentId,
@NotNull @DecimalMin("0.001") @DecimalMax("999999999.999") BigDecimal length,
@NotNull @DecimalMin("0.001") @DecimalMax("999999999.999") BigDecimal width,
@NotNull @DecimalMin("0.001") @DecimalMax("999999999.999") BigDecimal height,
@@ -21,6 +21,7 @@ public class InboundMeasurementItemEntity {
private Long inboundDetailId;
private String externalDetailNo;
private String boxCode;
private String scannedShipmentId;
private String itemNo;
private String boxSpecification;
private Integer packageCount;
@@ -19,6 +19,7 @@ public class MojiaMeasurementReceiptEntity {
private Long tenantId;
private Long subjectId;
private String boxCode;
private String scannedShipmentId;
private BigDecimal lengthCm;
private BigDecimal widthCm;
private BigDecimal heightCm;
@@ -177,6 +177,8 @@ public class CartonMeasurementService {
item.setInboundDetailId(binding.inboundDetailId());
item.setExternalDetailNo(boxCode);
item.setBoxCode(boxCode);
item.setScannedShipmentId(StringUtils.hasText(command.scannedShipmentId())
? command.scannedShipmentId().trim() : null);
item.setItemNo("B" + binding.cartonIndex());
item.setBoxSpecification(StringUtils.hasText(binding.boxSpecification())
? binding.boxSpecification().trim() : boxCode);
@@ -380,6 +382,10 @@ public class CartonMeasurementService {
if (!StringUtils.hasText(command.machineNo()) || command.machineNo().trim().length() > 64) {
throw new BizException(ResultCode.VALIDATION_FAILED, "设备编号不能为空且不能超过64个字符");
}
if (StringUtils.hasText(command.scannedShipmentId())
&& command.scannedShipmentId().trim().length() > 64) {
throw new BizException(ResultCode.VALIDATION_FAILED, "实扫Shipment ID不能超过64个字符");
}
if (command.measuredAt() == null) {
throw new BizException(ResultCode.VALIDATION_FAILED, "设备测量时间不能为空");
}
@@ -404,7 +410,8 @@ public class CartonMeasurementService {
private CartonMeasurementResult result(InboundMeasurementEntity measurement,
InboundMeasurementItemEntity item, boolean created) {
return new CartonMeasurementResult(measurement.getId(), measurement.getVersion(), item.getId(),
item.getBoxCode(), item.getPackageCount(), item.getLengthCm(), item.getWidthCm(),
item.getBoxCode(), item.getScannedShipmentId(), item.getPackageCount(),
item.getLengthCm(), item.getWidthCm(),
item.getHeightCm(), item.getUnitWeightKg(), item.getSourceImageFileId(), item.getMachineNo(),
item.getDeviceMeasuredAt(), created);
}
@@ -367,7 +367,8 @@ public class InboundMeasurementService {
item.getUnitWeightKg(), item.getUnitVolumeCbm(), item.getTotalWeightKg(),
item.getTotalVolumeCbm(), item.getVolumeWeightKg(), item.getSourceImageFileId(),
item.getOverLimitWarning(), item.getOuterLengthCm(), item.getOuterWidthCm(),
item.getOuterHeightCm(), item.getRemark(), item.getBoxCode(), item.getPackageCount(),
item.getOuterHeightCm(), item.getRemark(), item.getBoxCode(), item.getScannedShipmentId(),
item.getPackageCount(),
item.getMachineNo(), item.getDeviceMeasuredAt(), item.getUpdatedAt());
}
@@ -79,7 +79,7 @@ public class MojiaMeasurementOpenApiService {
app.tenantId(), app.subjectId(), new CartonMeasurementCommand(
request.boxCode(), request.length(), request.width(), request.height(), request.weight(),
request.machineNo(), request.measuredAt() == null ? LocalDateTime.now() : request.measuredAt(),
image));
image, request.shipmentId().trim()));
} catch (BizException exception) {
if (exception.getResultCode() == ResultCode.NOT_FOUND) {
return saveUnmatched(app, request, image, exception);
@@ -117,6 +117,7 @@ public class MojiaMeasurementOpenApiService {
receipt.setTenantId(app.tenantId());
receipt.setSubjectId(app.subjectId());
receipt.setBoxCode(request.boxCode().trim());
receipt.setScannedShipmentId(request.shipmentId().trim());
receipt.setLengthCm(request.length());
receipt.setWidthCm(request.width());
receipt.setHeightCm(request.height());
@@ -203,6 +203,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_measurement_item (
inbound_detail_id BIGINT UNSIGNED NULL COMMENT '绑定的订单货物明细ID,平台手工明细可为空',
external_detail_no VARCHAR(128) NULL COMMENT '第三方测量明细唯一号,平台手工明细可为空',
box_code VARCHAR(128) NULL COMMENT '柏悦唛头箱号;设备单箱测量时同一客户内唯一',
scanned_shipment_id VARCHAR(64) NULL COMMENT '设备从Amazon FBA箱标实扫的Shipment ID',
item_no VARCHAR(32) NOT NULL COMMENT '批次内明细号',
box_specification VARCHAR(64) NOT NULL COMMENT '箱规标识',
package_count INT UNSIGNED NOT NULL COMMENT '相同箱规箱数',
@@ -240,6 +241,7 @@ CREATE TABLE IF NOT EXISTS fl_mojia_measurement_receipt (
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户隔离ID',
subject_id BIGINT UNSIGNED NOT NULL COMMENT '设备应用操作主体ID',
box_code VARCHAR(128) NOT NULL COMMENT '设备扫描的原始箱码',
scanned_shipment_id VARCHAR(64) NULL COMMENT '设备从Amazon FBA箱标实扫的Shipment ID',
length_cm DECIMAL(12,3) NOT NULL COMMENT '设备实测长度cm',
width_cm DECIMAL(12,3) NOT NULL COMMENT '设备实测宽度cm',
height_cm DECIMAL(12,3) NOT NULL COMMENT '设备实测高度cm',
@@ -239,9 +239,10 @@ paths:
application/json:
schema:
type: object
required: [boxCode, length, width, height, machineNo, picture]
required: [boxCode, shipment_id, length, width, height, machineNo, picture]
properties:
boxCode: {type: string, maxLength: 128, example: 'RK-2085911321565003778#4-1'}
shipment_id: {type: string, maxLength: 64, example: 'FBA19L5KMY2CU000002', description: '设备从Amazon FBA箱标实际扫描得到;系统只保存,不生成且不覆盖客户下单值'}
length: {type: number, format: decimal, minimum: 0.001}
width: {type: number, format: decimal, minimum: 0.001}
height: {type: number, format: decimal, minimum: 0.001}