This commit is contained in:
2026-10-20 21:47:51 +08:00
parent 34b90f311a
commit 137efc6809
54 changed files with 1434 additions and 63 deletions
@@ -64,13 +64,13 @@ 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("""
<script>
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_container_document d
WHERE d.container_booking_id=owned.container_booking_id
AND d.document_type='DESTINATION_CLEARANCE' AND d.file_id 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
@@ -17,7 +17,8 @@ public interface WorkflowFactMapper {
+"EXISTS(SELECT 1 "+ACTUAL+" AND EXISTS(SELECT 1 FROM fl_carrier_schedule_node_fact n WHERE n.container_booking_id=b.id AND n.standard_node='DEPARTED_ORIGIN_PORT' AND n.actual_at IS NOT NULL)) departed,"
+"EXISTS(SELECT 1 "+ACTUAL+" AND EXISTS(SELECT 1 FROM fl_container_document d WHERE d.container_booking_id=b.id AND d.document_type='DESTINATION_CLEARANCE' AND d.file_id IS NOT NULL)) clearance_uploaded,"
+"EXISTS(SELECT 1 "+ACTUAL+" AND i.tax_mode='TAX_REFUND' AND NOT EXISTS(SELECT 1 FROM fl_customs_customer_document_inbound s JOIN fl_customs_customer_document d ON d.id=s.document_id AND d.tenant_id=i.tenant_id AND d.status='ACTIVE' JOIN fl_customs_container c ON c.id=d.customs_container_id AND c.loading_plan_id=p.id WHERE s.inbound_id=i.id AND s.tenant_id=i.tenant_id)) missing_customs,"
+"EXISTS(SELECT 1 "+ACTUAL+" AND (i.tax_mode='BUY_DECLARATION' OR EXISTS(SELECT 1 FROM fl_customs_customer_document_inbound s JOIN fl_customs_customer_document d ON d.id=s.document_id AND d.tenant_id=i.tenant_id AND d.status='ACTIVE' JOIN fl_customs_container c ON c.id=d.customs_container_id AND c.loading_plan_id=p.id WHERE s.inbound_id=i.id AND s.tenant_id=i.tenant_id))) export_customs_ready "
+"EXISTS(SELECT 1 "+ACTUAL+" AND (i.tax_mode='BUY_DECLARATION' OR EXISTS(SELECT 1 FROM fl_customs_customer_document_inbound s JOIN fl_customs_customer_document d ON d.id=s.document_id AND d.tenant_id=i.tenant_id AND d.status='ACTIVE' JOIN fl_customs_container c ON c.id=d.customs_container_id AND c.loading_plan_id=p.id WHERE s.inbound_id=i.id AND s.tenant_id=i.tenant_id))) export_customs_ready,"
+"EXISTS(SELECT 1 "+ACTUAL+" AND EXISTS(SELECT 1 FROM fl_customs_container c WHERE c.loading_plan_id=p.id AND c.status='COMPLETED')) customs_completed "
+"FROM fl_inbound_order i WHERE i.deleted=0 AND NOT EXISTS(SELECT 1 FROM fl_inbound_order child WHERE child.tenant_id=i.tenant_id AND child.parent_inbound_id=i.id AND child.inbound_role='CHILD' AND (child.split_purpose IS NULL OR child.split_purpose != 'REMAINDER') AND child.deleted=0) AND i.process_status != 'CANCELLED' AND i.id IN "
+"<foreach collection='ids' item='id' open='(' separator=',' close=')'>#{id}</foreach></script>")
List<WorkflowFacts.Fact> facts(@Param("ids") List<Long> ids);
@@ -5,7 +5,7 @@ public final class WorkflowFacts {
/** 仅承载事实查询契约,不允许实例化。 */
private WorkflowFacts() {}
public record Fact(long tenantId,long inboundId,long orderId,String reviewStatus,
boolean departed,boolean clearanceUploaded,boolean missingCustoms,boolean exportCustomsReady) {}
boolean departed,boolean clearanceUploaded,boolean missingCustoms,boolean exportCustomsReady,boolean customsCompleted) {}
public record Source(long tenantId,long inboundId) {}
public record Request(List<Source> sources) {}
public record Overseas(long tenantId,long inboundId,boolean outboundExists,boolean pendingOutbound,boolean delivering,boolean unloaded) {}
@@ -27,7 +27,7 @@ public class WorkflowTabService {
if(facts.stream().noneMatch(f->f.tenantId()==fee.tenantId() && f.orderId()==fee.orderId())) throw unavailable();
result.putIfAbsent(fee.orderId()+":"+fee.mainStatus(),fee);
}
var sources=facts.stream().filter(WorkflowFacts.Fact::departed).map(f->new WorkflowFacts.Source(f.tenantId(),f.inboundId())).distinct().toList();
var sources=facts.stream().filter(f->f.departed() || f.clearanceUploaded()).map(f->new WorkflowFacts.Source(f.tenantId(),f.inboundId())).distinct().toList();
Map<String,WorkflowFacts.Overseas> overseas=new HashMap<>();
if(!sources.isEmpty()) {
try {
@@ -56,16 +56,18 @@ public class WorkflowTabService {
Set<String> keys=new LinkedHashSet<>();
if("MEASURE_PENDING".equals(process) && "PENDING".equals(f.reviewStatus())) keys.add("MEASUREMENT_REVIEW");
boolean signed="DELIVERED".equals(process);
// 报关页签按资料与实装事实汇总,不依赖点击开始报关;实际开船后转入清关链路。
if(!f.departed() && !signed) {
// 报关完成即进入待清关;不再等待船期接口补齐实际离港节点。
boolean clearanceStage=f.customsCompleted() || f.departed() || f.clearanceUploaded();
if(!clearanceStage && !signed) {
if(f.missingCustoms()) keys.add("WAIT_CUSTOMS_DOCS");
if(f.exportCustomsReady()) keys.add("EXPORT_CUSTOMS");
}
if(signed) keys.add("SIGNED");
if(f.departed() && !signed) {
if(clearanceStage && !signed) {
if(!f.clearanceUploaded()) keys.add("SAILING_CLEARANCE");
if(o!=null) {
if(f.clearanceUploaded() && !o.unloaded()) keys.add("WAIT_UNLOAD");
// 清关资料保存成功后才进入海外待办;出库事实优先于拆柜和排车待办。
if(f.clearanceUploaded() && o!=null) {
if(!o.outboundExists() && !o.unloaded()) keys.add("WAIT_UNLOAD");
// 取消的出库不构成有效覆盖,读取事实后自动回显,不能保存永久隐藏标志。
if(!o.outboundExists()) keys.add("WAIT_DISPATCH");
if(o.pendingOutbound()) keys.add("OUTBOUND_DOCUMENT");