优化
This commit is contained in:
+3
@@ -22,6 +22,8 @@ class InboundOrderControllerContractTest {
|
||||
AuthenticatedUser.class, long.class, long.class);
|
||||
assertAuthority("printCartonLabels", "hasAuthority('platform:firstleg:inbound:view')",
|
||||
AuthenticatedUser.class, long.class, long.class, List.class, String.class);
|
||||
assertAuthority("printCartonLabelsBatch", "hasAuthority('platform:firstleg:inbound:view')",
|
||||
AuthenticatedUser.class, List.class, String.class);
|
||||
|
||||
Method page = PlatformInboundOrderController.class.getDeclaredMethod(
|
||||
"page", AuthenticatedUser.class, Long.class, InboundOrderQuery.class);
|
||||
@@ -47,6 +49,7 @@ class InboundOrderControllerContractTest {
|
||||
.contains("/api/platform/inbounds:")
|
||||
.contains("/api/platform/inbounds/{inboundId}:")
|
||||
.contains("/api/platform/inbounds/{inboundId}/carton-label-pdf:")
|
||||
.contains("/api/platform/inbounds/carton-label-pdf:")
|
||||
.contains("/api/platform/v1/first-leg/inbounds/{inboundId}/measurement/carton-scans:")
|
||||
.contains("required: false")
|
||||
.contains("InboundOrderSummary:")
|
||||
|
||||
+24
-2
@@ -209,20 +209,42 @@ class FbaPricingRepositoryRuleListTest {
|
||||
.thenReturn(1);
|
||||
|
||||
assertThat(repository.markInboundCalculated(
|
||||
10001L, 88L, "WAIT_PALLETIZE", "CBM", new java.math.BigDecimal("1.0000")))
|
||||
10001L, 88L, "WAIT_PALLETIZE", "CBM", new java.math.BigDecimal("10.000"),
|
||||
new java.math.BigDecimal("1.0000"), new java.math.BigDecimal("1.0000")))
|
||||
.isEqualTo(1);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<LambdaUpdateWrapper<InboundPricingEntity>> wrapper =
|
||||
ArgumentCaptor.forClass(LambdaUpdateWrapper.class);
|
||||
verify(pricing).update(org.mockito.ArgumentMatchers.isNull(), wrapper.capture());
|
||||
assertThat(wrapper.getValue().getSqlSet()).contains("feeStatus", "chargeableVolumeCbm")
|
||||
assertThat(wrapper.getValue().getSqlSet()).contains(
|
||||
"feeStatus", "chargeableWeightKg", "chargeableVolumeCbm")
|
||||
.doesNotContain("processStatus");
|
||||
assertThat(wrapper.getValue().getCustomSqlSegment())
|
||||
.contains("tenantId", "id", "processStatus", "feeStatus");
|
||||
assertThat(params(wrapper.getValue()).values()).contains(10001L, 88L, "WAIT_PALLETIZE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void kilogramPricingStoresChargeableWeightAndSelectedVolumeTogether() {
|
||||
when(pricing.update(org.mockito.ArgumentMatchers.isNull(), org.mockito.ArgumentMatchers.any()))
|
||||
.thenReturn(1);
|
||||
|
||||
assertThat(repository.markInboundCalculated(
|
||||
10001L, 88L, "WAIT_SPLIT", "KG", new java.math.BigDecimal("297.000"),
|
||||
new java.math.BigDecimal("9.0000"), new java.math.BigDecimal("1503.000")))
|
||||
.isEqualTo(1);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<LambdaUpdateWrapper<InboundPricingEntity>> wrapper =
|
||||
ArgumentCaptor.forClass(LambdaUpdateWrapper.class);
|
||||
verify(pricing).update(org.mockito.ArgumentMatchers.isNull(), wrapper.capture());
|
||||
assertThat(wrapper.getValue().getSqlSet())
|
||||
.contains("chargeableWeightKg", "chargeableVolumeCbm");
|
||||
assertThat(params(wrapper.getValue()).values()).contains(
|
||||
new java.math.BigDecimal("1503.000"), new java.math.BigDecimal("9.0000"));
|
||||
}
|
||||
|
||||
private Collection<Object> queryValues(Long tenantId, String ruleCode) {
|
||||
when(rules.selectList(org.mockito.ArgumentMatchers.any())).thenReturn(List.of());
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ class FbaPricingServiceTest {
|
||||
assertThat(response.feeStatus()).isEqualTo("CALCULATED");
|
||||
assertThat(response.nextProcessStatus()).isEqualTo("WAIT_SPLIT");
|
||||
verify(repository).markInboundCalculated(TENANT, INBOUND, "WAIT_SPLIT", "KG",
|
||||
new BigDecimal("167.000"));
|
||||
new BigDecimal("100.000"), new BigDecimal("1.0000"), new BigDecimal("167.000"));
|
||||
verify(feeDetails).materializeCalculatedFreight(TENANT, INBOUND, 501L, OPERATOR, NOW);
|
||||
verify(financeOutbox, never()).publishInbound(any(), anyLong(), anyLong(), anyLong(), anyInt(), any());
|
||||
}
|
||||
@@ -299,7 +299,7 @@ class FbaPricingServiceTest {
|
||||
|
||||
assertThat(response.nextProcessStatus()).isEqualTo("WAIT_PALLETIZE");
|
||||
verify(repository).markInboundCalculated(TENANT, INBOUND, "WAIT_PALLETIZE", "CBM",
|
||||
new BigDecimal("1.0000"));
|
||||
new BigDecimal("10.000"), new BigDecimal("1.0000"), new BigDecimal("1.0000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -325,7 +325,7 @@ class FbaPricingServiceTest {
|
||||
assertThat(response.nextProcessStatus()).isEqualTo("LOADED");
|
||||
verify(repository).supersedeCurrent(TENANT, 501L, "SENT");
|
||||
verify(repository).markInboundCalculated(TENANT, INBOUND, "LOADED", "CBM",
|
||||
new BigDecimal("1.0000"));
|
||||
new BigDecimal("10.000"), new BigDecimal("1.0000"), new BigDecimal("1.0000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -470,7 +470,8 @@ class FbaPricingServiceTest {
|
||||
.when(repository).insertIdempotency(any());
|
||||
when(repository.nextFeeVersion(TENANT, INBOUND)).thenReturn(2);
|
||||
when(repository.supersedeCurrent(TENANT, 501L, "SENT")).thenReturn(1);
|
||||
when(repository.markInboundAdjusted(eq(TENANT), eq(INBOUND), eq("WAIT_SPLIT"), eq("SENT"), eq("KG"), any()))
|
||||
when(repository.markInboundAdjusted(eq(TENANT), eq(INBOUND), eq("WAIT_SPLIT"), eq("SENT"),
|
||||
any(), any(), eq("KG"), any()))
|
||||
.thenReturn(1);
|
||||
doAnswer(invocation -> {
|
||||
InboundFeeEntity fee = invocation.getArgument(0);
|
||||
@@ -565,7 +566,8 @@ class FbaPricingServiceTest {
|
||||
.when(repository).insertIdempotency(any());
|
||||
when(repository.nextFeeVersion(TENANT, INBOUND)).thenReturn(2);
|
||||
when(repository.supersedeCurrent(TENANT, 501L, "CALCULATED")).thenReturn(1);
|
||||
when(repository.markInboundAdjusted(eq(TENANT), eq(INBOUND), eq("WAIT_SPLIT"), eq("CALCULATED"), eq("KG"), any()))
|
||||
when(repository.markInboundAdjusted(eq(TENANT), eq(INBOUND), eq("WAIT_SPLIT"), eq("CALCULATED"),
|
||||
any(), any(), eq("KG"), any()))
|
||||
.thenReturn(1);
|
||||
doAnswer(invocation -> {
|
||||
InboundFeeEntity fee = invocation.getArgument(0);
|
||||
@@ -624,7 +626,8 @@ class FbaPricingServiceTest {
|
||||
.when(repository).insertIdempotency(any());
|
||||
when(repository.nextFeeVersion(TENANT, INBOUND)).thenReturn(2);
|
||||
when(repository.supersedeCurrent(TENANT, 501L, "CALCULATED")).thenReturn(1);
|
||||
when(repository.markInboundAdjusted(eq(TENANT), eq(INBOUND), eq("WAIT_SPLIT"), eq("CALCULATED"), eq("KG"), any()))
|
||||
when(repository.markInboundAdjusted(eq(TENANT), eq(INBOUND), eq("WAIT_SPLIT"), eq("CALCULATED"),
|
||||
any(), any(), eq("KG"), any()))
|
||||
.thenReturn(1);
|
||||
doAnswer(invocation -> { ((InboundFeeEntity) invocation.getArgument(0)).setId(504L); return null; })
|
||||
.when(repository).insertFee(any());
|
||||
@@ -772,7 +775,8 @@ class FbaPricingServiceTest {
|
||||
when(repository.nextFeeVersion(TENANT, 30002L)).thenReturn(2);
|
||||
when(repository.completeIdempotency(any(), eq(901L), eq(NOW))).thenReturn(1);
|
||||
when(repository.supersedeCurrent(eq(TENANT), anyLong(), anyString())).thenReturn(1);
|
||||
when(repository.markInboundContainerFeeRecalculated(eq(TENANT), anyLong(), anyString(), anyString(), any()))
|
||||
when(repository.markInboundContainerFeeRecalculated(eq(TENANT), anyLong(), anyString(),
|
||||
any(), any(), anyString(), any()))
|
||||
.thenReturn(1);
|
||||
when(priceBookEstimator.estimate(eq(TENANT), any())).thenReturn(
|
||||
regionEstimate("200", "8", "1600"), regionEstimate("200", "8", "1600"));
|
||||
@@ -824,7 +828,8 @@ class FbaPricingServiceTest {
|
||||
when(repository.nextFeeVersion(TENANT, 30002L)).thenReturn(2);
|
||||
when(repository.completeIdempotency(any(), eq(901L), eq(NOW))).thenReturn(1);
|
||||
when(repository.supersedeCurrent(TENANT, 502L, "CALCULATED")).thenReturn(1);
|
||||
when(repository.markInboundContainerFeeRecalculated(eq(TENANT), eq(30002L), anyString(), anyString(), any()))
|
||||
when(repository.markInboundContainerFeeRecalculated(eq(TENANT), eq(30002L), anyString(),
|
||||
any(), any(), anyString(), any()))
|
||||
.thenReturn(1);
|
||||
when(priceBookEstimator.estimate(eq(TENANT), any())).thenReturn(regionEstimate("180", "8", "1440"));
|
||||
when(containerTierAllocator.allocate(any(), eq(new BigDecimal("8")))).thenReturn(
|
||||
@@ -908,7 +913,8 @@ class FbaPricingServiceTest {
|
||||
doAnswer(invocation -> { ((InboundFeeEntity) invocation.getArgument(0)).setId(501L); return null; })
|
||||
.when(repository).insertFee(any());
|
||||
when(repository.nextFeeVersion(TENANT, INBOUND)).thenReturn(1);
|
||||
when(repository.markInboundCalculated(eq(TENANT), eq(INBOUND), any(), any(), any())).thenReturn(1);
|
||||
when(repository.markInboundCalculated(eq(TENANT), eq(INBOUND), any(), any(), any(), any(), any()))
|
||||
.thenReturn(1);
|
||||
when(repository.completeIdempotency(any(), eq(501L), eq(NOW))).thenReturn(1);
|
||||
}
|
||||
|
||||
|
||||
+34
@@ -21,6 +21,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
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.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class InboundCartonLabelPrintServiceTest {
|
||||
@@ -118,6 +119,39 @@ class InboundCartonLabelPrintServiceTest {
|
||||
org.mockito.ArgumentMatchers.eq("request-batch"), org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformBatchCombinesLabelsAcrossCustomers() {
|
||||
when(labels.list(10001L, 70001L, null)).thenReturn(batch());
|
||||
when(labels.list(10002L, 70002L, null)).thenReturn(batch());
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_PDF);
|
||||
when(print.generateInboundMarks(org.mockito.ArgumentMatchers.anyString(),
|
||||
org.mockito.ArgumentMatchers.eq("platform-batch"), org.mockito.ArgumentMatchers.any()))
|
||||
.thenReturn(new ResponseEntity<>(new byte[] {1, 2, 3}, headers,
|
||||
org.springframework.http.HttpStatus.OK));
|
||||
|
||||
ResponseEntity<byte[]> response = service.generateForPlatformInbounds(List.of(
|
||||
new InboundCartonLabels.PlatformBatchItem(10001L, 70001L),
|
||||
new InboundCartonLabels.PlatformBatchItem(10002L, 70002L)), "platform-batch");
|
||||
|
||||
assertThat(response.getHeaders().getFirst("X-Carton-Label-Order-Count")).isEqualTo("2");
|
||||
assertThat(response.getBody()).containsExactly(1, 2, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformBatchFailsWhenAnySelectedInboundCannotGenerateLabels() {
|
||||
when(labels.list(10001L, 70001L, null)).thenReturn(batch());
|
||||
when(labels.list(10002L, 70002L, null))
|
||||
.thenThrow(new BizException(ResultCode.NOT_FOUND, "箱唛入库单不存在"));
|
||||
|
||||
assertThatThrownBy(() -> service.generateForPlatformInbounds(List.of(
|
||||
new InboundCartonLabels.PlatformBatchItem(10001L, 70001L),
|
||||
new InboundCartonLabels.PlatformBatchItem(10002L, 70002L)), "platform-batch"))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessage("箱唛入库单不存在");
|
||||
verifyNoInteractions(print);
|
||||
}
|
||||
|
||||
private InboundCartonLabels.Batch batch() {
|
||||
InboundCartonLabels.Label label = new InboundCartonLabels.Label(
|
||||
1L, 2L, 1, "音箱", 19, "PCHK2608040174#19-1", 19, 1,
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -233,6 +234,21 @@ class InboundCartonLabelServiceTest {
|
||||
.hasMessageContaining("订单服务暂不可用");
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertsOrderCargoCircuitBreakerFailureToActionableBusinessError() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
when(repository.lockInbound(10001L, 70001L)).thenReturn(inbound);
|
||||
when(repository.findActiveByInbound(10001L, 70001L)).thenReturn(new ArrayList<>());
|
||||
when(repository.findByInbound(10001L, 70001L)).thenReturn(new ArrayList<>());
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenThrow(new NoFallbackAvailableException("order unavailable",
|
||||
new IllegalStateException("downstream failure")));
|
||||
|
||||
assertThatThrownBy(() -> service.getOrCreate(10001L, 70001L))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessage("订单服务暂不可用,无法生成唛头");
|
||||
}
|
||||
|
||||
@Test
|
||||
void repairsMissingHistoricalInboundFromOwnedOrderSnapshot() {
|
||||
var snapshot = new com.baiyue.firstleg.dto.OrderApprovedInboundCommand(
|
||||
|
||||
Reference in New Issue
Block a user