fix(firstleg): update submitted outer dimensions safely
This commit is contained in:
+18
@@ -109,6 +109,24 @@ public class PlatformInboundMeasurementController {
|
|||||||
return ApiResponse.success(service.updateCalculationStrategy(tenantId, inboundId, request));
|
return ApiResponse.success(service.updateCalculationStrategy(tenantId, inboundId, request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BusinessAudit(event = "INBOUND_MEASUREMENT_OUTER_DIMENSIONS_UPDATE",
|
||||||
|
resourceType = "INBOUND_MEASUREMENT_ITEM", resourceId = "#itemId",
|
||||||
|
description = "更新仓库外箱长宽高")
|
||||||
|
@Operation(summary = "更新仓库外箱长宽高",
|
||||||
|
description = "独立更新当前测量批次指定明细的仓库外箱尺寸并重算体积;不改变测量提交或审核状态。"
|
||||||
|
+ "仅当客户已确认费用且该票已装柜完成时冻结。")
|
||||||
|
@PutMapping("/measurement/items/{itemId}/outer-dimensions")
|
||||||
|
@PreAuthorize("hasAuthority('platform:firstleg:inbound:measure:edit')")
|
||||||
|
public ApiResponse<InboundMeasurementResponses.OuterDimensionsUpdated> updateOuterDimensions(
|
||||||
|
@AuthenticationPrincipal AuthenticatedUser user,
|
||||||
|
@RequestParam long tenantId,
|
||||||
|
@PathVariable long inboundId,
|
||||||
|
@PathVariable long itemId,
|
||||||
|
@Valid @RequestBody InboundMeasurementRequests.UpdateOuterDimensionsRequest request) {
|
||||||
|
requirePlatformTenant(user, tenantId);
|
||||||
|
return ApiResponse.success(service.updateOuterDimensions(tenantId, inboundId, itemId, request));
|
||||||
|
}
|
||||||
|
|
||||||
@BusinessAudit(event = "INBOUND_MEASUREMENT_SUBMIT", resourceType = "INBOUND",
|
@BusinessAudit(event = "INBOUND_MEASUREMENT_SUBMIT", resourceType = "INBOUND",
|
||||||
resourceId = "#inboundId", description = "确认测量并提交审核")
|
resourceId = "#inboundId", description = "确认测量并提交审核")
|
||||||
@Operation(summary = "确认测量并提交审核",
|
@Operation(summary = "确认测量并提交审核",
|
||||||
|
|||||||
@@ -95,6 +95,18 @@ public final class InboundMeasurementRequests {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record UpdateOuterDimensionsRequest(
|
||||||
|
@NotNull @Positive Long measurementId,
|
||||||
|
@NotNull @PositiveOrZero Integer version,
|
||||||
|
@DecimalMin("0.001") @DecimalMax("999999999.999")
|
||||||
|
@Digits(integer = 9, fraction = 3) BigDecimal outerLengthCm,
|
||||||
|
@DecimalMin("0.001") @DecimalMax("999999999.999")
|
||||||
|
@Digits(integer = 9, fraction = 3) BigDecimal outerWidthCm,
|
||||||
|
@DecimalMin("0.001") @DecimalMax("999999999.999")
|
||||||
|
@Digits(integer = 9, fraction = 3) BigDecimal outerHeightCm
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public record ConfirmedPackageCountRequest(
|
public record ConfirmedPackageCountRequest(
|
||||||
@NotNull @PositiveOrZero Integer measurementVersion,
|
@NotNull @PositiveOrZero Integer measurementVersion,
|
||||||
@NotNull @Positive @Max(1000000) Integer confirmedPackageCount
|
@NotNull @Positive @Max(1000000) Integer confirmedPackageCount
|
||||||
|
|||||||
@@ -188,6 +188,11 @@ public final class InboundMeasurementResponses {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record OuterDimensionsUpdated(
|
||||||
|
Long measurementId, Integer version, String status, Long itemId
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public record MeasurementSubmitted(Long measurementId, Integer version, String processStatus,
|
public record MeasurementSubmitted(Long measurementId, Integer version, String processStatus,
|
||||||
String measureReviewStatus,
|
String measureReviewStatus,
|
||||||
@Schema(description = "测量完成后的推荐托盘类型,仅为建议,不代表已分配托盘",
|
@Schema(description = "测量完成后的推荐托盘类型,仅为建议,不代表已分配托盘",
|
||||||
|
|||||||
@@ -171,13 +171,7 @@ public class InboundMeasurementService {
|
|||||||
InboundMeasurementRequests.UpdateCalculationStrategyRequest request) {
|
InboundMeasurementRequests.UpdateCalculationStrategyRequest request) {
|
||||||
InboundOrderEntity inbound = repository.lockInbound(tenantId, inboundId);
|
InboundOrderEntity inbound = repository.lockInbound(tenantId, inboundId);
|
||||||
if (inbound == null) throw new BizException(ResultCode.NOT_FOUND, "入库单不存在");
|
if (inbound == null) throw new BizException(ResultCode.NOT_FOUND, "入库单不存在");
|
||||||
var currentFee = pricingRepository.findLatestFeeForUpdate(tenantId, inboundId);
|
requireMeasurementRevisionEditable(tenantId, inboundId, inbound, "箱规计算规则");
|
||||||
boolean customerConfirmed = currentFee != null && currentFee.getCustomerConfirmedAt() != null;
|
|
||||||
boolean loadingCompleted = Set.of("LOADED", "DELIVERED").contains(inbound.getProcessStatus());
|
|
||||||
if (customerConfirmed && loadingCompleted) {
|
|
||||||
throw new BizException(ResultCode.CONFLICT,
|
|
||||||
"客户已确认且该票已装柜完成,不能修改箱规计算规则");
|
|
||||||
}
|
|
||||||
if ("MULTIPLY".equals(request.coefficientMode()) && request.chargeRuleId() == null) {
|
if ("MULTIPLY".equals(request.coefficientMode()) && request.chargeRuleId() == null) {
|
||||||
throw new BizException(ResultCode.VALIDATION_FAILED, "箱规系数模式必须选择计费规则");
|
throw new BizException(ResultCode.VALIDATION_FAILED, "箱规系数模式必须选择计费规则");
|
||||||
}
|
}
|
||||||
@@ -199,6 +193,40 @@ public class InboundMeasurementService {
|
|||||||
request.coefficientMode(), appliedRuleId);
|
request.coefficientMode(), appliedRuleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public InboundMeasurementResponses.OuterDimensionsUpdated updateOuterDimensions(
|
||||||
|
long tenantId, long inboundId, long itemId,
|
||||||
|
InboundMeasurementRequests.UpdateOuterDimensionsRequest request) {
|
||||||
|
InboundOrderEntity inbound = repository.lockInbound(tenantId, inboundId);
|
||||||
|
if (inbound == null) throw new BizException(ResultCode.NOT_FOUND, "入库单不存在");
|
||||||
|
requireMeasurementRevisionEditable(tenantId, inboundId, inbound, "仓库外箱尺寸");
|
||||||
|
InboundMeasurementEntity measurement = repository.lockMeasurement(
|
||||||
|
tenantId, inboundId, request.measurementId());
|
||||||
|
if (measurement == null) throw new BizException(ResultCode.NOT_FOUND, "测量批次不存在");
|
||||||
|
requireVersion(request.version(), measurement.getVersion());
|
||||||
|
List<InboundMeasurementItemEntity> items = repository.listItems(tenantId, measurement.getId());
|
||||||
|
batchService.recalculateOuterDimensions(tenantId, measurement, items, itemId,
|
||||||
|
request.outerLengthCm(), request.outerWidthCm(), request.outerHeightCm());
|
||||||
|
measurement.setUpdatedAt(LocalDateTime.now());
|
||||||
|
if (!repository.updateMeasurement(measurement)) throw concurrentModification();
|
||||||
|
inbound.setActualVolumeCbm(measurement.getTotalVolumeCbm());
|
||||||
|
inbound.setVolumeWeightKg(measurement.getVolumeWeightKg());
|
||||||
|
if (!repository.updateInbound(inbound)) throw concurrentModification();
|
||||||
|
return new InboundMeasurementResponses.OuterDimensionsUpdated(
|
||||||
|
measurement.getId(), measurement.getVersion(), measurement.getStatus(), itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requireMeasurementRevisionEditable(long tenantId, long inboundId,
|
||||||
|
InboundOrderEntity inbound, String subject) {
|
||||||
|
var currentFee = pricingRepository.findLatestFeeForUpdate(tenantId, inboundId);
|
||||||
|
boolean customerConfirmed = currentFee != null && currentFee.getCustomerConfirmedAt() != null;
|
||||||
|
boolean loadingCompleted = Set.of("LOADED", "DELIVERED").contains(inbound.getProcessStatus());
|
||||||
|
if (customerConfirmed && loadingCompleted) {
|
||||||
|
throw new BizException(ResultCode.CONFLICT,
|
||||||
|
"客户已确认且该票已装柜完成,不能修改" + subject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public InboundMeasurementResponses.MeasurementSubmitted submit(
|
public InboundMeasurementResponses.MeasurementSubmitted submit(
|
||||||
long tenantId, long inboundId, long operatorId,
|
long tenantId, long inboundId, long operatorId,
|
||||||
|
|||||||
@@ -116,26 +116,64 @@ public class MeasurementBatchService {
|
|||||||
for (int index = 0; index < existingItems.size(); index++) {
|
for (int index = 0; index < existingItems.size(); index++) {
|
||||||
InboundMeasurementItemEntity target = existingItems.get(index);
|
InboundMeasurementItemEntity target = existingItems.get(index);
|
||||||
InboundMeasurementItemEntity source = recalculated.get(index);
|
InboundMeasurementItemEntity source = recalculated.get(index);
|
||||||
target.setGirthCm(source.getGirthCm());
|
applyRecalculatedItem(target, source, false);
|
||||||
target.setUnitVolumeCbm(source.getUnitVolumeCbm());
|
|
||||||
target.setVolumeRawCbm(source.getVolumeRawCbm());
|
|
||||||
target.setVolumeCbm(source.getVolumeCbm());
|
|
||||||
target.setTotalVolumeCbm(source.getTotalVolumeCbm());
|
|
||||||
target.setVolumeWeightKg(source.getVolumeWeightKg());
|
|
||||||
target.setChargeRuleId(source.getChargeRuleId());
|
|
||||||
target.setCoefficientMode(source.getCoefficientMode());
|
|
||||||
target.setCalculationRuleVersion(source.getCalculationRuleVersion());
|
|
||||||
target.setOuterLengthCm(source.getOuterLengthCm());
|
|
||||||
target.setOuterWidthCm(source.getOuterWidthCm());
|
|
||||||
target.setOuterHeightCm(source.getOuterHeightCm());
|
|
||||||
target.setUpdatedAt(LocalDateTime.now());
|
|
||||||
if (!repository.updateItem(target)) {
|
|
||||||
throw concurrentModification();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
applyTotals(measurement, existingItems);
|
applyTotals(measurement, existingItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void recalculateOuterDimensions(long tenantId, InboundMeasurementEntity measurement,
|
||||||
|
List<InboundMeasurementItemEntity> existingItems, long itemId,
|
||||||
|
BigDecimal outerLengthCm, BigDecimal outerWidthCm,
|
||||||
|
BigDecimal outerHeightCm) {
|
||||||
|
InboundMeasurementItemEntity target = existingItems.stream()
|
||||||
|
.filter(item -> item.getId() != null && item.getId() == itemId)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new BizException(ResultCode.NOT_FOUND, "测量明细不存在"));
|
||||||
|
MeasurementBatchCommand command = new MeasurementBatchCommand(
|
||||||
|
tenantId, measurement.getInboundId(), measurement.getId(), measurement.getVersion(),
|
||||||
|
measurement.getSourceType(), measurement.getSourceCode(), measurement.getExternalEventNo(),
|
||||||
|
measurement.getDeviceCode(), measurement.getWarehouseCode(), measurement.getMeasuredAt(),
|
||||||
|
measurement.getRawPayloadJson(), measurement.getOriginalDocumentNo(),
|
||||||
|
measurement.getOriginalGrossWeightKg(), measurement.getOriginalVolumeCbm(),
|
||||||
|
measurement.getActualGoodsName(), measurement.getCreatedBy(),
|
||||||
|
List.of(new MeasurementBatchCommand.Item(
|
||||||
|
target.getInboundDetailId(), target.getItemNo(), target.getBoxSpecification(),
|
||||||
|
target.getPackageCount(), target.getLengthCm(), target.getWidthCm(), target.getHeightCm(),
|
||||||
|
null, target.getSourceImageFileId(), target.getOverLimitWarning(), outerLengthCm,
|
||||||
|
outerWidthCm, outerHeightCm, target.getChargeRuleId(), target.getCoefficientMode(),
|
||||||
|
target.getRemark())));
|
||||||
|
InboundMeasurementItemEntity recalculated = calculateItems(
|
||||||
|
command, dimensionWeighting.load(tenantId)).get(0);
|
||||||
|
applyRecalculatedItem(target, recalculated, true);
|
||||||
|
applyTotals(measurement, existingItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyRecalculatedItem(InboundMeasurementItemEntity target,
|
||||||
|
InboundMeasurementItemEntity source,
|
||||||
|
boolean updateManualDimensions) {
|
||||||
|
target.setGirthCm(source.getGirthCm());
|
||||||
|
target.setUnitVolumeCbm(source.getUnitVolumeCbm());
|
||||||
|
target.setVolumeRawCbm(source.getVolumeRawCbm());
|
||||||
|
target.setVolumeCbm(source.getVolumeCbm());
|
||||||
|
target.setTotalVolumeCbm(source.getTotalVolumeCbm());
|
||||||
|
target.setVolumeWeightKg(source.getVolumeWeightKg());
|
||||||
|
target.setChargeRuleId(source.getChargeRuleId());
|
||||||
|
target.setCoefficientMode(source.getCoefficientMode());
|
||||||
|
target.setCalculationRuleVersion(source.getCalculationRuleVersion());
|
||||||
|
target.setOuterLengthCm(source.getOuterLengthCm());
|
||||||
|
target.setOuterWidthCm(source.getOuterWidthCm());
|
||||||
|
target.setOuterHeightCm(source.getOuterHeightCm());
|
||||||
|
if (updateManualDimensions) {
|
||||||
|
target.setManualOuterLengthCm(source.getManualOuterLengthCm());
|
||||||
|
target.setManualOuterWidthCm(source.getManualOuterWidthCm());
|
||||||
|
target.setManualOuterHeightCm(source.getManualOuterHeightCm());
|
||||||
|
}
|
||||||
|
target.setUpdatedAt(LocalDateTime.now());
|
||||||
|
if (!repository.updateItem(target)) {
|
||||||
|
throw concurrentModification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 人工补录会整批替换可编辑测量项,但不能抹掉同一项已冻结的扫码身份与设备取证。
|
* 人工补录会整批替换可编辑测量项,但不能抹掉同一项已冻结的扫码身份与设备取证。
|
||||||
* 只按入库货物明细和明细号精确匹配,避免把一个箱码猜测性地复制给其他测量项。
|
* 只按入库货物明细和明细号精确匹配,避免把一个箱码猜测性地复制给其他测量项。
|
||||||
|
|||||||
@@ -1015,6 +1015,25 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
'200': {description: 成功或业务失败,按响应体 code 判断}
|
'200': {description: 成功或业务失败,按响应体 code 判断}
|
||||||
'403': {description: 无测量编辑权限}
|
'403': {description: 无测量编辑权限}
|
||||||
|
/api/platform/v1/first-leg/inbounds/{inboundId}/measurement/items/{itemId}/outer-dimensions:
|
||||||
|
put:
|
||||||
|
summary: 更新仓库外箱长宽高
|
||||||
|
description: >-
|
||||||
|
独立更新当前测量批次指定明细的仓库外箱尺寸并重算体积,不覆盖整批测量数据,
|
||||||
|
不改变测量提交或审核状态。客户未确认或该票尚未装柜完成时均可修改;
|
||||||
|
仅当客户已确认费用且该票已装柜完成时冻结。
|
||||||
|
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: itemId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {$ref: '#/components/schemas/InboundMeasurementOuterDimensionsRequest'}
|
||||||
|
responses:
|
||||||
|
'200': {description: 成功或业务失败,按响应体 code 判断}
|
||||||
|
'403': {description: 无测量编辑权限}
|
||||||
/api/platform/v1/first-leg/inbounds/{inboundId}/measurement/carton-scans:
|
/api/platform/v1/first-leg/inbounds/{inboundId}/measurement/carton-scans:
|
||||||
post:
|
post:
|
||||||
summary: 平台模拟单箱设备扫描
|
summary: 平台模拟单箱设备扫描
|
||||||
@@ -1992,6 +2011,16 @@ components:
|
|||||||
version: {type: integer, minimum: 0}
|
version: {type: integer, minimum: 0}
|
||||||
coefficientMode: {type: string, enum: [ACTUAL, ADD, MULTIPLY]}
|
coefficientMode: {type: string, enum: [ACTUAL, ADD, MULTIPLY]}
|
||||||
chargeRuleId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, description: MULTIPLY 模式必填}
|
chargeRuleId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, description: MULTIPLY 模式必填}
|
||||||
|
InboundMeasurementOuterDimensionsRequest:
|
||||||
|
type: object
|
||||||
|
required: [measurementId, version]
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
measurementId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||||
|
version: {type: integer, minimum: 0}
|
||||||
|
outerLengthCm: {type: number, minimum: 0.001, nullable: true}
|
||||||
|
outerWidthCm: {type: number, minimum: 0.001, nullable: true}
|
||||||
|
outerHeightCm: {type: number, minimum: 0.001, nullable: true}
|
||||||
InboundMeasurementItemRequest:
|
InboundMeasurementItemRequest:
|
||||||
type: object
|
type: object
|
||||||
required: [inboundDetailId, itemNo, boxSpecification, packageCount, lengthCm, widthCm, heightCm]
|
required: [inboundDetailId, itemNo, boxSpecification, packageCount, lengthCm, widthCm, heightCm]
|
||||||
|
|||||||
+9
@@ -68,6 +68,15 @@ class InboundMeasurementEvidenceOpenApiContractTest {
|
|||||||
.contains("不覆盖整批测量数据", "不改变测量提交或审核状态", "客户已确认费用且该票已装柜完成");
|
.contains("不覆盖整批测量数据", "不改变测量提交或审核状态", "客户已确认费用且该票已装柜完成");
|
||||||
assertThat(properties(schemas, "InboundMeasurementCalculationStrategyRequest"))
|
assertThat(properties(schemas, "InboundMeasurementCalculationStrategyRequest"))
|
||||||
.containsKeys("measurementId", "version", "coefficientMode", "chargeRuleId");
|
.containsKeys("measurementId", "version", "coefficientMode", "chargeRuleId");
|
||||||
|
String outerDimensionsPath = "/api/platform/v1/first-leg/inbounds/{inboundId}"
|
||||||
|
+ "/measurement/items/{itemId}/outer-dimensions";
|
||||||
|
assertThat(paths).containsKey(outerDimensionsPath);
|
||||||
|
Map<String, Object> outerDimensionsOperation = stringMap(
|
||||||
|
stringMap(paths.get(outerDimensionsPath)).get("put"));
|
||||||
|
assertThat(outerDimensionsOperation.get("description").toString())
|
||||||
|
.contains("不覆盖整批测量数据", "不改变测量提交或审核状态", "客户已确认费用且该票已装柜完成");
|
||||||
|
assertThat(properties(schemas, "InboundMeasurementOuterDimensionsRequest"))
|
||||||
|
.containsKeys("measurementId", "version", "outerLengthCm", "outerWidthCm", "outerHeightCm");
|
||||||
|
|
||||||
Map<String, Object> itemProperties = properties(schemas, "InboundMeasurementItem");
|
Map<String, Object> itemProperties = properties(schemas, "InboundMeasurementItem");
|
||||||
assertThat(itemProperties).containsKeys(
|
assertThat(itemProperties).containsKeys(
|
||||||
|
|||||||
@@ -139,6 +139,39 @@ class InboundMeasurementServiceTest {
|
|||||||
verify(repository, never()).lockMeasurement(anyLong(), anyLong(), anyLong());
|
verify(repository, never()).lockMeasurement(anyLong(), anyLong(), anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void updatesSubmittedWarehouseOuterDimensionsWithoutReplacingMeasurementBatch() {
|
||||||
|
InboundOrderEntity inbound = inbound("MEASURE_PENDING");
|
||||||
|
InboundMeasurementEntity measurement = new InboundMeasurementEntity();
|
||||||
|
measurement.setId(30L);
|
||||||
|
measurement.setTenantId(1L);
|
||||||
|
measurement.setInboundId(10L);
|
||||||
|
measurement.setStatus("SUBMITTED");
|
||||||
|
measurement.setVersion(5);
|
||||||
|
measurement.setTotalVolumeCbm(new BigDecimal("1.8000"));
|
||||||
|
measurement.setVolumeWeightKg(new BigDecimal("300.600"));
|
||||||
|
InboundMeasurementItemEntity item = new InboundMeasurementItemEntity();
|
||||||
|
item.setId(31L);
|
||||||
|
item.setTenantId(1L);
|
||||||
|
item.setMeasurementId(30L);
|
||||||
|
when(repository.lockInbound(1L, 10L)).thenReturn(inbound);
|
||||||
|
when(repository.lockMeasurement(1L, 10L, 30L)).thenReturn(measurement);
|
||||||
|
when(repository.listItems(1L, 30L)).thenReturn(List.of(item));
|
||||||
|
when(repository.updateMeasurement(measurement)).thenReturn(true);
|
||||||
|
when(repository.updateInbound(inbound)).thenReturn(true);
|
||||||
|
|
||||||
|
var response = service.updateOuterDimensions(1L, 10L, 31L,
|
||||||
|
new InboundMeasurementRequests.UpdateOuterDimensionsRequest(
|
||||||
|
30L, 5, new BigDecimal("30"), new BigDecimal("20"), new BigDecimal("20")));
|
||||||
|
|
||||||
|
assertThat(response.status()).isEqualTo("SUBMITTED");
|
||||||
|
assertThat(response.itemId()).isEqualTo(31L);
|
||||||
|
verify(batchService).recalculateOuterDimensions(1L, measurement, List.of(item), 31L,
|
||||||
|
new BigDecimal("30"), new BigDecimal("20"), new BigDecimal("20"));
|
||||||
|
verify(repository, never()).replaceItems(anyLong(), anyLong(), any());
|
||||||
|
assertThat(inbound.getActualVolumeCbm()).isEqualByComparingTo("1.8000");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void correctingWeightKeepsOcrOriginalAndWritesImmutableRevision() {
|
void correctingWeightKeepsOcrOriginalAndWritesImmutableRevision() {
|
||||||
InboundOrderEntity inbound = inbound("MEASURING");
|
InboundOrderEntity inbound = inbound("MEASURING");
|
||||||
|
|||||||
@@ -133,6 +133,46 @@ class MeasurementBatchServiceTest {
|
|||||||
verify(repository, never()).replaceItems(anyLong(), anyLong(), any());
|
verify(repository, never()).replaceItems(anyLong(), anyLong(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void recalculatesOneSubmittedWarehouseOuterDimensionRowInPlace() {
|
||||||
|
InboundMeasurementEntity measurement = new InboundMeasurementEntity();
|
||||||
|
measurement.setId(100L);
|
||||||
|
measurement.setTenantId(1L);
|
||||||
|
measurement.setInboundId(10L);
|
||||||
|
measurement.setSourceType("MANUAL");
|
||||||
|
measurement.setStatus("SUBMITTED");
|
||||||
|
measurement.setVersion(4);
|
||||||
|
measurement.setCreatedBy(9L);
|
||||||
|
InboundMeasurementItemEntity existing = new InboundMeasurementItemEntity();
|
||||||
|
existing.setId(200L);
|
||||||
|
existing.setTenantId(1L);
|
||||||
|
existing.setMeasurementId(100L);
|
||||||
|
existing.setInboundDetailId(80001L);
|
||||||
|
existing.setBoxCode("RK-001#1");
|
||||||
|
existing.setItemNo("001");
|
||||||
|
existing.setBoxSpecification("40x30x20cm");
|
||||||
|
existing.setPackageCount(2);
|
||||||
|
existing.setLengthCm(new BigDecimal("40"));
|
||||||
|
existing.setWidthCm(new BigDecimal("30"));
|
||||||
|
existing.setHeightCm(new BigDecimal("20"));
|
||||||
|
when(repository.updateItem(existing)).thenReturn(true);
|
||||||
|
|
||||||
|
service.recalculateOuterDimensions(1L, measurement, List.of(existing), 200L,
|
||||||
|
new BigDecimal("30"), new BigDecimal("20"), new BigDecimal("20"));
|
||||||
|
|
||||||
|
assertThat(existing.getId()).isEqualTo(200L);
|
||||||
|
assertThat(existing.getBoxCode()).isEqualTo("RK-001#1");
|
||||||
|
assertThat(existing.getManualOuterLengthCm()).isEqualByComparingTo("30");
|
||||||
|
assertThat(existing.getManualOuterWidthCm()).isEqualByComparingTo("20");
|
||||||
|
assertThat(existing.getManualOuterHeightCm()).isEqualByComparingTo("20");
|
||||||
|
assertThat(existing.getOuterLengthCm()).isEqualByComparingTo("30.000");
|
||||||
|
assertThat(existing.getUnitVolumeCbm()).isEqualByComparingTo("0.0120");
|
||||||
|
assertThat(measurement.getStatus()).isEqualTo("SUBMITTED");
|
||||||
|
assertThat(measurement.getTotalVolumeCbm()).isEqualByComparingTo("0.0240");
|
||||||
|
verify(repository).updateItem(existing);
|
||||||
|
verify(repository, never()).replaceItems(anyLong(), anyLong(), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void automaticallyAppliesCustomerDefaultRuleToActualMeasurement() {
|
void automaticallyAppliesCustomerDefaultRuleToActualMeasurement() {
|
||||||
CustomerChargeRuleEntity rule = new CustomerChargeRuleEntity();
|
CustomerChargeRuleEntity rule = new CustomerChargeRuleEntity();
|
||||||
|
|||||||
Reference in New Issue
Block a user