Files
docs/海外仓业务/内部拼车需求池首版开发契约.md
T

237 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 内部拼车需求池首版开发契约
日期:2026-10-07。当前版本:V5,五轮开发前审核修订完成,进入开发。本文为本功能唯一范围与实现契约;审核记录随文维护。部署和实际验收结论仅写入两份环境主契约,不能用本文的方案代替已实现证明。
## 1. 目标与首版范围
### 当前页面范围(2026-10-21)
用户确认「海外业务 → 散板需求」当前仅作为平台内部的排车余位需求池,人工联系、下单,不向客户公开运力市场。2026-10-22 简化智能排车:搜索区仅提供默认不勾选的“发布公共需求”,统一应用于本次生成的所有排车单,每车独立保存;移除下方计划时间与备注填写区,需求时间直接使用关联排车的计划发车时间,时间和备注沿用“维护车辆信息”维护。2026-10-23 收敛为仅在“智能排车”建单时选择发布,默认不勾选;排车列表和入库单复用同一智能排车弹窗。维护车辆不再提供发布、取消发布或恢复发布,编辑命令不接收发布字段;预约工作日历创建排车不自动发布,服务端新建缺省也不发布。需要重发时,按原取消门禁取消当前排车,再通过智能排车重新创建并勾选发布。发布选择与新建命令同事务保存,沿用原权限和幂等键。
数据源直接来自当前排车主单,不再依赖旧车次的人工余位发布记录,也不创建另一份车次、发布单或占位。仅勾选发布、ACTIVE、DELIVERY、未实际发车且处于装车前/装车中/装车后的排车进入列表;取消排车、实际发车/进入派送中或任一已知容量维度满载时自动退出。取货和本土卡车排车不参与。查询复用实时排车快照,按本车业务号一行展示,不返回客户货物、司机私人信息或内部ID。
车辆容量与已排实托数分别展示,不将实托数等同标准托位。可靠装载确认存在时,用去重实托的标准托位、重量和体积计算起运段可再接的余量;首版均从我仓上车,沿途只卸货。任一已知维度已满即退出;缺少可靠装载/容量资料时保留需求并明确“余位待确认”,不填零、不按车型名称或默认30托推算。不存在可公开的调度联系方式时,不以司机电话替代。新列表仅读取运输和容量摘要,不开放详情跳入旧车次、登记、确认承运、来货、核量或排入本车等操作。
原需求池与后续拼车实现保留,不增加开放登记的功能开关、不删除组件或业务处理代码。客户本土散板下单入口保持独立;下文完整拼车流程描述保留能力,不能据此认为当前页面已开放。新增发布字段、读接口与页面的代码完成不等于已执行SQL、已部署或已通过真实环境验收。
### 2026年10月9日操作简化开发定稿与预约交接
本次已收到开始开发指令,采用《拼车数据入口与操作简化评估草案》第七、八节的完整范围:已有车次接货,分阶段登记、服务端缺项及角色提示、原登记连续履约、合格排车候选、共用车次准备与实收排入。保留直接外接预订来源,不新增独立待配货池、虚拟运力或跨车改配。本文记录规则,发布与实际验收继续归环境主契约。
文件归属:本侧维护 Admin `overseas-master-data/`、其公开出口和所需 `overseas-warehouse` 排车消费者;Backend `fleet/`、`dispatch/fleet/`、相关既有排车候选 Mapper 及 Fleet OpenAPI/测试。预约实施侧维护 `appointment-calendar/`、预约服务、预约投影及其 OpenAPI,并统一整合 `lastleg.sql`、公共导航和新增权限种子;本侧不重叠写这些共享文件。不改变已存在的财务修改。
预约交接的稳定身份:成交前为 `bookingNo`,成交后关联 `businessOrderNo`;安排来货后增加 `incomingNo`,实收依据为 `receiptHash + warehousePalletId + packages`;正式排车以 `dispatchNo` 及其完整来源组成核对。货物上车资格以同客户、同起运仓、同真实来货来源、完整实收托盘组成、未绑定其他车次为准。来源尚未形成合格排车或实际托盘时,预约侧只能保存筹划,不能通过本侧创建假托盘或实载。
现有共用 API 前缀为 `/api/platform/v1/last-leg/fleet`:`/trips` 维护真实车次;`/trips/{tripNo}/assignment` 分配资源;`/trips/{tripNo}/dispatches/bind` 关联合格排车;`/trips/{tripNo}/capacity-plan` 核对计划;`/capacity-offers` 及发布命令维护每车次唯一发布。当前 UI 以车次详情及 `CapacityOfferSettingsDialog.vue` 为入口;新增共用入口实现后通过模块 `index.ts` 导出,不允许预约侧直接引用内部组件。预约侧覆盖投影尚待交接,以正式来源查询结果为准,不在本侧新增预约状态。
共同样例:两柜真实货物的合格排车进入同一30托位车次,自有计划占18,确认外接登记8后同区间余4;外接实收排入后,8由预留转入真实计划,仍只计一次。来货绑定导致旧计划失效时,余位返回待核对,不能继续展示旧余4或自动恢复发布。托位、重量、体积逐段同时校验,三类阶段(预约筹划、外接保位、正式排入)不互相替代。
登记保存即对获准调度可见,不保位;后续必填与始终选填分区展示。`Inquiry.progress` 为只读派生的阶段、保位说明、负责角色、主要动作及缺项,不能被前端写成状态。承运资格同时检查本票资料与目的站余位,最终写命令仍锁定并复验。后续履约读取和操作以原登记身份进入,查看本人记录不授予整车其他客户或司机资料的读取权限。
用户场景:调度约定30托位车辆去目的仓A,自有货占18托位,将剩余12托位发布给内部销售;销售联系外部客户、登记意向,调度确认承运和占位,客户订单随后走真实到仓、装车、配送和签收。
本功能的“需求池”是**已发布车次的剩余运力目录**,不是客户待配货需求库。一条发布对应一个车次;销售从具体车次登记意向,不新建无车次撮合平台。
首版边界:
- 仅内部Admin展示运力池,Client不开放余位市场。客户只查看自己的本土订单和获准的承运安排。
- 所有外接货统一在我仓上车。客户自行送仓,或我方在线下安排提货回仓,均从实际到仓后开始系统收货。可记录两种交货说明,不能宣称已有独立提货任务闭环。
- 沿途提货直送、行驶途中新增承运、独立提货车调度及交接、自动撮合、销售临时限时锁位、整单拆分到多个干线车次均不在首版。
- 询价不占位,调度确认承运才占位。订单预算不等于成交运费,承运确认不等于收款。
- 本轮用户已授权TEST部署、测试数据库、真实HTTP和内置浏览器验收,Admin/Client固定1920×1080、100%缩放。操作目标为TEST,不沿用上轮灰度配置;密钥仅从私有配置读取。
## 2. 单一事实来源与复用
| 内容 | 权威来源与本轮处理 |
| --- | --- |
| 车次、线路、时间、车辆容量 | 现有FleetTrip及当前车辆主档;不建立第二套车次 |
| 自有货计划占位 | 当前有效capacity-plan及货物hash,保留三维容量 |
| 外接占位 | 复用外接预订CONFIRMED/RECEIVED;BOUND后由实际货物计入,不双扣 |
| 发布信息 | 新增每车次唯一的发布记录:业务编号、状态、交货截止、公开给销售的联系人/备注、版本和审计 |
| 客户意向 | 复用外接预订DRAFT,增加发布关联、服务端销售负责人、交货说明及本土业务类型 |
| 本土订单 | 本土散板/本土卡车保存客户委托;预订关联真实业务单号,不再重复产生无关商业订单 |
| 实收与发运 | 现有外接来货→WarehouseTransfer→库存→客户排车→共享车次→派送链 |
| 费用 | 沿现有实际派送费用来源发布,需求/询价阶段不新增应收。成交价、预算与实收款独立展示 |
开发前源码缺口记录:当时没有发布列表,预订没有销售负责人/发布来源,本土订单没有真实外接履约关联;本土散板create会另建逻辑尾程单,不能直接再调用外接来货形成两个来源;本土卡车原库存动作尚不等于外接真实库存链。此段说明本次设计起因,当前实现及验收结果以测试环境主契约为准。
## 3. 发布与余位
### 页面发布操作简化(2026-10-09)
车次关联排车单时,在同一事务按真实货物目的地标识自动补齐卸货站;去重,不按同名合并,不改变已有有效站点顺序与索引。仅新车默认的“待确定卸货点”占位由真实目的地替换;外接预订路线门禁、缺失目的地拒绝与绑定变更后的重新审核继续生效。多目的地的行驶顺序仍由调度在车次计划确认。
车次“发布拼车余位”使用1080px居中窗口,同窗展示计划容量与交货截止;唯一匹配卸货站直接显示,不重复选择。已有计划数值自动带入,只补缺失的预计重量、体积并核对托位;尚无可靠实托测量字段时不拿计费重量或零值填充。交货截止默认计划发车时间,可提前;公开联系人与交货说明收起为选填,不将司机联系方式自动公开。
“确认发布”依次复用容量确认、发布信息保存、发布/恢复接口,传递各步最新版本,保留服务端权限、容量、状态及幂等检查;已有有效且未编辑的容量直接复用。保存草稿与发布不再要求两次点击。发布失败不宣称成功;未知发布结果保留原键续试,已成功的保存步骤不重做。发布完成提供“查看需求池发布”。暂停与关闭继续显式确认。尚未自动匹配的车次可在同窗“按货物补齐卸货站”,不能自由输入标识绕过货物来源。
发布由有调度管理权限的用户在车次详情执行。前提:车次PLANNED,已分配可用车辆和司机,有真实起运仓及规范卸货站,发车/交货截止有效,容量计划有效。发布不替代调度审核、司机资质门禁或发车前理货审核。
本轮不新增“车牌司机尚未落实的虚拟运力”模型,沿用已分配资源的现有车次。计划容量或任何必须数据未就绪时给出具体阻断原因,不能以车型名字推算30托。
发布状态为DRAFT、OPEN、PAUSED、CLOSED。满位、超过交货截止、已发车/取消、容量待核对为服务端计算的接单资格,不另维护可手改的余位数字。暂停/关闭不取消已确认预订或删除客户订单;恢复发布必须重新校验。首版车次发车后不再新增承运。
状态转换为DRAFT→OPEN,OPEN→PAUSED/CLOSED,PAUSED→OPEN/CLOSED;CLOSED为终态,同车次不能另建发布规避关闭。OPEN但事实失效时允许调度显式“重新核对并恢复”更新事实指纹,仍须完整资格校验。
时间以服务端Clock的Instant为准,开放新询价/编辑须OPEN且`now < cutoff <= plannedDepartureAt`、车次仍PLANNED;询价不承诺运力,可在满位或待核对时保留草稿并明确提示,确认承运则必须所有资格有效。关闭、截止或发车后,销售仍可经“我的意向”只读跟踪本人已登记/成交业务;暂停不接受新询价或编辑,仅允许既有规则下的查看/取消。
容量按起运仓至选定卸货站的每段最小可用量校验,托位、重量和体积同时满足。列表展示分目的站的可接量,不能用全车某一个余位数字代表所有运输区间。30−18−已确认8=4仅为同一区间同规格例子。
读取可接资格、发布、确认承运均复验车辆当前启用状态和实际容量与计划是否一致;当前车辆停用或容量变更使旧计划不可承诺。改派/改线/新增自有货/绑定或解绑货物导致计划失效时,显示“待调度核对”、余位为未知并拒绝新确认,不回退到旧计划或显示0。确认承运仍由服务端在车次锁内重新计算。
发布保存本次核对的路线/发车时间、车辆容量和有效容量计划的事实指纹。仅询价、确认预订导致的版本变化不使发布失效;实际货物/容量计划或上述承诺事实变化则待核对,重新确认计划后由调度显式恢复接单,不静默恢复。GET只计算资格,不修改发布状态。表格采用“已关联货物计划占用 + 未关联外接预留(CONFIRMED/RECEIVED) + 可接余位”;BOUND外接已在计划内,若另示外接总量,只作信息列,绝不再次相加。
所有发布和预订写命令先锁车次,再按需锁实时车辆,随后锁发布记录、预订及商业关联;暂停/关闭与承运确认也共用该车次锁。实际实现须与现有车次/资源锁顺序一致。权限、登录身份与来源归属校验不能省略;已成功命令的同键同载荷重放在重新评估截止/OPEN等业务资格之前返回原结果,异载荷仍冲突。
## 4. 销售与调度权限
- 新增独立发布池列表权限,包含发布详情和不含敏感信息的只读辅助投影;不要求销售拥有trip:list。
- 销售可查看OPEN发布的线路、时间、容量、调度联系信息;登记并查看/修改/取消本人DRAFT意向。销售负责人取登录userId,不接受浏览器冒充,不按姓名判定归属。
- 调度管理权限可查看各销售意向、发布/暂停/关闭、确认承运和处理取消;不能通过一般销售写权限确认占位。
- 当前IAM无稳定销售客群ACL,只有salesOwnerName文本。本轮不新增CRM归属体系。授予本功能意向登记权限即允许在用途限定的客户候选中选择公司ACTIVE客户,仅返回ID、客户编号、名称,不返回电话/证照/财务资料;必须在文档与接口中明确该公司共享选单目录口径。
- 他人意向的直接编号访问、修改及取消须在服务端拒绝;发布总余位可以包含全部预订,但不向销售返回他人客户名称、货物、价格、司机私人信息或采购成本。
- Client根据自身客户身份查询本土订单,不提供发布池接口或其他客户预订详情。
建议权限族:`platform:fleet:capacity-offer:list/manage`与`platform:fleet:capacity-offer:inquiry-create/inquiry-edit/inquiry-cancel`。manage授权调度读取全部意向并确认承运,普通list只读取本人意向;列表和详情只读语义一致。最终路径与权限同步Controller、OpenAPI、IAM种子、导航和测试。
读取发布/本人意向允许list或manage;销售写操作同时要求list和对应inquiry写权限,manage可管理全部。所有查询/写入都由服务端取销售身份;池来源预订经既有trip booking接口操作时也必须执行一致的来源、权限、发布、订单桥和取消门禁,不能借旧接口绕过。
## 5. 意向、成交与本土订单
销售从发布详情登记意向:客户、本土散板或本土卡车类型、当前路线卸货站、货名、预计箱数/托位/重量/体积、交货方式、预计到仓、联系人、报价方式/币种/金额、备注。未完成询价允许缺预计载荷或价格;确认承运前必须完整且与本轮计划匹配。空值不等于0,报价库引用与手填成交价按既有权限规则处理。
首版每条外接意向整单绑定一个干线车次,不提供销售拆分数量。仅可选择本车现有卸货站,新增目的地须调度先改车次路线并重核计划;不能以自由文本地址伪造目的仓匹配。
确认承运采用一次服务端命令:验证发布/车次/预订版本、登录权限、客户资格、路线、时间、实际有效余位及成交价→创建本土商业订单及唯一桥关联→确认预订占位→返回新版本及业务单号。不可由浏览器串行三次写入拼接“成功”;使用稳定幂等键,同键同载荷返回原结果,同键异载荷拒绝。未知结果保留原键与内容,不能生成新单重试。
确认成交只新建一张池来源商业主单,不接受任意已有独立订单号。LOCAL_LOOSEBOARD通过专用内部方法创建主单与历史,不执行原独立下单生成占位ll_order的分支;US_TRUCK同样只建商业主单,不生成模拟实托记录。独立下单保持其合法业务入口,池内订单走真实运输桥,不以“兼容”保留两套同单行为。
唯一桥表`ll_fleet_pool_order_link`以booking_id唯一,保存客户、business_type、商业单ID/业务号和桥状态;来货生成后再绑定唯一incoming_no和lastleg_order_id。预订DTO商业号来自桥投影,不在两处维护可写副本。登记来货由现有FleetIncomingAdapter创建唯一WarehouseTransfer及真实尾程来源,并在同事务反绑商业单;客户、目的地或来源不符则回滚,不产生第二张尾程单。
尾程订单列表、详情与导出通过同客户、同尾程单的正式关联展示商业来源:池来源为“本土散板/本土卡车 · 拼车需求池”,独立散板为“本土散板 · 独立下单”,未关联商业单的外接来货为“仓储转运 · 外接来货”。`orderType` 继续表示履约类型,不改写为商业类型。`businessSource` 返回商业类型、来源中文说明、关联商业单号及外接预订号;缺少关联显示“—”,禁止解析备注。`businessType` 筛选本土散板时覆盖独立与池来源两条路径;商业单号和预订号支持服务端包含匹配。Admin 商业单号仅在具备目标列表权限时链接到带该单号筛选的既有本土业务列表,池来源继续从“承运安排”查看。
实托数与托位分开:询价提供可空的预计实托数;US_TRUCK确认前必须有正数预计实托数,不能拿palletSpaces当palletCount。预计箱数同样允许未知,确认前须补完整真实预报;不以0或1伪造未知。实收时以去重后的真实仓库托盘数记录实际实托,按核准每托占位合计记录托位。商业单预算仍是独立可空预算,不自动写入成交金额。
池询价未采集柜型或是否委托打盘服务,商业桥须将这两项保留为未知:卡车/散板的`containerType`及散板的`palletRequired`为null,不套用40HQ或YES。实托数、占用托位及实际托盘存在均不能证明客户委托打盘;Admin/Client列表和详情将未知显示为“—”。响应允许空值或省略空字段,详情经summary承载;普通独立Create/Update请求的必填、枚举及默认规则保持原合同。
池来源商业单状态映射:成交为WAITING_INBOUND;真实收货开始为RECEIVING;实收并核量确认后为WAITING_CONSOLIDATION(散板新增对应状态);完整关联客户排车后为PENDING_DISPATCH;整车实际出库/发车为IN_TRANSIT;全部实际货物签收为COMPLETED;安全取消为CANCELLED。不得把绑定车次标为已发车。状态与历史由实际来源事务推进并带来源业务号/时间;退回、部分签收保持未完成,并展示实际派送摘要。重复保存回执不得重复追加完成历史。
真实出库/签收需要本地桥回传:现国内完成Outbox只覆盖FIRSTLEG来源,不能依赖它完成本土单。按桥中唯一来源和同客户派送/实际货量核对后回写主单;不得创建第二笔运费。池来源散板编辑/手工状态、卡车编辑/审核/手工收托/超托审核/分配/发车/完成/取消等入口必须识别来源后拒绝旁路,并返回当前应操作入口;不能只在页面隐藏按钮。
运费仍由真实转派送的`FLEET:{bookingNo}:{dispatchNo}:FREIGHT`唯一来源发布;商业主单、发布池、来货和签收回传均不重复发布该费用。全外接货不能另填一份派送应收。成交价、实际约定运费、Finance应收/实收各自表达,零价沿现有正式规则处理,不能绕过费用门禁。
成交/取消锁顺序沿第3节:车次→资源→发布→预订→商业关联/商业单。实际收货/签收在既有作业锁之后仅锁商业关联/商业单,不反向锁车次/发布/预订。商业单旧手工入口在本单锁内识别池来源直接拒绝,不反向协调车次。已有池来源来货也不得独立从旧来货取消入口取消而留下有效承诺;本轮登记来货后的取消/跨车改配明确阻断。
Admin和Client自己的本土订单列表/详情返回同一批查询产生的`fleetArrangement`摘要:来源类型、真实商业单号、预订号、计划发车、起运仓和目的地、交货说明、实际履约阶段/时间、约定运费(非实收)及只读原因,并提供已签/未签/退回数量和异常摘要;独立订单该字段为null。不返回发布池内部ID、余位、他人货物、司机私人信息或采购成本。原列表/详情不得逐行额外调用池接口。首版不额外建设任意存量订单批量导入/撮合。
## 6. 真实到仓、变更与取消
已确认后复用登记来货、PDA实际收货、运营核量确认、生成客户排车并关联本车、调度审核、PDA拣货、实测装载、理货审核、整车发车、目的仓签收、结案及资源释放。需求池提供关联业务跳转和实时摘要,不再建立一套“手填已发车”状态。
实收托位/重量/体积改变,须重新核量、检查本车剩余容量和确认费用;超量不可自动覆盖承诺。整单价和按托价保持既有口径,不静默把预算写为应收。BOUND预订由真实货物占位替代预订,不能叠加扣减;对应容量计划失效时停止继续接单,待重核。
DRAFT由本人或调度取消;池来源CONFIRMED仅在尚未登记来货时由调度一体取消商业关联、预订及占位。已有incoming、实收或BOUND拒绝池内快捷取消,进入既有实际作业处理;现有booking.cancel允许RECEIVED的行为不能旁路该池来源门禁。不可通过关闭发布或取消意向删除库存、清除已拣货或把已发车货物变回草稿。首版不提供实收后跨车次改配,遇到该请求明确拒绝并保留原单据,不自动重造。
## 7. 页面、请求预算与错误处理
Admin「车辆管理」的「拼车接货」包含“可拼车次”“我的登记”两个独立页签,仅加载激活页签;调度默认进入“待我处理”登记范围,销售默认进入“可拼车次”。调度可选全部登记范围,服务端拒绝销售越权该范围。主列表一行一发布车次:操作、发布号/车次号、起运仓、目的站/路线、发车/交货截止、已关联货物计划占用、未关联外接预留、各目的地可接托位/重量/体积、接单状态和调度联系信息;多目的站在同一行分行展示,详情展开分段表。查询起运仓/目的地使用文本条件,日期和状态使用本地选项,不为筛选增加目录请求。“我的登记”跨发布状态可读历史,不依赖OPEN列表。可拼车次默认使用 `scope=AVAILABLE`,在数据库分页前按 `OPEN + PLANNED + now < cutoff <= plannedDepartureAt` 筛选,管理员也遵循同一默认范围;满位或容量待核对但允许草稿登记的发布仍保留。管理员显式选择“全部发布(含历史)”时使用 `scope=ALL`,普通销售不得请求该范围。车次发布设置查找已有发布显式使用ALL,避免遗漏草稿或过期发布。详情页有登记权限时保留“登记意向”按钮,业务资格不足则置灰并展示服务端原因;无登记权限不显示按钮。
发布详情为独立页,首个响应带运输摘要、分段余位及获准意向首20条、total/page/size;意向翻页单独1次请求。池接口只返回专用offer/inquiry DTO,不复用含司机或客户联系信息的TripDetail/FleetCustomerOption。offer独立返回canCreateInquiry、canConfirm和blockReason,满位或待核对不错误禁用允许的草稿登记;未取得有效容量时显示“待调度核对”,已知满位才显示0。
操作承载矩阵:发布详情独立页;登记/编辑/查看意向为1080px居中;车次详情内“发布设置”采用居中表单;确认承运复用1080px登记窗口,同窗补齐资料、核对并通过save-and-confirm一次保存确认,不追加独立确认框;取消采用现有确认框,明确对象和影响。当前新增操作没有外部原型,按用户授权、本文矩阵及已确认车次高密度样式实现,不能拿方便的抽屉替换。未保存提醒覆盖取消、X、Esc及路由离开;结果未知时保留原请求键和载荷。
Admin本土订单池来源行增加“承运安排”只读入口(1080px居中),原编辑深链也只能展示只读原因和安排;正常独立订单保持原操作。关联车次/来货/排车跳转逐项检查目标权限,无权限只显示业务号。Client沿原详情展示同一客户摘要,不新增公开池。两端同步散板新状态标签和筛选,不能显示裸内部状态码。
未知预计箱数与预计实托数的可空类型须同步既有bookingTypes、tripBookings normalizer、TripBookingPanel及对应测试,旧面板不得把pool询价解析失败或自动补成1。池来源确认/修改操作同样使用服务端允许动作;管理面板不得将未完成商业关联的旧确认视为成功。
样式复用Admin高密度、integrated DataTable、操作列左置、统一查询/分页/按钮/错误态;不接入演示假数据。Client只在自己的订单响应中增加承运安排摘要,沿既有列表详情展示,无新公开拼车菜单。
| 操作 | 业务请求预算(登录/公共外壳另计) |
| --- | --- |
| 任一页签进入/切换/查询/重置/翻页 | 每动作1次活动页签分页;不预加载另页签,不逐行查询车次或容量 |
| 打开发布详情 | 1次详情,含分段余位和获准意向首20条及total/page/size;后续翻页各1次 |
| 打开登记表单 | 复用详情事实;客户候选首次聚焦/搜索才请求,输入防抖,取消迟到响应 |
| 报价候选 | 仅用户显式查询/翻页各1次,走池作用域专用候选接口;无报价权限0次,手填价不附加报价权限 |
| 确认/修改/取消意向 | 1次写命令返回新摘要;必要时最多1次当前详情刷新,不全表逐项刷新 |
| Admin/Client本土订单列表/详情 | 仍各1次,不逐单补查运力或预订;Admin行内打开已有承运摘要额外0次 |
加载时保留上下文;区分无发布、筛选无结果、本人无意向、候选为空及接口失败;网络错误显示诊断和重试,不伪装空数据;版本冲突要求重新核对;写入处理中禁重复提交。切页/关闭/切发布时忽略旧响应。筛选重置和页码watch只能有一个实际加载入口,避免重复请求。真实请求计数包含非第一页重置、快速切页和写成功后的刷新,不能只测首屏。
普通运力列表由数据库执行起运仓、目的地、日期、状态和文本筛选及分页,仅核对当前页的实时容量。显式启用`canConfirm`接单资格筛选时,先统计基础筛选后的候选;超过100趟即返回缩小起运仓、目的地或日期范围的提示,不展开逐车容量查询。100趟以内计算实时资格并返回精确总数,不能按当前页过滤后伪造总数或在后台扫描全部车次。
## 8. 实现归属与部署
Backend仍归Lastleg,Gateway复用现有fleet/last-leg通配路由;按API变更执行gateway-route-contract。新增持久化Mapper须显式@Mapper并跑注册合同。数据库基线、权限种子和测试环境差异SQL统一维护,不清库、不重复执行已成功未知结果SQL。
部署单元预计Lastleg、Admin及受DTO展示影响的Client;IAM若仅新增库内权限种子则核对实时权限刷新,不无故部署全服务;必要时按实际依赖补充清单。TEST单机Maven只使用现有锁及单执行器,禁止并发构建挤压服务。部署与数据库写入由当前对话串行操作,内部协作仅分文件实现与只读/离线核对。
## 9. 必验场景
### 冻结的接口和实现分工
服务前缀为`/api/platform/v1/last-leg/fleet/capacity-offers`;Admin浏览器HTTP基址已经含`/api`,消费路径省略该前缀,避免重复。新增接口沿既有Lastleg Gateway路由,不暴露内部接口。
| 方法与相对路径 | 语义 |
| --- | --- |
| GET / | 当前用户获准的发布分页,含逐目的站余位和资格;text起运/目的地、日期、状态、可接筛选 |
| POST /,PUT /{offerNo} | 调度创建发布草稿及编辑公开信息,校验车次/发布版本 |
| GET /{offerNo} | 发布详情及获准意向首20条;非OPEN仅调度或本人已有意向者可读受限投影 |
| POST /{offerNo}/publish、pause、resume、close | 显式发布状态命令,版本和持久幂等 |
| GET /inquiries,GET /inquiries/{bookingNo} | 本人意向及单条详情;调度可选择全部范围,销售不能用参数越权 |
| POST /{offerNo}/inquiries,PUT /inquiries/{bookingNo} | 登记/编辑草稿,登录人冻结销售负责人 |
| POST /inquiries/{bookingNo}/confirm、cancel | 调度成交与适用范围的取消,唯一桥及容量事务 |
| GET /customer-options | 用途限定ACTIVE客户ID/编号/名称目录,不返回联系人或电话 |
| GET /{offerNo}/quote-candidates | 公开给该场景的销售报价候选,需额外quote:list,按本车及客户/卸货站/币种/计价方式过滤 |
offer写入携带tripNo、tripRecordVersion、存在时offerRecordVersion、cutoffAt、公开联系信息、remark和idempotencyKey;意向含offer/trip/booking版本、customerId、businessType(LOCAL_LOOSEBOARD/US_TRUCK)、deliveryMode(SELF_DELIVERY/MANUAL_PICKUP_TO_WAREHOUSE)、estimatedArrivalAt、独立expectedPalletCount、cargo、quoteRef、idempotencyKey。Cargo.packageCount可空,确认前完整校验;可空不以虚假默认数替代。对象主身份使用发布号、预订号等业务编号;ID仅用于明确接口关联。
Admin路由:`/overseas-master-data/capacity-offers`及`/overseas-master-data/capacity-offers/:offerNo`。菜单与路由允许list或manage;销售写另需对应inquiry权限。客户端不增加运力路由。
持久化:每trip唯一`ll_fleet_capacity_offer`、持久命令记录(作用域/动作/键/请求hash/原结果)、预订新增发布/销售负责人/业务类型/交货方式/预计到仓/独立实托数字段、唯一`ll_fleet_pool_order_link`。桥表booking_id、booking_no、(business_type,business_order_id)唯一,incoming_no/lastleg_order_id为nullable unique;来源未发生保持null。不得只保存“最后一次键”而丢失旧成功请求的重放事实。Mapper/基线/统一空库SQL/本轮精确结构补齐/权限种子分别核对,无清库、存量修复或双写兼容。
实现分工:运力池工作包独占fleet发布及预订服务和其测试;订单桥工作包独占fleet/business、商业订单/来货/实际作业回写及其测试;前端工作包独占业务页面/API/types/tests和矩阵。当前对话集成共享路由/导航/权限、SQL、OpenAPI与部署。跨包调用FleetPoolOrderBridge在已有事务中执行,不另开事务、不双写费用;源码签名先在实现者间固定,禁止两个工作包同时改同一服务文件。
### 验收用例
1. 自有18/总30,同路段外接8确认后余4;另一客户再确认5失败,原已确认事实不变;重量或体积先满同样拒绝。
2. 两名调度同时确认来自不同销售的最后余位意向,最多允许容量内的承诺;销售自身调用确认必须拒绝;原键重放不增加订单、预订或费用。
3. 两个不同登录账号但同姓名仍相互隔离;销售猜测他人意向编号、调用调度确认或车次敏感接口被拒绝;Client不能查看运力池。
4. 暂停、关闭、截止、发车/取消、改派/路线/自有货变化、车辆停用/缩容均不能沿旧余位继续接单。
5. 意向到本土订单/来货/排车/派送保持同客户和唯一来源;实收超量阻断、预订转实载不双扣、允许的取消释放且不删除事实。
6. 本土散板和本土卡车分别从池内成交走到签收,本土订单真实终态回传;不制造第二张虚假尾程来源,不重复收费。
7. Admin按调度和销售最小权限、Client按本票客户,在1920×1080检查列表、详情、表单、加载/空/错态、动作门禁和网络请求次数;保留截图与脱敏网络计数证据。
8. 保留当前车次自有货链的核心回归:审核、拣货、改派后复审、整车发车、签收及资源分别释放;新需求池不得旁路这些规则。
## 10. 五轮审核记录
每轮必须有实际发现、修订和复核依据,前一轮改完再检查下一轮;五个“通过”标题不能代替审核。五轮结束后冻结开发版,发现实现与合同冲突仍须修正并补测。
| 轮次 | 检查重点 | 当前记录 |
| --- | --- | --- |
| 1 | 用户范围、池的对象、延期功能与现有实现差距 | 已识别“车次余位池”被误解为“待配货客户需求池”的偏差,纠正为每车次发布、销售从具体车次登记;三种完整愿景与统一我仓首版分开;不引入沿途提货门禁改造 |
| 2 | 容量/并发/权限/状态与车辆实时事实 | 审核V1后修订V2:补齐统一锁序、暂停与确认竞争、服务端截止及成功重放顺序、关闭后本人历史可读、池来源未登记来货才可取消、BOUND不重复扣位、旧接口旁路及事实指纹失效后显式恢复;依据FleetBookingService、FleetTripService.persist、capacityPlan及Reservations |
| 3 | 本土订单唯一来源、实际履约、状态和费用 | 审核V2后修订V3:确认仅创建池来源商业单,散板不再建独立占位来源;新增唯一桥、来货反绑、实托/托位分离、真实状态回写、旧手工入口和来货取消防旁路、唯一运费来源及回传不反向锁车次;依据LocalLooseboardService、UsTruckOrderService、FleetIncomingAdapter、DeliveryTransfer及国内完成事件范围 |
| 4 | Admin/Client交互、最小权限、请求预算与验收 | 审核V3后修订V4:补独立我的意向历史入口、Admin本土单只读承载、offer/inquiry/fleetArrangement专用投影、可空箱数直接消费者、两端状态标签/筛选、逐动作请求预算/分页上限、未知与满位区分、完整弹框关闭保护;按现Trips/Booking/TransportOrders及Client消费者核对 |
| 5 | 全文一致性、接口/SQL/权限/测试/部署可执行性 | 总核对V4并冻结V5:去除“任意既有单关联”残留,明确关闭终态与显式恢复;补接口/字段/路由及数据库唯一约束、持久重放、实现归属;Admin/Client请求预算统一,测试覆盖两类商业单、权限及取消旁路;本轮只授权TEST,部署与浏览器证据不由文档通过替代 |
### 预约侧可直接使用的来源解析边界
`FleetPoolSourceResolver.resolve(List<SourceRef(customerId, bookingNo)>)` 在同一服务内批量只读,每次最多100条;返回 bookingNo、tripNo、bookingStatus、warehouseId、destinationKey/Label、incomingNo、lastlegOrderId、businessOrderNo、fulfillmentStage 和登记recordVersion。未成交也保留登记来源;没有对应别名时返回null,不能计作另一票货。不返回私人联系方式。调用侧先校验每个来源的权限;不匹配客户或不存在的来源不返回,调用侧须比较请求/返回集合并提示缺失。
本侧期望预约覆盖以 `customerId + bookingNo` 查询并返回同一键、覆盖状态、预约业务号/确认号列表、缺项、sourceVersion及changeReviewRequired;别名由上述解析入口提供,预约侧负责归一化及货量去重。实际生产者签名由预约侧确定后本侧接入,不使用假覆盖结果。
来源解析补充:`Source` 同时返回 nullable `packageCount`、`expectedPalletCount`(均为预报,不是实收)、`estimatedArrivalAt`(数据库UTC LocalDateTime,到我仓预计到仓,不是目的地预约)。货量未知保持null。
B接受由A在 `appointmentplanning` 公开包建立唯一预约覆盖生产者。建议Java入口 `AppointmentCoverageQuery.query(List<SourceRef>)`,SourceRef为customerId、sourceKey(BOOKING:业务号或ORDER:订单标识)、destinationKey;结果以相同键返回status、appointments(预约业务号/外部确认号/确认时间)、missingFields、sourceVersion、changeReviewRequired。必须按同客户正式别名归一化;无真实货件资料可返回待补,不可伪造已确认。B在生产者存在后消费其公开DTO/服务,不维护第二套覆盖判断;若A采用不同签名,以A公开实现和测试为准收口消费者。
### 共用准备和连续处理接口定稿
- `POST /fleet/trips/prepare`:新建(计划、车辆、司机、排车单)或加入已有车次(车次号、版本、排车单)两种输入互斥;一次事务全部完成,失败不留下半成品车次。持久幂等复用现有命令记录,重试不得重复建车。共用UI `TripPreparationDialog`参数为warehouseId、warehouseName、dispatchNos,通过模块index.ts导出,实际仓库/来源由服务端再校验。
- `GET /fleet/trips/{tripNo}/dispatch-candidates`:本仓、未绑定、未开始执行且无其他车次外接承诺的候选,数据库分页;`TripDispatchSelector`替代手填编号。
- `POST /capacity-offers/inquiries/{bookingNo}/save-and-confirm`:同窗核对后一次命令更新资料、创建商业关联并保位,全部回滚或全部成功,保持原MANAGE权限;不自动生成来货。
- 原登记下`/fulfillment`按需只读本票;`/incoming`、`/receipt-confirmation`和`/arrange-dispatch`分别明确安排来货、确认实收、排入本车。池manage并不自动获得原车次booking-edit/booking-confirm/trip-edit或智能排车权限;服务端和前端同时校验对应权限。
- 实收排入优先复用唯一的同客户同来源完整排车;没有时使用真实实收计划托盘调用原预排。多张、混入其他来源、实收不完整或被其他车次绑定时整体拒绝。不创建假库存,不自动改配,不重复扣减预留;关联后旧容量失效须核对,审核/装载/发车仍独立。
- “待我处理”使用scope=TODO,仅调度可读;未完成候选超过100条要求按客户或登记号缩小范围,实时投影后返回准确total并分页,普通列表仍数据库分页。仓库尚未实收的记录由仓库负责,不混入调度核量待办;收货阶段以批量权威状态读取,不逐行请求详情。
- 后续输入/返回和权限完整定义在`baiyue-firstleg/lastleg-service/src/main/resources/openapi/fleet-preparation-v1.yaml`;本次复用现有表,无新增SQL结构或权限码。