import assert from 'node:assert/strict'; import { randomUUID } from 'node:crypto'; import type { AddressInfo } from 'node:net'; import { Pool } from 'pg'; import type { Database } from '@atlas/database'; import type { NestExpressApplication } from '@nestjs/platform-express'; import { afterAll, beforeAll, describe, it } from 'vitest'; import { DATABASE } from '../src/database/database.module.js'; import { createApplication } from '../src/main.js'; let app: NestExpressApplication; let db: Database; let migrator: Pool; let base = '', token = '', user = '', workspace = '', card = '', platform = ''; const request = async ( path: string, method = 'GET', body?: unknown, key?: string, ) => { const response = await fetch(`${base}/api${path}`, { method, headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}), ...(key ? { 'Idempotency-Key': key } : {}), }, body: body === undefined ? undefined : JSON.stringify(body), }); return { status: response.status, body: (await response.json()) as any }; }; describe('系统物流费率审核', () => { beforeAll(async () => { Object.assign(process.env, { NODE_ENV: 'test', SWAGGER_ENABLED: 'false', AUTH_REGISTER_IP_LIMIT: '100', AUTH_REGISTER_EMAIL_LIMIT: '100', }); app = (await createApplication()).app; db = app.get(DATABASE); migrator = new Pool({ connectionString: process.env.MIGRATOR_DATABASE_URL, max: 1, }); await app.listen(0, '127.0.0.1'); base = `http://127.0.0.1:${(app.getHttpServer().address() as AddressInfo).port}`; const registered = await request('/auth/register', 'POST', { email: `pricing-review-${randomUUID()}@example.test`, password: 'pricing-review-test-password-123', password_confirmation: 'pricing-review-test-password-123', }); assert.equal(registered.status, 201, JSON.stringify(registered.body)); token = registered.body.data.access_token; user = registered.body.data.user.id; workspace = registered.body.data.workspace.id; const scope = await db.query<{ platform_id: string; provider_id: string; }>( `SELECT platform.id AS platform_id,provider.id AS provider_id FROM atlas.platforms platform CROSS JOIN atlas.logistics_providers provider WHERE upper(platform.code::text)='OZON' AND upper(provider.code::text)='CEL' LIMIT 1`, ); platform = scope.rows[0].platform_id; const provider = scope.rows[0].provider_id; card = ( await db.query<{ id: string }>( `INSERT INTO atlas.logistics_rate_cards(provider_id,platform_id,fulfillment,market_code,version,source_name,status,effective_from) VALUES($1,$2,'rfbs','RU',$3,'自动化审核测试,未来生效','draft',now()) RETURNING id`, [provider, platform, `qa-${randomUUID()}`], ) ).rows[0].id; const methods: string[] = []; for (const code of ['express', 'standard', 'economy']) { methods.push( ( await db.query<{ id: string }>( `INSERT INTO atlas.logistics_transport_methods(rate_card_id,code,name) VALUES($1,$2::text,$2::text) RETURNING id`, [card, code], ) ).rows[0].id, ); } for (const [index, code] of [ 'ExtraSmall', 'Budget', 'Small', 'Big', 'PremiumSmall', 'PremiumBig', ].entries()) { const type = ( await db.query<{ id: string }>( `INSERT INTO atlas.logistics_product_types(rate_card_id,code,name,merchandise_currency_code,min_merchandise_value,max_merchandise_value,min_actual_weight_kg,max_actual_weight_kg,billing_basis) VALUES($1,$2::text,$2::text,'CNY',0,10000,0.001,30,'actual_only') RETURNING id`, [card, code], ) ).rows[0].id; for (const method of methods.slice(0, [3, 3, 3, 2, 3, 2][index])) await db.query( `INSERT INTO atlas.logistics_rate_rules(product_type_id,transport_method_id,fixed_fee_cny,per_billable_kg_fee_cny,status) VALUES($1,$2,3.12,10,'draft')`, [type, method], ); } }); afterAll(async () => { if (migrator) { if (card) await migrator.query( `DELETE FROM atlas.logistics_rate_card_reviews WHERE rate_card_id=$1`, [card], ); if (user) await migrator.query( `DELETE FROM atlas.system_admin_grants WHERE user_id=$1`, [user], ); } if (db) { if (card) await db.query( `DELETE FROM atlas.logistics_rate_cards WHERE id=$1`, [card], ); if (user) { await db.query( `DELETE FROM atlas.workspace_memberships WHERE user_id=$1`, [user], ); await db.query(`DELETE FROM atlas.workspaces WHERE id=$1`, [ workspace, ]); await db.query(`DELETE FROM atlas.users WHERE id=$1`, [user]); } } if (migrator) await migrator.end(); if (app) await app.close(); }); it('仅系统管理员可读取和启用;六类账单复算、重放与过期版本保护', async () => { assert.equal( ( await request( `/system/pricing/rate-cards?platform_id=${platform}`, ) ).status, 403, ); await migrator.query( `INSERT INTO atlas.system_admin_grants(user_id) VALUES($1)`, [user], ); const listed = await request( `/system/pricing/rate-cards?platform_id=${platform}`, ); assert.equal(listed.status, 200, JSON.stringify(listed.body)); const item = listed.body.data.find((row: any) => row.id === card); assert.equal(item.status, 'draft'); assert.equal(item.types.length, 6); assert.equal(item.rules.length, 16); const input = { rules_hash: item.rules_hash, source_reference: 'CEL 真实账单 QA 批次-2026-09', review_note: '逐类型核对实际包装、货值、计费重量与物流账单费用;本测试版本仅在未来生效。', effective_from: new Date(Date.now() + 86400000).toISOString(), samples: item.types.map((type: any, index: number) => ({ rule_id: item.rules.find( (rule: any) => rule.product_type_id === type.id, ).id, invoice_reference: `QA-INVOICE-${index + 1}`, merchandise_value_cny: '100', shipping_weight_g: '1000', length_mm: '100', width_mm: '100', height_mm: '100', billed_logistics_cny: '13.12', })), }; const key = randomUUID(); const mismatch = structuredClone(input); mismatch.samples[0].billed_logistics_cny = '12.00'; const rejected = await request( `/system/pricing/rate-cards/${card}/reviews`, 'POST', mismatch, randomUUID(), ); assert.equal(rejected.status, 422, JSON.stringify(rejected.body)); const repeatedInvoice = structuredClone(input); repeatedInvoice.samples[1].invoice_reference = repeatedInvoice.samples[0].invoice_reference; assert.equal( ( await request( `/system/pricing/rate-cards/${card}/reviews`, 'POST', repeatedInvoice, randomUUID(), ) ).status, 422, ); assert.equal( (await request(`/system/pricing/rate-cards/${card}`)).body.data .status, 'draft', ); const [accepted, concurrentReplay] = await Promise.all([ request( `/system/pricing/rate-cards/${card}/reviews`, 'POST', input, key, ), request( `/system/pricing/rate-cards/${card}/reviews`, 'POST', input, key, ), ]); assert.equal(accepted.status, 201, JSON.stringify(accepted.body)); assert.equal( concurrentReplay.status, 201, JSON.stringify(concurrentReplay.body), ); assert.equal(accepted.body.data.status, 'active'); assert.equal(accepted.body.data.review.samples.length, 6); const replay = await request( `/system/pricing/rate-cards/${card}/reviews`, 'POST', input, key, ); assert.equal(replay.status, 201, JSON.stringify(replay.body)); assert.equal( ( await request( `/system/pricing/rate-cards/${card}/reviews`, 'POST', mismatch, key, ) ).status, 409, ); assert.equal( ( await request( `/system/pricing/rate-cards/${card}/reviews`, 'POST', input, randomUUID(), ) ).status, 409, ); const activeRuleCount = await db.query<{ count: string }>( `SELECT count(*) FROM atlas.logistics_rate_rules r JOIN atlas.logistics_product_types t ON t.id=r.product_type_id WHERE t.rate_card_id=$1 AND r.status='active'`, [card], ); assert.equal(Number(activeRuleCount.rows[0].count), 16); await assert.rejects(() => db.query( `UPDATE atlas.logistics_rate_rules SET fixed_fee_cny=4 WHERE id=$1`, [item.rules[0].id], ), ); await assert.rejects(() => db.query( `UPDATE atlas.logistics_rate_cards SET source_name='错误改写' WHERE id=$1`, [card], ), ); const draftCard = await db.query<{ id: string }>( `SELECT id FROM atlas.logistics_rate_cards WHERE version='cel-rfbs-review-2026-09' LIMIT 1`, ); await assert.rejects(() => db.query( `UPDATE atlas.logistics_product_types SET rate_card_id=$1 WHERE id=$2`, [draftCard.rows[0].id, item.types[0].id], ), ); }); });