完成单机TEST统一入口与可靠投递回归收尾

This commit is contained in:
2026-09-29 19:48:34 +08:00
parent 64a70c9f28
commit 6c0a026cc4
89 changed files with 968 additions and 983 deletions
@@ -48,8 +48,8 @@ async function merchantLogin(context, fixture) {
const response = await context.request('POST', '/api/auth/login', { loginId: fixture.username, password: fixture.password }, '')
const auth = success(response) ? response.body.data : null
assert(context, '客户账号同时取得国内和海外短时Token', response,
Boolean(auth?.accessToken) && Boolean(auth?.overseasAccessToken),
`customerId=${fixture.tenantId}, domestic=${Boolean(auth?.accessToken)}, overseas=${Boolean(auth?.overseasAccessToken)}`)
Boolean(auth?.accessToken) && Boolean(auth?.accessToken),
`customerId=${fixture.tenantId}, domestic=${Boolean(auth?.accessToken)}, overseas=${Boolean(auth?.accessToken)}`)
return auth
}
@@ -96,7 +96,7 @@ async function prepareWallet(context, customerId) {
return success(recharge) ? { before: before.account, funded: recharge.body.data, rechargeAmount, creditLimit } : null
}
async function procurementFlow(context, fixture, overseasToken) {
async function procurementFlow(context, fixture, token) {
const merchantPath = '/api/merchant/v1/last-leg/overseas-procurements'
const payload = {
customerName: fixture.tenantName, purchaseCategory: 'OFFICE_SUPPLIES', productName: `${context.marker} 钱包采购`,
@@ -105,7 +105,7 @@ async function procurementFlow(context, fixture, overseasToken) {
contactName: '全量验收联系人', contactPhone: '13800000002', remark: context.marker,
idempotencyKey: `${context.marker}-wallet-procurement`.slice(0, 255),
}
const created = await context.requestOverseas('POST', merchantPath, payload, {}, overseasToken)
const created = await context.request('POST', merchantPath, payload, token, {})
const detail = created?.body?.data
const orderNo = detail?.summary?.orderNo
assert(context, '客户创建钱包采购单', created,
@@ -117,7 +117,7 @@ async function procurementFlow(context, fixture, overseasToken) {
`orderNo=${orderNo}, expectedPrefix=${fixture.expectedProcurementPrefix || 'custom-customer'}`)
const customerId = id(fixture.tenantId)
const approved = await context.requestOverseas('POST', query(`${PROCUREMENT}/${encodeURIComponent(orderNo)}/review`, { customerId }), {
const approved = await context.request('POST', query(`${PROCUREMENT}/${encodeURIComponent(orderNo)}/review`, { customerId }), {
version: Number(detail.summary.version), decision: 'APPROVE',
idempotencyKey: `${context.marker}-wallet-procurement-review`.slice(0, 255), remark: context.marker,
})
@@ -128,7 +128,7 @@ async function procurementFlow(context, fixture, overseasToken) {
const files = []
for (const category of ['VOUCHER', 'RECEIPT']) {
const uploaded = await context.requestOverseasMultipart('POST',
const uploaded = await context.requestMultipart('POST',
query(`${PROCUREMENT}/${encodeURIComponent(orderNo)}/files/${category}`, { customerId }),
{ content: PNG, type: 'image/png', name: `${category.toLowerCase()}-${orderNo}.png` })
assert(context, `采购单上传${category}文件`, uploaded,
@@ -138,7 +138,7 @@ async function procurementFlow(context, fixture, overseasToken) {
}
if (files.length !== 2) return null
const fee = await context.requestOverseas('POST', query(`${PROCUREMENT}/${encodeURIComponent(orderNo)}/fees`, { customerId }), {
const fee = await context.request('POST', query(`${PROCUREMENT}/${encodeURIComponent(orderNo)}/fees`, { customerId }), {
feeItemCode: 'PROCUREMENT_SERVICE', feeItemName: '采购服务费', amount: 0.01,
voucherFileId: id(files.find((item) => item.category === 'VOUCHER')?.fileId), remark: context.marker,
})
@@ -149,7 +149,7 @@ async function procurementFlow(context, fixture, overseasToken) {
if (!success(fee) || !feeNo) return null
const detailPath = query(`${PROCUREMENT}/${encodeURIComponent(orderNo)}`, { customerId })
const frozen = await poll(async () => context.requestOverseas('GET', detailPath),
const frozen = await poll(async () => context.request('GET', detailPath),
(response) => success(response) && response.body.data?.fees?.find((item) => item.feeNo === feeNo)?.walletStatus === 'FROZEN')
const frozenFee = frozen.result?.body?.data?.fees?.find((item) => item.feeNo === feeNo)
assert(context, '采购费用跨区冻结到账', frozen.result,
@@ -157,13 +157,13 @@ async function procurementFlow(context, fixture, overseasToken) {
if (frozenFee?.walletStatus !== 'FROZEN') return null
const current = frozen.result.body.data.summary
const settledOrder = await context.requestOverseas('PATCH', detailPath, {
const settledOrder = await context.request('PATCH', detailPath, {
version: Number(current.version), inboundQuantity: Number(current.purchaseQuantity),
})
assert(context, '采购全量入库推进待出库并触发结算', settledOrder,
success(settledOrder) && settledOrder.body.data?.summary?.status === 'PENDING_OUTBOUND',
`status=${settledOrder.body?.data?.summary?.status || 'missing'}`)
const settled = await poll(async () => context.requestOverseas('GET', detailPath),
const settled = await poll(async () => context.request('GET', detailPath),
(response) => success(response) && response.body.data?.fees?.find((item) => item.feeNo === feeNo)?.walletStatus === 'SETTLED')
const settledFee = settled.result?.body?.data?.fees?.find((item) => item.feeNo === feeNo)
assert(context, '采购费用跨区结算到账', settled.result,
@@ -191,10 +191,9 @@ function relabelPayload(context, warehouseId, source, suffix, chargeAmount) {
}
}
async function relabelFlow(context, overseasToken, warehouseId, suffix, terminalStatus) {
const candidatesResponse = await context.requestOverseas('GET', query(
'/api/merchant/v1/last-leg/relabel-applications/inventory-candidates', { operationWarehouseId: warehouseId }),
undefined, {}, overseasToken)
async function relabelFlow(context, token, warehouseId, suffix, terminalStatus) {
const candidatesResponse = await context.request('GET', query(
'/api/merchant/v1/last-leg/relabel-applications/inventory-candidates', { operationWarehouseId: warehouseId }), undefined, token, {})
const candidates = success(candidatesResponse) && Array.isArray(candidatesResponse.body?.data)
? candidatesResponse.body.data : []
const currentPda = context.createdResources?.phase4OverseasPda
@@ -229,7 +228,7 @@ async function relabelFlow(context, overseasToken, warehouseId, suffix, terminal
Boolean(source?.position), `warehouseId=${warehouseId}, candidates=${candidates.length}`)
if (!source?.position) return null
const payload = relabelPayload(context, warehouseId, source, suffix, 0.01)
const created = await context.requestOverseas('POST', '/api/merchant/v1/last-leg/relabel-applications', payload, {}, overseasToken)
const created = await context.request('POST', '/api/merchant/v1/last-leg/relabel-applications', payload, token, {})
const relabelNo = created?.body?.data?.application?.relabelNo
assert(context, `${suffix}换标单创建并携带收费金额`, created,
success(created) && Boolean(relabelNo) && money(created.body.data?.application?.chargeAmount) === 0.01,
@@ -237,7 +236,7 @@ async function relabelFlow(context, overseasToken, warehouseId, suffix, terminal
if (!success(created) || !relabelNo) return null
const detailPath = `${RELABEL}/${encodeURIComponent(relabelNo)}`
const frozen = await poll(async () => context.requestOverseas('GET', detailPath),
const frozen = await poll(async () => context.request('GET', detailPath),
(response) => success(response) && response.body.data?.application?.walletStatus === 'FROZEN')
assert(context, `${suffix}换标费用跨区冻结到账`, frozen.result,
frozen.result?.body?.data?.application?.walletStatus === 'FROZEN',
@@ -245,32 +244,29 @@ async function relabelFlow(context, overseasToken, warehouseId, suffix, terminal
if (frozen.result?.body?.data?.application?.walletStatus !== 'FROZEN') return null
const reviewStatus = terminalStatus === 'COMPLETED' ? 'PENDING_PROCESSING' : 'CANCELLED'
const review = await context.requestOverseas('PUT', query(
const review = await context.request('PUT', query(
`/api/platform/v1/last-leg/orders/${encodeURIComponent(id(created.body.data.application.lastlegOrderId))}/relabel-review`,
{ customerId: id(context.context.merchantQualificationFixture.tenantId) }),
{ status: reviewStatus, remark: context.marker })
{ customerId: id(context.context.merchantQualificationFixture.tenantId) }), { status: reviewStatus, remark: context.marker })
assert(context, `${suffix}尾程订单审核直接贴标申请`, review,
success(review) && review.body.data?.application?.status === reviewStatus)
if (!success(review)) return null
if (terminalStatus === 'COMPLETED') {
const processing = await context.requestOverseas('PUT', `${detailPath}/status`, { status: 'PROCESSING', remark: context.marker })
const processing = await context.request('PUT', `${detailPath}/status`, { status: 'PROCESSING', remark: context.marker })
assert(context, '换标单冻结后才允许进入处理中', processing,
success(processing) && processing.body.data?.application?.status === 'PROCESSING')
const confirmPending = await context.requestOverseas('PUT', `${detailPath}/status`,
{ status: 'CUSTOMER_CONFIRM_PENDING', remark: context.marker })
const confirmPending = await context.request('PUT', `${detailPath}/status`, { status: 'CUSTOMER_CONFIRM_PENDING', remark: context.marker })
assert(context, '换标处理完成后进入客户确认', confirmPending,
success(confirmPending) && confirmPending.body.data?.application?.status === 'CUSTOMER_CONFIRM_PENDING')
const readyForOutbound = await context.requestOverseas('PUT', `${detailPath}/status`,
{ status: 'READY_FOR_OUTBOUND', remark: context.marker })
const readyForOutbound = await context.request('PUT', `${detailPath}/status`, { status: 'READY_FOR_OUTBOUND', remark: context.marker })
assert(context, '换标客户确认后进入待出库', readyForOutbound,
success(readyForOutbound) && readyForOutbound.body.data?.application?.status === 'READY_FOR_OUTBOUND')
}
const terminal = terminalStatus === 'CANCELLED' ? review : await context.requestOverseas('PUT', `${detailPath}/status`, { status: terminalStatus, remark: context.marker })
const terminal = terminalStatus === 'CANCELLED' ? review : await context.request('PUT', `${detailPath}/status`, { status: terminalStatus, remark: context.marker })
assert(context, `${suffix}换标单进入${terminalStatus}`, terminal,
success(terminal) && terminal.body.data?.application?.status === terminalStatus)
const walletTerminal = terminalStatus === 'COMPLETED' ? 'SETTLED' : 'RELEASED'
const wallet = await poll(async () => context.requestOverseas('GET', detailPath),
const wallet = await poll(async () => context.request('GET', detailPath),
(response) => success(response) && response.body.data?.application?.walletStatus === walletTerminal)
assert(context, `${suffix}换标费用跨区${walletTerminal}`, wallet.result,
wallet.result?.body?.data?.application?.walletStatus === walletTerminal,
@@ -308,14 +304,13 @@ async function verifyPalletSummaries(context, warehouseId) {
success(domestic) && summaryValid(d, ['totalCount', 'idleCount', 'occupiedCount'])
&& Number(d.totalCount) === Number(d.idleCount) + Number(d.occupiedCount),
`total=${d?.totalCount}, idle=${d?.idleCount}, occupied=${d?.occupiedCount}`)
const overseas = await context.requestOverseas('GET', '/api/platform/v1/warehouse-admin/pallets/summary?page=1&size=20')
const overseas = await context.request('GET', '/api/platform/v1/warehouse-admin/pallets/summary?page=1&size=20')
const o = overseas?.body?.data
assert(context, '海外托盘汇总含闲置、占用和报废数量', overseas,
success(overseas) && summaryValid(o, ['totalCount', 'idleCount', 'occupiedCount', 'scrappedCount'])
&& Number(o.totalCount) === Number(o.idleCount) + Number(o.occupiedCount) + Number(o.scrappedCount),
`total=${o?.totalCount}, idle=${o?.idleCount}, occupied=${o?.occupiedCount}, scrapped=${o?.scrappedCount}`)
const warehouse = await context.requestOverseas('GET',
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets/summary?page=1&size=20`)
const warehouse = await context.request('GET', `/api/platform/v1/overseas-warehouse-resources/${encodeURIComponent(warehouseId)}/pallets/summary?page=1&size=20`)
assert(context, '海外仓级托盘汇总可用', warehouse,
success(warehouse) && summaryValid(warehouse.body.data, ['totalCount', 'idleCount', 'occupiedCount', 'scrappedCount']))
}
@@ -324,7 +319,7 @@ async function verifyDestuffCosts(context, completedFacts) {
const evidence = []
for (const fact of completedFacts) {
const businessNo = `DESTUFF-${fact.containerBookingId}`
const lastleg = await poll(async () => context.requestOverseas('GET', query('/api/platform/v1/last-leg/finance-fee-sources', {
const lastleg = await poll(async () => context.request('GET', query('/api/platform/v1/last-leg/finance-fee-sources', {
businessType: 'OVERSEAS_CONTAINER', businessNo,
})), (response) => success(response) && rows(response.body.data).length > 0, 75)
const sources = success(lastleg.result) ? rows(lastleg.result.body.data) : []
@@ -363,9 +358,9 @@ export async function run(context) {
const auth = await merchantLogin(context, fixture)
const wallet = auth ? await prepareWallet(context, id(fixture.tenantId)) : null
const procurement = wallet ? await procurementFlow(context, fixture, auth.overseasAccessToken) : null
const settledRelabel = procurement ? await relabelFlow(context, auth.overseasAccessToken, warehouseId, 'SETTLE', 'COMPLETED') : null
const releasedRelabel = settledRelabel ? await relabelFlow(context, auth.overseasAccessToken, warehouseId, 'RELEASE', 'CANCELLED') : null
const procurement = wallet ? await procurementFlow(context, fixture, auth.accessToken) : null
const settledRelabel = procurement ? await relabelFlow(context, auth.accessToken, warehouseId, 'SETTLE', 'COMPLETED') : null
const releasedRelabel = settledRelabel ? await relabelFlow(context, auth.accessToken, warehouseId, 'RELEASE', 'CANCELLED') : null
const relabels = [settledRelabel, releasedRelabel].filter(Boolean)
const finalAccount = procurement && relabels.length === 2
? await verifyClientWallet(context, auth.accessToken, fixture, wallet, procurement, relabels) : null