feat(selfop): provide frozen turnover batches for backend Excel exports
This commit is contained in:
@@ -13,6 +13,7 @@ class LastlegExportDefinitionContractTest {
|
||||
Map<?, ?> nacos = definitions(Path.of("../config/nacos/test/file-service.yml"));
|
||||
Map<String, String> expected = Map.ofEntries(
|
||||
Map.entry("LAST_MILE_ORDER_LIST", "platform:overseas-warehouse:last-mile-order:export"),
|
||||
Map.entry("SELFOP_INVENTORY_TURNOVER", "platform:self-operated-analytics:export"),
|
||||
Map.entry("OVERSEAS_INVENTORY_BALANCE", "platform:overseas-warehouse:inventory:export"),
|
||||
Map.entry("OVERSEAS_INVENTORY_LEDGER", "platform:overseas-warehouse:inventory:export"),
|
||||
Map.entry("OVERSEAS_QUOTE_LIST", "platform:overseas-master-data:quote:export"),
|
||||
@@ -28,7 +29,7 @@ class LastlegExportDefinitionContractTest {
|
||||
assertEquals("/internal/exports/v1/" + entry.getKey() + "/batches", definition.get("provider-path"));
|
||||
assertEquals(entry.getValue(), definition.get("required-permission"));
|
||||
assertEquals("PLATFORM", definition.get("app-scope"));
|
||||
assertEquals(200, definition.get("batch-size"));
|
||||
assertEquals(entry.getKey().equals("SELFOP_INVENTORY_TURNOVER") ? 100 : 200, definition.get("batch-size"));
|
||||
var controlled = new ExportDefinitionRegistry.Definition();
|
||||
controlled.setProviderService("lastleg-service");
|
||||
controlled.setProviderPath(String.valueOf(definition.get("provider-path")));
|
||||
|
||||
@@ -39,6 +39,23 @@ class ExportTaskServiceTest {
|
||||
@MockBean private ExportStateService states;
|
||||
@MockBean private ExportMetrics metrics;
|
||||
@Resource private ExportTaskService service;
|
||||
@Test void turnoverKeepsBoundedSignedContextAndRequiresIndependentExportPermission() {
|
||||
var definition=definition();definition.setRequiredPermission("platform:self-operated-analytics:export");
|
||||
when(registry.require("SELFOP_INVENTORY_TURNOVER")).thenReturn(definition);
|
||||
when(states.createConstrained(any(FileExportTask.class))).thenAnswer(c->new ExportStateService.CreationResult(c.getArgument(0),true));
|
||||
Map<String,Object> parameters=new LinkedHashMap<>();
|
||||
parameters.put("sourceAccount","demo");parameters.put("warehouseCode","W");parameters.put("endDate","2026-10-14");parameters.put("baseWindowDays",30);
|
||||
parameters.put("snapshotContext","x".repeat(15000));parameters.put("columns",List.of("sku","quantityTurnoverRate"));parameters.put("expectedTotal",205);
|
||||
var request=new CreateExportTaskRequest("SELFOP_INVENTORY_TURNOVER","XLSX","库存周转",parameters);
|
||||
assertThrows(BizException.class,()->service.create(user(1L,Set.of("platform:self-operated-analytics:list")),request));
|
||||
assertEquals("PENDING",service.create(user(1L,Set.of("platform:self-operated-analytics:export")),request).status());
|
||||
parameters.put("snapshotContext","x".repeat(16001));
|
||||
assertThrows(BizException.class,()->service.create(user(1L,Set.of("platform:self-operated-analytics:export")),request));
|
||||
parameters.put("snapshotContext","fixed");parameters.put("current",2);
|
||||
assertThrows(BizException.class,()->service.create(user(1L,Set.of("platform:self-operated-analytics:export")),request));
|
||||
parameters.remove("current");parameters.remove("columns");
|
||||
assertThrows(BizException.class,()->service.create(user(1L,Set.of("platform:self-operated-analytics:export")),request));
|
||||
}
|
||||
@Test
|
||||
void createsPersistedTaskOnlyWhenSourceExportPermissionIsPresent() {
|
||||
when(registry.require("CUSTOMER_LIST")).thenReturn(definition());
|
||||
@@ -94,6 +111,15 @@ class ExportTaskServiceTest {
|
||||
assertEquals("9", service.get(user(1L, Set.of("platform:download:all")), 9L).id());
|
||||
}
|
||||
|
||||
@Test void turnoverDownloadAndRetryRecheckExportPermissionEvenWithDownloadAll() {
|
||||
var task=new FileExportTask();task.setId(9L);task.setTenantId(0L);task.setAppCode("PLATFORM");task.setRequestedBy(2L);
|
||||
task.setExportType("SELFOP_INVENTORY_TURNOVER");task.setStatus("SUCCEEDED");when(repository.find(9L)).thenReturn(task);
|
||||
var reader=user(1L,Set.of("platform:download:all","platform:self-operated-analytics:list"));
|
||||
assertEquals(ResultCode.FORBIDDEN,assertThrows(BizException.class,()->service.download(reader,9L)).getResultCode());
|
||||
assertEquals(ResultCode.FORBIDDEN,assertThrows(BizException.class,()->service.retry(reader,9L)).getResultCode());
|
||||
verifyNoInteractions(storage);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsParametersDeeperThanTwoLevels() {
|
||||
when(registry.require("CUSTOMER_LIST")).thenReturn(definition());
|
||||
|
||||
@@ -66,6 +66,24 @@ class GenericXlsxExportRunnerTest {
|
||||
assertNull(requests.getAllValues().get(0).snapshotToken());assertEquals("snapshot-9",requests.getAllValues().get(1).snapshotToken());
|
||||
}
|
||||
|
||||
@Test void turnoverWorkbookPreservesColumnOrderPercentUnknownAndLiteralSku() throws Exception {
|
||||
var columns=List.of(new ExportColumn("quantityTurnoverRate","期间周转率",ExportColumnType.STRING,24),
|
||||
new ExportColumn("sku","SKU",ExportColumnType.STRING,24),new ExportColumn("historyDays","合格历史库存天数",ExportColumnType.STRING,24));
|
||||
var batch=new ExportBatchResponse(1,"sha256:turnover","fixed",columns,List.of(
|
||||
Map.of("quantityTurnoverRate","125%","sku","=SUM(1,2)","historyDays","30/30"),
|
||||
Map.of("quantityTurnoverRate","—","sku","未知商品","historyDays","29/30"),
|
||||
Map.of("quantityTurnoverRate","0%","sku","零销量","historyDays","30/30")),"3",false,3L);
|
||||
when(provider.batch(anyString(),eq("SELFOP_INVENTORY_TURNOVER"),any(),any())).thenReturn(ApiResponse.success(batch));
|
||||
var task=new FileExportTask();task.setId(18L);task.setTenantId(0L);task.setAppCode("PLATFORM");task.setRequestedBy(7L);task.setDispatchVersion(1);
|
||||
task.setExportType("SELFOP_INVENTORY_TURNOVER");task.setTaskName("库存周转");task.setParametersJson("{\"snapshotContext\":\"fixed\"}");
|
||||
var definition=new ExportDefinitionRegistry.Definition();definition.setMaxRows(200000);definition.setBatchSize(100);
|
||||
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(0).getStringCellValue());
|
||||
assertEquals("125%",sheet.getRow(1).getCell(0).getStringCellValue());assertEquals("'=SUM(1,2)",sheet.getRow(1).getCell(1).getStringCellValue());
|
||||
assertEquals("—",sheet.getRow(2).getCell(0).getStringCellValue());assertEquals("0%",sheet.getRow(3).getCell(0).getStringCellValue());assertEquals(3,result.rows());
|
||||
}
|
||||
}
|
||||
@Test void deletesTheCompletedFileWhenReadingItsFinalSizeFails() throws Exception {
|
||||
var batch=new ExportBatchResponse(1,"sha256:test","snapshot-9",
|
||||
List.of(new ExportColumn("text","文本",ExportColumnType.STRING,18)),
|
||||
|
||||
Reference in New Issue
Block a user