test: honor runtime inbound code policy in HTTP order fixtures
This commit is contained in:
@@ -2,10 +2,24 @@ import assert from 'node:assert/strict'
|
|||||||
import { readFileSync } from 'node:fs'
|
import { readFileSync } from 'node:fs'
|
||||||
import test from 'node:test'
|
import test from 'node:test'
|
||||||
|
|
||||||
import { orderPersistenceFacts, requestedOrderDestinationType } from './orders.mjs'
|
import { fixtureInboundCode, orderPersistenceFacts, requestedOrderDestinationType } from './orders.mjs'
|
||||||
|
|
||||||
const source = readFileSync(new URL('orders.mjs', import.meta.url), 'utf8')
|
const source = readFileSync(new URL('orders.mjs', import.meta.url), 'utf8')
|
||||||
|
|
||||||
|
test('fresh fixture obeys the authoritative inbound-code policy without changing global settings', () => {
|
||||||
|
assert.deepEqual(fixtureInboundCode({ mode: 'AUTO', manualEntryRequired: false }, 'batch-A'), {})
|
||||||
|
const policy = { mode: 'LEGACY_MANUAL', manualEntryRequired: true }
|
||||||
|
const first = fixtureInboundCode(policy, 'batch-A')
|
||||||
|
assert.deepEqual(first, fixtureInboundCode(policy, 'batch-A'))
|
||||||
|
assert.notEqual(first.inboundCode, fixtureInboundCode(policy, 'batch-B').inboundCode)
|
||||||
|
assert.match(first.inboundCode, /^AT[A-F0-9]{20}$/)
|
||||||
|
assert.ok(`${first.inboundCode}#9999-9999`.length <= 34)
|
||||||
|
for (const invalid of [null, {}, { mode: 'AUTO', manualEntryRequired: true }, { mode: 'UNKNOWN', manualEntryRequired: false }]) {
|
||||||
|
assert.throws(() => fixtureInboundCode(invalid, 'batch-A'), /入仓码策略/)
|
||||||
|
}
|
||||||
|
assert.match(source, /GET', `\$\{createPath\}\/inbound-code-policy`/)
|
||||||
|
})
|
||||||
|
|
||||||
test('order demo payload covers multi-box multi-SKU images and both destination families', () => {
|
test('order demo payload covers multi-box multi-SKU images and both destination families', () => {
|
||||||
for (const boxType of ['SMALL', 'MEDIUM', 'LARGE', 'EXTRA_LARGE']) {
|
for (const boxType of ['SMALL', 'MEDIUM', 'LARGE', 'EXTRA_LARGE']) {
|
||||||
assert.match(source, new RegExp(`boxType: '${boxType}'`))
|
assert.match(source, new RegExp(`boxType: '${boxType}'`))
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { createHash } from 'node:crypto'
|
||||||
|
|
||||||
const MODULE = 'orders'
|
const MODULE = 'orders'
|
||||||
const CONTRACT_OPTIONS = { scenario: 'isolated-order-chain', deploymentBlocker: true }
|
const CONTRACT_OPTIONS = { scenario: 'isolated-order-chain', deploymentBlocker: true }
|
||||||
const MERCHANT_USERNAME = process.env.MERCHANT_TEST_USERNAME || ''
|
const MERCHANT_USERNAME = process.env.MERCHANT_TEST_USERNAME || ''
|
||||||
@@ -25,6 +27,14 @@ function rotate(values, offset) {
|
|||||||
return [...values.slice(shift), ...values.slice(0, shift)]
|
return [...values.slice(shift), ...values.slice(0, shift)]
|
||||||
}
|
}
|
||||||
function key(context, operation) { return `${context.marker}-${operation}`.slice(0, 128) }
|
function key(context, operation) { return `${context.marker}-${operation}`.slice(0, 128) }
|
||||||
|
export function fixtureInboundCode(policy, marker) {
|
||||||
|
if (policy?.mode === 'AUTO' && policy.manualEntryRequired === false) return {}
|
||||||
|
if (policy?.mode !== 'LEGACY_MANUAL' || policy.manualEntryRequired !== true || !marker) {
|
||||||
|
throw new Error('入仓码策略缺失或不一致,停止创建测试订单')
|
||||||
|
}
|
||||||
|
// Short enough for the 34-character carton QR limit; stable within this fresh fixture.
|
||||||
|
return { inboundCode: `AT${createHash('sha256').update(marker).digest('hex').slice(0, 20).toUpperCase()}` }
|
||||||
|
}
|
||||||
function declarationCargo(source, index) {
|
function declarationCargo(source, index) {
|
||||||
const number = (value) => Number.isFinite(Number(value)) ? Number(value) : 0
|
const number = (value) => Number.isFinite(Number(value)) ? Number(value) : 0
|
||||||
const optionalNumber = (value) => value === null || value === undefined || value === '' ? null : number(value)
|
const optionalNumber = (value) => value === null || value === undefined || value === '' ? null : number(value)
|
||||||
@@ -574,8 +584,11 @@ export async function run(context) {
|
|||||||
privateDestinationAddressId: master.destinationType === 'PRIVATE'
|
privateDestinationAddressId: master.destinationType === 'PRIVATE'
|
||||||
? await ensureCustomerAddress(context, merchantToken, profile, 'PRIVATE_DESTINATION') : null,
|
? await ensureCustomerAddress(context, merchantToken, profile, 'PRIVATE_DESTINATION') : null,
|
||||||
}
|
}
|
||||||
const payload = buildPayload(context, profile, master, productImageFileId, customerAddresses)
|
|
||||||
const createPath = '/api/merchant/v1/orders/first-leg'
|
const createPath = '/api/merchant/v1/orders/first-leg'
|
||||||
|
const policyResponse = await request(context, 'GET', `${createPath}/inbound-code-policy`, undefined, merchantToken)
|
||||||
|
const policy = context.apiSuccess(MODULE, 'Client 读取入仓码录入策略', policyResponse, '', CONTRACT_OPTIONS)
|
||||||
|
const payload = { ...buildPayload(context, profile, master, productImageFileId, customerAddresses),
|
||||||
|
...fixtureInboundCode(policy, context.marker) }
|
||||||
const createResponse = await request(context, 'POST', createPath, payload, merchantToken,
|
const createResponse = await request(context, 'POST', createPath, payload, merchantToken,
|
||||||
{ 'Idempotency-Key': key(context, 'client-create') })
|
{ 'Idempotency-Key': key(context, 'client-create') })
|
||||||
const orderId = id(context.apiSuccess(MODULE, 'Client 创建四箱型隔离订单', createResponse,
|
const orderId = id(context.apiSuccess(MODULE, 'Client 创建四箱型隔离订单', createResponse,
|
||||||
|
|||||||
Reference in New Issue
Block a user