diff --git a/firstleg/src/main/java/com/baiyue/firstleg/dto/MojiaMeasurementDtos.java b/firstleg/src/main/java/com/baiyue/firstleg/dto/MojiaMeasurementDtos.java index ff8e0bd65..96e61a581 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/dto/MojiaMeasurementDtos.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/dto/MojiaMeasurementDtos.java @@ -19,7 +19,7 @@ public final class MojiaMeasurementDtos { public record UploadRequest( @NotBlank @Size(max = 128) String boxCode, @JsonProperty("shipment_id") @JsonAlias("shipmentId") - @NotBlank @Size(max = 64) String shipmentId, + @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, diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/MojiaMeasurementOpenApiService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/MojiaMeasurementOpenApiService.java index ecbb8e1da..aa92f3f55 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/MojiaMeasurementOpenApiService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/MojiaMeasurementOpenApiService.java @@ -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, request.shipmentId().trim())); + image, optionalTrim(request.shipmentId()))); } catch (BizException exception) { if (exception.getResultCode() == ResultCode.NOT_FOUND) { return saveUnmatched(app, request, image, exception); @@ -117,7 +117,7 @@ public class MojiaMeasurementOpenApiService { receipt.setTenantId(app.tenantId()); receipt.setSubjectId(app.subjectId()); receipt.setBoxCode(request.boxCode().trim()); - receipt.setScannedShipmentId(request.shipmentId().trim()); + receipt.setScannedShipmentId(optionalTrim(request.shipmentId())); receipt.setLengthCm(request.length()); receipt.setWidthCm(request.width()); receipt.setHeightCm(request.height()); @@ -218,6 +218,10 @@ public class MojiaMeasurementOpenApiService { return normalized.length() <= 160 ? normalized : normalized.substring(0, 160); } + private String optionalTrim(String value) { + return value == null || value.isBlank() ? null : value.trim(); + } + private record InMemoryMultipartFile(byte[] content) implements MultipartFile { @Override public String getName() { return "image"; } @Override public String getOriginalFilename() { return "mojia-measurement.jpg"; } diff --git a/firstleg/src/main/resources/openapi/firstleg-v1.yaml b/firstleg/src/main/resources/openapi/firstleg-v1.yaml index 3ccfacc58..524888689 100644 --- a/firstleg/src/main/resources/openapi/firstleg-v1.yaml +++ b/firstleg/src/main/resources/openapi/firstleg-v1.yaml @@ -239,10 +239,10 @@ paths: application/json: schema: type: object - required: [boxCode, shipment_id, length, width, height, machineNo, picture] + required: [boxCode, 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箱标实际扫描得到;系统只保存,不生成且不覆盖客户下单值'} + 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} diff --git a/firstleg/src/test/java/com/baiyue/firstleg/controller/OpenApiInboundMeasurementControllerContractTest.java b/firstleg/src/test/java/com/baiyue/firstleg/controller/OpenApiInboundMeasurementControllerContractTest.java index 64d1af51a..7c1ec8313 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/controller/OpenApiInboundMeasurementControllerContractTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/controller/OpenApiInboundMeasurementControllerContractTest.java @@ -57,7 +57,8 @@ class OpenApiInboundMeasurementControllerContractTest { .contains("Nonce") .contains("inboundDetailId") .contains("multipart/form-data") - .contains("required: [boxCode, shipment_id, length, width, height, machineNo, picture]") + .contains("required: [boxCode, length, width, height, machineNo, picture]") + .doesNotContain("required: [boxCode, shipment_id") .contains("shipment_id:") .contains("不改变入库单状态"); } diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/MojiaMeasurementOpenApiServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/MojiaMeasurementOpenApiServiceTest.java index 8d06d7392..bb99f3f61 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/MojiaMeasurementOpenApiServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/MojiaMeasurementOpenApiServiceTest.java @@ -22,7 +22,6 @@ import org.springframework.test.util.ReflectionTestUtils; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.Map; -import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -33,7 +32,7 @@ import static org.mockito.Mockito.when; class MojiaMeasurementOpenApiServiceTest { @Test - void shipmentIdIsRequiredAndCamelCaseAliasIsAccepted() throws Exception { + void shipmentIdIsOptionalAndCamelCaseAliasIsAccepted() throws Exception { ObjectMapper mapper = new ObjectMapper().findAndRegisterModules(); var validator = Validation.buildDefaultValidatorFactory().getValidator(); @@ -41,12 +40,13 @@ class MojiaMeasurementOpenApiServiceTest { json().replace("\"shipment_id\"", "\"shipmentId\""), UploadRequest.class); UploadRequest missing = mapper.readValue( json().replace("\"shipment_id\":\"FBA19L5KMY2CU000002\",", ""), UploadRequest.class); + UploadRequest blank = mapper.readValue( + json().replace("FBA19L5KMY2CU000002", ""), UploadRequest.class); assertThat(camelCase.shipmentId()).isEqualTo("FBA19L5KMY2CU000002"); assertThat(validator.validate(camelCase)).isEmpty(); - assertThat(validator.validate(missing).stream() - .map(violation -> violation.getPropertyPath().toString()).collect(java.util.stream.Collectors.toSet())) - .isEqualTo(Set.of("shipmentId")); + assertThat(validator.validate(missing)).isEmpty(); + assertThat(validator.validate(blank)).isEmpty(); } @Test @@ -90,15 +90,16 @@ class MojiaMeasurementOpenApiServiceTest { images, receipts); ReflectionTestUtils.setField(service, "internalToken", "internal-token"); MeasurementRequestHeaders headers = new MeasurementRequestHeaders("mojia", null, null, null, null); + String requestJson = json().replace("\"shipment_id\":\"FBA19L5KMY2CU000002\",", ""); when(authenticator.authenticate("POST", MojiaMeasurementOpenApiService.CALLBACK_PATH, - headers, json(), false)).thenReturn(new AuthenticatedMeasurementApp("mojia", 10001L, 90001L, Map.of())); + headers, requestJson, false)).thenReturn(new AuthenticatedMeasurementApp("mojia", 10001L, 90001L, Map.of())); when(cartons.upsert(eq(10001L), eq(90001L), any())) .thenThrow(new BizException(ResultCode.NOT_FOUND, "箱号不存在或不属于当前客户")); when(images.uploadReceipt(eq("internal-token"), eq(90001L), eq(10001L), any(Long.TYPE), any())) .thenReturn(ApiResponse.success(new MeasurementImageClient.UploadResult( 3L, "mojia.jpg", "image/jpeg", 4L, "NOT_REQUIRED", null, null, null, null))); - UploadResponse result = service.receive(headers, json()); + UploadResponse result = service.receive(headers, requestJson); assertThat(result.accepted()).isTrue(); assertThat(result.matched()).isFalse(); @@ -108,7 +109,7 @@ class MojiaMeasurementOpenApiServiceTest { ArgumentCaptor.forClass(MojiaMeasurementReceiptEntity.class); verify(receipts).insert(receipt.capture()); assertThat(receipt.getValue().getBoxCode()).isEqualTo("RK-001#4-1"); - assertThat(receipt.getValue().getScannedShipmentId()).isEqualTo("FBA19L5KMY2CU000002"); + assertThat(receipt.getValue().getScannedShipmentId()).isNull(); assertThat(receipt.getValue().getLengthCm()).isEqualByComparingTo("60.1"); assertThat(receipt.getValue().getImageFileId()).isEqualTo(3L); assertThat(receipt.getValue().getStatus()).isEqualTo("UNMATCHED");