test: automate overseas wallet and pallet cost closure

This commit is contained in:
2026-09-06 11:00:06 +08:00
parent 64bf5aa0fe
commit 20b3074cb1
21 changed files with 506 additions and 103 deletions
@@ -40,6 +40,36 @@ async function request(context, token, method, name, path, body = undefined) {
return { response, data: success(response) ? response.body?.data : null }
}
async function poll(action, predicate, attempts = 60) {
let result = null
for (let index = 0; index < attempts; index += 1) {
result = await action()
if (predicate(result)) return { result, attempts: index + 1 }
if (index + 1 < attempts) await new Promise((resolve) => setTimeout(resolve, 1_000))
}
return { result, attempts }
}
async function fundRelabelWallet(context, customerId) {
const accountResponse = await context.request('GET',
`/api/platform/finance/v1/accounts?page=1&pageSize=20&customerId=${encodeURIComponent(customerId)}`)
const account = success(accountResponse)
? records(accountResponse.body?.data).find((item) => id(item?.customerId) === customerId) : null
context.addStep(MODULE, 'P5读取本轮客户钱包版本', accountResponse,
Boolean(account) && Number.isInteger(Number(account.accountVersion)), trace(accountResponse), OPTIONS)
if (!account) return false
const recharge = await context.request('POST',
`/api/platform/finance/v1/accounts/${encodeURIComponent(customerId)}/adjustments`, {
type: 'RECHARGE', amount: 1, occurredDate: new Date().toISOString().slice(0, 10),
paymentMethod: 'BANK_TRANSFER', referenceNo: `${context.marker}-P5`, remark: context.marker,
expectedAccountVersion: Number(account.accountVersion),
}, context.token, { 'Idempotency-Key': key(context, 'RELABEL-WALLET-FUND') })
context.addStep(MODULE, 'P5为收费换标准备本轮隔离实际余额', recharge,
success(recharge) && Number(recharge.body?.data?.actualBalanceAfter) >= 1,
`actualBalanceAfter=${recharge.body?.data?.actualBalanceAfter ?? 'missing'}; ${trace(recharge)}`, OPTIONS)
return success(recharge)
}
async function expectConflict(context, token, method, name, path, body) {
const response = await context.requestOverseas(method, path, body, {}, token)
context.addStep(MODULE, name, response, conflict(response), trace(response), OPTIONS)
@@ -292,13 +322,14 @@ async function verifyRelabel(context, token, fixture) {
blocker(context, 'P5本轮库存换标申请', '缺少本轮完成库存的客户、SKU或海外仓事实')
return false
}
if (!await fundRelabelWallet(context, customerId)) return false
const relabelBase = '/api/platform/v1/last-leg/relabel-applications'
const pdaBase = '/api/pda/v1/last-leg/relabel-tasks'
const newSku = `${inventory.skuCode}-NEW-${String(context.marker).slice(-8)}`.slice(0, 128)
const createBody = {
customerOrderNo: String(customerOrderNo).slice(0, 128), overseasWarehouseId: id(fixture.overseasWarehouseId),
labelDeadline: new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 19),
contactName: 'PDA换标验收', contactPhone: '13800000006', remark: context.marker,
contactName: 'PDA换标验收', contactPhone: '13800000006', chargeAmount: 0.01, remark: context.marker,
idempotencyKey: key(context, 'RELABEL-CREATE'),
items: [{ skuCode: inventory.skuCode, productNameZh: inventory.productName || '本轮库存商品',
totalPackageCount: 3, notifiedPackageCount: 3, shipmentNo: `SHIP-${context.marker}`.slice(0, 128),
@@ -316,6 +347,12 @@ async function verifyRelabel(context, token, fixture) {
blocker(context, 'P5真实换标申请', '平台正式换标创建接口未返回申请单号', createdResponse)
return false
}
const funded = await poll(async () => context.requestOverseas('GET', `${relabelBase}/${encodeURIComponent(relabelNo)}`),
(response) => success(response) && response.body?.data?.application?.walletStatus === 'FROZEN')
context.addStep(MODULE, 'P5换标费用冻结后开放PDA作业', funded.result,
funded.result?.body?.data?.application?.walletStatus === 'FROZEN',
`pollRequests=${funded.attempts}, walletStatus=${funded.result?.body?.data?.application?.walletStatus || 'missing'}; ${trace(funded.result)}`, OPTIONS)
if (funded.result?.body?.data?.application?.walletStatus !== 'FROZEN') return false
const candidates = await request(context, token, 'GET', 'P5读取当前仓换标候选', `${pdaBase}/candidates`)
context.assert(MODULE, 'P5候选包含本轮真实申请', candidates.response,
Array.isArray(candidates.data) && candidates.data.some((item) => id(item?.relabelNo) === relabelNo),
@@ -404,7 +441,12 @@ async function verifyRelabel(context, token, fixture) {
context.assert(MODULE, 'P5最终任务和申请均COMPLETED', approveReplay.response,
approved.data?.taskStatus === 'COMPLETED' && approved.data?.applicationStatus === 'COMPLETED'
&& approveReplay.data?.taskStatus === 'COMPLETED', trace(approveReplay.response), OPTIONS)
return success(approved.response)
const settled = await poll(async () => context.requestOverseas('GET', `${relabelBase}/${encodeURIComponent(relabelNo)}`),
(response) => success(response) && response.body?.data?.application?.walletStatus === 'SETTLED')
context.addStep(MODULE, 'P5换标完成后钱包结算收敛', settled.result,
settled.result?.body?.data?.application?.walletStatus === 'SETTLED',
`pollRequests=${settled.attempts}, walletStatus=${settled.result?.body?.data?.application?.walletStatus || 'missing'}; ${trace(settled.result)}`, OPTIONS)
return success(approved.response) && settled.result?.body?.data?.application?.walletStatus === 'SETTLED'
}
export async function run(context) {