This commit is contained in:
2026-09-14 20:03:22 +08:00
parent d53de922db
commit ebc299d58a
28 changed files with 756 additions and 95 deletions
@@ -270,10 +270,10 @@ export async function run(context) {
`attachmentId=${id(replacement?.id) || 'missing'}, fileId=${id(replacement?.fileId) || 'missing'}`, OPTIONS)
const editedResponse = await request(context, 'PUT', path,
truckAppointmentPayload(context, identity.suffix, identity, Number(appointment.version), { currency: 'USD', payableAmount: 12.34 }))
appointment = context.apiSuccess(MODULE, '编辑订舱级拖车为USD应付费用', editedResponse, '', OPTIONS)
truckAppointmentPayload(context, identity.suffix, identity, Number(appointment.version), { currency: 'RMB', payableAmount: 12.34 }))
appointment = context.apiSuccess(MODULE, '编辑订舱级拖车为RMB应付费用', editedResponse, '', OPTIONS)
context.assert(MODULE, '编辑响应费用正确且无柜次协议', editedResponse,
appointment?.currency === 'USD' && Number(appointment?.payableAmount) === 12.34 && !hasForbiddenTruckFields(appointment), '', OPTIONS)
appointment?.currency === 'RMB' && Number(appointment?.payableAmount) === 12.34 && !hasForbiddenTruckFields(appointment), '', OPTIONS)
const submitKey = `${context.marker}-truck-submit`.slice(0, 128)
const submitBody = { expectedVersion: Number(appointment.version), reason: '幂等提交' }
@@ -289,27 +289,24 @@ export async function run(context) {
codeOf(conflictResponse) === 'A0409', `code=${codeOf(conflictResponse)}`, OPTIONS)
for (const [name, reason] of [['DISPATCH', '派车'], ['PICKUP', '提柜'], ['ARRIVE', '到仓'],
['LOAD', '装货'], ['DEPART', '离仓'], ['COMPLETE', '完成']]) {
['LOAD', '装货']]) {
appointment = await action(context, path, appointment, name, reason)
context.assert(MODULE, `${name}响应无柜次协议`, null, Boolean(appointment) && !hasForbiddenTruckFields(appointment),
`status=${appointment?.status || 'missing'}`, OPTIONS)
}
const finalDetailResponse = await request(context, 'GET', path)
const finalDetail = context.apiSuccess(MODULE, '回查COMPLETED订舱级拖车详情', finalDetailResponse, '', OPTIONS)
context.assert(MODULE, '完整生命周期完成且详情无柜次协议', finalDetailResponse,
finalDetail?.status === 'COMPLETED' && truckAppointmentFieldGaps(finalDetail).length === 0
const finalDetail = context.apiSuccess(MODULE, '回查待离仓订舱级拖车详情', finalDetailResponse, '', OPTIONS)
context.assert(MODULE, '未确认国内离仓时保持装柜中且详情无柜次协议', finalDetailResponse,
finalDetail?.status === 'LOADING' && truckAppointmentFieldGaps(finalDetail).length === 0
&& !hasForbiddenTruckFields(finalDetail)
&& id(finalDetail?.oceanBookingId) === identity.oceanBookingId,
`appointmentNo=${finalDetail?.appointmentNo || 'missing'}, status=${finalDetail?.status || 'missing'}, fieldGaps=${truckAppointmentFieldGaps(finalDetail).join('|') || 'none'}`, OPTIONS)
const afterCompleteCandidate = await candidate(context, identity)
context.assert(MODULE, 'COMPLETED后订舱恢复候选', afterCompleteCandidate.response, Boolean(afterCompleteCandidate.item),
`oceanBookingNo=${identity.oceanBookingNo}`, OPTIONS)
const rebuiltResponse = await request(context, 'POST', TRUCKS, base)
let rebuilt = context.apiSuccess(MODULE, 'COMPLETED后同订舱可新建下一张拖车单', rebuiltResponse, '', OPTIONS)
context.assert(MODULE, '重建拖车单保持订舱级响应', rebuiltResponse,
rebuilt?.status === 'DRAFT' && !hasForbiddenTruckFields(rebuilt)
&& id(rebuilt?.oceanBookingId) === identity.oceanBookingId,
`appointmentNo=${rebuilt?.appointmentNo || 'missing'}`, OPTIONS)
for (const obsoleteAction of ['depart', 'complete']) {
const rejected = await request(context, 'POST', `${path}/${obsoleteAction}`,
{ expectedVersion: Number(finalDetail.version) }, { 'Idempotency-Key': `${context.marker}-${obsoleteAction}`.slice(0, 128) })
context.assert(MODULE, '禁止手工离仓或完成拖车', rejected, codeOf(rejected) === 'A0409', '', OPTIONS)
}
let rebuilt = finalDetail
const cancelled = await action(context, `${TRUCKS}/${id(rebuilt?.id)}`, rebuilt, 'CANCEL', '取消测试单')
const afterCancelCandidate = await candidate(context, identity)
context.assert(MODULE, 'CANCELLED后订舱恢复候选', afterCancelCandidate.response,