feat: complete phase 5 overseas fulfillment contracts
This commit is contained in:
+19
-5
@@ -4,6 +4,8 @@ import com.baiyue.lastleg.palletops.dto.PalletOperationRequests;
|
||||
import com.baiyue.lastleg.pda.move.dto.PdaInventoryMoveRequest;
|
||||
import com.baiyue.lastleg.pda.stocktake.dto.PdaStocktakeRequests;
|
||||
import com.baiyue.lastleg.relabel.pda.dto.PdaRelabelRequests;
|
||||
import com.baiyue.lastleg.dispatch.pda.dto.DispatchPdaRequests;
|
||||
import com.baiyue.lastleg.delivery.dto.DeliveryRequests;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -32,6 +34,11 @@ class PdaOperationsOpenApiContractTest {
|
||||
}
|
||||
}
|
||||
assertNoServerOwnedFields(PdaInventoryMoveRequest.class);
|
||||
assertNoServerOwnedFields(DispatchPdaRequests.Pick.class);
|
||||
assertNoServerOwnedFields(DispatchPdaRequests.CompletePicking.class);
|
||||
assertNoServerOwnedFields(DispatchPdaRequests.Depart.class);
|
||||
assertNoServerOwnedFields(DeliveryRequests.PdaPick.class);
|
||||
assertNoServerOwnedFields(DeliveryRequests.PdaComplete.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -56,16 +63,23 @@ class PdaOperationsOpenApiContractTest {
|
||||
"/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/exceptions:",
|
||||
"/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/photos/files:",
|
||||
"/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/complete:",
|
||||
"/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/review:");
|
||||
"/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/review:",
|
||||
"/api/pda/v1/last-leg/dispatches:",
|
||||
"/api/pda/v1/last-leg/dispatches/{dispatchNo}:",
|
||||
"/api/pda/v1/last-leg/dispatches/{dispatchNo}/items/{itemId}/pick:",
|
||||
"/api/pda/v1/last-leg/dispatches/{dispatchNo}/complete:",
|
||||
"/api/pda/v1/last-leg/dispatches/{dispatchNo}/depart:",
|
||||
"/api/pda/v1/last-leg/outbound-tasks:",
|
||||
"/api/pda/v1/last-leg/outbound-tasks/{taskNo}:",
|
||||
"/api/pda/v1/last-leg/outbound-tasks/{taskNo}/pick:",
|
||||
"/api/pda/v1/last-leg/outbound-tasks/{taskNo}/complete:");
|
||||
for (String path : paths) assertTrue(yaml.contains(path), path);
|
||||
assertEquals(19, paths.size());
|
||||
assertEquals(28, paths.size());
|
||||
assertTrue(yaml.contains("enum: [LOCATION, PALLET]"));
|
||||
assertTrue(yaml.contains("enum: [APPROVE, REWORK]"));
|
||||
assertTrue(yaml.contains("enum: [DAMAGED, MISSING_LABEL, LABEL_MISMATCH, UNREADABLE, OTHER]"));
|
||||
for (String field : SERVER_OWNED) assertFalse(yaml.contains(field + ":"), field);
|
||||
for (String excluded : List.of("/outbound", "/dispatch", "/delivery")) {
|
||||
assertFalse(yaml.contains(excluded), excluded);
|
||||
}
|
||||
assertFalse(yaml.contains("/api/pda/v1/last-leg/delivery"));
|
||||
}
|
||||
|
||||
private static void assertNoServerOwnedFields(Class<?> type) {
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package com.baiyue.lastleg.pda;
|
||||
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.delivery.controller.OutboundPdaController;
|
||||
import com.baiyue.lastleg.delivery.dto.DeliveryRequests;
|
||||
import com.baiyue.lastleg.delivery.dto.DeliveryResponses;
|
||||
import com.baiyue.lastleg.delivery.service.DeliveryTransferService;
|
||||
import com.baiyue.lastleg.dispatch.pda.controller.DispatchPdaController;
|
||||
import com.baiyue.lastleg.dispatch.pda.dto.DispatchPdaRequests;
|
||||
import com.baiyue.lastleg.dispatch.pda.service.DispatchPdaWorkflowService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
class PdaOutboundDispatchContractTest {
|
||||
private static final String SECURITY =
|
||||
"hasAuthority('lastleg:pda:operate') and hasAuthority('ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR')";
|
||||
|
||||
@Test
|
||||
void controllersRequirePdaRoleAndNeverAcceptCustomerOrWarehouseScope() {
|
||||
assertEquals(SECURITY, DispatchPdaController.class.getAnnotation(PreAuthorize.class).value());
|
||||
assertEquals(SECURITY, OutboundPdaController.class.getAnnotation(PreAuthorize.class).value());
|
||||
for (Class<?> controller : Set.of(DispatchPdaController.class, OutboundPdaController.class)) {
|
||||
for (Method method : controller.getDeclaredMethods()) {
|
||||
assertTrue(Arrays.stream(method.getParameters()).noneMatch(parameter -> {
|
||||
RequestParam query = parameter.getAnnotation(RequestParam.class);
|
||||
return query != null && Set.of("customerId", "warehouseId")
|
||||
.contains(query.name().isBlank() ? query.value() : query.name());
|
||||
}));
|
||||
}
|
||||
}
|
||||
assertTrue(Arrays.stream(DispatchPdaRequests.Pick.class.getRecordComponents())
|
||||
.noneMatch(component -> "warehouseId".equals(component.getName()) || "customerId".equals(component.getName())));
|
||||
assertTrue(Arrays.stream(DeliveryRequests.PdaPick.class.getRecordComponents())
|
||||
.noneMatch(component -> "warehouseId".equals(component.getName()) || "customerId".equals(component.getName())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void controllersPassOnlyTokenBoundWarehouseToServices() {
|
||||
DispatchPdaWorkflowService dispatchService = mock(DispatchPdaWorkflowService.class);
|
||||
DeliveryTransferService outboundService = mock(DeliveryTransferService.class);
|
||||
DispatchPdaController dispatch = new DispatchPdaController();
|
||||
OutboundPdaController outbound = new OutboundPdaController();
|
||||
ReflectionTestUtils.setField(dispatch, "service", dispatchService);
|
||||
ReflectionTestUtils.setField(outbound, "service", outboundService);
|
||||
AuthenticatedUser user = pda(Set.of("lastleg:pda:operate", "ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR"), 900L);
|
||||
|
||||
dispatch.list(user, null);
|
||||
outbound.list(user, null);
|
||||
|
||||
verify(dispatchService).list("900", null);
|
||||
verify(outboundService).pdaTasks("900", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingRolePermissionOrWarehouseBindingIsRejected() {
|
||||
DispatchPdaController controller = new DispatchPdaController();
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> controller.list(pda(Set.of("lastleg:pda:operate"), 900L), null));
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> controller.list(pda(Set.of("ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR"), 900L), null));
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> controller.list(pda(Set.of("lastleg:pda:operate", "ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR"), null), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void pdaOpenApiContainsOnlyFrozenDispatchAndOutboundWorkflow() throws Exception {
|
||||
String yaml = Files.readString(Path.of("src/main/resources/openapi/overseas-pda-operations-v1.yaml"),
|
||||
StandardCharsets.UTF_8);
|
||||
assertTrue(yaml.contains("/api/pda/v1/last-leg/dispatches:"));
|
||||
assertTrue(yaml.contains("/api/pda/v1/last-leg/dispatches/{dispatchNo}/depart:"));
|
||||
assertTrue(yaml.contains("/api/pda/v1/last-leg/outbound-tasks/{taskNo}/complete:"));
|
||||
assertFalse(yaml.contains("name: customerId"));
|
||||
assertFalse(yaml.contains("name: warehouseId"));
|
||||
assertFalse(yaml.contains("/api/pda/v1/last-leg/delivery"));
|
||||
assertTrue(yaml.contains("inventoryPositionId:"));
|
||||
assertTrue(yaml.contains("cartonMark:"));
|
||||
assertTrue(yaml.contains("availablePackages:"));
|
||||
assertTrue(yaml.contains("pickedPackages:"));
|
||||
assertEquals(Set.of("inventoryPositionId", "palletNo", "cartonMark", "skuCode", "inboundCode",
|
||||
"availablePackages", "pickedPackages"),
|
||||
Arrays.stream(DeliveryResponses.PdaPickPosition.class.getRecordComponents())
|
||||
.map(component -> component.getName()).collect(java.util.stream.Collectors.toSet()));
|
||||
assertEquals(Set.of("idempotencyKey"),
|
||||
Arrays.stream(DeliveryRequests.PdaComplete.class.getRecordComponents())
|
||||
.map(component -> component.getName()).collect(java.util.stream.Collectors.toSet()));
|
||||
}
|
||||
|
||||
private static AuthenticatedUser pda(Set<String> permissions, Long warehouseId) {
|
||||
return new AuthenticatedUser(7L, 0L, 0L, 8L, "picker", "PLATFORM", "PDA", permissions,
|
||||
false, null, null, false, warehouseId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user