fix(lastleg): expose dispatch reviews and filter available capacity offers
This commit is contained in:
+13
-1
@@ -15,10 +15,22 @@ public final class DispatchRequests {
|
||||
}
|
||||
|
||||
public record Query(@Min(1) long page, @Min(1) @Max(200) long size, String dispatchNo,
|
||||
String vehiclePlate, String status, String fbaAppointmentNo) {
|
||||
String vehiclePlate, String status, String fbaAppointmentNo, Stage stage) {
|
||||
public Query { if (page == 0) page = 1; if (size == 0) size = 20; }
|
||||
}
|
||||
|
||||
public enum Stage {
|
||||
BEFORE_LOADING, LOADING, AFTER_LOADING, CANCELLED;
|
||||
public List<String> statuses() {
|
||||
return switch (this) {
|
||||
case BEFORE_LOADING -> List.of("PENDING_DEPARTURE");
|
||||
case LOADING -> List.of("PICKING", "READY_TO_DEPART", "PARTIAL_READY_TO_DEPART");
|
||||
case AFTER_LOADING -> List.of("DEPARTED", "PARTIAL_DEPARTED");
|
||||
case CANCELLED -> List.of("CANCELLED");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public record PreArrange(@Size(max = 500) List<@NotNull Long> planPalletIds,
|
||||
@Size(max = 64) String fbaAppointmentNo,
|
||||
@Size(max = 32) String fbaAppointmentStatus,
|
||||
|
||||
@@ -12,7 +12,7 @@ public record DispatchResponse(Long id, String dispatchNo, String vehiclePlate,
|
||||
int itemCount, int palletCount, int packageCount, int pickedPackageCount,
|
||||
int shippedPackageCount, int remainingPackageCount, String partialCompletionReason,
|
||||
LocalDateTime createdAt,
|
||||
List<Item> items, List<BolLine> bolLines) {
|
||||
List<Item> items, List<BolLine> bolLines, com.baiyue.lastleg.fleet.trip.FleetDispatchWorkflowQuery.Workflow workflow) {
|
||||
public record Item(Long id, Long planPalletId, Long warehousePalletId, String palletNo,
|
||||
String overseasWarehouseId, String overseasWarehouseName,
|
||||
String orderNo, String orderRefs, String inboundCode, String destinationWarehouseCode,
|
||||
|
||||
+13
-2
@@ -75,6 +75,7 @@ public class DispatchService {
|
||||
@Resource private LastlegOrderMapper tailOrders;
|
||||
@Resource private OutboundOrderMapper outboundOrders;
|
||||
@Resource private FleetDispatchBindingGuard fleetBindings;
|
||||
@Resource private com.baiyue.lastleg.fleet.trip.FleetDispatchWorkflowQuery fleetWorkflow;
|
||||
@Resource private RelabelApplicationMapper relabelApplications;
|
||||
@Resource private com.baiyue.lastleg.relabel.service.RelabelBindingGuard relabelBindingGuard;
|
||||
|
||||
@@ -623,11 +624,16 @@ public class DispatchService {
|
||||
.like(StringUtils.hasText(query.dispatchNo()), DispatchOrder::getDispatchNo, query.dispatchNo())
|
||||
.like(StringUtils.hasText(query.vehiclePlate()), DispatchOrder::getVehiclePlate, query.vehiclePlate())
|
||||
.eq(StringUtils.hasText(query.status()), DispatchOrder::getStatus, query.status())
|
||||
.in(query.stage() != null, DispatchOrder::getStatus,
|
||||
query.stage() == null ? List.of() : query.stage().statuses())
|
||||
.like(StringUtils.hasText(query.fbaAppointmentNo()), DispatchOrder::getFbaAppointmentNo,
|
||||
query.fbaAppointmentNo())
|
||||
.orderByDesc(DispatchOrder::getCreatedAt));
|
||||
var workflows = acrossCustomers ? fleetWorkflow.read(page.getRecords().stream()
|
||||
.map(DispatchOrder::getDispatchNo).toList()) : java.util.Map.<String, com.baiyue.lastleg.fleet.trip.FleetDispatchWorkflowQuery.Workflow>of();
|
||||
List<DispatchResponse> records = page.getRecords().stream()
|
||||
.map(order -> response(order, items.findByDispatchOrder(order.getCustomerId(), order.getId()))).toList();
|
||||
.map(order -> response(order, items.findByDispatchOrder(order.getCustomerId(), order.getId()),
|
||||
List.of(), workflows.get(order.getDispatchNo()))).toList();
|
||||
return new PageResult<>(records, page.getCurrent(), page.getSize(), page.getTotal(), page.getPages());
|
||||
}
|
||||
|
||||
@@ -764,6 +770,11 @@ public class DispatchService {
|
||||
|
||||
private DispatchResponse response(DispatchOrder order, List<DispatchItem> itemList,
|
||||
List<DispatchResponse.BolLine> bolLineList) {
|
||||
return response(order, itemList, bolLineList, null);
|
||||
}
|
||||
|
||||
private DispatchResponse response(DispatchOrder order, List<DispatchItem> itemList,
|
||||
List<DispatchResponse.BolLine> bolLineList, com.baiyue.lastleg.fleet.trip.FleetDispatchWorkflowQuery.Workflow workflow) {
|
||||
String orderNos = itemList.stream().flatMap(item -> splitOrderRefs(item.getOrderRefs(), item.getOrderNo()).stream())
|
||||
.distinct().collect(Collectors.joining(","));
|
||||
return new DispatchResponse(order.getId(), order.getDispatchNo(), order.getVehiclePlate(), order.getDriverName(),
|
||||
@@ -782,7 +793,7 @@ public class DispatchService {
|
||||
item.getDestinationWarehouseCode(), item.getDestinationWarehouseName(), item.getFbaWarehouseCode(),
|
||||
Objects.requireNonNullElse(item.getPackageCount(), 0), item.getGrossWeightKg(),
|
||||
item.getVolumeWeightKg(), item.getVolumeCbm(), item.getSourceStage())).toList(),
|
||||
bolLineList == null ? List.of() : bolLineList);
|
||||
bolLineList == null ? List.of() : bolLineList, workflow);
|
||||
}
|
||||
|
||||
private static String candidateRoute(List<DispatchPalletCandidate> selected) {
|
||||
|
||||
+4
-2
@@ -7,7 +7,9 @@ public interface FleetCapacityOfferMapper extends BaseMapper<FleetCapacityOfferE
|
||||
<script>
|
||||
SELECT o.* FROM ll_fleet_capacity_offer o JOIN ll_fleet_trip t ON t.id=o.trip_id
|
||||
<where>
|
||||
<if test="salesOnly">o.status='OPEN'</if>
|
||||
<if test="availableOnly">o.status='OPEN' AND t.status='PLANNED'
|
||||
AND o.cutoff_at > #{now} AND o.cutoff_at <= t.planned_departure_at
|
||||
</if>
|
||||
<if test="q.status != null">AND o.status=#{q.status}</if>
|
||||
<if test="q.tripNo != null and q.tripNo != ''">AND o.trip_no=#{q.tripNo}</if>
|
||||
<if test="q.keyword != null and q.keyword != ''">AND (o.offer_no LIKE CONCAT('%',#{q.keyword},'%') OR o.trip_no LIKE CONCAT('%',#{q.keyword},'%'))</if>
|
||||
@@ -21,7 +23,7 @@ public interface FleetCapacityOfferMapper extends BaseMapper<FleetCapacityOfferE
|
||||
""")
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<FleetCapacityOfferEntity> pageOffers(
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<FleetCapacityOfferEntity> page,
|
||||
@Param("q") FleetCapacityOfferModels.Query query,@Param("salesOnly") boolean salesOnly);
|
||||
@Param("q") FleetCapacityOfferModels.Query query,@Param("availableOnly") boolean availableOnly,@Param("now") java.time.LocalDateTime now);
|
||||
@Select("SELECT * FROM ll_fleet_capacity_offer WHERE offer_no=#{offerNo}")
|
||||
FleetCapacityOfferEntity byNo(@Param("offerNo") String offerNo);
|
||||
@Select("SELECT * FROM ll_fleet_capacity_offer WHERE offer_no=#{offerNo} FOR UPDATE")
|
||||
|
||||
+2
-2
@@ -16,8 +16,8 @@ public final class FleetCapacityOfferModels {
|
||||
public record Query(@Min(1) Integer page,@Min(1) @Max(100) Integer size,
|
||||
@Size(max=128) String keyword,@Size(max=128) String origin,@Size(max=128) String destination,
|
||||
LocalDate departureFrom,LocalDate departureTo,@Pattern(regexp="DRAFT|OPEN|PAUSED|CLOSED") String status,
|
||||
Boolean canConfirm,@Size(max=64) String tripNo) {
|
||||
public Query {page=page==null?1:page;size=size==null?20:size;}
|
||||
Boolean canConfirm,@Size(max=64) String tripNo,@Pattern(regexp="AVAILABLE|ALL") String scope) {
|
||||
public Query {page=page==null?1:page;size=size==null?20:size;scope=scope==null?"AVAILABLE":scope;}
|
||||
}
|
||||
public record InquiryQuery(@Min(1) Integer page,@Min(1) @Max(100) Integer size,
|
||||
@Size(max=128) String keyword,@Size(max=64) String offerNo,@Size(max=32) String status,
|
||||
|
||||
+2
-1
@@ -52,7 +52,8 @@ public class FleetCapacityOfferService {
|
||||
@Transactional(readOnly=true,isolation=Isolation.REPEATABLE_READ)
|
||||
public PageResult<FleetCapacityOfferModels.Offer> page(FleetCapacityOfferModels.Query query){
|
||||
readPermission();
|
||||
var result=offers.pageOffers(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(query.canConfirm()==null?query.page():1,query.canConfirm()==null?query.size():100),query,!manage());
|
||||
if("ALL".equals(query.scope())&&!manage())throw forbidden();
|
||||
var result=offers.pageOffers(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(query.canConfirm()==null?query.page():1,query.canConfirm()==null?query.size():100),query,!"ALL".equals(query.scope()),LocalDateTime.ofInstant(clock.instant(),ZoneOffset.UTC));
|
||||
if(query.canConfirm()!=null&&result.getTotal()>100)throw bad("实时接单资格筛选最多核对100趟车次,请缩小起运仓、目的地或日期范围");
|
||||
var values=result.getRecords().stream().map(row->project(row,trip(row.getTripNo(),false)))
|
||||
.filter(value->query.canConfirm()==null||query.canConfirm()==value.canConfirm()).toList();
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.baiyue.lastleg.fleet.trip;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** Read existing reviews in batches; never infer approval from dispatch execution status. */
|
||||
@Service
|
||||
public class FleetDispatchWorkflowQuery {
|
||||
public record Review(String status, String reason, java.time.Instant reviewedAt) { }
|
||||
public record Workflow(String tripNo, Review dispatchReview, Review loadingReview) { }
|
||||
private final FleetTripDispatchMapper bindings;
|
||||
private final FleetTripMapper trips;
|
||||
private final ObjectMapper json;
|
||||
|
||||
public FleetDispatchWorkflowQuery(FleetTripDispatchMapper bindings, FleetTripMapper trips, ObjectMapper json) {
|
||||
this.bindings = bindings; this.trips = trips; this.json = json;
|
||||
}
|
||||
|
||||
public Map<String, Workflow> read(List<String> dispatchNos) {
|
||||
if (dispatchNos.isEmpty()) return Map.of();
|
||||
var members = bindings.findByDispatchNos(dispatchNos);
|
||||
if (members.isEmpty()) return Map.of();
|
||||
var parents = trips.selectBatchIds(members.stream().map(FleetTripDispatch::getTripId).distinct().toList())
|
||||
.stream().collect(Collectors.toMap(FleetTripEntity::getId, trip -> trip));
|
||||
Map<String, Workflow> result = new HashMap<>();
|
||||
for (var member : members) {
|
||||
var trip = parents.get(member.getTripId());
|
||||
if (trip == null) throw new IllegalStateException("关联车次不存在");
|
||||
result.put(member.getDispatchNo(), new Workflow(member.getTripNo(),
|
||||
review(member.getReviewJson()), review(trip.getLoadingReviewJson())));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Review review(String value) {
|
||||
var state = FleetTripReview.read(json, value);
|
||||
return new Review(state.status(), state.reason(), state.reviewedAt());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user