feat(appointments): track forecast impacts and handling history
This commit is contained in:
@@ -3523,3 +3523,43 @@ CREATE TABLE IF NOT EXISTS ll_procurement_closure_item (
|
||||
PRIMARY KEY(id), KEY idx_procurement_closure_source(closure_id,source_kind,source_id),
|
||||
CONSTRAINT chk_procurement_closure_quantity CHECK(quantity>0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='异常关闭逐来源剩余货物最终去向,不产生新发运';
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_appointment_impact (
|
||||
container_booking_id VARCHAR(64) NOT NULL COMMENT '稳定柜次关联键,不作业务编号展示',
|
||||
impact_no VARCHAR(40) NOT NULL COMMENT '船期核对事项业务号',
|
||||
baseline_json LONGTEXT NOT NULL COMMENT '已核对基准或首次变化前观察,原来源时间口径',
|
||||
latest_json LONGTEXT NOT NULL COMMENT '最新已读取观察,未知可为JSON null',
|
||||
forecast_token CHAR(64) NOT NULL COMMENT '最新观察摘要,处理时防止旧预测结案',
|
||||
status VARCHAR(20) NOT NULL COMMENT '事项状态:MONITORING监测/OPEN待处理/RESOLVED已完成',
|
||||
reason VARCHAR(64) NULL COMMENT '预测变化或资料待核实原因',
|
||||
owner_id VARCHAR(128) NULL COMMENT '认领平台人员ID',
|
||||
owner_name VARCHAR(200) NULL COMMENT '负责人姓名快照',
|
||||
version INT NOT NULL COMMENT '观察及人工处理共同版本',
|
||||
updated_at DATETIME(3) NOT NULL COMMENT 'UTC更新时间',
|
||||
PRIMARY KEY (container_booking_id),
|
||||
UNIQUE KEY uk_appointment_impact_no (impact_no),
|
||||
KEY idx_appointment_impact_work (status,updated_at),
|
||||
CONSTRAINT chk_appointment_impact_status CHECK (status IN ('MONITORING','OPEN','RESOLVED'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='一柜一个稳定船期变化核对事项,不改写预约或运输';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_appointment_impact_history (
|
||||
id BIGINT NOT NULL COMMENT '历史记录标识',
|
||||
container_booking_id VARCHAR(64) NOT NULL COMMENT '关联柜次标识',
|
||||
version INT NOT NULL COMMENT '记录版本',
|
||||
action VARCHAR(20) NOT NULL COMMENT '操作类型:OBSERVED观察/CLAIM认领/RECORD记录/RESOLVE完成',
|
||||
operator_id VARCHAR(128) NOT NULL COMMENT '操作人标识',
|
||||
operator_name VARCHAR(200) NULL COMMENT '操作人姓名',
|
||||
result VARCHAR(1000) NULL COMMENT '人工处理结果;观察记录为空',
|
||||
next_action VARCHAR(500) NULL COMMENT '下一步处理事项',
|
||||
followup_date DATE NULL COMMENT '业务跟进日期',
|
||||
command_key VARCHAR(64) NULL COMMENT '人工命令幂等键;观察记录为空',
|
||||
request_hash CHAR(64) NULL COMMENT '请求内容摘要',
|
||||
response_json LONGTEXT NOT NULL COMMENT '该版本完整响应快照,支持精确重放',
|
||||
created_at DATETIME(3) NOT NULL COMMENT 'UTC记录时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_appointment_impact_version (container_booking_id,version),
|
||||
UNIQUE KEY uk_appointment_impact_command (container_booking_id,operator_id,command_key),
|
||||
CONSTRAINT fk_appointment_impact_history FOREIGN KEY (container_booking_id) REFERENCES ll_appointment_impact(container_booking_id),
|
||||
CONSTRAINT chk_appointment_impact_action CHECK (action IN ('OBSERVED','CLAIM','RECORD','RESOLVE'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='船期观察及人工处理追加历史';
|
||||
|
||||
@@ -0,0 +1,643 @@
|
||||
{
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "船期变化影响核对",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/api/platform/v1/last-leg/appointment-planning/impacts": {
|
||||
"get": {
|
||||
"operationId": "listAppointmentImpacts",
|
||||
"description": "仅平台主体,同时要求platform:appointment:list和platform:overseas-warehouse:last-mile-order:list。按现有美国活动柜次分页,impact为空表示尚未核对。GET不读取远程船期、不创建记录。",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "page",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"default": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 100,
|
||||
"default": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "keyword",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ApiResponse,业务成功code为字符串200",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/ImpactPage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "非平台主体或缺少权限"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/platform/v1/last-leg/appointment-planning/impacts/refresh": {
|
||||
"post": {
|
||||
"operationId": "refreshAppointmentImpacts",
|
||||
"description": "仅平台主体,同时要求platform:appointment:list和platform:overseas-warehouse:last-mile-order:list。写入另需platform:appointment:followup。显式批量核对当前页,一次Firstleg来源查询;范围不完整或来源失败保留原状态并报错。稳定柜次事项和追加观察历史,不改外部确认、订单或车次。来源时间时区未核实,不转换为UTC或推算备妥窗口。",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"page": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 100
|
||||
},
|
||||
"keyword": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"page",
|
||||
"size"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ApiResponse,业务成功code为字符串200",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Impacts"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "非平台主体或缺少权限"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/platform/v1/last-leg/appointment-planning/impacts/{id}": {
|
||||
"get": {
|
||||
"operationId": "readAppointmentImpact",
|
||||
"description": "仅平台主体,同时要求platform:appointment:list和platform:overseas-warehouse:last-mile-order:list。直接货物和预约按客户归属关联;运输明细另外要求platform:fleet:trip:list,无权时transport为null。sameTripBookings仅提示同车运输承诺复核,不断言直接延期。明细任一范围超过1000拒绝,不静默截断。历史服务端分页,业务确认时间保持原值。",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "内部柜次关联键,不作界面业务编号"
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"default": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 100,
|
||||
"default": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ApiResponse,业务成功code为字符串200",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/ImpactDetail"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "非平台主体或缺少权限"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/platform/v1/last-leg/appointment-planning/impacts/{id}/commands": {
|
||||
"post": {
|
||||
"operationId": "handleAppointmentImpact",
|
||||
"description": "仅平台主体,同时要求platform:appointment:list和platform:overseas-warehouse:last-mile-order:list。写入另需platform:appointment:followup。CLAIM认领当前人;RECORD和RESOLVE必须填写实际结果。其他人已认领、事项版本或来源观察变化时拒绝;同操作者同键同体精确重放原响应。处理完成仅确认核对事项,绝不改约/撤销承运/改库存。处理后新预测变化重新打开同一事项。",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "内部柜次关联键,不作界面业务编号"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"expectedVersion": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"forecastToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"idempotencyKey": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 64
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"CLAIM",
|
||||
"RECORD",
|
||||
"RESOLVE"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"maxLength": 1000
|
||||
},
|
||||
"nextAction": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"maxLength": 500
|
||||
},
|
||||
"followupDate": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"expectedVersion",
|
||||
"forecastToken",
|
||||
"idempotencyKey",
|
||||
"action"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ApiResponse,业务成功code为字符串200",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Impact"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "非平台主体或缺少权限"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"bearerAuth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT"
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"Fact": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"containerBookingId": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"factId": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"providerCode": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"sourceReference": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"observedAt": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"estimatedAt": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"actualAt": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"nullable": true
|
||||
},
|
||||
"Impact": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"containerBookingId": {
|
||||
"type": "string"
|
||||
},
|
||||
"impactNo": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"MONITORING",
|
||||
"OPEN",
|
||||
"RESOLVED"
|
||||
]
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"ownerId": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"ownerName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"baseline": {
|
||||
"$ref": "#/components/schemas/Fact"
|
||||
},
|
||||
"latest": {
|
||||
"$ref": "#/components/schemas/Fact"
|
||||
},
|
||||
"forecastToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ImpactPage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"records": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"container": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"containerBookingId": {
|
||||
"type": "string"
|
||||
},
|
||||
"containerNo": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"orderCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"customerCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"packages": {
|
||||
"type": "integer",
|
||||
"nullable": true
|
||||
},
|
||||
"unknownPackageOrders": {
|
||||
"type": "integer"
|
||||
},
|
||||
"earliestArrivalAt": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"latestArrivalAt": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"standardNode": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"sourceVersion": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"incompleteScope": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warehouses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"warehouseId": {
|
||||
"type": "string"
|
||||
},
|
||||
"warehouseName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"orderCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"customerCount": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"impact": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Impact"
|
||||
}
|
||||
],
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pages": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Impacts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Impact"
|
||||
}
|
||||
},
|
||||
"ImpactDetail": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"impact": {
|
||||
"$ref": "#/components/schemas/Impact"
|
||||
},
|
||||
"cargo": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"customerId": {
|
||||
"type": "string"
|
||||
},
|
||||
"orderId": {
|
||||
"type": "string"
|
||||
},
|
||||
"inboundCode": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"customerName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"packages": {
|
||||
"type": "integer",
|
||||
"nullable": true
|
||||
},
|
||||
"destination": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"appointments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"appointmentNo": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"destination": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"confirmedAt": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"timezone": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"transport": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"trips": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tripNo": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"plannedDepartureAt": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sameTripBookings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tripNo": {
|
||||
"type": "string"
|
||||
},
|
||||
"bookingNo": {
|
||||
"type": "string"
|
||||
},
|
||||
"customerName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"destinationLabel": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"nullable": true
|
||||
},
|
||||
"history": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"records": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "integer"
|
||||
},
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"operatorName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"result": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"nextAction": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"followupDate": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"nullable": true
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pages": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user