打印箱唛修改 尾程垮桥事件提交
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.firstleg.service.InboundCartonLabelPrintService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@SpringJUnitConfig(MerchantInboundCartonLabelController.class)
|
||||
class MerchantInboundCartonLabelControllerTest {
|
||||
@MockBean private InboundCartonLabelPrintService service;
|
||||
@Resource private MerchantInboundCartonLabelController controller;
|
||||
|
||||
@Test
|
||||
void usesAuthenticatedCustomerId() throws Exception {
|
||||
AuthenticatedUser merchant = new AuthenticatedUser(1L, 10001L, 0L, 1L,
|
||||
"merchant", "MERCHANT", "WEB", Set.of());
|
||||
|
||||
controller.print(merchant, 88L, null, "req-1");
|
||||
|
||||
verify(service).generate(10001L, 88L, null, "req-1");
|
||||
PreAuthorize permission = MerchantInboundCartonLabelController.class
|
||||
.getDeclaredMethod("print", AuthenticatedUser.class, long.class, java.util.List.class, String.class)
|
||||
.getAnnotation(PreAuthorize.class);
|
||||
assertThat(permission.value()).isEqualTo("hasAuthority('merchant:order:view')");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsPlatformIdentity() {
|
||||
AuthenticatedUser platform = new AuthenticatedUser(1L, 0L, 0L, 1L,
|
||||
"admin", "PLATFORM", "WEB", Set.of());
|
||||
assertThatThrownBy(() -> controller.print(platform, 88L, null, null))
|
||||
.isInstanceOf(BizException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void printsByOrderWithoutRequiringAnInboundIdFromTheClient() {
|
||||
AuthenticatedUser merchant = new AuthenticatedUser(1L, 10001L, 0L, 1L,
|
||||
"merchant", "MERCHANT", "WEB", Set.of());
|
||||
|
||||
controller.printByOrder(merchant, 77L, null, "req-2");
|
||||
|
||||
verify(service).generateByOrder(10001L, 77L, null, "req-2");
|
||||
}
|
||||
}
|
||||
+39
@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -79,6 +80,44 @@ class InboundCartonLabelPrintServiceTest {
|
||||
.isEqualTo(ResultCode.VALIDATION_FAILED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertsCircuitBreakerFailureToServiceUnavailable() {
|
||||
when(labels.list(10001L, 70001L, null)).thenReturn(batch());
|
||||
when(print.generateInboundMarks(org.mockito.ArgumentMatchers.anyString(),
|
||||
org.mockito.ArgumentMatchers.isNull(), org.mockito.ArgumentMatchers.any()))
|
||||
.thenThrow(new NoFallbackAvailableException("print unavailable",
|
||||
new IllegalStateException("down")));
|
||||
|
||||
assertThatThrownBy(() -> service.generate(10001L, 70001L, null, null))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessage("打印服务暂不可用,请稍后重试")
|
||||
.extracting(value -> ((BizException) value).getResultCode())
|
||||
.isEqualTo(ResultCode.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void batchCombinesSuccessfulOrdersAndReportsIsolatedFailures() {
|
||||
when(labels.requireInboundIdByOrder(10001L, 60001L)).thenReturn(70001L);
|
||||
when(labels.requireInboundIdByOrder(10001L, 60002L))
|
||||
.thenThrow(new BizException(ResultCode.NOT_FOUND, "missing"));
|
||||
when(labels.list(10001L, 70001L, null)).thenReturn(batch());
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_PDF);
|
||||
when(print.generateInboundMarks(org.mockito.ArgumentMatchers.anyString(),
|
||||
org.mockito.ArgumentMatchers.eq("request-batch"), org.mockito.ArgumentMatchers.any()))
|
||||
.thenReturn(new ResponseEntity<>(new byte[] {1, 2, 3}, headers,
|
||||
org.springframework.http.HttpStatus.OK));
|
||||
|
||||
ResponseEntity<byte[]> response = service.generateByOrders(
|
||||
10001L, List.of(60001L, 60002L), "request-batch");
|
||||
|
||||
assertThat(response.getHeaders().getFirst("X-Carton-Label-Order-Count")).isEqualTo("2");
|
||||
assertThat(response.getHeaders().getFirst("X-Carton-Label-Failure-Count")).isEqualTo("1");
|
||||
assertThat(response.getHeaders().getFirst("X-Carton-Label-Failures")).contains("60002:A0404");
|
||||
verify(print).generateInboundMarks(org.mockito.ArgumentMatchers.anyString(),
|
||||
org.mockito.ArgumentMatchers.eq("request-batch"), org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
private InboundCartonLabels.Batch batch() {
|
||||
InboundCartonLabels.Label label = new InboundCartonLabels.Label(
|
||||
1L, 2L, 1, "音箱", 19, "PCHK2608040174#19-1", 19, 1,
|
||||
|
||||
+135
-24
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
|
||||
class InboundCartonLabelServiceTest {
|
||||
@Mock private InboundCartonLabelRepository repository;
|
||||
@Mock private OrderCargoClient orderCargoClient;
|
||||
@Mock private InboundOrderCreationService inboundOrderCreationService;
|
||||
private InboundCartonLabelService service;
|
||||
|
||||
@BeforeEach
|
||||
@@ -35,6 +36,7 @@ class InboundCartonLabelServiceTest {
|
||||
service = new InboundCartonLabelService();
|
||||
ReflectionTestUtils.setField(service, "repository", repository);
|
||||
ReflectionTestUtils.setField(service, "orderCargoClient", orderCargoClient);
|
||||
ReflectionTestUtils.setField(service, "inboundOrderCreationService", inboundOrderCreationService);
|
||||
ReflectionTestUtils.setField(service, "internalToken", "internal-token");
|
||||
}
|
||||
|
||||
@@ -42,12 +44,13 @@ class InboundCartonLabelServiceTest {
|
||||
void firstAllocationUsesCargoOrderAndFreezesEveryPhysicalCarton() {
|
||||
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<>());
|
||||
var second = cargo(80002L, 2, 2, "50", "30", "20");
|
||||
var first = cargo(80001L, 1, 3, "60", "40", "30");
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(second, first)));
|
||||
when(repository.initializeOriginalPackageCount(10001L, 70001L, 5)).thenReturn(true);
|
||||
when(repository.nextVersion(10001L, 70001L)).thenReturn(1);
|
||||
List<InboundCartonLabelEntity> inserted = new ArrayList<>();
|
||||
org.mockito.Mockito.doAnswer(invocation -> {
|
||||
inserted.add(invocation.getArgument(0));
|
||||
@@ -58,56 +61,116 @@ class InboundCartonLabelServiceTest {
|
||||
|
||||
assertThat(batch.totalCount()).isEqualTo(5);
|
||||
assertThat(batch.labels()).extracting(label -> label.boxCode())
|
||||
.containsExactly("PCHK2608040174#5-1", "PCHK2608040174#5-2", "PCHK2608040174#5-3",
|
||||
"PCHK2608040174#5-4", "PCHK2608040174#5-5");
|
||||
.containsExactly("PCHK2608040174#V1#5-1", "PCHK2608040174#V1#5-2", "PCHK2608040174#V1#5-3",
|
||||
"PCHK2608040174#V1#5-4", "PCHK2608040174#V1#5-5");
|
||||
assertThat(batch.labels()).extracting(label -> label.inboundDetailId())
|
||||
.containsExactly(80001L, 80001L, 80001L, 80002L, 80002L);
|
||||
assertThat(batch.labels().get(0).boxSpecification()).isEqualTo("60x40x30cm");
|
||||
assertThat(batch.labels().get(0).cartonText()).isEqualTo("CTNS:5-1");
|
||||
assertThat(inbound.getTotalPackageCount()).isEqualTo(5);
|
||||
assertThat(inserted).hasSize(5);
|
||||
verify(repository).initializeOriginalPackageCount(10001L, 70001L, 5);
|
||||
verify(repository).updatePackageCount(10001L, 70001L, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void repeatedAndPartialPrintsReadFrozenMappingWithoutReallocation() {
|
||||
void repeatedAndPartialPrintsReadCurrentVersionWithoutReallocation() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setTotalPackageCount(5);
|
||||
List<InboundCartonLabelEntity> existing = labels(inbound, 5);
|
||||
when(repository.lockInbound(10001L, 70001L)).thenReturn(inbound);
|
||||
when(repository.findByInbound(10001L, 70001L)).thenReturn(existing);
|
||||
when(repository.findActiveByInbound(10001L, 70001L)).thenReturn(existing);
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(cargo(80001L, 1, 5, "60", "40", "30"))));
|
||||
|
||||
var batch = service.list(10001L, 70001L, List.of(5, 2, 2));
|
||||
|
||||
assertThat(batch.totalCount()).isEqualTo(5);
|
||||
assertThat(batch.labels()).extracting(label -> label.cartonIndex()).containsExactly(2, 5);
|
||||
verify(orderCargoClient, never()).listForCartonLabels(any(String.class),
|
||||
org.mockito.ArgumentMatchers.anyLong(), org.mockito.ArgumentMatchers.anyLong());
|
||||
verify(repository).initializeLegacyFingerprint(org.mockito.ArgumentMatchers.eq(10001L),
|
||||
org.mockito.ArgumentMatchers.eq(70001L), org.mockito.ArgumentMatchers.eq(1), any(String.class));
|
||||
verify(repository, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void refusesFrozenMappingWhenOriginalPackageCountDoesNotMatch() {
|
||||
void changedCargoCreatesNewVersion() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setTotalPackageCount(4);
|
||||
when(repository.lockInbound(10001L, 70001L)).thenReturn(inbound);
|
||||
when(repository.findByInbound(10001L, 70001L)).thenReturn(labels(inbound, 5));
|
||||
List<InboundCartonLabelEntity> existing = labels(inbound, 5);
|
||||
existing.forEach(label -> { label.setCargoFingerprint("old"); label.setBatchStatus("ACTIVE"); });
|
||||
when(repository.findActiveByInbound(10001L, 70001L)).thenReturn(existing);
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(cargo(80001L, 1, 2, "60", "40", "30"))));
|
||||
when(repository.nextVersion(10001L, 70001L)).thenReturn(2);
|
||||
org.mockito.Mockito.doAnswer(invocation -> null).when(repository).insert(any());
|
||||
var result = service.getOrCreate(10001L, 70001L);
|
||||
assertThat(result.labels()).extracting(label -> label.boxCode())
|
||||
.containsExactly("PCHK2608040174#V2#2-1", "PCHK2608040174#V2#2-2");
|
||||
verify(repository).voidActive(org.mockito.ArgumentMatchers.eq(10001L),
|
||||
org.mockito.ArgumentMatchers.eq(70001L), any());
|
||||
}
|
||||
|
||||
assertThatThrownBy(() -> service.getOrCreate(10001L, 70001L))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("订单总箱数与已冻结箱号数量不一致");
|
||||
@Test
|
||||
void draftCanGenerateLabelsBeforeSubmission() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setProcessStatus("PREPARING");
|
||||
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))
|
||||
.thenReturn(ApiResponse.success(List.of(cargo(80001L, 1, 2, "60", "40", "30"))));
|
||||
when(repository.nextVersion(10001L, 70001L)).thenReturn(1);
|
||||
org.mockito.Mockito.doAnswer(invocation -> null).when(repository).insert(any());
|
||||
|
||||
verify(repository, never()).initializeOriginalPackageCount(
|
||||
org.mockito.ArgumentMatchers.anyLong(), org.mockito.ArgumentMatchers.anyLong(),
|
||||
org.mockito.ArgumentMatchers.anyInt());
|
||||
var result = service.getOrCreate(10001L, 70001L);
|
||||
|
||||
assertThat(result.totalCount()).isEqualTo(2);
|
||||
assertThat(result.labels()).extracting(label -> label.boxCode())
|
||||
.containsExactly("PCHK2608040174#V1#2-1", "PCHK2608040174#V1#2-2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void existingLabelsCanBeRepeatedAfterLoading() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setProcessStatus("LOADING");
|
||||
List<InboundCartonLabelEntity> existing = labels(inbound, 1);
|
||||
when(repository.lockInbound(10001L, 70001L)).thenReturn(inbound);
|
||||
when(repository.findActiveByInbound(10001L, 70001L)).thenReturn(existing);
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(cargo(80001L, 1, 1, "60", "40", "30"))));
|
||||
var result = service.getOrCreate(10001L, 70001L);
|
||||
assertThat(result.totalCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void changedCargoAfterLoadingVoidsCurrentBatchAndCreatesNextVersion() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setProcessStatus("LOADING");
|
||||
List<InboundCartonLabelEntity> existing = labels(inbound, 1);
|
||||
existing.forEach(label -> {
|
||||
label.setCargoFingerprint("old-fingerprint");
|
||||
label.setBatchStatus("ACTIVE");
|
||||
});
|
||||
when(repository.lockInbound(10001L, 70001L)).thenReturn(inbound);
|
||||
when(repository.findActiveByInbound(10001L, 70001L)).thenReturn(existing);
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(cargo(80001L, 1, 2, "60", "40", "30"))));
|
||||
when(repository.nextVersion(10001L, 70001L)).thenReturn(2);
|
||||
|
||||
var result = service.getOrCreate(10001L, 70001L);
|
||||
|
||||
assertThat(result.labels()).extracting(label -> label.boxCode())
|
||||
.containsExactly("PCHK2608040174#V2#2-1", "PCHK2608040174#V2#2-2");
|
||||
verify(repository).voidActive(org.mockito.ArgumentMatchers.eq(10001L),
|
||||
org.mockito.ArgumentMatchers.eq(70001L), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolvesBoxCodeInsideCustomerBoundary() {
|
||||
InboundCartonLabelEntity label = labels(inbound(), 1).get(0);
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#1-1")).thenReturn(label);
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#V1#1-1")).thenReturn(label);
|
||||
|
||||
var resolved = service.resolveByBoxCode(10001L, " PCHK2608040174#1-1 ");
|
||||
var resolved = service.resolveByBoxCode(10001L, " PCHK2608040174#V1#1-1 ");
|
||||
|
||||
assertThat(resolved.inboundId()).isEqualTo(70001L);
|
||||
assertThat(resolved.inboundDetailId()).isEqualTo(80001L);
|
||||
@@ -115,27 +178,37 @@ class InboundCartonLabelServiceTest {
|
||||
assertThat(resolved.cartonIndex()).isEqualTo(1);
|
||||
assertThat(resolved.totalCartons()).isEqualTo(1);
|
||||
assertThat(resolved.boxSpecification()).isEqualTo("60x40x30cm");
|
||||
verify(repository).findByBoxCode(10001L, "PCHK2608040174#1-1");
|
||||
verify(repository).findByBoxCode(10001L, "PCHK2608040174#V1#1-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void exposesDetailedResolutionForFirstlegConsumers() {
|
||||
InboundCartonLabelEntity label = labels(inbound(), 1).get(0);
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#1-1")).thenReturn(label);
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#V1#1-1")).thenReturn(label);
|
||||
|
||||
var resolved = service.resolveDetailsByBoxCode(10001L, "PCHK2608040174#1-1");
|
||||
var resolved = service.resolveDetailsByBoxCode(10001L, "PCHK2608040174#V1#1-1");
|
||||
|
||||
assertThat(resolved.orderId()).isEqualTo(60001L);
|
||||
assertThat(resolved.boxCode()).isEqualTo("PCHK2608040174#1-1");
|
||||
assertThat(resolved.boxCode()).isEqualTo("PCHK2608040174#V1#1-1");
|
||||
assertThat(resolved.cargoItemNo()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsVoidedLabelVersionDuringScanResolution() {
|
||||
InboundCartonLabelEntity label = labels(inbound(), 1).get(0);
|
||||
label.setBatchStatus("VOID");
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#V1#1-1")).thenReturn(label);
|
||||
|
||||
assertThatThrownBy(() -> service.resolveByBoxCode(10001L, "PCHK2608040174#V1#1-1"))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessage("箱唛版本已作废,请重新打印");
|
||||
}
|
||||
|
||||
@Test
|
||||
void refusesFirstAllocationAfterMeasurementSubmission() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setProcessStatus("MEASURE_PENDING");
|
||||
when(repository.lockInbound(10001L, 70001L)).thenReturn(inbound);
|
||||
when(repository.findByInbound(10001L, 70001L)).thenReturn(List.of());
|
||||
|
||||
assertThatThrownBy(() -> service.getOrCreate(10001L, 70001L))
|
||||
.isInstanceOf(BizException.class)
|
||||
@@ -144,6 +217,42 @@ class InboundCartonLabelServiceTest {
|
||||
org.mockito.ArgumentMatchers.anyLong(), org.mockito.ArgumentMatchers.anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolvesTheRealInboundIdByTenantAndOrder() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
when(repository.findByOrder(10001L, 60001L)).thenReturn(inbound);
|
||||
|
||||
assertThat(service.requireInboundIdByOrder(10001L, 60001L)).isEqualTo(70001L);
|
||||
verify(repository).findByOrder(10001L, 60001L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsAnOrderWithoutAnOwnedPreparingInbound() {
|
||||
when(repository.findByOrder(10001L, 60001L)).thenReturn(null);
|
||||
when(orderCargoClient.inboundSnapshot("internal-token", 10001L, 60001L))
|
||||
.thenThrow(org.mockito.Mockito.mock(feign.FeignException.class));
|
||||
|
||||
assertThatThrownBy(() -> service.requireInboundIdByOrder(10001L, 60001L))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("订单服务暂不可用");
|
||||
}
|
||||
|
||||
@Test
|
||||
void repairsMissingHistoricalInboundFromOwnedOrderSnapshot() {
|
||||
var snapshot = new com.baiyue.firstleg.dto.OrderApprovedInboundCommand(
|
||||
10001L, 60001L, "FL60001", "PCHK2608040174", 1L, "Customer",
|
||||
41L, "Warehouse", null, null, null, "EXPORT_SEA", null, null,
|
||||
null, null, null, null, null, false, "FBA", null, null, null,
|
||||
null, null, null, 2);
|
||||
InboundOrderEntity repaired = inbound();
|
||||
when(repository.findByOrder(10001L, 60001L)).thenReturn(null, repaired);
|
||||
when(orderCargoClient.inboundSnapshot("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(snapshot));
|
||||
|
||||
assertThat(service.requireInboundIdByOrder(10001L, 60001L)).isEqualTo(70001L);
|
||||
verify(inboundOrderCreationService).prepareFromDraft(snapshot);
|
||||
}
|
||||
|
||||
private InboundOrderEntity inbound() {
|
||||
InboundOrderEntity inbound = new InboundOrderEntity();
|
||||
inbound.setId(70001L);
|
||||
@@ -175,9 +284,11 @@ class InboundCartonLabelServiceTest {
|
||||
label.setCargoName("货物1");
|
||||
label.setDetailPackageCount(total);
|
||||
label.setInboundCode(inbound.getInboundCode());
|
||||
label.setBoxCode(inbound.getInboundCode() + "#" + total + "-" + index);
|
||||
label.setBoxCode(inbound.getInboundCode() + "#V1#" + total + "-" + index);
|
||||
label.setTotalCartonCount(total);
|
||||
label.setCartonIndex(index);
|
||||
label.setLabelVersion(1);
|
||||
label.setBatchStatus("ACTIVE");
|
||||
label.setBoxSpecification("60x40x30cm");
|
||||
label.setLengthCm(new BigDecimal("60"));
|
||||
label.setWidthCm(new BigDecimal("40"));
|
||||
|
||||
+17
@@ -113,6 +113,23 @@ class InboundOrderCreationServiceTest {
|
||||
verify(orders, never()).insert(any(InboundOrderEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPrepareDraftIdempotentlyAndUpgradeSameInboundOnApproval() {
|
||||
InboundOrderEntity prepared = inbound(900L, "RK-CUSTOM-77", "UNPRICED", null, null);
|
||||
prepared.setProcessStatus("PREPARING");
|
||||
when(orders.selectOne(any(Wrapper.class))).thenReturn(null, prepared, prepared);
|
||||
when(orders.update(any(), any(Wrapper.class))).thenReturn(1);
|
||||
when(fulfillmentTasks.provision(any(), any())).thenReturn(task(700L));
|
||||
|
||||
long preparedId = service.prepareFromDraft(approvedCommand("RK-CUSTOM-77"));
|
||||
long approvedId = service.createFromApprovedOrder(approvedCommand("RK-CUSTOM-77"));
|
||||
|
||||
assertThat(preparedId).isNotNull();
|
||||
assertThat(approvedId).isEqualTo(900L);
|
||||
verify(orders, times(1)).insert(any(InboundOrderEntity.class));
|
||||
verify(orders, times(2)).update(any(), any(Wrapper.class));
|
||||
}
|
||||
|
||||
private static InboundOrderEntity inbound(long id, String code, String feeStatus,
|
||||
Long carrierId, String carrierName) {
|
||||
InboundOrderEntity inbound = new InboundOrderEntity();
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import com.baiyue.common.event.EventEnvelope;
|
||||
import com.baiyue.common.event.EventTypes;
|
||||
import com.baiyue.firstleg.entity.InboundOutboxEntity;
|
||||
import com.baiyue.firstleg.mapper.InboundOutboxMapper;
|
||||
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper;
|
||||
import com.baiyue.firstleg.mapper.LoadingCompletedEventMapper.Row;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class LoadingCompletedOutboxServiceTest {
|
||||
private final LoadingCompletedEventMapper snapshots = mock(LoadingCompletedEventMapper.class);
|
||||
private final InboundOutboxMapper outbox = mock(InboundOutboxMapper.class);
|
||||
private final ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
|
||||
private final LoadingCompletedOutboxService service = new LoadingCompletedOutboxService();
|
||||
|
||||
@BeforeEach void setup() {
|
||||
ReflectionTestUtils.setField(service,"snapshotMapper",snapshots);
|
||||
ReflectionTestUtils.setField(service,"outboxMapper",outbox);
|
||||
ReflectionTestUtils.setField(service,"objectMapper",mapper);
|
||||
}
|
||||
|
||||
@Test void groupsByAccountAndKeepsAllOrdersAndItemsStable() throws Exception {
|
||||
when(snapshots.rows(90L)).thenReturn(List.of(row(22,300,302),row(11,200,202),row(11,100,102),row(11,100,101)));
|
||||
service.publish(90L);
|
||||
ArgumentCaptor<InboundOutboxEntity> captor=ArgumentCaptor.forClass(InboundOutboxEntity.class);
|
||||
verify(outbox,org.mockito.Mockito.times(2)).insert(captor.capture());
|
||||
List<InboundOutboxEntity> rows=captor.getAllValues();
|
||||
assertThat(rows).extracting(InboundOutboxEntity::getTenantId).containsExactly(11L,22L);
|
||||
EventEnvelope first=mapper.readValue(rows.get(0).getPayloadJson(),EventEnvelope.class);
|
||||
assertThat(first.eventType()).isEqualTo(EventTypes.FIRST_LEG_LOADING_PLAN_COMPLETED);
|
||||
assertThat(first.tenantId()).isEqualTo("11");
|
||||
assertThat(first.payload().get("orders")).hasSize(2);
|
||||
assertThat(first.payload().at("/orders/0/sourceInboundId").asText()).isEqualTo("100");
|
||||
assertThat(first.payload().at("/orders/0/items/0/sourceInboundDetailId").asText()).isEqualTo("101");
|
||||
assertThat(rows.get(0).getEventKey()).isEqualTo("FIRSTLEG_LOADING_COMPLETED:90:11:1");
|
||||
}
|
||||
|
||||
private Row row(long account,long inbound,long detail) {
|
||||
Row r=new Row(); r.setLoadingPlanId(90L); r.setPlanNo("P90"); r.setContainerBookingId(91L);
|
||||
r.setAggregateVersion(8); r.setContainerNo("CONT"); r.setCabinetNo("CAB"); r.setWarehouseId(92L);
|
||||
r.setWarehouseName("WH"); r.setAccountId(account); r.setSourceInboundId(inbound); r.setRootInboundId(99L);
|
||||
r.setSourceOrderId(inbound+1000); r.setSourceOrderNo("FL"+inbound); r.setRootOrderId(1099L);
|
||||
r.setInboundCode("RK"+inbound); r.setDestinationWarehouseId(93L); r.setDestinationWarehouseCode("ONT8");
|
||||
r.setDestinationWarehouseName("ONT8"); r.setSourceInboundDetailId(detail); r.setSkuCode("SKU"+detail);
|
||||
r.setPackageCount(1); r.setProductQuantity(10); r.setPalletCount(1); r.setGrossWeightKg(BigDecimal.ONE);
|
||||
r.setNetWeightKg(BigDecimal.ONE); r.setVolumeCbm(BigDecimal.ONE); return r;
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,8 @@ class LoadingListServiceTest {
|
||||
private LoadingPickRepository pickRepository;
|
||||
@MockBean
|
||||
private LoadingDocumentFileClient documentFiles;
|
||||
@MockBean
|
||||
private LoadingCompletedOutboxService loadingCompletedOutboxService;
|
||||
@Resource
|
||||
private LoadingListService service;
|
||||
|
||||
@@ -135,6 +137,7 @@ class LoadingListServiceTest {
|
||||
verify(repository).appendHistory(eq(10L), eq("PDA-COMPLETE-10-21"),
|
||||
eq("PDA_COMPLETE_LOADING"), eq("LOADING"), eq("COMPLETED"), anyString(), anyString(),
|
||||
eq(9L), eq("operator"), eq("PDA已人工确认装柜完成"));
|
||||
verify(loadingCompletedOutboxService).publish(10L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -147,6 +150,7 @@ class LoadingListServiceTest {
|
||||
.isEqualTo(ResultCode.CONFLICT);
|
||||
verify(repository, never()).advance(eq(10L), anyString(), anyString(),
|
||||
org.mockito.ArgumentMatchers.anyInt(), eq(9L), anyString());
|
||||
verify(loadingCompletedOutboxService, never()).publish(10L);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user