2026-08-08 20:39:49 +08:00
openapi : 3.0.3
info :
2026-08-10 09:11:56 +08:00
title : Truck Appointment API
2026-08-31 19:55:58 +08:00
version : 1.3.0
description : Every truck appointment must select one RELEASED ocean booking and one ACTIVE real-numbered container already allocated to that booking. The bill-of-lading number is frozen from the booking, and the booking must own at least one active BOOKING_CONFIRMATION or BILL_OF_LADING file under OCEAN_BOOKING_DOCUMENT. Booking and bill files are not owned by truck appointments. After a PDA loading transaction commits, the server best-effort completes the unique active appointment explicitly linked to that container in an isolated transaction; absence, duplicates or concurrent truck edits never roll back loading completion.
2026-08-08 20:39:49 +08:00
paths :
2026-08-10 09:11:56 +08:00
/api/platform/v1/truck-appointments :
get :
summary : Query truck appointments
responses :
2026-08-17 19:51:54 +08:00
'200' :
description : Paged truck appointments with stable booking/container snapshots and attachment count
content :
application/json :
schema :
type : object
properties :
data :
type : object
properties :
records : {type : array, items : {$ref : '#/components/schemas/DetailStableReferences' }}
2026-08-10 09:11:56 +08:00
post :
2026-08-31 19:55:58 +08:00
summary : Create a truck appointment for a released booking and its allocated real container
2026-09-01 11:30:35 +08:00
description : If the real container already has a non-terminal appointment, the server returns A0409 with the existing appointment number and instructs the operator to continue editing. This duplicate guard runs before booking-document validation; the database unique key provides the same response for concurrent creates.
2026-08-10 09:11:56 +08:00
requestBody :
required : true
content :
application/json :
schema : {$ref : '#/components/schemas/SaveRequest' }
responses :
2026-08-25 12:27:47 +08:00
'200' : {description : 'Created appointment', content : {application/json : {schema : {$ref : '#/components/schemas/DetailEnvelope' }}}}
2026-09-01 11:30:35 +08:00
'409' : {description : 'A0409 - this container already has a non-terminal appointment; message includes its appointment number and asks the operator to continue editing' }
2026-08-10 09:11:56 +08:00
/api/platform/v1/truck-appointments/{id}:
parameters : [ {$ref : '#/components/parameters/AppointmentId' }]
get :
summary : Query a truck appointment
responses :
2026-08-25 12:27:47 +08:00
'200' : {description : 'Appointment detail', content : {application/json : {schema : {$ref : '#/components/schemas/DetailStableReferences' }}}}
2026-08-10 09:11:56 +08:00
put :
summary : Update an editable truck appointment with optimistic locking
requestBody :
required : true
content :
application/json :
schema : {$ref : '#/components/schemas/SaveRequest' }
responses :
'200' : {description : Updated appointment}
/api/platform/v1/truck-appointments/{id}/{action}:
parameters :
- {$ref : '#/components/parameters/AppointmentId' }
- {$ref : '#/components/parameters/Action' }
- {$ref : '#/components/parameters/IdempotencyKey' }
- {$ref : '#/components/parameters/RequestHash' }
post :
summary : Apply an idempotent appointment lifecycle action
description : ARRIVE, LOAD and DEPART persist their actual event timestamps atomically with the status transition.
requestBody :
required : true
content :
application/json :
schema : {$ref : '#/components/schemas/ActionRequest' }
responses :
'200' : {description : Updated or replayed appointment}
/api/platform/v1/truck-appointments/{id}/reschedule:
parameters :
- {$ref : '#/components/parameters/AppointmentId' }
- {$ref : '#/components/parameters/IdempotencyKey' }
- {$ref : '#/components/parameters/RequestHash' }
- name : plannedLoadingAt
in : query
required : true
schema : {type : string, format : date-time}
post :
summary : Idempotently reschedule an appointment
requestBody :
required : true
content :
application/json :
schema : {$ref : '#/components/schemas/ActionRequest' }
responses :
'200' : {description : Rescheduled or replayed appointment}
2026-08-08 20:39:49 +08:00
/api/platform/v1/truck-appointments/{id}/history:
parameters : [ {$ref : '#/components/parameters/AppointmentId' }]
get :
summary : Query immutable appointment status history
responses :
2026-08-25 12:27:47 +08:00
'200' : {description : 'History entries including action, from/to status, operator, reason and time' }
2026-08-08 20:39:49 +08:00
/api/platform/v1/truck-appointments/{id}/attachments:
parameters : [ {$ref : '#/components/parameters/AppointmentId' }]
get :
2026-08-31 19:55:58 +08:00
summary : Query non-booking operational attachment references owned by the appointment
2026-08-14 14:26:56 +08:00
description : 'Requires platform:firstleg:truck-appointment:list.'
2026-08-08 20:39:49 +08:00
responses :
2026-08-25 12:27:47 +08:00
'200' : {description : 'Attachment references', content : {application/json : {schema : {type : array, items : {$ref : '#/components/schemas/Attachment' }}}}}
2026-08-08 20:39:49 +08:00
post :
2026-09-01 09:51:59 +08:00
summary : Reference a platform-owned file already scoped to this appointment
description : 'Requires platform:firstleg:truck-appointment:edit. The file must belong to platform scope + TRUCK_APPOINTMENT_ATTACHMENT + appointmentId.'
2026-08-14 14:26:56 +08:00
requestBody : {required : true, content : {application/json : {schema : {$ref : '#/components/schemas/AttachmentRequest' }}}}
2026-08-08 20:39:49 +08:00
responses :
2026-08-25 12:27:47 +08:00
'200' : {description : 'Created attachment reference', content : {application/json : {schema : {$ref : '#/components/schemas/Attachment' }}}}
2026-08-08 20:39:49 +08:00
/api/platform/v1/truck-appointments/{id}/attachments/upload:
parameters : [ {$ref : '#/components/parameters/AppointmentId' }]
post :
summary : Upload and reference a truck appointment attachment
2026-08-14 14:26:56 +08:00
description : 'Requires platform:firstleg:truck-appointment:edit.'
2026-08-08 20:39:49 +08:00
requestBody :
required : true
content :
multipart/form-data :
schema :
type : object
2026-08-18 15:43:58 +08:00
required : [ attachmentType, file]
2026-08-08 20:39:49 +08:00
properties :
2026-08-31 19:55:58 +08:00
attachmentType : {type : string, enum : [DISPATCH_ORDER, DRIVER_DOCUMENT, VEHICLE_DOCUMENT, OTHER], description : Booking confirmations and bills of lading belong to the ocean-booking aggregate}
2026-08-08 20:39:49 +08:00
file : {type : string, format : binary}
responses :
'200' : {description : Uploaded attachment reference}
/api/platform/v1/truck-appointments/{id}/attachments/{attachmentId}:
parameters :
- {$ref : '#/components/parameters/AppointmentId' }
- {$ref : '#/components/parameters/AttachmentId' }
delete :
summary : Delete an attachment reference owned by the appointment
2026-08-14 14:26:56 +08:00
description : 'Requires platform:firstleg:truck-appointment:edit. Deletes the appointment reference only; the File object is retained.'
2026-08-08 20:39:49 +08:00
responses :
'200' : {description : Reference deleted}
components :
parameters :
AppointmentId : {name : id, in : path, required : true, schema : {type : string, pattern : '^[1-9][0-9]*$' }}
AttachmentId : {name : attachmentId, in : path, required : true, schema : {type : string, pattern : '^[1-9][0-9]*$' }}
2026-08-10 09:11:56 +08:00
Action :
name : action
in : path
required : true
schema :
type : string
enum : [ SUBMIT, DISPATCH, PICKUP, ARRIVE, LOAD, DEPART, COMPLETE, EXCEPTION, CANCEL]
IdempotencyKey : {name : Idempotency-Key, in : header, required : true, schema : {type : string, maxLength : 128 }}
RequestHash : {name : X-Request-Hash, in : header, required : false, schema : {type : string, pattern : '^[0-9a-fA-F]{64}$' }}
schemas :
2026-08-19 09:42:07 +08:00
DetailEnvelope :
type : object
required : [ code, message, data, timestamp]
properties :
code : {type : string, example : '200' }
message : {type : string}
data :
allOf : [ {$ref : '#/components/schemas/DetailStableReferences' }]
nullable : true
requestId : {type : string, nullable : true }
traceId : {type : string, nullable : true }
timestamp : {type : string, format : date-time}
2026-08-14 14:26:56 +08:00
AttachmentRequest :
type : object
2026-08-18 15:43:58 +08:00
required : [ fileId, attachmentType]
2026-08-14 14:26:56 +08:00
properties :
fileId : {type : integer, format : int64, minimum : 1 }
2026-08-31 19:55:58 +08:00
attachmentType : {type : string, enum : [ DISPATCH_ORDER, DRIVER_DOCUMENT, VEHICLE_DOCUMENT, OTHER]}
2026-08-14 14:26:56 +08:00
fileName : {type : string, maxLength : 255, description : Ignored; authoritative metadata comes from File service}
fileHash : {type : string, maxLength : 128, description : Ignored; authoritative metadata comes from File service}
Attachment :
type : object
properties :
id : {type : integer, format : int64}
appointmentId : {type : integer, format : int64}
fileId : {type : integer, format : int64}
2026-08-31 19:55:58 +08:00
attachmentType : {type : string, enum : [ DISPATCH_ORDER, DRIVER_DOCUMENT, VEHICLE_DOCUMENT, OTHER]}
2026-08-14 14:26:56 +08:00
fileName : {type : string}
fileHash : {type : string}
visibility : {type : string, enum : [ PLATFORM]}
uploadedBy : {type : integer, format : int64}
uploadedAt : {type : string, format : date-time}
2026-08-10 09:11:56 +08:00
ActionRequest :
type : object
required : [ expectedVersion]
properties :
expectedVersion : {type : integer, minimum : 0 }
reason : {type : string, maxLength : 500 }
SaveRequest :
type : object
2026-09-01 09:51:59 +08:00
required : [ oceanBookingId, containerBookingId, carrierId, plannedLoadingAt, expectedVersion]
2026-08-10 09:11:56 +08:00
properties :
2026-08-18 09:09:28 +08:00
outboundOrderId : {type : integer, format : int64, minimum : 1, nullable : true }
2026-08-31 19:55:58 +08:00
oceanBookingId : {type : integer, format : int64, minimum : 1, description : Required RELEASED booking; must own an active BOOKING_CONFIRMATION or BILL_OF_LADING file.}
containerBookingId : {type : integer, format : int64, minimum : 1, description : Required ACTIVE container already allocated to oceanBookingId and carrying a valid unique ISO 6346 container number.}
2026-08-18 09:09:28 +08:00
loadingPlanId : {type : integer, format : int64, minimum : 1, nullable : true, description : Optional loading-plan association. It may be supplied only with containerBookingId and must be that container's current plan.}
warehouseId : {type : integer, format : int64, minimum : 1, nullable : true, description : Optional warehouse scope. Linked booking/container warehouse facts must agree; when omitted the linked fact is frozen if available.}
carrierId : {type : integer, format : int64, minimum : 1, description : Required ACTIVE Warehouse supplier ID validated as TRUCKING.}
carrierName : {type : string, maxLength : 128, nullable : true, description : Optional consistency hint only; the persisted snapshot comes from Warehouse supplier master data.}
2026-08-31 19:55:58 +08:00
billOfLadingNo : {type : string, maxLength : 128, nullable : true, description : Optional consistency hint; the persisted snapshot is always frozen from the selected RELEASED booking.}
2026-08-10 09:11:56 +08:00
plannedLoadingAt : {type : string, format : date-time}
2026-09-01 10:38:15 +08:00
payableAmount : {type : number, format : double, minimum : 0, nullable : true, description : Amount payable to the trucking supplier.}
currency : {type : string, enum : [RMB, USD], default : RMB, description : Payable amount currency.}
2026-08-18 09:09:28 +08:00
expectedVersion : {type : integer, minimum : 0, description : Must be 0 on create; current version on edit.}
2026-08-14 14:26:56 +08:00
DetailStableReferences :
type : object
2026-09-01 09:51:59 +08:00
required : [ appointmentNo, carrierId, carrierName, attachmentCount]
2026-08-31 19:55:58 +08:00
description : Stable IDs plus server-resolved saved resource names returned by appointment detail. Ocean booking and container associations are always present.
2026-08-14 14:26:56 +08:00
properties :
2026-08-19 09:14:30 +08:00
appointmentNo : {type : string, pattern : '^TA-[0-9]{6}-[0-9]{4}$' , example : TA-260818-0001, description : 派车单号;按北京时间创建日逐日编号}
2026-08-18 09:09:28 +08:00
oceanBookingId : {type : integer, format : int64, nullable : true }
2026-08-19 09:14:30 +08:00
oceanBookingNo : {type : string, nullable : true, pattern : '^OB-[0-9]{6}-[0-9]{4}$' , example : OB-260818-0001}
2026-08-18 09:09:28 +08:00
containerBookingId : {type : integer, format : int64, nullable : true }
2026-08-19 09:14:30 +08:00
cabinetNo : {type : string, nullable : true, pattern : '^CAB-[0-9]{6}-[0-9]{4}$' , example : CAB-260818-0001}
2026-08-14 14:26:56 +08:00
containerNo : {type : string, nullable : true }
2026-08-18 09:09:28 +08:00
loadingPlanId : {type : integer, format : int64, nullable : true }
warehouseId : {type : integer, format : int64, nullable : true }
warehouseName : {type : string, nullable : true }
shippingCompanyId : {type : integer, format : int64, nullable : true }
shippingCompanyName : {type : string, nullable : true }
bookingAgentId : {type : integer, format : int64, nullable : true }
bookingAgentName : {type : string, nullable : true }
2026-08-14 14:26:56 +08:00
carrierId : {type : integer, format : int64}
carrierName : {type : string}
2026-08-18 15:43:58 +08:00
billOfLadingNo : {type : string, maxLength : 128, nullable : true, description : Frozen bill of lading snapshot used by dispatch readiness.}
2026-09-01 10:38:15 +08:00
payableAmount : {type : number, format : double, minimum : 0, nullable : true }
currency : {type : string, enum : [ RMB, USD]}
2026-08-17 19:51:54 +08:00
attachmentCount : {type : integer, format : int64, minimum : 0, description : Number of attachment references owned by this appointment}