Merge branch 'test' of http://8.163.30.128:10082/java-project/baiyue-firstleg into test
This commit is contained in:
+2
@@ -153,6 +153,8 @@ class ReceivingContainerContractTest {
|
||||
assertTrue(yaml.contains("enum: [LICENSE_PLATE, CONTAINER_SEAL, DOOR_OPEN]"));
|
||||
assertTrue(yaml.contains("photos: { type: array, minItems: 3, maxItems: 3"));
|
||||
assertTrue(yaml.contains("required: [role, fileId, downloadPath]"));
|
||||
assertTrue(yaml.contains("packageCount: { type: integer, minimum: 1, maximum: 66 }"));
|
||||
assertTrue(receivingPaths.contains("单托最多 66 箱"));
|
||||
assertTrue(yaml.contains("overseasWarehouseId: { type: string"));
|
||||
assertTrue(yaml.contains("overseasWarehouseName: { type: string"));
|
||||
assertFalse(receivingPaths.contains("photoFileIds"));
|
||||
|
||||
+73
@@ -49,6 +49,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -422,6 +423,55 @@ class ReceivingContainerServiceBehaviorTest {
|
||||
verifyNoInteractions(workflow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void fbaPalletAccepts66PackagesAndRejects67BeforeReceivingStarts() {
|
||||
stubCurrent("FBA", "CONT-A");
|
||||
InboundPlanLine fbaLine = line("FBA");
|
||||
fbaLine.setRequiredPackageCount(66);
|
||||
when(lines.selectList(any())).thenReturn(List.of(fbaLine));
|
||||
when(orderDetails.selectList(any())).thenReturn(List.of(detail("SKU-1", 66)));
|
||||
when(skuReceipts.listLineSku("100", 10L, "SKU-1")).thenReturn(List.of());
|
||||
stubReservedFbaPallet();
|
||||
when(workflow.receiveBulkResolved(any(), any(), any(), any(), anyInt(), any(), any()))
|
||||
.thenAnswer(invocation -> invocation.getArgument(4));
|
||||
when(fbaPalletCounts.insert(any(ReceivingFbaPalletCount.class))).thenReturn(1);
|
||||
when(sessions.updateById(any(ReceivingContainerSession.class))).thenReturn(1);
|
||||
when(operations.insert(any(ReceivingContainerOperation.class))).thenReturn(1);
|
||||
|
||||
var accepted = service.receiveBulk("7", "receiver",
|
||||
new ReceivingContainerRequests.BulkReceive("IN-1", "PAL-1", 66, "capacity-66"));
|
||||
|
||||
assertThat(accepted.acceptedPackages()).isEqualTo(66);
|
||||
|
||||
org.mockito.Mockito.reset(sessions, workflow, warehouse);
|
||||
assertThatThrownBy(() -> service.receiveBulk("7", "receiver",
|
||||
new ReceivingContainerRequests.BulkReceive("IN-1", "PAL-1", 67, "capacity-67")))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("66箱");
|
||||
verifyNoInteractions(sessions, workflow, warehouse);
|
||||
}
|
||||
|
||||
@Test
|
||||
void overseasCartonIsRejectedWhenPhysicalPalletAlreadyContains66Packages() {
|
||||
stubCurrent("OVERSEAS", "CONT-A");
|
||||
when(cartons.selectOne(any())).thenReturn(carton(1L, "IN-1#67"));
|
||||
InboundPlanPallet reserved = planPallet();
|
||||
reserved.setPalletNo("PAL-1"); reserved.setWarehousePalletId(30L); reserved.setWarehouseLocationId(40L);
|
||||
reserved.setWarehouseResourceLockId(50L); reserved.setAssignmentStatus("RESERVED");
|
||||
when(pallets.selectList(any())).thenReturn(List.of(reserved));
|
||||
when(warehouse.resolveReservedPallet("PAL-1", "100", 100L, 30L, 40L, 50L))
|
||||
.thenReturn(resource(100L, null));
|
||||
when(cartons.selectCount(any())).thenReturn(66L);
|
||||
|
||||
assertThatThrownBy(() -> service.receiveCarton("7", "receiver",
|
||||
new ReceivingContainerRequests.CartonReceive("IN-1#67", "PAL-1", "carton-capacity")))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("66箱");
|
||||
|
||||
verify(workflow, never()).validateCartonResolved(any(), any(), any(), any(), any());
|
||||
verify(workflow, never()).assignResolvedPallet(any(), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void crossContainerCartonAndMismatchedPalletAreRejectedBeforeReservation() {
|
||||
stubCurrent("OVERSEAS", "CONT-A");
|
||||
@@ -950,6 +1000,29 @@ class ReceivingContainerServiceBehaviorTest {
|
||||
verifyNoInteractions(warehouse);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dropshipWholePalletOver66PackagesIsRejectedBeforePicking() {
|
||||
stubCurrent("OVERSEAS", "CONT-A");
|
||||
LastlegOrder dropship = order("OVERSEAS"); dropship.setOrderType("ONE_CLICK_DROPSHIP");
|
||||
when(orders.selectById(1L)).thenReturn(dropship);
|
||||
InboundPlanPallet pallet = planPallet();
|
||||
pallet.setPalletNo("DP-260909-0067"); pallet.setSourcePalletNo("DP-260909-0067");
|
||||
pallet.setWarehousePalletId(30L);
|
||||
InboundPlanPalletAllocation pending = new InboundPlanPalletAllocation();
|
||||
pending.setId(67L); pending.setCustomerId("100"); pending.setPlanId(2L);
|
||||
pending.setLineId(10L); pending.setPalletId(20L); pending.setPlannedPackageCount(67);
|
||||
when(pallets.selectList(any())).thenReturn(List.of(pallet));
|
||||
when(allocations.selectList(any())).thenReturn(List.of(pending));
|
||||
stubCompleteManifest("DP-260909-0067", 67);
|
||||
|
||||
assertThatThrownBy(() -> service.receiveWholePallet("7", "receiver",
|
||||
new ReceivingContainerRequests.WholePalletReceive("DP-260909-0067", "whole-capacity")))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("66箱");
|
||||
|
||||
verify(workflow, never()).pickWholePallet(any(), any(), anyLong(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void domesticLoadingPhotoDownloadIsScopedToTheCurrentPhysicalContainer() {
|
||||
ReceivingContainerSession current = session("CONT-A", "SIGNED");
|
||||
|
||||
+16
@@ -85,6 +85,22 @@ class ContainerInboundPlanPreviewTest {
|
||||
assertFalse(result.ready());
|
||||
}
|
||||
|
||||
@Test
|
||||
void heldHistoricalOrderRemainsReadyBecauseHoldOnlyBlocksOutbound() {
|
||||
when(orderMapper.containerPreviewOrders("BOOKING-HELD")).thenReturn(List.of(
|
||||
new InboundPlanOrderMapper.ContainerPreviewOrderRow("100", 1L, "LM-HELD", "FO-1",
|
||||
"测试客户", "FIRST_LEG", "FBA", "IN-1", "PENDING_ASSIGNMENT", null,
|
||||
"MSCU6639870", 1, 10, new BigDecimal("1.0000"), "193000000000200003", "US-LAX-01",
|
||||
"洛杉矶仓", "ACY2", null, null, "Amazon ACY2", 0, true, 1,
|
||||
null, null, null, null, 1)));
|
||||
|
||||
var result = service.previewContainer("BOOKING-HELD");
|
||||
|
||||
assertEquals(true, result.ready());
|
||||
assertEquals("READY", result.groups().get(0).orders().get(0).readiness());
|
||||
assertEquals(List.of(), result.groups().get(0).orders().get(0).blockers());
|
||||
}
|
||||
|
||||
@Test
|
||||
void dropshipPreviewKeepsUnderlyingFbaFactSeparateFromItsDisplayCategory() {
|
||||
when(orderMapper.containerPreviewOrders("BOOKING-DROPSHIP")).thenReturn(List.of(
|
||||
|
||||
+9
-7
@@ -352,21 +352,23 @@ class InboundPlanServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void refusesManualPlanForHeldOrderBeforeWriting() {
|
||||
void createsManualPlanForHeldHistoricalOrderBecauseHoldOnlyBlocksOutbound() {
|
||||
SourceOrderSnapshot held = new SourceOrderSnapshot(2L, "100", "MSCU6639870", "RK-2",
|
||||
"PENDING_ASSIGNMENT", null, new BigDecimal("1.0000"), 10, 0,
|
||||
"193000000000200003", "US-LAX-01", "洛杉矶仓", null,
|
||||
null, "WH-A", "仓A", 1, 0, true, 5);
|
||||
"WH-A", "WH-A", "仓A", 1, 0, true, 5);
|
||||
when(orderMapper.lockOrder("100", 2L)).thenReturn(List.of(held));
|
||||
when(orderMapper.markPlannedManual(eq("100"), eq(2L), any(), eq(1), eq(false), eq(5), any()))
|
||||
.thenReturn(1);
|
||||
|
||||
ResponseStatusException error = assertThrows(ResponseStatusException.class, () -> service.convertManual(
|
||||
var result = service.convertManual(
|
||||
new ManualInboundPlanRequest("100", 2L, 5,
|
||||
1, "STANDARD", false, false, false, null),
|
||||
"manual-held", "900"));
|
||||
"manual-held", "900");
|
||||
|
||||
assertEquals(409, error.getStatusCode().value());
|
||||
verify(planMapper, never()).insert(any(InboundPlan.class));
|
||||
verify(commandMapper, never()).insert(any(com.baiyue.lastleg.entity.LastlegOrderCommandRecord.class));
|
||||
assertEquals(2L, result.sourceOrderId());
|
||||
verify(planMapper).insert(any(InboundPlan.class));
|
||||
verify(orderMapper).markPlannedManual(eq("100"), eq(2L), any(), eq(1), eq(false), eq(5), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+17
@@ -280,6 +280,23 @@ class InventoryCommandServiceTest {
|
||||
verify(balances, never()).updateById(any(InventoryBalance.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void holdsAllAvailablePositionsForOneInboundOrder() {
|
||||
InventoryBalance balance = balance(200L, 5);
|
||||
InventoryPosition position = position(201L, 200L, 5);
|
||||
when(commands.lockInboundAvailablePositions("100", 101L)).thenReturn(List.of(position));
|
||||
when(commands.lockPosition("100", 201L)).thenReturn(position);
|
||||
when(commands.lockBalance("100", 200L)).thenReturn(balance);
|
||||
|
||||
service.holdInboundOrderInventory("100", "7", 101L, "ORD-1", "质检暂扣");
|
||||
|
||||
assertEquals(0L, position.getAvailablePackages());
|
||||
assertEquals(5L, position.getHoldPackages());
|
||||
assertEquals(0L, balance.getAvailablePackages());
|
||||
assertEquals(5L, balance.getHoldPackages());
|
||||
verify(ledgers).insert(any(InventoryLedger.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void replayUsesPersistedResultWithoutMutatingInventoryAgain() throws Exception {
|
||||
var request = stockIn("IN-1", "stock-in-1", 12, 24);
|
||||
|
||||
+72
-8
@@ -1,14 +1,19 @@
|
||||
package com.baiyue.lastleg.merchant;
|
||||
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.controller.MerchantLastlegOrderController;
|
||||
import com.baiyue.lastleg.inboundplan.controller.MerchantInboundPlanController;
|
||||
import com.baiyue.lastleg.inboundplan.dto.InboundPlanRequests;
|
||||
import com.baiyue.lastleg.inboundplan.service.InboundPlanService;
|
||||
import com.baiyue.lastleg.discard.controller.MerchantCargoDiscardController;
|
||||
import com.baiyue.lastleg.looseboard.controller.MerchantLocalLooseboardController;
|
||||
import com.baiyue.lastleg.looseboard.dto.LocalLooseboardRequests;
|
||||
import com.baiyue.lastleg.looseboard.service.LocalLooseboardService;
|
||||
import com.baiyue.lastleg.procurement.controller.MerchantOverseasProcurementController;
|
||||
import com.baiyue.lastleg.relabel.controller.MerchantRelabelApplicationController;
|
||||
import com.baiyue.lastleg.returnreceipt.controller.MerchantReturnOrderController;
|
||||
import com.baiyue.lastleg.security.OverseasPermissions;
|
||||
import com.baiyue.lastleg.transfer.controller.MerchantWarehouseTransferController;
|
||||
import com.baiyue.lastleg.trucking.controller.MerchantUsTruckOrderController;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -21,6 +26,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -43,15 +49,57 @@ class MerchantOverseasCustomerApiContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void merchantControllersUseFrozenPathsAndExistingClientPermissionCodes() {
|
||||
assertController(MerchantOverseasProcurementController.class,
|
||||
"/api/merchant/v1/last-leg/overseas-procurements", OverseasPermissions.MERCHANT_PROCUREMENT);
|
||||
assertController(MerchantUsTruckOrderController.class,
|
||||
"/api/merchant/v1/last-leg/us-truck-orders", OverseasPermissions.MERCHANT_TRUCKING);
|
||||
assertController(MerchantLocalLooseboardController.class,
|
||||
"/api/merchant/v1/last-leg/local-looseboard-orders", OverseasPermissions.MERCHANT_LOOSEBOARD);
|
||||
void merchantControllersUseFrozenPathsAndOperationPermissions() {
|
||||
assertPath(MerchantOverseasProcurementController.class, "/api/merchant/v1/last-leg/overseas-procurements");
|
||||
assertPermissions(MerchantOverseasProcurementController.class, Map.of(
|
||||
"create", OverseasPermissions.MERCHANT_PROCUREMENT_CREATE,
|
||||
"page", OverseasPermissions.MERCHANT_PROCUREMENT_LIST,
|
||||
"detail", OverseasPermissions.MERCHANT_PROCUREMENT_LIST));
|
||||
assertPath(MerchantUsTruckOrderController.class, "/api/merchant/v1/last-leg/us-truck-orders");
|
||||
assertPermissions(MerchantUsTruckOrderController.class, Map.of(
|
||||
"create", OverseasPermissions.MERCHANT_TRUCKING_CREATE,
|
||||
"page", OverseasPermissions.MERCHANT_TRUCKING_LIST,
|
||||
"detail", OverseasPermissions.MERCHANT_TRUCKING_LIST,
|
||||
"update", OverseasPermissions.MERCHANT_TRUCKING_EDIT));
|
||||
assertPath(MerchantLocalLooseboardController.class, "/api/merchant/v1/last-leg/local-looseboard-orders");
|
||||
assertPermissions(MerchantLocalLooseboardController.class, Map.of(
|
||||
"create", OverseasPermissions.MERCHANT_LOOSEBOARD_CREATE,
|
||||
"page", OverseasPermissions.MERCHANT_LOOSEBOARD_LIST,
|
||||
"detail", OverseasPermissions.MERCHANT_LOOSEBOARD_LIST,
|
||||
"update", OverseasPermissions.MERCHANT_LOOSEBOARD_EDIT));
|
||||
assertController(MerchantInboundPlanController.class,
|
||||
"/api/merchant/v1/last-leg/inbound-plans", OverseasPermissions.MERCHANT_INBOUND_LIST);
|
||||
assertController(MerchantLastlegOrderController.class,
|
||||
"/api/merchant/v1/last-leg/orders", OverseasPermissions.MERCHANT_LAST_MILE_ORDER_LIST);
|
||||
|
||||
assertPermissions(MerchantWarehouseTransferController.class, Map.of(
|
||||
"create", OverseasPermissions.MERCHANT_TRANSFER_CREATE,
|
||||
"page", OverseasPermissions.MERCHANT_TRANSFER_LIST,
|
||||
"detail", OverseasPermissions.MERCHANT_TRANSFER_LIST,
|
||||
"confirmMeasurement", OverseasPermissions.MERCHANT_TRANSFER_CONFIRM));
|
||||
assertPermissions(MerchantCargoDiscardController.class, Map.of(
|
||||
"candidates", OverseasPermissions.MERCHANT_DISCARD_LIST,
|
||||
"create", OverseasPermissions.MERCHANT_DISCARD_CREATE,
|
||||
"page", OverseasPermissions.MERCHANT_DISCARD_LIST,
|
||||
"detail", OverseasPermissions.MERCHANT_DISCARD_LIST,
|
||||
"cancel", OverseasPermissions.MERCHANT_DISCARD_CANCEL));
|
||||
assertPermissions(MerchantReturnOrderController.class, Map.of(
|
||||
"create", OverseasPermissions.MERCHANT_RETURN_ORDER_CREATE,
|
||||
"page", OverseasPermissions.MERCHANT_RETURN_ORDER_LIST,
|
||||
"detail", OverseasPermissions.MERCHANT_RETURN_ORDER_LIST,
|
||||
"relabelCandidates", OverseasPermissions.MERCHANT_RETURN_ORDER_RELABEL,
|
||||
"createRelabel", OverseasPermissions.MERCHANT_RETURN_ORDER_RELABEL));
|
||||
assertPermissions(MerchantRelabelApplicationController.class, Map.of(
|
||||
"candidates", OverseasPermissions.MERCHANT_RELABEL_LIST,
|
||||
"historicalOrders", OverseasPermissions.MERCHANT_RELABEL_LIST,
|
||||
"create", OverseasPermissions.MERCHANT_RELABEL_CREATE,
|
||||
"page", OverseasPermissions.MERCHANT_RELABEL_LIST,
|
||||
"detail", OverseasPermissions.MERCHANT_RELABEL_LIST,
|
||||
"uploadShippingLabel", OverseasPermissions.MERCHANT_RELABEL_FILES,
|
||||
"uploadFile", OverseasPermissions.MERCHANT_RELABEL_FILES,
|
||||
"downloadShippingLabel", OverseasPermissions.MERCHANT_RELABEL_LIST,
|
||||
"downloadCompletionPhoto", OverseasPermissions.MERCHANT_RELABEL_LIST,
|
||||
"confirmCompletion", OverseasPermissions.MERCHANT_RELABEL_CONFIRM));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -90,11 +138,27 @@ class MerchantOverseasCustomerApiContractTest {
|
||||
}
|
||||
|
||||
private static void assertController(Class<?> type, String path, String permission) {
|
||||
assertThat(type.getAnnotation(RequestMapping.class).value()).containsExactly(path);
|
||||
assertPath(type, path);
|
||||
assertThat(type.getAnnotation(PreAuthorize.class).value())
|
||||
.isEqualTo("hasAuthority('" + permission + "')");
|
||||
}
|
||||
|
||||
private static void assertPath(Class<?> type, String path) {
|
||||
assertThat(type.getAnnotation(RequestMapping.class).value()).containsExactly(path);
|
||||
}
|
||||
|
||||
private static void assertPermissions(Class<?> type, Map<String, String> permissions) {
|
||||
for (var entry : permissions.entrySet()) {
|
||||
var method = Arrays.stream(type.getDeclaredMethods())
|
||||
.filter(candidate -> candidate.getName().equals(entry.getKey()))
|
||||
.findFirst().orElseThrow();
|
||||
assertThat(method.getAnnotation(PreAuthorize.class))
|
||||
.as(type.getSimpleName() + "." + entry.getKey()).isNotNull();
|
||||
assertThat(method.getAnnotation(PreAuthorize.class).value())
|
||||
.isEqualTo("hasAuthority('" + entry.getValue() + "')");
|
||||
}
|
||||
}
|
||||
|
||||
private static AuthenticatedUser user(long customerId, String appCode) {
|
||||
return new AuthenticatedUser(7L, customerId, customerId, 8L, "operator", appCode, "WEB", Set.of());
|
||||
}
|
||||
|
||||
+31
-3
@@ -16,6 +16,15 @@ class MerchantOverseasOpenApiContractTest {
|
||||
}
|
||||
|
||||
for (String path : new String[] {
|
||||
"/api/merchant/v1/last-leg/orders:",
|
||||
"/api/merchant/v1/last-leg/orders/{id}:",
|
||||
"/api/merchant/v1/last-leg/warehouse-transfers:",
|
||||
"/api/merchant/v1/last-leg/warehouse-transfers/{transferNo}:",
|
||||
"/api/merchant/v1/last-leg/warehouse-transfers/{transferNo}/confirm-measurement:",
|
||||
"/api/merchant/v1/last-leg/cargo-discards:",
|
||||
"/api/merchant/v1/last-leg/cargo-discards/inventory-candidates:",
|
||||
"/api/merchant/v1/last-leg/cargo-discards/{discardNo}:",
|
||||
"/api/merchant/v1/last-leg/cargo-discards/{discardNo}/cancel:",
|
||||
"/api/merchant/v1/last-leg/overseas-procurements:",
|
||||
"/api/merchant/v1/last-leg/overseas-procurements/{orderNo}:",
|
||||
"/api/merchant/v1/last-leg/us-truck-orders:",
|
||||
@@ -27,9 +36,28 @@ class MerchantOverseasOpenApiContractTest {
|
||||
assertThat(yaml).contains(path);
|
||||
assertThat(pathBlock(yaml, path)).doesNotContain("name: customerId");
|
||||
}
|
||||
assertThat(yaml).contains("merchant:cross-border:procurement")
|
||||
.contains("merchant:cross-border:domestic-trucking")
|
||||
.contains("merchant:cross-border:pallet-shipping")
|
||||
assertThat(yaml).contains("merchant:cross-border:procurement:list")
|
||||
.contains("merchant:cross-border:procurement:create")
|
||||
.contains("merchant:cross-border:domestic-trucking:list")
|
||||
.contains("merchant:cross-border:domestic-trucking:create")
|
||||
.contains("merchant:cross-border:domestic-trucking:edit")
|
||||
.contains("merchant:cross-border:pallet-shipping:list")
|
||||
.contains("merchant:cross-border:pallet-shipping:create")
|
||||
.contains("merchant:cross-border:pallet-shipping:edit")
|
||||
.contains("merchant:overseas-warehouse:last-mile-order:list")
|
||||
.contains("merchant:overseas-warehouse:transfer:list")
|
||||
.contains("merchant:overseas-warehouse:transfer:create")
|
||||
.contains("merchant:overseas-warehouse:transfer:confirm")
|
||||
.contains("merchant:overseas-warehouse:discard:list")
|
||||
.contains("merchant:overseas-warehouse:discard:create")
|
||||
.contains("merchant:overseas-warehouse:discard:cancel")
|
||||
.contains("merchant:overseas-warehouse:relabel:list")
|
||||
.contains("merchant:overseas-warehouse:relabel:create")
|
||||
.contains("merchant:overseas-warehouse:relabel:files")
|
||||
.contains("merchant:overseas-warehouse:relabel:confirm")
|
||||
.contains("merchant:overseas-warehouse:return-order:list")
|
||||
.contains("merchant:overseas-warehouse:return-order:create")
|
||||
.contains("merchant:overseas-warehouse:return-order:relabel")
|
||||
.contains("merchant:warehouse:inbound:list")
|
||||
.contains("#/components/schemas/ProcurementDetailResponse")
|
||||
.contains("#/components/schemas/TruckDetailResponse")
|
||||
|
||||
@@ -96,7 +96,10 @@ class RelabelContractTest {
|
||||
}
|
||||
assertTrue(openApi.contains("RelabelMerchantPageResponse"));
|
||||
assertTrue(openApi.contains("RelabelCustomerConfirm"));
|
||||
assertTrue(openApi.contains("merchant:warehouse:relabel"));
|
||||
assertTrue(openApi.contains("merchant:overseas-warehouse:relabel:list"));
|
||||
assertTrue(openApi.contains("merchant:overseas-warehouse:relabel:create"));
|
||||
assertTrue(openApi.contains("merchant:overseas-warehouse:relabel:files"));
|
||||
assertTrue(openApi.contains("merchant:overseas-warehouse:relabel:confirm"));
|
||||
String relabelPaths = openApi.substring(openApi.indexOf("/api/platform/v1/last-leg/relabel-applications:"),
|
||||
openApi.indexOf("components:"));
|
||||
assertTrue(relabelPaths.contains("name: customerId, in: query, required: true"));
|
||||
|
||||
+37
@@ -12,6 +12,7 @@ import com.baiyue.lastleg.mapper.LastlegOrderManualNodeHistoryMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderManualNodeMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderOperationLogMapper;
|
||||
import com.baiyue.lastleg.inventory.command.service.InventoryCommandService;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -48,6 +49,7 @@ class LastlegOrderCommandServiceTest {
|
||||
@Mock LastlegOrderManualNodeHistoryMapper manualNodeHistory;
|
||||
@Mock LastlegOrderOperationLogMapper operationLogs;
|
||||
@Mock InboundOrderDetainedOutboxService detainedOutbox;
|
||||
@Mock InventoryCommandService inventory;
|
||||
LastlegOrderCommandService service;
|
||||
|
||||
@BeforeEach
|
||||
@@ -60,12 +62,14 @@ class LastlegOrderCommandServiceTest {
|
||||
ReflectionTestUtils.setField(service, "manualNodeHistory", manualNodeHistory);
|
||||
ReflectionTestUtils.setField(service, "operationLogs", operationLogs);
|
||||
ReflectionTestUtils.setField(service, "detainedOutbox", detainedOutbox);
|
||||
ReflectionTestUtils.setField(service, "inventory", inventory);
|
||||
ReflectionTestUtils.setField(service, "objectMapper", JsonMapper.builder().findAndAddModules().build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void holdsOnlySelectedOrderWithVersionAndImmutableHistory() {
|
||||
LastlegOrder order = order(11L, 3);
|
||||
order.setCurrentStatus("INBOUND_COMPLETED");
|
||||
when(orders.selectById(11L)).thenReturn(order);
|
||||
when(orders.lockById("100", 11L)).thenReturn(order);
|
||||
when(orders.updateHold(eq("100"), eq(11L), eq(true), eq(true), eq("海关查验"), eq(3),
|
||||
@@ -80,9 +84,42 @@ class LastlegOrderCommandServiceTest {
|
||||
verify(orders).updateHold(eq("100"), eq(11L), eq(true), eq(true), eq("海关查验"), eq(3), any());
|
||||
verify(holdHistory).insert(any(LastlegOrderHoldHistory.class));
|
||||
verify(commands).insert(any(LastlegOrderCommandRecord.class));
|
||||
verify(inventory).holdInboundOrderInventory("100", "900", 11L, "LL-11", "海关查验");
|
||||
verify(orders, never()).lockContainerOrders(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void releasingHoldMovesOrderInventoryBackToAvailable() {
|
||||
LastlegOrder order = order(11L, 3);
|
||||
order.setCurrentStatus("INBOUND_COMPLETED");
|
||||
order.setDetained(true);
|
||||
when(orders.selectById(11L)).thenReturn(order);
|
||||
when(orders.lockById("100", 11L)).thenReturn(order);
|
||||
when(orders.updateHold(eq("100"), eq(11L), eq(false), eq(false), eq("质检通过"), eq(3),
|
||||
any(LocalDateTime.class))).thenReturn(1);
|
||||
|
||||
service.hold("100", 11L, "release-11",
|
||||
new LastlegOrderCommandDtos.HoldRequest(false, false, "质检通过", 3), "900", "管理员");
|
||||
|
||||
verify(inventory).releaseInboundOrderHold("100", "900", 11L, "LL-11", "质检通过");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsNewHoldBeforeInboundCompletion() {
|
||||
LastlegOrder order = order(11L, 3);
|
||||
when(orders.selectById(11L)).thenReturn(order);
|
||||
when(orders.lockById("100", 11L)).thenReturn(order);
|
||||
|
||||
ResponseStatusException error = assertThrows(ResponseStatusException.class, () -> service.hold("100", 11L,
|
||||
"hold-before-inbound", new LastlegOrderCommandDtos.HoldRequest(true, false, "待入库", 3),
|
||||
"900", "管理员"));
|
||||
|
||||
assertEquals(409, error.getStatusCode().value());
|
||||
assertEquals("货物完成入库后才能暂扣", error.getReason());
|
||||
verify(orders, never()).updateHold(anyString(), anyLong(), anyBoolean(), anyBoolean(),
|
||||
nullable(String.class), anyInt(), any(LocalDateTime.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsStaleHoldWithoutAnyWrite() {
|
||||
LastlegOrder order = order(11L, 4);
|
||||
|
||||
@@ -51,7 +51,6 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -71,7 +70,6 @@ class LastlegOrderServiceTest {
|
||||
@Mock InboundPlanCartonMapper cartons;
|
||||
@Mock FbaWarehouseValidator fbaWarehouses;
|
||||
@Mock InventoryCommandService inventory;
|
||||
@Mock InboundOrderDetainedOutboxService detainedOutbox;
|
||||
@Mock ReceivingWarehouseOperationMapper receivingWarehouseOperations;
|
||||
@Mock ContainerArrivalTimeOperationMapper containerArrivalTimeOperations;
|
||||
@Mock WarehouseResourceGateway warehouseResourceGateway;
|
||||
@@ -118,7 +116,6 @@ class LastlegOrderServiceTest {
|
||||
Long.parseLong(invocation.getArgument(0)), invocation.getArgument(1), invocation.getArgument(2),
|
||||
"US", "CA"));
|
||||
ReflectionTestUtils.setField(service, "inventory", inventory);
|
||||
ReflectionTestUtils.setField(service, "detainedOutbox", detainedOutbox);
|
||||
ReflectionTestUtils.setField(service, "receivingWarehouseOperations", receivingWarehouseOperations);
|
||||
ReflectionTestUtils.setField(service, "containerArrivalTimeOperations", containerArrivalTimeOperations);
|
||||
ReflectionTestUtils.setField(service, "warehouseResourceGateway", warehouseResourceGateway);
|
||||
@@ -586,40 +583,6 @@ class LastlegOrderServiceTest {
|
||||
assertEquals("NYEXX2609060063", result.records().get(2).inboundCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void holdingBeforeInboundPersistsTheOrderMarkerAndOperationRemark() {
|
||||
LastlegOrder order = order(11L, "100", "PENDING_INBOUND", null);
|
||||
when(orders.selectOne(any())).thenReturn(order);
|
||||
when(orders.lockById("100", 11L)).thenReturn(order);
|
||||
|
||||
service.setDetained("100", 11L, new LastlegOrderRequests.SetDetained(true, "等待质检"), "operator");
|
||||
|
||||
assertTrue(order.getDetained());
|
||||
verify(orders).updateById(order);
|
||||
ArgumentCaptor<com.baiyue.lastleg.entity.LastlegOrderOperationLog> operation =
|
||||
ArgumentCaptor.forClass(com.baiyue.lastleg.entity.LastlegOrderOperationLog.class);
|
||||
verify(operations).insert(operation.capture());
|
||||
assertEquals("暂扣", operation.getValue().getOperationNode());
|
||||
assertEquals("等待质检", operation.getValue().getResult());
|
||||
verify(detainedOutbox).publish(eq(order), eq(true), eq("等待质检"), isNull(), eq("operator"), any(), anyLong());
|
||||
verify(inventory, never()).releaseInboundOrderHold(any(), any(), anyLong(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void releasingAfterInboundMovesAllOrderHeldInventoryToAvailable() {
|
||||
LastlegOrder order = order(11L, "100", "INBOUND_COMPLETED", "IP-1");
|
||||
order.setOrderNo("LM-1");
|
||||
order.setDetained(true);
|
||||
when(orders.selectOne(any())).thenReturn(order);
|
||||
when(orders.lockById("100", 11L)).thenReturn(order);
|
||||
|
||||
service.setDetained("100", 11L, new LastlegOrderRequests.SetDetained(false, "质检通过"), "operator");
|
||||
|
||||
verify(inventory).releaseInboundOrderHold("100", "operator", 11L, "LM-1", "质检通过");
|
||||
assertEquals(false, order.getDetained());
|
||||
verify(detainedOutbox).publish(eq(order), eq(false), eq("质检通过"), isNull(), eq("operator"), any(), anyLong());
|
||||
}
|
||||
|
||||
private static LastlegOrder order(long id, String customerId, String status, String inboundOrderNo) {
|
||||
LastlegOrder order = new LastlegOrder();
|
||||
order.setId(id);
|
||||
|
||||
Reference in New Issue
Block a user