提交
This commit is contained in:
+9
-10
@@ -9,14 +9,15 @@ import com.baiyue.lastleg.security.InternalServiceTokenGuard;
|
||||
import com.baiyue.lastleg.service.LastlegOrderService;
|
||||
import com.baiyue.lastleg.service.LoadingCompletedConsumer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@@ -27,17 +28,15 @@ class LastlegOrderControllerTest {
|
||||
1, 20, null, null, null, null, null, null, null, null, null, null);
|
||||
|
||||
@Test
|
||||
void customerCannotOverrideItsTenantScope() {
|
||||
ApiResponse<PageResult<LastlegOrderSummary>> response =
|
||||
controller.list(user(100L, "MERCHANT"), "200", query);
|
||||
assertNotNull(response);
|
||||
verify(service).page(eq("100"), eq(query));
|
||||
void platformEndpointRejectsMerchantIdentity() {
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> controller.list(user(100L, "MERCHANT"), "200", query));
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformOperatorMustExplicitlyChooseCustomerTenant() {
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> controller.list(user(0L, "PLATFORM"), null, query));
|
||||
void platformOperatorCanQueryAllCustomerTenantsWithoutCustomerId() {
|
||||
controller.list(user(0L, "PLATFORM"), null, query);
|
||||
verify(service).page(isNull(), eq(query));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.baiyue.lastleg.controller;
|
||||
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.dto.LastlegOrderRequests;
|
||||
import com.baiyue.lastleg.service.LastlegOrderService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
class MerchantLastlegOrderControllerTest {
|
||||
private final LastlegOrderService service = mock(LastlegOrderService.class);
|
||||
private final MerchantLastlegOrderController controller = controller();
|
||||
private final LastlegOrderRequests.Query query = new LastlegOrderRequests.Query(
|
||||
1, 20, null, null, null, null, null, null, null, null, null, null);
|
||||
|
||||
@Test
|
||||
void merchantListUsesOnlyAuthenticatedTenant() {
|
||||
controller.list(user(100L, "MERCHANT"), query);
|
||||
verify(service).page(eq("100"), eq(query));
|
||||
}
|
||||
|
||||
@Test
|
||||
void merchantDetailUsesOnlyAuthenticatedTenant() {
|
||||
controller.detail(user(100L, "MERCHANT"), 11L);
|
||||
verify(service).detail("100", 11L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void merchantEndpointRejectsPlatformIdentity() {
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> controller.list(user(0L, "PLATFORM"), query));
|
||||
}
|
||||
|
||||
private static AuthenticatedUser user(long tenantId, String appCode) {
|
||||
return new AuthenticatedUser(1L, tenantId, tenantId, 1L, "tester", appCode, "WEB", Set.of());
|
||||
}
|
||||
|
||||
private MerchantLastlegOrderController controller() {
|
||||
MerchantLastlegOrderController controller = new MerchantLastlegOrderController();
|
||||
ReflectionTestUtils.setField(controller, "orderService", service);
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
+16
@@ -2,6 +2,7 @@ package com.baiyue.lastleg.controller;
|
||||
|
||||
import com.baiyue.lastleg.delivery.controller.DeliveryTransferController;
|
||||
import com.baiyue.lastleg.dispatch.controller.DispatchController;
|
||||
import com.baiyue.lastleg.dispatch.controller.DispatchQueryController;
|
||||
import com.baiyue.lastleg.dispatch.pda.controller.DispatchPdaController;
|
||||
import com.baiyue.lastleg.inboundplan.pda.controller.InboundPalletAssignmentController;
|
||||
import com.baiyue.lastleg.inboundplan.pda.controller.InboundPdaController;
|
||||
@@ -9,6 +10,7 @@ import com.baiyue.lastleg.inventory.command.controller.InventoryCommandControlle
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
@@ -37,6 +39,20 @@ class Phase4BrowserApiBoundaryTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void dispatchQueryIsIndependentlyEnabledWithoutExposingOutboundCommands() {
|
||||
ConditionalOnProperty condition = DispatchQueryController.class.getAnnotation(ConditionalOnProperty.class);
|
||||
assertTrue(condition != null);
|
||||
assertTrue(Arrays.asList(condition.name()).contains("lastleg.dispatch-query-api.enabled"));
|
||||
assertFalse(condition.matchIfMissing());
|
||||
assertTrue(Arrays.stream(DispatchQueryController.class.getDeclaredMethods())
|
||||
.filter(method -> method.isAnnotationPresent(GetMapping.class)).count() == 2);
|
||||
assertFalse(Arrays.stream(DispatchQueryController.class.getDeclaredMethods())
|
||||
.flatMap(method -> Arrays.stream(method.getAnnotations()))
|
||||
.anyMatch(annotation -> Set.of("PostMapping", "PutMapping", "DeleteMapping")
|
||||
.contains(annotation.annotationType().getSimpleName())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformInventoryCommandsDoNotMapOutboundAllocationPickingOrShipping() {
|
||||
Set<String> paths = Arrays.stream(InventoryCommandController.class.getDeclaredMethods())
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package com.baiyue.lastleg.dispatch.controller;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.dispatch.dto.DispatchRequests;
|
||||
import com.baiyue.lastleg.dispatch.service.DispatchService;
|
||||
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 java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class DispatchQueryControllerTest {
|
||||
@Mock DispatchService service;
|
||||
private DispatchQueryController controller;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
controller = new DispatchQueryController();
|
||||
ReflectionTestUtils.setField(controller, "service", service);
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformPageQueriesAllCustomersWithoutCustomerId() {
|
||||
DispatchRequests.Query query = new DispatchRequests.Query(1, 20, null, null, null, null);
|
||||
when(service.page(null, query)).thenReturn(new PageResult<>(List.of(), 1, 20, 0, 0));
|
||||
|
||||
var response = controller.page(platform(), query);
|
||||
|
||||
verify(service).page(null, query);
|
||||
assertThat(response.code()).isEqualTo("200");
|
||||
assertThat(response.data().records()).isEmpty();
|
||||
assertThatThrownBy(() -> controller.page(null, query))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.satisfies(error -> org.assertj.core.api.Assertions.assertThat(
|
||||
((ResponseStatusException) error).getStatusCode().value()).isEqualTo(401));
|
||||
}
|
||||
|
||||
private static AuthenticatedUser platform() {
|
||||
return new AuthenticatedUser(7L, 0L, 0L, 8L, "operator", "PLATFORM", "WEB", Set.of());
|
||||
}
|
||||
}
|
||||
+13
@@ -104,6 +104,19 @@ class DispatchServiceTest {
|
||||
verify(orders, never()).updateById(any(DispatchOrder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformDetailFindsDispatchGloballyAndLoadsItemsWithRecordCustomer() {
|
||||
DispatchOrder dispatch = new DispatchOrder();
|
||||
dispatch.setId(1L);
|
||||
dispatch.setCustomerId("200");
|
||||
dispatch.setDispatchNo("PC1");
|
||||
when(orders.findAnyByDispatchNo("PC1")).thenReturn(dispatch);
|
||||
|
||||
service.detail(null, "PC1");
|
||||
|
||||
verify(items).findByDispatchOrder("200", 1L);
|
||||
}
|
||||
|
||||
private DispatchPalletCandidate candidate(long planPalletId, Long warehousePalletId, String destination) {
|
||||
return new DispatchPalletCandidate(1L, planPalletId, warehousePalletId, 2L, "WH-1", "Overseas warehouse", "LMO1", "LMO1", "RK1",
|
||||
"LIP1-P001", destination, destination, destination, destination, 12,
|
||||
|
||||
+3
-7
@@ -36,18 +36,14 @@ class InboundPlanControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformPageRequiresAndPassesExplicitCustomerId() {
|
||||
void platformPageAllowsAllCustomersWhenCustomerIdIsOmitted() {
|
||||
InboundPlanRequests.Query query = new InboundPlanRequests.Query(1, 20, null, null, null,
|
||||
null, null, null, null, null, null, null, null);
|
||||
when(service.page("100", query)).thenReturn(new PageResult<>(List.of(), 1, 20, 0, 0));
|
||||
|
||||
controller.page(platform(), "100", query);
|
||||
controller.page(platform(), null, query);
|
||||
|
||||
verify(service).page("100", query);
|
||||
assertThatThrownBy(() -> controller.page(platform(), "", query))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.satisfies(error -> org.assertj.core.api.Assertions.assertThat(
|
||||
((ResponseStatusException) error).getStatusCode().value()).isEqualTo(400));
|
||||
verify(service).page(null, query);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+19
-2
@@ -97,7 +97,7 @@ class InventoryCommandServiceTest {
|
||||
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> service.hold("100", "7", new InventoryCommandRequests.Move(
|
||||
"100", 201L, 6, "ORD-1", null, null, "hold-1", null)));
|
||||
201L, 6, "ORD-1", null, null, "hold-1", null)));
|
||||
verify(positions, never()).updateById(any(InventoryPosition.class));
|
||||
verify(balances, never()).updateById(any(InventoryBalance.class));
|
||||
}
|
||||
@@ -129,7 +129,7 @@ class InventoryCommandServiceTest {
|
||||
when(commands.palletPackages("100", 300L)).thenReturn(0L);
|
||||
|
||||
var result = service.ship("100", "7", new InventoryCommandRequests.Move(
|
||||
"100", 201L, 5, "OUT-1", "OUT-1", null, "ship-1", null));
|
||||
201L, 5, "OUT-1", "OUT-1", null, "ship-1", null));
|
||||
|
||||
assertTrue(result.palletEmpty());
|
||||
assertEquals("EMPTY", position.getStatus());
|
||||
@@ -137,6 +137,23 @@ class InventoryCommandServiceTest {
|
||||
verify(ledgers).insert(any(InventoryLedger.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformHoldDerivesCustomerFromInventoryPosition() {
|
||||
InventoryBalance balance = balance(200L, 5);
|
||||
InventoryPosition position = position(201L, 200L, 5);
|
||||
position.setCustomerId("200");
|
||||
when(commands.findPosition(201L)).thenReturn(position);
|
||||
when(commands.lockPosition("200", 201L)).thenReturn(position);
|
||||
when(commands.lockBalance("200", 200L)).thenReturn(balance);
|
||||
InventoryCommandRequests.Move request = new InventoryCommandRequests.Move(
|
||||
201L, 2, "ORD-1", null, null, "platform-hold-1", null);
|
||||
|
||||
service.holdPlatform("7", request);
|
||||
|
||||
verify(commands).lockPosition("200", 201L);
|
||||
verify(operations).findIdempotency("200", "platform-hold-1");
|
||||
}
|
||||
|
||||
private InventoryCommandRequests.StockIn stockIn(String inbound, String key, long packages, long quantity) {
|
||||
return new InventoryCommandRequests.StockIn("100", "Customer 100", "WH-1", "WH1", "Warehouse 1",
|
||||
"DEST-1", "ONT8", "ONT8", 101L, inbound, "IN-CODE-1", "SKU-1", "Product 1", null,
|
||||
|
||||
+5
-5
@@ -44,14 +44,14 @@ class InventoryCommandControllerTest {
|
||||
@Test
|
||||
void permittedBackOfficeUserCanRunInventoryFormCommand() {
|
||||
var request = move();
|
||||
when(service.hold("100", "7", request)).thenReturn(response());
|
||||
when(service.holdPlatform("7", request)).thenReturn(response());
|
||||
controller.hold(user(Set.of(InventoryCommandController.MANAGE_PERMISSION)), request);
|
||||
verify(service).hold("100", "7", request);
|
||||
verify(service).holdPlatform("7", request);
|
||||
}
|
||||
|
||||
@Test
|
||||
void physicalAdjustmentRequiresDedicatedPermission() {
|
||||
var request = new InventoryCommandRequests.Adjustment("100", 1L, 2, "COUNT", "ORD-1", "adj-1", null);
|
||||
var request = new InventoryCommandRequests.Adjustment(1L, 2, "COUNT", "ORD-1", "adj-1", null);
|
||||
ResponseStatusException exception = assertThrows(ResponseStatusException.class,
|
||||
() -> controller.adjust(user(Set.of(InventoryCommandController.MANAGE_PERMISSION)), request));
|
||||
assertEquals(403, exception.getStatusCode().value());
|
||||
@@ -59,11 +59,11 @@ class InventoryCommandControllerTest {
|
||||
}
|
||||
|
||||
private InventoryCommandRequests.Move move() {
|
||||
return new InventoryCommandRequests.Move("100", 1L, 2, "ORD-1", null, null, "hold-1", null);
|
||||
return new InventoryCommandRequests.Move(1L, 2, "ORD-1", null, null, "hold-1", null);
|
||||
}
|
||||
|
||||
private AuthenticatedUser user(Set<String> permissions) {
|
||||
return new AuthenticatedUser(7L, 100L, 100L, 8L, "operator", "MERCHANT", "WEB", permissions);
|
||||
return new AuthenticatedUser(7L, 0L, 0L, 8L, "operator", "PLATFORM", "WEB", permissions);
|
||||
}
|
||||
|
||||
private InventoryCommandResponse response() {
|
||||
|
||||
+9
-9
@@ -21,21 +21,21 @@ class InventoryQueryControllerTest {
|
||||
1L, 20L, null, null, null, null, null, null, null, null, null, null, null, null);
|
||||
|
||||
@Test
|
||||
void merchantCannotOverrideCustomerScope() {
|
||||
controller.balances(user(100L, "MERCHANT"), "200", query);
|
||||
verify(service).balances(eq("100"), eq(query));
|
||||
void platformBalancePageQueriesAllCustomers() {
|
||||
controller.balances(user(0L, "PLATFORM"), query);
|
||||
verify(service).balances(eq(null), eq(query));
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformMustSelectCustomer() {
|
||||
void merchantCannotUsePlatformInventoryController() {
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> controller.summary(user(0L, "PLATFORM"), null, query));
|
||||
() -> controller.summary(user(100L, "MERCHANT"), query));
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformCanQuerySelectedCustomer() {
|
||||
controller.summary(user(0L, "PLATFORM"), "200", query);
|
||||
verify(service).dashboard(eq("200"), eq(query));
|
||||
void platformSummaryQueriesAllCustomers() {
|
||||
controller.summary(user(0L, "PLATFORM"), query);
|
||||
verify(service).dashboard(eq(null), eq(query));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -43,7 +43,7 @@ class InventoryQueryControllerTest {
|
||||
InventoryQueryRequests.PositionQuery positionQuery =
|
||||
new InventoryQueryRequests.PositionQuery(null, null, null);
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> controller.positions(null, null, 1L, positionQuery));
|
||||
() -> controller.positions(null, 1L, positionQuery));
|
||||
}
|
||||
|
||||
private static AuthenticatedUser user(long customerId, String appCode) {
|
||||
|
||||
+24
@@ -65,6 +65,16 @@ class InventoryQueryServiceTest {
|
||||
verify(mapper).balances("100", query, 0, 20);
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformBalancePagePassesNoCustomerFilter() {
|
||||
InventoryQueryRequests.BalanceQuery query = balanceQuery(null);
|
||||
when(mapper.countBalances(null, query)).thenReturn(0L);
|
||||
|
||||
service.balances(null, query);
|
||||
|
||||
verify(mapper).countBalances(null, query);
|
||||
}
|
||||
|
||||
@Test
|
||||
void unknownStatusIsRejectedBeforeDatabaseQuery() {
|
||||
InventoryQueryRequests.BalanceQuery query = balanceQuery("DAMAGED");
|
||||
@@ -102,6 +112,20 @@ class InventoryQueryServiceTest {
|
||||
assertEquals(7L, result.totalPackages());
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformPositionDetailDerivesCustomerFromBalance() {
|
||||
InventoryQueryRequests.PositionQuery query = new InventoryQueryRequests.PositionQuery(null, null, null);
|
||||
InventoryBalance balance = new InventoryBalance();
|
||||
balance.setId(99L);
|
||||
balance.setCustomerId("200");
|
||||
when(mapper.findBalance(99L)).thenReturn(balance);
|
||||
when(mapper.positions("200", 99L, query)).thenReturn(List.of());
|
||||
|
||||
service.positions(null, 99L, query);
|
||||
|
||||
verify(mapper).positions("200", 99L, query);
|
||||
}
|
||||
|
||||
@Test
|
||||
void reversedLedgerDateRangeIsRejected() {
|
||||
InventoryQueryRequests.LedgerQuery query = new InventoryQueryRequests.LedgerQuery(
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.baiyue.lastleg.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class LastlegOrderTypeTest {
|
||||
@Test
|
||||
void exposesTheSupportedBusinessTypes() {
|
||||
assertEquals(
|
||||
Arrays.asList("FIRST_LEG", "RELABEL_APPLICATION", "WAREHOUSE_TRANSFER",
|
||||
"LOCAL_LOOSEBOARD", "RETURN_RELABEL", "ONE_CLICK_DROPSHIP"),
|
||||
Arrays.stream(LastlegOrderType.values()).map(Enum::name).toList());
|
||||
assertEquals("换标下单", LastlegOrderType.RELABEL_APPLICATION.label());
|
||||
assertEquals("本土散板", LastlegOrderType.LOCAL_LOOSEBOARD.label());
|
||||
}
|
||||
}
|
||||
@@ -37,4 +37,20 @@ class RelabelContractTest {
|
||||
assertTrue(schema.contains("request_hash"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void openApiDocumentsAllRelabelApplicationOperations() throws Exception {
|
||||
String openApi = Files.readString(Path.of("src/main/resources/openapi/overseas-business-v1.yaml"), StandardCharsets.UTF_8);
|
||||
assertTrue(openApi.contains("/api/platform/v1/last-leg/relabel-applications:"));
|
||||
assertTrue(openApi.contains("/api/platform/v1/last-leg/relabel-applications/{relabelNo}:"));
|
||||
assertTrue(openApi.contains("/api/platform/v1/last-leg/relabel-applications/{relabelNo}/status:"));
|
||||
assertTrue(openApi.contains("RelabelCreate"));
|
||||
assertTrue(openApi.contains("RelabelStatusChange"));
|
||||
assertTrue(openApi.contains("platform:overseas-warehouse:relabel-order:list"));
|
||||
assertTrue(openApi.contains("platform:overseas-warehouse:relabel-order:create"));
|
||||
assertTrue(openApi.contains("platform:overseas-warehouse:relabel-order:status"));
|
||||
String relabelPaths = openApi.substring(openApi.indexOf("/api/platform/v1/last-leg/relabel-applications:"),
|
||||
openApi.indexOf("components:"));
|
||||
assertFalse(relabelPaths.contains("name: customerId"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ class LastlegOrderServiceTest {
|
||||
var response = service.detail("100", 11L);
|
||||
|
||||
assertEquals(11L, response.order().id());
|
||||
assertEquals("100", response.order().customerId());
|
||||
assertTrue(java.util.Arrays.stream(response.getClass().getRecordComponents())
|
||||
.noneMatch(component -> "dropshipPallets".equals(component.getName())));
|
||||
assertTrue(java.util.Arrays.stream(com.baiyue.lastleg.dto.LastlegOrderDetailResponse.History.class.getRecordComponents())
|
||||
|
||||
Reference in New Issue
Block a user