fix(order): load all warehouse template options

This commit is contained in:
2026-09-03 17:04:57 +08:00
parent 3664f036cc
commit 253ca82b99
2 changed files with 102 additions and 8 deletions
@@ -34,6 +34,7 @@ import java.util.function.Function;
@Service
public class MerchantBatchImportService {
private static final int MAX_ROWS = 50;
private static final int WAREHOUSE_PAGE_SIZE = 200;
private static final long MAX_BYTES = 5L * 1024 * 1024;
@Resource private MerchantBatchDraftService drafts;
@Resource private OrderBatchFileClient files;
@@ -216,14 +217,7 @@ public class MerchantBatchImportService {
private Catalog catalog(long tenantId, String authorization) {
if (!StringUtils.hasText(authorization)) throw new BizException(ResultCode.UNAUTHORIZED, "登录凭证缺失");
try {
var warehouseResponse = warehouses.page(authorization, 1, 200, "ACTIVE");
if (warehouseResponse == null || !warehouseResponse.successful() || warehouseResponse.data() == null) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项暂不可用");
}
List<MerchantWarehouseCatalogClient.Warehouse> allWarehouses = warehouseResponse.data().records();
if (warehouseResponse.data().pages() > 1) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "可用仓库超过模板支持范围,请联系平台处理");
}
List<MerchantWarehouseCatalogClient.Warehouse> allWarehouses = activeWarehouses(authorization);
var receiving = optionMap(allWarehouses.stream().filter(value -> "DOMESTIC".equals(value.warehouseType())).toList(),
value -> label(value.warehouseName(), value.warehouseCode()));
if (receiving.isEmpty()) throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "暂无可用国内收货仓");
@@ -255,6 +249,57 @@ public class MerchantBatchImportService {
}
}
private List<MerchantWarehouseCatalogClient.Warehouse> activeWarehouses(String authorization) {
Map<Long, MerchantWarehouseCatalogClient.Warehouse> unique = new LinkedHashMap<>();
Long expectedTotal = null;
Long expectedPages = null;
long fetchedRows = 0;
for (long requestedPage = 1; ; requestedPage++) {
var response = warehouses.page(authorization, requestedPage, WAREHOUSE_PAGE_SIZE, "ACTIVE");
if (response == null || !response.successful() || response.data() == null) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项第" + requestedPage + "页暂不可用");
}
var page = response.data();
if (page.page() != requestedPage || page.size() != WAREHOUSE_PAGE_SIZE) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项分页响应异常");
}
long calculatedPages = page.total() == 0 ? 0 : ((page.total() - 1) / page.size()) + 1;
if (page.pages() != calculatedPages) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项分页统计异常");
}
if (expectedTotal == null) {
expectedTotal = page.total();
expectedPages = page.pages();
} else if (expectedTotal != page.total() || expectedPages != page.pages()) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项分页数据发生变化,请重试");
}
if (requestedPage > Math.max(1L, expectedPages)) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项分页响应异常");
}
List<MerchantWarehouseCatalogClient.Warehouse> records = page.records();
if (expectedPages > 0 && records.isEmpty()) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项分页数据不完整");
}
fetchedRows += records.size();
for (var warehouse : records) {
if (warehouse == null || warehouse.id() == null || warehouse.id() <= 0
|| !"ACTIVE".equals(warehouse.status())) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项数据异常");
}
var previous = unique.putIfAbsent(warehouse.id(), warehouse);
if (previous != null && !previous.equals(warehouse)) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项分页数据发生变化,请重试");
}
}
if (requestedPage >= expectedPages) {
if (fetchedRows != expectedTotal) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓库选项分页数据不完整");
}
return List.copyOf(unique.values());
}
}
}
private static Map<String, CustomerAddressDtos.Response> addressOptions(List<CustomerAddressDtos.Response> values) {
return optionMap(values, value -> String.join("|", value.addressName(), value.contactName(), value.city(), value.addressLine()));
}
@@ -13,10 +13,13 @@ import org.springframework.test.util.ReflectionTestUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class MerchantBatchImportServiceTest {
@@ -86,6 +89,52 @@ class MerchantBatchImportServiceTest {
}
}
@Test
void templateReadsEveryActiveWarehousePageWithoutApplyingBusinessLimit() throws Exception {
List<MerchantWarehouseCatalogClient.Warehouse> firstPage = new ArrayList<>();
for (long id = 1000; id < 1200; id++) {
firstPage.add(new MerchantWarehouseCatalogClient.Warehouse(id, "US-" + id, "海外仓" + id,
"OVERSEAS", "US", "ACTIVE"));
}
var lastWarehouse = new MerchantWarehouseCatalogClient.Warehouse(21L, "CN-YW", "义乌收货仓",
"DOMESTIC", "CN", "ACTIVE");
when(warehouses.page("Bearer test", 1, 200, "ACTIVE"))
.thenReturn(ApiResponse.success(new PageResult<>(firstPage, 1, 200, 201, 2)));
when(warehouses.page("Bearer test", 2, 200, "ACTIVE"))
.thenReturn(ApiResponse.success(new PageResult<>(List.of(lastWarehouse), 2, 200, 201, 2)));
byte[] content = service.template(88L, "Bearer test");
try (var workbook = new XSSFWorkbook(new ByteArrayInputStream(content))) {
var options = workbook.getSheet("选项数据");
assertThat(hasCellValue(options, "海外仓1000|US-1000")).isTrue();
assertThat(hasCellValue(options, "海外仓1199|US-1199")).isTrue();
assertThat(hasCellValue(options, "义乌收货仓|CN-YW")).isTrue();
}
verify(warehouses).page("Bearer test", 2, 200, "ACTIVE");
}
@Test
void templateFailsClosedWhenLaterWarehousePageCannotBeRead() {
List<MerchantWarehouseCatalogClient.Warehouse> firstPage = new ArrayList<>();
for (long id = 1000; id < 1200; id++) {
firstPage.add(new MerchantWarehouseCatalogClient.Warehouse(id, "US-" + id, "海外仓" + id,
"OVERSEAS", "US", "ACTIVE"));
}
when(warehouses.page("Bearer test", 1, 200, "ACTIVE"))
.thenReturn(ApiResponse.success(new PageResult<>(firstPage, 1, 200, 201, 2)));
when(warehouses.page("Bearer test", 2, 200, "ACTIVE")).thenReturn(null);
assertThatThrownBy(() -> service.template(88L, "Bearer test"))
.isInstanceOf(com.baiyue.common.core.exception.BizException.class)
.hasMessage("仓库选项第2页暂不可用");
}
private static boolean hasCellValue(org.apache.poi.ss.usermodel.Sheet sheet, String expected) {
for (var row : sheet) for (var cell : row) if (expected.equals(cell.getStringCellValue())) return true;
return false;
}
private static CustomerAddressDtos.Response address(long id, String name, String type) {
return new CustomerAddressDtos.Response(id, type, name, "测试公司", "张三", "13800000000", null,
"CN", "广东", "深圳", "南山", "科技园1号", "518000", true);