优化
This commit is contained in:
@@ -212,6 +212,7 @@ paths:
|
||||
description: >-
|
||||
需要 platform:order:declaration:edit。货物使用订单内 itemNo 定位,不接受货物数据库 ID;
|
||||
不允许修改客户、国内收货仓、订单号、入仓码、状态、仓库/PDA/设备实测、测量审核或计费事实。
|
||||
仅待审核、待测量数据、待分柜阶段允许修改;进入装柜中及后续阶段后拒绝修改。
|
||||
已有测量或计费事实不阻断客户申报快照更新,详情继续以最新申报与既有实测分别展示;
|
||||
只有渠道发生变化时才在写入前校验同柜/分柜/装柜可逆性和重新计价资格,任何校验失败均不写入。
|
||||
正式门禁分别为 /internal/firstleg/v1/inbounds/order-channel-changes/validate 与
|
||||
|
||||
+1
@@ -66,6 +66,7 @@ class OrderDeclarationUpdateContractTest {
|
||||
assertThat(map(row.get("actualVolumeCbm")).get("description").toString()).contains("仅 Firstleg 实测");
|
||||
assertThat(map(row.get("estimatedVolumeCbm")).get("description").toString()).contains("平台运营");
|
||||
assertThat(source).contains("ORDER_DECLARATION_UPDATED_V1", "platform:order:declaration:edit", "A0409",
|
||||
"仅待审核、待测量数据、待分柜阶段允许修改",
|
||||
"/internal/firstleg/v1/inbounds/order-channel-changes/validate",
|
||||
"/internal/firstleg/v1/pricing/order-channel-changes/validate",
|
||||
"/internal/firstleg/v1/pricing/order-channel-changes/apply");
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.baiyue.order.service;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.client.FirstlegUnifiedOrderClient;
|
||||
import com.baiyue.order.entity.OrderEntity;
|
||||
import com.baiyue.order.entity.OrderStatus;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(OrderDeclarationEditGuard.class)
|
||||
@TestPropertySource(properties = "baiyue.security.internal-service-token=token")
|
||||
class OrderDeclarationEditGuardTest {
|
||||
@MockBean private FirstlegUnifiedOrderClient firstleg;
|
||||
@Resource private OrderDeclarationEditGuard guard;
|
||||
|
||||
@Test
|
||||
void allowsPendingReviewWithoutFirstlegAndWaitSplitWithAuthoritativeSummary() {
|
||||
OrderEntity pendingReview = order(OrderStatus.SUBMITTED);
|
||||
assertThatCode(() -> guard.requireEditable(pendingReview)).doesNotThrowAnyException();
|
||||
|
||||
OrderEntity waitSplit = order(OrderStatus.APPROVED);
|
||||
var request = new FirstlegUnifiedOrderClient.BatchRequest(11L, List.of(21L));
|
||||
var waitSplitSummary = summary("WAIT_SPLIT");
|
||||
when(firstleg.summaries("token", request)).thenReturn(ApiResponse.success(List.of(waitSplitSummary)));
|
||||
assertThatCode(() -> guard.requireEditable(waitSplit)).doesNotThrowAnyException();
|
||||
verify(firstleg).summaries("token", request);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsLoadingAndLaterStatuses() {
|
||||
OrderEntity order = order(OrderStatus.APPROVED);
|
||||
var request = new FirstlegUnifiedOrderClient.BatchRequest(11L, List.of(21L));
|
||||
for (String status : List.of("LOADING", "LOADED", "DELIVERED")) {
|
||||
var fulfillmentSummary = summary(status);
|
||||
when(firstleg.summaries("token", request)).thenReturn(ApiResponse.success(List.of(fulfillmentSummary)));
|
||||
assertThatThrownBy(() -> guard.requireEditable(order))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("已进入装柜或后续阶段");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void failsClosedWhenFirstlegSummaryIsMissing() {
|
||||
OrderEntity order = order(OrderStatus.APPROVED);
|
||||
var request = new FirstlegUnifiedOrderClient.BatchRequest(11L, List.of(21L));
|
||||
when(firstleg.summaries("token", request)).thenReturn(ApiResponse.success(List.of()));
|
||||
|
||||
assertThatThrownBy(() -> guard.requireEditable(order))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("状态校验服务暂时不可用");
|
||||
}
|
||||
|
||||
private FirstlegUnifiedOrderClient.Summary summary(String mainStatus) {
|
||||
var inbound = mock(FirstlegUnifiedOrderClient.Inbound.class);
|
||||
when(inbound.orderId()).thenReturn(21L);
|
||||
var summary = mock(FirstlegUnifiedOrderClient.Summary.class);
|
||||
when(summary.inbound()).thenReturn(inbound);
|
||||
when(summary.mainStatus()).thenReturn(mainStatus);
|
||||
return summary;
|
||||
}
|
||||
|
||||
private OrderEntity order(OrderStatus status) {
|
||||
OrderEntity order = new OrderEntity();
|
||||
order.setId(21L); order.setTenantId(11L); order.setStatus(status);
|
||||
return order;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ class OrderDeclarationUpdateServiceTest {
|
||||
@MockBean private OrderRepository repository;
|
||||
@MockBean private OrderPricingChannelGuard pricingChannelGuard;
|
||||
@MockBean private OrderFulfillmentChannelChangeGuard fulfillmentChannelGuard;
|
||||
@MockBean private OrderDeclarationEditGuard declarationEditGuard;
|
||||
@MockBean private ObjectMapper json;
|
||||
@Resource private OrderDeclarationUpdateService service;
|
||||
|
||||
@@ -57,6 +58,7 @@ class OrderDeclarationUpdateServiceTest {
|
||||
.contains("channelCode", "channelName", "customerRemark", "expectedArrivalAt", "estimatedVolumeCbm",
|
||||
"cargoName", "packageCount", "totalQuantity", "lengthCm", "grossWeightKg");
|
||||
verify(pricingChannelGuard).requireAvailable(100L, 31L, "NEW", "FBA");
|
||||
verify(declarationEditGuard).requireEditable(order);
|
||||
verify(repository).insertHistory(any());
|
||||
verify(repository, never()).insertOutbox(any());
|
||||
assertThat(cargo.getPackageCount()).isEqualTo(20);
|
||||
@@ -128,6 +130,23 @@ class OrderDeclarationUpdateServiceTest {
|
||||
any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsDeclarationUpdateWhenFulfillmentHasReachedLoading() {
|
||||
OrderEntity order = order(OrderStatus.APPROVED, 3);
|
||||
when(repository.findOwned(100L, 200L)).thenReturn(order);
|
||||
org.mockito.Mockito.doThrow(new BizException(com.baiyue.common.core.api.ResultCode.CONFLICT,
|
||||
"订单已进入装柜或后续阶段,不能修改客户申报资料"))
|
||||
.when(declarationEditGuard).requireEditable(order);
|
||||
|
||||
assertThatThrownBy(() -> service.update(100L, 200L, 700L, "平台操作员",
|
||||
request(3, "OLD", "旧渠道", "备注")))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("已进入装柜");
|
||||
|
||||
verify(repository, never()).findCargo(anyLong(), anyLong());
|
||||
verify(repository, never()).updateDeclarationHeader(anyLong(), anyLong(), anyInt(), anyLong(),
|
||||
any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updatesPlanningFieldsWithCurrentDeclarationSnapshotAndVersion() {
|
||||
OrderEntity order = order(OrderStatus.SUBMITTED, 3);
|
||||
|
||||
Reference in New Issue
Block a user