openapi: 3.0.3 info: title: Lastleg Overseas Business API description: 派送资料完整契约见同目录 delivery-documents-v1.yaml;派送列表/详情行返回 bolNo、documentSummary(三类状态与x/3),状态仍使用 version 和 allowedActions。 version: 1.0.0 paths: /api/platform/v1/last-leg/inventory/balances/{balanceId}: get: summary: 查询单条库存余额详情 description: 仅平台且要求 lastleg:inventory:list;按 balanceId 直接查询非零库存余额,不依赖列表分页。可选 customerId 用于精确客户隔离,越权或不存在统一返回404。 security: [{ bearerAuth: [] }] parameters: - { in: path, name: balanceId, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$', description: 长整型ID按字符串传输 } } - { in: query, name: customerId, required: false, schema: { type: string } } responses: '200': { description: 单条库存余额, content: { application/json: { schema: { $ref: '#/components/schemas/InventoryBalanceApiResponse' } } } } '403': { description: 非平台身份或缺少库存查看权限 } '404': { description: 库存余额不存在、已归零或不属于指定客户 } /api/platform/v1/last-leg/inventory/inbound-code-relationships/{inboundCode}: get: summary: 按入仓码查询海外关系摘要 description: 仅平台且要求 lastleg:inventory:list;不接收customerId,不跨国内数据库查询,未命中返回found=false和空关系。 security: [{ bearerAuth: [] }] parameters: - { in: path, name: inboundCode, required: true, schema: { type: string, minLength: 1, maxLength: 128 } } responses: '200': { description: 海外订单、计划、收货、托盘和库存业务关系, content: { application/json: { schema: { $ref: '#/components/schemas/InboundCodeRelationshipApiResponse' } } } } '403': { description: 非平台身份或缺少库存查看权限 } '409': { description: 入仓码跨客户或快照关系不一致 } /api/pda/v1/last-leg/receiving-containers/candidates: get: summary: 查询当前客户待签收柜号 description: 权限 lastleg:pda:operate;仅 PLATFORM OVERSEAS_WAREHOUSE_PDA_OPERATOR 可用;仅返回已单调消费 PICKUP_READY(80) 或更高实际船节点、状态为 RECEIVING_AVAILABLE 的柜,不接收 customerId。 security: [{ bearerAuth: [] }] responses: { '200': { description: 柜号候选及箱数进度, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingCandidateListApiResponse' } } } }, '403': { description: 缺少 PDA 操作权限 } } /api/pda/v1/last-leg/receiving-containers/warehouse-profile: get: summary: 查询当前PDA账号绑定的海外仓主档 description: 权限 lastleg:pda:operate;仓库ID只取Token,名称与编码由共享仓库主档实时解析,不接收warehouseId参数。 security: [{ bearerAuth: [] }] responses: { '200': { description: 当前绑定仓库中文名称与编码, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingWarehouseProfileApiResponse' } } } }, '403': { description: 账号未绑定有效海外仓 } } /api/pda/v1/last-leg/receiving-containers/{containerNo}: get: summary: 查询待签收柜号详情 description: 权限 lastleg:pda:operate;按柜号唯一解析客户并返回柜内全部入仓码、目的类型、目的仓、托数和实收进度。 security: [{ bearerAuth: [] }] parameters: [{ name: containerNo, in: path, required: true, schema: { type: string } }] responses: { '200': { description: 柜号详情, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingSessionApiResponse' } } } }, '409': { description: 当前账号已锁定其他柜号 } } /api/pda/v1/last-leg/receiving-containers/{containerNo}/prepare: post: summary: 选择当前待签收柜号 description: 权限 lastleg:pda:operate;仅 RECEIVING_AVAILABLE 柜可建立 WAIT_SIGN 会话,并以平台操作账号、柜号全局双唯一键防止切柜或多人同时处理。 security: [{ bearerAuth: [] }] parameters: [{ name: containerNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingAction' } } } } responses: { '200': { description: 当前柜会话, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingSessionApiResponse' } } } }, '409': { description: 账号或柜号已有未完成会话 } } /api/pda/v1/last-leg/receiving-containers/current/unload-photos/files: post: summary: 上传当前柜签收照片 description: 权限 lastleg:pda:operate;multipart 文件归属当前 WAIT_SIGN 会话。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { multipart/form-data: { schema: { type: object, required: [file], properties: { file: { type: string, format: binary } } } } } } responses: { '200': { description: 文件标识, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingPhotoApiResponse' } } } }, '409': { description: 当前柜已签收 } } /api/pda/v1/last-leg/receiving-containers/current/unload-photos/files/{fileId}/download: get: summary: 下载当前柜签收照片 description: 权限 lastleg:pda:operate;仅允许下载当前会话已签收角色绑定的照片。 security: [{ bearerAuth: [] }] parameters: - { name: fileId, in: path, required: true, schema: { type: string, pattern: '^[1-9][0-9]{0,18}$' } } responses: '200': description: 签收照片字节流;Content-Type 透传文件类型,缺失时为 application/octet-stream;Content-Disposition 为 inline;Cache-Control 为 no-store。 headers: Content-Disposition: { schema: { type: string }, description: inline 文件名 } Cache-Control: { schema: { type: string, example: no-store } } content: image/jpeg: { schema: { type: string, format: binary } } image/png: { schema: { type: string, format: binary } } application/octet-stream: { schema: { type: string, format: binary } } '403': { description: fileId 未绑定到当前操作员的当前柜会话三类签收照片 } '404': { description: 当前柜会话或照片不存在 } /api/pda/v1/last-leg/receiving-containers/current/sign: post: summary: 签收当前柜 description: 权限 lastleg:pda:operate;精确校验车牌、封签、开门三类照片各且仅 1 张及文件归属后由 WAIT_SIGN 推进 SIGNED;重拍由调用端在签收前替换对应槽位。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingSign' } } } } responses: { '200': { description: 已签收会话, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingSessionApiResponse' } } } }, '409': { description: 状态或照片校验失败 } } /api/pda/v1/last-leg/receiving-containers/current: get: summary: 恢复当前账号已签柜 description: 权限 lastleg:pda:operate;返回 WAIT_SIGN、SIGNED 或 RECEIVING 当前柜,不依赖 planNo。 security: [{ bearerAuth: [] }] responses: { '200': { description: 当前柜完整进度, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingSessionApiResponse' } } } }, '404': { description: 无当前柜 } } /api/pda/v1/last-leg/receiving-containers/current/cartons/resolve: post: summary: 解析当前柜箱唛 description: 权限 lastleg:pda:operate;FBA 从完整 cartonMark 的第一个 # 前提取固定入仓码,并精确匹配当前锁定柜唯一 FBA line;不要求逐箱 manifest,不校验 SKU 或箱序号。OVERSEAS 必须命中真实 manifest。两者均不返回 SKU,也不登记收货。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { type: object, required: [cartonMark], properties: { cartonMark: { type: string } } } } } } responses: { '200': { description: 箱唛与入仓码信息, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingCartonResolvedApiResponse' } } } }, '404': { description: 入仓码未命中当前柜,或 OVERSEAS 箱码未命中真实 manifest }, '409': { description: '缺少 #、空入仓码前缀、跨柜或当前柜多重命中' } } /api/pda/v1/last-leg/receiving-containers/current/pallets/resolve: post: summary: 解析当前柜实物托盘码 description: 权限 lastleg:pda:operate;托盘固定从 Warehouse Overseas 公共资源作用域解析并校验实际仓与目的仓。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { type: object, required: [palletCode, inboundCode], properties: { palletCode: { type: string }, inboundCode: { type: string } } } } } } responses: { '200': { description: 可用托盘与目的匹配结果, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingPalletResolvedApiResponse' } } } }, '409': { description: 仓库、目的仓或托盘状态不符 } } /api/pda/v1/last-leg/receiving-containers/current/receipts/bulk: post: summary: FBA 入仓码按箱数收货 description: 权限 lastleg:pda:operate;只允许 destinationType=FBA,OVERSEAS 在服务端硬拒绝;服务端按当前入仓码所属计划的 line.id ASC 和冻结 SKU 明细顺序拆分箱数并记录真实 SKU 收货;不接收 SKU、customerId、planNo、allocationId、warehouseId、locationId。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingBulk' } } } } responses: { '200': { description: 本次与累计实收进度, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingReceiptApiResponse' } } } }, '409': { description: 海外仓批量、超收或托盘不匹配 } } /api/pda/v1/last-leg/receiving-containers/current/receipts/carton: post: summary: 海外仓入仓码逐箱收货 description: 权限 lastleg:pda:operate;只允许 destinationType=OVERSEAS,拒绝跨柜、重复箱和不匹配托盘。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingCarton' } } } } responses: { '200': { description: 本次与累计实收进度, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingReceiptApiResponse' } } } }, '409': { description: FBA逐箱、跨柜、重复箱或托盘不匹配 } } /api/pda/v1/last-leg/receiving-containers/current/complete: post: summary: 完成当前柜收货并入库存 description: 权限 lastleg:pda:operate;仅柜内每个入仓码实收总数精确相等后完成,库存、计划、尾程状态与卸柜 Outbox 同事务落地。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingAction' } } } } responses: { '200': { description: COMPLETED 柜号会话, content: { application/json: { schema: { $ref: '#/components/schemas/ReceivingSessionApiResponse' } } } }, '409': { description: 数量未核平或状态冲突 } } /api/pda/v1/last-leg/inventory/resolve: post: summary: PDA按SKU、箱唛或入仓码扫码查询库存 description: 仅 OVERSEAS_WAREHOUSE_PDA_OPERATOR + lastleg:pda:operate;海外实际仓只取Token overseasWarehouseId,不接收客户或仓库参数。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/PdaWarehouseScan' } } } } responses: { '200': { description: 同仓跨客户库存与物理仓位事实, content: { application/json: { schema: { $ref: '#/components/schemas/PdaInventoryScanApiResponse' } } } }, '404': { description: A0404:当前绑定仓无匹配库存 } } /api/pda/v1/last-leg/locations/resolve: post: summary: PDA查询库位容量、状态与库存占用 description: 库位从Warehouse Overseas公共资源解析,并强制匹配Token绑定仓。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/PdaWarehouseScan' } } } } responses: { '200': { description: 库位物理事实及Lastleg库存占用汇总, content: { application/json: { schema: { $ref: '#/components/schemas/PdaLocationApiResponse' } } } }, '404': { description: A0404:库位不存在或跨仓 } } /api/pda/v1/last-leg/pallets/resolve: post: summary: PDA查询托盘、库位与绑定库存 description: 托盘从Warehouse Overseas公共资源解析;跨Token绑定仓返回A0409。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/PdaWarehouseScan' } } } } responses: { '200': { description: 托盘物理事实及Lastleg绑定库存, content: { application/json: { schema: { $ref: '#/components/schemas/PdaPalletApiResponse' } } } }, '409': { description: A0409:托盘属于其他仓 } } /api/pda/v1/last-leg/operations: get: summary: 查询当前PDA账号真实作业历史 description: 返回Token绑定仓内当前操作账号的柜号作业及盘点、移库、托盘、换标历史;不含出库或派送。 security: [{ bearerAuth: [] }] 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: operationType, in: query, schema: { type: string } } responses: { '200': { description: 真实作业历史分页, content: { application/json: { schema: { $ref: '#/components/schemas/PdaOperationPageApiResponse' } } } } } /api/platform/v1/last-leg/orders: get: summary: 分页查询尾程订单 description: 权限 platform:overseas-warehouse:last-mile-order:list;平台管理员省略 customerId 时查询全部客户。 security: [{ bearerAuth: [] }] 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: orderNo, in: query, schema: { type: string } } - { name: orderType, in: query, schema: { type: string, enum: [FIRST_LEG, RELABEL_APPLICATION, WAREHOUSE_TRANSFER, LOCAL_LOOSEBOARD, RETURN_RELABEL, ONE_CLICK_DROPSHIP] } } - { name: currentStatus, in: query, schema: { type: string } } - { name: inboundCode, in: query, schema: { type: string } } - { name: sourceOrderNo, in: query, schema: { type: string } } - { name: containerNo, in: query, schema: { type: string } } - { name: warehouse, in: query, description: 按尾程订单冻结的海外接柜仓名称或编码进行大小写无关的包含匹配, schema: { type: string } } - { name: transferWarehouseCode, in: query, schema: { type: string } } - { name: abnormal, in: query, schema: { type: boolean } } - { name: detained, in: query, schema: { type: boolean } } - { name: createdFrom, in: query, schema: { type: string, format: date-time } } - { name: createdTo, in: query, schema: { type: string, format: date-time } } responses: { '200': { description: 统一 ApiResponse 包装的尾程订单分页;列表行 destinationType 为 FBA 或 OVERSEAS;inboundCode 仅返回真实来源入仓码,无入仓关系的换标申请和本土散板为空 } } /api/platform/v1/last-leg/orders/{id}: get: summary: 查询尾程订单详情 description: 权限 platform:overseas-warehouse:last-mile-order:list;返回订单、货物、状态历史、费用明细和操作记录。 security: [{ bearerAuth: [] }] parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 } } - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } responses: '200': { description: 统一 ApiResponse 包装的尾程订单详情 } '404': { description: 尾程订单不存在或不属于查询客户 } /api/platform/v1/last-leg/orders/{id}/fees: post: summary: 新增尾程订单费用 description: 权限 platform:overseas-warehouse:last-mile-order:edit;在订单客户范围内创建统一费用来源并提交财务审核。 security: [{ bearerAuth: [] }] parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 } } - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } - { name: Idempotency-Key, in: header, required: true, schema: { type: string, minLength: 1, maxLength: 128 } } requestBody: required: true content: { application/json: { schema: { $ref: '#/components/schemas/LastMileFeeCreate' } } } responses: '200': { description: 新增后的费用明细, content: { application/json: { schema: { $ref: '#/components/schemas/LastMileFeeApiResponse' } } } } '404': { description: 尾程订单不存在或不属于操作客户 } /api/platform/v1/last-leg/orders/{id}/hold: put: summary: 设置或解除尾程订单暂扣 description: 权限 platform:overseas-warehouse:last-mile-order:edit;使用订单版本和 Idempotency-Key 原子写入计费标记、原因及不可变历史。已进入出库流程的订单不得新增暂扣;暂扣只作用于当前票,不影响同柜其他订单。 security: [{ bearerAuth: [] }] parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 } } - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } - { name: Idempotency-Key, in: header, required: true, schema: { type: string, minLength: 1, maxLength: 128 } } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/LastlegOrderHoldRequest' } responses: '200': { description: 暂扣状态已更新, content: { application/json: { schema: { type: object, properties: { code: { type: string }, data: { $ref: '#/components/schemas/LastlegOrderHoldResponse' } } } } } } '409': { description: 版本冲突、幂等键冲突、重复状态或订单已进入出库流程 } /api/platform/v1/last-leg/orders/{id}/manual-nodes: get: summary: 查询尾程订单人工展示节点 description: 权限 platform:overseas-warehouse:last-mile-order:list;人工覆盖开启后返回完整且固定顺序的8行快照,行值允许为空。 security: [{ bearerAuth: [] }] parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 } } - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } responses: { '200': { description: 完整人工展示节点快照 } } put: summary: 永久启用并保存尾程订单人工展示节点 description: 权限 platform:overseas-warehouse:last-mile-order:edit;提交完整8行快照且至少一个时间非空,使用订单版本和 Idempotency-Key;保存后 nodeSource 永久为 MANUAL,不回写柜节点,也不提供清除或恢复继承接口。 security: [{ bearerAuth: [] }] parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 } } - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } - { name: Idempotency-Key, in: header, required: true, schema: { type: string, minLength: 1, maxLength: 128 } } requestBody: required: true content: { application/json: { schema: { $ref: '#/components/schemas/LastlegOrderManualNodesRequest' } } } responses: '200': { description: 更新后的完整8行人工展示节点快照 } '409': { description: 订单版本或幂等键冲突 } /api/platform/v1/last-leg/orders/{id}/pallet-merge-required: put: summary: 设置尾程订单合托标记 description: 权限 platform:overseas-warehouse:last-mile-order:edit;标记后 PDA 扫描本单箱唛时返回合托提示;实际完成合托后不可取消。 security: [{ bearerAuth: [] }] parameters: - { name: id, in: path, required: true, schema: { type: integer, format: int64 } } - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } requestBody: required: true content: application/json: schema: type: object required: [palletMergeRequired] properties: { palletMergeRequired: { type: boolean } } responses: { '200': { description: 合托标记已更新 }, '409': { description: 已完成实际合托,不能修改标记 } } /api/platform/v1/last-leg/orders/pallet-merge-required/batch: put: summary: 批量设置同组合托标记 description: 权限 platform:overseas-warehouse:last-mile-order:edit;所选订单按同一合托批次原子标记或取消。 security: [{ bearerAuth: [] }] requestBody: required: true content: application/json: schema: type: object required: [orderIds, palletMergeRequired] properties: orderIds: { type: array, minItems: 1, uniqueItems: true, items: { type: integer, format: int64 } } palletMergeRequired: { type: boolean } responses: { '200': { description: 批量合托标记已更新 } } /api/platform/v1/last-leg/orders/export: get: summary: 导出筛选后的尾程订单 description: 权限 platform:overseas-warehouse:last-mile-order:export;筛选参数与列表一致,返回 UTF-8 CSV。 security: [{ bearerAuth: [] }] responses: { '200': { description: CSV 文件, content: { text/csv: { schema: { type: string, format: binary } } } } } /api/platform/v1/last-leg/orders/container-summaries: get: summary: 分页查询柜级入库计划进度 description: 权限 platform:overseas-warehouse:last-mile-order:list;平台跨客户按稳定 sourceContainerBookingId 服务端聚合,不受订单分页影响,返回全部稳定来源柜;全部入仓码均已生成有效独立计划的柜仍保留,供柜级接柜仓查询与修改,生成计划动作由 allPlansReady/pendingPlanCount 控制。containerNo 只返回装柜完成事件携带并规范化冻结的真实集装箱号,不从 cabinetNo、订单号或内部 ID 推导。plannedArrivalAt 仅来自装柜完成事件 estimatedWarehouseArrivalAt 冻结的 ll_order.estimated_warehouse_at;按该时间升序、null 最后、稳定柜 ID 升序。 security: [{ bearerAuth: [] }] 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: containerNo, in: query, schema: { type: string } } - { name: createdFrom, in: query, schema: { type: string, format: date-time } } - { name: createdTo, in: query, schema: { type: string, format: date-time } } responses: '200': description: 统一 ApiResponse 包装的柜级摘要分页 content: application/json: schema: type: object properties: code: { type: string, enum: ['200'] } data: type: object properties: page: { type: integer, format: int64 } size: { type: integer, format: int64 } total: { type: integer, format: int64 } pages: { type: integer, format: int64 } records: type: array items: { $ref: '#/components/schemas/ContainerPlanProgressSummary' } /api/platform/v1/last-leg/orders/container-summaries/{sourceContainerBookingId}: get: summary: 查询柜级入库计划进度详情 description: 权限 platform:overseas-warehouse:last-mile-order:list;按稳定柜 ID 返回柜内全部尾程订单、入仓码及各自计划状态,不受订单分页截断。 security: [{ bearerAuth: [] }] parameters: - { name: sourceContainerBookingId, in: path, required: true, schema: { type: string, minLength: 1, maxLength: 128 } } responses: '200': description: 统一 ApiResponse 包装的柜级进度详情 content: application/json: schema: type: object properties: code: { type: string, enum: ['200'] } data: { $ref: '#/components/schemas/ContainerPlanProgressDetail' } '404': { description: 稳定柜 ID 不存在 } /api/platform/v1/last-leg/orders/container-summaries/{sourceContainerBookingId}/receiving-warehouse: put: summary: 修改整柜海外接柜仓 description: 权限 platform:overseas-warehouse:last-mile-order:edit;目标必须为国内 Warehouse Service 有效 OVERSEAS 仓。使用柜级版本和 Idempotency-Key,事务内原子同步柜内全部尾程订单及已有入库计划;海外PDA一旦建立接柜会话即永久锁定。 security: [{ bearerAuth: [] }] parameters: - { name: sourceContainerBookingId, in: path, required: true, schema: { type: string, minLength: 1, maxLength: 128 } } - { name: Idempotency-Key, in: header, required: true, schema: { type: string, minLength: 1, maxLength: 255 } } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/ChangeReceivingWarehouseRequest' } responses: '200': { description: 更新后的柜级摘要, content: { application/json: { schema: { type: object, properties: { code: { type: string, enum: ['200'] }, data: { $ref: '#/components/schemas/ContainerPlanProgressSummary' } } } } } '400': { description: 请求无效或目标不是有效 OVERSEAS 仓 } '409': { description: 版本冲突、幂等键冲突或PDA接柜会话已建立 } /api/platform/v1/last-leg/orders/{id}/destination: put: summary: 将单票尾程订单转入 FBA 目的仓 description: 权限 platform:overseas-warehouse:last-mile-order:edit;目标必须来自国内 Warehouse Service 平台公共 ACTIVE FBA 主档,warehouseId/warehouseCode/warehouseName 必须与权威记录一致。实际海外收货仓、普通国内中转仓、停用仓或伪造字段均返回 A0400“所选FBA仓不存在或已停用”。 security: [{ bearerAuth: [] }] parameters: - { name: id, in: path, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/FbaTransferDestination' } responses: '200': { description: 统一 ApiResponse 包装的更新订单数 } '400': { description: 所选FBA仓不存在、已停用、类型错误或字段不一致 } '503': { description: 国内FBA仓权威主数据暂不可用,写入失败关闭 } /api/platform/v1/last-leg/orders/destination: put: summary: 批量将尾程订单转入 FBA 目的仓 description: 权限 platform:overseas-warehouse:last-mile-order:edit;一次校验国内 Warehouse Service 权威 FBA 主档后,在 Lastleg 事务内更新所选订单及冻结明细。目标仓必须为平台公共 ACTIVE FBA 且 ID/编码/名称完全一致。 security: [{ bearerAuth: [] }] parameters: - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/FbaBatchTransferDestination' } responses: '200': { description: 统一 ApiResponse 包装的更新订单数 } '400': { description: 所选FBA仓不存在、已停用、类型错误或字段不一致 } '503': { description: 国内FBA仓权威主数据暂不可用,写入失败关闭 } /api/platform/v1/last-leg/inbound-plans: get: summary: 平台分页查询海外入库订单 description: 权限 platform:overseas-warehouse:inbound-order:list;列表中的 overseasWarehouseCode/overseasWarehouseName 只取尾程订单预分配接柜仓事实,warehouseCode/warehouseName 仍表示目的仓。 security: [{ bearerAuth: [] }] parameters: - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } - { 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: planNo, in: query, schema: { type: string } } - { name: inboundCode, in: query, schema: { type: string } } - { name: lxCode, in: query, schema: { type: string } } - { name: status, in: query, schema: { type: string } } - { name: overseasWarehouseId, in: query, schema: { type: string } } - { name: destinationWarehouseCode, in: query, schema: { type: string } } - { name: warehouse, in: query, schema: { type: string } } - { name: fbaWarehouseCode, in: query, schema: { type: string } } - { name: appointmentStatus, in: query, schema: { type: string, enum: [UNAPPOINTED, PENDING, SUCCESS, FAILED, CANCELLED] } } - { name: dispatchStatus, in: query, schema: { type: string, enum: [UNSCHEDULED, SCHEDULED] } } - { name: createdFrom, in: query, schema: { type: string, format: date-time } } - { name: createdTo, in: query, schema: { type: string, format: date-time } } responses: { '200': { description: 平台入库订单分页, content: { application/json: { schema: { $ref: '#/components/schemas/InboundPlanPageResponse' } } } } } /api/platform/v1/last-leg/inbound-plans/{planNo}: get: summary: 平台查询海外入库订单详情 description: 权限 platform:overseas-warehouse:inbound-order:list;详情中的 overseasWarehouseCode/overseasWarehouseName 只取当前计划来源尾程订单的预分配接柜仓事实。 security: [{ bearerAuth: [] }] parameters: - { name: planNo, in: path, required: true, schema: { type: string } } - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } responses: '200': { description: 平台入库订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/InboundPlanDetailResponse' } } } } '404': { description: 入库订单不存在或不属于指定客户 } /api/platform/v1/last-leg/inbound-plans/manual: post: summary: 平台按单票手工生成入库计划 description: 权限 platform:overseas-warehouse:inbound-order:create;按 customerId 与 orderId 锁定单票,校验订单版本、状态、暂扣状态、真实入仓码、客户归属及有效公共接柜仓。一次只生成当前票的独立计划,不改变同柜其他订单;命令原子且幂等。 security: [{ bearerAuth: [] }] parameters: - { name: Idempotency-Key, in: header, required: true, schema: { type: string, minLength: 1, maxLength: 128 } } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/ManualInboundPlanRequest' } responses: '200': { description: 统一 ApiResponse 包装的入库计划详情 } '400': { description: 客户、入仓码、仓库主数据或请求字段无效 } '409': { description: 订单版本、状态、暂扣状态、重复计划或幂等键冲突 } /api/platform/v1/last-leg/inbound-plans/convert-container: post: summary: 按整柜批量生成剩余入库计划 description: 权限 platform:overseas-warehouse:inbound-order:create;调用方必须先取柜级预览并原样回传 snapshotVersion/snapshotHash。服务端以 sourceContainerBookingId 建立唯一 Saga 命令,先向海外仓资源服务按票、按托盘批量预留真实 palletId/palletCode/locationId/resourceLockId,再在一个本地事务中锁整柜并为每票生成独立计划,最后确认资源批次。本地任一票失败时整柜回滚并补偿资源;本地已提交但远端确认失败时重放只重试确认。同柜不同 Idempotency-Key 也不会产生第二批资源。 security: [{ bearerAuth: [] }] parameters: - { name: Idempotency-Key, in: header, required: true, schema: { type: string, minLength: 1, maxLength: 128 } } requestBody: required: true content: application/json: schema: type: object required: [sourceContainerBookingId, snapshotVersion, snapshotHash] properties: sourceContainerBookingId: { type: string, minLength: 1, maxLength: 128 } snapshotVersion: { type: integer, format: int64, minimum: 0 } snapshotHash: { type: string, pattern: '^[0-9a-f]{64}$' } responses: { '200': { description: 统一 ApiResponse 包装的入库计划数组 } } /api/platform/v1/last-leg/inbound-plans/container-preview: get: summary: 预览按柜生成入库计划 description: 权限 platform:overseas-warehouse:inbound-order:list;按稳定 sourceContainerBookingId 返回不受订单分页影响的全柜事实。分组固定为 FBA、一件代发、私人地址,FBA 按目的仓编码/名称/ID 稳定排序;托数及 readiness/blockers 只由服务端计算。确认时必须原样回传 snapshotVersion 与 snapshotHash,服务端仍会锁柜重算。 security: [{ bearerAuth: [] }] parameters: - { name: sourceContainerBookingId, in: query, required: true, schema: { type: string, minLength: 1, maxLength: 128 } } responses: '200': { description: 柜级入库计划转换预览, content: { application/json: { schema: { $ref: '#/components/schemas/ContainerInboundPlanPreviewApiResponse' } } } } '404': { description: 来源柜没有尾程订单 } /api/platform/v1/last-leg/dispatches: get: summary: 分页查询排车单 description: 权限 platform:overseas-warehouse:dispatch:list;平台跨客户分页查询,前端不传 customerId。 security: [{ bearerAuth: [] }] 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: dispatchNo, in: query, schema: { type: string } } - { name: vehiclePlate, in: query, schema: { type: string } } - { name: status, in: query, schema: { type: string } } - { name: fbaAppointmentNo, in: query, schema: { type: string } } responses: '200': { description: 统一 ApiResponse 包装的排车单分页,records 元素为 DispatchResponse } /api/platform/v1/last-leg/dispatches/{dispatchNo}: get: summary: 查询排车单详情 description: 权限 platform:overseas-warehouse:dispatch:list;列表权限包含详情只读;平台按全局排车单号定位记录,并使用记录自身客户范围查询明细,前端不传 customerId。 security: [{ bearerAuth: [] }] parameters: - { name: dispatchNo, in: path, required: true, schema: { type: string } } responses: '200': { description: 统一 ApiResponse 包装的 DispatchResponse } '404': { description: 排车单不存在 } put: summary: 编辑待发车排车单 description: 权限 platform:overseas-warehouse:dispatch:edit;只按全局唯一 dispatchNo 锁定记录并从记录解析客户范围,不接收 customerId。仅允许 PENDING_DEPARTURE,且请求不包含 status/departAt,发车事实只能由 PDA 作业命令产生。 security: [{ bearerAuth: [] }] parameters: [{ name: dispatchNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DispatchUpdate' } } } } responses: { '200': { description: 更新后的 DispatchResponse }, '404': { description: 排车单不存在 }, '409': { description: 排车单已执行或不可编辑 } } delete: summary: 取消待发车排车单 description: 权限 platform:overseas-warehouse:dispatch:cancel;只按全局唯一 dispatchNo 锁定记录并解析客户范围,不接收 customerId。仅 PENDING_DEPARTURE 可取消并释放正式托盘锁;重复取消幂等成功。 security: [{ bearerAuth: [] }] parameters: [{ name: dispatchNo, in: path, required: true, schema: { type: string } }] responses: { '200': { description: 取消成功或已取消 }, '404': { description: 排车单不存在 }, '409': { description: 排车已开始执行 } } /api/platform/v1/last-leg/dispatches/candidates: get: summary: 查询智能排车候选托盘 description: 权限 platform:overseas-warehouse:inbound-order:list;planIds 为空时平台跨客户查询全部可排托盘,传入时按所选入库计划解析客户范围;仅返回尚未被有效排车锁定的计划或已实收托盘,前端不传 customerId。 security: [{ bearerAuth: [] }] parameters: - name: planIds in: query required: false description: 可选的入库计划 ID,逗号分隔;省略时平台查询全部客户候选。 schema: { type: array, minItems: 1, maxItems: 500, items: { type: integer, format: int64 } } style: form explode: false - { name: orderNo, in: query, schema: { type: string } } - { name: fbaWarehouseCode, in: query, schema: { type: string } } - { name: sourceStage, in: query, schema: { type: string, enum: [PLAN, RECEIVED] } } - { name: draftToken, in: query, schema: { type: string, maxLength: 64 }, description: 当前智能排车草稿标识;当前草稿已锁托盘仍可见 } responses: '200': description: 统一 ApiResponse 包装的候选托盘数组 content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/SmartDispatchCandidate' } } } } /api/platform/v1/last-leg/dispatches/pre-arrange: post: summary: 创建智能预排车单 description: 权限 platform:overseas-warehouse:inbound-order:smart-dispatch;服务端根据所选托盘解析并校验唯一客户范围,锁定同一海外仓的托盘并创建 PENDING_DEPARTURE 排车单,前端不传 customerId;本接口只负责预排车创建,编辑、取消、转出库派送和 PDA 发车使用各自独立接口与权限。 security: [{ bearerAuth: [] }] requestBody: required: true content: { application/json: { schema: { $ref: '#/components/schemas/SmartDispatchPreArrange' } } } responses: '200': { description: 统一 ApiResponse 包装的预排车详情, content: { application/json: { schema: { $ref: '#/components/schemas/DispatchResponse' } } } } /api/platform/v1/last-leg/dispatches/draft-locks/lock: post: summary: 将托盘移入智能排车草稿并立即锁定 description: 权限 platform:overseas-warehouse:inbound-order:smart-dispatch;草稿锁 30 分钟失效,与正式排车锁共享托盘排他约束。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/SmartDispatchDraftPallet' } } } } responses: { '200': { description: 锁定成功 }, '409': { description: 托盘已被其他草稿或正式排车锁定 } } /api/platform/v1/last-leg/dispatches/draft-locks/unlock: post: summary: 从智能排车草稿移除托盘并立即解锁 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/SmartDispatchDraftPallet' } } } } responses: { '200': { description: 解锁成功 }, '409': { description: 草稿锁不属于当前操作人 } } /api/platform/v1/last-leg/dispatches/draft-locks/release: post: summary: 关闭智能排车草稿并释放草稿内全部托盘 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/SmartDispatchDraftRelease' } } } } responses: { '200': { description: 草稿锁已全部释放 } } /api/platform/v1/last-leg/dispatches/drafts: get: summary: 查询当前操作人的有效智能排车草稿 description: 权限 platform:overseas-warehouse:inbound-order:smart-dispatch;只返回当前操作人未失效且未释放的草稿。 security: [{ bearerAuth: [] }] responses: '200': { description: 统一 ApiResponse 包装的智能排车草稿数组, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/SmartDispatchDraft' } } } } } /api/platform/v1/last-leg/dispatches/drafts/snapshot: post: summary: 保存智能排车草稿布局快照 description: 权限 platform:overseas-warehouse:inbound-order:smart-dispatch;草稿仅归当前操作人。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/SmartDispatchDraftSnapshot' } } } } responses: { '200': { description: 草稿快照保存成功 } } /api/platform/v1/last-leg/dispatches/drafts/containers: post: summary: 在智能排车草稿中新增车厢 description: 权限 platform:overseas-warehouse:inbound-order:smart-dispatch;返回服务端生成的字符串 ID。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/SmartDispatchDraftContainerCreate' } } } } responses: { '200': { description: 统一 ApiResponse 包装的草稿车厢, content: { application/json: { schema: { $ref: '#/components/schemas/SmartDispatchDraftContainer' } } } } } /api/platform/v1/last-leg/dispatches/drafts/{draftToken}/containers/{containerId}: delete: summary: 删除智能排车草稿中的空车厢 description: 权限 platform:overseas-warehouse:inbound-order:smart-dispatch;仅允许当前操作人删除未绑定托盘的草稿车厢。 security: [{ bearerAuth: [] }] parameters: - { name: draftToken, in: path, required: true, schema: { type: string, maxLength: 64 } } - { name: containerId, in: path, required: true, schema: { type: string } } responses: { '200': { description: 空车厢删除成功 }, '409': { description: 车厢仍绑定托盘或草稿状态冲突 } } /api/platform/v1/last-leg/dispatches/{dispatchNo}/transfer-delivery: post: summary: 排车转出库与派送单 description: 权限 platform:overseas-warehouse:dispatch:transfer-delivery;只按全局唯一 dispatchNo 锁定记录并从记录解析客户范围,不接收 customerId;同一幂等键或已转换排车重复调用返回既有单据。 security: [{ bearerAuth: [] }] parameters: [{ name: dispatchNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DeliveryTransfer' } } } } responses: { '200': { description: 出库与派送单转换结果 }, '404': { description: 排车单不存在 }, '409': { description: 状态、托盘或幂等冲突 } } /api/platform/v1/last-leg/outbound-orders: get: summary: 分页查询出库单 description: 权限 platform:overseas-warehouse:outbound:list;customerId 仅为可选平台筛选条件。 security: [{ bearerAuth: [] }] parameters: - { name: customerId, in: query, required: false, schema: { type: string, pattern: '^[1-9][0-9]*$' } } - { 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: documentNo, in: query, schema: { type: string } } - { name: warehouseId, in: query, schema: { type: string } } - { name: status, in: query, schema: { type: string } } responses: { '200': { description: 出库单分页 } } /api/platform/v1/last-leg/outbound-orders/one-click-dropship: post: summary: 创建一件代发出库单 description: 权限 platform:overseas-warehouse:outbound:create;因尚无既有业务单号可解析归属,平台必须显式传 customerId。 security: [{ bearerAuth: [] }] parameters: [{ name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/OneClickOutboundCreate' } } } } responses: { '200': { description: 一件代发出库 PDA 任务 }, '409': { description: 库存或幂等冲突 } } /api/platform/v1/last-leg/outbound-orders/one-click-dropship/candidates: get: summary: 查询一件代发出库候选库存 description: 权限 platform:overseas-warehouse:outbound:create;按客户及可选海外仓一次查询服务端权威候选,仅返回 ACTIVE 一件代发档案、OCCUPIED 正可用库存、AVAILABLE 箱唛与 SKU 余额共同覆盖且未被排车、转仓或待执行出库占用的维度。创建命令会再次校验,不信任前端候选快照。 security: [{ bearerAuth: [] }] parameters: - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } - { name: warehouseId, in: query, required: false, schema: { type: string } } responses: '200': description: 最多 500 条一件代发出库候选;单次 SQL 返回,不逐行补查 content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/OneClickOutboundCandidate' } } } } /api/platform/v1/last-leg/outbound-orders/{outboundNo}: get: summary: 查询出库单详情 description: 权限 platform:overseas-warehouse:outbound:list;只按全局唯一 outboundNo 定位并从记录解析客户范围,不接收 customerId。 security: [{ bearerAuth: [] }] parameters: [{ name: outboundNo, in: path, required: true, schema: { type: string } }] responses: { '200': { description: 出库单、出库托盘及关联派送单详情;pallets[].palletNo 为 Warehouse 权威实物托盘码 }, '404': { description: 出库单不存在 } } /api/platform/v1/last-leg/outbound-orders/{outboundNo}/cancel: post: summary: 取消未执行出库单 description: 权限 platform:overseas-warehouse:outbound:cancel;只按全局唯一 outboundNo 锁定并解析客户范围,不接收 customerId。仅未开始拣货/出库的单据可取消,重复取消幂等成功。 security: [{ bearerAuth: [] }] parameters: [{ name: outboundNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/OutboundCancel' } } } } responses: { '200': { description: 取消成功或已取消 }, '404': { description: 出库单不存在 }, '409': { description: 出库已开始执行 } } /api/platform/v1/last-leg/delivery-orders: get: summary: 分页查询平台派送单 description: 权限 platform:overseas-warehouse:delivery:list;customerId 仅为可选平台筛选条件。每行返回服务端计算的 allowedActions,页面不得自行推导状态门禁。 security: [{ bearerAuth: [] }] responses: { '200': { description: 派送单分页 } } /api/platform/v1/last-leg/delivery-orders/{deliveryNo}: get: summary: 查询平台派送单详情 description: 权限 platform:overseas-warehouse:delivery:list;列表权限包含详情只读;order.allowedActions 为当前可执行动作。 security: [{ bearerAuth: [] }] parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] responses: { '200': { description: 派送单详情 }, '404': { description: 派送单不存在 } } /api/platform/v1/last-leg/exception-orders: get: summary: 分页查询异常订单 description: 权限 platform:overseas-warehouse:exception-order:list。 security: [{ bearerAuth: [] }] responses: { '200': { description: 异常订单分页 } } post: summary: 创建异常订单 description: 权限 platform:overseas-warehouse:exception-order:create。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { type: object } } } } responses: { '200': { description: 已创建异常订单 } } /api/platform/v1/last-leg/exception-orders/{exceptionNo}: get: summary: 查询异常订单详情与冻结退回明细 description: 权限 platform:overseas-warehouse:exception-order:list;返回 version 和服务端 allowedActions。 security: [{ bearerAuth: [] }] parameters: [{ name: exceptionNo, in: path, required: true, schema: { type: string } }] responses: { '200': { description: 异常订单详情 }, '404': { description: 异常订单不存在 } } /api/platform/v1/last-leg/exception-orders/{exceptionNo}/start-processing: post: summary: 开始处理异常订单 description: 权限 platform:overseas-warehouse:exception-order:process;仅 PENDING→PROCESSING,同版本与同幂等请求可重放。 security: [{ bearerAuth: [] }] parameters: [{ name: exceptionNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ExceptionStartProcessing' } } } } responses: { '200': { description: 异常处理命令结果 }, '409': { description: 版本、状态或幂等冲突 } } /api/platform/v1/last-leg/exception-orders/{exceptionNo}/evidence: post: summary: 上传异常处理证据 description: 权限 platform:overseas-warehouse:exception-order:process;文件按当前客户和异常订单绑定为 OVERSEAS_EXCEPTION_EVIDENCE。 security: [{ bearerAuth: [] }] parameters: [{ name: exceptionNo, in: path, required: true, schema: { type: string } }] requestBody: required: true content: multipart/form-data: schema: { type: object, required: [file], properties: { file: { type: string, format: binary } } } responses: { '200': { description: 异常处理证据元数据 }, '400': { description: 文件或归属无效 } } /api/platform/v1/last-leg/exception-orders/{exceptionNo}/complete: post: summary: 完成异常处理并原子恢复退回库存 description: 权限 platform:overseas-warehouse:exception-order:process;仅 PROCESSING→COMPLETED。退回海外仓必须提交证据和实收目标,库存 RETURN_STOCK_IN 成功后才完成异常单和派送退回。 security: [{ bearerAuth: [] }] parameters: [{ name: exceptionNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ExceptionComplete' } } } } responses: { '200': { description: 异常处理与库存恢复结果 }, '409': { description: 版本、状态、归属、数量或幂等冲突 } } /api/platform/v1/last-leg/exception-orders/{exceptionNo}/cancel: post: summary: 取消未处理异常订单 description: 权限 platform:overseas-warehouse:exception-order:process;仅 PENDING→CANCELLED。 security: [{ bearerAuth: [] }] parameters: [{ name: exceptionNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ExceptionCancel' } } } } responses: { '200': { description: 异常取消结果 }, '409': { description: 版本、状态或幂等冲突 } } /api/platform/v1/last-leg/exception-orders/resolve: get: summary: 解析异常订单关联关系 description: 权限 platform:overseas-warehouse:exception-order:list;属于列表页只读辅助接口。 security: [{ bearerAuth: [] }] responses: { '200': { description: 关联关系 } } /api/platform/v1/last-leg/delivery-orders/{deliveryNo}/return-inbound-options: get: summary: 查询派送退回候选入仓单 description: 权限 platform:overseas-warehouse:exception-order:list;返回按原出库拣货事实解析的 returnSources,页面不得自由填写 SKU 或猜测库存位置。 security: [{ bearerAuth: [] }] parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] responses: { '200': { description: 退回候选入仓单 } } /api/platform/v1/last-leg/delivery-orders/{deliveryNo}/mark-return: post: summary: 将派送单标记为退回入仓 description: 权限 platform:overseas-warehouse:delivery:return;items 必须来自 return-inbound-options,服务端冻结源出库明细与批准退回上限。 security: [{ bearerAuth: [] }] parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DeliveryMarkReturn' } } } } responses: { '200': { description: 已创建退回异常单 } } /api/platform/v1/last-leg/delivery-orders/{deliveryNo}/complete: post: summary: 标记派送完成并生成回访记录 description: 权限 platform:overseas-warehouse:delivery:status。仅 WAIT_DELIVERY/DELIVERING 可完成;DELIVERED 同状态重放成功,其他终态或倒退返回 409。 security: [{ bearerAuth: [] }] parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DeliveryStatusChange' } } } } responses: { '200': { description: 派送状态与回访记录 }, '409': { description: 版本或状态冲突 } } /api/platform/v1/last-leg/delivery-orders/{deliveryNo}/status: put: summary: 更新派送状态 description: 权限 platform:overseas-warehouse:delivery:status。只允许 WAIT_DELIVERY→DELIVERING/DELIVERED/REJECTED/CANCELLED、DELIVERING→DELIVERED/REJECTED;同状态幂等,终态不可倒退。 security: [{ bearerAuth: [] }] parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DeliveryStatusChange' } } } } responses: { '200': { description: 更新后的派送状态 }, '409': { description: 非法状态迁移 } } /api/platform/v1/last-leg/customer-visits: get: summary: 分页查询客户回访 description: 权限 platform:overseas-warehouse:customer-visit:list。 security: [{ bearerAuth: [] }] responses: { '200': { description: 客户回访分页 } } /api/platform/v1/last-leg/customer-visits/{visitId}: get: summary: 查询客户回访详情 description: 权限 platform:overseas-warehouse:customer-visit:list;列表权限包含详情只读。 security: [{ bearerAuth: [] }] parameters: [{ name: visitId, in: path, required: true, schema: { type: integer, format: int64 } }] responses: { '200': { description: 客户回访详情 } } put: summary: 保存客户回访 description: 权限 platform:overseas-warehouse:customer-visit:edit。 security: [{ bearerAuth: [] }] parameters: [{ name: visitId, in: path, required: true, schema: { type: integer, format: int64 } }] requestBody: { required: true, content: { application/json: { schema: { type: object } } } } responses: { '200': { description: 已保存客户回访 } } /api/platform/v1/last-leg/customer-visits/{visitId}/attachments: post: summary: 上传客户回访附件 description: 权限 platform:overseas-warehouse:customer-visit:edit。 security: [{ bearerAuth: [] }] parameters: [{ name: visitId, in: path, required: true, schema: { type: integer, format: int64 } }] requestBody: { required: true, content: { multipart/form-data: { schema: { type: object } } } } responses: { '200': { description: 已上传附件 } } /api/platform/v1/last-leg/overseas-procurements: get: summary: 分页查询海外采购订单 description: 权限 platform:overseas-business:purchase:list;customerId 为空时查询全部客户。 security: [{ bearerAuth: [] }] parameters: - { name: customerId, in: query, schema: { type: string } } - { name: page, in: query, required: true, schema: { type: integer, minimum: 1 } } - { name: size, in: query, required: true, schema: { type: integer, minimum: 1, maximum: 200 } } - { name: orderNo, in: query, schema: { type: string } } - { name: customerKeyword, in: query, schema: { type: string } } - { name: purchaseCategory, in: query, schema: { type: string } } - { name: productName, in: query, schema: { type: string } } - { name: status, in: query, schema: { $ref: '#/components/schemas/ProcurementStatus' } } - { name: purchaseWarehouseId, in: query, schema: { type: string } } responses: { '200': { description: 统一 ApiResponse 包装的采购订单分页 } } /api/platform/v1/last-leg/overseas-procurements/customer-options: get: summary: 查询已有采购订单的客户候选 description: 权限 platform:overseas-business:purchase:list;候选来自尾程库采购订单客户快照,不跨库查询 IAM。 security: [{ bearerAuth: [] }] parameters: - { name: keyword, in: query, schema: { type: string } } - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 200, default: 50 } } responses: '200': description: 客户候选 content: { application/json: { schema: { $ref: '#/components/schemas/CustomerOptionResponse' } } } /api/platform/v1/last-leg/overseas-procurements/warehouse-options: get: summary: 查询启用的海外合作采购仓候选 description: 权限 platform:overseas-business:purchase:list;复用服务端缓存目录,浏览器不访问国内内部 API。 security: [{ bearerAuth: [] }] responses: '200': description: 采购仓候选 content: { application/json: { schema: { $ref: '#/components/schemas/WarehouseOptionResponse' } } } /api/platform/v1/last-leg/overseas-procurements/{orderNo}: parameters: - { name: orderNo, in: path, required: true, schema: { type: string } } - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } get: summary: 查询海外采购订单详情及操作流水 description: 权限 platform:overseas-business:purchase:list。 security: [{ bearerAuth: [] }] responses: { '200': { description: 统一 ApiResponse 包装的采购订单详情 } } patch: summary: 编辑海外采购订单 description: 权限 platform:overseas-business:purchase:edit;可选字段缺失表示不修改,显式 null 或空串表示清空。采购仓名称由 warehouse ID 对应候选快照决定。采购出库不属于本 API。 security: [{ bearerAuth: [] }] requestBody: required: true content: { application/json: { schema: { $ref: '#/components/schemas/ProcurementUpdate' } } } responses: { '200': { description: 统一 ApiResponse 包装的采购订单详情 }, '409': { description: 乐观锁冲突或状态不允许 } } /api/platform/v1/last-leg/overseas-procurements/{orderNo}/review: post: summary: 审核海外采购订单 description: 权限 platform:overseas-business:purchase:review;同幂等键同请求重放成功,异请求、旧 version 或终态反向审核返回 A0409。 security: [{ bearerAuth: [] }] parameters: - { name: orderNo, in: path, required: true, schema: { type: string } } - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } requestBody: required: true content: { application/json: { schema: { $ref: '#/components/schemas/ProcurementReview' } } } responses: { '200': { description: 统一 ApiResponse 包装的采购订单详情 } } /api/merchant/v1/last-leg/delivery-orders: get: summary: 客户分页查询自己的派送单 description: 权限 merchant:warehouse:delivery:list;客户范围只取认证 Token,不接收 customerId。 security: [{ bearerAuth: [] }] 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: documentNo, in: query, schema: { type: string } } - { name: warehouseId, in: query, schema: { type: string } } - { name: status, in: query, schema: { type: string } } - { name: dispatchNo, in: query, schema: { type: string } } - { name: waybillNo, in: query, schema: { type: string } } - { name: vehiclePlate, in: query, schema: { type: string } } - { name: driverName, in: query, schema: { type: string } } - { name: deliveryMethod, in: query, schema: { type: string } } - { name: plannedFrom, in: query, schema: { type: string, format: date-time } } - { name: plannedTo, in: query, schema: { type: string, format: date-time } } responses: { '200': { description: 当前客户派送单分页 }, '403': { description: 缺少客户派送查看权限 } } post: summary: 客户从自己的排车单创建派送单 description: 权限 merchant:warehouse:delivery:create;客户范围只取认证 Token,dispatchNo 必填,不接收 customerId;同一幂等键或已转换排车重复调用返回既有单据。 security: [{ bearerAuth: [] }] parameters: [{ name: dispatchNo, in: query, required: true, schema: { type: string, minLength: 1 } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DeliveryTransfer' } } } } responses: { '200': { description: 出库与派送单转换结果 }, '403': { description: 缺少客户派送创建权限 }, '404': { description: 当前客户下排车单不存在 }, '409': { description: 状态、参数或幂等冲突 } } /api/merchant/v1/last-leg/delivery-orders/{deliveryNo}: get: summary: 客户查询自己的派送单详情 description: 权限 merchant:warehouse:delivery:list;列表权限包含详情只读,客户范围只取认证 Token,不接收 customerId。 security: [{ bearerAuth: [] }] parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }] responses: { '200': { description: 当前客户派送单详情 }, '403': { description: 缺少客户派送查看权限 }, '404': { description: 当前客户下派送单不存在 } } /api/merchant/v1/last-leg/overseas-procurements: post: summary: 客户创建海外采购订单 description: 权限 merchant:cross-border:procurement;客户 ID 只取认证身份且不接收 customerId;新单固定进入 PENDING_REVIEW。同幂等键同请求返回既有订单,异请求返回 A0409。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ProcurementCreate' } } } } responses: { '200': { description: 采购订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/ProcurementDetailResponse' } } } }, '409': { description: 幂等冲突 } } get: summary: 客户分页查询自己的海外采购订单 description: 权限 merchant:cross-border:procurement;客户范围只取认证 Token,不接收 customerId。 security: [{ bearerAuth: [] }] 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: orderNo, in: query, schema: { type: string } } - { name: purchaseCategory, in: query, schema: { type: string } } - { name: productName, in: query, schema: { type: string } } - { name: status, in: query, schema: { type: string } } - { name: purchaseWarehouseId, in: query, schema: { type: string } } - { name: createdFrom, in: query, schema: { type: string, format: date-time } } - { name: createdTo, in: query, schema: { type: string, format: date-time } } responses: { '200': { description: 当前客户采购订单分页, content: { application/json: { schema: { $ref: '#/components/schemas/ProcurementPageResponse' } } } } } /api/merchant/v1/last-leg/overseas-procurements/{orderNo}: get: summary: 客户查询自己的海外采购订单详情及流水 description: 权限 merchant:cross-border:procurement;列表权限包含详情只读,客户范围只取认证 Token。 security: [{ bearerAuth: [] }] parameters: [{ name: orderNo, in: path, required: true, schema: { type: string } }] responses: { '200': { description: 当前客户采购订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/ProcurementDetailResponse' } } } }, '404': { description: 当前客户下订单不存在 } } /api/merchant/v1/last-leg/us-truck-orders: get: summary: 客户分页查询自己的美国本土卡订单 description: 权限 merchant:cross-border:domestic-trucking;客户范围只取认证 Token,不接收 customerId。 security: [{ bearerAuth: [] }] 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: orderNo, in: query, schema: { type: string } } - { name: routeKeyword, in: query, schema: { type: string } } - { name: status, in: query, schema: { $ref: '#/components/schemas/TruckStatus' } } - { name: transportType, in: query, schema: { type: string } } - { name: requestedFrom, in: query, schema: { type: string, format: date } } - { name: requestedTo, in: query, schema: { type: string, format: date } } responses: { '200': { description: 当前客户本土卡订单分页, content: { application/json: { schema: { $ref: '#/components/schemas/TruckPageResponse' } } } } } post: summary: 客户创建美国本土卡订单 description: 权限 merchant:cross-border:domestic-trucking;新单固定进入 PENDING_REVIEW,客户不能调用平台审核或状态推进端点。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckCreate' } } } } responses: { '200': { description: 本土卡订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/TruckDetailResponse' } } } }, '409': { description: 幂等冲突 } } /api/merchant/v1/last-leg/us-truck-orders/{orderNo}: parameters: [{ name: orderNo, in: path, required: true, schema: { type: string } }] get: summary: 客户查询自己的美国本土卡订单详情 description: 权限 merchant:cross-border:domestic-trucking;不泄露其他客户订单。 security: [{ bearerAuth: [] }] responses: { '200': { description: 当前客户本土卡订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/TruckDetailResponse' } } } }, '404': { description: 当前客户下订单不存在 } } patch: summary: 客户编辑待审核的美国本土卡订单 description: 权限 merchant:cross-border:domestic-trucking;仅 PENDING_REVIEW 可编辑,version 必填;不能修改状态。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckUpdate' } } } } responses: { '200': { description: 更新后的订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/TruckDetailResponse' } } } }, '409': { description: 版本或状态冲突 } } /api/merchant/v1/last-leg/local-looseboard-orders: get: summary: 客户分页查询自己的本土散板订单 description: 权限 merchant:cross-border:pallet-shipping;客户范围只取认证 Token,不接收 customerId。 security: [{ bearerAuth: [] }] 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: orderNo, in: query, schema: { type: string } } - { name: routeKeyword, in: query, schema: { type: string } } - { name: status, in: query, schema: { $ref: '#/components/schemas/LooseboardStatus' } } - { name: transportMode, in: query, schema: { type: string, enum: [SHARED_TRUCK, PRIORITY_CONSOLIDATION] } } - { name: requestedFrom, in: query, schema: { type: string, format: date } } - { name: requestedTo, in: query, schema: { type: string, format: date } } responses: { '200': { description: 当前客户本土散板订单分页, content: { application/json: { schema: { $ref: '#/components/schemas/LooseboardPageResponse' } } } } } post: summary: 客户创建本土散板订单 description: 权限 merchant:cross-border:pallet-shipping;新单固定进入 PENDING_ACCEPTANCE,客户不能调用平台状态推进端点。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/LooseboardCreate' } } } } responses: { '200': { description: 本土散板订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/LooseboardDetailResponse' } } } }, '409': { description: 幂等冲突 } } /api/merchant/v1/last-leg/local-looseboard-orders/{orderNo}: parameters: [{ name: orderNo, in: path, required: true, schema: { type: string } }] get: summary: 客户查询自己的本土散板订单详情 description: 权限 merchant:cross-border:pallet-shipping;不泄露其他客户订单。 security: [{ bearerAuth: [] }] responses: { '200': { description: 当前客户本土散板订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/LooseboardDetailResponse' } } } }, '404': { description: 当前客户下订单不存在 } } put: summary: 客户编辑待接单的本土散板订单 description: 权限 merchant:cross-border:pallet-shipping;仅 PENDING_ACCEPTANCE 可编辑,version 必填;不能修改状态。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/LooseboardUpdate' } } } } responses: { '200': { description: 更新后的订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/LooseboardDetailResponse' } } } }, '409': { description: 版本或状态冲突 } } /api/merchant/v1/last-leg/inbound-plans: get: summary: 客户分页查询自己的海外入库订单 description: 权限 merchant:warehouse:inbound:list;客户范围只取认证 Token,不接收 customerId;overseasWarehouseCode/overseasWarehouseName 只取该客户尾程订单预分配接柜仓事实,warehouseCode/warehouseName 仍表示目的仓。 security: [{ bearerAuth: [] }] 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: planNo, in: query, schema: { type: string } } - { name: inboundCode, in: query, schema: { type: string } } - { name: status, in: query, schema: { type: string } } - { name: overseasWarehouseId, in: query, schema: { type: string } } - { name: destinationWarehouseCode, in: query, schema: { type: string } } - { name: appointmentStatus, in: query, schema: { type: string, enum: [UNAPPOINTED, PENDING, SUCCESS, FAILED, CANCELLED] } } - { name: dispatchStatus, in: query, schema: { type: string, enum: [UNSCHEDULED, SCHEDULED] } } - { name: createdFrom, in: query, schema: { type: string, format: date-time } } - { name: createdTo, in: query, schema: { type: string, format: date-time } } responses: { '200': { description: 当前客户入库订单分页, content: { application/json: { schema: { $ref: '#/components/schemas/InboundPlanPageResponse' } } } } } /api/merchant/v1/last-leg/inbound-plans/{planNo}: get: summary: 客户查询自己的海外入库订单详情 description: 权限 merchant:warehouse:inbound:list;列表权限包含详情只读,不接收 customerId;overseasWarehouseCode/overseasWarehouseName 只取该计划来源尾程订单的预分配接柜仓事实。 security: [{ bearerAuth: [] }] parameters: [{ name: planNo, in: path, required: true, schema: { type: string } }] responses: { '200': { description: 当前客户入库订单详情, content: { application/json: { schema: { $ref: '#/components/schemas/InboundPlanDetailResponse' } } } }, '404': { description: 当前客户下入库订单不存在 } } /api/platform/v1/last-leg/us-truck-orders: get: summary: 分页查询本土卡车订单 description: 权限 platform:overseas-business:truck:list。 security: [{ bearerAuth: [] }] responses: { '200': { description: 统一 ApiResponse 包装的卡车订单分页 } } post: summary: 平台为指定客户创建本土卡车订单 description: 权限 platform:overseas-business:truck:create;customerId 必填且只作为可信服务端隔离键。 security: [{ bearerAuth: [] }] parameters: [{ name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckCreate' } } } } responses: { '200': { description: 统一 ApiResponse 包装的卡车订单详情 } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}: parameters: - { name: orderNo, in: path, required: true, schema: { type: string } } - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } get: summary: 查询本土卡车订单详情 description: 权限 platform:overseas-business:truck:list。 security: [{ bearerAuth: [] }] responses: { '200': { description: 统一 ApiResponse 包装的卡车订单详情 } } patch: summary: 平台普通编辑本土卡车订单 description: 权限 platform:overseas-business:truck:edit;仅待审核订单可编辑,不能修改状态。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckUpdate' } } } } responses: { '200': { description: 统一 ApiResponse 包装的卡车订单详情 } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}/status: patch: summary: 取消未发车的本土卡车订单 description: 权限 platform:overseas-business:truck:status;该通用入口只接受 CANCELLED,正向状态必须使用具名命令,不能绕过实收、超托与分配事实。 security: [{ bearerAuth: [] }] parameters: - { name: orderNo, in: path, required: true, schema: { type: string } } - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckCancel' } } } } responses: { '200': { description: 统一 ApiResponse 包装的卡车订单详情 }, '409': { description: 非法状态迁移 } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}/review: parameters: &truckOrderTarget - { name: orderNo, in: path, required: true, schema: { type: string } } - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } post: summary: 审核本土卡车订单 description: 权限 platform:overseas-business:truck:status;PENDING_REVIEW 审核通过进入 WAITING_INBOUND 并生成预期托盘;拒绝进入 REJECTED。幂等键异请求、旧 version 或非法跳转返回 A0409。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckReview' } } } } responses: { '200': { description: 卡车订单详情 }, '409': { description: 版本、状态或幂等冲突 } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}/receive-pallets: post: summary: 记录本土卡车订单实收托盘 description: 权限 platform:overseas-business:truck:status;幂等记录实收,不创建海外仓出库或派送单。 security: [{ bearerAuth: [] }] parameters: - { name: orderNo, in: path, required: true, schema: { type: string } } - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckReceivePallets' } } } } responses: { '200': { description: 统一 ApiResponse 包装的卡车订单详情 } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}/review-pallet-overage: parameters: *truckOrderTarget post: summary: 审核实收超出申报数的托盘 description: 权限 platform:overseas-business:truck:status;APPROVE 将超收托盘纳入本单并进入 WAITING_CONSOLIDATION;REJECT 标记超收托盘拒收并按原申报数继续。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckReviewPalletOverage' } } } } responses: { '200': { description: 卡车订单详情 }, '409': { description: 版本、状态或幂等冲突 } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}/allocate-pallets: parameters: *truckOrderTarget post: summary: 分配已实收托盘到本土卡车行程 description: 权限 platform:overseas-business:truck:status;仅接收本单 RECEIVED 托盘 ID;部分分配进入 PARTIALLY_ALLOCATED,全部分配进入 ALLOCATED。不创建海外仓出库单或扣减库存。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckAllocatePallets' } } } } responses: { '200': { description: 卡车订单详情 }, '409': { description: 托盘归属、状态、版本或幂等冲突 } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}/prepare-dispatch: parameters: *truckOrderTarget post: summary: 全部托盘分配后准备派车 description: 权限 platform:overseas-business:truck:status;旧 version、幂等键异请求或非 ALLOCATED 状态返回 A0409。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckCommand' } } } } responses: { '200': { description: 状态 PENDING_DISPATCH } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}/dispatch: parameters: *truckOrderTarget post: summary: 确认本土卡车已派车 description: 权限 platform:overseas-business:truck:status;本土卡车单自身履约,不创建海外仓排车单、出库单或派送单。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckCommand' } } } } responses: { '200': { description: 状态 DISPATCHED } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}/start-transit: parameters: *truckOrderTarget post: summary: 确认本土卡车开始运输 description: 权限 platform:overseas-business:truck:status;仅 DISPATCHED 可进入 IN_TRANSIT。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckCommand' } } } } responses: { '200': { description: 状态 IN_TRANSIT } } /api/platform/v1/last-leg/us-truck-orders/{orderNo}/complete: parameters: *truckOrderTarget post: summary: 完成本土卡车订单 description: 权限 platform:overseas-business:truck:status;仅 IN_TRANSIT 可进入不可逆 COMPLETED。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/TruckCommand' } } } } responses: { '200': { description: 状态 COMPLETED } } /api/platform/v1/last-leg/local-looseboard-orders: get: summary: 分页查询本土散板订单 description: 权限 platform:overseas-business:looseboard:list。 security: [{ bearerAuth: [] }] responses: { '200': { description: 统一 ApiResponse 包装的散板订单分页 } } post: summary: 创建本土散板订单 description: 权限 platform:overseas-business:looseboard:create;独立稳定子域,不复用卡车端点。 security: [{ bearerAuth: [] }] parameters: [{ name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/LooseboardCreate' } } } } responses: { '200': { description: 统一 ApiResponse 包装的散板订单详情 } } /api/platform/v1/last-leg/local-looseboard-orders/{orderNo}: parameters: - { name: orderNo, in: path, required: true, schema: { type: string } } - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } get: summary: 查询本土散板订单详情及操作流水 description: 权限 platform:overseas-business:looseboard:list。 security: [{ bearerAuth: [] }] responses: { '200': { description: 统一 ApiResponse 包装的散板订单详情 } } put: summary: 全量更新待接单的本土散板订单 description: 权限 platform:overseas-business:looseboard:edit;可空字段传 null 或空串即清空;状态由独立端点推进。 security: [{ bearerAuth: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/LooseboardUpdate' } } } } responses: { '200': { description: 统一 ApiResponse 包装的散板订单详情 }, '409': { description: 版本或状态冲突 } } /api/platform/v1/last-leg/local-looseboard-orders/{orderNo}/status: patch: summary: 推进或取消本土散板订单 description: 权限 platform:overseas-business:looseboard:status;只允许 PENDING_ACCEPTANCE→DISPATCHED→IN_TRANSIT→COMPLETED,另建订单可进入 CANCELLED;幂等键异请求、旧 version、非法跳转或终态反向返回 A0409。 security: [{ bearerAuth: [] }] parameters: - { name: orderNo, in: path, required: true, schema: { type: string } } - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/LooseboardStatusChange' } } } } responses: { '200': { description: 统一 ApiResponse 包装的散板订单详情 }, '409': { description: 非法状态迁移 } } /api/platform/v1/last-leg/relabel-applications: get: summary: 分页查询海外换标单 description: 权限 platform:overseas-warehouse:relabel-order:list;平台查询全部换标单,不接收 customerId。 security: [{ bearerAuth: [] }] 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: relabelNo, in: query, schema: { type: string, maxLength: 64 } } - { name: customerOrderNo, in: query, schema: { type: string, maxLength: 128 } } - { name: skuCode, in: query, schema: { type: string, maxLength: 128 } } - { name: status, in: query, schema: { $ref: '#/components/schemas/RelabelStatus' } } - { name: overseasWarehouseId, in: query, schema: { type: string, maxLength: 128 } } - { name: createdFrom, in: query, schema: { type: string, format: date-time } } - { name: createdTo, in: query, schema: { type: string, format: date-time } } responses: { '200': { description: 统一 ApiResponse 包装的换标单分页 } } post: summary: 创建海外换标单 description: 权限 platform:overseas-warehouse:relabel-order:create;明细与换标文件按请求快照保存,使用 idempotencyKey 幂等。 security: [{ bearerAuth: [] }] parameters: - { name: customerId, in: query, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } } requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelCreate' } } } } responses: { '200': { description: 统一 ApiResponse 包装的换标单详情 }, '409': { description: 幂等键冲突 } } /api/platform/v1/last-leg/relabel-applications/{relabelNo}: get: summary: 查询海外换标单详情 description: 权限 platform:overseas-warehouse:relabel-order:list。 security: [{ bearerAuth: [] }] parameters: - { name: relabelNo, in: path, required: true, schema: { type: string, maxLength: 64 } } responses: { '200': { description: 统一 ApiResponse 包装的换标单详情 }, '404': { description: 换标单不存在或不属于当前客户 } } /api/platform/v1/last-leg/relabel-applications/{relabelNo}/status: put: summary: 变更海外换标单状态 description: 权限 platform:overseas-warehouse:relabel-order:status;状态按 PENDING_PROCESSING→PROCESSING→COMPLETED/REJECTED/CANCELLED 流转。 security: [{ bearerAuth: [] }] parameters: - { name: relabelNo, in: path, required: true, schema: { type: string, maxLength: 64 } } requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelStatusChange' } } } } responses: { '200': { description: 统一 ApiResponse 包装的换标单详情 }, '409': { description: 非法状态迁移或关联尾程单缺失 } } components: schemas: InventoryBalance: type: object required: [id, customerId, totalPackages, availablePackages, holdPackages, allocatedPackages, pickedPackages, inTransitPackages, receivingPackages, procurementPackages] properties: id: { type: string, pattern: '^[1-9][0-9]*$', description: 库存余额长整型ID,按字符串传输 } customerId: { type: string } customerName: { type: string, nullable: true } overseasWarehouseId: { type: string, nullable: true } overseasWarehouseCode: { type: string, nullable: true } overseasWarehouseName: { type: string, nullable: true } destinationWarehouseId: { type: string, nullable: true } destinationWarehouseCode: { type: string, nullable: true } destinationWarehouseName: { type: string, nullable: true } inboundOrderId: { type: string, nullable: true, pattern: '^[1-9][0-9]*$', description: 长整型ID按字符串传输 } inboundOrderNo: { type: string, nullable: true } inboundCode: { type: string, nullable: true } skuCode: { type: string, nullable: true } productNameZh: { type: string, nullable: true } productNameEn: { type: string, nullable: true } totalPackages: { type: integer, format: int64, minimum: 0 } availablePackages: { type: integer, format: int64, minimum: 0 } holdPackages: { type: integer, format: int64, minimum: 0 } allocatedPackages: { type: integer, format: int64, minimum: 0 } pickedPackages: { type: integer, format: int64, minimum: 0 } inTransitPackages: { type: integer, format: int64, minimum: 0 } receivingPackages: { type: integer, format: int64, minimum: 0 } procurementPackages: { type: integer, format: int64, minimum: 0 } updatedAt: { type: string, format: date-time, nullable: true } InventoryBalanceApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object properties: { data: { $ref: '#/components/schemas/InventoryBalance' } } InboundCodeRelationship: type: object required: [inboundCode, found, taillegOrders, inboundPlans, palletCodes, inventory] properties: inboundCode: { type: string } found: { type: boolean } customer: { $ref: '#/components/schemas/InboundCodeRelationshipCustomer', nullable: true } overseasWarehouse: { $ref: '#/components/schemas/InboundCodeRelationshipWarehouse', nullable: true } overseasReceivingStatus: { type: string, nullable: true } taillegOrders: { type: array, items: { $ref: '#/components/schemas/InboundCodeRelationshipOrder' } } inboundPlans: { type: array, items: { $ref: '#/components/schemas/InboundCodeRelationshipPlan' } } palletCodes: { type: array, uniqueItems: true, items: { type: string } } inventory: { type: array, items: { $ref: '#/components/schemas/InboundCodeRelationshipInventorySku' } } InboundCodeRelationshipCustomer: type: object required: [customerId] properties: customerId: { type: string, description: 字符串业务隔离标识,禁止按JavaScript number处理 } customerName: { type: string, nullable: true } InboundCodeRelationshipWarehouse: type: object properties: warehouseId: { type: string, nullable: true, description: 字符串共享仓库ID,禁止按JavaScript number处理 } warehouseCode: { type: string, nullable: true } warehouseName: { type: string, nullable: true } InboundCodeRelationshipOrder: type: object required: [orderNo] properties: orderNo: { type: string } orderStatus: { type: string, nullable: true } InboundCodeRelationshipPlan: type: object required: [planNo] properties: planNo: { type: string } planStatus: { type: string, nullable: true } receivingStatus: { type: string, nullable: true } InboundCodeRelationshipInventorySku: type: object required: [skuCode, packageCount] properties: skuCode: { type: string } productNameZh: { type: string, nullable: true } productNameEn: { type: string, nullable: true } packageCount: { type: integer, format: int64, minimum: 0 } InboundCodeRelationshipApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object properties: { data: { $ref: '#/components/schemas/InboundCodeRelationship' } } FbaTransferDestination: type: object required: [warehouseId, warehouseCode, warehouseName] properties: warehouseId: { type: string, pattern: '^[1-9][0-9]*$', description: 国内 Warehouse Service 平台公共 FBA 仓 ID } warehouseCode: { type: string, minLength: 1, maxLength: 128 } warehouseName: { type: string, minLength: 1, maxLength: 255 } remark: { type: string, nullable: true, maxLength: 500 } FbaBatchTransferDestination: allOf: - { $ref: '#/components/schemas/FbaTransferDestination' } - type: object required: [orderIds] properties: orderIds: type: array minItems: 1 maxItems: 200 uniqueItems: true items: { type: string, pattern: '^[1-9][0-9]*$' } ContainerPlanProgressSummary: type: object required: [sourceContainerBookingId, containerNo, overseasWarehouseId, overseasWarehouseCode, overseasWarehouseName, assignmentVersion, canChangeReceivingWarehouse, totalOrderCount, inboundCodeCount, missingInboundCodeCount, planCount, plannedInboundCodeCount, pendingPlanCount, allPlansReady] properties: sourceContainerBookingId: { type: string } containerNo: { type: string, pattern: '^[A-Z]{3}[UJZ][0-9]{7}$', description: 装柜完成事件非空且通过 ISO 6346 校验位验证的规范化真实集装箱号;不使用 cabinetNo、订单号或内部 ID 回退 } overseasWarehouseId: { type: string, pattern: '^[1-9][0-9]*$', description: 平台预分配的海外接柜仓ID,不是FBA目的仓 } overseasWarehouseCode: { type: string, description: 海外接柜仓业务编码 } overseasWarehouseName: { type: string, description: 海外接柜仓业务名称 } assignmentVersion: { type: integer, minimum: 0, description: 柜级接柜仓乐观锁版本 } canChangeReceivingWarehouse: { type: boolean } receivingWarehouseLockReason: { type: string, nullable: true } totalOrderCount: { type: integer, format: int64 } inboundCodeCount: { type: integer, format: int64 } missingInboundCodeCount: { type: integer, format: int64 } planCount: { type: integer, format: int64 } plannedInboundCodeCount: { type: integer, format: int64 } pendingPlanCount: { type: integer, format: int64, description: 尚未生成有效计划的尾程订单数,即未操作数 } plannedArrivalAt: { type: string, format: date-time, nullable: true, description: 仅来源于装柜完成事件 estimatedWarehouseArrivalAt 冻结的 ll_order.estimated_warehouse_at } allPlansReady: { type: boolean, description: 全柜每票均有入仓码且均存在有效独立计划时为 true } blockingReason: { type: string, nullable: true } ChangeReceivingWarehouseRequest: type: object required: [overseasWarehouseId, expectedVersion] properties: overseasWarehouseId: { type: integer, format: int64, minimum: 1 } expectedVersion: { type: integer, minimum: 0 } remark: { type: string, maxLength: 500, nullable: true } ContainerPlanProgressDetail: type: object required: [summary, orders] properties: summary: { $ref: '#/components/schemas/ContainerPlanProgressSummary' } orders: type: array items: { $ref: '#/components/schemas/ContainerPlanProgressItem' } ContainerPlanProgressItem: type: object required: [orderId, customerId, orderStatus, planValid] properties: orderId: { type: string, pattern: '^[1-9][0-9]*$' } customerId: { type: string } orderNo: { type: string, nullable: true } inboundCode: { type: string, nullable: true } lxCode: { type: string, nullable: true, maxLength: 128, description: 一件代发领星入库单代码 } orderStatus: { type: string } planId: { type: string, nullable: true, pattern: '^[1-9][0-9]*$' } planNo: { type: string, nullable: true } planStatus: { type: string, nullable: true } planValid: { type: boolean } plannedArrivalAt: { type: string, format: date-time, nullable: true, description: ll_order.estimated_warehouse_at } LastMileFeeCreate: type: object required: [feeItemCode, feeItemName, direction, currency, amount, businessDate] properties: feeItemCode: { type: string, minLength: 1, maxLength: 64 } feeItemName: { type: string, minLength: 1, maxLength: 128 } direction: { type: string, enum: [RECEIVABLE, PAYABLE] } currency: { type: string, enum: [CNY, USD] } amount: { type: number, format: decimal, minimum: 0.01 } businessDate: { type: string, format: date } supplierId: { type: string, pattern: '^[1-9][0-9]*$' } supplierName: { type: string, maxLength: 200 } supplierCategory: { type: string, maxLength: 32 } settlementMode: { type: string, enum: [ON_ACCOUNT, DIRECT_PAID] } chargeableQuantity: { type: number, exclusiveMinimum: 0 } quantityUnit: { type: string, maxLength: 32 } unitPrice: { type: number, exclusiveMinimum: 0 } periodStart: { type: string, format: date } periodEnd: { type: string, format: date } LastMileFee: type: object required: [id, sourceFeeId, sourceVersion, customerId, feeItemCode, feeItemName, direction, currency, amount, originalCurrency, originalAmount, reviewStatus, publicationStatus, sourceStatus] properties: id: { type: string, pattern: '^[1-9][0-9]*$' } sourceFeeId: { type: string, pattern: '^[1-9][0-9]*$' } sourceVersion: { type: integer, minimum: 1 } customerId: { type: string } orderId: { type: string, pattern: '^[1-9][0-9]*$' } feeItemCode: { type: string } feeItemName: { type: string } direction: { type: string, enum: [RECEIVABLE, PAYABLE] } currency: { type: string, enum: [CNY] } amount: { type: number, format: decimal } originalCurrency: { type: string, enum: [CNY, USD] } originalAmount: { type: number, format: decimal } exchangeRate: { type: number, format: decimal } exchangeRateMonth: { type: string, pattern: '^\\d{4}-\\d{2}$' } reviewStatus: { type: string, enum: [DRAFT, PENDING, APPROVED, REJECTED] } publicationStatus: { type: string } sourceStatus: { type: string } LastMileFeeApiResponse: type: object required: [code, message, data] properties: code: { type: string } message: { type: string } data: { $ref: '#/components/schemas/LastMileFee' } PdaWarehouseScan: type: object required: [code] properties: { code: { type: string, minLength: 1, maxLength: 128 } } PdaInventoryItem: type: object required: [customerId, balanceId, positionId, inboundCode, palletId, palletCode, availablePackages, holdPackages, receivingPackages, status, version] properties: customerId: { type: string } customerName: { type: string, nullable: true } balanceId: { type: integer, format: int64 } positionId: { type: integer, format: int64 } skuCode: { type: string, nullable: true } productName: { type: string, nullable: true } inboundCode: { type: string } cartonMark: { type: string, nullable: true } palletId: { type: integer, format: int64 } palletCode: { type: string } locationId: { type: integer, format: int64, nullable: true } locationCode: { type: string, nullable: true } availablePackages: { type: integer, format: int64, minimum: 0 } holdPackages: { type: integer, format: int64, minimum: 0 } receivingPackages: { type: integer, format: int64, minimum: 0 } status: { type: string } version: { type: integer, format: int64, minimum: 0 } PdaInventoryScan: type: object required: [queryCode, items] properties: queryCode: { type: string } items: { type: array, items: { $ref: '#/components/schemas/PdaInventoryItem' } } PdaLocation: type: object required: [locationId, locationCode, locationType, status, occupiedPackages, inventoryPositionCount] properties: locationId: { type: integer, format: int64 } locationCode: { type: string } locationType: { type: string } maxLoadKg: { type: number, nullable: true } status: { type: string } occupiedPackages: { type: integer, format: int64, minimum: 0 } inventoryPositionCount: { type: integer, minimum: 0 } PdaPallet: type: object required: [palletId, palletCode, status, version, locationId, locationCode, occupiedPackages, inventoryPositionCount, inventory] properties: palletId: { type: integer, format: int64 } palletCode: { type: string } status: { type: string } version: { type: integer, minimum: 0 } locationId: { type: integer, format: int64 } locationCode: { type: string } occupiedPackages: { type: integer, format: int64, minimum: 0 } inventoryPositionCount: { type: integer, minimum: 0 } inventory: { type: array, items: { $ref: '#/components/schemas/PdaInventoryItem' } } PdaOperation: type: object required: [operationId, operationType, businessKey, status, occurredAt] properties: operationId: { type: integer, format: int64 } operationType: { type: string } businessKey: { type: string } status: { type: string } summary: { type: string, nullable: true } customerId: { type: string, nullable: true } occurredAt: { type: string, format: date-time } PdaInventoryScanApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object properties: { data: { $ref: '#/components/schemas/PdaInventoryScan' } } PdaLocationApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object properties: { data: { $ref: '#/components/schemas/PdaLocation' } } PdaPalletApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object properties: { data: { $ref: '#/components/schemas/PdaPallet' } } PdaOperationPageApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object properties: data: type: object required: [records, page, size, total, pages] properties: records: { type: array, items: { $ref: '#/components/schemas/PdaOperation' } } page: { type: integer } size: { type: integer } total: { type: integer, format: int64 } pages: { type: integer, format: int64 } ReceivingAction: type: object required: [idempotencyKey] properties: { idempotencyKey: { type: string, minLength: 1, maxLength: 255 } } ReceivingSign: type: object required: [photos, idempotencyKey] properties: photos: { type: array, minItems: 3, maxItems: 3, items: { $ref: '#/components/schemas/ReceivingSignedPhoto' } } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } ReceivingSignedPhoto: type: object required: [role, fileId] properties: role: { type: string, enum: [LICENSE_PLATE, CONTAINER_SEAL, DOOR_OPEN] } fileId: { type: string, pattern: '^[1-9][0-9]{0,18}$', description: Snowflake file ID kept as a decimal string } ReceivingSignedSessionPhoto: type: object required: [role, fileId, downloadPath] properties: role: { type: string, enum: [LICENSE_PLATE, CONTAINER_SEAL, DOOR_OPEN] } fileId: { type: string, pattern: '^[1-9][0-9]{0,18}$', description: Snowflake file ID kept as a decimal string } downloadPath: { type: string, description: 用于会话恢复时直接下载签收照片 } ReceivingBulk: type: object required: [inboundCode, palletCode, packageCount, idempotencyKey] properties: inboundCode: { type: string, minLength: 1 } palletCode: { type: string, minLength: 1 } packageCount: { type: integer, minimum: 1 } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } ReceivingCarton: type: object required: [cartonMark, palletCode, idempotencyKey] properties: cartonMark: { type: string, minLength: 1 } palletCode: { type: string, minLength: 1 } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } ReceivingApiResponseBase: type: object required: [code, message, timestamp] properties: code: { type: string, example: '200' } message: { type: string } requestId: { type: string, nullable: true } traceId: { type: string, nullable: true } timestamp: { type: string, format: date-time } ReceivingInbound: type: object required: [inboundCode, destinationType, plannedPalletCount, totalPackages, receivedPackages, pendingPackages, assigned, mergeAllowed, urgent] properties: inboundCode: { type: string } destinationType: { type: string, enum: [FBA, OVERSEAS] } overseasWarehouseId: { type: string, nullable: true, description: 实际海外收货仓ID;与FBA或其他业务目的仓ID严格区分 } overseasWarehouseName: { type: string, nullable: true, description: 实际海外收货仓名称快照 } destinationWarehouseId: { type: string, nullable: true } destinationWarehouseCode: { type: string, nullable: true } destinationWarehouseName: { type: string, nullable: true } fbaWarehouseCode: { type: string, nullable: true } plannedPalletCount: { type: integer } totalPackages: { type: integer } receivedPackages: { type: integer } pendingPackages: { type: integer } assigned: { type: boolean, description: 入库计划是否已分配 } mergeAllowed: { type: boolean, description: 入库计划是否允许现场选择合托;true不代表强制合托 } urgent: { type: boolean, description: 入库计划是否加急 } mergeHint: { type: string, nullable: true, description: 允许合托时供PDA直接展示的非强制中文提示 } ReceivingWarehouseProfile: type: object required: [warehouseId, warehouseCode, warehouseName] properties: warehouseId: { type: string, pattern: '^\d+$' } warehouseCode: { type: string } warehouseName: { type: string, description: 国内Warehouse Service主档维护的当前中文名称 } ReceivingCandidate: type: object required: [sourceContainerBookingId, containerNo, overseasWarehouseCode, overseasWarehouseName, status, totalOrderCount, inboundCodeCount, missingInboundCodeCount, planCount, plannedInboundCodeCount, pendingPlanCount, destinationCodes, plannedPalletCount, totalPackages, receivedPackages, operable, allPlansReady, currentAccount] properties: sourceContainerBookingId: { type: string, description: 头程与尾程共享的稳定柜身份 } containerNo: { type: string } overseasWarehouseCode: { type: string } overseasWarehouseName: { type: string } status: { type: string, enum: [WAIT_SIGN, SIGNED, RECEIVING, COMPLETED] } totalOrderCount: { type: integer, minimum: 1 } missingInboundCodeCount: { type: integer, minimum: 0 } planCount: { type: integer } inboundCodeCount: { type: integer } plannedInboundCodeCount: { type: integer, minimum: 0 } pendingPlanCount: { type: integer, minimum: 0 } destinationCodes: { type: array, uniqueItems: true, items: { type: string } } plannedPalletCount: { type: integer } totalPackages: { type: integer } receivedPackages: { type: integer } operable: { type: boolean } allPlansReady: { type: boolean } blockReason: { type: string, nullable: true } plannedArrivalAt: { type: string, format: date-time, nullable: true } currentAccount: { type: boolean } ReceivingSession: type: object required: [containerNo, overseasWarehouseId, overseasWarehouseCode, overseasWarehouseName, status, version, photos, totalPackages, receivedPackages, pendingPackages, inbounds] properties: containerNo: { type: string } overseasWarehouseId: { type: string, pattern: '^\d+$', description: 平台预分配并与PDA Token匹配的海外接柜仓ID } overseasWarehouseCode: { type: string, description: 海外接柜仓业务编码快照 } overseasWarehouseName: { type: string, description: Warehouse Overseas服务校验后的共享实际海外收货仓名称快照 } status: { type: string, enum: [WAIT_SIGN, SIGNED, RECEIVING, COMPLETED] } operatorName: { type: string, nullable: true } version: { type: integer } photos: { type: array, maxItems: 3, items: { $ref: '#/components/schemas/ReceivingSignedSessionPhoto' } } preparedAt: { type: string, format: date-time, nullable: true } signedAt: { type: string, format: date-time, nullable: true } receivingAt: { type: string, format: date-time, nullable: true } completedAt: { type: string, format: date-time, nullable: true } totalPackages: { type: integer } receivedPackages: { type: integer } pendingPackages: { type: integer } inbounds: { type: array, items: { $ref: '#/components/schemas/ReceivingInbound' } } ReceivingPhoto: type: object required: [fileId, fileName, contentType, sizeBytes] properties: fileId: { type: string, pattern: '^[1-9][0-9]{0,18}$', description: Snowflake file ID kept as a decimal string } fileName: { type: string } contentType: { type: string } sizeBytes: { type: integer, format: int64 } ReceivingCartonResolved: allOf: - { $ref: '#/components/schemas/ReceivingInbound' } - type: object required: [cartonMark] properties: cartonMark: { type: string } ReceivingPalletResolved: type: object required: [palletCode, warehouseId, status, inboundCode, destinationType, compatible] properties: palletCode: { type: string } warehouseId: { type: integer, format: int64 } status: { type: string } fbaWarehouseCode: { type: string, nullable: true } inboundCode: { type: string } destinationType: { type: string, enum: [FBA, OVERSEAS] } compatible: { type: boolean } ReceivingReceipt: type: object required: [result, containerNo, inboundCode, destinationType, palletCode, acceptedPackages, receivedPackages, pendingPackages, sessionStatus, assigned, mergeAllowed, urgent] properties: result: { type: string } containerNo: { type: string } inboundCode: { type: string } destinationType: { type: string, enum: [FBA, OVERSEAS] } palletCode: { type: string } acceptedPackages: { type: integer } receivedPackages: { type: integer } pendingPackages: { type: integer } sessionStatus: { type: string, enum: [SIGNED, RECEIVING] } assigned: { type: boolean } mergeAllowed: { type: boolean, description: 现场可选择合托,不作为实收或完成门禁 } urgent: { type: boolean } mergeHint: { type: string, nullable: true } ReceivingCandidateListApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object required: [data] properties: { data: { type: array, items: { $ref: '#/components/schemas/ReceivingCandidate' } } } ReceivingWarehouseProfileApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object required: [data] properties: { data: { $ref: '#/components/schemas/ReceivingWarehouseProfile' } } ReceivingSessionApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object required: [data] properties: { data: { $ref: '#/components/schemas/ReceivingSession' } } ReceivingPhotoApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object required: [data] properties: { data: { $ref: '#/components/schemas/ReceivingPhoto' } } ReceivingCartonResolvedApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object required: [data] properties: { data: { $ref: '#/components/schemas/ReceivingCartonResolved' } } ReceivingPalletResolvedApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object required: [data] properties: { data: { $ref: '#/components/schemas/ReceivingPalletResolved' } } ReceivingReceiptApiResponse: allOf: - { $ref: '#/components/schemas/ReceivingApiResponseBase' } - type: object required: [data] properties: { data: { $ref: '#/components/schemas/ReceivingReceipt' } } SmartDispatchCandidate: type: object properties: planId: { type: string } planPalletId: { type: string } warehousePalletId: { type: string, nullable: true } orderId: { type: string } customerId: { type: string } customerName: { type: string, nullable: true } planNo: { type: string, nullable: true } orderType: { type: string, nullable: true } volumeWeightKg: { type: number, nullable: true } containerNo: { type: string, nullable: true } appointmentAt: { type: string, format: date-time, nullable: true } expectedLoadingAt: { type: string, format: date-time, nullable: true } overseasWarehouseId: { type: string } overseasWarehouseName: { type: string } orderNo: { type: string } orderRefs: { type: string } inboundCode: { type: string } palletNo: { type: string, description: 未入库时为计划托盘码;绑定实物托盘后为 Warehouse 权威实物托盘码 } destinationWarehouseId: { type: string } destinationWarehouseCode: { type: string } destinationWarehouseName: { type: string } fbaWarehouseCode: { type: string } packageCount: { type: integer } volumeCbm: { type: number } sourceStage: { type: string, enum: [PLAN, RECEIVED] } cartonMarks: { type: string, nullable: true, description: 该托盘箱号,逗号分隔 } SmartDispatchPreArrange: type: object required: [planPalletIds] properties: planPalletIds: { type: array, minItems: 1, maxItems: 500, uniqueItems: true, items: { type: string } } route: { type: string, nullable: true, maxLength: 255 } fbaAppointmentNo: { type: string, nullable: true, maxLength: 64 } fbaAppointmentStatus: { type: string, nullable: true, maxLength: 32, default: PENDING } vehicleAppointmentStatus: { type: string, nullable: true, maxLength: 32, default: PENDING } draftToken: { type: string, nullable: true, maxLength: 64, description: 拖入托盘时使用的智能排车草稿标识 } SmartDispatchDraftPallet: type: object required: [planPalletId, draftToken] properties: planPalletId: { type: string } draftToken: { type: string, minLength: 1, maxLength: 64 } draftContainerId: { type: string, nullable: true, description: 托盘所在草稿车厢ID } SmartDispatchDraftRelease: type: object required: [draftToken] properties: draftToken: { type: string, minLength: 1, maxLength: 64 } SmartDispatchDraftSnapshot: type: object required: [draftToken, planIds, containersJson] properties: draftToken: { type: string, minLength: 1, maxLength: 64 } planIds: { type: array, minItems: 1, maxItems: 500, uniqueItems: true, items: { type: string } } containersJson: { type: string, minLength: 1, maxLength: 20000 } SmartDispatchDraftContainerCreate: type: object required: [draftToken, capacity] properties: draftToken: { type: string, minLength: 1, maxLength: 64 } capacity: { type: integer, minimum: 1, maximum: 500 } SmartDispatchDraft: type: object required: [draftToken, containers] properties: draftToken: { type: string } planIdsJson: { type: string, nullable: true } containersJson: { type: string, nullable: true } containers: { type: array, items: { $ref: '#/components/schemas/SmartDispatchDraftContainer' } } SmartDispatchDraftContainer: type: object required: [id, capacity, palletIds] properties: id: { type: string } capacity: { type: integer } palletIds: { type: array, items: { type: string } } DispatchUpdate: type: object description: 普通编辑字段;不包含 status 或 departAt。 properties: vehiclePlate: { type: string, nullable: true, maxLength: 64 } driverName: { type: string, nullable: true, maxLength: 128 } driverPhone: { type: string, nullable: true, maxLength: 64 } carrierName: { type: string, nullable: true, maxLength: 255 } route: { type: string, nullable: true, maxLength: 255 } fbaAppointmentNo: { type: string, nullable: true, maxLength: 64 } fbaAppointmentStatus: { type: string, nullable: true, maxLength: 32 } vehicleAppointmentStatus: { type: string, nullable: true, maxLength: 32 } estimatedArrivalAt: { type: string, format: date-time, nullable: true } DeliveryTransfer: type: object required: [idempotencyKey, plannedDeliveryAt, deliveryMethod, pickupMethod, loadingType, fees] properties: idempotencyKey: { type: string, minLength: 1, maxLength: 255 } plannedDeliveryAt: { type: string, format: date-time } deliveryMethod: { type: string, maxLength: 32 } waybillNo: { type: string, nullable: true, maxLength: 128 } carrierName: { type: string, nullable: true, maxLength: 255 } pickupMethod: { type: string, maxLength: 64 } loadingType: { type: string, maxLength: 64 } vehicleType: { type: string, nullable: true, maxLength: 64 } vehicleSize: { type: string, nullable: true, maxLength: 64 } driverName: { type: string, nullable: true, maxLength: 128 } driverPhone: { type: string, nullable: true, maxLength: 64 } vehiclePlate: { type: string, nullable: true, maxLength: 64 } appointmentAccount: { type: string, nullable: true, maxLength: 128 } sellerName: { type: string, nullable: true, maxLength: 128 } remark: { type: string, nullable: true, maxLength: 1000 } fees: { type: array, minItems: 1, maxItems: 20, items: { $ref: '#/components/schemas/DeliveryFeeInput' } } DeliveryStatusChange: type: object required: [status, expectedVersion] properties: status: { type: string, enum: [WAIT_DELIVERY, DELIVERING, DELIVERED, REJECTED, CANCELLED] } expectedVersion: { type: integer, format: int64, minimum: 0 } remark: { type: string, nullable: true, maxLength: 500 } DeliveryAllowedAction: type: string enum: [START_DELIVERY, COMPLETE_DELIVERY, REJECT_DELIVERY, CANCEL_DELIVERY, MARK_RETURN] description: START/COMPLETE/REJECT/CANCEL 使用通用 status 接口;MARK_RETURN 使用 mark-return 接口。 DeliveryMarkReturn: type: object required: [inboundOrderId, reason, returnDirection, items, idempotencyKey] properties: inboundOrderId: { type: string, pattern: '^[1-9][0-9]*$' } reason: { type: string, minLength: 1, maxLength: 1000 } returnDirection: { type: string, enum: [OVERSEAS_WAREHOUSE, CUSTOMER, OTHER] } returnLogisticsNo: { type: string, nullable: true, maxLength: 128 } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } items: type: array minItems: 1 maxItems: 200 items: type: object required: [outboundPalletItemId, inventoryPositionId, packageCount] properties: outboundPalletItemId: { type: string, pattern: '^[1-9][0-9]*$' } inventoryPositionId: { type: string, pattern: '^[1-9][0-9]*$' } packageCount: { type: integer, format: int64, minimum: 1 } ExceptionStartProcessing: type: object required: [expectedVersion, idempotencyKey] properties: expectedVersion: { type: integer, format: int64, minimum: 0 } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } handlingAction: { type: string, nullable: true, maxLength: 1000 } ExceptionCancel: type: object required: [expectedVersion, idempotencyKey, reason] properties: expectedVersion: { type: integer, format: int64, minimum: 0 } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } reason: { type: string, minLength: 1, maxLength: 1000 } ExceptionComplete: type: object required: [expectedVersion, idempotencyKey, handlingResult, evidenceFileIds] properties: expectedVersion: { type: integer, format: int64, minimum: 0 } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } handlingResult: { type: string, minLength: 1, maxLength: 2000 } evidenceFileIds: { type: array, minItems: 1, maxItems: 20, items: { type: string } } receipts: type: array maxItems: 200 items: type: object required: [outboundPalletItemId, inventoryPositionId, receivedPackages, targetPalletId, targetPalletNo, targetLocationId, targetLocationCode] properties: outboundPalletItemId: { type: string, pattern: '^[1-9][0-9]*$' } inventoryPositionId: { type: string, pattern: '^[1-9][0-9]*$' } receivedPackages: { type: integer, format: int64, minimum: 1 } targetPalletId: { type: string, pattern: '^[1-9][0-9]*$' } targetPalletNo: { type: string, minLength: 1, maxLength: 128 } targetLocationId: { type: string, pattern: '^[1-9][0-9]*$' } targetLocationCode: { type: string, minLength: 1, maxLength: 128 } ExceptionAllowedAction: type: string enum: [START_PROCESSING, COMPLETE_EXCEPTION, CANCEL_EXCEPTION] DeliveryFeeInput: type: object required: [feeType, feeName, direction, currency, amount] properties: feeType: { type: string, maxLength: 64 } feeName: { type: string, maxLength: 128 } direction: { type: string, enum: [RECEIVABLE, PAYABLE] } currency: { type: string, enum: [CNY, USD] } amount: { type: number, exclusiveMinimum: 0 } supplierId: { type: string, pattern: '^[1-9][0-9]*$' } supplierName: { type: string, maxLength: 200 } supplierCategory: { type: string, maxLength: 32 } settlementMode: { type: string, enum: [ON_ACCOUNT, DIRECT_PAID] } chargeableQuantity: { type: number, exclusiveMinimum: 0 } quantityUnit: { type: string, maxLength: 32 } unitPrice: { type: number, exclusiveMinimum: 0 } periodStart: { type: string, format: date } periodEnd: { type: string, format: date } remark: { type: string, nullable: true, maxLength: 500 } OneClickOutboundCreate: type: object required: [recipient, items, idempotencyKey] properties: recipient: { type: string, maxLength: 1000 } remark: { type: string, nullable: true, maxLength: 1000 } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } items: type: array minItems: 1 maxItems: 200 items: type: object required: [inventoryPositionId, packages, sku] properties: inventoryPositionId: { type: string, pattern: '^[1-9][0-9]*$' } packages: { type: integer, format: int64, minimum: 1 } sku: { type: string, maxLength: 128 } OneClickOutboundCandidate: type: object required: [inventoryPositionId, overseasWarehouseId, palletNo, skuCode, availablePackages] properties: inventoryPositionId: { type: string, pattern: '^[1-9][0-9]*$', description: 创建命令提交键,不作为用户展示编号 } overseasWarehouseId: { type: string } overseasWarehouseName: { type: string, nullable: true } palletNo: { type: string } inboundCode: { type: string, nullable: true } skuCode: { type: string } productName: { type: string, nullable: true } availablePackages: { type: integer, format: int64, minimum: 1, description: 库存位置、SKU余额和AVAILABLE箱唛三者的可用最小值 } OutboundCancel: type: object required: [reason] properties: { reason: { type: string, minLength: 1, maxLength: 1000 } } DispatchResponse: type: object properties: id: { type: string } dispatchNo: { type: string } vehiclePlate: { type: string, nullable: true } driverName: { type: string, nullable: true } driverPhone: { type: string, nullable: true } carrierName: { type: string, nullable: true } orderNos: { type: string } route: { type: string, nullable: true } overseasWarehouseId: { type: string } overseasWarehouseName: { type: string } departAt: { type: string, format: date-time, nullable: true } fbaAppointmentNo: { type: string, nullable: true } fbaAppointmentStatus: { type: string } vehicleAppointmentStatus: { type: string } estimatedArrivalAt: { type: string, format: date-time, nullable: true } status: { type: string, description: 预排新建固定为 PENDING_DEPARTURE;查询可返回历史排车状态 } itemCount: { type: integer } palletCount: { type: integer } packageCount: { type: integer } pickedPackageCount: { type: integer } shippedPackageCount: { type: integer } remainingPackageCount: { type: integer } partialCompletionReason: { type: string, nullable: true } createdAt: { type: string, format: date-time } items: { type: array, items: { $ref: '#/components/schemas/DispatchItem' } } DispatchItem: type: object properties: id: { type: string } planPalletId: { type: string } warehousePalletId: { type: string, nullable: true } palletNo: { type: string } overseasWarehouseId: { type: string } overseasWarehouseName: { type: string } orderNo: { type: string } orderRefs: { type: string } inboundCode: { type: string } destinationWarehouseCode: { type: string } destinationWarehouseName: { type: string } fbaWarehouseCode: { type: string } packageCount: { type: integer } volumeCbm: { type: number } sourceStage: { type: string, enum: [PLAN, RECEIVED] } RelabelStatus: { type: string, enum: [PENDING_PROCESSING, PROCESSING, COMPLETED, REJECTED, CANCELLED] } RelabelCreate: type: object required: [customerOrderNo, labelDeadline, contactName, contactPhone, chargeAmount, idempotencyKey, items] properties: customerOrderNo: { type: string, maxLength: 128 } overseasWarehouseId: { type: string, nullable: true, maxLength: 128, description: 统一目的海外仓;明细未填写目的仓时使用 } labelDeadline: { type: string, format: date-time } contactName: { type: string, maxLength: 128 } contactPhone: { type: string, maxLength: 64 } chargeAmount: { type: number, minimum: 0.01, description: 本次贴标费用(CNY) } remark: { type: string, nullable: true, maxLength: 1000 } idempotencyKey: { type: string, maxLength: 255 } items: { type: array, minItems: 1, maxItems: 500, items: { $ref: '#/components/schemas/RelabelItem' } } RelabelItem: type: object required: [productNameZh, totalPackageCount, notifiedPackageCount, shipmentNo, newSkuCode, cartonMark, fbaCartonMark] properties: skuCode: { type: string, nullable: true, maxLength: 128, description: 商品 SKU(选填) } productImageFileId: { type: string, nullable: true, maxLength: 128 } productImageFileName: { type: string, nullable: true, maxLength: 255 } productImageUrl: { type: string, nullable: true, maxLength: 1000 } productNameZh: { type: string, maxLength: 255 } totalPackageCount: { type: integer, minimum: 1 } notifiedPackageCount: { type: integer, minimum: 1 } shipmentNo: { type: string, maxLength: 128 } trackingCode: { type: string, nullable: true, maxLength: 255 } newSkuCode: { type: string, maxLength: 128 } labelRequirement: { type: string, nullable: true, maxLength: 1000 } relabelFileId: { type: string, nullable: true, maxLength: 128 } relabelFileName: { type: string, nullable: true, maxLength: 255 } relabelFileUrl: { type: string, nullable: true, maxLength: 1000 } cartonMark: { type: string, maxLength: 255, description: 客户自有箱唛(不在编辑列表展示) } fbaCartonMark: { type: string, maxLength: 255, description: 关联 FBA 箱唛 } destinationWarehouseId: { type: string, nullable: true, maxLength: 128, description: 该箱目的海外仓;为空时使用申请统一目的仓 } RelabelStatusChange: type: object required: [status] properties: status: { $ref: '#/components/schemas/RelabelStatus' } remark: { type: string, nullable: true, maxLength: 1000 } MerchantApiResponse: type: object required: [code, data] properties: code: { type: string, example: '200' } message: { type: string, nullable: true } data: { nullable: true } requestId: { type: string, nullable: true } traceId: { type: string, nullable: true } timestamp: { type: string, format: date-time, nullable: true } ProcurementPageResponse: allOf: - { $ref: '#/components/schemas/MerchantApiResponse' } - type: object properties: { data: { $ref: '#/components/schemas/ProcurementPage' } } ProcurementDetailResponse: allOf: - { $ref: '#/components/schemas/MerchantApiResponse' } - type: object properties: { data: { $ref: '#/components/schemas/ProcurementDetail' } } TruckPageResponse: allOf: - { $ref: '#/components/schemas/MerchantApiResponse' } - type: object properties: { data: { $ref: '#/components/schemas/TruckPage' } } TruckDetailResponse: allOf: - { $ref: '#/components/schemas/MerchantApiResponse' } - type: object properties: { data: { $ref: '#/components/schemas/TruckDetail' } } LooseboardPageResponse: allOf: - { $ref: '#/components/schemas/MerchantApiResponse' } - type: object properties: { data: { $ref: '#/components/schemas/LooseboardPage' } } LooseboardDetailResponse: allOf: - { $ref: '#/components/schemas/MerchantApiResponse' } - type: object properties: { data: { $ref: '#/components/schemas/LooseboardDetail' } } InboundPlanPageResponse: allOf: - { $ref: '#/components/schemas/MerchantApiResponse' } - type: object properties: { data: { $ref: '#/components/schemas/InboundPlanPage' } } InboundPlanDetailResponse: allOf: - { $ref: '#/components/schemas/MerchantApiResponse' } - type: object properties: { data: { $ref: '#/components/schemas/InboundPlanDetail' } } ContainerInboundPlanPreviewApiResponse: allOf: - { $ref: '#/components/schemas/MerchantApiResponse' } - type: object properties: { data: { $ref: '#/components/schemas/ContainerInboundPlanPreview' } } LastlegOrderHoldRequest: type: object required: [held, chargeable, reason, expectedVersion] properties: held: { type: boolean } chargeable: { type: boolean, description: 仅 held=true 时生效;解除暂扣后固定为 false } reason: { type: string, minLength: 1, maxLength: 500 } expectedVersion: { type: integer, minimum: 0 } LastlegOrderHoldResponse: type: object required: [orderId, held, chargeable, version] properties: orderId: { type: integer, format: int64 } held: { type: boolean } chargeable: { type: boolean } reason: { type: string, nullable: true } version: { type: integer, minimum: 0 } LastlegOrderManualNodeCode: type: string enum: [DOMESTIC_CUSTOMS_COMPLETED, ESTIMATED_DEPARTURE, ACTUAL_DEPARTURE, ESTIMATED_ARRIVAL, OVERSEAS_CUSTOMS_COMPLETED, ACTUAL_ARRIVAL_WAITING_UNLOAD, PICKUP_APPOINTED, UNLOADED] LastlegOrderManualNode: type: object required: [nodeCode] properties: nodeCode: { $ref: '#/components/schemas/LastlegOrderManualNodeCode' } nodeAt: { type: string, format: date-time, nullable: true } LastlegOrderManualNodesRequest: type: object required: [expectedVersion, nodes] properties: expectedVersion: { type: integer, minimum: 0 } nodes: type: array minItems: 8 maxItems: 8 description: 必须包含8个枚举节点且各出现一次,至少一个 nodeAt 非空。 items: { $ref: '#/components/schemas/LastlegOrderManualNode' } ManualInboundPlanRequest: type: object description: 单票人工计划只能使用所属柜已冻结的接柜仓;接柜仓变更必须通过柜级接口完成。 required: [customerId, orderId, expectedOrderVersion, plannedArrivalDate, palletCount, palletType, assigned, mergeRequired, urgent] properties: customerId: { type: string, pattern: '^[1-9][0-9]*$' } orderId: { type: integer, format: int64, minimum: 1 } expectedOrderVersion: { type: integer, minimum: 0 } plannedArrivalDate: { type: string, format: date } palletCount: { type: integer, minimum: 1, maximum: 999 } palletType: { type: string, minLength: 1, maxLength: 64 } assigned: { type: boolean } mergeRequired: { type: boolean } urgent: { type: boolean } remark: { type: string, nullable: true, maxLength: 1000 } PageMetadata: type: object required: [page, size, total, pages] properties: page: { type: integer, format: int64 } size: { type: integer, format: int64 } total: { type: integer, format: int64 } pages: { type: integer, format: int64 } ProcurementPage: allOf: - { $ref: '#/components/schemas/PageMetadata' } - type: object required: [records] properties: { records: { type: array, items: { $ref: '#/components/schemas/ProcurementSummary' } } } ProcurementSummary: type: object required: [id, orderNo, customerId, purchaseCategory, productName, purchaseQuantity, inboundQuantity, outboundQuantity, inventoryQuantity, status, version, createdAt, updatedAt] properties: id: { type: string, pattern: '^[0-9]+$' } orderNo: { type: string } customerId: { type: string } customerName: { type: string, nullable: true } purchaseCategory: { type: string } productName: { type: string } productSpecification: { type: string, nullable: true } purchaseQuantity: { type: integer, format: int64 } budgetUnitPrice: { type: number, nullable: true } currency: { type: string, nullable: true } purchaseWarehouseId: { type: string, nullable: true } purchaseWarehouseName: { type: string, nullable: true } inboundQuantity: { type: integer, format: int64 } outboundQuantity: { type: integer, format: int64 } inventoryQuantity: { type: integer, format: int64 } status: { type: string, description: PENDING_REVIEW/APPROVED/REJECTED 或按审核后出库数量派生的 PENDING_OUTBOUND/PARTIALLY_OUTBOUND/OUTBOUNDED } version: { type: integer, format: int64 } createdAt: { type: string, format: date-time } updatedAt: { type: string, format: date-time } ProcurementDetail: type: object required: [summary, histories, outboundDetails] properties: summary: { $ref: '#/components/schemas/ProcurementSummary' } productUrl: { type: string, nullable: true } receivingAddress: { type: string, nullable: true } contactName: { type: string, nullable: true } contactPhone: { type: string, nullable: true } domesticCarrier: { type: string, nullable: true } domesticTrackingNo: { type: string, nullable: true } overseasCarrier: { type: string, nullable: true } overseasTrackingNo: { type: string, nullable: true } estimatedArrivalAt: { type: string, format: date-time, nullable: true } remark: { type: string, nullable: true } createdBy: { type: string, nullable: true } reviewedBy: { type: string, nullable: true } reviewRemark: { type: string, nullable: true } reviewedAt: { type: string, format: date-time, nullable: true } histories: { type: array, items: { $ref: '#/components/schemas/BusinessHistory' } } outboundDetails: { type: array, items: { $ref: '#/components/schemas/ProcurementOutboundDetail' } } ProcurementOutboundDetail: type: object properties: id: { type: string } quantity: { type: integer, format: int64 } carrier: { type: string, nullable: true } trackingNo: { type: string, nullable: true } shippedAt: { type: string, format: date-time, nullable: true } remark: { type: string, nullable: true } TruckPage: allOf: - { $ref: '#/components/schemas/PageMetadata' } - type: object required: [records] properties: { records: { type: array, items: { $ref: '#/components/schemas/TruckSummary' } } } TruckSummary: type: object required: [id, customerId, orderNo, origin, destination, palletCount, packageCount, receivedPalletCount, allocatedPalletCount, totalWeightKg, totalVolumeCbm, status, version, createdAt, updatedAt] properties: id: { type: string, pattern: '^[0-9]+$' } customerId: { type: string } orderNo: { type: string } transportType: { type: string, nullable: true } origin: { type: string } destination: { type: string } containerType: { type: string, nullable: true } palletCount: { type: integer } packageCount: { type: integer } receivedPalletCount: { type: integer } allocatedPalletCount: { type: integer } totalWeightKg: { type: number } totalVolumeCbm: { type: number } budgetAmount: { type: number, nullable: true } currency: { type: string, nullable: true } contactName: { type: string, nullable: true } contactInfo: { type: string, nullable: true } requestedDate: { type: string, format: date, nullable: true } status: { $ref: '#/components/schemas/TruckStatus' } version: { type: integer, format: int64 } createdAt: { type: string, format: date-time } updatedAt: { type: string, format: date-time } TruckDetail: type: object required: [summary, pallets, histories] properties: summary: { $ref: '#/components/schemas/TruckSummary' } originAddress: { type: string, nullable: true } destinationAddress: { type: string, nullable: true } remark: { type: string, nullable: true } createdBy: { type: string, nullable: true } pallets: { type: array, items: { $ref: '#/components/schemas/TruckPallet' } } histories: { type: array, items: { $ref: '#/components/schemas/BusinessHistory' } } TruckPallet: type: object properties: id: { type: string, pattern: '^[0-9]+$' } palletNo: { type: string } sequenceNo: { type: integer } source: { type: string } status: { type: string } warehousePalletId: { type: string, pattern: '^[0-9]+$', nullable: true } packageCount: { type: integer, nullable: true } receivedAt: { type: string, format: date-time, nullable: true } LooseboardPage: allOf: - { $ref: '#/components/schemas/PageMetadata' } - type: object required: [records] properties: { records: { type: array, items: { $ref: '#/components/schemas/LooseboardSummary' } } } LooseboardSummary: type: object required: [id, customerId, orderNo, transportMode, palletRequired, transportType, origin, destination, packageCount, totalWeightKg, totalVolumeCbm, status, version, createdAt, updatedAt] properties: id: { type: string, pattern: '^[0-9]+$' } customerId: { type: string } orderNo: { type: string } transportMode: { type: string, enum: [SHARED_TRUCK, PRIORITY_CONSOLIDATION] } palletRequired: { type: string, enum: [YES, NO] } transportType: { type: string } origin: { type: string } destination: { type: string } containerType: { type: string, nullable: true } packageCount: { type: integer } totalWeightKg: { type: number } totalVolumeCbm: { type: number } budgetAmount: { type: number, nullable: true } currency: { type: string, nullable: true } contactName: { type: string, nullable: true } contactInfo: { type: string, nullable: true } requestedDate: { type: string, format: date, nullable: true } status: { $ref: '#/components/schemas/LooseboardStatus' } version: { type: integer, format: int64 } createdAt: { type: string, format: date-time } updatedAt: { type: string, format: date-time } LooseboardDetail: type: object required: [summary, histories] properties: summary: { $ref: '#/components/schemas/LooseboardSummary' } originAddress: { type: string, nullable: true } destinationAddress: { type: string, nullable: true } remark: { type: string, nullable: true } createdBy: { type: string, nullable: true } histories: { type: array, items: { $ref: '#/components/schemas/BusinessHistory' } } BusinessHistory: type: object properties: operationType: { type: string } fromStatus: { type: string, nullable: true } toStatus: { type: string, nullable: true } operatorId: { type: string, nullable: true } idempotencyKey: { type: string, nullable: true } changeDetail: { type: string, nullable: true } remark: { type: string, nullable: true } createdAt: { type: string, format: date-time } InboundPlanPage: allOf: - { $ref: '#/components/schemas/PageMetadata' } - type: object required: [records] properties: { records: { type: array, items: { $ref: '#/components/schemas/InboundPlanSummary' } } } InboundPlanSummary: type: object required: [lineId, planId, planNo, customerId, orderId, inboundCode, overseasWarehouseCode, overseasWarehouseName, packageCount, pickedPackageCount, palletCount, assigned, mergeAllowed, urgent, status, createdAt, version] properties: lineId: { type: string, pattern: '^[0-9]+$' } planId: { type: string, pattern: '^[0-9]+$' } planNo: { type: string } customerId: { type: string } orderId: { type: string, pattern: '^[0-9]+$' } inboundCode: { type: string } orderType: { type: string, nullable: true } overseasWarehouseCode: { type: string, description: 接柜仓编码,取自尾程订单预分配接收仓事实 } overseasWarehouseName: { type: string, description: 接柜仓名称,取自尾程订单预分配接收仓事实 } warehouseId: { type: string, nullable: true } warehouseCode: { type: string, nullable: true } warehouseName: { type: string, nullable: true } fbaWarehouseCode: { type: string, nullable: true } customerName: { type: string, nullable: true } packageCount: { type: integer } pickedPackageCount: { type: integer } volumeCbm: { type: number, nullable: true } palletCount: { type: integer } assigned: { type: boolean, description: 入库计划是否已分配 } mergeAllowed: { type: boolean, description: 入库计划是否允许现场选择合托;不作为强制门禁 } urgent: { type: boolean, description: 入库计划是否加急 } status: { type: string } appointmentNo: { type: string, nullable: true } appointmentStatus: { type: string, nullable: true } appointmentAt: { type: string, format: date-time, nullable: true } expectedLoadingAt: { type: string, format: date-time, nullable: true } dispatchStatus: { type: string, nullable: true } createdAt: { type: string, format: date-time } version: { type: integer } InboundPlanDetail: type: object required: [id, planNo, customerId, overseasWarehouseCode, overseasWarehouseName, status, lineCount, palletCount, totalVolumeCbm, expectedPackageCount, pickedPackageCount, lines, pallets, allocations, version] properties: id: { type: string, pattern: '^[0-9]+$' } planNo: { type: string } customerId: { type: string } sourceOrderId: { type: string, pattern: '^[0-9]+$', nullable: true } containerNo: { type: string, nullable: true } overseasWarehouseCode: { type: string, description: 接柜仓编码,取自尾程订单预分配接收仓事实 } overseasWarehouseName: { type: string, description: 接柜仓名称,取自尾程订单预分配接收仓事实 } status: { type: string } lineCount: { type: integer } palletCount: { type: integer } totalVolumeCbm: { type: number } expectedPackageCount: { type: integer } pickedPackageCount: { type: integer } plannedArrivalDate: { type: string, format: date, nullable: true } palletType: { type: string, nullable: true } assigned: { type: boolean } mergeRequired: { type: boolean } urgent: { type: boolean } creationMode: { type: string, enum: [AUTO, MANUAL] } remark: { type: string, nullable: true } lines: { type: array, items: { $ref: '#/components/schemas/InboundPlanLine' } } pallets: { type: array, items: { $ref: '#/components/schemas/InboundPlanPallet' } } allocations: { type: array, items: { $ref: '#/components/schemas/InboundPlanAllocation' } } version: { type: integer } ContainerInboundPlanPreview: type: object required: [sourceContainerBookingId, snapshotVersion, snapshotHash, totalOrderCount, readyOrderCount, blockedOrderCount, pendingOrderCount, pendingPalletCount, existingPlannedPalletCount, totalSuggestedPalletCount, totalPlannedPalletCount, ready, groups] properties: sourceContainerBookingId: { type: string } containerNo: { type: string, nullable: true } overseasWarehouseId: { type: string, nullable: true } overseasWarehouseCode: { type: string, nullable: true } overseasWarehouseName: { type: string, nullable: true } snapshotVersion: { type: integer, format: int64, minimum: 0 } snapshotHash: { type: string, pattern: '^[0-9a-f]{64}$' } totalOrderCount: { type: integer } readyOrderCount: { type: integer } blockedOrderCount: { type: integer } pendingOrderCount: { type: integer, description: 本次确认将新建计划的 READY 订单数 } pendingPalletCount: { type: integer, description: 本次确认将向资源服务批量预留的新托盘数 } existingPlannedPalletCount: { type: integer, description: 已有有效计划的托盘总数,不计入本次新增 } totalSuggestedPalletCount: { type: integer } totalPlannedPalletCount: { type: integer } ready: { type: boolean } groups: { type: array, items: { $ref: '#/components/schemas/ContainerInboundPlanPreviewGroup' } } ContainerInboundPlanPreviewGroup: type: object required: [destinationType, orderCount, pendingOrderCount, pendingPalletCount, existingPlannedPalletCount, suggestedPalletCount, plannedPalletCount, orders] properties: destinationType: { type: string, enum: [FBA, ONE_CLICK_DROPSHIP, PRIVATE_ADDRESS] } destinationWarehouseId: { type: string, nullable: true } destinationWarehouseCode: { type: string, nullable: true } destinationWarehouseName: { type: string, nullable: true } orderCount: { type: integer } pendingOrderCount: { type: integer } pendingPalletCount: { type: integer } existingPlannedPalletCount: { type: integer } suggestedPalletCount: { type: integer } plannedPalletCount: { type: integer } orders: { type: array, items: { $ref: '#/components/schemas/ContainerInboundPlanPreviewOrder' } } ContainerInboundPlanPreviewOrder: type: object required: [customerId, orderId, businessOrderNo, orderType, destinationType, packageCount, volumeCbm, orderVersion, readiness, blockers] properties: customerId: { type: string } customerName: { type: string, nullable: true } orderId: { type: string, pattern: '^[0-9]+$' } businessOrderNo: { type: string } inboundCode: { type: string, nullable: true } orderType: { type: string } destinationType: { type: string, enum: [FBA, ONE_CLICK_DROPSHIP, PRIVATE_ADDRESS] } destinationWarehouseId: { type: string, nullable: true } destinationWarehouseCode: { type: string, nullable: true } destinationWarehouseName: { type: string, nullable: true } fbaWarehouseCode: { type: string, nullable: true, description: 底层目的类型为 FBA 时的目的仓编码;一件代发展示分类不改变该事实 } packageCount: { type: integer } volumeCbm: { type: number } suggestedPalletCount: { type: integer, nullable: true } plannedPalletCount: { type: integer, nullable: true } existingPlanNo: { type: string, nullable: true } planStatus: { type: string, nullable: true } orderVersion: { type: integer, minimum: 0 } readiness: { type: string, enum: [READY, PLANNED, BLOCKED] } blockers: { type: array, items: { type: string } } InboundPlanLine: type: object properties: id: { type: string, pattern: '^[0-9]+$' } orderId: { type: string, pattern: '^[0-9]+$' } inboundCode: { type: string } fbaWarehouseCode: { type: string, nullable: true } destinationWarehouseId: { type: string, nullable: true } destinationWarehouseCode: { type: string, nullable: true } destinationWarehouseName: { type: string, nullable: true } volumeCbm: { type: number } requiredPackageCount: { type: integer } plannedPalletCount: { type: integer } InboundPlanPallet: type: object properties: id: { type: string, pattern: '^[0-9]+$' } palletNo: { type: string } palletType: { type: string, nullable: true } destinationWarehouseId: { type: string, nullable: true } destinationWarehouseCode: { type: string, nullable: true } destinationWarehouseName: { type: string, nullable: true } capacityCbm: { type: number } allocatedVolumeCbm: { type: number } sequenceNo: { type: integer } warehousePalletId: { type: string, pattern: '^[0-9]+$', nullable: true } warehouseLocationId: { type: string, pattern: '^[0-9]+$', nullable: true } warehouseResourceLockId: { type: string, pattern: '^[0-9]+$', nullable: true } assignmentStatus: { type: string, nullable: true } lockedAt: { type: string, format: date-time, nullable: true } actualVolumeCbm: { type: number, nullable: true } actualPackageCount: { type: integer } InboundPlanAllocation: type: object properties: lineId: { type: string, pattern: '^[0-9]+$' } palletId: { type: string, pattern: '^[0-9]+$' } allocatedVolumeCbm: { type: number } plannedPackageCount: { type: integer } countedPackageCount: { type: integer } pickedPackageCount: { type: integer } actualVolumeCbm: { type: number, nullable: true } status: { type: string } version: { type: integer } ProcurementStatus: { type: string, enum: [PENDING_REVIEW, APPROVED, REJECTED] } ProcurementReview: type: object required: [version, decision, idempotencyKey] properties: version: { type: integer, format: int64, minimum: 0 } decision: { type: string, enum: [APPROVE, REJECT] } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } remark: { type: string, nullable: true, maxLength: 1000 } ProcurementCreate: type: object required: [purchaseCategory, productName, purchaseQuantity, contactName, contactPhone, idempotencyKey] properties: customerName: { type: string, nullable: true, maxLength: 255 } purchaseCategory: { type: string, maxLength: 128 } productName: { type: string, maxLength: 255 } productSpecification: { type: string, nullable: true, maxLength: 500 } productUrl: { type: string, nullable: true, maxLength: 2000 } purchaseQuantity: { type: integer, format: int64, minimum: 1 } budgetUnitPrice: { type: number, nullable: true, minimum: 0 } currency: { type: string, minLength: 3, maxLength: 3, default: USD } receivingAddress: { type: string, nullable: true, maxLength: 1000 } contactName: { type: string, maxLength: 128 } contactPhone: { type: string, maxLength: 64 } remark: { type: string, nullable: true, maxLength: 1000 } idempotencyKey: { type: string, maxLength: 255 } NullableTextPatch: { type: string, nullable: true, description: 缺失不修改;null 或空串清空 } ProcurementUpdate: type: object required: [version] properties: version: { type: integer, format: int64, minimum: 0 } purchaseCategory: { type: string, maxLength: 128 } productName: { type: string, maxLength: 255 } productSpecification: { $ref: '#/components/schemas/NullableTextPatch' } productUrl: { $ref: '#/components/schemas/NullableTextPatch' } inboundQuantity: { type: integer, format: int64, minimum: 0 } purchaseWarehouseId: { $ref: '#/components/schemas/NullableTextPatch' } purchaseWarehouseName: { $ref: '#/components/schemas/NullableTextPatch' } domesticCarrier: { $ref: '#/components/schemas/NullableTextPatch' } domesticTrackingNo: { $ref: '#/components/schemas/NullableTextPatch' } overseasCarrier: { $ref: '#/components/schemas/NullableTextPatch' } overseasTrackingNo: { $ref: '#/components/schemas/NullableTextPatch' } estimatedArrivalAt: { type: string, format: date-time, nullable: true, description: 缺失不修改;null 或空串清空 } remark: { $ref: '#/components/schemas/NullableTextPatch' } outboundDetails: type: array description: 出库明细,可一次提交多条;总出库量不得超过入库量 items: type: object required: [quantity] properties: id: { type: string } quantity: { type: integer, format: int64, minimum: 0 } carrier: { type: string, nullable: true, maxLength: 128 } trackingNo: { type: string, nullable: true, maxLength: 128 } shippedAt: { type: string, format: date-time, nullable: true } remark: { type: string, nullable: true, maxLength: 500 } CustomerOptionResponse: type: object properties: code: { type: string, enum: ['200'] } data: { type: array, items: { type: object, properties: { customerId: { type: string }, customerName: { type: string } } } } WarehouseOptionResponse: type: object properties: code: { type: string, enum: ['200'] } data: { type: array, items: { type: object, properties: { warehouseId: { type: string }, warehouseCode: { type: string }, warehouseName: { type: string }, countryCode: { type: string } } } } TruckStatus: { type: string, enum: [PENDING_REVIEW, WAITING_INBOUND, RECEIVING, WAITING_CONSOLIDATION, PALLET_OVERAGE_REVIEW, PARTIALLY_ALLOCATED, ALLOCATED, PENDING_DISPATCH, DISPATCHED, IN_TRANSIT, COMPLETED, REJECTED, CANCELLED] } TruckReview: type: object required: [version, decision, idempotencyKey] properties: version: { type: integer, format: int64, minimum: 0 } decision: { type: string, enum: [APPROVE, REJECT] } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } remark: { type: string, nullable: true, maxLength: 1000 } TruckCancel: type: object required: [version, status, idempotencyKey] properties: version: { type: integer, format: int64, minimum: 0 } status: { type: string, enum: [CANCELLED] } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } remark: { type: string, nullable: true, maxLength: 1000 } TruckReceivePallets: type: object required: [version, actualPalletCount, idempotencyKey] properties: version: { type: integer, format: int64, minimum: 0 } actualPalletCount: { type: integer, minimum: 1 } packageCount: { type: integer, nullable: true, minimum: 0 } palletPackageCounts: { type: array, maxItems: 500, items: { type: integer, minimum: 0 } } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } remark: { type: string, nullable: true, maxLength: 1000 } TruckReviewPalletOverage: allOf: [{ $ref: '#/components/schemas/TruckReview' }] TruckAllocatePallets: type: object required: [version, palletIds, idempotencyKey] properties: version: { type: integer, format: int64, minimum: 0 } palletIds: { type: array, minItems: 1, maxItems: 500, uniqueItems: true, items: { type: integer, format: int64, minimum: 1 } } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } remark: { type: string, nullable: true, maxLength: 1000 } TruckCommand: type: object required: [version, idempotencyKey] properties: version: { type: integer, format: int64, minimum: 0 } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } remark: { type: string, nullable: true, maxLength: 1000 } TruckCreate: type: object required: [origin, destination, palletCount, totalWeightKg, totalVolumeCbm, contactName, contactInfo, requestedDate, idempotencyKey] properties: transportType: { type: string, enum: [PORT_PICKUP, WAREHOUSE_TO_WAREHOUSE, WAREHOUSE_TO_DOOR] } origin: { type: string, maxLength: 255 } originAddress: { type: string, nullable: true, maxLength: 500 } destination: { type: string, maxLength: 255 } destinationAddress: { type: string, nullable: true, maxLength: 500 } containerType: { type: string, nullable: true, maxLength: 32 } palletCount: { type: integer, minimum: 1 } packageCount: { type: integer, nullable: true, minimum: 0 } totalWeightKg: { type: number, minimum: 0 } totalVolumeCbm: { type: number, minimum: 0 } budgetAmount: { type: number, nullable: true, minimum: 0 } currency: { type: string, minLength: 3, maxLength: 3, default: USD } contactName: { type: string, maxLength: 128 } contactInfo: { type: string, maxLength: 128 } requestedDate: { type: string, format: date } remark: { type: string, nullable: true, maxLength: 1000 } idempotencyKey: { type: string, maxLength: 255 } TruckUpdate: type: object required: [version] properties: version: { type: integer, format: int64, minimum: 0 } transportType: { type: string, enum: [PORT_PICKUP, WAREHOUSE_TO_WAREHOUSE, WAREHOUSE_TO_DOOR] } origin: { type: string, maxLength: 255 } originAddress: { type: string, nullable: true, maxLength: 500 } destination: { type: string, maxLength: 255 } destinationAddress: { type: string, nullable: true, maxLength: 500 } containerType: { type: string, nullable: true, maxLength: 32 } palletCount: { type: integer, minimum: 1 } packageCount: { type: integer, minimum: 0 } totalWeightKg: { type: number, minimum: 0 } totalVolumeCbm: { type: number, minimum: 0 } budgetAmount: { type: number, nullable: true, minimum: 0 } currency: { type: string, minLength: 3, maxLength: 3 } contactName: { type: string, maxLength: 128 } contactInfo: { type: string, maxLength: 128 } requestedDate: { type: string, format: date } remark: { type: string, nullable: true, maxLength: 1000 } LooseboardStatus: { type: string, enum: [PENDING_ACCEPTANCE, DISPATCHED, IN_TRANSIT, COMPLETED, CANCELLED] } LooseboardStatusChange: type: object required: [version, status, idempotencyKey] properties: version: { type: integer, format: int64, minimum: 0 } status: { $ref: '#/components/schemas/LooseboardStatus' } idempotencyKey: { type: string, minLength: 1, maxLength: 255 } remark: { type: string, nullable: true, maxLength: 1000 } LooseboardCreate: type: object required: [transportMode, palletRequired, transportType, origin, destination, packageCount, totalWeightKg, totalVolumeCbm, idempotencyKey] properties: transportMode: { type: string, enum: [SHARED_TRUCK, PRIORITY_CONSOLIDATION] } palletRequired: { type: string, enum: [YES, NO] } transportType: { type: string, enum: [PORT_PICKUP, WAREHOUSE_TO_WAREHOUSE, WAREHOUSE_TO_DOOR] } origin: { type: string, maxLength: 255 } originAddress: { type: string, nullable: true, maxLength: 500 } destination: { type: string, maxLength: 255 } destinationAddress: { type: string, nullable: true, maxLength: 500 } containerType: { type: string, nullable: true, maxLength: 32 } packageCount: { type: integer, minimum: 0 } totalWeightKg: { type: number, minimum: 0 } totalVolumeCbm: { type: number, minimum: 0 } budgetAmount: { type: number, nullable: true, minimum: 0 } currency: { type: string, minLength: 3, maxLength: 3, default: USD } contactName: { type: string, nullable: true, maxLength: 128 } contactInfo: { type: string, nullable: true, maxLength: 128 } requestedDate: { type: string, format: date, nullable: true } remark: { type: string, nullable: true, maxLength: 1000 } idempotencyKey: { type: string, maxLength: 255 } LooseboardUpdate: type: object required: [version, transportMode, palletRequired, transportType, origin, destination, packageCount, totalWeightKg, totalVolumeCbm] properties: version: { type: integer, format: int64, minimum: 0 } transportMode: { type: string, enum: [SHARED_TRUCK, PRIORITY_CONSOLIDATION] } palletRequired: { type: string, enum: [YES, NO] } transportType: { type: string, enum: [PORT_PICKUP, WAREHOUSE_TO_WAREHOUSE, WAREHOUSE_TO_DOOR] } origin: { type: string, maxLength: 255 } originAddress: { type: string, nullable: true, maxLength: 500 } destination: { type: string, maxLength: 255 } destinationAddress: { type: string, nullable: true, maxLength: 500 } containerType: { type: string, nullable: true, maxLength: 32 } packageCount: { type: integer, minimum: 0 } totalWeightKg: { type: number, minimum: 0 } totalVolumeCbm: { type: number, minimum: 0 } budgetAmount: { type: number, nullable: true, minimum: 0 } currency: { type: string, minLength: 3, maxLength: 3, default: USD } contactName: { type: string, nullable: true, maxLength: 128 } contactInfo: { type: string, nullable: true, maxLength: 128 } requestedDate: { type: string, format: date, nullable: true } remark: { type: string, nullable: true, maxLength: 1000 } securitySchemes: bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }