fix(lastleg): filter domestic first-leg orders by sailing stage

This commit is contained in:
2026-10-08 15:12:47 +08:00
parent 136a2bc3b5
commit 27a89a6ff3
8 changed files with 112 additions and 10 deletions
@@ -38,11 +38,11 @@ class LastlegOrderControllerTest {
private final LastlegOrderCommandService commandService = mock(LastlegOrderCommandService.class);
private final LastlegOrderController controller = controller();
private final LastlegOrderRequests.Query query = new LastlegOrderRequests.Query(
1L, 20L, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
1L, 20L, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
@Test
void orderQueryHasOneResolvableConstructorForRequestParameterBinding() {
assertEquals(16, BeanUtils.getResolvableConstructor(LastlegOrderRequests.Query.class).getParameterCount());
assertEquals(17, BeanUtils.getResolvableConstructor(LastlegOrderRequests.Query.class).getParameterCount());
}
@Test
@@ -138,7 +138,7 @@ class LastlegOrderControllerTest {
void platformOperatorCanExportAllCustomersWithoutFilters() {
byte[] csv = "all customers".getBytes(java.nio.charset.StandardCharsets.UTF_8);
LastlegOrderRequests.Query emptyQuery = new LastlegOrderRequests.Query(
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
when(service.exportCsv(null, emptyQuery)).thenReturn(csv);
var response = controller.export(user(0L, "PLATFORM"), null, emptyQuery);
@@ -18,7 +18,7 @@ class MerchantLastlegOrderControllerTest {
private final LastlegOrderService service = mock(LastlegOrderService.class);
private final MerchantLastlegOrderController controller = controller();
private final LastlegOrderRequests.Query query = new LastlegOrderRequests.Query(
1L, 20L, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
1L, 20L, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
@Test
void merchantListUsesOnlyAuthenticatedTenant() {
@@ -0,0 +1,82 @@
package com.baiyue.lastleg.service;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baiyue.lastleg.dto.LastlegOrderRequests;
import com.baiyue.lastleg.dto.LastlegOrderRequests.SailingStage;
import com.baiyue.lastleg.entity.LastlegOrder;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import static org.junit.jupiter.api.Assertions.assertEquals;
class LastlegOrderSailingStageTest {
@Test
void filtersBeforePaginationByActualDepartureAndKeepsOtherTypesOnlyInAll() throws Exception {
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), "sailing-test"), LastlegOrder.class);
try (var db = DriverManager.getConnection("jdbc:h2:mem:sailing;MODE=MySQL")) {
var sql = db.createStatement();
sql.execute("CREATE TABLE ll_order (id BIGINT, customer_id VARCHAR, order_type VARCHAR, source_region VARCHAR, " +
"source_container_booking_id VARCHAR, manual_node_override BOOLEAN, current_status VARCHAR)");
sql.execute("CREATE TABLE ll_container_shipping_gate (container_booking_id VARCHAR, node_sequence INT, actual_at TIMESTAMP)");
sql.execute("CREATE TABLE ll_order_manual_node (order_id BIGINT, customer_id VARCHAR, node_code VARCHAR, node_at TIMESTAMP)");
sql.execute("INSERT INTO ll_container_shipping_gate VALUES ('loaded',30,CURRENT_TIMESTAMP)," +
"('departed',40,CURRENT_TIMESTAMP),('arrived',60,CURRENT_TIMESTAMP),('estimated',40,NULL)");
sql.execute("INSERT INTO ll_order VALUES " +
"(1,'A','FIRST_LEG','FIRSTLEG',NULL,NULL,'PENDING_ASSIGNMENT')," +
"(2,'A','FIRST_LEG','FIRSTLEG','loaded',FALSE,'INBOUND_PLANNED')," +
"(3,'A','FIRST_LEG','FIRSTLEG','departed',FALSE,'PENDING_ASSIGNMENT')," +
"(4,'A','FIRST_LEG','FIRSTLEG','arrived',FALSE,'INBOUND_COMPLETED')," +
"(5,'A','FIRST_LEG','FIRSTLEG','estimated',FALSE,'PENDING_ASSIGNMENT')," +
"(6,'A','FIRST_LEG','FIRSTLEG','arrived',TRUE,'PENDING_ASSIGNMENT')," +
"(7,'A','FIRST_LEG','FIRSTLEG','loaded',TRUE,'PENDING_ASSIGNMENT')," +
"(8,'B','FIRST_LEG','FIRSTLEG','departed',FALSE,'PENDING_ASSIGNMENT')," +
"(9,'A','FIRST_LEG','CUSTOMER','departed',FALSE,'PENDING_ASSIGNMENT')");
sql.execute("INSERT INTO ll_order_manual_node VALUES (6,'A','ESTIMATED_DEPARTURE',CURRENT_TIMESTAMP)," +
"(6,'A','ACTUAL_DEPARTURE',NULL),(6,'B','ACTUAL_DEPARTURE',CURRENT_TIMESTAMP)," +
"(7,'A','ACTUAL_DEPARTURE',CURRENT_TIMESTAMP)");
int id = 10;
for (String type : List.of("ONE_CLICK_DROPSHIP", "RELABEL_APPLICATION", "WAREHOUSE_TRANSFER",
"LOCAL_LOOSEBOARD", "RETURN_RELABEL", "CARGO_DISCARD")) {
try (var insert = db.prepareStatement("INSERT INTO ll_order VALUES (?,'A',?,'FIRSTLEG','departed',FALSE,'PENDING_ASSIGNMENT')")) {
insert.setInt(1, id++); insert.setString(2, type); insert.executeUpdate();
}
}
assertEquals(List.of(1L, 2L, 5L, 6L), find(db, null, SailingStage.BEFORE_DEPARTURE, null));
assertEquals(List.of(3L, 4L, 7L, 8L), find(db, null, SailingStage.AFTER_DEPARTURE, null));
assertEquals(List.of(3L, 4L, 7L), find(db, "A", SailingStage.AFTER_DEPARTURE, null));
assertEquals(List.of(3L, 7L), find(db, "A", SailingStage.AFTER_DEPARTURE, "PENDING_ASSIGNMENT"));
assertEquals(15, find(db, null, null, null).size());
}
}
private List<Long> find(java.sql.Connection db, String customerId, SailingStage stage, String status) throws Exception {
var query = new LastlegOrderRequests.Query(1L, 20L, null, null, null, null, null, null,
status, null, null, null, null, null, null, null, stage);
LambdaQueryWrapper<LastlegOrder> filter = ReflectionTestUtils.invokeMethod(
new LastlegOrderService(), "filter", customerId, query);
String where = filter.getSqlSegment();
var matcher = Pattern.compile("#\\{ew.paramNameValuePairs.([^}]+)}").matcher(where);
List<Object> parameters = new ArrayList<>();
StringBuilder boundSql = new StringBuilder();
while (matcher.find()) {
parameters.add(filter.getParamNameValuePairs().get(matcher.group(1)));
matcher.appendReplacement(boundSql, "?");
}
matcher.appendTail(boundSql);
try (var statement = db.prepareStatement("SELECT id FROM ll_order" +
(where.isBlank() ? "" : " WHERE " + boundSql) + " ORDER BY id")) {
for (int i = 0; i < parameters.size(); i++) statement.setObject(i + 1, parameters.get(i));
List<Long> ids = new ArrayList<>();
try (var rows = statement.executeQuery()) { while (rows.next()) ids.add(rows.getLong(1)); }
return ids;
}
}
}
@@ -375,7 +375,7 @@ class LastlegOrderServiceTest {
@Test
void pageUsesPaginationAndPlatformFiltersWithoutCustomerScope() {
var query = new LastlegOrderRequests.Query(3L, 25L, "LL-", "FIRST_LEG", "IN-", null,
null, "", "PENDING_ASSIGNMENT", null, "LAX", null, null, null, null, null);
null, "", "PENDING_ASSIGNMENT", null, "LAX", null, null, null, null, null, null);
var resultPage = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<LastlegOrder>(3, 25);
resultPage.setTotal(0);
when(orders.selectPage(any(), any())).thenReturn(resultPage);
@@ -401,7 +401,7 @@ class LastlegOrderServiceTest {
String csv = new String(service.exportCsv(null, new LastlegOrderRequests.Query(
1L, 20L, null, null, null, null, null, null, null, null, null, null,
null, null, null, null)), StandardCharsets.UTF_8);
null, null, null, null, null)), StandardCharsets.UTF_8);
assertTrue(csv.contains("\"否\",\"是\""));
assertTrue(csv.contains("\"待分配\""));
@@ -553,7 +553,7 @@ class LastlegOrderServiceTest {
new LastlegOrderMapper.PalletMergeRelationRow(11L, "INBOUND-2", "PMG-1"),
new LastlegOrderMapper.PalletMergeRelationRow(11L, "INBOUND-3", "PMG-1")));
var query = new LastlegOrderRequests.Query(1L, 10L, null, null, null, null,
null, null, null, null, null, null, null, null, null, null);
null, null, null, null, null, null, null, null, null, null, null);
var result = service.page(null, query);
@@ -577,7 +577,7 @@ class LastlegOrderServiceTest {
resultPage.setTotal(3);
when(orders.selectPage(any(), any())).thenReturn(resultPage);
var query = new LastlegOrderRequests.Query(1L, 10L, null, null, null, null,
null, null, null, null, null, null, null, null, null, null);
null, null, null, null, null, null, null, null, null, null, null);
var result = service.page(null, query);
@@ -609,7 +609,7 @@ class LastlegOrderServiceTest {
when(orders.selectPage(any(), any())).thenReturn(resultPage);
var result = service.page(null, new LastlegOrderRequests.Query(1L, 10L, null, null, null, null,
null, null, null, null, input, null, null, null, null, null));
null, null, null, null, input, null, null, null, null, null, null));
ArgumentCaptor<com.baomidou.mybatisplus.core.conditions.Wrapper<LastlegOrder>> filter =
ArgumentCaptor.forClass(com.baomidou.mybatisplus.core.conditions.Wrapper.class);