feat(file): register domestic order exports
This commit is contained in:
+60
@@ -0,0 +1,60 @@
|
||||
package com.baiyue.file.config;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class DomesticWarehouseOrderExportContractTest {
|
||||
private static final String TYPE = "DOMESTIC_WAREHOUSE_ORDER_LIST";
|
||||
|
||||
@Test void applicationAndNacosRegisterTheSameOrderProvider() throws Exception {
|
||||
for (String file : List.of("file/src/main/resources/application.yml",
|
||||
"config/nacos/local/file-service.yml", "config/nacos/cn/file-service.yml")) {
|
||||
String source = Files.readString(repositoryRoot().resolve(file));
|
||||
assertThat(source).contains(TYPE + ":")
|
||||
.contains("provider-service: order-service")
|
||||
.contains("provider-path: /internal/exports/v1/" + TYPE + "/batches")
|
||||
.contains("required-permission: platform:order:export")
|
||||
.contains("app-scope: PLATFORM");
|
||||
}
|
||||
}
|
||||
|
||||
@Test void fileOpenApiFreezesSelectionPrecedenceFiltersAndBusinessColumns() throws Exception {
|
||||
String source = Files.readString(repositoryRoot().resolve(
|
||||
"file/src/main/resources/openapi/domestic-order-export-v1.yaml"));
|
||||
Map<String, Object> document = map(new Yaml().load(source));
|
||||
Map<String, Object> schemas = map(map(document.get("components")).get("schemas"));
|
||||
Map<String, Object> parameters = map(map(schemas.get("DomesticOrderExportParameters")).get("properties"));
|
||||
Map<String, Object> columns = map(map(schemas.get("DomesticOrderExportColumns")).get("properties"));
|
||||
|
||||
assertThat(parameters).containsKeys("selectedOrderNos", "tenantId", "keyword", "orderNo", "mainStatus",
|
||||
"customerId", "receivingWarehouseId", "destinationWarehouseId", "inboundCode",
|
||||
"internalOrderStatus", "expectedArrivalDate", "feeReviewStatus", "channelName", "containerNo",
|
||||
"cabinetNo", "sailingDate", "loaded", "fullContainer", "measurementReviewStatus", "fbaCode",
|
||||
"createdFrom", "createdTo").doesNotContainKeys("page", "size", "orderId");
|
||||
assertThat(columns.keySet()).containsExactly("inboundCode", "orderNo", "mainStatus", "customerName",
|
||||
"channelName", "channelChanged", "receivingWarehouseName", "destinationWarehouseName",
|
||||
"expectedShipDate", "expectedArrivalAt", "expectedVolumeCbm", "totalPackageCount", "totalQuantity",
|
||||
"actualGrossWeightKg", "actualVolumeCbm", "chargeableWeightKg", "chargeableVolumeCbm",
|
||||
"feeReviewStatus", "skuNos", "taxMode", "containerMode", "customsInspection", "containerNo",
|
||||
"cabinetNo", "vesselName", "voyageNo", "createdAt");
|
||||
assertThat(columns).containsKeys("expectedVolumeCbm", "expectedArrivalAt")
|
||||
.doesNotContainKeys("orderId", "tenantId", "customerId", "inboundId", "receivingWarehouseId",
|
||||
"destinationWarehouseId");
|
||||
assertThat(source).contains("platform:order:export", "selectedOrderNos 非空时优先", "no-store");
|
||||
}
|
||||
|
||||
private static Path repositoryRoot() {
|
||||
Path current = Path.of("").toAbsolutePath();
|
||||
return Files.isDirectory(current.resolve("file")) ? current : current.getParent();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, Object> map(Object value) { return (Map<String, Object>) value; }
|
||||
}
|
||||
@@ -18,10 +18,13 @@ import jakarta.annotation.Resource;
|
||||
import com.baiyue.file.config.ExportDefinitionRegistry;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -112,6 +115,62 @@ class ExportTaskServiceTest {
|
||||
.getResultCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void domesticOrderExportAcceptsSelectedBusinessNumbersAndTheCompleteFilterSnapshot() throws Exception {
|
||||
var definition = definition();
|
||||
definition.setProviderService("order-service");
|
||||
definition.setProviderPath("/internal/exports/v1/DOMESTIC_WAREHOUSE_ORDER_LIST/batches");
|
||||
definition.setRequiredPermission("platform:order:export");
|
||||
when(registry.require(ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST)).thenReturn(definition);
|
||||
when(states.createConstrained(any(FileExportTask.class))).thenAnswer(invocation ->
|
||||
new ExportStateService.CreationResult(invocation.getArgument(0), true));
|
||||
var user = user(1L, Set.of("platform:order:export"));
|
||||
List<String> selected = IntStream.range(0, 5000).mapToObj(index -> "ORD-" + index).toList();
|
||||
|
||||
var selectedResponse = service.create(user, new CreateExportTaskRequest(
|
||||
ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST, "XLSX", "国内仓订单", Map.of(
|
||||
"selectedOrderNos", selected)));
|
||||
|
||||
assertEquals(ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST, selectedResponse.exportType());
|
||||
var filters = new LinkedHashMap<String, Object>();
|
||||
filters.put("tenantId", "10001"); filters.put("keyword", "订单"); filters.put("orderNo", "ORD-1");
|
||||
filters.put("mainStatus", "WAIT_MEASURE"); filters.put("customerId", "10001");
|
||||
filters.put("receivingWarehouseId", "11"); filters.put("destinationWarehouseId", "12");
|
||||
filters.put("inboundCode", "IN-1"); filters.put("internalOrderStatus", "APPROVED");
|
||||
filters.put("expectedArrivalDate", "2026-09-01"); filters.put("feeReviewStatus", "PENDING");
|
||||
filters.put("channelName", "海运"); filters.put("containerNo", "CONT-1");
|
||||
filters.put("cabinetNo", "CAB-1"); filters.put("sailingDate", "2026-09-02");
|
||||
filters.put("loaded", false); filters.put("fullContainer", true);
|
||||
filters.put("measurementReviewStatus", "APPROVED"); filters.put("fbaCode", "FBA-1");
|
||||
filters.put("createdFrom", "2026-08-01T00:00:00"); filters.put("createdTo", "2026-09-01T23:59:59");
|
||||
|
||||
service.create(user, new CreateExportTaskRequest(
|
||||
ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST, "XLSX", "国内仓订单", filters));
|
||||
|
||||
var tasks = org.mockito.ArgumentCaptor.forClass(FileExportTask.class);
|
||||
verify(states, org.mockito.Mockito.times(2)).createConstrained(tasks.capture());
|
||||
Map<?, ?> selectedSnapshot = new ObjectMapper().readValue(tasks.getAllValues().get(0).getParametersJson(), Map.class);
|
||||
Map<?, ?> filterSnapshot = new ObjectMapper().readValue(tasks.getAllValues().get(1).getParametersJson(), Map.class);
|
||||
assertEquals(5000, ((List<?>) selectedSnapshot.get("selectedOrderNos")).size());
|
||||
assertEquals(filters, filterSnapshot);
|
||||
}
|
||||
|
||||
@Test
|
||||
void domesticOrderExportRequiresItsDedicatedPermission() {
|
||||
var definition = definition();
|
||||
definition.setProviderService("order-service");
|
||||
definition.setProviderPath("/internal/exports/v1/DOMESTIC_WAREHOUSE_ORDER_LIST/batches");
|
||||
definition.setRequiredPermission("platform:order:export");
|
||||
when(registry.require(ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST)).thenReturn(definition);
|
||||
|
||||
BizException denied = assertThrows(BizException.class, () -> service.create(user(1L, Set.of("platform:order:list")),
|
||||
new CreateExportTaskRequest(ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST,
|
||||
"XLSX", "国内仓订单", Map.of())));
|
||||
|
||||
assertEquals(ResultCode.FORBIDDEN, denied.getResultCode());
|
||||
assertTrue(denied.getMessage().contains("权限"));
|
||||
}
|
||||
|
||||
private AuthenticatedUser user(long id, Set<String> permissions) {
|
||||
return new AuthenticatedUser(id, 0L, 0L, id, "user" + id, "PLATFORM", "WEB", permissions);
|
||||
}
|
||||
|
||||
@@ -136,6 +136,58 @@ class GenericXlsxExportRunnerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test void domesticOrderProviderMustReturnTheFrozenBusinessColumnsWithoutInternalIds() throws Exception {
|
||||
List<ExportColumn> invalid = ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_COLUMNS.stream()
|
||||
.filter(column -> !"expectedVolumeCbm".equals(column.key()))
|
||||
.map(column -> new ExportColumn(column.key(), column.title(), column.type(), 18)).toList();
|
||||
var batch = new ExportBatchResponse(1, "sha256:domestic-orders", "snapshot-orders",
|
||||
invalid, List.of(), null, false, 0L);
|
||||
when(provider.batch(anyString(), eq(ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST), any(), any()))
|
||||
.thenReturn(ApiResponse.success(batch));
|
||||
FileExportTask task = domesticOrderTask(61L, Map.of());
|
||||
var definition = new ExportDefinitionRegistry.Definition(); definition.setMaxRows(200000); definition.setBatchSize(500);
|
||||
|
||||
assertThrows(ExportFailure.class,
|
||||
() -> runner.run(task, definition, new AtomicBoolean(), ignored -> { }));
|
||||
}
|
||||
|
||||
@Test void domesticOrderColumnsGenerateWorkbookAndPassTheSelectionSnapshotToOrder() throws Exception {
|
||||
List<ExportColumn> columns = ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_COLUMNS.stream()
|
||||
.map(column -> new ExportColumn(column.key(), column.title(), column.type(), 18)).toList();
|
||||
Map<String, Object> row = new java.util.LinkedHashMap<>();
|
||||
row.put("inboundCode", "IN-1"); row.put("orderNo", "ORD-1");
|
||||
row.put("expectedVolumeCbm", "1.25"); row.put("expectedArrivalAt", "2026-09-03T12:30:00");
|
||||
var batch = new ExportBatchResponse(1, "sha256:domestic-orders", "snapshot-orders",
|
||||
columns, List.of(row), null, false, 1L);
|
||||
when(provider.batch(anyString(), eq(ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST), any(), any()))
|
||||
.thenReturn(ApiResponse.success(batch));
|
||||
Map<String, Object> parameters = Map.of("selectedOrderNos", List.of("ORD-1", "ORD-2"));
|
||||
FileExportTask task = domesticOrderTask(62L, parameters);
|
||||
var definition = new ExportDefinitionRegistry.Definition(); definition.setMaxRows(200000); definition.setBatchSize(500);
|
||||
|
||||
var result = runner.run(task, definition, new AtomicBoolean(), ignored -> { });
|
||||
|
||||
try (var workbook = new XSSFWorkbook(storage.load(result.objectKey()).getInputStream())) {
|
||||
var sheet = workbook.getSheetAt(0);
|
||||
assertEquals("订单号", sheet.getRow(0).getCell(1).getStringCellValue());
|
||||
assertEquals("预计到货时间", sheet.getRow(0).getCell(9).getStringCellValue());
|
||||
assertEquals("预计体积(m³)", sheet.getRow(0).getCell(10).getStringCellValue());
|
||||
assertEquals(1.25d, sheet.getRow(1).getCell(10).getNumericCellValue());
|
||||
}
|
||||
ArgumentCaptor<ExportBatchRequest> request = ArgumentCaptor.forClass(ExportBatchRequest.class);
|
||||
verify(provider).batch(anyString(), eq(ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST),
|
||||
eq(definition), request.capture());
|
||||
assertEquals(parameters, request.getValue().parameters());
|
||||
}
|
||||
|
||||
private FileExportTask domesticOrderTask(long id, Map<String, Object> parameters) throws Exception {
|
||||
FileExportTask task = new FileExportTask(); task.setId(id); task.setTenantId(0L);
|
||||
task.setAppCode("PLATFORM"); task.setRequestedBy(7L); task.setDispatchVersion(1);
|
||||
task.setExportType(ExportSchemaContracts.DOMESTIC_WAREHOUSE_ORDER_LIST); task.setTaskName("国内仓订单");
|
||||
task.setParametersJson(new ObjectMapper().writeValueAsString(parameters));
|
||||
return task;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestConfig {
|
||||
@Bean ObjectMapper objectMapper() { return new ObjectMapper(); }
|
||||
|
||||
Reference in New Issue
Block a user