|
|
|
@@ -22,6 +22,32 @@ async function post(context, path, body, label) {
|
|
|
|
|
{ 'Idempotency-Key': operationId(context, label) })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function uploadDocument(context, path, expectedVersion, operationReason, label) {
|
|
|
|
|
const form = new FormData()
|
|
|
|
|
form.append('file', new Blob([`${context.marker}-${label}`], { type: 'text/plain' }), `${label}.txt`)
|
|
|
|
|
form.append('expectedVersion', String(expectedVersion))
|
|
|
|
|
if (operationReason) form.append('operationReason', operationReason)
|
|
|
|
|
try {
|
|
|
|
|
const response = await fetch(`${context.options.gateway}${path}`, {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
Accept: 'application/json', Authorization: `Bearer ${context.token}`,
|
|
|
|
|
'Idempotency-Key': operationId(context, `${label}-upload`),
|
|
|
|
|
},
|
|
|
|
|
body: form,
|
|
|
|
|
signal: AbortSignal.timeout(60_000),
|
|
|
|
|
})
|
|
|
|
|
const raw = await response.text()
|
|
|
|
|
let body = null
|
|
|
|
|
try { body = raw ? JSON.parse(raw) : null } catch { /* bounded raw evidence */ }
|
|
|
|
|
return { method: 'POST', path, http: response.status, body, raw: body ? null : raw.slice(0, 500),
|
|
|
|
|
requestId: body?.requestId || response.headers.get('x-request-id'),
|
|
|
|
|
traceId: body?.traceId || response.headers.get('x-trace-id') }
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { method: 'POST', path, http: 0, body: null, raw: String(error), requestId: null, traceId: null }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function prepareInbound(context, label) {
|
|
|
|
|
const originalMarker = context.marker
|
|
|
|
|
const fixtureMarker = `${originalMarker}-MAN-${label}`
|
|
|
|
@@ -224,10 +250,71 @@ function fixture(value, status, detailPath, extra = {}) {
|
|
|
|
|
return { id: id(value), status, detailPath, ...extra }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function completeSimpleDocuments(context, chain, matrix) {
|
|
|
|
|
const reason = `${context.marker} 人工页面动作验收`
|
|
|
|
|
const clearancePath = `${CONTAINERS}/${chain.containerId}/clearance`
|
|
|
|
|
const clearanceUpload = await uploadDocument(context, `${clearancePath}/document/upload`, 0,
|
|
|
|
|
reason, 'container-clearance')
|
|
|
|
|
const clearanceDocument = context.apiSuccess(MODULE, '货柜公开接口上传目的港清关资料',
|
|
|
|
|
clearanceUpload, '', OPTIONS)
|
|
|
|
|
context.assert(MODULE, '货柜清关上传返回真实文件事实', clearanceUpload,
|
|
|
|
|
Boolean(clearanceDocument?.id) && Boolean(clearanceDocument?.fileId)
|
|
|
|
|
&& clearanceDocument?.documentType === 'DESTINATION_CLEARANCE'
|
|
|
|
|
&& /^[0-9a-f]{64}$/i.test(String(clearanceDocument?.fileHash || ''))
|
|
|
|
|
&& !clearanceDocument?.completedAt,
|
|
|
|
|
`documentId=${id(clearanceDocument?.id) || 'missing'}, version=${clearanceDocument?.version ?? 'missing'}`, OPTIONS)
|
|
|
|
|
if (!clearanceDocument?.id || !clearanceDocument?.fileId || !Number.isInteger(Number(clearanceDocument?.version))) return
|
|
|
|
|
const clearanceCompleteResponse = await post(context, `${clearancePath}/complete`, {
|
|
|
|
|
expectedVersion: Number(clearanceDocument?.version), operationReason: reason,
|
|
|
|
|
}, 'container-clearance-complete')
|
|
|
|
|
const clearanceCompleted = context.apiSuccess(MODULE, '货柜点击完成目的港清关',
|
|
|
|
|
clearanceCompleteResponse, '', OPTIONS)
|
|
|
|
|
context.assert(MODULE, '货柜清关完成事实可回读', clearanceCompleteResponse,
|
|
|
|
|
id(clearanceCompleted?.id) === id(clearanceDocument?.id) && Boolean(clearanceCompleted?.completedAt)
|
|
|
|
|
&& Number(clearanceCompleted?.version) === Number(clearanceDocument?.version) + 1,
|
|
|
|
|
`documentId=${id(clearanceCompleted?.id) || 'missing'}, completedAt=${clearanceCompleted?.completedAt || 'missing'}`, OPTIONS)
|
|
|
|
|
|
|
|
|
|
const customsPath = `${LOADING}/loading-lists/${chain.plan.id}/customs`
|
|
|
|
|
const warehouse = `warehouseId=${encodeURIComponent(chain.source.warehouseId)}`
|
|
|
|
|
const customsUpload = await uploadDocument(context, `${customsPath}/document/upload?${warehouse}`, 0,
|
|
|
|
|
reason, 'loading-customs')
|
|
|
|
|
const customsDocument = context.apiSuccess(MODULE, '装柜清单公开接口上传出口报关文档',
|
|
|
|
|
customsUpload, '', OPTIONS)
|
|
|
|
|
context.assert(MODULE, '装柜清单报关上传返回真实文件事实', customsUpload,
|
|
|
|
|
Boolean(customsDocument?.id) && Boolean(customsDocument?.fileId)
|
|
|
|
|
&& customsDocument?.documentType === 'CUSTOMS_DECLARATION'
|
|
|
|
|
&& /^[0-9a-f]{64}$/i.test(String(customsDocument?.fileHash || ''))
|
|
|
|
|
&& !customsDocument?.completedAt,
|
|
|
|
|
`documentId=${id(customsDocument?.id) || 'missing'}, version=${customsDocument?.version ?? 'missing'}`, OPTIONS)
|
|
|
|
|
if (!customsDocument?.id || !customsDocument?.fileId || !Number.isInteger(Number(customsDocument?.version))) return
|
|
|
|
|
const customsCompleteResponse = await post(context, `${customsPath}/complete?${warehouse}`, {
|
|
|
|
|
expectedVersion: Number(customsDocument?.version), operationReason: reason,
|
|
|
|
|
}, 'loading-customs-complete')
|
|
|
|
|
const customsCompleted = context.apiSuccess(MODULE, '装柜清单点击完成出口报关',
|
|
|
|
|
customsCompleteResponse, '', OPTIONS)
|
|
|
|
|
context.assert(MODULE, '装柜清单报关完成事实可回读', customsCompleteResponse,
|
|
|
|
|
id(customsCompleted?.id) === id(customsDocument?.id) && Boolean(customsCompleted?.completedAt)
|
|
|
|
|
&& Number(customsCompleted?.version) === Number(customsDocument?.version) + 1,
|
|
|
|
|
`documentId=${id(customsCompleted?.id) || 'missing'}, completedAt=${customsCompleted?.completedAt || 'missing'}`, OPTIONS)
|
|
|
|
|
|
|
|
|
|
matrix.pages.containerLoading.actions = { clearance: fixture(chain.containerId, 'COMPLETED',
|
|
|
|
|
`/container-loading/${chain.containerId}/smart-loading`, {
|
|
|
|
|
documentId: id(clearanceCompleted?.id), documentVersion: Number(clearanceCompleted?.version),
|
|
|
|
|
completedAt: clearanceCompleted?.completedAt || null,
|
|
|
|
|
}) }
|
|
|
|
|
matrix.pages.loadingLists.actions = { customsDeclaration: fixture(chain.plan.id, 'COMPLETED',
|
|
|
|
|
`/loading-lists?planId=${chain.plan.id}&warehouseId=${chain.source.warehouseId}`, {
|
|
|
|
|
warehouseId: chain.source.warehouseId, documentId: id(customsCompleted?.id),
|
|
|
|
|
documentVersion: Number(customsCompleted?.version), completedAt: customsCompleted?.completedAt || null,
|
|
|
|
|
}) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function run(context, matrix = context.createdResources.manualStateMatrix) {
|
|
|
|
|
matrix.pages.containerLoading = { requiredStatuses: CONTAINER_STATUSES, fixtures: {} }
|
|
|
|
|
matrix.pages.containerLoading = { requiredStatuses: CONTAINER_STATUSES,
|
|
|
|
|
requiredActions: ['clearance'], fixtures: {}, actions: {} }
|
|
|
|
|
matrix.pages.preloadPlans = { requiredStatuses: PRELOAD_STATUSES, fixtures: {} }
|
|
|
|
|
matrix.pages.loadingLists = { requiredStatuses: ['COMPLETED'], fixtures: {} }
|
|
|
|
|
matrix.pages.loadingLists = { requiredStatuses: ['COMPLETED'],
|
|
|
|
|
requiredActions: ['customsDeclaration'], fixtures: {}, actions: {} }
|
|
|
|
|
matrix.pages.pdaTasks = { requiredStatuses: PDA_STATUSES, fixtures: {} }
|
|
|
|
|
|
|
|
|
|
const warehouseId = '193000000000200001'
|
|
|
|
@@ -283,4 +370,6 @@ export async function run(context, matrix = context.createdResources.manualState
|
|
|
|
|
context.assert(MODULE, 'COMPLETED 装柜清单详情身份正确', listDetailResponse,
|
|
|
|
|
id(listDetail?.summary?.planId) === listFixture.id && listDetail?.summary?.status === 'COMPLETED',
|
|
|
|
|
`planId=${listFixture.id}, actual=${listDetail?.summary?.status || 'missing'}`, OPTIONS)
|
|
|
|
|
|
|
|
|
|
await completeSimpleDocuments(context, completed, matrix)
|
|
|
|
|
}
|
|
|
|
|