fix(lastleg): normalize source key comparisons across MySQL collations

This commit is contained in:
2026-10-09 16:31:19 +08:00
parent f6605a1ab0
commit 023b28e31f
2 changed files with 15 additions and 4 deletions
@@ -17,13 +17,24 @@ import java.math.BigDecimal;
@Mapper
public interface LastlegOrderMapper extends BaseMapper<LastlegOrder> {
// Correlate both order identity and customer; never infer a business source from remarks.
// CHAR(128) uses the connection character set/collation on both sides. These keys
// have at most 128 characters; table defaults differ between the fleet and order schemas.
String POOL_SOURCE_WHERE = " FROM ll_fleet_pool_order_link l WHERE l.lastleg_order_id=ll_order.id " +
"AND l.customer_id=ll_order.customer_id AND ll_order.order_type='WAREHOUSE_TRANSFER'";
"AND CAST(l.customer_id AS CHAR(128))=CAST(ll_order.customer_id AS CHAR(128)) " +
"AND ll_order.order_type='WAREHOUSE_TRANSFER'";
String BUSINESS_TYPE_SQL = "COALESCE((SELECT l.business_type" + POOL_SOURCE_WHERE + "),ll_order.order_type)";
String BUSINESS_ORDER_NO_SQL = "COALESCE((SELECT l.business_order_no" + POOL_SOURCE_WHERE +
"),CASE WHEN ll_order.order_type='LOCAL_LOOSEBOARD' THEN ll_order.source_order_no END)";
// Compare each authoritative column separately: MySQL COALESCE across these tables
// has no single collation and cannot safely be compared with a bound string.
String BUSINESS_TYPE_FILTER_SQL = "(EXISTS(SELECT 1" + POOL_SOURCE_WHERE + " AND l.business_type={0}) OR " +
"(ll_order.order_type={0} AND NOT EXISTS(SELECT 1" + POOL_SOURCE_WHERE + ")))";
String BUSINESS_ORDER_NO_FILTER_SQL = "(EXISTS(SELECT 1" + POOL_SOURCE_WHERE +
" AND l.business_order_no LIKE CONCAT('%',{0},'%')) OR (ll_order.order_type='LOCAL_LOOSEBOARD' " +
"AND ll_order.source_order_no LIKE CONCAT('%',{0},'%')))";
String EXTERNAL_BOOKING_NO_SQL = "(SELECT b.booking_no FROM ll_fleet_external_booking b " +
"WHERE b.customer_id=ll_order.customer_id AND b.incoming_no=ll_order.source_order_no " +
"WHERE CAST(b.customer_id AS CHAR(128))=CAST(ll_order.customer_id AS CHAR(128)) " +
"AND CAST(b.incoming_no AS CHAR(128))=CAST(ll_order.source_order_no AS CHAR(128)) " +
"AND ll_order.order_type='WAREHOUSE_TRANSFER')";
@Select("<script>SELECT ll_order.id AS orderId," + BUSINESS_TYPE_SQL + " AS businessType," +
@@ -554,8 +554,8 @@ public class LastlegOrderService {
.or().apply("EXISTS (SELECT 1 FROM ll_relabel_application r WHERE r.lastleg_order_id=ll_order.id " +
"AND r.customer_id=ll_order.customer_id AND r.relabel_no LIKE CONCAT('%',{0},'%'))", relabelNo))
.eq(StringUtils.hasText(query.orderType()), LastlegOrder::getOrderType, query.orderType())
.apply(StringUtils.hasText(query.businessType()), LastlegOrderMapper.BUSINESS_TYPE_SQL + "={0}", query.businessType())
.apply(StringUtils.hasText(query.businessOrderNo()), LastlegOrderMapper.BUSINESS_ORDER_NO_SQL + " LIKE CONCAT('%',{0},'%')", query.businessOrderNo())
.apply(StringUtils.hasText(query.businessType()), LastlegOrderMapper.BUSINESS_TYPE_FILTER_SQL, query.businessType())
.apply(StringUtils.hasText(query.businessOrderNo()), LastlegOrderMapper.BUSINESS_ORDER_NO_FILTER_SQL, query.businessOrderNo())
.apply(StringUtils.hasText(query.externalBookingNo()), LastlegOrderMapper.EXTERNAL_BOOKING_NO_SQL + " LIKE CONCAT('%',{0},'%')", query.externalBookingNo())
.apply(query.sailingStage() != null, LastlegOrderMapper.SAILING_STAGE_FILTER_SQL,
query.sailingStage() == LastlegOrderRequests.SailingStage.AFTER_DEPARTURE ? 1 : 0)