feat(appointments): discover external booking candidates through fleet boundary

This commit is contained in:
2026-10-10 14:03:42 +08:00
parent 369613a2e7
commit 71111bf21b
9 changed files with 265 additions and 0 deletions
@@ -0,0 +1,28 @@
package com.baiyue.lastleg.fleet.business;
import com.baiyue.lastleg.appointmentplanning.AppointmentExternalSourceGateway.Candidate;
import com.baiyue.lastleg.appointmentplanning.AppointmentExternalSourceGateway.CandidateQuery;
import org.apache.ibatis.annotations.*;
import java.util.List;
/** Fleet-owned discovery; original booking remains the identity before and after receipt. */
@Mapper
public interface FleetAppointmentCandidateMapper {
String FILTER = """
FROM ll_fleet_external_booking b JOIN ll_fleet_trip t ON t.id=b.trip_id
WHERE b.offer_id IS NOT NULL AND b.status IN ('CONFIRMED','RECEIVED','BOUND')
AND t.status NOT IN ('CANCELLED','COMPLETED')
AND t.warehouse_id IN <foreach collection='q.originIds' item='id' open='(' separator=',' close=')'>#{id}</foreach>
AND b.destination_key IN <foreach collection='q.destinationCodes' item='code' open='(' separator=',' close=')'>CONCAT('FBA:',#{code})</foreach>
<if test='q.warehouseId != null'>AND t.warehouse_id=#{q.warehouseId}</if>
<if test='q.destination != null'>AND b.destination_key=CONCAT('FBA:',#{q.destination})</if>
<if test='q.keyword != null'>AND (b.booking_no LIKE CONCAT('%',#{q.keyword},'%')
OR b.trip_no LIKE CONCAT('%',#{q.keyword},'%') OR b.customer_name LIKE CONCAT('%',#{q.keyword},'%')
OR b.incoming_no LIKE CONCAT('%',#{q.keyword},'%'))</if>
""";
@Select("<script>SELECT COUNT(*) " + FILTER + "</script>")
long count(@Param("q") CandidateQuery query);
@Select("<script>SELECT b.customer_id,b.customer_name,b.booking_no,b.trip_no,b.destination_key " + FILTER
+ " ORDER BY b.created_at DESC,b.id DESC LIMIT #{q.size} OFFSET #{offset}</script>")
List<Candidate> page(@Param("q") CandidateQuery query,@Param("offset") long offset);
}
@@ -7,6 +7,17 @@ import java.util.List;
/** Appointment resolves aliases through Fleet's read boundary, never by copying cargo. */
@Component
public class FleetAppointmentSourceAdapter implements AppointmentExternalSourceGateway {
@jakarta.annotation.Resource private FleetAppointmentCandidateMapper candidates;
@Override
public com.baiyue.common.core.api.PageResult<Candidate> candidates(CandidateQuery query) {
if (query == null || query.page()<1 || query.size()<1 || query.size()>100)
throw new IllegalArgumentException("外接候选分页无效");
if (query.originIds().isEmpty() || query.destinationCodes().isEmpty())
return new com.baiyue.common.core.api.PageResult<>(List.of(),query.page(),query.size(),0,0);
long total=candidates.count(query);
return new com.baiyue.common.core.api.PageResult<>(candidates.page(query,(long)(query.page()-1)*query.size()),
query.page(),query.size(),total,(total+query.size()-1)/query.size());
}
private final FleetPoolSourceResolver sources;
public FleetAppointmentSourceAdapter(FleetPoolSourceResolver sources){this.sources=sources;}
@Override