fix(order): require dropship SKU before submission
This commit is contained in:
@@ -401,6 +401,7 @@ public class OrderApplicationService {
|
|||||||
"提交订单前必须完善货物品名、包装类型、箱数、毛重和体积");
|
"提交订单前必须完善货物品名、包装类型、箱数、毛重和体积");
|
||||||
}
|
}
|
||||||
validatePersistedCargoQuantity(cargo, cargoIndex, true);
|
validatePersistedCargoQuantity(cargo, cargoIndex, true);
|
||||||
|
requireDropshipSku(order.getFulfillmentType(), cargo.getSkuNo(), cargoIndex);
|
||||||
if (Boolean.TRUE.equals(cargo.getWoodenProduct()) && !Boolean.TRUE.equals(order.getCustomsInspection())) {
|
if (Boolean.TRUE.equals(cargo.getWoodenProduct()) && !Boolean.TRUE.equals(order.getCustomsInspection())) {
|
||||||
throw new BizException(ResultCode.VALIDATION_FAILED, "木制品必须选择商检");
|
throw new BizException(ResultCode.VALIDATION_FAILED, "木制品必须选择商检");
|
||||||
}
|
}
|
||||||
@@ -441,7 +442,8 @@ public class OrderApplicationService {
|
|||||||
}
|
}
|
||||||
validateWoodInspection(request);
|
validateWoodInspection(request);
|
||||||
validateRequestCargoQuantities(request.cargoes(), true);
|
validateRequestCargoQuantities(request.cargoes(), true);
|
||||||
for (var cargo : request.cargoes()) {
|
for (int cargoIndex = 0; cargoIndex < request.cargoes().size(); cargoIndex++) {
|
||||||
|
var cargo = request.cargoes().get(cargoIndex);
|
||||||
if (!StringUtils.hasText(cargo.cargoName()) || !StringUtils.hasText(cargo.packageType())
|
if (!StringUtils.hasText(cargo.cargoName()) || !StringUtils.hasText(cargo.packageType())
|
||||||
|| cargo.packageCount() < 1 || cargo.grossWeightKg() == null
|
|| cargo.packageCount() < 1 || cargo.grossWeightKg() == null
|
||||||
|| cargo.grossWeightKg().signum() <= 0 || cargo.volumeCbm() == null
|
|| cargo.grossWeightKg().signum() <= 0 || cargo.volumeCbm() == null
|
||||||
@@ -449,6 +451,7 @@ public class OrderApplicationService {
|
|||||||
throw new BizException(ResultCode.VALIDATION_FAILED,
|
throw new BizException(ResultCode.VALIDATION_FAILED,
|
||||||
"提交订单前必须完善货物品名、包装类型、箱数、毛重和体积");
|
"提交订单前必须完善货物品名、包装类型、箱数、毛重和体积");
|
||||||
}
|
}
|
||||||
|
requireDropshipSku(request.fulfillmentType(), cargo.skuNo(), cargoIndex);
|
||||||
}
|
}
|
||||||
validateMixedCartons(request);
|
validateMixedCartons(request);
|
||||||
if ("FBA".equals(request.destinationType())) {
|
if ("FBA".equals(request.destinationType())) {
|
||||||
@@ -467,6 +470,13 @@ public class OrderApplicationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void requireDropshipSku(String fulfillmentType, String skuNo, int cargoIndex) {
|
||||||
|
if ("ONE_CLICK_DROPSHIP".equals(fulfillmentType) && !StringUtils.hasText(skuNo)) {
|
||||||
|
throw new BizException(ResultCode.VALIDATION_FAILED,
|
||||||
|
"第 " + (cargoIndex + 1) + " 条一件代发货物必须填写 SKU NO.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validateRequestCargoQuantities(List<OrderRequests.Cargo> cargoes, boolean required) {
|
private void validateRequestCargoQuantities(List<OrderRequests.Cargo> cargoes, boolean required) {
|
||||||
for (int index = 0; index < cargoes.size(); index++) {
|
for (int index = 0; index < cargoes.size(); index++) {
|
||||||
OrderRequests.Cargo cargo = cargoes.get(index);
|
OrderRequests.Cargo cargo = cargoes.get(index);
|
||||||
|
|||||||
@@ -1399,7 +1399,7 @@ components:
|
|||||||
type: object
|
type: object
|
||||||
required: [packageCount, woodenProduct]
|
required: [packageCount, woodenProduct]
|
||||||
properties:
|
properties:
|
||||||
skuNo: {type: string, maxLength: 64}
|
skuNo: {type: string, maxLength: 64, description: 草稿可空;FBA 或 ONE_CLICK_DROPSHIP 订单提交及已提交编辑时每条货物必填}
|
||||||
cargoName: {type: string, maxLength: 128}
|
cargoName: {type: string, maxLength: 128}
|
||||||
cargoNameEn: {type: string, maxLength: 128}
|
cargoNameEn: {type: string, maxLength: 128}
|
||||||
productImageFileId: {type: string, pattern: '^[1-9][0-9]*$'}
|
productImageFileId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||||
|
|||||||
@@ -375,6 +375,72 @@ class OrderApplicationServiceStateTest {
|
|||||||
verify(repository).saveOrder(20002L, order);
|
verify(repository).saveOrder(20002L, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void submittingDropshipDraftRequiresEachPersistedSkuBeforeAnyStateWriteForBothTaxModes() {
|
||||||
|
for (String taxMode : List.of("BUY_DECLARATION", "TAX_REFUND")) {
|
||||||
|
for (String sku : java.util.Arrays.asList(null, "", " ")) {
|
||||||
|
OrderRepository repository = mock(OrderRepository.class);
|
||||||
|
OrderEntity order = persistedDraft("SELF_EXPRESS", "OVERSEAS");
|
||||||
|
order.setFulfillmentType("ONE_CLICK_DROPSHIP"); order.setTaxMode(taxMode);
|
||||||
|
OrderCargoEntity valid = completeCargo(); valid.setSkuNo("SKU-VALID");
|
||||||
|
OrderCargoEntity missing = completeCargo(); missing.setSkuNo(sku);
|
||||||
|
when(repository.findOwned(20002L, 1L)).thenReturn(order);
|
||||||
|
when(repository.findCargo(20002L, 1L)).thenReturn(List.of(valid, missing));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> service(repository, mock(OrderEligibilityGuard.class), mock(OrderMasterDataGuard.class))
|
||||||
|
.submit(20002L, 2L, "u", 1L, "missing-sku"))
|
||||||
|
.isInstanceOf(BizException.class).hasMessage("第 2 条一件代发货物必须填写 SKU NO.")
|
||||||
|
.extracting(exception -> ((BizException) exception).getResultCode()).isEqualTo(ResultCode.VALIDATION_FAILED);
|
||||||
|
assertThat(order.getStatus()).isEqualTo(OrderStatus.DRAFT);
|
||||||
|
assertThat(order.getSubmittedAt()).isNull(); assertThat(order.getInboundCode()).isNull();
|
||||||
|
verify(repository, never()).saveOrder(anyLong(), any());
|
||||||
|
verify(repository, never()).insertOutbox(any());
|
||||||
|
verify(repository, never()).insertHistory(any());
|
||||||
|
verify(repository, never()).completeIdempotency(anyLong(), any(), anyLong());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void submittingDropshipDraftWithSkuKeepsUpcOptional() {
|
||||||
|
OrderRepository repository = mock(OrderRepository.class);
|
||||||
|
OrderEntity order = persistedDraft("SELF_EXPRESS", "OVERSEAS");
|
||||||
|
order.setFulfillmentType("ONE_CLICK_DROPSHIP");
|
||||||
|
OrderCargoEntity cargo = completeCargo(); cargo.setSkuNo("SKU-VALID"); cargo.setUpcNo(null);
|
||||||
|
when(repository.findOwned(20002L, 1L)).thenReturn(order);
|
||||||
|
when(repository.findCargo(20002L, 1L)).thenReturn(List.of(cargo));
|
||||||
|
when(repository.findParties(20002L, 1L)).thenReturn(List.of());
|
||||||
|
when(repository.saveOrder(20002L, order)).thenReturn(1);
|
||||||
|
service(repository, mock(OrderEligibilityGuard.class), mock(OrderMasterDataGuard.class))
|
||||||
|
.transit(20002L, 2L, "u", 1L, OrderStatus.SUBMITTED, null);
|
||||||
|
assertThat(order.getStatus()).isEqualTo(OrderStatus.SUBMITTED);
|
||||||
|
verify(repository).saveOrder(20002L, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void submittedDropshipEditorCannotRemoveRequiredSku() {
|
||||||
|
OrderRepository repository = mock(OrderRepository.class);
|
||||||
|
OrderEntity order = persistedOrder(OrderStatus.SUBMITTED);
|
||||||
|
when(repository.findOwned(10001L, 1L)).thenReturn(order);
|
||||||
|
OrderRequests.SaveRequest source = request();
|
||||||
|
OrderRequests.SaveRequest missingSku = new OrderRequests.SaveRequest(
|
||||||
|
source.customerId(), source.customerName(), source.transportMode(), source.tradeTerm(),
|
||||||
|
source.destinationCountryCode(), source.destinationWarehouseId(), source.destinationWarehouseName(),
|
||||||
|
source.expectedShipDate(), source.customerRemark(), source.sender(), source.receiver(), source.cargoes(),
|
||||||
|
source.pickupMethod(), source.requestedPickupAt(), source.receivingWarehouseId(),
|
||||||
|
source.receivingWarehouseName(), source.channelCode(), source.channelName(), source.carrierId(),
|
||||||
|
source.carrierName(), source.taxMode(), source.pricingTaxMode(), source.containerMode(),
|
||||||
|
source.customsInspection(), source.destinationType(), source.amazonWarehouseCode(), source.shipmentId(),
|
||||||
|
source.referenceId(), source.inboundCode(), "ONE_CLICK_DROPSHIP");
|
||||||
|
assertThatThrownBy(() -> service(repository, mock(OrderEligibilityGuard.class), mock(OrderMasterDataGuard.class))
|
||||||
|
.updateSubmittedOrder(10001L, 2L, 1L, missingSku))
|
||||||
|
.isInstanceOf(BizException.class).hasMessage("第 1 条一件代发货物必须填写 SKU NO.")
|
||||||
|
.extracting(exception -> ((BizException) exception).getResultCode()).isEqualTo(ResultCode.VALIDATION_FAILED);
|
||||||
|
verify(repository, never()).saveOrder(anyLong(), any());
|
||||||
|
verify(repository, never()).replaceDraftChildren(anyLong(), anyLong());
|
||||||
|
verify(repository, never()).insertHistory(any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void submittingDraftPreparesInboundForWarehouseMeasurementBeforeReview() {
|
void submittingDraftPreparesInboundForWarehouseMeasurementBeforeReview() {
|
||||||
OrderRepository repository = mock(OrderRepository.class);
|
OrderRepository repository = mock(OrderRepository.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user