提交
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package com.baiyue.order.dto;
|
||||
|
||||
import jakarta.validation.constraints.Size;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** 页签统计独立接收筛选条件,避免未传分页时基本类型构造绑定失败。 */
|
||||
public record UnifiedOrderStatusCountQuery(
|
||||
@Size(max = 64) String keyword,
|
||||
@Size(max = 64) String orderNo,
|
||||
Long customerId,
|
||||
Long receivingWarehouseId,
|
||||
Long destinationWarehouseId,
|
||||
@Size(max = 64) String inboundCode,
|
||||
@Size(max = 32) String internalOrderStatus,
|
||||
LocalDate expectedArrivalDate,
|
||||
@Size(max = 32) String feeReviewStatus,
|
||||
@Size(max = 128) String channelName,
|
||||
@Size(max = 64) String containerNo,
|
||||
@Size(max = 64) String cabinetNo,
|
||||
LocalDate sailingDate,
|
||||
Boolean loaded,
|
||||
Boolean fullContainer,
|
||||
@Size(max = 32) String measurementReviewStatus,
|
||||
@Size(max = 64) String fbaCode,
|
||||
LocalDateTime createdFrom,
|
||||
LocalDateTime createdTo,
|
||||
@Schema(allowableValues = {"TAX_REFUND", "BUY_DECLARATION"})
|
||||
@Pattern(regexp = "TAX_REFUND|BUY_DECLARATION") String taxMode
|
||||
) {
|
||||
/** 复用列表查询条件,统计不受当前页签和分页影响。 */
|
||||
public UnifiedOrderQuery toOrderQuery() {
|
||||
return new UnifiedOrderQuery(keyword, orderNo, null, customerId, receivingWarehouseId,
|
||||
destinationWarehouseId, inboundCode, internalOrderStatus, expectedArrivalDate,
|
||||
feeReviewStatus, channelName, containerNo, cabinetNo, sailingDate, loaded, fullContainer,
|
||||
measurementReviewStatus, fbaCode, createdFrom, createdTo, 1, 200, taxMode);
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package com.baiyue.order.controller;
|
||||
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.order.dto.UnifiedOrderQuery;
|
||||
import com.baiyue.order.service.UnifiedOrderQueryService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
class UnifiedOrderStatusCountBindingTest {
|
||||
private UnifiedOrderQueryService service;
|
||||
private MockMvc mvc;
|
||||
|
||||
/** 使用真实 MVC 构造绑定,复现浏览器不传分页的调用。 */
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
service = mock(UnifiedOrderQueryService.class);
|
||||
when(service.statusCounts(any(), any())).thenReturn(
|
||||
new UnifiedOrderQueryService.StatusCounts(Map.of("WAIT_WEIGHT_CONFIRM", 125L, "SIGNED", 0L)));
|
||||
var controller = new PlatformUnifiedOrderController();
|
||||
ReflectionTestUtils.setField(controller, "service", service);
|
||||
mvc = MockMvcBuilders.standaloneSetup(controller).setCustomArgumentResolvers(new HandlerMethodArgumentResolver() {
|
||||
/** 仅为测试注入已认证的平台身份。 */
|
||||
public boolean supportsParameter(MethodParameter p) { return p.getParameterType() == AuthenticatedUser.class; }
|
||||
/** 保持平台作用域守卫正常执行。 */
|
||||
public Object resolveArgument(MethodParameter p, ModelAndViewContainer c, NativeWebRequest r, WebDataBinderFactory f) {
|
||||
return new AuthenticatedUser(1L, 0L, null, 1L, "operator", "PLATFORM", "WEB", Set.of("platform:order:list"));
|
||||
}
|
||||
}).build();
|
||||
}
|
||||
|
||||
/** 不传分页时正常返回,并保留零数量。 */
|
||||
@Test
|
||||
void acceptsRequestWithoutPagination() throws Exception {
|
||||
mvc.perform(get("/api/platform/v1/orders/status-counts"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data.counts.WAIT_WEIGHT_CONFIRM").value(125))
|
||||
.andExpect(jsonPath("$.data.counts.SIGNED").value(0));
|
||||
var query = org.mockito.ArgumentCaptor.forClass(UnifiedOrderQuery.class);
|
||||
verify(service).statusCounts(isNull(), query.capture());
|
||||
assertThat(query.getValue().mainStatus()).isNull();
|
||||
}
|
||||
|
||||
/** 筛选值完整保留,外部附带的页签和分页不会缩小统计范围。 */
|
||||
@Test
|
||||
void preservesFiltersAndIgnoresPaginationAndStatus() throws Exception {
|
||||
mvc.perform(get("/api/platform/v1/orders/status-counts")
|
||||
.param("tenantId", "11").param("customerId", "11").param("loaded", "false")
|
||||
.param("fullContainer", "false").param("taxMode", "TAX_REFUND")
|
||||
.param("fbaCode", "FBA123").param("measurementReviewStatus", "APPROVED")
|
||||
.param("createdFrom", "2026-10-01T00:00:00")
|
||||
.param("mainStatus", "LOADED").param("page", "null").param("size", "null"))
|
||||
.andExpect(status().isOk());
|
||||
var captured = org.mockito.ArgumentCaptor.forClass(UnifiedOrderQuery.class);
|
||||
verify(service).statusCounts(eq(11L), captured.capture());
|
||||
var query = captured.getValue();
|
||||
assertThat(query.customerId()).isEqualTo(11L);
|
||||
assertThat(query.loaded()).isFalse();
|
||||
assertThat(query.fullContainer()).isFalse();
|
||||
assertThat(query.taxMode()).isEqualTo("TAX_REFUND");
|
||||
assertThat(query.fbaCode()).isEqualTo("FBA123");
|
||||
assertThat(query.measurementReviewStatus()).isEqualTo("APPROVED");
|
||||
assertThat(query.createdFrom()).isEqualTo(LocalDateTime.of(2026, 10, 1, 0, 0));
|
||||
assertThat(query.mainStatus()).isNull();
|
||||
assertThat(query.page()).isEqualTo(1);
|
||||
assertThat(query.size()).isEqualTo(200);
|
||||
}
|
||||
|
||||
/** 独立统计对象仍执行原有筛选值校验。 */
|
||||
@Test
|
||||
void rejectsInvalidFilter() throws Exception {
|
||||
mvc.perform(get("/api/platform/v1/orders/status-counts").param("taxMode", "INVALID"))
|
||||
.andExpect(status().isBadRequest());
|
||||
verifyNoInteractions(service);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user