发布当前测试版本至临时灰度环境 #19

Merged
admin merged 177 commits from test into main 2026-10-07 11:04:53 +08:00
3 changed files with 78 additions and 2 deletions
Showing only changes of commit babc7de4b6 - Show all commits
@@ -401,6 +401,7 @@ public class OrderApplicationService {
"提交订单前必须完善货物品名、包装类型、箱数、毛重和体积");
}
validatePersistedCargoQuantity(cargo, cargoIndex, true);
requireDropshipSku(order.getFulfillmentType(), cargo.getSkuNo(), cargoIndex);
if (Boolean.TRUE.equals(cargo.getWoodenProduct()) && !Boolean.TRUE.equals(order.getCustomsInspection())) {
throw new BizException(ResultCode.VALIDATION_FAILED, "木制品必须选择商检");
}
@@ -441,7 +442,8 @@ public class OrderApplicationService {
}
validateWoodInspection(request);
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())
|| cargo.packageCount() < 1 || cargo.grossWeightKg() == null
|| cargo.grossWeightKg().signum() <= 0 || cargo.volumeCbm() == null
@@ -449,6 +451,7 @@ public class OrderApplicationService {
throw new BizException(ResultCode.VALIDATION_FAILED,
"提交订单前必须完善货物品名、包装类型、箱数、毛重和体积");
}
requireDropshipSku(request.fulfillmentType(), cargo.skuNo(), cargoIndex);
}
validateMixedCartons(request);
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) {
for (int index = 0; index < cargoes.size(); index++) {
OrderRequests.Cargo cargo = cargoes.get(index);
@@ -1399,7 +1399,7 @@ components:
type: object
required: [packageCount, woodenProduct]
properties:
skuNo: {type: string, maxLength: 64}
skuNo: {type: string, maxLength: 64, description: 草稿可空;FBA 或 ONE_CLICK_DROPSHIP 订单提交及已提交编辑时每条货物必填}
cargoName: {type: string, maxLength: 128}
cargoNameEn: {type: string, maxLength: 128}
productImageFileId: {type: string, pattern: '^[1-9][0-9]*$'}
@@ -375,6 +375,72 @@ class OrderApplicationServiceStateTest {
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
void submittingDraftPreparesInboundForWarehouseMeasurementBeforeReview() {
OrderRepository repository = mock(OrderRepository.class);