test(acceptance): align retained state fixtures
This commit is contained in:
@@ -37,7 +37,7 @@ test('retains all clickable container, loading-list and PDA workflow states thro
|
||||
assert.doesNotMatch(source, /\/preload\/confirming|\/preload\/confirm\?tenantId=/)
|
||||
assert.match(source, /linked\?\.cabinetNo !== simulation\.cabinetNo/)
|
||||
assert.match(source, /iso6346ContainerNumber/)
|
||||
assert.match(source, /shippingCompanyId: id\(agent\.id\), shippingCompanyName: agent\.name/)
|
||||
assert.match(source, /shippingCompanyId: id\(carrier\.id\), shippingCompanyName: carrier\.name/)
|
||||
assert.match(source, /bookingAgentId: id\(agent\.id\), bookingAgentName: agent\.name/)
|
||||
assert.match(source, /billOfLadingNo: `BL-\$\{value\}`/)
|
||||
const batch = source.slice(source.indexOf('async function pickAll'), source.indexOf('async function complete'))
|
||||
@@ -57,7 +57,7 @@ test('fails closed when invoked outside the manual matrix wrapper', () => {
|
||||
assert.match(source, /missing=manualStateMatrix\.pages/)
|
||||
})
|
||||
|
||||
test('covers simplified clearance and customs actions through public multipart upload and complete APIs', () => {
|
||||
test('covers clearance through its public API and keeps customs on the dedicated customs-v1 flow', () => {
|
||||
assert.match(source, /new FormData\(\)/)
|
||||
assert.match(source, /form\.append\('file'/)
|
||||
assert.match(source, /form\.append\('expectedVersion'/)
|
||||
@@ -65,10 +65,9 @@ test('covers simplified clearance and customs actions through public multipart u
|
||||
assert.match(source, /'Idempotency-Key'/)
|
||||
assert.match(source, /clearancePath\}\/document\/upload/)
|
||||
assert.match(source, /clearancePath\}\/complete/)
|
||||
assert.match(source, /customsPath\}\/document\/upload\?\$\{warehouse\}/)
|
||||
assert.match(source, /customsPath\}\/complete\?\$\{warehouse\}/)
|
||||
assert.match(source, /matrix\.pages\.containerLoading\.actions/)
|
||||
assert.match(source, /matrix\.pages\.loadingLists\.actions/)
|
||||
assert.doesNotMatch(source, /CUSTOMS_DECLARATION|loading-customs|customsPath/)
|
||||
assert.match(source, /tasks\/\$\{taskId\}\/evidence/)
|
||||
assert.doesNotMatch(source, /internal\/file|business-files/)
|
||||
assert.doesNotMatch(source, /\{\s*fileId\s*:/)
|
||||
})
|
||||
|
||||
@@ -49,31 +49,31 @@ async function uploadDocument(context, path, expectedVersion, operationReason, l
|
||||
}
|
||||
|
||||
async function ensureCompletionEvidence(context, chain, label) {
|
||||
const tenantId = chain.source.tenantId
|
||||
const inboundId = chain.source.inboundId
|
||||
const taskId = id(chain.task?.id)
|
||||
const warehouseId = id(chain.source?.warehouseId)
|
||||
const png = Uint8Array.from([137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,1,0,0,0,1,8,6,0,0,0,31,21,196,137,0,0,0,13,73,68,65,84,8,215,99,248,207,192,240,31,0,5,0,1,255,137,153,61,29,0,0,0,0,73,69,78,68,174,66,96,130])
|
||||
for (const evidenceType of ['PHOTO_STEP_1', 'PHOTO_STEP_2', 'PHOTO_STEP_3', 'PHOTO_STEP_4', 'SEAL']) {
|
||||
const uploadPath = `/api/platform/v1/files/loading-evidence/${tenantId}/${inboundId}?evidenceType=${encodeURIComponent(evidenceType)}`
|
||||
const query = new URLSearchParams({ warehouseId, expectedVersion: '0', evidenceType,
|
||||
remark: context.marker })
|
||||
if (evidenceType === 'SEAL') query.set('sealNo', `SEAL-${suffix(context, label)}`.slice(0, 64))
|
||||
const uploadPath = `${PDA}/tasks/${taskId}/evidence?${query}`
|
||||
const form = new FormData()
|
||||
form.append('file', new Blob([png], { type: 'image/png' }), `${label}-${evidenceType}.png`)
|
||||
const rawUpload = await fetch(`${context.options.gateway}${uploadPath}`, {
|
||||
method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}` },
|
||||
method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}`,
|
||||
'Idempotency-Key': operationId(context, `${label}-evidence-${evidenceType}`) },
|
||||
body: form, signal: AbortSignal.timeout(60_000),
|
||||
})
|
||||
const uploadBody = await rawUpload.json()
|
||||
const upload = { method: 'POST', path: uploadPath, http: rawUpload.status, body: uploadBody,
|
||||
requestId: uploadBody?.requestId || rawUpload.headers.get('x-request-id'),
|
||||
traceId: uploadBody?.traceId || rawUpload.headers.get('x-trace-id') }
|
||||
const file = context.apiSuccess(MODULE, `${label} 上传 ${evidenceType} 装柜证据`, upload, '', OPTIONS)
|
||||
const fileId = id(file?.id || file?.fileId)
|
||||
if (!fileId) throw new Error(`${label} ${evidenceType} 未返回文件ID`)
|
||||
const bind = await post(context,
|
||||
`/api/platform/v1/inbounds/${inboundId}/loading/evidence?tenantId=${encodeURIComponent(tenantId)}`, {
|
||||
expectedVersion: 0, evidenceType, fileId,
|
||||
sealNo: evidenceType === 'SEAL' ? `SEAL-${suffix(context, label)}`.slice(0, 64) : null,
|
||||
remark: context.marker,
|
||||
}, `${label}-evidence-${evidenceType}`)
|
||||
context.apiSuccess(MODULE, `${label} 绑定 ${evidenceType} 装柜证据`, bind, '', OPTIONS)
|
||||
const evidence = context.apiSuccess(MODULE, `${label} 上传并绑定 ${evidenceType} 装柜证据`, upload, '', OPTIONS)
|
||||
const active = evidence?.evidences?.find?.((item) => item.evidenceType === evidenceType
|
||||
&& item.status !== 'VOID')
|
||||
if (!active?.evidenceId || id(evidence?.taskId) !== taskId) {
|
||||
throw new Error(`${label} ${evidenceType} 未返回任务证据ID`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,11 +133,14 @@ async function createConfirmedContainer(context, source, label) {
|
||||
const agentPage = context.apiSuccess(MODULE, `${label} 读取 ACTIVE 订舱代理`, agentResponse, '', OPTIONS)
|
||||
const agent = agentPage?.records?.find?.((item) => item?.id && item?.name)
|
||||
if (!agent) throw new Error(`${label} 未取得 ACTIVE 订舱代理`)
|
||||
const { ensureMatsonCarrierPartner } = await import('./carrier-partner-fixture.mjs')
|
||||
const carrier = await ensureMatsonCarrierPartner(context, MODULE, OPTIONS)
|
||||
if (!carrier?.id) throw new Error(`${label} 未取得 ACTIVE 船公司`)
|
||||
const draft = {
|
||||
customerId: source.tenantId, customerName: summary.customerName || 'IT 测试客户',
|
||||
channelCode: summary.channelCode, warehouseId: source.warehouseId,
|
||||
billOfLadingNo: `BL-${value}`.slice(0, 128),
|
||||
shippingCompanyId: id(agent.id), shippingCompanyName: agent.name, carrierCode: 'OTHER',
|
||||
shippingCompanyId: id(carrier.id), shippingCompanyName: carrier.name, carrierCode: carrier.carrierCode,
|
||||
bookingAgentId: id(agent.id), bookingAgentName: agent.name, departurePortCode: 'CNSZX',
|
||||
vesselName: `人工船-${value}`.slice(0, 128), voyageNo: `V-${value}`.slice(0, 64),
|
||||
departurePortName: '深圳', destinationPortCode: 'USLAX', destinationPortName: '洛杉矶',
|
||||
@@ -161,8 +164,20 @@ async function createConfirmedContainer(context, source, label) {
|
||||
{ expectedVersion: 0, data: draft }, `${label}-booking-create`)
|
||||
const created = context.apiSuccess(MODULE, `${label} 创建订舱`, createdResponse, '', OPTIONS)
|
||||
const bookingId = id(created?.oceanBooking?.id)
|
||||
if (!bookingId) throw new Error(`${label} 创建订舱未返回订舱ID`)
|
||||
const documentForm = new FormData()
|
||||
documentForm.append('expectedVersion', String(Number(created?.oceanBooking?.version)))
|
||||
documentForm.append('documentType', 'BOOKING_CONFIRMATION')
|
||||
documentForm.append('file', new Blob([`${context.marker}-${label}-BOOKING_CONFIRMATION`],
|
||||
{ type: 'text/plain' }), `booking-confirmation-${value}.txt`)
|
||||
const documentResponse = await context.requestMultipart('POST',
|
||||
`/api/platform/v1/ocean-bookings/${bookingId}/documents/upload`, documentForm, context.token,
|
||||
{ 'Idempotency-Key': operationId(context, `${label}-booking-document`) })
|
||||
const document = context.apiSuccess(MODULE, `${label} 上传订舱确认文件`, documentResponse, '', OPTIONS)
|
||||
const releaseVersion = Number(document?.bookingVersion)
|
||||
if (!Number.isInteger(releaseVersion)) throw new Error(`${label} 订舱确认文件未返回有效版本`)
|
||||
const releasedResponse = await post(context, `/api/platform/v1/ocean-bookings/${bookingId}/release`, {
|
||||
expectedVersion: Number(created?.oceanBooking?.version), reason: context.marker,
|
||||
expectedVersion: releaseVersion, reason: context.marker,
|
||||
}, `${label}-booking-release`)
|
||||
const confirmed = context.apiSuccess(MODULE, `${label} 放舱订舱`, releasedResponse, '', OPTIONS)
|
||||
context.assert(MODULE, `${label} 订舱为 RELEASED 且不预生成真实柜`, releasedResponse,
|
||||
@@ -179,12 +194,13 @@ async function createConfirmedContainer(context, source, label) {
|
||||
throw new Error(`${label} 关联真实订舱后内部柜次身份漂移`)
|
||||
}
|
||||
context.apiSuccess(MODULE, `${label} 放舱后关联真实柜号`, linkedResponse, '', OPTIONS)
|
||||
return containerId
|
||||
return { containerId, containerNo }
|
||||
}
|
||||
|
||||
async function createPlanTask(context, label) {
|
||||
const source = await readInbound(context, await prepareInbound(context, label))
|
||||
const containerId = await createConfirmedContainer(context, source, label)
|
||||
const container = await createConfirmedContainer(context, source, label)
|
||||
const { containerId, containerNo } = container
|
||||
const candidateResponse = await context.request('GET',
|
||||
`${SMART}/candidates?bookingId=${containerId}&warehouseId=${source.warehouseId}`)
|
||||
const candidates = context.apiSuccess(MODULE, `${label} 查询同渠道候选货物`, candidateResponse, '', OPTIONS)
|
||||
@@ -288,6 +304,15 @@ async function complete(context, chain, label) {
|
||||
remark: `${context.marker} 人工完成状态样本`,
|
||||
})
|
||||
chain.task = context.apiSuccess(MODULE, `${label} 人工确认装柜完成`, response, '', OPTIONS)
|
||||
for (let attempt = 0; attempt < 90 && chain.task?.taskStatus !== 'COMPLETED'
|
||||
&& chain.task?.taskStatus !== 'COMPLETION_FAILED'; attempt += 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1_000))
|
||||
const detailResponse = await context.request('GET',
|
||||
`${PDA}/tasks/${chain.task.id}?warehouseId=${encodeURIComponent(chain.source.warehouseId)}`)
|
||||
if (detailResponse.http === 200 && String(detailResponse?.body?.code) === '200') {
|
||||
chain.task = detailResponse.body?.data
|
||||
}
|
||||
}
|
||||
return chain
|
||||
}
|
||||
|
||||
@@ -351,39 +376,11 @@ async function completeSimpleDocuments(context, chain, matrix) {
|
||||
&& 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) {
|
||||
@@ -396,13 +393,13 @@ export async function run(context, matrix = context.createdResources.manualState
|
||||
requiredActions: ['clearance'], fixtures: {}, actions: {} }
|
||||
matrix.pages.preloadPlans = { requiredStatuses: PRELOAD_STATUSES, fixtures: {} }
|
||||
matrix.pages.loadingLists = { requiredStatuses: ['COMPLETED'],
|
||||
requiredActions: ['customsDeclaration'], fixtures: {}, actions: {} }
|
||||
requiredActions: [], fixtures: {}, actions: {} }
|
||||
matrix.pages.pdaTasks = { requiredStatuses: PDA_STATUSES, fixtures: {} }
|
||||
|
||||
const waitingSource = await readInbound(context, await prepareInbound(context, 'WAIT'))
|
||||
const waitingContainerId = await createConfirmedContainer(context, waitingSource, 'WAIT')
|
||||
matrix.pages.containerLoading.fixtures.WAIT_LOADING = fixture(waitingContainerId, 'WAIT_LOADING',
|
||||
`/container-loading?containerId=${waitingContainerId}`)
|
||||
const waitingContainer = await createConfirmedContainer(context, waitingSource, 'WAIT')
|
||||
matrix.pages.containerLoading.fixtures.WAIT_LOADING = fixture(waitingContainer.containerId, 'WAIT_LOADING',
|
||||
`/container-loading?containerId=${waitingContainer.containerId}`)
|
||||
|
||||
const editing = await createPlanTask(context, 'EDIT')
|
||||
const inProgress = await claim(context, await createPlanTask(context, 'PROGRESS'), 'PROGRESS')
|
||||
|
||||
@@ -39,9 +39,11 @@ async function raw(context, method, path, body, token, headers = {}) {
|
||||
|
||||
async function loginMerchant(context) {
|
||||
const account = context.context?.merchantQualificationFixture
|
||||
if (!account?.username || !account?.password) throw new Error('缺少本轮客户登录凭据')
|
||||
const username = account?.username || process.env.MERCHANT_TEST_USERNAME || ''
|
||||
const password = account?.password || process.env.MERCHANT_TEST_PASSWORD || ''
|
||||
if (!username || !password) throw new Error('缺少客户登录凭据')
|
||||
const response = await context.request('POST', '/api/auth/login', {
|
||||
username: account.username, password: account.password,
|
||||
username, password,
|
||||
}, '')
|
||||
const token = success(response) ? response.body?.data?.accessToken : null
|
||||
if (!token) throw new Error(`本轮客户登录失败: requestId=${response?.requestId || 'missing'}, traceId=${response?.traceId || 'missing'}`)
|
||||
|
||||
@@ -69,31 +69,28 @@ async function request(context, method, path, body, headers = {}, token = contex
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureCompletionEvidence(context, tenantId, inboundId, keyBase) {
|
||||
async function ensureCompletionEvidence(context, taskId, warehouseId, keyBase) {
|
||||
const png = Uint8Array.from([137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,1,0,0,0,1,8,6,0,0,0,31,21,196,137,0,0,0,13,73,68,65,84,8,215,99,248,207,192,240,31,0,5,0,1,255,137,153,61,29,0,0,0,0,73,69,78,68,174,66,96,130])
|
||||
for (const evidenceType of ['PHOTO_STEP_1', 'PHOTO_STEP_2', 'PHOTO_STEP_3', 'PHOTO_STEP_4', 'SEAL']) {
|
||||
const uploadPath = `/api/platform/v1/files/loading-evidence/${tenantId}/${inboundId}?evidenceType=${encodeURIComponent(evidenceType)}`
|
||||
const query = new URLSearchParams({ warehouseId, expectedVersion: '0', evidenceType,
|
||||
remark: context.marker })
|
||||
if (evidenceType === 'SEAL') query.set('sealNo', `SEAL-${keyBase}`.slice(0, 64))
|
||||
const uploadPath = `${PDA}/tasks/${taskId}/evidence?${query}`
|
||||
const form = new FormData()
|
||||
form.append('file', new Blob([png], { type: 'image/png' }), `${keyBase}-${evidenceType}.png`)
|
||||
const rawUpload = await fetch(`${context.options.gateway}${uploadPath}`, {
|
||||
method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}` },
|
||||
method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}`,
|
||||
'Idempotency-Key': `${keyBase}-evidence-${evidenceType}`.slice(0, 128) },
|
||||
body: form, signal: AbortSignal.timeout(60_000),
|
||||
})
|
||||
const uploadBody = await rawUpload.json()
|
||||
const upload = { method: 'POST', path: uploadPath, http: rawUpload.status, body: uploadBody,
|
||||
requestId: uploadBody?.requestId || rawUpload.headers.get('x-request-id'),
|
||||
traceId: uploadBody?.traceId || rawUpload.headers.get('x-trace-id') }
|
||||
const file = context.apiSuccess(MODULE, `${keyBase} 上传 ${evidenceType} 装柜证据`, upload, '', OPTIONS)
|
||||
const fileId = id(file?.id || file?.fileId)
|
||||
if (!fileId) return false
|
||||
const bind = await request(context, 'POST',
|
||||
`/api/platform/v1/inbounds/${inboundId}/loading/evidence?tenantId=${encodeURIComponent(tenantId)}`, {
|
||||
expectedVersion: 0, evidenceType, fileId,
|
||||
sealNo: evidenceType === 'SEAL' ? `SEAL-${keyBase}`.slice(0, 64) : null,
|
||||
remark: context.marker,
|
||||
}, { 'Idempotency-Key': `${keyBase}-evidence-${evidenceType}`.slice(0, 128) })
|
||||
const bound = context.apiSuccess(MODULE, `${keyBase} 绑定 ${evidenceType} 装柜证据`, bind, '', OPTIONS)
|
||||
if (!bound) return false
|
||||
const evidence = context.apiSuccess(MODULE, `${keyBase} 上传并绑定 ${evidenceType} 装柜证据`, upload, '', OPTIONS)
|
||||
const active = evidence?.evidences?.find?.((item) => item.evidenceType === evidenceType
|
||||
&& item.status !== 'VOID')
|
||||
if (!active?.evidenceId || id(evidence?.taskId) !== taskId) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -201,8 +198,20 @@ async function loadOneFragment(context, state) {
|
||||
const oceanBookingId = id(bookingCreated?.oceanBooking?.id)
|
||||
if (!oceanBookingId) return null
|
||||
context.createdResources.phase3OrderSplitting.retainedAuditRecordIds.push(oceanBookingId)
|
||||
const bookingDocumentForm = new FormData()
|
||||
bookingDocumentForm.append('expectedVersion', String(Number(bookingCreated?.oceanBooking?.version)))
|
||||
bookingDocumentForm.append('documentType', 'BOOKING_CONFIRMATION')
|
||||
bookingDocumentForm.append('file', new Blob([`${context.marker}-${sourceOrderNo}-BOOKING_CONFIRMATION`],
|
||||
{ type: 'text/plain' }), `booking-confirmation-${operationBase.replace(/[^A-Za-z0-9-]/g, '')}.txt`)
|
||||
const bookingDocumentResponse = await context.requestMultipart('POST',
|
||||
`/api/platform/v1/ocean-bookings/${oceanBookingId}/documents/upload`, bookingDocumentForm, context.token,
|
||||
{ 'Idempotency-Key': `${operationBase}-booking-document`.slice(0, 128) })
|
||||
const bookingDocument = context.apiSuccess(MODULE, `上传 ${sourceOrderNo} 的订舱确认文件`,
|
||||
bookingDocumentResponse, '', OPTIONS)
|
||||
const releaseVersion = Number(bookingDocument?.bookingVersion)
|
||||
if (!Number.isInteger(releaseVersion)) return null
|
||||
const releaseResponse = await request(context, 'POST', `/api/platform/v1/ocean-bookings/${oceanBookingId}/release`, {
|
||||
expectedVersion: Number(bookingCreated?.oceanBooking?.version), reason: context.marker,
|
||||
expectedVersion: releaseVersion, reason: context.marker,
|
||||
}, { 'Idempotency-Key': `${operationBase}-booking-release`.slice(0, 128) })
|
||||
const bookingConfirmed = context.apiSuccess(MODULE, `放舱 ${sourceOrderNo} 的订舱`, releaseResponse, '', OPTIONS)
|
||||
context.assert(MODULE, `${sourceOrderNo} 订舱为 RELEASED 且不预生成真实柜`, releaseResponse,
|
||||
@@ -419,7 +428,7 @@ async function loadOneFragment(context, state) {
|
||||
`HTTP=${differentReplay.http}, code=${codeOf(differentReplay)}, requestId=${differentReplay.requestId || 'missing'}, traceId=${differentReplay.traceId || 'missing'}`, OPTIONS)
|
||||
}
|
||||
|
||||
if (!await ensureCompletionEvidence(context, tenantId, id(candidate.inboundId), operationBase)) return null
|
||||
if (!await ensureCompletionEvidence(context, taskId, warehouseId, operationBase)) return null
|
||||
|
||||
const completePath = `${PDA}/tasks/${taskId}/complete`
|
||||
const completePayload = {
|
||||
@@ -427,8 +436,18 @@ async function loadOneFragment(context, state) {
|
||||
remark: context.marker,
|
||||
}
|
||||
const complete = await request(context, 'POST', completePath, completePayload)
|
||||
const completed = context.apiSuccess(MODULE, `人工确认 ${sourceOrderNo} 装柜完成并结算余量`, complete, '', OPTIONS)
|
||||
context.assert(MODULE, `${sourceOrderNo} 只在 complete 后进入完成态`, complete,
|
||||
let completed = context.apiSuccess(MODULE, `人工确认 ${sourceOrderNo} 装柜完成并结算余量`, complete, '', OPTIONS)
|
||||
let completedResponse = complete
|
||||
for (let attempt = 0; attempt < 90 && completed?.taskStatus !== 'COMPLETED'
|
||||
&& completed?.taskStatus !== 'COMPLETION_FAILED'; attempt += 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1_000))
|
||||
completedResponse = await context.request('GET',
|
||||
`${PDA}/tasks/${taskId}?warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
if (completedResponse.http === 200 && codeOf(completedResponse) === '200') {
|
||||
completed = completedResponse.body?.data
|
||||
}
|
||||
}
|
||||
context.assert(MODULE, `${sourceOrderNo} 只在 complete 后进入完成态`, completedResponse,
|
||||
completed?.taskStatus === 'COMPLETED' && completed?.workflowStatus === 'COMPLETED'
|
||||
&& completed?.items?.some?.((row) => id(row.id) === id(claimedItem.id)
|
||||
&& Number(row.pickedPackageCount) === 1 && Number(row.plannedPackageCount) === 1),
|
||||
|
||||
Reference in New Issue
Block a user