This commit is contained in:
2026-10-09 17:36:24 +08:00
parent 74bf0e73c5
commit 261cdc87cb
27 changed files with 636 additions and 45 deletions
@@ -13,5 +13,8 @@ public final class MerchantWorkbenchFilters {
@Pattern(regexp = "WAIT_MEASURE|WAIT_PALLETIZE|WAIT_SPLIT|LOADING|LOADED|DELIVERED") String mainStatus) {}
public record Response(List<Long> matchingStatusOrderIds, List<Long> feeOrderIds,
List<Long> customsOrderIds) {}
List<Long> customsOrderIds, List<Progress> progress) {}
public record Progress(long orderId, String stage, boolean partial) {}
public record Fragment(long orderId, int stage) {}
}
@@ -63,4 +63,29 @@ public interface MerchantWorkbenchFilterMapper {
ORDER BY i.order_id
""")
List<Long> pendingCustoms(@Param("tenantId") long tenantId);
/** Only physically loaded fragments can expose container milestones to the customer. */
@Select("""
SELECT o.order_id, CASE WHEN owned.container_booking_id IS NULL THEN 0
WHEN EXISTS (SELECT 1 FROM fl_carrier_schedule_node_fact n
WHERE n.container_booking_id=owned.container_booking_id
AND n.standard_node='PICKUP_READY' AND n.actual_at IS NOT NULL) THEN 3
WHEN EXISTS (SELECT 1 FROM fl_customs_container c
WHERE c.loading_plan_id=owned.loading_plan_id AND c.status='COMPLETED') THEN 2
ELSE 1 END AS stage
FROM fl_inbound_order o
LEFT JOIN (
SELECT DISTINCT i.inbound_id, i.account_id, p.id AS loading_plan_id, p.container_booking_id
FROM fl_loading_plan_item i
JOIN fl_loading_plan p ON p.id=i.loading_plan_id AND p.plan_status='COMPLETED'
JOIN fl_loading_pick_task t ON t.loading_plan_id=p.id AND t.task_status='COMPLETED'
JOIN fl_loading_pick_item picked ON picked.pick_task_id=t.id AND picked.loading_plan_item_id=i.id
JOIN fl_container_booking b ON b.id=p.container_booking_id AND b.record_status='ACTIVE'
WHERE i.account_id=#{tenantId} AND i.deleted=0
AND picked.item_status IN ('PICKED','PARTIAL') AND picked.picked_package_count>0
) owned ON owned.inbound_id=o.id AND owned.account_id=o.tenant_id
WHERE o.tenant_id=#{tenantId} AND o.deleted=0 AND o.order_id IS NOT NULL
AND o.process_status <> 'CANCELLED'
ORDER BY o.order_id
""")
List<com.baiyue.firstleg.dto.MerchantWorkbenchFilters.Fragment> progressFragments(@Param("tenantId") long tenantId);
}
@@ -10,10 +10,22 @@ public class MerchantWorkbenchFilterService {
@Resource private MerchantWorkbenchFilterMapper mapper;
@Resource private UnifiedInboundQueryService unified;
@org.springframework.transaction.annotation.Transactional(readOnly=true)
public MerchantWorkbenchFilters.Response read(MerchantWorkbenchFilters.Request request) {
return new MerchantWorkbenchFilters.Response(
request.mainStatus() == null ? null : mapper.byProcessStatuses(request.tenantId(),
unified.internalStatuses(request.mainStatus())),
mapper.pendingFees(request.tenantId()), mapper.pendingCustoms(request.tenantId()));
mapper.pendingFees(request.tenantId()), mapper.pendingCustoms(request.tenantId()),
progress(mapper.progressFragments(request.tenantId())));
}
static java.util.List<MerchantWorkbenchFilters.Progress> progress(java.util.List<MerchantWorkbenchFilters.Fragment> facts) {
var grouped = facts.stream().collect(java.util.stream.Collectors.groupingBy(MerchantWorkbenchFilters.Fragment::orderId));
return grouped.entrySet().stream().sorted(java.util.Map.Entry.comparingByKey()).map(entry -> {
int max = entry.getValue().stream().mapToInt(MerchantWorkbenchFilters.Fragment::stage).max().orElse(0);
boolean partial = entry.getValue().stream().anyMatch(fragment -> fragment.stage() < max);
return new MerchantWorkbenchFilters.Progress(entry.getKey(),
switch(max) { case 1 -> "loaded"; case 2 -> "declared"; case 3 -> "cleared"; default -> "none"; }, partial);
}).filter(fact -> !"none".equals(fact.stage())).toList();
}
}