openapi: 3.0.3 info: title: 平台运输车次与资源分配 version: 1.0.0 description: >- 车次是一次实际运输的稳定业务编号,客户排车、库存和派送单继续保留各自客户归属。 本文件定义计划、资源分配及客户排车单关联命令;分配或关联不会扣库存或标记发车。 创建可暂不指定车与司机,幂等键按创建人隔离;相同键相同内容返回同一车次,不同内容拒绝。 正式分配要求在役海外车辆及已确认的托位/载重/容积,以及海外司机;司机按预计任务结束时间重新核验且验证证照文件。 发车预览与实际发车重新核对司机当前海外区域和身份;分配后档案变更不能沿用原分配时的资格结果。 一个车辆或司机同时只能占用一个未释放车次;当前不提供多个未来时段的并行预约。 改派先取得新资源,成功后释放旧资源;整次写入与历史处于同一事务。 司机预计结束包含承担的返程/转场;修改预计结束须重新核验司机,所有写命令使用recordVersion。 普通计划接口不提供修改发车或签收状态的入口;PDA统一发车,结案检查所有客户派送终态及实发数量。 货物结案不释放车辆或司机;结束各资源任务独立提交实际结束时间、地点和原因,车辆另确认可用/维修/停用/已归还状态。 结案和结束任务命令携带版本及幂等键;结束司机任务不要求其证照仍有效,也不自动恢复其派车资格。 关联要求已分配车和司机,客户排车单同起运仓且未开始拣货;可跨客户关联但不改变客户数据归属。 同一排车单唯一关联一个车次;关联、改派、解除及尚未执行的派送单车/司机快照同步使用同一事务。 关联后子排车不能独立编辑、取消或单独发车;取消车次前须解除关联,已开工不允许直接解除或变更路线。 发车前允许在车次统一换车、换司机或调整时间,保留全部拣货事实与客户归属;已确认装载须能容纳于替换车辆。 改派或调整计划使原装载确认失效,发车前须重新确认;不支持用计划接口处理在途换车或撤销已执行货物。 关联只建立执行单据关系,不代表实际装载量、容量核验或审核已完成。 每张客户排车单调度审核通过后允许新拣货;整车确认实际装载并通过理货审核后允许发车。 审核仅通过或打回,通过意见选填、打回原因必填;无需额外提交或不同审核人。 换车换司机、修改路线或时间使调度与理货审核待审;仅修改备注保留审核及装载。 关联变更、重新确认装载或重新审核客户排车单使理货审核待审;保留全部拣货事实及历史审核快照。 security: - bearerAuth: [] paths: /api/platform/v1/last-leg/fleet/trips: get: summary: 分页查询车次 description: '权限:platform:fleet:trip:list' parameters: - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}} - {name: size, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 20}} - {name: keyword, in: query, schema: {type: string, maxLength: 128}, description: 车次号/车牌/司机} - {name: status, in: query, schema: {type: string, enum: [PLANNED, IN_TRANSIT, COMPLETED, CANCELLED]}} - {name: warehouseId, in: query, schema: {type: string, pattern: '^[1-9][0-9]*$'}} responses: '200': description: 统一业务响应,data包含records/page/size/total/pages;不逐行请求司机详情 content: application/json: schema: allOf: - {$ref: '#/components/schemas/Envelope'} - properties: data: type: object properties: records: {type: array, items: {$ref: '#/components/schemas/Trip'}} page: {type: integer} size: {type: integer} total: {type: integer} pages: {type: integer} post: summary: 幂等创建车次计划 description: '权限:platform:fleet:trip:create;起运仓使用公共有效海外仓目录;不推断GPS路线。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/Create'}}}} responses: {'200': {$ref: '#/components/responses/Detail'}} /api/platform/v1/last-leg/fleet/trips/customer-options: get: summary: 查询有效委托客户候选 description: '权限:platform:fleet:trip:list;读取IAM当前客户主档;不使用采购历史或允许输入不存在的客户。' parameters: [{name: keyword, in: query, schema: {type: string}}] responses: {'200': {description: 统一响应data为客户id/code/name/contactName/contactPhone数组}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/bookings/quote-candidates: parameters: [{$ref: '#/components/parameters/TripNo'}] get: summary: 按本车真实起运仓及当地计划日期查询客户销售报价 description: '同时要求platform:fleet:trip:list与platform:fleet:quote:list。城市来自有效公共海外仓的唯一明确地址城市,日期为计划起运UTC时间转换到仓库明确时区;不接收浏览器城市或日期。目的地须为本车既有FBA卸货站;私人地址、缺失或歧义城市/时区明确拒绝查询,仍可手工询价。' parameters: - {name: customerId, in: query, required: true, schema: {type: integer, format: int64, minimum: 1}} - {name: destinationKey, in: query, required: true, schema: {type: string, maxLength: 160}} - {name: currency, in: query, required: true, schema: {type: string, enum: [CNY, USD]}} - {name: priceBasis, in: query, required: true, schema: {type: string, enum: [PALLET, ORDER]}} - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}} - {name: size, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}} responses: '200': description: 统一业务响应,data为报价来源候选分页;无价不列入,零价保留 content: application/json: schema: allOf: - {$ref: '#/components/schemas/Envelope'} - properties: data: type: object properties: records: {type: array, items: {$ref: 'fleet-quote-candidates-v1.yaml#/components/schemas/SourceSnapshot'}} page: {type: integer} size: {type: integer} total: {type: integer} pages: {type: integer} '403': {description: 缺少任一读取权限} '409': {description: 无法确定本车报价查询上下文} /api/platform/v1/last-leg/fleet/trips/{tripNo}/bookings: parameters: [{$ref: '#/components/parameters/TripNo'}] get: summary: 查询本车外接询价与承运预订 description: '权限:platform:fleet:trip:list;返回tripRecordVersion及records;约定金额不是应收或实收。' responses: {'200': {description: 统一响应data为版本及Booking数组}} post: summary: 登记外接询价 description: '权限:platform:fleet:trip:booking-create;DRAFT不占位。客户由IAM校验,报价和预计载荷可待确认再补;起点固定本起运仓,卸货站为既有路线站点。相同创建键与内容重放原预订。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BookingCreate'}}}} responses: {'200': {$ref: '#/components/responses/BookingResult'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/bookings/{bookingNo}: parameters: [{$ref: '#/components/parameters/TripNo'}, {$ref: '#/components/parameters/BookingNo'}] put: summary: 编辑尚未确认的外接询价 description: '权限:platform:fleet:trip:booking-edit;仅DRAFT;客户与预订业务编号不变,更新前核对车次及预订版本。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BookingUpdate'}}}} responses: {'200': {$ref: '#/components/responses/BookingResult'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/bookings/{bookingNo}/confirm: parameters: [{$ref: '#/components/parameters/TripNo'}, {$ref: '#/components/parameters/BookingNo'}] post: summary: 确认外接承运并占用计划容量 description: '权限:platform:fleet:trip:booking-confirm;父车次锁内核对来源仍有效的自有货容量计划及全部已确认预订;报价/币种/预计托位重量体积完整。幂等重放返回当前预订事实,不重复占位;确认不代表已收货、已发运或已入财务。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BookingCommand'}}}} responses: {'200': {$ref: '#/components/responses/BookingResult'}, '409': {description: 版本、资格或容量不满足}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/bookings/{bookingNo}/incoming: parameters: [{$ref: '#/components/parameters/TripNo'}, {$ref: '#/components/parameters/BookingNo'}] get: summary: 查询外接来货及实际测量依据 description: '权限:platform:fleet:trip:list;固定预订客户范围,返回tripRecordVersion、recordVersion与incoming;尚未登记时incoming为null,不逐行预取。' responses: {'200': {description: 统一响应data为版本及IncomingEvidence}} post: summary: 为已确认承运生成真实来货单 description: '权限:platform:fleet:trip:booking-edit;复用仓储转运创建/审核,在同一事务建立客户自送来货并关联预订;不写库存,不冒充实收;已有来货拒绝重复创建,同键同内容重放。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BookingIncoming'}}}} responses: {'200': {$ref: '#/components/responses/BookingResult'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/bookings/{bookingNo}/receipt-confirmation: parameters: [{$ref: '#/components/parameters/TripNo'}, {$ref: '#/components/parameters/BookingNo'}] post: summary: 运营确认委托方实收货量与运费 description: '权限:platform:fleet:trip:booking-confirm;实际来货已完成测量,receiptHash和实托集合一致,重新核算容量和约定金额,引用真实收货证据并确认原来货流程;不重复入库。差异必须显式确认,超容量回滚。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BookingAcceptReceipt'}}}} responses: {'200': {$ref: '#/components/responses/BookingResult'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/bookings/{bookingNo}/dispatch: parameters: [{$ref: '#/components/parameters/TripNo'}, {$ref: '#/components/parameters/BookingNo'}] post: summary: 将外接实收货物关联客户排车 description: '权限:同时要求platform:fleet:trip:booking-edit和platform:fleet:trip:edit;排车必须同客户同仓,完整包含预订来货的实收托盘与数量且目的地一致;原子绑定共享车次,防止绕过预订挂到其他车次。解除未开工关联后回到RECEIVED并重新预留容量,已拣货不允许直接解除。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BookingBindDispatch'}}}} responses: {'200': {$ref: '#/components/responses/BookingResult'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/bookings/{bookingNo}/cancel: parameters: [{$ref: '#/components/parameters/TripNo'}, {$ref: '#/components/parameters/BookingNo'}] post: summary: 取消未执行的外接预订并释放容量 description: '权限:platform:fleet:trip:booking-cancel;仅计划中车次的DRAFT/CONFIRMED/RECEIVED;只释放承运预留,不删除来货或库存;同键同内容重放不重复释放,历史保留报价及承运确认。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BookingCommand'}}}} responses: {'200': {$ref: '#/components/responses/BookingResult'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}: parameters: [{$ref: '#/components/parameters/TripNo'}] get: summary: 查询车次详情和当前司机资格 description: '权限:platform:fleet:trip:list;司机资格仅是详情预览,实际命令必须重新核验。' responses: {'200': {$ref: '#/components/responses/Detail'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/dispatches/{dispatchNo}/review: parameters: - {$ref: '#/components/parameters/TripNo'} - {name: dispatchNo, in: path, required: true, schema: {type: string}} post: summary: 通过或打回单张客户排车调度审核 description: '权限:platform:fleet:trip:dispatch-review;仅PLANNED;审核所属车次内的排车单,成功后理货审核待审;审批不扣库存。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/Review'}}}} responses: {'200': {$ref: '#/components/responses/Detail'}, '409': {description: 版本、关联或资格冲突}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/loading-review: parameters: [{$ref: '#/components/parameters/TripNo'}] post: summary: 通过或打回整车理货审核 description: '权限:platform:fleet:trip:loading-review;仅PLANNED;通过要求全部调度审核、拣货和实际装载确认已完成,当前司机资格有效。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/Review'}}}} responses: {'200': {$ref: '#/components/responses/Detail'}, '409': {description: 版本、调度审核、装载或资格冲突}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/plan: parameters: [{$ref: '#/components/parameters/TripNo'}] put: summary: 修改计划时间和路线 description: '权限:platform:fleet:trip:edit;仅PLANNED;司机预计结束变更重新核验;原因必填。已开始拣货时路线须完全一致,仅可调整时间和备注;调整时间使审核及装载确认失效,仅修改备注保留。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/Plan'}}}} responses: {'200': {$ref: '#/components/responses/Detail'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/assignment: parameters: [{$ref: '#/components/parameters/TripNo'}] post: summary: 分配或更换车辆与司机 description: '权限:platform:fleet:trip:assign;仅PLANNED且全部关联单未发车、未出库;允许已拣货时统一改派并同步派送快照,保留拣货和到达时间。替换车辆须满足已确认装载容量,成功后清除原装载确认并重新核验;行锁和唯一占用键防重复派车,资格校验不得通过人工审核绕过。' requestBody: required: true content: application/json: schema: type: object required: [recordVersion, vehicleId, driverId, reason] properties: recordVersion: {type: integer, format: int64, minimum: 0} vehicleId: {type: string, pattern: '^[1-9][0-9]*$'} driverId: {type: string, pattern: '^[1-9][0-9]*$'} reason: {type: string, minLength: 1, maxLength: 1000} responses: {'200': {$ref: '#/components/responses/Detail'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/cancel: parameters: [{$ref: '#/components/parameters/TripNo'}] post: summary: 取消计划并释放车和司机 description: '权限:platform:fleet:trip:cancel;仅PLANNED;保留车次快照和历史。已执行货物后续须按实际执行状态校验,不允许取消抹除作业事实。' requestBody: required: true content: application/json: schema: type: object required: [recordVersion, reason] properties: recordVersion: {type: integer, format: int64, minimum: 0} reason: {type: string, minLength: 1, maxLength: 1000} responses: {'200': {$ref: '#/components/responses/Detail'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/dispatches/bind: parameters: [{$ref: '#/components/parameters/TripNo'}] post: summary: 将客户排车单关联到车次 description: '权限:platform:fleet:trip:edit;按业务单号解析客户归属,同仓且未开工;关联、车/司机快照同步及按真实货物目的地标识补齐卸货站原子提交;目的地缺失拒绝关联,已有有效站点顺序与索引保留,初始默认占位站替换为真实目的地。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BindingCommand'}}}} responses: {'200': {$ref: '#/components/responses/Detail'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/dispatches/unbind: parameters: [{$ref: '#/components/parameters/TripNo'}] post: summary: 解除尚未执行的客户排车单关联 description: '权限:platform:fleet:trip:edit;清除排车及派送单当前车辆司机快照,历史保留;已拣货禁止直接解除。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BindingCommand'}}}} responses: {'200': {$ref: '#/components/responses/Detail'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/history: parameters: [{$ref: '#/components/parameters/TripNo'}] get: summary: 分页读取车次操作历史 description: '权限:platform:fleet:trip:list;版本倒序;不将历史快照当作当前资格。' parameters: - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}} - {name: size, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 20}} responses: '200': description: 统一响应;data为PageResult,records项包含recordVersion/action/reason/operatorId/occurredAt/snapshot,snapshot包含trip、带review的dispatches、capacityPlan、confirmedLoad、completion及loadingReview、externalBookings不可变快照 /api/platform/v1/last-leg/fleet/trips/{tripNo}/capacity-plan: parameters: [{$ref: '#/components/parameters/TripNo'}] get: summary: 读取拣货前计划载荷和逐段余位 description: '权限:platform:fleet:trip:list;按当前关联货物返回manifestHash;planValid为false表示尚未核对或来源已经变化,不能据旧计划承诺外接运力。' responses: '200': {description: 统一响应data为Planning, content: {application/json: {schema: {$ref: '#/components/schemas/PlanningEnvelope'}}}} post: summary: 核对本车货物计划载荷 description: '权限:platform:fleet:trip:edit;仅PLANNED;允许尚未拣货或审核,通过实托去重及逐段容量检查。保存计划不推进审核、库存或发车,不代替实际装载确认;调整计划/资源/关联使容量计划失效,纯备注保留。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/ConfirmLoad'}}}} responses: '200': {description: 已保存容量计划, content: {application/json: {schema: {$ref: '#/components/schemas/PlanningEnvelope'}}}} '409': {description: 版本、来源变化或容量超限} /api/platform/v1/last-leg/fleet/trips/{tripNo}/loading: parameters: [{$ref: '#/components/parameters/TripNo'}] get: summary: 读取整车实物装载核对依据 description: '权限:platform:fleet:trip:list;返回各客户货物组成、manifestHash和当前装载确认,实际重量不得使用计费材积重。' responses: '200': {description: 统一响应data为Loading, content: {application/json: {schema: {$ref: '#/components/schemas/LoadingEnvelope'}}}} post: summary: 确认整车实际装载及逐段容量 description: '权限:platform:fleet:trip:edit;全部客户拣货核平且转派送后确认;同一实物托盘只计量一次。货物hash或车次版本变化拒绝,托盘卸货站须匹配原货物目的地。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/ConfirmLoad'}}}} responses: '200': {description: 已确认装载快照,统一响应data为Loading, content: {application/json: {schema: {$ref: '#/components/schemas/LoadingEnvelope'}}}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/completion: parameters: [{$ref: '#/components/parameters/TripNo'}] get: summary: 核对各客户货物是否全部结束履约 description: '权限:platform:fleet:trip:list;返回tripNo、recordVersion、canComplete、blockReason、outcomes。签收以signedAt为准,退回须有RETURN_COMPLETED操作事实,不以updatedAt代替实际终态时间。' responses: '200': {description: 统一响应data包含结案检查结果与逐张派送Outcome, content: {application/json: {schema: {$ref: '#/components/schemas/CompletionEnvelope'}}}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/complete: parameters: [{$ref: '#/components/parameters/TripNo'}] post: summary: 核对全部货物并结案车次 description: '权限:platform:fleet:trip:complete;仅IN_TRANSIT,实发数量由全部已签收或已真实退回派送单覆盖;拒收、待退回、取消不算终态完成。不改写客户单、不新增收费、不释放资源;同键同内容重放,旧版本或不同内容拒绝。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/Complete'}}}} responses: {'200': {$ref: '#/components/responses/Detail'}} /api/platform/v1/last-leg/fleet/trips/{tripNo}/resources/release: parameters: [{$ref: '#/components/parameters/TripNo'}] post: summary: 单独结束车辆或司机本次任务并释放占用 description: '权限:platform:fleet:trip:release;货物结案后才允许;实际结束时间不早于货物完成且不晚于当前时间,地点及原因必填。车辆状态与释放同事务更新;司机可继续返程而保持占用。原请求重放不释放后来另一个车次的占用。' requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/Release'}}}} responses: {'200': {$ref: '#/components/responses/Detail'}} components: securitySchemes: bearerAuth: {type: http, scheme: bearer, bearerFormat: JWT} parameters: BookingNo: name: bookingNo in: path required: true schema: {type: string} TripNo: {name: tripNo, in: path, required: true, schema: {type: string}} responses: BookingResult: description: 统一响应data含tripRecordVersion、booking及replayed;客户端使用当前状态,重放不覆盖后续已发生的取消 content: application/json: schema: allOf: - {$ref: '#/components/schemas/Envelope'} - properties: data: type: object properties: tripRecordVersion: {type: integer, format: int64} booking: {$ref: '#/components/schemas/Booking'} replayed: {type: boolean} Detail: description: 统一响应,code为200代表成功,data为车次详情;业务冲突使用业务错误,不降级为成功 content: application/json: schema: allOf: - {$ref: '#/components/schemas/Envelope'} - properties: data: type: object properties: trip: {$ref: '#/components/schemas/Trip'} dispatches: {type: array, items: {$ref: '#/components/schemas/DispatchBinding'}} loadingReview: {$ref: '#/components/schemas/ReviewState'} driverQualification: type: object nullable: true description: 未分配司机为null;字段与fleet-drivers-v1的Qualification一致 properties: canDispatch: {type: boolean} expiringSoon: {type: boolean} reason: {type: string} licenseExpiresOn: {type: string, format: date, nullable: true} schemas: BookingCargo: type: object required: [destinationKey] properties: destinationKey: {type: string, maxLength: 160} cargoName: {type: string, nullable: true, maxLength: 255} packageCount: {type: integer, nullable: true, minimum: 1, description: 询价未知可为空,确认承运前必须补齐正数箱数} palletSpaces: {type: integer, nullable: true, minimum: 1} weightKg: {type: number, nullable: true, minimum: 0.001} volumeCbm: {type: number, nullable: true, minimum: 0.001} priceBasis: {type: string, nullable: true, enum: [PALLET, ORDER], description: 为空时默认PALLET} unitPrice: {type: number, nullable: true, minimum: 0, multipleOf: 0.01} currency: {type: string, nullable: true, maxLength: 3} contactName: {type: string, nullable: true, maxLength: 128} contactPhone: {type: string, nullable: true, maxLength: 128} remark: {type: string, nullable: true, maxLength: 1000} IncomingEvidence: type: object properties: incomingNo: {type: string} inboundCode: {type: string} warehouseId: {type: string} destinationKey: {type: string} status: {type: string} receiptHash: {type: string, description: 实托、数量、实测值及来源匹配摘要,不包含可变作业状态} receivedPackages: {type: integer} pallets: type: array items: type: object properties: warehousePalletId: {type: string} palletNo: {type: string} packages: {type: integer} weightKg: {type: number, nullable: true} volumeCbm: {type: number, nullable: true} BookingIncoming: allOf: - {$ref: '#/components/schemas/BookingCommand'} - properties: estimatedArrivalAt: {type: string, format: date-time, nullable: true, description: 缺省为计划发车前2小时的预计值} deliveryInstructions: {type: string, nullable: true, maxLength: 1000} privateAddress: {type: string, nullable: true, maxLength: 1000} postalCode: {type: string, nullable: true, maxLength: 32} recipientName: {type: string, nullable: true, maxLength: 128} recipientPhone: {type: string, nullable: true, maxLength: 64} BookingPalletSpaces: type: object required: [warehousePalletId, palletSpaces] properties: warehousePalletId: {type: string} palletSpaces: {type: integer, minimum: 1} BookingAcceptReceipt: allOf: - {$ref: '#/components/schemas/BookingCommand'} - required: [receiptHash, pallets, unitPrice] properties: receiptHash: {type: string} pallets: {type: array, minItems: 1, items: {$ref: '#/components/schemas/BookingPalletSpaces'}} unitPrice: {type: number, minimum: 0, multipleOf: 0.01} BookingBindDispatch: allOf: - {$ref: '#/components/schemas/BookingCommand'} - required: [dispatchNo] properties: dispatchNo: {type: string, maxLength: 64} BookingCreate: type: object required: [tripRecordVersion, customerId, cargo, idempotencyKey] properties: tripRecordVersion: {type: integer, format: int64, minimum: 0} customerId: {type: string, pattern: '^[1-9][0-9]*$'} quoteRef: {$ref: '#/components/schemas/BookingQuoteRef'} cargo: {$ref: '#/components/schemas/BookingCargo'} idempotencyKey: {type: string, minLength: 8, maxLength: 128} BookingUpdate: type: object required: [tripRecordVersion, recordVersion, cargo] properties: tripRecordVersion: {type: integer, format: int64, minimum: 0} recordVersion: {type: integer, format: int64, minimum: 0} quoteRef: {$ref: '#/components/schemas/BookingQuoteRef'} cargo: {$ref: '#/components/schemas/BookingCargo'} BookingQuoteRef: type: object nullable: true description: '选填;null或省略为手工询价。引用或清除已有来源另要求platform:fleet:quote:list。服务端在承运写事务内锁定并核对精确版本、SALE/ACTIVE、客户、路线、币种、仓库当地计划日期及价项;只保存可信来源,不接收浏览器快照。PALLET选LOOSE_DELIVERY,ORDER选FULL_DELIVERY。' allOf: [{$ref: 'fleet-quote-candidates-v1.yaml#/components/schemas/QuoteRef'}] BookingCommand: type: object required: [tripRecordVersion, recordVersion, idempotencyKey] properties: tripRecordVersion: {type: integer, format: int64, minimum: 0} recordVersion: {type: integer, format: int64, minimum: 0} idempotencyKey: {type: string, minLength: 8, maxLength: 128} reason: {type: string, nullable: true, maxLength: 1000} Booking: type: object properties: offerNo: {type: string, nullable: true, description: 来源拼车发布号,池来源的成交和取消必须经专用接口} expectedPalletCount: {type: integer, nullable: true, minimum: 1, description: 预计实托数,不等同托位} bookingNo: {type: string} tripNo: {type: string} customerId: {type: string} customerCode: {type: string} customerName: {type: string} status: {type: string, enum: [DRAFT, CONFIRMED, RECEIVED, BOUND, CANCELLED]} cargo: {$ref: '#/components/schemas/BookingCargo'} quoteSource: type: object nullable: true description: '可信报价来源,独立于cargo.unitPrice及agreedAmount。确认承运重新核对报价及当前计划日期;确认后的报价变更或实收议价不覆盖已保存来源。' allOf: [{$ref: 'fleet-quote-candidates-v1.yaml#/components/schemas/SourceSnapshot'}] destinationLabel: {type: string} agreedAmount: {type: number, nullable: true, description: 约定运费,非财务应收或实收} incomingNo: {type: string, nullable: true} dispatchNo: {type: string, nullable: true} receipt: type: object nullable: true properties: source: {$ref: '#/components/schemas/IncomingEvidence'} pallets: {type: array, items: {$ref: '#/components/schemas/BookingPalletSpaces'}} operatorId: {type: string} confirmedAt: {type: string, format: date-time} recordVersion: {type: integer, format: int64} updatedAt: {type: string, format: date-time} Outcome: description: packages保留原实发量;signedPackages为不可变实签量,returnedPackages只计原运输实际退回,remainingPackages必须为零且三者守恒才可结案。签收后的另行退货不重开原运输。 type: object properties: dispatchNo: {type: string} deliveryNo: {type: string} customerId: {type: string} destination: {type: string, nullable: true} status: {type: string} packages: {type: integer} terminalAt: {type: string, format: date-time, nullable: true} signedPackages: {type: integer, minimum: 0} returnedPackages: {type: integer, minimum: 0} remainingPackages: {type: integer, minimum: 0} CompletionEnvelope: allOf: - {$ref: '#/components/schemas/Envelope'} - properties: data: type: object properties: tripNo: {type: string} recordVersion: {type: integer, format: int64} canComplete: {type: boolean} blockReason: {type: string, nullable: true} outcomes: {type: array, items: {$ref: '#/components/schemas/Outcome'}} Complete: type: object required: [recordVersion, idempotencyKey, reason] properties: recordVersion: {type: integer, format: int64, minimum: 0} idempotencyKey: {type: string, minLength: 8, maxLength: 128} reason: {type: string, minLength: 1, maxLength: 1000} Release: type: object required: [recordVersion, resourceKind, actualEndAt, endLocation, idempotencyKey, reason] properties: recordVersion: {type: integer, format: int64, minimum: 0} resourceKind: {type: string, enum: [VEHICLE, DRIVER]} actualEndAt: {type: string, format: date-time} endLocation: {type: string, minLength: 1, maxLength: 500} vehicleStatus: {type: string, nullable: true, enum: [IN_SERVICE, MAINTENANCE, INACTIVE, RETURNED], description: 结束车辆任务必填,结束司机任务必须为空} idempotencyKey: {type: string, minLength: 8, maxLength: 128} reason: {type: string, minLength: 1, maxLength: 1000} ReleaseInfo: type: object nullable: true properties: actualEndAt: {type: string, format: date-time} endLocation: {type: string} vehicleStatus: {type: string, nullable: true, description: 结束本次车辆任务时的状态快照,不代表车辆此后的实时可派状态} LoadingEnvelope: allOf: - {$ref: '#/components/schemas/Envelope'} - properties: data: type: object properties: tripNo: {type: string} recordVersion: {type: integer, format: int64} manifestHash: {type: string} cargo: {type: array, items: {$ref: '#/components/schemas/Cargo'}} blockReason: {type: string, nullable: true} confirmedLoad: type: object nullable: true properties: manifestHash: {type: string} cargo: {type: array, items: {$ref: '#/components/schemas/Cargo'}} pallets: {type: array, items: {$ref: '#/components/schemas/Measurement'}} segments: {type: array, items: {type: object}, description: 逐段fromIndex/toIndex及occupied/remaining托位、weightKg、volumeCbm} operatorId: {type: string} confirmedAt: {type: string, format: date-time} Cargo: type: object properties: dispatchNo: {type: string} customerId: {type: string} dispatchItemId: {type: string} warehousePalletId: {type: string, nullable: true} palletNo: {type: string, nullable: true} packages: {type: integer} destinationKey: {type: string, nullable: true, description: 原货物目的地稳定匹配键,选择路线站点时透传} destinationLabel: {type: string, nullable: true} Measurement: type: object required: [warehousePalletId, palletSpaces, weightKg, volumeCbm, deliveryIndex] properties: warehousePalletId: {type: string} palletSpaces: {type: integer, minimum: 1} weightKg: {type: number, minimum: 0.001, multipleOf: 0.001, maximum: 999999999.999} volumeCbm: {type: number, minimum: 0.001, multipleOf: 0.001, maximum: 999999999.999} deliveryIndex: {type: integer, minimum: 1, description: 卸货站索引,起运仓固定为0} PlanningEnvelope: allOf: - {$ref: '#/components/schemas/Envelope'} - properties: data: type: object properties: tripNo: {type: string} recordVersion: {type: integer, format: int64} cargo: {type: array, items: {$ref: '#/components/schemas/Cargo'}} manifestHash: {type: string} planValid: {type: boolean, description: 计划已经核对且来源hash仍一致} availableSegments: {type: array, items: {$ref: '#/components/schemas/Segment'}, description: 当前自有货计划加已确认外接预订后的逐段占用与余位;计划失效返回空数组} blockReason: {type: string, nullable: true} capacityPlan: type: object nullable: true description: 计划值,不能作为实际装载确认 properties: manifestHash: {type: string} cargo: {type: array, items: {$ref: '#/components/schemas/Cargo'}} pallets: {type: array, items: {$ref: '#/components/schemas/Measurement'}} segments: {type: array, items: {$ref: '#/components/schemas/Segment'}} operatorId: {type: string} confirmedAt: {type: string, format: date-time} Segment: type: object properties: fromIndex: {type: integer} toIndex: {type: integer} occupied: {$ref: '#/components/schemas/CapacityLoad'} remaining: {$ref: '#/components/schemas/CapacityLoad'} CapacityLoad: type: object properties: palletSpaces: {type: integer} weightKg: {type: number} volumeCbm: {type: number} ConfirmLoad: type: object required: [recordVersion, manifestHash, pallets, reason] properties: recordVersion: {type: integer, format: int64, minimum: 0} manifestHash: {type: string, pattern: '^[0-9a-f]{64}$'} pallets: {type: array, minItems: 1, maxItems: 1000, items: {$ref: '#/components/schemas/Measurement'}} reason: {type: string, minLength: 1, maxLength: 1000} BindingCommand: type: object required: [recordVersion, dispatchNo, reason] properties: recordVersion: {type: integer, format: int64, minimum: 0} dispatchNo: {type: string, minLength: 1, maxLength: 64} reason: {type: string, minLength: 1, maxLength: 1000} Review: type: object required: [recordVersion, decision] properties: recordVersion: {type: integer, format: int64, minimum: 0} decision: {type: string, enum: [APPROVED, REJECTED]} reason: {type: string, nullable: true, maxLength: 1000, description: 通过选填;打回必填} ReviewState: type: object required: [status] properties: status: {type: string, enum: [PENDING, APPROVED, REJECTED]} reason: {type: string, nullable: true} reviewerId: {type: string, nullable: true} reviewedAt: {type: string, format: date-time, nullable: true} recordVersion: {type: integer, format: int64, nullable: true, description: 本次审核所核对的车次版本} DispatchBinding: type: object properties: dispatchNo: {type: string} customerId: {type: string, description: 排车单自身客户归属,由服务端解析} packageCount: {type: integer, description: 关联时待发运箱数,不是实物托位数} boundBy: {type: string} boundAt: {type: string, format: date-time} review: {$ref: '#/components/schemas/ReviewState'} Envelope: type: object properties: code: {type: string} message: {type: string, nullable: true} data: {type: object, nullable: true} Stop: type: object required: [name] properties: name: {type: string, minLength: 1, maxLength: 128} address: {type: string, nullable: true, maxLength: 500} destinationKey: {type: string, nullable: true, maxLength: 160, description: 卸货站匹配Loading货物的destinationKey;未配置时可以保存计划但不能确认装载} Create: type: object required: [warehouseId, plannedDepartureAt, expectedDriverEndAt, stops, idempotencyKey] properties: warehouseId: {type: string, pattern: '^[1-9][0-9]*$'} plannedDepartureAt: {type: string, format: date-time} expectedDriverEndAt: {type: string, format: date-time} stops: {type: array, minItems: 2, maxItems: 200, items: {$ref: '#/components/schemas/Stop'}} remark: {type: string, nullable: true, maxLength: 1000} idempotencyKey: {type: string, minLength: 8, maxLength: 128} Plan: type: object required: [recordVersion, plannedDepartureAt, expectedDriverEndAt, stops, reason] properties: recordVersion: {type: integer, format: int64, minimum: 0} plannedDepartureAt: {type: string, format: date-time} expectedDriverEndAt: {type: string, format: date-time} stops: {type: array, minItems: 2, maxItems: 200, items: {$ref: '#/components/schemas/Stop'}} remark: {type: string, nullable: true, maxLength: 1000} reason: {type: string, minLength: 1, maxLength: 1000} Trip: type: object properties: tripNo: {type: string} status: {type: string, enum: [PLANNED, IN_TRANSIT, COMPLETED, CANCELLED]} warehouseId: {type: string} warehouseCode: {type: string} warehouseName: {type: string} vehicleId: {type: string, nullable: true} vehiclePlate: {type: string, nullable: true} driverId: {type: string, nullable: true} driverName: {type: string, nullable: true} driverPhone: {type: string, nullable: true} maxPalletSpaces: {type: integer, nullable: true} maxLoadKg: {type: number, nullable: true} maxVolumeCbm: {type: number, nullable: true} plannedDepartureAt: {type: string, format: date-time} expectedDriverEndAt: {type: string, format: date-time} departedAt: {type: string, format: date-time, nullable: true} completedAt: {type: string, format: date-time, nullable: true} stops: {type: array, items: {$ref: '#/components/schemas/Stop'}} remark: {type: string, nullable: true} recordVersion: {type: integer, format: int64} updatedAt: {type: string, format: date-time} vehicleRelease: {$ref: '#/components/schemas/ReleaseInfo'} driverRelease: {$ref: '#/components/schemas/ReleaseInfo'}