This commit is contained in:
2026-09-16 11:06:33 +08:00
parent a4c659f4c6
commit a098c4377c
46 changed files with 356 additions and 109 deletions
@@ -20,8 +20,15 @@ class InternalSupplierContactTest {
var supplier = mock(SupplierResource.class);
when(supplier.name()).thenReturn("Fleet"); when(supplier.email()).thenReturn("fleet@example.com");
when(service.detail(1L)).thenReturn(supplier);
when(service.internalSnapshot(1L,false,"TRUCKING")).thenReturn(
new com.baiyue.warehouse.dto.SupplierDtos.InternalSnapshot(1L,"Fleet","TRUCKING","ACTIVE",java.util.List.of(),"OVERSEAS"));
var result = controller.truckingContact("test-token",1L,false).data();
assertThat(result.email()).isEqualTo("fleet@example.com");
verify(service).internalSnapshot(1L,false,"TRUCKING");
when(service.internalSnapshot(2L,true,"TRUCKING")).thenReturn(
new com.baiyue.warehouse.dto.SupplierDtos.InternalSnapshot(2L,"Domestic","TRUCKING","ACTIVE",java.util.List.of(),"DOMESTIC"));
assertThatThrownBy(() -> controller.truckingContact("test-token",2L,true))
.isInstanceOf(BizException.class).hasMessageContaining("海外车队");
verify(service, never()).detail(2L);
}
}
@@ -14,7 +14,7 @@ class SupplierSqlContractTest {
String sql = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
assertThat(sql).contains("CREATE TABLE IF NOT EXISTS wh_supplier", "tenant_id BIGINT UNSIGNED NOT NULL DEFAULT 0",
"chk_wh_supplier_tenant CHECK (tenant_id = 0)",
"license_file_id VARCHAR(128)",
"license_file_id VARCHAR(128)", "trucking_scope VARCHAR(16)", "chk_wh_supplier_trucking_scope", "trucking_scope IS NOT NULL", "trucking_scope IS NULL", "DOMESTIC", "OVERSEAS",
"MONTHLY_30','MONTHLY_45','MONTHLY_60','MONTHLY_90','PER_TRANSACTION','IMMEDIATE",
"created_by BIGINT UNSIGNED", "updated_by BIGINT UNSIGNED",
"supplier_add_column_if_missing", "uk_wh_supplier_name", "idx_wh_supplier_filter",
@@ -23,7 +23,7 @@ class SupplierSqlContractTest {
String supplierTable = sql.substring(sql.indexOf("CREATE TABLE IF NOT EXISTS wh_supplier ("),
sql.indexOf("CREATE TABLE IF NOT EXISTS wh_supplier_carrier"));
assertThat(supplierTable).doesNotContain("carrier_code", "carrier_codes");
assertThat(sql).doesNotContain("scope VARCHAR", "chk_wh_supplier_scope", "DOMESTIC/INTERNATIONAL");
assertThat(sql).doesNotContain("\n scope VARCHAR", "chk_wh_supplier_scope", "DOMESTIC/INTERNATIONAL");
}
}
@@ -21,14 +21,16 @@ import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class SupplierImportExportServiceTest {
@Mock private SupplierService supplierService;
@Mock private com.baiyue.warehouse.repository.SupplierRepository repository;
@InjectMocks private SupplierImportExportService service;
private PageQuery query;
@BeforeEach void setUp() { query = new PageQuery(1, 20, "BOOKING", null, "ACTIVE", null, "MATSON"); }
@BeforeEach void setUp() { query = new PageQuery(1, 20, "BOOKING", null, "ACTIVE", null, "MATSON", null);
org.springframework.test.util.ReflectionTestUtils.setField(service, "validator", jakarta.validation.Validation.buildDefaultValidatorFactory().getValidator()); }
@Test void templateUsesMultiCarrierCodesColumn() throws Exception {
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(service.template()))) {
assertThat(workbook.getSheetAt(0).getRow(0).getCell(1).getStringCellValue()).isEqualTo("2");
assertThat(workbook.getSheetAt(0).getRow(0).getCell(1).getStringCellValue()).isEqualTo("3");
assertThat(workbook.getSheetAt(0).getRow(2).getCell(2).getStringCellValue()).isEqualTo("船司标准编码(多值)");
}
}
@@ -36,10 +38,49 @@ class SupplierImportExportServiceTest {
@Test void csvExportsCarrierCodesWithoutChangingPersistenceShape() {
SupplierResource resource = new SupplierResource(7L, 0L, "订舱代理", "BOOKING", List.of("MATSON", "ZIM"),
"宁波", "法人", "联系人", "13800000000", null, null, null, null, "ACTIVE", "MONTHLY_30", null,
null, null, null, null, false, 0);
when(supplierService.page(new PageQuery(1, 200, "BOOKING", null, "ACTIVE", null, "MATSON")))
null, null, null, null, false, 0, null);
when(supplierService.page(new PageQuery(1, 200, "BOOKING", null, "ACTIVE", null, "MATSON", null)))
.thenReturn(new PageResult<>(List.of(resource), 1, 200, 1, 1));
String csv = new String(service.exportCsv(query), StandardCharsets.UTF_8);
assertThat(csv).contains("船司标准编码", "\"MATSON|ZIM\"");
}
@Test void importRequiresScopeBeforeAnyRowIsWritten() throws Exception {
var invalid = service.importFile("suppliers.xlsx", truckingWorkbook(null, "OVERSEAS"));
assertThat(invalid.success()).isFalse();
assertThat(invalid.errors()).anySatisfy(error -> {
assertThat(error.row()).isEqualTo(4);
assertThat(error.field()).isEqualTo("truckingScope");
});
org.mockito.Mockito.verifyNoInteractions(supplierService);
var valid = service.importFile("suppliers.xlsx", truckingWorkbook("DOMESTIC", "OVERSEAS"));
assertThat(valid.success()).isTrue();
var captor = org.mockito.ArgumentCaptor.forClass(com.baiyue.warehouse.dto.SupplierDtos.SaveRequest.class);
org.mockito.Mockito.verify(supplierService, org.mockito.Mockito.times(2)).create(org.mockito.ArgumentMatchers.anyLong(), captor.capture());
assertThat(captor.getAllValues()).extracting(com.baiyue.warehouse.dto.SupplierDtos.SaveRequest::truckingScope)
.containsExactly("DOMESTIC", "OVERSEAS");
}
@Test void exportPreservesScopeFilterAndTypeColumn() {
var query = new PageQuery(1, 20, "TRUCKING", null, "ACTIVE", null, null, "OVERSEAS");
var resource = new SupplierResource(8L, 0L, "海外车队", "TRUCKING", List.of(),
"洛杉矶", "法人", "联系人", "13800000000", null, null, null, null, "ACTIVE", "MONTHLY_30", null,
null, null, null, null, false, 0, "OVERSEAS");
when(supplierService.page(new PageQuery(1, 200, "TRUCKING", null, "ACTIVE", null, null, "OVERSEAS")))
.thenReturn(new PageResult<>(List.of(resource), 1, 200, 1, 1));
assertThat(new String(service.exportCsv(query), StandardCharsets.UTF_8)).contains("拖车类型", "\"OVERSEAS\"");
}
private byte[] truckingWorkbook(String... scopes) throws Exception {
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(service.template()));
var output = new java.io.ByteArrayOutputStream()) {
for (int i = 0; i < scopes.length; i++) {
var row = workbook.getSheetAt(0).createRow(3 + i);
String[] values = {"车队" + i, "TRUCKING", "", "宁波", "法人", "联系人", "13800000000", "", "", "", "", "ACTIVE", "MONTHLY_30", "", scopes[i]};
for (int c = 0; c < values.length; c++) if (values[c] != null) row.createCell(c).setCellValue(values[c]);
}
workbook.write(output);
return output.toByteArray();
}
}
}
@@ -29,7 +29,7 @@ class SupplierServiceTest {
@BeforeEach void setUp() {
booking = new SaveRequest("测试供应商", "BOOKING", java.util.List.of("MATSON"), "宁波", "法人", "联系人",
"13800000000", "supplier@example.com", "地址", "91330000TEST", "192000000000000001",
"ACTIVE", "MONTHLY_30", null);
"ACTIVE", "MONTHLY_30", null, null);
}
@Test void createsPlatformPublicBookingSupplier() {
@@ -42,26 +42,26 @@ class SupplierServiceTest {
@Test void deduplicatesBookingCarrierCodesAndRejectsNonBookingAssociations() {
SaveRequest duplicated = new SaveRequest("测试供应商", "BOOKING", java.util.List.of("MATSON", "MATSON", "ZIM"),
"宁波", "法人", "联系人", "13800000000", null, null, null, null,
"ACTIVE", "MONTHLY_30", null);
"ACTIVE", "MONTHLY_30", null, null);
service.create(102L, duplicated);
verify(repository).replaceCarrierCodes(eq(0L), eq(102L), eq(java.util.List.of("MATSON", "ZIM")), any());
SaveRequest customs = new SaveRequest("报关行", "CUSTOMS", java.util.List.of("MATSON"), "宁波", "法人",
"联系人", "13800000000", null, null, null, null, "ACTIVE", "MONTHLY_30", null);
"联系人", "13800000000", null, null, null, null, "ACTIVE", "MONTHLY_30", null, null);
assertThatThrownBy(() -> service.create(103L, customs)).isInstanceOf(BizException.class)
.hasMessageContaining("非BOOKING");
}
@Test void bookingRequiresAtLeastOneCarrierCode() {
SaveRequest empty = new SaveRequest("测试供应商", "BOOKING", java.util.List.of(), "宁波", "法人", "联系人",
"13800000000", null, null, null, null, "ACTIVE", "MONTHLY_30", null);
"13800000000", null, null, null, null, "ACTIVE", "MONTHLY_30", null, null);
assertThatThrownBy(() -> service.create(104L, empty)).isInstanceOf(BizException.class)
.hasMessageContaining("至少关联一个");
}
@Test void nonBookingMayOmitCarrierCodes() {
SaveRequest customs = new SaveRequest("报关行", "CUSTOMS", null, "宁波", "法人", "联系人",
"13800000000", null, null, null, null, "ACTIVE", "MONTHLY_30", null);
"13800000000", null, null, null, null, "ACTIVE", "MONTHLY_30", null, null);
service.create(105L, customs);
verify(repository).replaceCarrierCodes(eq(0L), eq(105L), eq(java.util.List.of()), any());
}
@@ -105,4 +105,42 @@ class SupplierServiceTest {
assertThatThrownBy(() -> service.internalSnapshot(101L, true, "CUSTOMS"))
.isInstanceOf(BizException.class).hasMessageContaining("类别不匹配");
}
@Test void truckingRequiresExactlyOneScopeAndNonTruckingRejectsScope() {
for (String scope : new String[] {null, "", "BOTH", "DOMESTIC,OVERSEAS"}) {
assertThatThrownBy(() -> service.create(201L, trucking(scope)))
.isInstanceOf(BizException.class).hasMessageContaining("国内拖车或海外车队");
}
assertThatThrownBy(() -> SupplierService.validateTruckingScope("BOOKING", "DOMESTIC"))
.isInstanceOf(BizException.class).hasMessageContaining("非拖车");
verify(repository, never()).insert(any());
}
@Test void persistsScopeAndReturnsItInResourcesAndInternalSnapshot() {
for (String scope : java.util.List.of("DOMESTIC", "OVERSEAS")) {
long id = "DOMESTIC".equals(scope) ? 201L : 202L;
service.create(id, trucking(scope));
var captor = org.mockito.ArgumentCaptor.forClass(SupplierEntity.class);
verify(repository, org.mockito.Mockito.atLeastOnce()).insert(captor.capture());
var entity = captor.getValue();
assertThat(entity.getTruckingScope()).isEqualTo(scope);
when(repository.find(0L, id)).thenReturn(entity);
assertThat(service.detail(id).truckingScope()).isEqualTo(scope);
assertThat(service.internalSnapshot(id, true, "TRUCKING").truckingScope()).isEqualTo(scope);
}
}
@Test void changingCategoryClearsTruckingScope() {
SupplierEntity entity = new SupplierEntity(); entity.setId(201L); entity.setTenantId(0L);
entity.setCategory("TRUCKING"); entity.setTruckingScope("DOMESTIC");
when(repository.find(0L, 201L)).thenReturn(entity);
service.update(201L, booking);
assertThat(entity.getTruckingScope()).isNull();
verify(repository).save(entity);
}
private SaveRequest trucking(String scope) {
return new SaveRequest("车队", "TRUCKING", java.util.List.of(), "宁波", "法人", "联系人",
"13800000000", null, null, null, null, "ACTIVE", "MONTHLY_30", null, scope);
}
}