feat(appointment): integrate work calendar and stable cargo batches

This commit is contained in:
2026-10-15 16:55:57 +08:00
parent dbb93a06c2
commit a1d5ebdab2
171 changed files with 7898 additions and 396 deletions
@@ -0,0 +1,59 @@
-- DDL proposal only. The coordinator must integrate the approved baseline; do not execute from this task.
CREATE TABLE IF NOT EXISTS ll_dispatch_appointment_allocation (
dispatch_id BIGINT NOT NULL,
dispatch_item_id BIGINT NOT NULL,
plan_pallet_id BIGINT NOT NULL,
batch_key VARCHAR(96) NOT NULL,
customer_id VARCHAR(64) NOT NULL,
source_key VARCHAR(160) NOT NULL,
destination_key VARCHAR(160) NOT NULL,
package_count INT NOT NULL,
PRIMARY KEY(dispatch_item_id,batch_key,source_key,destination_key),
KEY idx_dispatch_appointment_batch(batch_key,customer_id),
KEY idx_dispatch_appointment_dispatch(dispatch_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='排车实物与预约批次逐票分配,原执行域事实';
CREATE TABLE IF NOT EXISTS ll_appointment_work_commitment (
entity_key VARCHAR(160) NOT NULL,
state_json LONGTEXT NOT NULL COMMENT '原业务命令产生的只读语义影响基线,不是第二份可编辑计划',
impact_version BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (entity_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工作事项承诺影响审计基线';
CREATE TABLE IF NOT EXISTS ll_appointment_work_guard (
id INT NOT NULL COMMENT '工作事项协调锁,固定1',
scan_cursor VARCHAR(128) NULL COMMENT '已开船来源同步游标',
initialized BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否完成首次完整来源扫描',
scope_version VARCHAR(128) NULL COMMENT '完整同步已确认的权威来源集合版本',
scan_scope_version VARCHAR(128) NULL COMMENT '当前扫描来源集合版本,防跨页漂移',
completed_at DATETIME(3) NULL COMMENT '最近完整同步UTC时间',
requirement_version BIGINT NOT NULL DEFAULT 0 COMMENT '原域命令在同一事务推进的需求版本',
synchronized_requirement_version BIGINT NOT NULL DEFAULT 0 COMMENT '完整扫描已消费需求版本',
scan_requirement_version BIGINT NOT NULL DEFAULT 0 COMMENT '当前扫描需求版本,防跨页漂移',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='预约工作事项同步与命令串行守卫';
INSERT INTO ll_appointment_work_guard(id,initialized) SELECT 1,FALSE WHERE NOT EXISTS(SELECT 1 FROM ll_appointment_work_guard WHERE id=1);
CREATE TABLE IF NOT EXISTS ll_appointment_work (
work_item_key VARCHAR(96) NOT NULL COMMENT '不可变事项键,业务身份确定性生成',
container_booking_id VARCHAR(64) NOT NULL COMMENT '来源柜次内部关联标识,不作展示编号',
version INT NOT NULL DEFAULT 0 COMMENT '工作命令乐观锁版本',
retired BOOLEAN NOT NULL DEFAULT FALSE COMMENT '已替代或已完成路线需求,不计活动工作',
state_json LONGTEXT NOT NULL COMMENT '工作关系责任跟进及影响基线,不保存可编辑业务执行事实',
PRIMARY KEY (work_item_key),
KEY idx_appointment_work_container (container_booking_id,retired)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='预约工作事项需求与关系';
CREATE TABLE IF NOT EXISTS ll_appointment_work_history (
id VARCHAR(36) NOT NULL COMMENT '历史记录标识',
work_item_key VARCHAR(96) NOT NULL COMMENT '事项稳定键',
operator_id VARCHAR(64) NOT NULL COMMENT '真实操作人员标识',
operator_name VARCHAR(128) NULL COMMENT '操作人显示名称',
action VARCHAR(48) NOT NULL COMMENT '工作命令或观察动作',
summary VARCHAR(2000) NOT NULL COMMENT '处理或责任变更依据',
command_key VARCHAR(64) NULL COMMENT '请求幂等键,观察记录为空',
request_hash VARCHAR(64) NULL COMMENT '包含操作者的规范请求摘要',
response_json LONGTEXT NULL COMMENT '原命令响应快照,重放不随当前状态改变',
occurred_at DATETIME(3) NOT NULL COMMENT '历史发生UTC时间',
PRIMARY KEY (id),
UNIQUE KEY uk_appointment_work_command (work_item_key,command_key),
KEY idx_appointment_work_history (work_item_key,occurred_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='预约工作事项历史与幂等命令';
@@ -1667,6 +1667,9 @@ CREATE TABLE IF NOT EXISTS ll_inbound_fba_appointment (
appointment_remark VARCHAR(1000) NULL COMMENT '备注或取消原因',
fba_warehouse_code VARCHAR(128) NOT NULL COMMENT 'FBA目的仓编码',
selected_count INT NOT NULL DEFAULT 0 COMMENT '真实货源票数',
replacement_nos_json LONGTEXT NULL COMMENT '分批或合并后的新预约业务号列表,非空时原批次只读',
replacement_keys_json LONGTEXT NULL COMMENT '替代批次不可变键列表,只用于内部业务关联',
repartition_reason VARCHAR(1000) NULL COMMENT '分批或合并原因,原安排及来源明细保留',
created_by VARCHAR(128) NOT NULL COMMENT '登录操作人',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建UTC时间',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '更新UTC时间',
@@ -1686,19 +1689,42 @@ CREATE TABLE IF NOT EXISTS ll_inbound_fba_appointment_item (
order_id BIGINT NULL COMMENT '尚未形成尾程订单时为空',
inbound_code VARCHAR(128) NULL COMMENT '真实入仓码,不伪造',
fba_warehouse_code VARCHAR(128) NOT NULL COMMENT '目的FBA仓编码',
package_count INT NULL COMMENT '所选整票预报箱数,未知保持空',
package_count INT NULL COMMENT '本批分配箱数,未知保持空;同一原来源总量守恒',
cargo_verification_version INT NULL COMMENT '采用的预约货物核实版本,未核实时为空',
shipment_references_json LONGTEXT NULL COMMENT '本次采用的货件或追踪号核实快照',
active TINYINT(1) NOT NULL DEFAULT 1 COMMENT '取消或失败后释放货源占用',
active_source_key VARCHAR(160) GENERATED ALWAYS AS (CASE WHEN active=1 THEN source_key ELSE NULL END) STORED COMMENT '有效货源唯一占用键',
active_order_id BIGINT GENERATED ALWAYS AS (CASE WHEN active=1 THEN order_id ELSE NULL END) STORED COMMENT '有效订单唯一占用键',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建UTC时间',
PRIMARY KEY (id),
UNIQUE KEY uk_ll_fba_item_source (appointment_id,source_key),
UNIQUE KEY uk_ll_fba_active_source (active_source_key),
UNIQUE KEY uk_ll_fba_active_order (active_order_id),
KEY idx_ll_fba_active_source (customer_id,source_key,active),
KEY idx_ll_fba_active_order (customer_id,order_id,active),
KEY idx_ll_fba_item_source_lookup (source_key,customer_id),
KEY idx_ll_fba_item_customer_order (customer_id,order_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='入仓前后共用的预约真实货源';
CREATE TABLE IF NOT EXISTS ll_appointment_cargo_verification (
id BIGINT NOT NULL COMMENT '核实记录主键',
customer_id VARCHAR(128) NOT NULL COMMENT '原货源所属客户',
source_key VARCHAR(160) NOT NULL COMMENT '稳定ORDER或BOOKING原来源键',
destination_key VARCHAR(160) NOT NULL COMMENT '核实时的原目的地',
source_version VARCHAR(160) NULL COMMENT '核实时的原来源版本',
source_packages INT NULL COMMENT '核实时的原来源箱数,未知为空',
version INT NOT NULL COMMENT '同一来源的核实版本,从一递增',
package_count INT NULL COMMENT '独立核实箱数,不回写原订单',
shipment_references_json LONGTEXT NOT NULL COMMENT '本票货件号或追踪号列表,不回写原订单',
remark VARCHAR(1000) NULL COMMENT '核实说明',
operator_id VARCHAR(128) NOT NULL COMMENT '登录操作人',
operator_name VARCHAR(200) NULL COMMENT '操作人名称快照',
command_key VARCHAR(64) NOT NULL COMMENT '来源内幂等命令键',
request_hash CHAR(64) NOT NULL COMMENT '来源、操作人及请求摘要',
created_at DATETIME(3) NOT NULL COMMENT '核实UTC时间',
PRIMARY KEY (id),
UNIQUE KEY uk_ll_cargo_verification_version (customer_id,source_key,version),
UNIQUE KEY uk_ll_cargo_verification_command (customer_id,source_key,command_key),
CONSTRAINT chk_ll_cargo_verification_quantity CHECK (package_count IS NULL OR package_count > 0),
CONSTRAINT chk_ll_cargo_verification_version CHECK (version > 0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='预约货物核实资料及不可覆盖的版本历史';
CREATE TABLE IF NOT EXISTS ll_fba_appointment_command (
command_key VARCHAR(128) NOT NULL COMMENT '持久化幂等键',
request_hash CHAR(64) NOT NULL COMMENT '操作、操作者和请求摘要',
@@ -4082,3 +4108,65 @@ CREATE TABLE IF NOT EXISTS ll_selfop_inventory_daily (
KEY idx_selfop_daily_identity (customer_code,sku_code,day_version_id),
CONSTRAINT chk_selfop_daily_quantity CHECK ((quality_status='VALID' AND physical_quantity IS NOT NULL AND physical_quantity>=0) OR (quality_status='UNKNOWN' AND physical_quantity IS NULL))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='历史日末分货主商品品质实物库存';
-- Appointment work scope, audit and physical batch allocation.
USE baiyue_lastleg;
CREATE TABLE IF NOT EXISTS ll_dispatch_appointment_allocation (
dispatch_id BIGINT NOT NULL,
dispatch_item_id BIGINT NOT NULL,
plan_pallet_id BIGINT NOT NULL,
batch_key VARCHAR(96) NOT NULL,
customer_id VARCHAR(64) NOT NULL,
source_key VARCHAR(160) NOT NULL,
destination_key VARCHAR(160) NOT NULL,
package_count INT NOT NULL,
PRIMARY KEY(dispatch_item_id,batch_key,source_key,destination_key),
KEY idx_dispatch_appointment_batch(batch_key,customer_id),
KEY idx_dispatch_appointment_dispatch(dispatch_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='排车实物与预约批次逐票分配,原执行域事实';
CREATE TABLE IF NOT EXISTS ll_appointment_work_commitment (
entity_key VARCHAR(160) NOT NULL,
state_json LONGTEXT NOT NULL COMMENT '原业务命令产生的只读语义影响基线,不是第二份可编辑计划',
impact_version BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (entity_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工作事项承诺影响审计基线';
CREATE TABLE IF NOT EXISTS ll_appointment_work_guard (
id INT NOT NULL COMMENT '工作事项协调锁,固定1',
scan_cursor VARCHAR(128) NULL COMMENT '已开船来源同步游标',
initialized BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否完成首次完整来源扫描',
scope_version VARCHAR(128) NULL COMMENT '完整同步已确认的权威来源集合版本',
scan_scope_version VARCHAR(128) NULL COMMENT '当前扫描来源集合版本,防跨页漂移',
completed_at DATETIME(3) NULL COMMENT '最近完整同步UTC时间',
requirement_version BIGINT NOT NULL DEFAULT 0 COMMENT '原域命令在同一事务推进的需求版本',
synchronized_requirement_version BIGINT NOT NULL DEFAULT 0 COMMENT '完整扫描已消费需求版本',
scan_requirement_version BIGINT NOT NULL DEFAULT 0 COMMENT '当前扫描需求版本,防跨页漂移',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='预约工作事项同步与命令串行守卫';
INSERT INTO ll_appointment_work_guard(id,initialized) SELECT 1,FALSE WHERE NOT EXISTS(SELECT 1 FROM ll_appointment_work_guard WHERE id=1);
CREATE TABLE IF NOT EXISTS ll_appointment_work (
work_item_key VARCHAR(96) NOT NULL COMMENT '不可变事项键,业务身份确定性生成',
container_booking_id VARCHAR(64) NOT NULL COMMENT '来源柜次内部关联标识,不作展示编号',
version INT NOT NULL DEFAULT 0 COMMENT '工作命令乐观锁版本',
retired BOOLEAN NOT NULL DEFAULT FALSE COMMENT '已替代或已完成路线需求,不计活动工作',
state_json LONGTEXT NOT NULL COMMENT '工作关系责任跟进及影响基线,不保存可编辑业务执行事实',
PRIMARY KEY (work_item_key),
KEY idx_appointment_work_container (container_booking_id,retired)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='预约工作事项需求与关系';
CREATE TABLE IF NOT EXISTS ll_appointment_work_history (
id VARCHAR(36) NOT NULL COMMENT '历史记录标识',
work_item_key VARCHAR(96) NOT NULL COMMENT '事项稳定键',
operator_id VARCHAR(64) NOT NULL COMMENT '真实操作人员标识',
operator_name VARCHAR(128) NULL COMMENT '操作人显示名称',
action VARCHAR(48) NOT NULL COMMENT '工作命令或观察动作',
summary VARCHAR(2000) NOT NULL COMMENT '处理或责任变更依据',
command_key VARCHAR(64) NULL COMMENT '请求幂等键,观察记录为空',
request_hash VARCHAR(64) NULL COMMENT '包含操作者的规范请求摘要',
response_json LONGTEXT NULL COMMENT '原命令响应快照,重放不随当前状态改变',
occurred_at DATETIME(3) NOT NULL COMMENT '历史发生UTC时间',
PRIMARY KEY (id),
UNIQUE KEY uk_appointment_work_command (work_item_key,command_key),
KEY idx_appointment_work_history (work_item_key,occurred_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='预约工作事项历史与幂等命令';
@@ -0,0 +1,136 @@
openapi: 3.0.3
info:
title: 预约货物分批与合并
version: 1.0.0
description: 原子重新分配已有未确认批次。保留原来源、客户、柜及历史;不创建车次、库存或外部确认。
security:
- bearerAuth: []
paths:
/api/platform/v1/last-leg/appointment-planning/batches/{batchKey}:
get:
operationId: getFbaAppointmentBatchContext
summary: 按不可变批次键读取分批资料和操作条件
description: >-
仅平台,需预约列表及尾程订单列表权限。batchKey为FBA_APPOINTMENT加内部不可变主键,仅供关联,不作为展示编号。
返回appointment原快照、sources当前逐来源可用于重新分配的本批数量、allowedActions和blockReasons。
原批次箱数未知且已独立核实总量时,本批数量由核实总量减其他活动批次分配量计算;不修改旧快照。
已替代、已确认或关联排车时不开放分批合并。原来源或核实事实读取失败明确报错,不以空列表冒充无货。
allowedActions表示业务资格,前端与FBA预约写权限取交集;实际写入仍在事务内重验。
parameters:
- {name: batchKey, in: path, required: true, schema: {type: string, pattern: '^FBA_APPOINTMENT:[1-9][0-9]*$'}}
responses:
'200':
description: code=200时data为批次上下文
content:
application/json:
schema:
type: object
properties:
code: {type: string}
data:
type: object
properties:
appointment: {$ref: './fba-appointment-calendar-v1.yaml#/components/schemas/Appointment'}
sources:
type: array
items:
type: object
properties:
customerId: {type: string}
sourceKey: {type: string}
destinationKey: {type: string}
packageCount: {type: integer, nullable: true, description: 本批分配量或可从独立核实资料确认的本批量}
originalPackages: {type: integer, nullable: true, description: 原订单/登记箱数,独立核实不回写}
sourceVersion: {type: string, nullable: true}
cargoVerificationVersion: {type: integer, nullable: true}
shipmentReferences: {type: array, items: {type: string}}
allowedActions: {type: array, items: {type: string, enum: [VERIFY_CARGO, SPLIT, MERGE]}}
blockReasons: {type: array, items: {type: string}}
'400': {description: 批次键格式无效}
'403': {description: 非平台或缺少读取权限}
'404': {description: 批次或原来源不存在}
'409': {description: 原来源变化,需重新核实资料}
'503': {description: 原来源权威目录不可用}
/api/platform/v1/last-leg/appointment-planning/appointments/repartition:
post:
operationId: repartitionFbaAppointments
summary: 一批分多批或多批合一批
description: >-
仅平台,需platform:appointment:list、platform:overseas-warehouse:last-mile-order:list及platform:overseas-warehouse:inbound-order:fba-appointment。
originals为一条且batches多条表示分批;originals多条且batches一条表示合并,其他组合拒绝。
原批次必须同起运仓、同目的仓,尚未正式确认、未被替代且没有有效关联排车。
先按业务号有序锁原预约,再锁原BOOKING/订单;版本、来源资格、客户归属及数量均在锁内重新核对。
按每个稳定来源分别比较调整前后总量,不能只比较合计箱数或跨客户挪量;逐来源预期版本及核实版本必须与最新资料一致。
原批次箱数未知时可采用刚保存的独立核实总量,无需先登记预约确认;仍未知则拒绝。
全部旧明细释放、新批次和来源明细建立、替代关系及幂等结果在同一事务内;任一失败全部回滚。
原批次仍可详情读取,replacementAppointmentNos和repartitionReason标识替代关系,不能再次编辑或取消;日历和未定时列表只返回当前批次。
新批次都是PENDING,仅保存显式计划日期,确认号和确认时段为空;旧柜级提柜、接仓、还空不复制。
同键同操作人同请求返回原结果,后续编辑不会改变原重试快照;同键异内容、并发版本或已安排冲突返回409。
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/Repartition'}
responses:
'200':
description: code=200时data为原批次业务号及新批次快照,按请求batches顺序返回
content:
application/json:
schema:
type: object
properties:
code: {type: string}
data:
type: object
properties:
replacedBatchKeys: {type: array, items: {type: string}, description: 被替代的稳定批次键,用于协调原工作需求}
replacedAppointmentNos: {type: array, items: {type: string}}
appointments: {type: array, items: {$ref: './fba-appointment-calendar-v1.yaml#/components/schemas/Appointment'}}
'400': {description: 分组不合法、客户/来源替换、数量不守恒或跨起讫点}
'403': {description: 非平台或权限不足}
'404': {description: 原批次或货源不存在}
'409': {description: 原版本变化、来源待核实、已有确认或有效排车、幂等内容冲突}
'503': {description: 权威仓库目录或时区暂不可用}
components:
securitySchemes:
bearerAuth: {type: http, scheme: bearer, bearerFormat: JWT}
schemas:
Repartition:
type: object
required: [originals, batches, reason, idempotencyKey]
properties:
originals:
type: array
minItems: 1
maxItems: 20
items:
type: object
required: [appointmentNo, version]
properties:
appointmentNo: {type: string, minLength: 1, maxLength: 64}
version: {type: integer, minimum: 0}
batches:
type: array
minItems: 1
maxItems: 20
items:
type: object
required: [allocations]
properties:
plannedDate: {type: string, format: date, nullable: true}
remark: {type: string, maxLength: 1000, nullable: true}
allocations:
type: array
minItems: 1
maxItems: 100
items:
type: object
required: [customerId, sourceKey, packageCount]
properties:
customerId: {type: string, minLength: 1, maxLength: 128}
sourceKey: {type: string, minLength: 1, maxLength: 160}
packageCount: {type: integer, minimum: 1, description: 本批来自该原来源的箱数;不使用零数量占位行}
expectedSourceVersion: {type: string, maxLength: 160, nullable: true, description: 批次上下文sources的sourceVersion;空值也须一致}
expectedVerificationVersion: {type: integer, minimum: 1, nullable: true, description: 批次上下文sources的cargoVerificationVersion,无独立核实时为空}
reason: {type: string, minLength: 1, maxLength: 1000}
idempotencyKey: {type: string, minLength: 1, maxLength: 64}
@@ -0,0 +1,114 @@
openapi: 3.0.3
info:
title: 预约货物核实资料
version: 1.0.0
description: >-
按原ORDER或BOOKING货源保存独立核实资料,不修改订单、登记、库存或预约确认状态。
未取得预约确认也可保存箱数和各票货件号。核实记录逐版本追加,取消预约不删除资料。
security:
- bearerAuth: []
paths:
/api/platform/v1/last-leg/appointment-planning/sources/{sourceKey}/cargo-verification:
parameters:
- {name: sourceKey, in: path, required: true, schema: {type: string, maxLength: 160}, description: 原稳定货源键;外接货来货前后均使用BOOKING键}
- {name: customerId, in: query, required: true, schema: {type: string, maxLength: 128}, description: 服务端核对的原客户归属}
get:
operationId: getAppointmentCargoVerification
summary: 读取本票独立核实资料和分配总量
description: >-
仅平台,需platform:appointment:list与platform:overseas-warehouse:last-mile-order:list。
source为权威原来源,verification为空表示尚无独立核实记录。
原版本、目的地或原箱数变化后sourceChanged为true,可分配量返回null,重新核实前不得采用旧资料。
allocatedPackages合计当前活动预约明细;未知分配单独计数,不当作零。
availablePackages为当前有效总量减已分配量,未知、超量或待复核时为空,不虚构可用量。
allowedActions表示业务资格;前端仍须与当前用户写权限取交集。
parameters:
- {name: destinationKey, in: query, schema: {type: string, maxLength: 160}, description: 可传选择时的目的地;与原来源不符则拒绝}
responses:
'200':
description: 业务响应,data为核实上下文
content:
application/json:
schema:
type: object
properties:
code: {type: string}
data: {$ref: '#/components/schemas/CargoContext'}
'400': {description: 来源格式或目的地不符}
'403': {description: 非平台身份或权限不足}
'404': {description: 原来源不存在或客户不匹配}
'503': {description: 权威仓库目录不可用}
post:
operationId: saveAppointmentCargoVerification
summary: 独立保存箱数和本票货件或追踪号
description: >-
仅平台,需两个读取权限及platform:overseas-warehouse:inbound-order:fba-appointment。
操作人取登录身份。原货源锁与预约写命令共用,锁后重读来源和版本;expectedVersion首次为0。
原来源已知箱数时,核实量不得超过原来源;任何情况下不得低于活动预约已分配量。
原来源箱数未知时允许独立核实总量,原来源仍为空。
可以暂缺箱数或货件,保存不会自动确认预约;正式确认仍需完整材料。
同来源客户内的同幂等键、同操作人、同请求返回原核实版本,即使此后又有新版本。
同键异内容、并发版本冲突或原来源变化返回409;记录与业务写入处于同一事务。
后续预约写入采用核实版本及货件快照;单独再次核实不会改写已保存预约快照。
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/SaveCargoVerification'}
responses:
'200':
description: 保存或重试原命令的核实资料快照
content:
application/json:
schema:
type: object
properties:
code: {type: string}
data: {$ref: '#/components/schemas/CargoVerification'}
'400': {description: 请求字段无效}
'403': {description: 非平台身份或缺少独立写权限}
'404': {description: 原来源不存在或客户不匹配}
'409': {description: 原来源或核实版本变化、幂等冲突、箱数越界或来源不可安排}
'503': {description: 权威仓库目录不可用}
components:
securitySchemes:
bearerAuth: {type: http, scheme: bearer, bearerFormat: JWT}
schemas:
SaveCargoVerification:
type: object
required: [destinationKey, expectedVersion, shipmentReferences, idempotencyKey]
properties:
destinationKey: {type: string, minLength: 1, maxLength: 160}
expectedSourceVersion: {type: string, maxLength: 160, nullable: true, description: 读取上下文中的原来源版本,空值也须一致}
expectedVersion: {type: integer, minimum: 0}
packageCount: {type: integer, minimum: 1, nullable: true}
shipmentReferences: {type: array, maxItems: 100, items: {type: string, minLength: 1, maxLength: 128}, description: 本票货件号或追踪号,允许暂时空列表;保存时去首尾空格并去重}
remark: {type: string, maxLength: 1000, nullable: true}
idempotencyKey: {type: string, minLength: 1, maxLength: 64}
CargoVerification:
type: object
required: [version, destinationKey, shipmentReferences, verifiedAt]
properties:
version: {type: integer, minimum: 1}
sourceVersion: {type: string, nullable: true}
destinationKey: {type: string}
sourcePackages: {type: integer, nullable: true}
packageCount: {type: integer, nullable: true}
shipmentReferences: {type: array, items: {type: string}}
remark: {type: string, nullable: true}
operatorName: {type: string, nullable: true}
verifiedAt: {type: string, format: date-time, description: UTC时间}
CargoContext:
type: object
properties:
source: {$ref: './appointment-planning-v1.yaml#/components/schemas/PlanningSource'}
verification:
allOf: [{$ref: '#/components/schemas/CargoVerification'}]
nullable: true
allocatedPackages: {type: integer, format: int64}
unknownAllocationCount: {type: integer, format: int64}
effectivePackages: {type: integer, nullable: true, description: 独立核实箱数;没有核实记录时采用原来源箱数}
availablePackages: {type: integer, format: int64, nullable: true}
sourceChanged: {type: boolean}
allowedActions: {type: array, items: {type: string, enum: [VERIFY_CARGO]}}
blockReasons: {type: array, items: {type: string}}
@@ -6,6 +6,37 @@ info:
security:
- bearerAuth: []
paths:
/api/platform/v1/last-leg/appointment-planning/sources/resolve-order:
get:
operationId: resolveOrderAppointmentSource
summary: 从实际订单读取规范原货源及预约覆盖
description: >-
仅平台;同时要求platform:appointment:list与platform:overseas-warehouse:last-mile-order:list。
入仓列表只知道订单时使用此只读入口;服务端保留外接登记BOOKING键,其他来源返回ORDER键,核对客户、订单关联及目的地。
前端后续核实和预约命令必须使用返回的source.sourceKey,不将外接来货改写为ORDER别名。
parameters:
- {name: orderId, in: query, required: true, schema: {type: integer, format: int64, minimum: 1}}
- {name: customerId, in: query, required: true, schema: {type: string, minLength: 1, maxLength: 128}}
- {name: destinationKey, in: query, schema: {type: string}}
responses:
'200':
description: 真实原来源和当前活动预约覆盖
content:
application/json:
schema:
type: object
properties:
code: {type: string}
data:
type: object
properties:
source: {$ref: '#/components/schemas/PlanningSource'}
coverage: {$ref: '#/components/schemas/Coverage'}
'400': {description: 订单、客户或目的地参数无效}
'403': {description: 非平台或缺少任一读取权限}
'404': {description: 当前客户下来源不存在}
'409': {description: 订单与原来源关联变化}
'503': {description: 权威目录不可用}
/api/platform/v1/last-leg/appointment-planning/external-candidates:
get:
operationId: listExternalAppointmentCandidates
@@ -52,7 +83,7 @@ paths:
仅平台;同时需要platform:appointment:list、platform:overseas-warehouse:last-mile-order:list及platform:overseas-warehouse:inbound-order:fba-appointment。
与入仓明细入口共用同一FBA预约聚合;系统生成AP单号,不创建入仓计划、库存或车次。
PENDING允许日期、时段、外部约号及箱数暂缺。SUCCESS必须有权威目的仓时区、真实货件材料、确定箱数及外部约号和确认时段。
实际客户、起运仓、目的仓及原BOOKING由服务端核对;活动来源与已形成订单均唯一占用,取消后释放并保留历史。
实际客户、起运仓、目的仓及原BOOKING由服务端核对;锁原来源后按剩余未分配箱数建立新安排,分批总量不能超过独立核实或原来源总量。取消只释放本批数量并保留历史。
命令与主单、明细同事务;同键同操作人同内容重试返回原快照,不受后来编辑影响。异内容或来源占用冲突拒绝。
requestBody:
required: true
@@ -117,7 +148,7 @@ paths:
description: >-
只读核对,不保存预约安排、不占货、不确认预约。仅平台,同时要求platform:appointment:list与platform:overseas-warehouse:last-mile-order:list。
最多100票,批量查询货源、实际开船节点和美国仓目录,支持ORDER与已确认承运BOOKING混合;同一订单重复别名拒绝。
必须同美国起运仓及同美国FBA目的仓;暂扣、多目的地、已有有效预约或已取消完成货源拒绝;未知箱数保留待核实,不填0。
必须同美国起运仓及同美国FBA目的仓;暂扣、多目的地、已分配完或已取消完成货源拒绝;部分分配后仍可选择剩余量。未知箱数保留待核实,不填0。
未建入仓计划及尚未来货的已确认BOOKING不伪造计划、库存或入仓码;正式确认前必须核实箱数。
未接入权威备妥窗口时返回readinessIncomplete及READY_WINDOW_UNVERIFIED,不拿到港/到仓预测代替。
requestBody:
@@ -156,6 +187,7 @@ paths:
destinationWarehouseCode: {type: string}
destinationTimezone: {type: string, nullable: true, description: 当前目的仓主档IANA时区;主档为空时为null,读取失败返回错误,不使用历史预约快照}
sources: {type: array, items: {$ref: '#/components/schemas/PlanningSource'}}
cargoVerification: {type: array, items: {$ref: './appointment-cargo-verification-v1.yaml#/components/schemas/CargoContext'}, description: 各原来源当前独立核实及剩余分配量,sources本身仍保留原事实}
missingFields: {type: array, items: {type: string}}
group:
type: object
File diff suppressed because it is too large Load Diff
@@ -229,6 +229,10 @@ components:
properties:
id: {type: string, description: 内部标识,不作为展示编号}
appointmentNo: {type: string, description: 系统生成AP业务单号}
batchKey: {type: string, description: FBA_APPOINTMENT加不可变主键,用于工作事项关联,不展示内部键}
replacementBatchKeys: {type: array, items: {type: string}, description: 分批/合并后的稳定批次键;旧批次历史保留}
replacementAppointmentNos: {type: array, items: {type: string}, description: 替代批次业务号;非空时原批次只读}
repartitionReason: {type: string, nullable: true}
confirmationNo: {type: string, nullable: true, description: 对方正式外部确认号}
plannedDate: {type: string, format: date, nullable: true}
plannedAt: {type: string, nullable: true}
@@ -255,8 +259,11 @@ components:
id: {type: string}
customerId: {type: string, description: 本票货物客户归属,不在预约主单指定客户}
sourceKey: {type: string}
destinationKey: {type: string, description: 本票目的地FBA加仓码,与原来源归属一同保留}
sourceVersion: {type: string, nullable: true}
orderId: {type: string, nullable: true}
inboundCode: {type: string, nullable: true}
packageCount: {type: integer, nullable: true}
cargoVerificationVersion: {type: integer, nullable: true, description: 本次采用的独立核实版本,后续单独核实不改写此快照}
shipmentReferences: {type: array, items: {type: string}, description: 本次采用的独立核实货件或追踪号快照,无核实资料时为空列表}
fbaWarehouseCode: {type: string}
@@ -29,12 +29,12 @@ security:
paths:
/api/platform/v1/last-leg/fleet/trips/calendar:
get:
summary: 读取美国车次计划日历来源
summary: 读取美国车次用车日历来源
description: >-
仅PLATFORM且平台公共主体(tenantId=0),权限 platform:fleet:trip:list。from/to 是明确UTC时间点,按计划发车时间读取半开区间,最多44天;
仅PLATFORM且平台公共主体(tenantId=0),权限 platform:fleet:trip:list。from/to 是明确UTC时间点,已发车按实际发车时间、尚未发车按计划发车时间读取半开区间,最多44天;
该保护性窗口供界面最多42个当地日历日加时区边界使用,不扩大界面范围。
最多2000条候选,超限明确拒绝并要求缩小日期范围,不分页扫描、不静默截断。
一车一条,保留取消及完成状态;记录只表示用车计划,不表示收货预约已确认。
一车一条,保留取消及完成状态;保留原计划与实际时间,已执行事实不随计划改期移动,不表示收货预约已确认。
已知非美国仓排除;未知仓库/国家/地理IANA时区进入unresolvedRecords,不落入美国当地日槽。
一次车次查询加一次仓库批量资料请求,包含停用仓历史资料,资料服务失败返回错误而非空日历。
parameters:
@@ -512,7 +512,7 @@ paths:
- { 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: appointmentStatus, in: query, schema: { type: string, enum: [UNAPPOINTED, PENDING, SUCCESS, FAILED, CANCELLED, MULTIPLE] } }
- { 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 } }
@@ -1372,7 +1372,7 @@ paths:
- { 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: appointmentStatus, in: query, schema: { type: string, enum: [UNAPPOINTED, PENDING, SUCCESS, FAILED, CANCELLED, MULTIPLE] } }
- { 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 } }
@@ -2698,6 +2698,7 @@ components:
draftContainerId: { type: integer, format: int64 }
planPalletIds: { type: array, maxItems: 500, items: { type: integer, format: int64 } }
returnReceiptIds: { type: array, maxItems: 500, items: { type: integer, format: int64 } }
batchAllocations: { type: array, maxItems: 1000, items: { $ref: './appointment-work-v1.yaml#/components/schemas/DispatchBatchAllocation' } }
SmartDispatchDraftGroupResult:
type: object
required: [draftContainerId, dispatch]
@@ -2708,6 +2709,11 @@ components:
type: object
description: planPalletIds与returnReceiptIds是两类正式来源,合计至少一项且最多500项。退回来源仅接受实际入账生成的实收记录,不得用退回实收ID冒充计划托盘ID;同一实物托盘不可重复选择。
properties:
batchAllocations:
type: array
maxItems: 1000
description: 已有预约批次的FBA实物必须逐票绑定,整托总量或可变预约号不能替代;发车再次校验实物与原预约。
items: { $ref: './appointment-work-v1.yaml#/components/schemas/DispatchBatchAllocation' }
planPalletIds: { type: array, maxItems: 500, uniqueItems: true, items: { type: string } }
returnReceiptIds: { type: array, maxItems: 500, uniqueItems: true, items: { type: string }, description: 原订单实际退回入账来源ID }
fbaAppointmentNo: { type: string, nullable: true, maxLength: 64 }