优化
This commit is contained in:
+35
@@ -0,0 +1,35 @@
|
||||
package com.baiyue.lastleg.inventory.query;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class InboundCodeRelationshipOpenApiContractTest {
|
||||
|
||||
@Test
|
||||
void publishesPlatformRelationshipLookupWithoutClientCustomerScope() throws IOException {
|
||||
String yaml = Files.readString(Path.of("src/main/resources/openapi/overseas-business-v1.yaml"));
|
||||
String path = "/api/platform/v1/last-leg/inventory/inbound-code-relationships/{inboundCode}:";
|
||||
int start = yaml.indexOf(path);
|
||||
int end = yaml.indexOf("\n /", start + path.length());
|
||||
|
||||
assertThat(start).isGreaterThanOrEqualTo(0);
|
||||
String operation = yaml.substring(start, end > start ? end : yaml.length());
|
||||
assertThat(operation)
|
||||
.contains("name: inboundCode")
|
||||
.contains("$ref: '#/components/schemas/InboundCodeRelationshipApiResponse'")
|
||||
.doesNotContain("name: customerId");
|
||||
assertThat(yaml)
|
||||
.contains("InboundCodeRelationship:")
|
||||
.contains("overseasReceivingStatus:")
|
||||
.contains("taillegOrders:")
|
||||
.contains("inboundPlans:")
|
||||
.contains("orderStatus:")
|
||||
.contains("planStatus:")
|
||||
.contains("palletCodes:")
|
||||
.contains("inventory:");
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.baiyue.lastleg.inventory.query.controller;
|
||||
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.inventory.query.dto.InboundCodeRelationshipResponse;
|
||||
import com.baiyue.lastleg.inventory.query.service.InboundCodeRelationshipService;
|
||||
import com.baiyue.lastleg.security.OverseasPermissions;
|
||||
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.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class InboundCodeRelationshipControllerTest {
|
||||
@Mock InboundCodeRelationshipService service;
|
||||
private InboundCodeRelationshipController controller;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
controller = new InboundCodeRelationshipController();
|
||||
ReflectionTestUtils.setField(controller, "service", service);
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformReadsByInboundCodeWithoutSupplyingCustomerId() {
|
||||
InboundCodeRelationshipResponse response = new InboundCodeRelationshipResponse(
|
||||
"IN-1", false, null, null, null, List.of(), List.of(), List.of(), List.of());
|
||||
when(service.find("IN-1")).thenReturn(response);
|
||||
|
||||
var result = controller.find(platform(), "IN-1");
|
||||
|
||||
assertThat(result.data()).isSameAs(response);
|
||||
verify(service).find("IN-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void customerAccountCannotUsePlatformRelationshipReadModel() {
|
||||
AuthenticatedUser customer = new AuthenticatedUser(8L, 100L, 100L, 8L, "customer",
|
||||
"MERCHANT", "WEB", Set.of(OverseasPermissions.INVENTORY_LIST));
|
||||
|
||||
assertThatThrownBy(() -> controller.find(customer, "IN-1"))
|
||||
.isInstanceOf(ResponseStatusException.class).hasMessageContaining("403");
|
||||
verifyNoInteractions(service);
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingIdentityIsUnauthorized() {
|
||||
assertThatThrownBy(() -> controller.find(null, "IN-1"))
|
||||
.isInstanceOf(ResponseStatusException.class).hasMessageContaining("401");
|
||||
verifyNoInteractions(service);
|
||||
}
|
||||
|
||||
private static AuthenticatedUser platform() {
|
||||
return new AuthenticatedUser(7L, 0L, 0L, 8L, "admin", "PLATFORM", "WEB",
|
||||
Set.of(OverseasPermissions.INVENTORY_LIST));
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.baiyue.lastleg.inventory.query.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class InboundCodeRelationshipMapperContractTest {
|
||||
@Test
|
||||
void mapperIsExplicitlyScannableAndQueriesOnlyLastlegTables() throws Exception {
|
||||
assertThat(InboundCodeRelationshipMapper.class).hasAnnotation(Mapper.class);
|
||||
String sql = String.join(" ", InboundCodeRelationshipMapper.class
|
||||
.getMethod("bases", String.class).getAnnotation(Select.class).value());
|
||||
|
||||
assertThat(sql).contains("ll_order", "ll_inbound_plan", "ll_inventory_balance");
|
||||
assertThat(sql).doesNotContain("customerId}", "warehouse.", "iam.");
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package com.baiyue.lastleg.inventory.query.service;
|
||||
|
||||
import com.baiyue.lastleg.inventory.query.mapper.InboundCodeRelationshipMapper;
|
||||
import com.baiyue.lastleg.inventory.query.model.InboundCodeRelationshipRows;
|
||||
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.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class InboundCodeRelationshipServiceTest {
|
||||
@Mock InboundCodeRelationshipMapper mapper;
|
||||
private InboundCodeRelationshipService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new InboundCodeRelationshipService();
|
||||
ReflectionTestUtils.setField(service, "mapper", mapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingInboundCodeReturnsExplicitEmptyRelationship() {
|
||||
when(mapper.bases("NYEXX2608300001")).thenReturn(List.of());
|
||||
|
||||
var result = service.find(" NYEXX2608300001 ");
|
||||
|
||||
assertThat(result.found()).isFalse();
|
||||
assertThat(result.customer()).isNull();
|
||||
assertThat(result.taillegOrders()).isEmpty();
|
||||
assertThat(result.inboundPlans()).isEmpty();
|
||||
assertThat(result.palletCodes()).isEmpty();
|
||||
assertThat(result.inventory()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void relationshipUsesBusinessNumbersAndKeepsLongIdentifiersAsStrings() {
|
||||
InboundCodeRelationshipRows.Base row = base("2092618717861048321", "Customer A");
|
||||
when(mapper.bases("NYEXX2608300001")).thenReturn(List.of(row, row));
|
||||
when(mapper.palletCodes("2092618717861048321", "NYEXX2608300001"))
|
||||
.thenReturn(List.of("PAL-LAX-001"));
|
||||
InboundCodeRelationshipRows.InventorySku sku = new InboundCodeRelationshipRows.InventorySku();
|
||||
sku.setSkuCode("SKU-001"); sku.setProductNameZh("产品一"); sku.setPackageCount(40L);
|
||||
when(mapper.inventory("2092618717861048321", "NYEXX2608300001")).thenReturn(List.of(sku));
|
||||
|
||||
var result = service.find("NYEXX2608300001");
|
||||
|
||||
assertThat(result.found()).isTrue();
|
||||
assertThat(result.customer().customerId()).isEqualTo("2092618717861048321");
|
||||
assertThat(result.overseasWarehouse().warehouseId()).isEqualTo("193000000000200003");
|
||||
assertThat(result.taillegOrders()).extracting("orderNo").containsExactly("LMO-260830-0001");
|
||||
assertThat(result.taillegOrders()).extracting("orderStatus").containsExactly("INBOUND_PLANNED");
|
||||
assertThat(result.inboundPlans()).extracting("planNo").containsExactly("LIP-260830-0001");
|
||||
assertThat(result.inboundPlans()).extracting("planStatus").containsExactly("COMPLETED");
|
||||
assertThat(result.palletCodes()).containsExactly("PAL-LAX-001");
|
||||
assertThat(result.inventory()).extracting("skuCode", "packageCount")
|
||||
.containsExactly(org.assertj.core.groups.Tuple.tuple("SKU-001", 40L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sameInboundCodeAcrossCustomersIsRejectedBeforeScopedDetailQueries() {
|
||||
when(mapper.bases("DUPLICATE")).thenReturn(List.of(
|
||||
base("100", "Customer A"), base("200", "Customer B")));
|
||||
|
||||
assertThatThrownBy(() -> service.find("DUPLICATE"))
|
||||
.isInstanceOf(ResponseStatusException.class).hasMessageContaining("409");
|
||||
|
||||
verify(mapper, never()).palletCodes(anyString(), anyString());
|
||||
verify(mapper, never()).inventory(anyString(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void blankAndOversizedInboundCodesAreRejected() {
|
||||
assertThatThrownBy(() -> service.find(" ")).isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("400");
|
||||
assertThatThrownBy(() -> service.find("X".repeat(129))).isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("400");
|
||||
verifyNoInteractions(mapper);
|
||||
}
|
||||
|
||||
private static InboundCodeRelationshipRows.Base base(String customerId, String customerName) {
|
||||
InboundCodeRelationshipRows.Base value = new InboundCodeRelationshipRows.Base();
|
||||
value.setCustomerId(customerId); value.setCustomerName(customerName);
|
||||
value.setOrderNo("LMO-260830-0001"); value.setOrderStatus("INBOUND_PLANNED");
|
||||
value.setPlanNo("LIP-260830-0001"); value.setPlanStatus("COMPLETED");
|
||||
value.setReceivingStatus("COMPLETED"); value.setOverseasWarehouseId("193000000000200003");
|
||||
value.setOverseasWarehouseCode("US-LAX-01"); value.setOverseasWarehouseName("洛杉矶一号仓");
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user