Merge remote-tracking branch 'origin/test' into test
# Conflicts: # lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml
This commit is contained in:
+12
@@ -169,6 +169,18 @@ class DeliveryTransferServiceTest {
|
||||
org.mockito.Mockito.lenient().when(returnStock.matchesReturnSource(any(), any())).thenCallRealMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
void uncountedPalletBoxCannotCreateReturnOutbound() {
|
||||
ReturnInventoryCarton carton = returnCarton("RC-UNCOUNTED", "PAL-1");
|
||||
carton.setCountStatus("PENDING");
|
||||
when(returnCartons.lockMark("RC-UNCOUNTED")).thenReturn(carton);
|
||||
var error = assertThrows(ResponseStatusException.class, () -> service.createReturnOutbound("TENANT-A", "U-1",
|
||||
new DeliveryRequests.ReturnOutbound("receiver", "WH-1", "RT-1", List.of("RC-UNCOUNTED"), null, "uncounted-1")));
|
||||
assertEquals(409, error.getStatusCode().value());
|
||||
org.mockito.Mockito.verifyNoInteractions(returnCartonItems, outboundPallets);
|
||||
verify(outboundOrders, org.mockito.Mockito.never()).insert(any(OutboundOrder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnBoxOutboundCanSelectOneCartonFromAPallet() {
|
||||
ReturnInventoryCarton first = returnCarton("RC-1", "PAL-1");
|
||||
|
||||
+64
@@ -569,6 +569,38 @@ class RelabelApplicationServiceTest {
|
||||
assertEquals("COMPLETED", order.getRelabelStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void zeroFeeCompletionPersistsFulfillmentForBothOutboundRoutes() {
|
||||
for (String route : List.of("PRE_DISPATCH_CREATED", "OUTBOUND_CREATED")) {
|
||||
RelabelApplication app = application(11L, "FBR-ZERO", "10001", "key", "hash", RelabelApplicationService.READY_FOR_OUTBOUND);
|
||||
app.setLastlegOrderId(21L);
|
||||
app.setWalletStatus("NOT_REQUIRED");
|
||||
app.setChargeAmount(BigDecimal.ZERO);
|
||||
app.setFulfillmentStatus(route);
|
||||
if ("OUTBOUND_CREATED".equals(route)) app.setOutboundOrderNo("OUT-ZERO");
|
||||
LastlegOrder order = order(21L, "10001", "LMO-ZERO", "PROCESSING");
|
||||
order.setOrderType("RETURN_RELABEL");
|
||||
order.setRelabelOrderNo(app.getRelabelNo());
|
||||
when(applications.lockNo("10001", app.getRelabelNo())).thenReturn(app);
|
||||
when(orders.selectById(21L)).thenReturn(order);
|
||||
stubDetail(app);
|
||||
List<String> persistedFulfillment = new java.util.ArrayList<>();
|
||||
org.mockito.Mockito.doAnswer(invocation -> {
|
||||
RelabelApplication saved = invocation.getArgument(0);
|
||||
persistedFulfillment.add(saved.getFulfillmentStatus());
|
||||
return 1;
|
||||
}).when(applications).updateById(any(RelabelApplication.class));
|
||||
|
||||
service.changeStatus("10001", app.getRelabelNo(), "operator-2",
|
||||
new RelabelRequests.ChangeStatus("COMPLETED", "finished"));
|
||||
|
||||
assertEquals("OUTBOUNDED", persistedFulfillment.get(persistedFulfillment.size() - 1), route);
|
||||
}
|
||||
verify(feeSources, never()).publishApproved(any(), any(), any());
|
||||
verify(walletCommands, never()).publish(any(), anyLong(), any(), any(), any(), any(), anyLong());
|
||||
verify(inventoryCommands, never()).release(any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void completingEarlierReturnRelabelDoesNotOverwriteLaterApplicationStatus() {
|
||||
RelabelApplication application = application(11L, "FBR-FIRST", "10001", "key-1", "hash", RelabelApplicationService.READY_FOR_OUTBOUND);
|
||||
@@ -895,6 +927,25 @@ class RelabelApplicationServiceTest {
|
||||
return app;
|
||||
}
|
||||
|
||||
@Test
|
||||
void uncountedPalletBoxCannotCreateRelabelApplication() {
|
||||
var cartonMapper = org.mockito.Mockito.mock(com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonMapper.class);
|
||||
ReflectionTestUtils.setField(service, "returnCartons", cartonMapper);
|
||||
var carton = new com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCarton();
|
||||
carton.setId(901L); carton.setCustomerId("10001"); carton.setOverseasWarehouseId("WH-1");
|
||||
carton.setCartonMark("RETURN-BOX-1"); carton.setStatus("AVAILABLE"); carton.setSourceUnitType("PALLET"); carton.setCountStatus("PENDING");
|
||||
when(cartonMapper.lockId(901L)).thenReturn(carton);
|
||||
var detail = new RelabelRequests.Item(null, null, null, "SKU-A", null, null, null,
|
||||
"Return goods", 1, 1, "RT-1", null, "NEW-A", null, null,
|
||||
null, null, null, "RETURN-BOX-1", null, null, "SKU_LABEL",
|
||||
List.of(new RelabelRequests.SkuItem("SKU-A", "NEW-A", 1, null)), 901L);
|
||||
var request = new RelabelRequests.Create("RT-1", "WH-1", LocalDateTime.now().plusDays(1),
|
||||
"Li", "13800000000", null, null, "return-uncounted", List.of(detail), null, false);
|
||||
var error = assertThrows(ResponseStatusException.class, () -> service.create("10001", "operator-1", request));
|
||||
assertTrue(error.getReason().contains("清点"));
|
||||
verify(applications, never()).insert(any(RelabelApplication.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnSkuRelabelRejectsQuantityBeyondSelectedSourceBox() {
|
||||
var cartonMapper = org.mockito.Mockito.mock(com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonMapper.class);
|
||||
@@ -934,6 +985,19 @@ class RelabelApplicationServiceTest {
|
||||
"SKU-NEW", "Label on carton", "file-1", "relabel.pdf", "https://files/relabel.pdf")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsDifferentOperationTypesInOneApplicationBeforeStockIsHeld() {
|
||||
var first = carton("A", "RC-A", "FBA-A", "ABE8");
|
||||
var second = new RelabelRequests.Item(101L, 202L, 301L, "B", null, null, null,
|
||||
"商品B", 1, 1, "SHP-2", null, "B-NEW", null, null,
|
||||
null, null, null, "RC-B", null, null, "SKU_LABEL", List.of());
|
||||
var request = new RelabelRequests.Create("CUSTOMER-1", "WH-1", LocalDateTime.now().plusDays(1),
|
||||
"Li", "13800000000", new BigDecimal("20.00"), null, "mixed-types", List.of(first, second));
|
||||
var error = assertThrows(ResponseStatusException.class, () -> service.create("10001", "operator-1", request));
|
||||
assertEquals(400, error.getStatusCode().value());
|
||||
assertTrue(error.getReason().contains("只能选择一种"));
|
||||
}
|
||||
|
||||
private static RelabelRequests.Item carton(String sku, String cartonMark, String fbaCartonMark,
|
||||
String destinationWarehouseId) {
|
||||
long positionId = "ABE8".equals(destinationWarehouseId) ? 202L : 201L;
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
package com.baiyue.lastleg.returnreceipt.service;
|
||||
|
||||
import com.baiyue.lastleg.pda.security.PdaWarehouseIdentity;
|
||||
import com.baiyue.lastleg.returnreceipt.dto.ReturnCartonCountDtos.*;
|
||||
import com.baiyue.lastleg.returnreceipt.entity.*;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.*;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import java.util.List;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ReturnCartonCountServiceTest {
|
||||
@Mock ReturnReceiptMapper receipts;
|
||||
@Mock ReturnReceiptItemMapper receiptItems;
|
||||
@Mock ReturnInventoryCartonMapper cartons;
|
||||
@Mock ReturnInventoryCartonItemMapper items;
|
||||
@Mock ReturnInventoryBalanceMapper balances;
|
||||
@Mock ReturnInventoryOperationMapper operations;
|
||||
@Mock ReturnCartonCountSessionMapper sessions;
|
||||
ReturnCartonCountService service;
|
||||
PdaWarehouseIdentity identity = new PdaWarehouseIdentity("op", "operator", 123L);
|
||||
ReturnReceipt receipt;
|
||||
ReturnInventoryCarton a, b;
|
||||
@BeforeEach void setup() {
|
||||
service = new ReturnCartonCountService();
|
||||
ReflectionTestUtils.setField(service,"receipts",receipts);
|
||||
ReflectionTestUtils.setField(service,"receiptItems",receiptItems);
|
||||
ReflectionTestUtils.setField(service,"cartons",cartons);
|
||||
ReflectionTestUtils.setField(service,"items",items);
|
||||
ReflectionTestUtils.setField(service,"balances",balances);
|
||||
ReflectionTestUtils.setField(service,"operations",operations);
|
||||
ReflectionTestUtils.setField(service,"sessions",sessions);
|
||||
lenient().when(sessions.lockOperator("op")).thenReturn(new ReturnCartonCountSessionMapper.Session("op","123",1L,null));
|
||||
lenient().when(sessions.lockOperator("other")).thenReturn(new ReturnCartonCountSessionMapper.Session("other","999",null,null));
|
||||
lenient().when(sessions.release("op",1L)).thenReturn(1);
|
||||
ReflectionTestUtils.setField(service,"objectMapper",new ObjectMapper().findAndRegisterModules());
|
||||
receipt = new ReturnReceipt(); receipt.setId(1L); receipt.setReceiptNo("RR-1"); receipt.setCustomerId("C1"); receipt.setPalletCode("PLT-1");
|
||||
a = box(2L,"RC#2-1"); b = box(3L,"RC#2-2");
|
||||
}
|
||||
private ReturnInventoryCarton box(long id, String mark) {
|
||||
var box = new ReturnInventoryCarton(); box.setId(id); box.setCartonMark(mark); box.setCustomerId("C1"); box.setOverseasWarehouseId("123");
|
||||
box.setCountStatus("PENDING"); box.setStatus("AVAILABLE"); box.setSourceReceiptId(1L); box.setSourceUnitType("PALLET"); return box;
|
||||
}
|
||||
private ReturnReceiptItem expected(String sku, long qty) {
|
||||
var item = new ReturnReceiptItem(); item.setSkuCode(sku); item.setReceivedQuantity(qty); return item;
|
||||
}
|
||||
private ReturnInventoryCartonItem provisional(long box, String sku, long qty) {
|
||||
var item = new ReturnInventoryCartonItem(); item.setCartonId(box); item.setSkuCode(sku); item.setQuantity(qty); item.setPackingReservedQuantity(0L); return item;
|
||||
}
|
||||
private void prepare(List<ReturnReceiptItem> expected) {
|
||||
when(receipts.lockCountReceipt("RR-1")).thenReturn(receipt);
|
||||
when(cartons.lockReceipt(1L)).thenReturn(List.of(a,b));
|
||||
when(receiptItems.listReceipt(1L)).thenReturn(expected);
|
||||
}
|
||||
private Confirm unequal(long first, long second) {
|
||||
return new Confirm("retry", List.of(new CountBox(a.getCartonMark(),List.of(new CountItem("SKU1",first))),new CountBox(b.getCartonMark(),List.of(new CountItem("SKU1",second)))));
|
||||
}
|
||||
@Test void unequalBoxesAreConfirmedWithoutChangingSkuUnitBalanceAndRetryIsStable() {
|
||||
prepare(List.of(expected("SKU1",10)));
|
||||
when(items.lockCarton(2L)).thenReturn(List.of(provisional(2,"SKU1",5)));
|
||||
when(items.lockCarton(3L)).thenReturn(List.of(provisional(3,"SKU1",5)));
|
||||
when(items.listCarton(2L)).thenReturn(List.of(provisional(2,"SKU1",3)));
|
||||
when(items.listCarton(3L)).thenReturn(List.of(provisional(3,"SKU1",7)));
|
||||
var result = service.confirm(identity,"RR-1",unequal(3,7));
|
||||
assertThat(result.status()).isEqualTo("CONFIRMED");
|
||||
assertThat(a.getTotalQuantity()).isEqualTo(3); assertThat(b.getTotalQuantity()).isEqualTo(7);
|
||||
assertThat(a.getCountedBy()).isEqualTo("op"); assertThat(a.getCountedAt()).isNotNull();
|
||||
verify(items).deleteCarton(2L); verify(items).deleteCarton(3L); verify(items,times(2)).insert(any(ReturnInventoryCartonItem.class));
|
||||
verifyNoInteractions(balances);
|
||||
var audit = org.mockito.ArgumentCaptor.forClass(ReturnInventoryOperation.class); verify(operations).insert(audit.capture());
|
||||
when(operations.lockKey("op","retry")).thenReturn(audit.getValue());
|
||||
assertThat(service.confirm(identity,"RR-1",unequal(3,7))).isEqualTo(result);
|
||||
assertThatThrownBy(() -> service.confirm(identity,"RR-1",unequal(4,6))).isInstanceOf(ResponseStatusException.class).hasMessageContaining("幂等键");
|
||||
verify(items,times(2)).deleteCarton(anyLong());
|
||||
}
|
||||
@Test void mixedBoxesAdjustOnlyContainingBoxCounts() {
|
||||
prepare(List.of(expected("SKU1",6),expected("SKU2",4)));
|
||||
when(items.lockCarton(2L)).thenReturn(List.of(provisional(2,"SKU1",6)));
|
||||
when(items.lockCarton(3L)).thenReturn(List.of(provisional(3,"SKU2",4)));
|
||||
when(balances.adjustCartonQuantity("C1","123","SKU1",1)).thenReturn(1);
|
||||
when(balances.adjustCartonQuantity("C1","123","SKU2",1)).thenReturn(1);
|
||||
var request = new Confirm("mixed",List.of(new CountBox(a.getCartonMark(),List.of(new CountItem("SKU1",2),new CountItem("SKU2",1))),new CountBox(b.getCartonMark(),List.of(new CountItem("SKU1",4),new CountItem("SKU2",3)))));
|
||||
service.confirm(identity,"RR-1",request);
|
||||
verify(balances).adjustCartonQuantity("C1","123","SKU1",1); verify(balances).adjustCartonQuantity("C1","123","SKU2",1);
|
||||
verifyNoMoreInteractions(balances); assertThat(a.getSkuTypes()).isEqualTo(2);
|
||||
}
|
||||
@Test void totalsMismatchDoesNotDeleteOrReleaseAnyBox() {
|
||||
prepare(List.of(expected("SKU1",10)));
|
||||
assertThatThrownBy(() -> service.confirm(identity,"RR-1",unequal(3,6))).isInstanceOf(ResponseStatusException.class).hasMessageContaining("汇总");
|
||||
verify(items,never()).deleteCarton(anyLong()); verify(cartons,never()).updateById(any(ReturnInventoryCarton.class)); verifyNoInteractions(balances);
|
||||
assertThat(a.getCountStatus()).isEqualTo("PENDING");
|
||||
}
|
||||
@Test void duplicateOrForeignBoxesCannotBeSubmitted() {
|
||||
prepare(List.of(expected("SKU1",10)));
|
||||
var request = new Confirm("dup",List.of(new CountBox(a.getCartonMark(),List.of(new CountItem("SKU1",5))),new CountBox(a.getCartonMark(),List.of(new CountItem("SKU1",5)))));
|
||||
assertThatThrownBy(() -> service.confirm(identity,"RR-1",request)).isInstanceOf(ResponseStatusException.class).hasMessageContaining("重复");
|
||||
verify(items,never()).deleteCarton(anyLong());
|
||||
}
|
||||
@Test void warehouseScopeCannotBeSuppliedByAnotherOperator() {
|
||||
when(receipts.lockCountReceipt("RR-1")).thenReturn(receipt); when(cartons.lockReceipt(1L)).thenReturn(List.of(a,b));
|
||||
assertThatThrownBy(() -> service.confirm(new PdaWarehouseIdentity("other","other",999),"RR-1",unequal(3,7))).isInstanceOf(ResponseStatusException.class).hasMessageContaining("当前仓");
|
||||
verifyNoInteractions(items,receiptItems,operations);
|
||||
}
|
||||
@Test void scanDoesNotExposeProvisionalAverageAsActualCount() {
|
||||
when(cartons.findMark(a.getCartonMark())).thenReturn(a); when(receipts.selectById(1L)).thenReturn(receipt);
|
||||
when(cartons.listReceipt(1L)).thenReturn(List.of(a,b)); when(receiptItems.listReceipt(1L)).thenReturn(List.of(expected("SKU1",10)));
|
||||
when(items.listCarton(2L)).thenReturn(List.of(provisional(2,"SKU1",5))); when(items.listCarton(3L)).thenReturn(List.of(provisional(3,"SKU1",5)));
|
||||
var task = service.scan(identity,a.getCartonMark());
|
||||
assertThat(task.boxes()).allSatisfy(box -> assertThat(box.items()).allSatisfy(item -> assertThat(item.quantity()).isZero()));
|
||||
assertThatThrownBy(() -> ReturnCartonCountGuard.requireConfirmed(a)).isInstanceOf(ResponseStatusException.class).hasMessageContaining("清点");
|
||||
a.setCountStatus("CONFIRMED"); assertThatCode(() -> ReturnCartonCountGuard.requireConfirmed(a)).doesNotThrowAnyException();
|
||||
}
|
||||
@Test void unifiedScanUsesExactCodeAndWarehouseAndReturnsAllPendingPalletBatches() {
|
||||
var second = new ReturnReceipt(); second.setId(4L); second.setReceiptNo("RR-2"); second.setPalletCode("PLT-1");
|
||||
when(receipts.scanPendingContents("123","PLT-1")).thenReturn(List.of(receipt,second));
|
||||
when(cartons.listReceipt(1L)).thenReturn(List.of(a,b));
|
||||
var tasks = service.scanTasks(identity," PLT-1 ");
|
||||
assertThat(tasks).extracting(Task::receiptNo).containsExactly("RR-1","RR-2");
|
||||
verify(receipts).scanPendingContents("123","PLT-1");
|
||||
verifyNoInteractions(operations,balances);
|
||||
}
|
||||
@Test void unifiedScanWithNoPendingBoxesReturnsEmptyInsteadOfCompletedContents() {
|
||||
when(receipts.scanPendingContents("123","RC-DONE")).thenReturn(List.of());
|
||||
assertThat(service.scanTasks(identity,"RC-DONE")).isEmpty();
|
||||
verifyNoInteractions(cartons,items,receiptItems);
|
||||
}
|
||||
@Test void beginClaimsAndRetriesSameTaskWithoutClaimingAgain() {
|
||||
when(sessions.lockOperator("op")).thenReturn(new ReturnCartonCountSessionMapper.Session("op","123",null,null),new ReturnCartonCountSessionMapper.Session("op","123",1L,null));
|
||||
when(receipts.lockCountReceipt("RR-1")).thenReturn(receipt); when(cartons.lockReceipt(1L)).thenReturn(List.of(a,b));
|
||||
when(sessions.claim("op","123",1L)).thenReturn(1);
|
||||
when(sessions.findReceipt(1L)).thenReturn(null,new ReturnCartonCountSessionMapper.Session("op","123",1L,null));
|
||||
service.begin(identity,"RR-1"); service.begin(identity,"RR-1");
|
||||
verify(sessions,times(1)).claim("op","123",1L);
|
||||
verify(sessions,never()).release(anyString(),anyLong());
|
||||
}
|
||||
@Test void activeTaskBlocksAnotherTaskEvenAfterLeavingThePage() {
|
||||
var another = new ReturnReceipt(); another.setId(4L); another.setReceiptNo("RR-2");
|
||||
when(receipts.lockCountReceipt("RR-2")).thenReturn(another);
|
||||
assertThatThrownBy(() -> service.begin(identity,"RR-2")).isInstanceOf(ResponseStatusException.class).hasMessageContaining("一次只能清点一单");
|
||||
verify(sessions,never()).claim(anyString(),anyString(),anyLong()); verifyNoInteractions(cartons);
|
||||
}
|
||||
@Test void anotherOperatorCannotTakeClaimedTask() {
|
||||
when(sessions.lockOperator("op")).thenReturn(new ReturnCartonCountSessionMapper.Session("op","123",null,null));
|
||||
when(receipts.lockCountReceipt("RR-1")).thenReturn(receipt); when(cartons.lockReceipt(1L)).thenReturn(List.of(a,b));
|
||||
when(sessions.findReceipt(1L)).thenReturn(new ReturnCartonCountSessionMapper.Session("someone","123",1L,null));
|
||||
assertThatThrownBy(() -> service.begin(identity,"RR-1")).isInstanceOf(ResponseStatusException.class).hasMessageContaining("其他人员");
|
||||
verify(sessions,never()).claim(anyString(),anyString(),anyLong());
|
||||
}
|
||||
@Test void currentRestoresClaimedTaskAndDirectConfirmRequiresBegin() {
|
||||
when(sessions.findOperator("op")).thenReturn(new ReturnCartonCountSessionMapper.Session("op","123",1L,null));
|
||||
when(sessions.findReceipt(1L)).thenReturn(new ReturnCartonCountSessionMapper.Session("op","123",1L,null));
|
||||
when(receipts.selectById(1L)).thenReturn(receipt); when(cartons.listReceipt(1L)).thenReturn(List.of(a,b));
|
||||
assertThat(service.current(identity).status()).isEqualTo("COUNTING");
|
||||
when(sessions.lockOperator("op")).thenReturn(new ReturnCartonCountSessionMapper.Session("op","123",null,null));
|
||||
when(receipts.lockCountReceipt("RR-1")).thenReturn(receipt); when(cartons.lockReceipt(1L)).thenReturn(List.of(a,b));
|
||||
assertThatThrownBy(() -> service.confirm(identity,"RR-1",unequal(3,7))).isInstanceOf(ResponseStatusException.class).hasMessageContaining("先开始");
|
||||
verify(items,never()).deleteCarton(anyLong());
|
||||
}
|
||||
}
|
||||
+43
-2
@@ -84,6 +84,46 @@ class ReturnInventoryServiceTest {
|
||||
verify(packingPlans).listPlatform(null, "PLAN-1", "C1", "W1", "SKU1", 20L, 20L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void receiptDetailsUseCountSnapshotEvenAfterInventoryChanges() throws Exception {
|
||||
var receipt = new ReturnReceipt(); receipt.setId(21L); receipt.setCustomerId("C1"); receipt.setReceiptNo("RR-1"); receipt.setUnitType("PALLET"); receipt.setPalletCode("PLT-1");
|
||||
var snapshot = new com.baiyue.lastleg.returnreceipt.dto.ReturnCartonCountDtos.Task("RR-1", "RT-1", "PLT-1", "CONFIRMED", List.of(), List.of(
|
||||
new com.baiyue.lastleg.returnreceipt.dto.ReturnCartonCountDtos.Box("RC#2-1", List.of(new com.baiyue.lastleg.returnreceipt.dto.ReturnCartonCountDtos.Sku("A", "商品A", 3))),
|
||||
new com.baiyue.lastleg.returnreceipt.dto.ReturnCartonCountDtos.Box("RC#2-2", List.of(new com.baiyue.lastleg.returnreceipt.dto.ReturnCartonCountDtos.Sku("A", "商品A", 7)))));
|
||||
var operation = new com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryOperation();
|
||||
operation.setResultJson(new com.fasterxml.jackson.databind.ObjectMapper().findAndRegisterModules().writeValueAsString(snapshot));
|
||||
when(operations.receiptContents("C1", 21L)).thenReturn(operation);
|
||||
var detail = service.receiptContents(receipt);
|
||||
assertThat(detail).hasSize(2);
|
||||
assertThat(detail.get(0).items().get(0).quantity()).isEqualTo(3);
|
||||
assertThat(detail.get(1).items().get(0).quantity()).isEqualTo(7);
|
||||
assertThat(detail.get(0).countStatus()).isEqualTo("CONFIRMED");
|
||||
verifyNoInteractions(cartons, cartonItems);
|
||||
}
|
||||
|
||||
@Test
|
||||
void pendingReceiptDetailsDoNotExposeProvisionalAveragesAndParcelsHaveNoBoxes() {
|
||||
var receipt = new ReturnReceipt(); receipt.setId(21L); receipt.setCustomerId("C1"); receipt.setReceiptNo("RR-1"); receipt.setUnitType("PALLET");
|
||||
var box = new ReturnInventoryCarton(); box.setCartonMark("RC#2-1"); box.setCountStatus("PENDING"); box.setTotalQuantity(5L);
|
||||
when(cartons.listReceipt(21L)).thenReturn(List.of(box));
|
||||
var detail = service.receiptContents(receipt);
|
||||
assertThat(detail.get(0).countStatus()).isEqualTo("PENDING");
|
||||
assertThat(detail.get(0).items()).isEmpty();
|
||||
receipt.setUnitType("PARCEL");
|
||||
assertThat(service.receiptContents(receipt)).isEmpty();
|
||||
verifyNoInteractions(cartonItems);
|
||||
}
|
||||
|
||||
@Test
|
||||
void boxSigningStoresActualContentsAsImmutableReceiptSnapshot() {
|
||||
var receipt = new ReturnReceipt(); receipt.setId(21L); receipt.setReceiptNo("RR-BOX"); receipt.setUnitType("BOX"); receipt.setUnitCode("RC-BOX"); receipt.setOperatorId("operator-1");
|
||||
service.createReceiptCarton(completedOrder(), receipt, "RC-BOX", List.of(new ReturnInventoryService.ReceiptLine("A", "商品A", 3), new ReturnInventoryService.ReceiptLine("B", "商品B", 7)));
|
||||
var capture = ArgumentCaptor.forClass(com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryOperation.class);
|
||||
verify(operations).insert(capture.capture());
|
||||
assertThat(capture.getValue().getOperationType()).isEqualTo("SIGN_CONTENTS");
|
||||
assertThat(capture.getValue().getResultJson()).contains("RC-BOX", "RR-BOX", "商品A", "\"quantity\":3", "\"quantity\":7");
|
||||
}
|
||||
|
||||
@Test
|
||||
void cartonDetailsExposeImmutableMergeHistoryWithinCustomerScope() {
|
||||
ReturnInventoryCarton carton = new ReturnInventoryCarton();
|
||||
@@ -141,7 +181,8 @@ class ReturnInventoryServiceTest {
|
||||
when(cartons.findCustomerMark(carton.getCustomerId(), carton.getCartonMark())).thenReturn(carton);
|
||||
when(cartonItems.listCarton(31L)).thenReturn(List.of(item(41L, "SKU-A", 2L)));
|
||||
String html = service.label(carton.getCustomerId(), carton.getCartonMark()).printableHtml();
|
||||
assertThat(html).contains("<svg", carton.getCartonMark(), "SKU-A", "box-sizing:border-box");
|
||||
assertThat(html).contains("<svg", carton.getCartonMark(), "box-sizing:border-box");
|
||||
assertThat(html).doesNotContain("SKU-A", "class=\"sku\"");
|
||||
assertThat(html).doesNotContain("RT-1", "RB-1,RB-2", "—");
|
||||
assertThat(html).doesNotContain("repeating-linear-gradient", "null", carton.getCustomerId(), carton.getOverseasWarehouseId());
|
||||
}
|
||||
@@ -309,7 +350,7 @@ class ReturnInventoryServiceTest {
|
||||
assertThat(result.totalQuantity()).isEqualTo(1L);
|
||||
assertThat(result.label().items()).hasSize(1);
|
||||
assertThat(result.label().items().get(0).quantity()).isEqualTo(1L);
|
||||
assertThat(result.label().printableHtml()).contains("RC-WINNER", "SKU-A");
|
||||
assertThat(result.label().printableHtml()).contains("RC-WINNER").doesNotContain("SKU-A");
|
||||
verify(operations).findKey("operator-2", "concurrent-key");
|
||||
verify(operations).lockKey("operator-2", "concurrent-key");
|
||||
verify(cartons, never()).selectById(anyLong());
|
||||
|
||||
+3
-2
@@ -299,7 +299,6 @@ class ReturnReceiptServiceTest {
|
||||
AtomicReference<ReturnOrder> saved = new AtomicReference<>();
|
||||
when(orders.findKey("customer-1", "create-key")).thenReturn(null);
|
||||
when(numbers.next(eq("RETURN"), eq("10"), anyLong())).thenReturn("RT-1");
|
||||
when(numbers.next(eq("RETURN_RELABEL"), eq("10"), anyLong())).thenReturn("RETU-1");
|
||||
when(orders.insert(any(ReturnOrder.class))).thenAnswer(invocation -> { saved.set(invocation.getArgument(0)); return 1; });
|
||||
when(orders.findNo("customer-1", "RT-1")).thenAnswer(invocation -> saved.get());
|
||||
when(orderItems.listOrder(anyLong())).thenReturn(List.of());
|
||||
@@ -313,7 +312,9 @@ class ReturnReceiptServiceTest {
|
||||
assertEquals("RT-1", tail.getValue().getSourceInboundId());
|
||||
assertEquals("RETURN_ORDER:RT-1", tail.getValue().getSourceEventId());
|
||||
assertEquals(saved.get().getRequestHash(), tail.getValue().getSourcePayloadHash());
|
||||
assertEquals("RETU-1", result.order().lastlegOrderNo());
|
||||
assertEquals("RT-1", tail.getValue().getOrderNo());
|
||||
assertEquals("RT-1", result.order().lastlegOrderNo());
|
||||
verify(numbers, never()).next(eq("RETURN_RELABEL"), anyString(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -75,6 +75,7 @@ class LastlegOrderServiceTest {
|
||||
@Mock WarehouseResourceGateway warehouseResourceGateway;
|
||||
@Mock ContainerShippingGateMapper containerShippingGates;
|
||||
@Mock ReturnOrderReferenceResolver returnOrderReferences;
|
||||
@Mock com.baiyue.lastleg.returnreceipt.service.ReturnReceiptService returnReceipts;
|
||||
LastlegOrderService service;
|
||||
|
||||
@Test
|
||||
@@ -87,6 +88,13 @@ class LastlegOrderServiceTest {
|
||||
assertEquals("WT-WH-20260911-020225", LastlegOrderService.displayOrderNo(order));
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnTailOrderUsesSourceReturnNumber() {
|
||||
LastlegOrder order = new LastlegOrder(); order.setOrderType("RETURN_RELABEL");
|
||||
order.setOrderNo("RETU-OLD"); order.setSourceOrderNo("RT-1");
|
||||
assertEquals("RT-1", LastlegOrderService.displayOrderNo(order));
|
||||
}
|
||||
|
||||
@Test
|
||||
void exposesStableContainerBookingIdInOrderSummary() {
|
||||
LastlegOrder order = new LastlegOrder();
|
||||
@@ -236,6 +244,18 @@ class LastlegOrderServiceTest {
|
||||
.noneMatch(component -> "eventId".equals(component.getName())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnTailDetailReadsReceiptFactsWithOwnedCustomerAndSourceReturnNumber() {
|
||||
ReflectionTestUtils.setField(service, "returnReceipts", returnReceipts);
|
||||
LastlegOrder order = order(11L, "100", "INBOUND_COMPLETED", null);
|
||||
order.setOrderType("RETURN_RELABEL"); order.setSourceOrderNo("RT-SOURCE");
|
||||
when(orders.selectOne(any())).thenReturn(order);
|
||||
var receiptDetail = new com.baiyue.lastleg.returnreceipt.dto.ReturnOrderResponses.Detail(null, null, List.of(), List.of(), List.of(), List.of());
|
||||
when(returnReceipts.detail("100", "RT-SOURCE")).thenReturn(receiptDetail);
|
||||
assertSame(receiptDetail, service.detail("100", 11L).returnReceipt());
|
||||
verify(returnReceipts).detail("100", "RT-SOURCE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void detailReadsContainerNodeFromTheContainerShippingGate() {
|
||||
LastlegOrder order = order(11L, "100", "PENDING_ASSIGNMENT", null);
|
||||
|
||||
+2
-2
@@ -136,7 +136,7 @@ class WarehouseTransferServiceTest {
|
||||
1, 20, null, null, null, null, null, null, null, null));
|
||||
|
||||
assertEquals("RL-20260923-000001", result.records().get(0).relabelNo());
|
||||
assertEquals("COMPLETED", result.records().get(0).relabelApplicationStatus());
|
||||
assertEquals("COMPLETED", result.records().get(0).relabelStatus());
|
||||
assertEquals("READY_FOR_DISPATCH", result.records().get(0).relabelFulfillmentStatus());
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ class WarehouseTransferServiceTest {
|
||||
1, 20, null, null, null, null, null, null, null, null));
|
||||
|
||||
assertEquals(1, result.records().size());
|
||||
assertNull(result.records().get(0).relabelApplicationStatus());
|
||||
assertNull(result.records().get(0).relabelStatus());
|
||||
assertNull(result.records().get(0).relabelFulfillmentStatus());
|
||||
verify(relabelApplications, never()).selectList(any());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user