Merge branch 'test' into dev
This commit is contained in:
+49
@@ -0,0 +1,49 @@
|
||||
package com.baiyue.order.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.dto.PendingReviewOrderDtos;
|
||||
import com.baiyue.order.service.PendingReviewOrderQueryService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/** Firstleg 智能装柜读取尚未审核订单的内部入口。 */
|
||||
@RestController
|
||||
@RequestMapping("/internal/order/v1/pending-review-orders")
|
||||
public class InternalPendingReviewOrderController {
|
||||
@Resource private PendingReviewOrderQueryService service;
|
||||
@Value("${baiyue.security.internal-service-token}") private String configuredToken;
|
||||
private byte[] expectedToken;
|
||||
|
||||
@PostConstruct
|
||||
void initializeToken() {
|
||||
expectedToken = configuredToken.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ApiResponse<PageResult<PendingReviewOrderDtos.Row>> page(
|
||||
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||
@Valid @ModelAttribute PendingReviewOrderDtos.Query query) {
|
||||
requireToken(token);
|
||||
return ApiResponse.success(service.page(query));
|
||||
}
|
||||
|
||||
private void requireToken(String token) {
|
||||
byte[] supplied = token == null ? new byte[0] : token.getBytes(StandardCharsets.UTF_8);
|
||||
if (!MessageDigest.isEqual(expectedToken, supplied)) {
|
||||
throw new BizException(ResultCode.FORBIDDEN, "内部服务凭证无效");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.baiyue.order.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/** Order 向履约服务提供的待审核订单权威只读契约。 */
|
||||
public final class PendingReviewOrderDtos {
|
||||
private PendingReviewOrderDtos() {
|
||||
}
|
||||
|
||||
public record Query(
|
||||
List<@Size(max = 64) String> channelCodes,
|
||||
@Min(1) Long warehouseId,
|
||||
@Min(1) Long customerId,
|
||||
@Size(max = 40) String inboundCode,
|
||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate createdStart,
|
||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate createdEnd,
|
||||
@Min(1) long page,
|
||||
@Min(1) @Max(200) long size
|
||||
) {
|
||||
@AssertTrue(message = "创建日期起始日不能晚于结束日")
|
||||
public boolean isCreatedRangeValid() {
|
||||
return createdStart == null || createdEnd == null || !createdStart.isAfter(createdEnd);
|
||||
}
|
||||
}
|
||||
|
||||
public record Row(
|
||||
@Schema(type = "string", pattern = "^[1-9][0-9]*$") Long orderId,
|
||||
String orderNo,
|
||||
String inboundCode,
|
||||
@Schema(type = "string", pattern = "^[1-9][0-9]*$") Long customerId,
|
||||
String customerName,
|
||||
@Schema(type = "string", pattern = "^[1-9][0-9]*$") Long warehouseId,
|
||||
String channelCode,
|
||||
String channelName,
|
||||
int totalPackageCount,
|
||||
LocalDateTime createdAt,
|
||||
String mainStatus
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -212,6 +212,26 @@ public class OrderRepository {
|
||||
return PageResult.from(orderMapper.selectPage(new Page<>(query.page(), query.size()), wrapper));
|
||||
}
|
||||
|
||||
/** Order 权威待审核页;只允许查询未删除的 SUBMITTED 头程订单。 */
|
||||
public PageResult<OrderEntity> pendingReviewPage(List<String> channelCodes, Long warehouseId,
|
||||
Long customerId, String inboundCode,
|
||||
LocalDateTime createdFrom,
|
||||
LocalDateTime createdBefore,
|
||||
long page, long size) {
|
||||
LambdaQueryWrapper<OrderEntity> wrapper = new LambdaQueryWrapper<OrderEntity>()
|
||||
.eq(OrderEntity::getDeleted, false)
|
||||
.eq(OrderEntity::getStatus, OrderStatus.SUBMITTED)
|
||||
.in(channelCodes != null && !channelCodes.isEmpty(), OrderEntity::getChannelCode, channelCodes)
|
||||
.eq(warehouseId != null, OrderEntity::getReceivingWarehouseId, warehouseId)
|
||||
.eq(customerId != null, OrderEntity::getCustomerId, customerId)
|
||||
.eq(StringUtils.hasText(inboundCode), OrderEntity::getInboundCode, inboundCode)
|
||||
.ge(createdFrom != null, OrderEntity::getCreatedAt, createdFrom)
|
||||
.lt(createdBefore != null, OrderEntity::getCreatedAt, createdBefore)
|
||||
.orderByDesc(OrderEntity::getCreatedAt)
|
||||
.orderByDesc(OrderEntity::getId);
|
||||
return PageResult.from(orderMapper.selectPage(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
public PageResult<OrderEntity> merchantInboundPage(long tenantId, MerchantInboundOrderQuery query) {
|
||||
com.baiyue.order.entity.OrderStatus effectiveStatus = query.operationStatus() == null
|
||||
? query.status() : query.operationStatus();
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.baiyue.order.service;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.dto.PendingReviewOrderDtos;
|
||||
import com.baiyue.order.entity.OrderCargoEntity;
|
||||
import com.baiyue.order.repository.OrderRepository;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** 为 Firstleg 智能装柜提供 Order 权威待审核订单页。 */
|
||||
@Service
|
||||
public class PendingReviewOrderQueryService {
|
||||
private static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai");
|
||||
@Resource private OrderRepository orders;
|
||||
|
||||
public PageResult<PendingReviewOrderDtos.Row> page(PendingReviewOrderDtos.Query query) {
|
||||
if (query == null || query.page() < 1 || query.size() < 1 || query.size() > 200
|
||||
|| !query.isCreatedRangeValid()) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "待审核订单查询参数不正确");
|
||||
}
|
||||
List<String> channelCodes = normalizeChannelCodes(query.channelCodes());
|
||||
LocalDateTime createdFrom = query.createdStart() == null ? null
|
||||
: query.createdStart().atStartOfDay(BUSINESS_ZONE).toLocalDateTime();
|
||||
LocalDateTime createdBefore = query.createdEnd() == null ? null
|
||||
: query.createdEnd().plusDays(1).atStartOfDay(BUSINESS_ZONE).toLocalDateTime();
|
||||
var source = orders.pendingReviewPage(channelCodes, query.warehouseId(), query.customerId(),
|
||||
normalize(query.inboundCode()), createdFrom, createdBefore, query.page(), query.size());
|
||||
List<Long> orderIds = source.records().stream().map(order -> order.getId()).toList();
|
||||
Map<Long, Integer> packageCounts = orders.findCargoByOrderIds(null, orderIds).stream()
|
||||
.collect(Collectors.groupingBy(OrderCargoEntity::getOrderId,
|
||||
Collectors.summingInt(cargo -> cargo.getPackageCount() == null ? 0 : cargo.getPackageCount())));
|
||||
var rows = source.records().stream().map(order -> new PendingReviewOrderDtos.Row(
|
||||
order.getId(), order.getOrderNo(), order.getInboundCode(), order.getCustomerId(),
|
||||
order.getCustomerName(), order.getReceivingWarehouseId(), order.getChannelCode(),
|
||||
order.getChannelName(), packageCounts.getOrDefault(order.getId(), 0), order.getCreatedAt(),
|
||||
"PENDING_REVIEW")).toList();
|
||||
return new PageResult<>(rows, source.page(), source.size(), source.total(), source.pages());
|
||||
}
|
||||
|
||||
private static List<String> normalizeChannelCodes(List<String> values) {
|
||||
if (values == null || values.isEmpty()) return List.of();
|
||||
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
||||
for (String value : values) {
|
||||
if (!StringUtils.hasText(value) || value.trim().length() > 64) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "渠道编码不能为空且不能超过64个字符");
|
||||
}
|
||||
normalized.add(value.trim());
|
||||
}
|
||||
return List.copyOf(normalized);
|
||||
}
|
||||
|
||||
private static String normalize(String value) {
|
||||
return StringUtils.hasText(value) ? value.trim() : null;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,34 @@ info:
|
||||
security:
|
||||
- bearerAuth: []
|
||||
paths:
|
||||
/internal/order/v1/pending-review-orders:
|
||||
get:
|
||||
security: []
|
||||
summary: Firstleg 分页读取 Order 权威待审核订单
|
||||
description: >-
|
||||
仅接受内部服务令牌。只返回 ord_order 中未删除且 status=SUBMITTED 的头程订单,
|
||||
mainStatus 固定为 PENDING_REVIEW。createdStart/createdEnd 按 Asia/Shanghai 自然日闭区间过滤
|
||||
ord_order.created_at,稳定按 created_at DESC、id DESC 分页;不读取或修复 Firstleg 投影。
|
||||
parameters:
|
||||
- name: X-Internal-Service-Token
|
||||
in: header
|
||||
required: true
|
||||
schema: {type: string}
|
||||
- {name: channelCodes, in: query, required: false, style: form, explode: true, schema: {type: array, items: {type: string, maxLength: 64}}}
|
||||
- {name: warehouseId, in: query, required: false, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: customerId, in: query, required: false, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: inboundCode, in: query, required: false, schema: {type: string, maxLength: 40}}
|
||||
- {name: createdStart, in: query, required: false, schema: {type: string, format: date}}
|
||||
- {name: createdEnd, in: query, required: false, schema: {type: string, format: date}}
|
||||
- {name: page, in: query, required: true, schema: {type: integer, format: int64, minimum: 1}}
|
||||
- {name: size, in: query, required: true, schema: {type: integer, format: int64, minimum: 1, maximum: 200}}
|
||||
responses:
|
||||
'200':
|
||||
description: Order 权威待审核订单页
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/PendingReviewOrderPageEnvelope'}
|
||||
'403': {description: 内部服务令牌无效}
|
||||
/internal/exports/v1/DOMESTIC_WAREHOUSE_ORDER_LIST/batches:
|
||||
post:
|
||||
security: []
|
||||
@@ -1001,6 +1029,35 @@ components:
|
||||
description: 前端外层行标识;同一批次内必须唯一,用于幂等重试和结果关联
|
||||
draft:
|
||||
$ref: '#/components/schemas/FirstLegOrderDraft'
|
||||
PendingReviewOrderPageEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
code: {type: string, example: '200'}
|
||||
message: {type: string}
|
||||
data:
|
||||
type: object
|
||||
required: [records, page, size, total, pages]
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/PendingReviewOrderRow'}}
|
||||
page: {type: integer, format: int64, minimum: 1}
|
||||
size: {type: integer, format: int64, minimum: 1}
|
||||
total: {type: integer, format: int64, minimum: 0}
|
||||
pages: {type: integer, format: int64, minimum: 0}
|
||||
PendingReviewOrderRow:
|
||||
type: object
|
||||
required: [orderId, orderNo, inboundCode, customerId, customerName, warehouseId, channelCode, channelName, totalPackageCount, createdAt, mainStatus]
|
||||
properties:
|
||||
orderId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
orderNo: {type: string}
|
||||
inboundCode: {type: string}
|
||||
customerId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
customerName: {type: string}
|
||||
warehouseId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
channelCode: {type: string}
|
||||
channelName: {type: string}
|
||||
totalPackageCount: {type: integer, minimum: 0}
|
||||
createdAt: {type: string, format: date-time}
|
||||
mainStatus: {type: string, enum: [PENDING_REVIEW]}
|
||||
FirstLegBatchDraftResponse:
|
||||
type: object
|
||||
required: [total, succeeded, failed, items]
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.baiyue.order.controller;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.dto.PendingReviewOrderDtos;
|
||||
import com.baiyue.order.service.PendingReviewOrderQueryService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
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.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(InternalPendingReviewOrderController.class)
|
||||
@TestPropertySource(properties = "baiyue.security.internal-service-token=0123456789abcdef0123456789abcdef")
|
||||
class InternalPendingReviewOrderControllerTest {
|
||||
@MockBean private PendingReviewOrderQueryService service;
|
||||
@Resource private InternalPendingReviewOrderController controller;
|
||||
|
||||
@Test
|
||||
void acceptsOnlyTheConfiguredInternalServiceToken() {
|
||||
var query = new PendingReviewOrderDtos.Query(List.of("SEA-US"), null, null, null, null, null, 1, 20);
|
||||
var page = new PageResult<PendingReviewOrderDtos.Row>(List.of(), 1, 20, 0, 0);
|
||||
when(service.page(query)).thenReturn(page);
|
||||
|
||||
assertThatThrownBy(() -> controller.page(null, query)).isInstanceOf(BizException.class);
|
||||
assertThatThrownBy(() -> controller.page("wrong", query)).isInstanceOf(BizException.class);
|
||||
assertThat(controller.page("0123456789abcdef0123456789abcdef", query).data()).isSameAs(page);
|
||||
verify(service).page(query);
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.baiyue.order.controller;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PendingReviewOrderOpenApiContractTest {
|
||||
@Test
|
||||
void documentsInternalPendingReviewPageAndStringIds() throws Exception {
|
||||
String yaml = Files.readString(Path.of("src/main/resources/openapi/order-v1.yaml"));
|
||||
assertThat(yaml)
|
||||
.contains("/internal/order/v1/pending-review-orders:")
|
||||
.contains("channelCodes")
|
||||
.contains("createdStart")
|
||||
.contains("createdEnd")
|
||||
.contains("PendingReviewOrderRow:")
|
||||
.contains("mainStatus: {type: string, enum: [PENDING_REVIEW]}")
|
||||
.contains("orderId: {type: string, pattern: '^[1-9][0-9]*$'}")
|
||||
.contains("warehouseId: {type: string, pattern: '^[1-9][0-9]*$'}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.baiyue.order.repository;
|
||||
|
||||
import com.baiyue.order.entity.OrderEntity;
|
||||
import com.baiyue.order.mapper.*;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(OrderRepository.class)
|
||||
class PendingReviewOrderRepositoryTest {
|
||||
@MockBean private OrderMapper orderMapper;
|
||||
@MockBean private OrderCargoMapper cargoMapper;
|
||||
@MockBean private OrderPartyMapper partyMapper;
|
||||
@MockBean private OrderInternalNoteMapper noteMapper;
|
||||
@MockBean private OrderStatusHistoryMapper historyMapper;
|
||||
@MockBean private OutboxEventMapper outboxMapper;
|
||||
@MockBean private OrderChildPurgeMapper childPurgeMapper;
|
||||
@MockBean private OrderIdempotencyRecordMapper idempotencyMapper;
|
||||
@MockBean private InboundCodeSequenceMapper inboundCodeSequenceMapper;
|
||||
@Resource private OrderRepository repository;
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
void buildsSubmittedOnlyStablePageWithEverySupportedFilter() throws Exception {
|
||||
when(orderMapper.selectPage(any(Page.class), any(Wrapper.class))).thenReturn(new Page<>());
|
||||
repository.pendingReviewPage(List.of("SEA-US", "AIR-US"), 11L, 22L, "RK-1",
|
||||
LocalDateTime.of(2026, 9, 1, 0, 0), LocalDateTime.of(2026, 9, 4, 0, 0), 3, 40);
|
||||
|
||||
ArgumentCaptor<Page<OrderEntity>> page = ArgumentCaptor.forClass(Page.class);
|
||||
ArgumentCaptor<Wrapper<OrderEntity>> wrapper = ArgumentCaptor.forClass(Wrapper.class);
|
||||
verify(orderMapper).selectPage(page.capture(), wrapper.capture());
|
||||
assertThat(page.getValue().getCurrent()).isEqualTo(3);
|
||||
assertThat(page.getValue().getSize()).isEqualTo(40);
|
||||
assertThat(wrapper.getValue().getExpression().getNormal()).hasSizeGreaterThanOrEqualTo(15);
|
||||
assertThat(wrapper.getValue().getExpression().getOrderBy()).hasSize(2);
|
||||
String source = Files.readString(Path.of("src/main/java/com/baiyue/order/repository/OrderRepository.java"));
|
||||
assertThat(source)
|
||||
.contains(".eq(OrderEntity::getDeleted, false)")
|
||||
.contains(".eq(OrderEntity::getStatus, OrderStatus.SUBMITTED)")
|
||||
.contains(".in(channelCodes != null && !channelCodes.isEmpty(), OrderEntity::getChannelCode, channelCodes)")
|
||||
.contains(".lt(createdBefore != null, OrderEntity::getCreatedAt, createdBefore)")
|
||||
.contains(".orderByDesc(OrderEntity::getCreatedAt)")
|
||||
.contains(".orderByDesc(OrderEntity::getId)");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.baiyue.order.service;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.dto.PendingReviewOrderDtos;
|
||||
import com.baiyue.order.entity.OrderCargoEntity;
|
||||
import com.baiyue.order.entity.OrderEntity;
|
||||
import com.baiyue.order.repository.OrderRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
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.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class PendingReviewOrderQueryServiceTest {
|
||||
private final OrderRepository repository = mock(OrderRepository.class);
|
||||
private PendingReviewOrderQueryService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new PendingReviewOrderQueryService();
|
||||
ReflectionTestUtils.setField(service, "orders", repository);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertsShanghaiNaturalDatesToClosedDayRangeAndNormalizesFilters() {
|
||||
when(repository.pendingReviewPage(any(), any(), any(), any(), any(), any(), anyLong(), anyLong()))
|
||||
.thenReturn(new PageResult<>(List.of(), 2, 20, 0, 0));
|
||||
|
||||
service.page(new PendingReviewOrderDtos.Query(List.of(" SEA-US ", "SEA-US"), 11L, 22L,
|
||||
" RK-1 ", LocalDate.of(2026, 9, 1), LocalDate.of(2026, 9, 3), 2, 20));
|
||||
|
||||
@SuppressWarnings("unchecked") ArgumentCaptor<List<String>> channels = ArgumentCaptor.forClass(List.class);
|
||||
verify(repository).pendingReviewPage(channels.capture(), eq(11L), eq(22L), eq("RK-1"),
|
||||
eq(LocalDateTime.of(2026, 9, 1, 0, 0)),
|
||||
eq(LocalDateTime.of(2026, 9, 4, 0, 0)), eq(2L), eq(20L));
|
||||
assertThat(channels.getValue()).containsExactly("SEA-US");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsAuthoritativeOrderFieldsAndSumsPackageCounts() {
|
||||
OrderEntity order = new OrderEntity();
|
||||
order.setId(101L); order.setOrderNo("FL101"); order.setInboundCode("RK101");
|
||||
order.setCustomerId(22L); order.setCustomerName("测试客户"); order.setReceivingWarehouseId(33L);
|
||||
order.setChannelCode("SEA-US"); order.setChannelName("美线");
|
||||
order.setCreatedAt(LocalDateTime.of(2026, 9, 3, 10, 30));
|
||||
OrderCargoEntity first = cargo(101L, 2);
|
||||
OrderCargoEntity second = cargo(101L, 3);
|
||||
when(repository.pendingReviewPage(any(), any(), any(), any(), any(), any(), anyLong(), anyLong()))
|
||||
.thenReturn(new PageResult<>(List.of(order), 1, 20, 1, 1));
|
||||
when(repository.findCargoByOrderIds(null, List.of(101L))).thenReturn(List.of(first, second));
|
||||
|
||||
var result = service.page(new PendingReviewOrderDtos.Query(null, null, null, " ", null, null, 1, 20));
|
||||
|
||||
assertThat(result.records()).singleElement().satisfies(row -> {
|
||||
assertThat(row.orderId()).isEqualTo(101L);
|
||||
assertThat(row.warehouseId()).isEqualTo(33L);
|
||||
assertThat(row.totalPackageCount()).isEqualTo(5);
|
||||
assertThat(row.mainStatus()).isEqualTo("PENDING_REVIEW");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsReversedDatesAndBlankChannelValues() {
|
||||
assertThatThrownBy(() -> service.page(new PendingReviewOrderDtos.Query(null, null, null, null,
|
||||
LocalDate.of(2026, 9, 4), LocalDate.of(2026, 9, 3), 1, 20))).isInstanceOf(BizException.class);
|
||||
assertThatThrownBy(() -> service.page(new PendingReviewOrderDtos.Query(List.of(" "), null, null,
|
||||
null, null, null, 1, 20))).isInstanceOf(BizException.class);
|
||||
}
|
||||
|
||||
private static OrderCargoEntity cargo(long orderId, int packageCount) {
|
||||
OrderCargoEntity cargo = new OrderCargoEntity();
|
||||
cargo.setOrderId(orderId); cargo.setPackageCount(packageCount);
|
||||
return cargo;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user