优化
This commit is contained in:
+18
-11
@@ -13,39 +13,44 @@ import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = "warehouse-service", contextId = "warehousePalletLocationClient",
|
||||
url = "${baiyue.clients.warehouse.url:}", path = "/internal/warehouse/v1/pallet-locations")
|
||||
url = "${baiyue.clients.warehouse.url:}", path = "/internal/warehouse/v1")
|
||||
public interface WarehousePalletLocationClient {
|
||||
@PostMapping("/reservations")
|
||||
@GetMapping("/pallets/snapshots")
|
||||
ApiResponse<List<PalletSnapshot>> palletSnapshots(
|
||||
@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestParam("warehouseId") long warehouseId);
|
||||
|
||||
@PostMapping("/pallet-locations/reservations")
|
||||
ApiResponse<BatchResult> reserve(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestBody ReserveRequest request);
|
||||
|
||||
@PostMapping("/confirm")
|
||||
@PostMapping("/pallet-locations/confirm")
|
||||
ApiResponse<BatchResult> confirm(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestBody ConfirmRequest request);
|
||||
|
||||
@PostMapping("/release")
|
||||
@PostMapping("/pallet-locations/release")
|
||||
ApiResponse<List<ActiveResource>> release(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestBody ReleaseRequest request);
|
||||
|
||||
@PostMapping("/release-selected")
|
||||
@PostMapping("/pallet-locations/release-selected")
|
||||
ApiResponse<List<SelectiveReleaseResult>> releaseSelected(
|
||||
@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestBody SelectiveReleaseRequest request);
|
||||
|
||||
@PostMapping("/transfer")
|
||||
@PostMapping("/pallet-locations/transfer")
|
||||
ApiResponse<List<TransferResult>> transfer(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestBody TransferRequest request);
|
||||
|
||||
@PostMapping("/settlements")
|
||||
@PostMapping("/pallet-locations/settlements")
|
||||
ApiResponse<SettlementResult> settle(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestBody SettlementRequest request);
|
||||
|
||||
@GetMapping("/settlements/target")
|
||||
@GetMapping("/pallet-locations/settlements/target")
|
||||
ApiResponse<Long> settlementTarget(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestParam("sourceBusinessId") long sourceBusinessId,
|
||||
@RequestParam("idempotencyKey") String idempotencyKey);
|
||||
|
||||
@GetMapping("/occupied-resources")
|
||||
@GetMapping("/pallet-locations/occupied-resources")
|
||||
ApiResponse<List<OccupiedResource>> occupiedResources(
|
||||
@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestParam("tenantId") long tenantId,
|
||||
@@ -90,6 +95,8 @@ public interface WarehousePalletLocationClient {
|
||||
List<SettlementTransferItem> remainingItems) {}
|
||||
record SettlementResult(List<SelectiveReleaseResult> released, List<TransferResult> transferred) {}
|
||||
record OccupiedResource(long reservationId, long occupancyId, int allocationNo, long warehouseId,
|
||||
long palletId, long locationId, String locationCode, boolean sharedOverflow,
|
||||
int allocatedPackageCount) {}
|
||||
long palletId, long locationId, String locationCode, boolean sharedOverflow,
|
||||
int allocatedPackageCount) {}
|
||||
record PalletSnapshot(long palletId, String palletCode, String palletType,
|
||||
BigDecimal capacityCbm, BigDecimal tareWeightKg) {}
|
||||
}
|
||||
|
||||
+19
-2
@@ -33,6 +33,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** 平台后台入库测量录入、提交和 OCR 重量结果维护接口。 */
|
||||
@Tag(name = "平台入库测量", description = "维护测量草稿、箱规明细和可追溯 OCR 重量结果。")
|
||||
@RestController
|
||||
@@ -53,6 +55,19 @@ public class PlatformInboundMeasurementController {
|
||||
return ApiResponse.success(service.detail(tenantId, inboundId));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询称重可选托盘快照",
|
||||
description = "按入库单所属仓库返回未删除的托盘只读快照,不校验托盘状态或占用资格。")
|
||||
@GetMapping("/weight-pallet-options")
|
||||
@PreAuthorize("hasAnyAuthority('platform:firstleg:inbound:measure:view',"
|
||||
+ " 'platform:firstleg:inbound:weight:edit')")
|
||||
public ApiResponse<List<InboundMeasurementResponses.PalletSnapshot>> weightPalletOptions(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam long tenantId,
|
||||
@PathVariable long inboundId) {
|
||||
requirePlatformTenant(user, tenantId);
|
||||
return ApiResponse.success(service.weightPalletOptions(tenantId, inboundId));
|
||||
}
|
||||
|
||||
@BusinessAudit(event = "INBOUND_MEASUREMENT_DRAFT_SAVE", resourceType = "INBOUND",
|
||||
resourceId = "#inboundId", description = "保存入库测量草稿")
|
||||
@Operation(summary = "保存测量草稿", description = "保存人工测量批次和服务端计算明细,不推进入库状态。")
|
||||
@@ -142,7 +157,8 @@ public class PlatformInboundMeasurementController {
|
||||
|
||||
@BusinessAudit(event = "INBOUND_WEIGHT_OCR_RECORD", resourceType = "INBOUND",
|
||||
resourceId = "#inboundId", description = "登记称重图片 OCR 原值")
|
||||
@Operation(summary = "登记 OCR 重量结果", description = "按图片文件 ID 保存不可覆盖的 OCR 原值。")
|
||||
@Operation(summary = "登记 OCR 重量结果",
|
||||
description = "按图片文件 ID 和托盘 ID 保存 OCR 毛重原值及同仓托盘快照。")
|
||||
@PostMapping("/weight-results")
|
||||
@PreAuthorize("hasAuthority('platform:firstleg:inbound:weight:edit')")
|
||||
public ApiResponse<InboundMeasurementResponses.WeightResult> createWeightResult(
|
||||
@@ -173,7 +189,8 @@ public class PlatformInboundMeasurementController {
|
||||
@BusinessAudit(event = "INBOUND_WEIGHT_OCR_CONFIRM", resourceType = "INBOUND_WEIGHT_RESULT",
|
||||
resourceId = "#resultId", description = "确认 OCR 重量并累加实际总毛重")
|
||||
@Operation(summary = "确认 OCR 重量",
|
||||
description = "可在同一事务中携带人工修改值并确认;统一换算为 KG 后重算所有已确认图片的总重量。")
|
||||
description = "可在同一事务中携带人工毛重修改值并确认;统一换算 KG、扣除托盘皮重后,"
|
||||
+ "按所有已确认净重重算入库单 actualGrossWeightKg。")
|
||||
@PostMapping("/weight-results/{resultId}/confirm")
|
||||
@PreAuthorize("hasAuthority('platform:firstleg:inbound:weight:confirm')"
|
||||
+ " and (!#request.hasAdjustment() or hasAuthority('platform:firstleg:inbound:weight:edit'))")
|
||||
|
||||
@@ -79,6 +79,7 @@ public final class InboundMeasurementRequests {
|
||||
|
||||
public record CreateWeightResultRequest(
|
||||
@NotNull @Positive Long fileId,
|
||||
@NotNull @Positive Long palletId,
|
||||
@Size(max = 64) String ocrProvider,
|
||||
@Size(max = 1000) String ocrRawText,
|
||||
@DecimalMin("0.000") @Digits(integer = 15, fraction = 3) BigDecimal ocrWeightValue,
|
||||
|
||||
@@ -81,14 +81,20 @@ public final class InboundMeasurementResponses {
|
||||
public record WeightResult(
|
||||
Long id,
|
||||
Long fileId,
|
||||
Long palletId,
|
||||
String palletCode,
|
||||
String palletType,
|
||||
BigDecimal palletCapacityCbm,
|
||||
BigDecimal palletTareWeightKg,
|
||||
String ocrProvider,
|
||||
String ocrRawText,
|
||||
BigDecimal ocrWeightValue,
|
||||
String ocrWeightUnit,
|
||||
BigDecimal confidence,
|
||||
BigDecimal grossWeightKg,
|
||||
BigDecimal adjustedWeightValue,
|
||||
String adjustedWeightUnit,
|
||||
BigDecimal finalWeightKg,
|
||||
BigDecimal netWeightKg,
|
||||
String recognitionStatus,
|
||||
String adjustmentReason,
|
||||
Long adjustedBy,
|
||||
@@ -99,6 +105,15 @@ public final class InboundMeasurementResponses {
|
||||
) {
|
||||
}
|
||||
|
||||
public record PalletSnapshot(
|
||||
Long palletId,
|
||||
String palletCode,
|
||||
String palletType,
|
||||
BigDecimal capacityCbm,
|
||||
BigDecimal tareWeightKg
|
||||
) {
|
||||
}
|
||||
|
||||
public record DraftSaved(Long measurementId, Integer version, String status) {
|
||||
}
|
||||
|
||||
|
||||
@@ -37,9 +37,11 @@ public record MerchantInboundBillingResponse(InboundOrderDetail inbound,
|
||||
}
|
||||
|
||||
public record WeightResult(
|
||||
Long id, Long fileId, BigDecimal recognizedWeightValue, String recognizedWeightUnit,
|
||||
BigDecimal adjustedWeightValue, String adjustedWeightUnit,
|
||||
BigDecimal finalWeightKg, String recognitionStatus) {
|
||||
Long id, Long fileId, Long palletId, String palletCode, String palletType,
|
||||
BigDecimal palletCapacityCbm, BigDecimal palletTareWeightKg,
|
||||
BigDecimal recognizedWeightValue, String recognizedWeightUnit,
|
||||
BigDecimal grossWeightKg, BigDecimal adjustedWeightValue, String adjustedWeightUnit,
|
||||
BigDecimal netWeightKg, String recognitionStatus) {
|
||||
}
|
||||
|
||||
public record BillingBasis(
|
||||
|
||||
@@ -10,7 +10,7 @@ import lombok.Setter;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** 称重图片 OCR 原值、人工修正值和最终确认重量。 */
|
||||
/** 称重图片、托盘皮重快照、OCR 原值和最终确认净重。 */
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("fl_inbound_weight_result")
|
||||
@@ -20,6 +20,11 @@ public class InboundWeightResultEntity extends BaseEntity {
|
||||
private Long tenantId;
|
||||
private Long inboundId;
|
||||
private Long fileId;
|
||||
private Long palletId;
|
||||
private String palletCode;
|
||||
private String palletType;
|
||||
private BigDecimal palletCapacityCbm;
|
||||
private BigDecimal palletTareWeightKg;
|
||||
private String ocrProvider;
|
||||
private String ocrRawText;
|
||||
private BigDecimal ocrWeightValue;
|
||||
@@ -27,7 +32,8 @@ public class InboundWeightResultEntity extends BaseEntity {
|
||||
private BigDecimal confidence;
|
||||
private BigDecimal adjustedWeightValue;
|
||||
private String adjustedWeightUnit;
|
||||
private BigDecimal finalWeightKg;
|
||||
private BigDecimal grossWeightKg;
|
||||
private BigDecimal netWeightKg;
|
||||
private String recognitionStatus;
|
||||
private String adjustmentReason;
|
||||
private Long adjustedBy;
|
||||
|
||||
@@ -25,7 +25,8 @@ public class InboundWeightRevisionEntity {
|
||||
private String beforeWeightUnit;
|
||||
private BigDecimal afterWeightValue;
|
||||
private String afterWeightUnit;
|
||||
private BigDecimal finalWeightKg;
|
||||
private BigDecimal grossWeightKg;
|
||||
private BigDecimal netWeightKg;
|
||||
private String reason;
|
||||
private Long operatorId;
|
||||
private String operatorName;
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.baiyue.firstleg.dto.CartonMeasurementResult;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementEntity;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementItemEntity;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.entity.InboundWeightResultEntity;
|
||||
import com.baiyue.firstleg.repository.InboundMeasurementRepository;
|
||||
import feign.FeignException;
|
||||
import org.slf4j.Logger;
|
||||
@@ -143,13 +144,26 @@ public class CartonMeasurementService {
|
||||
}
|
||||
// 提交审核后仍允许平台人工修正代表箱数,但订单原始总箱数不可被测量汇总覆盖。
|
||||
if ("MEASURE_PENDING".equals(inbound.getProcessStatus())) {
|
||||
BigDecimal totalWeight = items.stream()
|
||||
.map(InboundMeasurementItemEntity::getTotalWeightKg)
|
||||
.filter(java.util.Objects::nonNull)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
.setScale(3, RoundingMode.CEILING);
|
||||
if (positive(totalWeight)) {
|
||||
inbound.setActualGrossWeightKg(totalWeight);
|
||||
List<InboundWeightResultEntity> confirmedWeights = repository.listWeights(tenantId, inboundId)
|
||||
.stream()
|
||||
.filter(weight -> "CONFIRMED".equals(weight.getRecognitionStatus()))
|
||||
.toList();
|
||||
if (!confirmedWeights.isEmpty()) {
|
||||
BigDecimal confirmedNetWeight = confirmedWeights.stream()
|
||||
.map(InboundWeightResultEntity::getNetWeightKg)
|
||||
.filter(java.util.Objects::nonNull)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
.setScale(3, RoundingMode.CEILING);
|
||||
inbound.setActualGrossWeightKg(confirmedNetWeight);
|
||||
} else {
|
||||
BigDecimal totalWeight = items.stream()
|
||||
.map(InboundMeasurementItemEntity::getTotalWeightKg)
|
||||
.filter(java.util.Objects::nonNull)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
.setScale(3, RoundingMode.CEILING);
|
||||
if (positive(totalWeight)) {
|
||||
inbound.setActualGrossWeightKg(totalWeight);
|
||||
}
|
||||
}
|
||||
inbound.setActualVolumeCbm(measurement.getTotalVolumeCbm());
|
||||
inbound.setVolumeWeightKg(measurement.getVolumeWeightKg());
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.client.OrderCargoClient;
|
||||
import com.baiyue.firstleg.client.MeasurementImageClient;
|
||||
import com.baiyue.firstleg.client.WarehousePalletLocationClient;
|
||||
import com.baiyue.firstleg.dto.InboundMeasurementRequests;
|
||||
import com.baiyue.firstleg.dto.InboundMeasurementResponses;
|
||||
import com.baiyue.firstleg.dto.MeasurementBatchCommand;
|
||||
@@ -57,6 +58,8 @@ public class InboundMeasurementService {
|
||||
private String internalToken;
|
||||
@Resource
|
||||
private MeasurementImageClient imageClient;
|
||||
@Resource
|
||||
private WarehousePalletLocationClient warehousePallets;
|
||||
|
||||
public InboundMeasurementResponses.Detail detail(long tenantId, long inboundId) {
|
||||
InboundOrderEntity inbound = requireInbound(tenantId, inboundId);
|
||||
@@ -68,6 +71,16 @@ public class InboundMeasurementService {
|
||||
return toDetail(inbound, measurement, items, weights, review);
|
||||
}
|
||||
|
||||
public List<InboundMeasurementResponses.PalletSnapshot> weightPalletOptions(
|
||||
long tenantId, long inboundId) {
|
||||
InboundOrderEntity inbound = requireInbound(tenantId, inboundId);
|
||||
return loadPalletSnapshots(inbound).stream()
|
||||
.map(snapshot -> new InboundMeasurementResponses.PalletSnapshot(
|
||||
snapshot.palletId(), snapshot.palletCode(), snapshot.palletType(),
|
||||
snapshot.capacityCbm(), snapshot.tareWeightKg()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public InboundMeasurementResponses.DraftSaved saveDraft(
|
||||
long tenantId, long inboundId, long operatorId,
|
||||
@@ -147,11 +160,22 @@ public class InboundMeasurementService {
|
||||
if (repository.findWeightByFile(tenantId, inboundId, request.fileId()) != null) {
|
||||
throw new BizException(ResultCode.CONFLICT, "同一称重图片不能重复计重");
|
||||
}
|
||||
WarehousePalletLocationClient.PalletSnapshot pallet = loadPalletSnapshots(inbound).stream()
|
||||
.filter(snapshot -> snapshot.palletId() == request.palletId())
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new BizException(ResultCode.VALIDATION_FAILED,
|
||||
"所选托盘不属于当前入库仓库或已被删除"));
|
||||
validatePalletSnapshot(pallet);
|
||||
String unit = rawOcrUnit(request.ocrWeightUnit());
|
||||
InboundWeightResultEntity weight = new InboundWeightResultEntity();
|
||||
weight.setTenantId(tenantId);
|
||||
weight.setInboundId(inboundId);
|
||||
weight.setFileId(request.fileId());
|
||||
weight.setPalletId(pallet.palletId());
|
||||
weight.setPalletCode(pallet.palletCode().trim());
|
||||
weight.setPalletType(pallet.palletType().trim());
|
||||
weight.setPalletCapacityCbm(pallet.capacityCbm().setScale(4, RoundingMode.HALF_UP));
|
||||
weight.setPalletTareWeightKg(pallet.tareWeightKg().setScale(3, RoundingMode.HALF_UP));
|
||||
weight.setOcrProvider(request.ocrProvider());
|
||||
weight.setOcrRawText(request.ocrRawText());
|
||||
weight.setOcrWeightValue(request.ocrWeightValue());
|
||||
@@ -196,7 +220,8 @@ public class InboundMeasurementService {
|
||||
weight.setAdjustmentReason(adjustmentReason.trim());
|
||||
weight.setAdjustedBy(operatorId);
|
||||
weight.setAdjustedAt(LocalDateTime.now());
|
||||
weight.setFinalWeightKg(null);
|
||||
weight.setGrossWeightKg(null);
|
||||
weight.setNetWeightKg(null);
|
||||
weight.setConfirmedBy(null);
|
||||
weight.setConfirmedAt(null);
|
||||
weight.setRecognitionStatus(WEIGHT_PENDING_CONFIRM);
|
||||
@@ -207,7 +232,7 @@ public class InboundMeasurementService {
|
||||
int correctedVersion = expectedVersion + 1;
|
||||
weight.setVersion(correctedVersion);
|
||||
insertRevision(weight, correctedVersion, "CORRECT", beforeValue, beforeUnit,
|
||||
adjustedWeightValue, adjustedUnit, null, adjustmentReason.trim(),
|
||||
adjustedWeightValue, adjustedUnit, null, null, adjustmentReason.trim(),
|
||||
operatorId, operatorName);
|
||||
return correctedVersion;
|
||||
}
|
||||
@@ -236,8 +261,15 @@ public class InboundMeasurementService {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "OCR 重量无法确认,请先人工修正数值和单位");
|
||||
}
|
||||
String unit = normalizeUnit(rawUnit);
|
||||
BigDecimal finalKg = requireConfirmableKg(value, unit);
|
||||
weight.setFinalWeightKg(finalKg);
|
||||
BigDecimal grossWeightKg = requireConfirmableKg(value, unit);
|
||||
BigDecimal netWeightKg = grossWeightKg.subtract(weight.getPalletTareWeightKg())
|
||||
.setScale(3, RoundingMode.HALF_UP);
|
||||
if (!isPositive(netWeightKg)) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED,
|
||||
"称重毛重必须大于托盘皮重");
|
||||
}
|
||||
weight.setGrossWeightKg(grossWeightKg);
|
||||
weight.setNetWeightKg(netWeightKg);
|
||||
weight.setRecognitionStatus(WEIGHT_CONFIRMED);
|
||||
weight.setConfirmedBy(operatorId);
|
||||
weight.setConfirmedAt(LocalDateTime.now());
|
||||
@@ -248,7 +280,7 @@ public class InboundMeasurementService {
|
||||
int confirmedVersion = currentVersion + 1;
|
||||
weight.setVersion(confirmedVersion);
|
||||
insertRevision(weight, confirmedVersion, "CONFIRM", value, unit, value, unit,
|
||||
finalKg, null, operatorId, operatorName);
|
||||
grossWeightKg, netWeightKg, null, operatorId, operatorName);
|
||||
recalculateConfirmedWeight(inbound, operatorId);
|
||||
return toWeight(weight);
|
||||
}
|
||||
@@ -288,7 +320,7 @@ public class InboundMeasurementService {
|
||||
.filter(weight -> WEIGHT_CONFIRMED.equals(weight.getRecognitionStatus()))
|
||||
.toList();
|
||||
BigDecimal total = confirmedWeights.stream()
|
||||
.map(InboundWeightResultEntity::getFinalWeightKg)
|
||||
.map(InboundWeightResultEntity::getNetWeightKg)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
.setScale(3, RoundingMode.HALF_UP);
|
||||
inbound.setActualGrossWeightKg(confirmedWeights.isEmpty() ? null : total);
|
||||
@@ -304,7 +336,7 @@ public class InboundMeasurementService {
|
||||
private BigDecimal confirmedWeightForSubmission(List<InboundWeightResultEntity> weights) {
|
||||
BigDecimal total = weights.stream()
|
||||
.filter(weight -> WEIGHT_CONFIRMED.equals(weight.getRecognitionStatus()))
|
||||
.map(InboundWeightResultEntity::getFinalWeightKg)
|
||||
.map(InboundWeightResultEntity::getNetWeightKg)
|
||||
.filter(java.util.Objects::nonNull)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add).setScale(3, RoundingMode.HALF_UP);
|
||||
return isPositive(total) ? total : null;
|
||||
@@ -319,7 +351,8 @@ public class InboundMeasurementService {
|
||||
|
||||
private void insertRevision(InboundWeightResultEntity weight, int revisionNo, String action,
|
||||
BigDecimal beforeValue, String beforeUnit,
|
||||
BigDecimal afterValue, String afterUnit, BigDecimal finalWeightKg,
|
||||
BigDecimal afterValue, String afterUnit,
|
||||
BigDecimal grossWeightKg, BigDecimal netWeightKg,
|
||||
String reason, long operatorId, String operatorName) {
|
||||
InboundWeightRevisionEntity revision = new InboundWeightRevisionEntity();
|
||||
revision.setTenantId(weight.getTenantId());
|
||||
@@ -331,7 +364,8 @@ public class InboundMeasurementService {
|
||||
revision.setBeforeWeightUnit(beforeUnit);
|
||||
revision.setAfterWeightValue(afterValue);
|
||||
revision.setAfterWeightUnit(afterUnit);
|
||||
revision.setFinalWeightKg(finalWeightKg);
|
||||
revision.setGrossWeightKg(grossWeightKg);
|
||||
revision.setNetWeightKg(netWeightKg);
|
||||
revision.setReason(reason);
|
||||
revision.setOperatorId(operatorId);
|
||||
revision.setOperatorName(operatorName);
|
||||
@@ -396,13 +430,46 @@ public class InboundMeasurementService {
|
||||
|
||||
private InboundMeasurementResponses.WeightResult toWeight(InboundWeightResultEntity weight) {
|
||||
return new InboundMeasurementResponses.WeightResult(
|
||||
weight.getId(), weight.getFileId(), weight.getOcrProvider(), weight.getOcrRawText(),
|
||||
weight.getId(), weight.getFileId(), weight.getPalletId(), weight.getPalletCode(),
|
||||
weight.getPalletType(), weight.getPalletCapacityCbm(), weight.getPalletTareWeightKg(),
|
||||
weight.getOcrProvider(), weight.getOcrRawText(),
|
||||
weight.getOcrWeightValue(), weight.getOcrWeightUnit(), weight.getConfidence(),
|
||||
weight.getAdjustedWeightValue(), weight.getAdjustedWeightUnit(), weight.getFinalWeightKg(),
|
||||
weight.getGrossWeightKg(),
|
||||
weight.getAdjustedWeightValue(), weight.getAdjustedWeightUnit(),
|
||||
weight.getNetWeightKg(),
|
||||
weight.getRecognitionStatus(), weight.getAdjustmentReason(), weight.getAdjustedBy(),
|
||||
weight.getAdjustedAt(), weight.getConfirmedBy(), weight.getConfirmedAt(), weight.getVersion());
|
||||
}
|
||||
|
||||
private List<WarehousePalletLocationClient.PalletSnapshot> loadPalletSnapshots(
|
||||
InboundOrderEntity inbound) {
|
||||
if (inbound.getWarehouseId() == null || inbound.getWarehouseId() <= 0) {
|
||||
throw new BizException(ResultCode.CONFLICT, "入库单未绑定有效仓库,无法选择称重托盘");
|
||||
}
|
||||
try {
|
||||
ApiResponse<List<WarehousePalletLocationClient.PalletSnapshot>> response =
|
||||
warehousePallets.palletSnapshots(internalToken, inbound.getWarehouseId());
|
||||
if (response == null || !response.successful() || response.data() == null) {
|
||||
String message = response == null || !StringUtils.hasText(response.message())
|
||||
? "托盘快照查询失败" : response.message();
|
||||
throw new BizException(response == null ? ResultCode.SERVICE_UNAVAILABLE
|
||||
: ResultCode.of(response.code()), message);
|
||||
}
|
||||
return response.data();
|
||||
} catch (FeignException exception) {
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库服务暂不可用,无法查询托盘快照");
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePalletSnapshot(WarehousePalletLocationClient.PalletSnapshot snapshot) {
|
||||
if (snapshot.palletId() <= 0 || !StringUtils.hasText(snapshot.palletCode())
|
||||
|| !StringUtils.hasText(snapshot.palletType()) || !isPositive(snapshot.capacityCbm())
|
||||
|| snapshot.tareWeightKg() == null
|
||||
|| snapshot.tareWeightKg().compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new BizException(ResultCode.CONFLICT, "仓库服务返回的托盘快照不完整");
|
||||
}
|
||||
}
|
||||
|
||||
private InboundOrderEntity requireInbound(long tenantId, long inboundId) {
|
||||
InboundOrderEntity inbound = repository.findInbound(tenantId, inboundId);
|
||||
if (inbound == null) {
|
||||
|
||||
+5
-3
@@ -73,9 +73,11 @@ public class MerchantInboundBillingService {
|
||||
.toList();
|
||||
var weightResults = measurement.weightResults().stream()
|
||||
.map(weight -> new MerchantInboundBillingResponse.WeightResult(
|
||||
weight.id(), weight.fileId(), weight.ocrWeightValue(), weight.ocrWeightUnit(),
|
||||
weight.adjustedWeightValue(), weight.adjustedWeightUnit(),
|
||||
weight.finalWeightKg(), weight.recognitionStatus()))
|
||||
weight.id(), weight.fileId(), weight.palletId(), weight.palletCode(), weight.palletType(),
|
||||
weight.palletCapacityCbm(), weight.palletTareWeightKg(),
|
||||
weight.ocrWeightValue(), weight.ocrWeightUnit(),
|
||||
weight.grossWeightKg(), weight.adjustedWeightValue(), weight.adjustedWeightUnit(),
|
||||
weight.netWeightKg(), weight.recognitionStatus()))
|
||||
.toList();
|
||||
var basis = new MerchantInboundBillingResponse.BillingBasis(
|
||||
fee.chargeMode(), fee.chargeUnit(), chargeableBasis(fee), fee.actualWeightKg(),
|
||||
|
||||
@@ -77,7 +77,8 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_revision (
|
||||
before_weight_unit VARCHAR(8) NULL COMMENT '变更前单位',
|
||||
after_weight_value DECIMAL(18,3) NULL COMMENT '变更后原单位重量',
|
||||
after_weight_unit VARCHAR(8) NULL COMMENT '变更后单位',
|
||||
final_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的重量kg',
|
||||
gross_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的含托盘毛重kg',
|
||||
net_weight_kg DECIMAL(18,3) NULL COMMENT '确认毛重扣除托盘皮重后的货物净重kg',
|
||||
reason VARCHAR(500) NULL COMMENT '人工修正原因',
|
||||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
|
||||
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
|
||||
|
||||
@@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_order (
|
||||
hold_flag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '当前是否扣货',
|
||||
current_hold_reason VARCHAR(500) NULL COMMENT '当前扣货理由快照',
|
||||
total_package_count INT UNSIGNED NULL COMMENT '确认后的总箱数',
|
||||
actual_gross_weight_kg DECIMAL(18,3) NULL COMMENT '确认后的实际总毛重kg',
|
||||
actual_gross_weight_kg DECIMAL(18,3) NULL COMMENT '下游货物实际毛重kg,汇总已确认称重净重',
|
||||
chargeable_weight_kg DECIMAL(18,3) NULL COMMENT '当前费用快照的计费重量kg',
|
||||
actual_volume_cbm DECIMAL(18,4) NULL COMMENT '确认后的实际总体积m3',
|
||||
chargeable_volume_cbm DECIMAL(18,4) NULL COMMENT '当前费用快照的计费体积m3',
|
||||
@@ -270,6 +270,11 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_result (
|
||||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
|
||||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||||
file_id BIGINT UNSIGNED NOT NULL COMMENT '称重图片文件ID',
|
||||
pallet_id BIGINT UNSIGNED NOT NULL COMMENT 'Warehouse托盘ID',
|
||||
pallet_code VARCHAR(50) NOT NULL COMMENT '托盘编码快照',
|
||||
pallet_type VARCHAR(32) NOT NULL COMMENT '托盘类型快照',
|
||||
pallet_capacity_cbm DECIMAL(18,4) NOT NULL COMMENT '托盘容量CBM快照',
|
||||
pallet_tare_weight_kg DECIMAL(18,3) NOT NULL COMMENT '托盘皮重KG快照',
|
||||
ocr_provider VARCHAR(64) NULL COMMENT 'OCR服务商编码',
|
||||
ocr_raw_text VARCHAR(1000) NULL COMMENT 'OCR原始文本',
|
||||
ocr_weight_value DECIMAL(18,3) NULL COMMENT 'OCR识别原始重量值',
|
||||
@@ -277,7 +282,8 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_result (
|
||||
confidence DECIMAL(6,5) NULL COMMENT '识别置信度',
|
||||
adjusted_weight_value DECIMAL(18,3) NULL COMMENT '人工修正后的原单位重量',
|
||||
adjusted_weight_unit VARCHAR(8) NULL COMMENT '人工修正后的单位',
|
||||
final_weight_kg DECIMAL(18,3) NULL COMMENT '确认并统一换算后的重量kg',
|
||||
gross_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的含托盘毛重kg',
|
||||
net_weight_kg DECIMAL(18,3) NULL COMMENT '确认毛重扣除托盘皮重后的货物净重kg',
|
||||
recognition_status VARCHAR(24) NOT NULL DEFAULT 'PENDING' COMMENT '重量识别状态:PENDING待识别、PENDING_CONFIRM待确认、NEEDS_MANUAL需人工录入、CONFIRMED已确认',
|
||||
adjustment_reason VARCHAR(500) NULL COMMENT '人工修正原因',
|
||||
adjusted_by BIGINT UNSIGNED NULL COMMENT '修正人ID',
|
||||
@@ -293,8 +299,9 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_result (
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_weight_inbound_file (tenant_id, inbound_id, file_id),
|
||||
KEY idx_weight_inbound_status (tenant_id, inbound_id, recognition_status),
|
||||
KEY idx_weight_inbound_pallet (tenant_id, inbound_id, pallet_id),
|
||||
CONSTRAINT fk_weight_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||||
) ENGINE=InnoDB COMMENT='称重图片OCR原值、人工修正值和确认重量';
|
||||
) ENGINE=InnoDB COMMENT='称重图片、托盘皮重快照、OCR毛重和确认净重';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_inbound_weight_revision (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT 'OCR重量修订记录ID',
|
||||
@@ -307,7 +314,8 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_revision (
|
||||
before_weight_unit VARCHAR(8) NULL COMMENT '变更前单位',
|
||||
after_weight_value DECIMAL(18,3) NULL COMMENT '变更后原单位重量',
|
||||
after_weight_unit VARCHAR(8) NULL COMMENT '变更后单位',
|
||||
final_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的重量kg',
|
||||
gross_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的含托盘毛重kg',
|
||||
net_weight_kg DECIMAL(18,3) NULL COMMENT '确认毛重扣除托盘皮重后的货物净重kg',
|
||||
reason VARCHAR(500) NULL COMMENT '人工修正原因',
|
||||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
|
||||
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
|
||||
@@ -664,7 +672,6 @@ CREATE TABLE IF NOT EXISTS fl_inbound_pallet_allocation (
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pallet_allocation_no (tenant_id, inbound_id, allocation_no),
|
||||
UNIQUE KEY uk_pallet_allocation_pallet (tenant_id, inbound_id, pallet_id),
|
||||
KEY idx_allocation_location (tenant_id, warehouse_id, location_id, allocation_status),
|
||||
KEY idx_allocation_reservation (reservation_id),
|
||||
CONSTRAINT fk_allocation_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||||
|
||||
@@ -542,13 +542,62 @@ paths:
|
||||
responses:
|
||||
'200': {description: 成功或业务失败,按响应体 code 判断}
|
||||
'403': {description: 无测量编辑权限}
|
||||
/api/platform/v1/first-leg/inbounds/{inboundId}/weight-pallet-options:
|
||||
get:
|
||||
summary: 查询称重可选托盘快照
|
||||
description: >-
|
||||
需要入库测量查看或称重编辑权限。Firstleg 按入库单 warehouseId 查询 Warehouse 公共托盘快照;
|
||||
仅限定同仓且未删除,不校验托盘状态或占用资格,Admin 不需要 platform:pallet:list。
|
||||
parameters:
|
||||
- {name: tenantId, in: query, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: inboundId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
responses:
|
||||
'200':
|
||||
description: 成功或业务失败,按响应体 code 判断
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
code: {type: string}
|
||||
message: {type: string}
|
||||
data: {type: array, items: {$ref: '#/components/schemas/WeightPalletSnapshot'}}
|
||||
'403': {description: 无入库测量查看或称重编辑权限}
|
||||
/api/platform/v1/first-leg/inbounds/{inboundId}/weight-results:
|
||||
post:
|
||||
summary: 登记称重图片 OCR 毛重结果
|
||||
description: >-
|
||||
需要称重编辑权限。请求必须绑定 palletId;Firstleg 按入库单 warehouseId 读取 Warehouse
|
||||
权威快照并固化托盘编码、类型、容量和皮重,不信任前端托盘快照。
|
||||
parameters:
|
||||
- {name: tenantId, in: query, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: inboundId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/CreateWeightResultRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: 成功或业务失败,按响应体 code 判断
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
code: {type: string}
|
||||
message: {type: string}
|
||||
data: {$ref: '#/components/schemas/InboundWeightResult'}
|
||||
'403': {description: 无称重编辑权限}
|
||||
/api/platform/v1/first-leg/inbounds/{inboundId}/weight-results/{resultId}/confirm:
|
||||
post:
|
||||
summary: 确认 OCR 重量
|
||||
description: >-
|
||||
需要 platform:firstleg:inbound:weight:confirm 权限;携带人工修改字段时还需要
|
||||
platform:firstleg:inbound:weight:edit 权限。修改与确认在同一事务内完成,保留 OCR 原值,
|
||||
分别写入 CORRECT 和 CONFIRM 修订记录,并重算所有已确认图片的实际总毛重。
|
||||
分别写入 CORRECT 和 CONFIRM 修订记录。输入表示含托盘毛重;服务端统一换算为 KG,
|
||||
使用创建时固化的托盘皮重计算 netWeightKg,且毛重必须大于皮重。
|
||||
入库单 actualGrossWeightKg 明确保留为下游货物实际毛重字段,值汇总所有已确认 netWeightKg。
|
||||
parameters:
|
||||
- {name: tenantId, in: query, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: inboundId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
@@ -559,14 +608,48 @@ paths:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/ConfirmWeightResultRequest'}
|
||||
responses:
|
||||
'200': {description: 成功或业务失败,按响应体 code 判断}
|
||||
'200':
|
||||
description: 成功或业务失败,按响应体 code 判断
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
code: {type: string}
|
||||
message: {type: string}
|
||||
data: {$ref: '#/components/schemas/InboundWeightResult'}
|
||||
'403': {description: 无确认权限,或修改重量时无编辑权限}
|
||||
/api/platform/v1/first-leg/inbounds/{inboundId}/weight-results/{resultId}:
|
||||
put:
|
||||
summary: 人工修正 OCR 毛重
|
||||
description: >-
|
||||
需要称重编辑权限。修正值仍表示含托盘毛重;保留 OCR 原值,已确认结果修正后立即移出净重汇总并回到待确认。
|
||||
parameters:
|
||||
- {name: tenantId, in: query, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: inboundId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: resultId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/CorrectWeightResultRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: 成功或业务失败,按响应体 code 判断
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
code: {type: string}
|
||||
message: {type: string}
|
||||
data: {$ref: '#/components/schemas/InboundWeightResult'}
|
||||
'403': {description: 无称重编辑权限}
|
||||
delete:
|
||||
summary: 删除称重图片及重量结果
|
||||
description: >-
|
||||
需要 platform:firstleg:inbound:weight:edit 权限;仅允许在可编辑的测量状态删除。
|
||||
删除已确认图片后重新汇总剩余已确认图片的实际总毛重,删除最后一张时总毛重恢复为空。
|
||||
删除已确认图片后重新汇总剩余已确认图片的净重,删除最后一张时 actualGrossWeightKg 恢复为空。
|
||||
parameters:
|
||||
- {name: tenantId, in: query, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: version, in: query, required: true, schema: {type: integer, format: int32, minimum: 0}}
|
||||
@@ -986,10 +1069,65 @@ components:
|
||||
properties:
|
||||
configId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
createdByThisInitialization: {type: boolean}
|
||||
WeightPalletSnapshot:
|
||||
type: object
|
||||
required: [palletId, palletCode, palletType, capacityCbm, tareWeightKg]
|
||||
properties:
|
||||
palletId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
palletCode: {type: string}
|
||||
palletType: {type: string}
|
||||
capacityCbm: {type: number, format: double, minimum: 0.0001}
|
||||
tareWeightKg: {type: number, format: double, minimum: 0, multipleOf: 0.001}
|
||||
CreateWeightResultRequest:
|
||||
type: object
|
||||
required: [fileId, palletId]
|
||||
properties:
|
||||
fileId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
palletId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
ocrProvider: {type: string, maxLength: 64, nullable: true}
|
||||
ocrRawText: {type: string, maxLength: 1000, nullable: true}
|
||||
ocrWeightValue: {type: number, format: double, minimum: 0, nullable: true, description: OCR 原始含托盘毛重}
|
||||
ocrWeightUnit: {type: string, maxLength: 8, nullable: true}
|
||||
confidence: {type: number, format: double, minimum: 0, maximum: 1, nullable: true}
|
||||
CorrectWeightResultRequest:
|
||||
type: object
|
||||
required: [version, adjustedWeightValue, adjustedWeightUnit, adjustmentReason]
|
||||
properties:
|
||||
version: {type: integer, minimum: 0}
|
||||
adjustedWeightValue: {type: number, format: double, minimum: 0.001, description: 人工修正后的含托盘毛重}
|
||||
adjustedWeightUnit: {type: string, enum: [KG, LB]}
|
||||
adjustmentReason: {type: string, minLength: 1, maxLength: 500}
|
||||
InboundWeightResult:
|
||||
type: object
|
||||
required: [id, fileId, palletId, palletCode, palletType, palletCapacityCbm, palletTareWeightKg, recognitionStatus, version]
|
||||
properties:
|
||||
id: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
fileId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
palletId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
palletCode: {type: string}
|
||||
palletType: {type: string}
|
||||
palletCapacityCbm: {type: number, format: double, minimum: 0.0001}
|
||||
palletTareWeightKg: {type: number, format: double, minimum: 0, multipleOf: 0.001}
|
||||
ocrProvider: {type: string, nullable: true}
|
||||
ocrRawText: {type: string, nullable: true}
|
||||
ocrWeightValue: {type: number, format: double, nullable: true, description: OCR 原始含托盘毛重}
|
||||
ocrWeightUnit: {type: string, nullable: true}
|
||||
confidence: {type: number, format: double, nullable: true}
|
||||
grossWeightKg: {type: number, format: double, nullable: true, multipleOf: 0.001, description: 确认时标准化的含托盘毛重 KG}
|
||||
adjustedWeightValue: {type: number, format: double, nullable: true, description: 人工修正后的含托盘毛重}
|
||||
adjustedWeightUnit: {type: string, nullable: true}
|
||||
netWeightKg: {type: number, format: double, nullable: true, multipleOf: 0.001, description: grossWeightKg - palletTareWeightKg}
|
||||
recognitionStatus: {type: string, enum: [PENDING, PENDING_CONFIRM, NEEDS_MANUAL, CONFIRMED]}
|
||||
adjustmentReason: {type: string, nullable: true}
|
||||
adjustedBy: {type: string, nullable: true}
|
||||
adjustedAt: {type: string, format: date-time, nullable: true}
|
||||
confirmedBy: {type: string, nullable: true}
|
||||
confirmedAt: {type: string, format: date-time, nullable: true}
|
||||
version: {type: integer, minimum: 0}
|
||||
ConfirmWeightResultRequest:
|
||||
type: object
|
||||
required: [version]
|
||||
description: 人工修改字段必须同时提供;全部省略时直接确认现有 OCR 或已修正重量。
|
||||
description: 人工修改字段表示含托盘毛重且必须同时提供;全部省略时直接确认现有 OCR 或已修正毛重。
|
||||
properties:
|
||||
version: {type: integer, minimum: 0}
|
||||
adjustedWeightValue: {type: number, format: double, minimum: 0.001, nullable: true}
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.baiyue.firstleg.client;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class WarehousePalletLocationClientContractTest {
|
||||
@Test
|
||||
void consumesTheWarehousePalletSnapshotContractExactly() throws Exception {
|
||||
FeignClient client = WarehousePalletLocationClient.class.getAnnotation(FeignClient.class);
|
||||
assertThat(client.path()).isEqualTo("/internal/warehouse/v1");
|
||||
|
||||
Method method = WarehousePalletLocationClient.class.getDeclaredMethod(
|
||||
"palletSnapshots", String.class, long.class);
|
||||
assertThat(method.getAnnotation(GetMapping.class).value())
|
||||
.containsExactly("/pallets/snapshots");
|
||||
assertThat(method.getParameters()[1].getAnnotation(RequestParam.class).value())
|
||||
.isEqualTo("warehouseId");
|
||||
|
||||
var snapshot = new WarehousePalletLocationClient.PalletSnapshot(
|
||||
101L, "PLT-101", "STANDARD", new java.math.BigDecimal("2.0000"),
|
||||
new java.math.BigDecimal("18.500"));
|
||||
assertThat(snapshot).extracting(
|
||||
WarehousePalletLocationClient.PalletSnapshot::palletId,
|
||||
WarehousePalletLocationClient.PalletSnapshot::palletCode,
|
||||
WarehousePalletLocationClient.PalletSnapshot::palletType,
|
||||
WarehousePalletLocationClient.PalletSnapshot::capacityCbm,
|
||||
WarehousePalletLocationClient.PalletSnapshot::tareWeightKg)
|
||||
.containsExactly(101L, "PLT-101", "STANDARD",
|
||||
new java.math.BigDecimal("2.0000"), new java.math.BigDecimal("18.500"));
|
||||
}
|
||||
}
|
||||
+4
@@ -17,6 +17,10 @@ class PlatformInboundMeasurementControllerContractTest {
|
||||
void everyMeasurementOperationUsesDedicatedButtonPermission() throws Exception {
|
||||
assertAuthority("detail", "hasAuthority('platform:firstleg:inbound:measure:view')",
|
||||
AuthenticatedUser.class, long.class, long.class);
|
||||
assertAuthority("weightPalletOptions",
|
||||
"hasAnyAuthority('platform:firstleg:inbound:measure:view',"
|
||||
+ " 'platform:firstleg:inbound:weight:edit')",
|
||||
AuthenticatedUser.class, long.class, long.class);
|
||||
assertAuthority("saveDraft", "hasAuthority('platform:firstleg:inbound:measure:edit')",
|
||||
AuthenticatedUser.class, long.class, long.class,
|
||||
InboundMeasurementRequests.SaveDraftRequest.class);
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.baiyue.firstleg.dto;
|
||||
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class CreateWeightResultRequestValidationTest {
|
||||
private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
|
||||
@Test
|
||||
void requiresAValidFileAndPalletBinding() {
|
||||
var valid = request(120L, 501L);
|
||||
var missingPallet = request(120L, null);
|
||||
var invalidPallet = request(120L, 0L);
|
||||
|
||||
assertThat(validator.validate(valid)).isEmpty();
|
||||
assertThat(validator.validate(missingPallet))
|
||||
.extracting(violation -> violation.getPropertyPath().toString())
|
||||
.contains("palletId");
|
||||
assertThat(validator.validate(invalidPallet))
|
||||
.extracting(violation -> violation.getPropertyPath().toString())
|
||||
.contains("palletId");
|
||||
}
|
||||
|
||||
private InboundMeasurementRequests.CreateWeightResultRequest request(Long fileId, Long palletId) {
|
||||
return new InboundMeasurementRequests.CreateWeightResultRequest(
|
||||
fileId, palletId, "FILE_WEIGHT_OCR", "30.000 KG", new BigDecimal("30.000"),
|
||||
"KG", new BigDecimal("0.99000"));
|
||||
}
|
||||
}
|
||||
+22
@@ -63,4 +63,26 @@ class InboundWorkflowSqlContractTest {
|
||||
.contains("uk_measure_box_code")
|
||||
.contains("单箱当前测量字段未完整创建");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("称重结果固化托盘快照、毛重和净重并允许托盘主数据复用")
|
||||
void shouldPersistWeightPalletSnapshotsAndNetWeight() throws Exception {
|
||||
String schema = new ClassPathResource("db/phase2-inbound-schema.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
String unified = Files.readString(Path.of("..", "deploy", "sql", "头程数据库统一增量-MySQL8.sql"));
|
||||
|
||||
assertThat(schema)
|
||||
.contains("pallet_tare_weight_kg DECIMAL(18,3) NOT NULL")
|
||||
.contains("gross_weight_kg DECIMAL(18,3) NULL")
|
||||
.contains("net_weight_kg DECIMAL(18,3) NULL")
|
||||
.contains("idx_weight_inbound_pallet")
|
||||
.doesNotContain("final_weight_kg")
|
||||
.doesNotContain("uk_pallet_allocation_pallet");
|
||||
assertThat(unified)
|
||||
.contains("CALL phase2_measure_add_column('fl_inbound_weight_result', 'pallet_id'")
|
||||
.contains("ALTER TABLE fl_inbound_weight_result DROP COLUMN final_weight_kg")
|
||||
.contains("ALTER TABLE fl_inbound_pallet_allocation DROP INDEX uk_pallet_allocation_pallet")
|
||||
.contains("称重托盘快照或毛重净重字段未正确收敛")
|
||||
.contains("同票托盘唯一约束仍阻止托盘主数据复用");
|
||||
}
|
||||
}
|
||||
|
||||
+38
-1
@@ -10,6 +10,7 @@ import com.baiyue.firstleg.entity.CustomerDimensionConfigEntity;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementEntity;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementItemEntity;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.entity.InboundWeightResultEntity;
|
||||
import com.baiyue.firstleg.repository.InboundMeasurementRepository;
|
||||
import com.baiyue.firstleg.repository.CustomerDimensionConfigRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -248,7 +249,7 @@ class CartonMeasurementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void confirmedPackageCountSynchronizesActualWeightAndVolumeForPricingAfterSubmission() {
|
||||
void confirmedPackageCountUsesCartonWeightAsFallbackWhenNoConfirmedImageExists() {
|
||||
InboundOrderEntity inbound = inbound("MEASURE_PENDING");
|
||||
InboundMeasurementEntity measurement = measurement(30001L, "SUBMITTED", 2);
|
||||
measurement.setTotalPackageCount(1);
|
||||
@@ -266,6 +267,7 @@ class CartonMeasurementServiceTest {
|
||||
when(repository.findMeasurement(10001L, 70001L, 30001L)).thenReturn(measurement);
|
||||
when(repository.updateItem(item)).thenReturn(true);
|
||||
when(repository.listItems(10001L, 30001L)).thenReturn(List.of(item));
|
||||
when(repository.listWeights(10001L, 70001L)).thenReturn(List.of());
|
||||
when(repository.updateMeasurement(measurement)).thenReturn(true);
|
||||
when(repository.updateInbound(inbound)).thenReturn(true);
|
||||
|
||||
@@ -278,6 +280,41 @@ class CartonMeasurementServiceTest {
|
||||
verify(repository).updateInbound(inbound);
|
||||
}
|
||||
|
||||
@Test
|
||||
void cartonMeasurementAfterConfirmedWeightKeepsNetWeightAndUpdatesVolume() {
|
||||
InboundOrderEntity inbound = inbound("MEASURE_PENDING");
|
||||
inbound.setActualGrossWeightKg(new BigDecimal("11.500"));
|
||||
InboundMeasurementEntity measurement = measurement(30001L, "SUBMITTED", 2);
|
||||
measurement.setTotalPackageCount(1);
|
||||
measurement.setTotalVolumeCbm(new BigDecimal("0.0600"));
|
||||
measurement.setVolumeWeightKg(new BigDecimal("10.020"));
|
||||
InboundMeasurementItemEntity item = item(40001L, 30001L, 1, 99001L);
|
||||
item.setUnitWeightKg(new BigDecimal("10.880"));
|
||||
item.setOuterLengthCm(new BigDecimal("50"));
|
||||
item.setOuterWidthCm(new BigDecimal("40"));
|
||||
item.setOuterHeightCm(new BigDecimal("30"));
|
||||
item.setUnitVolumeCbm(new BigDecimal("0.1496"));
|
||||
item.setCalculationRuleVersion("ACTUAL_DIMENSION_V1");
|
||||
InboundWeightResultEntity confirmedWeight = new InboundWeightResultEntity();
|
||||
confirmedWeight.setRecognitionStatus("CONFIRMED");
|
||||
confirmedWeight.setNetWeightKg(new BigDecimal("11.500"));
|
||||
when(repository.findInbound(10001L, 70001L)).thenReturn(inbound);
|
||||
when(repository.findItem(10001L, 40001L)).thenReturn(item);
|
||||
when(repository.findMeasurement(10001L, 70001L, 30001L)).thenReturn(measurement);
|
||||
when(repository.updateItem(item)).thenReturn(true);
|
||||
when(repository.listItems(10001L, 30001L)).thenReturn(List.of(item));
|
||||
when(repository.listWeights(10001L, 70001L)).thenReturn(List.of(confirmedWeight));
|
||||
when(repository.updateMeasurement(measurement)).thenReturn(true);
|
||||
when(repository.updateInbound(inbound)).thenReturn(true);
|
||||
|
||||
service.updateConfirmedPackageCount(10001L, 70001L, 40001L, 2, 5);
|
||||
|
||||
assertThat(inbound.getActualGrossWeightKg()).isEqualByComparingTo("11.500");
|
||||
assertThat(inbound.getActualVolumeCbm()).isEqualByComparingTo("0.7480");
|
||||
assertThat(inbound.getVolumeWeightKg()).isEqualByComparingTo("124.916");
|
||||
verify(repository).updateInbound(inbound);
|
||||
}
|
||||
|
||||
private CartonMeasurementCommand command() {
|
||||
return new CartonMeasurementCommand("RK-001#5-1", new BigDecimal("59.100"),
|
||||
new BigDecimal("40.200"), new BigDecimal("30.300"), new BigDecimal("12.500"),
|
||||
|
||||
+120
-14
@@ -4,6 +4,7 @@ import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.firstleg.client.OrderCargoClient;
|
||||
import com.baiyue.firstleg.client.MeasurementImageClient;
|
||||
import com.baiyue.firstleg.client.WarehousePalletLocationClient;
|
||||
import com.baiyue.firstleg.dto.InboundMeasurementRequests;
|
||||
import com.baiyue.firstleg.dto.MeasurementBatchCommand;
|
||||
import com.baiyue.firstleg.dto.InboundMeasurementResponses;
|
||||
@@ -49,8 +50,15 @@ class InboundMeasurementServiceTest {
|
||||
@MockBean private MeasurementBatchService batchService;
|
||||
@MockBean private OrderCargoClient orderCargoClient;
|
||||
@MockBean private MeasurementImageClient imageClient;
|
||||
@MockBean private WarehousePalletLocationClient warehousePallets;
|
||||
@Resource private InboundMeasurementService service;
|
||||
|
||||
@BeforeEach
|
||||
void stubWarehousePalletSnapshots() {
|
||||
when(warehousePallets.palletSnapshots("internal-token", 100L)).thenReturn(
|
||||
ApiResponse.success(List.of(palletSnapshot())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void customerCannotReadAnotherCustomersMeasurement() {
|
||||
assertThatThrownBy(() -> service.detail(2L, 10L))
|
||||
@@ -90,7 +98,8 @@ class InboundMeasurementServiceTest {
|
||||
InboundOrderEntity inbound = inbound("MEASURING");
|
||||
inbound.setActualGrossWeightKg(new BigDecimal("12.500"));
|
||||
InboundWeightResultEntity weight = weight(20L, "12.500", "KG", "CONFIRMED", 4);
|
||||
weight.setFinalWeightKg(new BigDecimal("12.500"));
|
||||
weight.setGrossWeightKg(new BigDecimal("12.500"));
|
||||
weight.setNetWeightKg(new BigDecimal("12.500"));
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
when(repository.findWeight(1L, 10L, 20L)).thenReturn(weight);
|
||||
when(repository.updateWeight(weight)).thenReturn(true);
|
||||
@@ -102,7 +111,8 @@ class InboundMeasurementServiceTest {
|
||||
4, new BigDecimal("13.200"), "KG", "秤面显示修正"));
|
||||
|
||||
assertThat(weight.getRecognitionStatus()).isEqualTo("PENDING_CONFIRM");
|
||||
assertThat(weight.getFinalWeightKg()).isNull();
|
||||
assertThat(weight.getGrossWeightKg()).isNull();
|
||||
assertThat(weight.getNetWeightKg()).isNull();
|
||||
assertThat(inbound.getActualGrossWeightKg()).isNull();
|
||||
verify(repository).updateInboundWeightSummary(inbound);
|
||||
}
|
||||
@@ -134,22 +144,55 @@ class InboundMeasurementServiceTest {
|
||||
InboundMeasurementResponses.WeightResult result = service.createWeightResult(
|
||||
1L, 10L, 9L,
|
||||
new InboundMeasurementRequests.CreateWeightResultRequest(
|
||||
120L, "FILE_WEIGHT_OCR", "285.5", new BigDecimal("285.500"), "KG",
|
||||
120L, 501L, "FILE_WEIGHT_OCR", "285.5", new BigDecimal("285.500"), "KG",
|
||||
new BigDecimal("0.5097191334")));
|
||||
|
||||
ArgumentCaptor<InboundWeightResultEntity> saved =
|
||||
ArgumentCaptor.forClass(InboundWeightResultEntity.class);
|
||||
verify(repository).insertWeight(saved.capture());
|
||||
assertThat(saved.getValue().getConfidence()).isEqualByComparingTo("0.50972");
|
||||
assertThat(saved.getValue().getPalletId()).isEqualTo(501L);
|
||||
assertThat(saved.getValue().getPalletCode()).isEqualTo("PLT-501");
|
||||
assertThat(saved.getValue().getPalletTareWeightKg()).isEqualByComparingTo("18.500");
|
||||
assertThat(result.confidence()).isEqualByComparingTo("0.50972");
|
||||
}
|
||||
|
||||
@Test
|
||||
void weightPalletOptionsUsesInboundWarehouseWithoutCustomerScope() {
|
||||
InboundOrderEntity inbound = inbound("WAIT_MEASURE");
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
|
||||
List<InboundMeasurementResponses.PalletSnapshot> result =
|
||||
service.weightPalletOptions(1L, 10L);
|
||||
|
||||
assertThat(result).singleElement().satisfies(snapshot -> {
|
||||
assertThat(snapshot.palletId()).isEqualTo(501L);
|
||||
assertThat(snapshot.tareWeightKg()).isEqualByComparingTo("18.500");
|
||||
});
|
||||
verify(warehousePallets).palletSnapshots("internal-token", 100L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void creatingWeightResultRejectsPalletOutsideTheInboundWarehouse() {
|
||||
InboundOrderEntity inbound = inbound("WAIT_MEASURE");
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
|
||||
assertThatThrownBy(() -> service.createWeightResult(1L, 10L, 9L,
|
||||
new InboundMeasurementRequests.CreateWeightResultRequest(
|
||||
120L, 999L, "FILE_WEIGHT_OCR", "20.0 KG", new BigDecimal("20.000"),
|
||||
"KG", new BigDecimal("0.99"))))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("不属于当前入库仓库");
|
||||
|
||||
verify(repository, never()).insertWeight(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void confirmingLbWeightConvertsToKgAndRecalculatesOnlyConfirmedImages() {
|
||||
InboundOrderEntity inbound = inbound("WAIT_MEASURE");
|
||||
InboundWeightResultEntity current = weight(20L, "10.000", "LB", "PENDING_CONFIRM", 0);
|
||||
InboundWeightResultEntity previous = weight(21L, "2.000", "KG", "CONFIRMED", 1);
|
||||
previous.setFinalWeightKg(new BigDecimal("2.000"));
|
||||
previous.setNetWeightKg(new BigDecimal("2.000"));
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
when(repository.findWeight(1L, 10L, 20L)).thenReturn(current);
|
||||
when(repository.updateWeight(current)).thenReturn(true);
|
||||
@@ -160,12 +203,58 @@ class InboundMeasurementServiceTest {
|
||||
1L, 10L, 20L, 9L, "操作员",
|
||||
new InboundMeasurementRequests.ConfirmWeightResultRequest(0, null, null, null));
|
||||
|
||||
assertThat(response.finalWeightKg()).isEqualByComparingTo("4.536");
|
||||
assertThat(response.grossWeightKg()).isEqualByComparingTo("4.536");
|
||||
assertThat(response.netWeightKg()).isEqualByComparingTo("4.536");
|
||||
assertThat(inbound.getActualGrossWeightKg()).isEqualByComparingTo("6.536");
|
||||
assertThat(inbound.getProcessStatus()).isEqualTo("MEASURING");
|
||||
verify(repository).insertRevision(any(InboundWeightRevisionEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void confirmingWeightAfterCartonMeasurementReplacesFallbackWithNetWeight() {
|
||||
InboundOrderEntity inbound = inbound("WAIT_MEASURE");
|
||||
inbound.setActualGrossWeightKg(new BigDecimal("54.400"));
|
||||
InboundWeightResultEntity weight = weight(20L, "30.000", "KG", "PENDING_CONFIRM", 0);
|
||||
weight.setPalletTareWeightKg(new BigDecimal("18.500"));
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
when(repository.findWeight(1L, 10L, 20L)).thenReturn(weight);
|
||||
when(repository.updateWeight(weight)).thenReturn(true);
|
||||
when(repository.listWeights(1L, 10L)).thenReturn(List.of(weight));
|
||||
when(repository.updateInboundWeightSummary(inbound)).thenReturn(true);
|
||||
|
||||
InboundMeasurementResponses.WeightResult response = service.confirmWeightResult(
|
||||
1L, 10L, 20L, 9L, "操作员",
|
||||
new InboundMeasurementRequests.ConfirmWeightResultRequest(0, null, null, null));
|
||||
|
||||
assertThat(response.grossWeightKg()).isEqualByComparingTo("30.000");
|
||||
assertThat(response.netWeightKg()).isEqualByComparingTo("11.500");
|
||||
assertThat(inbound.getActualGrossWeightKg()).isEqualByComparingTo("11.500");
|
||||
ArgumentCaptor<InboundWeightRevisionEntity> revision =
|
||||
ArgumentCaptor.forClass(InboundWeightRevisionEntity.class);
|
||||
verify(repository).insertRevision(revision.capture());
|
||||
assertThat(revision.getValue().getGrossWeightKg()).isEqualByComparingTo("30.000");
|
||||
assertThat(revision.getValue().getNetWeightKg()).isEqualByComparingTo("11.500");
|
||||
}
|
||||
|
||||
@Test
|
||||
void confirmingWeightRejectsGrossWeightNotAboveFrozenTare() {
|
||||
InboundOrderEntity inbound = inbound("WAIT_MEASURE");
|
||||
InboundWeightResultEntity weight = weight(20L, "18.500", "KG", "PENDING_CONFIRM", 0);
|
||||
weight.setPalletTareWeightKg(new BigDecimal("18.500"));
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
when(repository.findWeight(1L, 10L, 20L)).thenReturn(weight);
|
||||
|
||||
assertThatThrownBy(() -> service.confirmWeightResult(
|
||||
1L, 10L, 20L, 9L, "操作员",
|
||||
new InboundMeasurementRequests.ConfirmWeightResultRequest(0, null, null, null)))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("毛重必须大于托盘皮重");
|
||||
|
||||
verify(repository, never()).updateWeight(any());
|
||||
verify(repository, never()).insertRevision(any());
|
||||
verify(repository, never()).updateInboundWeightSummary(any());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"kg,2.000",
|
||||
@@ -190,7 +279,8 @@ class InboundMeasurementServiceTest {
|
||||
|
||||
assertThat(response.adjustedWeightUnit()).isEqualTo(
|
||||
unit.trim().toUpperCase().startsWith("LB") ? "LB" : "KG");
|
||||
assertThat(response.finalWeightKg()).isEqualByComparingTo(expectedKg);
|
||||
assertThat(response.grossWeightKg()).isEqualByComparingTo(expectedKg);
|
||||
assertThat(response.netWeightKg()).isEqualByComparingTo(expectedKg);
|
||||
assertThat(response.version()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@@ -208,7 +298,7 @@ class InboundMeasurementServiceTest {
|
||||
1L, 10L, 20L, 9L, "操作员",
|
||||
new InboundMeasurementRequests.ConfirmWeightResultRequest(0, null, null, null));
|
||||
|
||||
assertThat(response.finalWeightKg()).isEqualByComparingTo("0.001");
|
||||
assertThat(response.netWeightKg()).isEqualByComparingTo("0.001");
|
||||
assertThat(inbound.getActualGrossWeightKg()).isEqualByComparingTo("0.001");
|
||||
}
|
||||
|
||||
@@ -283,7 +373,8 @@ class InboundMeasurementServiceTest {
|
||||
0, new BigDecimal("286.125"), "kg", "OCR 原值 285.500 KG,人工确认 286.125 KG"));
|
||||
|
||||
assertThat(response.adjustedWeightValue()).isEqualByComparingTo("286.125");
|
||||
assertThat(response.finalWeightKg()).isEqualByComparingTo("286.125");
|
||||
assertThat(response.grossWeightKg()).isEqualByComparingTo("286.125");
|
||||
assertThat(response.netWeightKg()).isEqualByComparingTo("286.125");
|
||||
assertThat(response.recognitionStatus()).isEqualTo("CONFIRMED");
|
||||
assertThat(response.version()).isEqualTo(2);
|
||||
assertThat(inbound.getActualGrossWeightKg()).isEqualByComparingTo("286.125");
|
||||
@@ -344,7 +435,8 @@ class InboundMeasurementServiceTest {
|
||||
void confirmingAnAlreadyConfirmedWeightWithCurrentVersionIsIdempotent() {
|
||||
InboundOrderEntity inbound = inbound("MEASURING");
|
||||
InboundWeightResultEntity weight = weight(20L, "285.500", "KG", "CONFIRMED", 2);
|
||||
weight.setFinalWeightKg(new BigDecimal("285.500"));
|
||||
weight.setGrossWeightKg(new BigDecimal("285.500"));
|
||||
weight.setNetWeightKg(new BigDecimal("285.500"));
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
when(repository.findWeight(1L, 10L, 20L)).thenReturn(weight);
|
||||
|
||||
@@ -363,7 +455,8 @@ class InboundMeasurementServiceTest {
|
||||
void confirmingWithStaleVersionDoesNotTreatRequestAsIdempotent() {
|
||||
InboundOrderEntity inbound = inbound("MEASURING");
|
||||
InboundWeightResultEntity weight = weight(20L, "285.500", "KG", "CONFIRMED", 2);
|
||||
weight.setFinalWeightKg(new BigDecimal("285.500"));
|
||||
weight.setGrossWeightKg(new BigDecimal("285.500"));
|
||||
weight.setNetWeightKg(new BigDecimal("285.500"));
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
when(repository.findWeight(1L, 10L, 20L)).thenReturn(weight);
|
||||
|
||||
@@ -420,7 +513,8 @@ class InboundMeasurementServiceTest {
|
||||
InboundOrderEntity inbound = inbound("MEASURING");
|
||||
inbound.setActualGrossWeightKg(new BigDecimal("285.500"));
|
||||
InboundWeightResultEntity weight = weight(20L, "285.500", "KG", "CONFIRMED", 2);
|
||||
weight.setFinalWeightKg(new BigDecimal("285.500"));
|
||||
weight.setGrossWeightKg(new BigDecimal("285.500"));
|
||||
weight.setNetWeightKg(new BigDecimal("285.500"));
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
when(repository.findWeight(1L, 10L, 20L)).thenReturn(weight);
|
||||
when(repository.deleteWeight(1L, 10L, 20L, 2)).thenReturn(true);
|
||||
@@ -440,9 +534,9 @@ class InboundMeasurementServiceTest {
|
||||
InboundOrderEntity inbound = inbound("MEASURING");
|
||||
inbound.setActualGrossWeightKg(new BigDecimal("15.000"));
|
||||
InboundWeightResultEntity deleted = weight(20L, "10.000", "KG", "CONFIRMED", 2);
|
||||
deleted.setFinalWeightKg(new BigDecimal("10.000"));
|
||||
deleted.setNetWeightKg(new BigDecimal("10.000"));
|
||||
InboundWeightResultEntity remaining = weight(21L, "5.000", "KG", "CONFIRMED", 1);
|
||||
remaining.setFinalWeightKg(new BigDecimal("5.000"));
|
||||
remaining.setNetWeightKg(new BigDecimal("5.000"));
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
when(repository.findWeight(1L, 10L, 20L)).thenReturn(deleted);
|
||||
when(repository.deleteWeight(1L, 10L, 20L, 2)).thenReturn(true);
|
||||
@@ -488,7 +582,7 @@ class InboundMeasurementServiceTest {
|
||||
item.setPackageCount(3);
|
||||
item.setSourceImageFileId(500L);
|
||||
InboundWeightResultEntity weight = weight(20L, "20.000", "KG", "CONFIRMED", 1);
|
||||
weight.setFinalWeightKg(new BigDecimal("20.000"));
|
||||
weight.setNetWeightKg(new BigDecimal("20.000"));
|
||||
when(repository.findInbound(1L, 10L)).thenReturn(inbound);
|
||||
when(repository.findMeasurement(1L, 10L, 30L)).thenReturn(measurement);
|
||||
when(repository.listItems(1L, 30L)).thenReturn(List.of(item));
|
||||
@@ -592,6 +686,7 @@ class InboundMeasurementServiceTest {
|
||||
InboundOrderEntity inbound = new InboundOrderEntity();
|
||||
inbound.setId(10L);
|
||||
inbound.setTenantId(1L);
|
||||
inbound.setWarehouseId(100L);
|
||||
inbound.setProcessStatus(status);
|
||||
inbound.setTotalPackageCount(3);
|
||||
inbound.setVersion(0);
|
||||
@@ -605,10 +700,21 @@ class InboundMeasurementServiceTest {
|
||||
weight.setTenantId(1L);
|
||||
weight.setInboundId(10L);
|
||||
weight.setFileId(id + 100L);
|
||||
weight.setPalletId(501L);
|
||||
weight.setPalletCode("PLT-501");
|
||||
weight.setPalletType("STANDARD");
|
||||
weight.setPalletCapacityCbm(new BigDecimal("2.0000"));
|
||||
weight.setPalletTareWeightKg(BigDecimal.ZERO.setScale(3));
|
||||
weight.setOcrWeightValue(new BigDecimal(value));
|
||||
weight.setOcrWeightUnit(unit);
|
||||
weight.setRecognitionStatus(status);
|
||||
weight.setVersion(version);
|
||||
return weight;
|
||||
}
|
||||
|
||||
private WarehousePalletLocationClient.PalletSnapshot palletSnapshot() {
|
||||
return new WarehousePalletLocationClient.PalletSnapshot(
|
||||
501L, "PLT-501", "STANDARD", new BigDecimal("2.0000"),
|
||||
new BigDecimal("18.500"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user