test(phase4): provision overseas lifecycle fixtures

This commit is contained in:
2026-08-24 15:07:17 +08:00
parent cd97229791
commit e11a528dfe
12 changed files with 248 additions and 48 deletions
@@ -20,6 +20,11 @@ async function domesticGet(context, name, path) {
const data = context.apiSuccess(MODULE, name, response, trace(response), OPTIONS)
return { response, data }
}
async function domestic(context, method, name, path, body) {
const response = await context.request(method, path, body)
const data = context.apiSuccess(MODULE, name, response, trace(response), OPTIONS)
return { response, data }
}
async function overseas(context, method, name, path, body) {
const response = await context.requestOverseas(method, path, body)
const data = context.apiSuccess(MODULE, name, response, trace(response), OPTIONS)
@@ -38,6 +43,11 @@ async function prerequisites(context) {
coverageGap(context, '海外业务写验收 ACTIVE 客户前置', `IAM 未返回真实 ACTIVE 客户;${trace(tenants.response)}`, 'missing-active-customer')
return null
}
const fixture = context.createdResources?.merchantQualificationFixture
const fixtureCustomerId = id(fixture?.tenantId)
const activeCustomer = activeCustomers.find((item) => id(item?.id) === fixtureCustomerId) || activeCustomers[0]
const partnerWarehouse = await createPartnerWarehouse(context)
const purchase = await createMerchantProcurement(context, activeCustomer)
const customerOptions = await overseas(context, 'GET', '查询采购客户候选', `${BASE}/overseas-procurements/customer-options?limit=200`)
const warehouseOptions = await overseas(context, 'GET', '查询 ACTIVE 采购仓候选', `${BASE}/overseas-procurements/warehouse-options`)
context.assert(MODULE, '采购客户候选结构正确', customerOptions.response,
@@ -50,9 +60,62 @@ async function prerequisites(context) {
const procurementCustomer = Array.isArray(customerOptions.data)
? customerOptions.data.find((item) => activeIds.has(id(item?.customerId))) : null
const warehouse = Array.isArray(warehouseOptions.data) ? warehouseOptions.data.find((item) => longId(item?.warehouseId)) : null
return { activeCustomer: activeCustomers[0], procurementCustomer, warehouse, customerOptions, warehouseOptions }
return { activeCustomer, procurementCustomer, warehouse, customerOptions, warehouseOptions, partnerWarehouse, purchase }
}
function partnerWarehousePayload(context) {
const suffix = String(context.marker || '').replace(/[^A-Za-z0-9]/g, '').slice(-20).toUpperCase()
return {
tenantId: 0, warehouseCode: `P4B-${suffix}`.slice(0, 50), warehouseName: `${context.marker} 采购合作仓`,
warehouseType: 'OVERSEAS_PARTNER', countryCode: 'US', timezone: 'UTC-8', contactName: 'Phase4 QA',
contactPhone: '+1-213-555-0177', contactEmail: null, status: 'ACTIVE', remark: `${context.marker}-procurement-fixture`,
address: { addressType: 'WAREHOUSE', countryCode: 'US', stateProvince: 'California', city: 'Los Angeles',
district: 'Commerce', postalCode: '90040', addressLine1: '601 Procurement Partner Avenue', addressLine2: null,
latitude: null, longitude: null },
capabilities: [{ capabilityCode: 'STORAGE', capabilityName: 'Storage', enabled: true,
cutoffTime: null, description: `${context.marker} procurement acceptance` }],
}
}
async function createPartnerWarehouse(context) {
const payload = partnerWarehousePayload(context)
const created = await domestic(context, 'POST', '创建本轮采购合作仓', '/api/platform/v1/warehouse-admin', payload)
const warehouseId = id(created.data)
context.assert(MODULE, '采购合作仓创建返回长ID', created.response, longId(warehouseId),
`warehouseId=${warehouseId || 'missing'}; ${trace(created.response)}`, OPTIONS)
return warehouseId ? { id: warehouseId, finalStatus: 'ACTIVE' } : null
}
async function createMerchantProcurement(context, activeCustomer) {
const username = context.context?.merchantQualificationFixture?.username
const password = context.context?.merchantQualificationFixture?.password
const login = await context.request('POST', '/api/auth/login', { username, password }, '')
const auth = context.apiSuccess(MODULE, '采购客户账号登录', login, trace(login), OPTIONS)
const overseasToken = auth?.overseasAccessToken
context.assert(MODULE, '采购客户登录返回海外Token', login, nonEmpty(overseasToken),
`customerId=${id(activeCustomer?.id) || 'missing'}, tokenPresent=${Boolean(overseasToken)}; ${trace(login)}`, OPTIONS)
if (!overseasToken) return null
const payload = {
customerName: activeCustomer?.tenantName || activeCustomer?.name || `Customer-${id(activeCustomer?.id)}`,
purchaseCategory: 'OFFICE_SUPPLIES', productName: `${context.marker} 采购商品`,
productSpecification: 'Phase4 acceptance', productUrl: null, purchaseQuantity: 10,
budgetUnitPrice: 1.25, currency: 'USD', receivingAddress: 'Los Angeles',
contactName: '采购验收联系人', contactPhone: '13800000002', remark: context.marker,
idempotencyKey: `${context.marker}-phase4-procurement`.slice(0, 255),
}
const response = await context.requestOverseas('POST', '/api/merchant/v1/last-leg/overseas-procurements', payload, {}, overseasToken)
const detail = context.apiSuccess(MODULE, '创建本轮客户采购订单', response, trace(response), OPTIONS)
const value = summary(detail)
context.assert(MODULE, '客户采购订单创建为待审核且归属正确', response,
nonEmpty(value?.orderNo) && id(value?.customerId) === id(activeCustomer?.id) && value?.status === 'PENDING_REVIEW',
`orderNo=${id(value?.orderNo) || 'missing'}, customerId=${id(value?.customerId) || 'missing'}, status=${value?.status || 'missing'}; ${trace(response)}`, OPTIONS)
const purchase = value?.orderNo ? { marker: context.marker, orderNo: id(value.orderNo), customerId: id(value.customerId), version: Number(value.version), retained: true } : null
if (purchase) ownedRegistry(context).purchase = purchase
return purchase
}
function nonEmpty(value) { return typeof value === 'string' && value.trim().length > 0 }
function markerOwnedPurchase(context) {
const candidates = [context.createdResources?.phase4OverseasBusiness?.purchase, context.createdResources?.overseasProcurement]
return candidates.find((item) => item?.marker === context.marker && id(item?.orderNo) && longId(item?.customerId)) || null
@@ -65,7 +128,7 @@ async function procurementFlow(context, prerequisite) {
}
const customerId = id(prerequisite.procurementCustomer.customerId)
const warehouseId = id(prerequisite.warehouse.warehouseId)
const list = await overseas(context, 'GET', '按真实客户与采购仓查询采购订单', query(`${BASE}/overseas-procurements`, { page: 1, size: 20, customerId, purchaseWarehouseId: warehouseId }))
const list = await overseas(context, 'GET', '按真实客户查询采购订单', query(`${BASE}/overseas-procurements`, { page: 1, size: 20, customerId }))
assertPage(context, '海外采购订单', list)
const owned = markerOwnedPurchase(context)
const row = records(list.data).find((item) => owned && item?.orderNo === owned.orderNo && id(item?.customerId) === id(owned.customerId))
@@ -77,12 +140,22 @@ async function procurementFlow(context, prerequisite) {
const detail = await overseas(context, 'GET', '查询本轮自有采购订单详情', detailPath)
const current = summary(detail.data)
const update = await overseas(context, 'PATCH', '编辑本轮自有采购订单', detailPath,
{ version: Number(current?.version), productSpecification: `${context.marker}-procurement`, remark: context.marker })
{ version: Number(current?.version), productSpecification: `${context.marker}-procurement`,
purchaseWarehouseId: warehouseId, purchaseWarehouseName: prerequisite.warehouse.warehouseName,
remark: context.marker })
const updated = summary(update.data)
context.assert(MODULE, '本轮采购编辑回显 marker 且版本递增', update.response,
updated?.productSpecification === `${context.marker}-procurement` && Number(updated?.version) === Number(current?.version) + 1,
`orderNo=${id(updated?.orderNo) || 'missing'}, version=${updated?.version ?? 'missing'}; ${trace(update.response)}`, OPTIONS)
ownedRegistry(context).purchase = { marker: context.marker, orderNo: id(updated?.orderNo), customerId: id(updated?.customerId), version: Number(updated?.version), retained: true }
const reviewed = await overseas(context, 'POST', '驳回本轮采购订单并安全收口',
query(`${BASE}/overseas-procurements/${encodeURIComponent(row.orderNo)}/review`, { customerId }),
{ decision: 'REJECT', remark: `${context.marker}-acceptance-cleanup` })
const reviewedSummary = summary(reviewed.data)
context.assert(MODULE, '本轮采购订单终态为已驳回', reviewed.response,
reviewedSummary?.status === 'REJECTED' && Number(reviewedSummary?.version) === Number(updated?.version) + 1,
`orderNo=${id(reviewedSummary?.orderNo) || 'missing'}, status=${reviewedSummary?.status || 'missing'}, version=${reviewedSummary?.version ?? 'missing'}; ${trace(reviewed.response)}`, OPTIONS)
ownedRegistry(context).purchase = { marker: context.marker, orderNo: id(reviewedSummary?.orderNo), customerId, version: Number(reviewedSummary?.version), finalStatus: reviewedSummary?.status, retained: reviewedSummary?.status !== 'REJECTED' }
}
function truckPayload(context) {
@@ -215,8 +288,16 @@ async function looseboardFlow(context, customerId) {
export async function run(context) {
const prerequisite = await prerequisites(context)
if (!prerequisite) return
await procurementFlow(context, prerequisite)
const customerId = id(prerequisite.activeCustomer.id)
await truckFlow(context, customerId)
await looseboardFlow(context, customerId)
try {
await procurementFlow(context, prerequisite)
const customerId = id(prerequisite.activeCustomer.id)
await truckFlow(context, customerId)
await looseboardFlow(context, customerId)
} finally {
if (prerequisite.partnerWarehouse?.id) {
const retired = await context.request('PATCH', `/api/platform/v1/warehouse-admin/${encodeURIComponent(prerequisite.partnerWarehouse.id)}/status?tenantId=0&status=INACTIVE`)
context.addStep(MODULE, '本轮采购合作仓已停用收口', retired,
retired?.http === 200 && codeOf(retired) === '200', trace(retired), OPTIONS)
}
}
}