import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' import test from 'node:test' const read = (path: URL) => readFile(path, 'utf8') test('销售事实重算必须冻结已关账期间', async () => { const source = await read(new URL('./sales-facts-service.ts', import.meta.url)) assert.ok(source.includes('finance_periods'), '重算必须读取会计期间') assert.ok(source.includes("p.status = 'closed'"), '必须识别已关账期间') assert.ok(source.includes('skippedClosedPeriods'), '必须返回被跳过的关账期间') }) test('人工确认/退款不得静默改已关账期间', async () => { const [manual, refund] = await Promise.all([ read(new URL('./manual-fulfillment-service.ts', import.meta.url)), read(new URL('./order-refund-service.ts', import.meta.url)), ]) assert.ok(manual.includes('manual_fulfillment_period_closed')) assert.ok(refund.includes('order_refund_period_closed')) }) test('总账同步必须追加调整凭证,不能删除重建', async () => { const source = await read(new URL('./finance-ledger-service.ts', import.meta.url)) assert.ok(!source.includes('DELETE FROM finance_journal_entries'), '已过账凭证不得删除重建') assert.ok(source.includes('sales_revenue_adjustment'), '收入变化必须走调整凭证') assert.ok(source.includes('sales_cost_adjustment'), '成本变化必须走调整凭证') assert.ok(source.includes('finance_sales_sync:'), '按日同步必须加 advisory lock') }) test('关账必须具备门槛、期间锁和重复关账保护', async () => { const source = await read(new URL('./finance-ledger-service.ts', import.meta.url)) assert.ok(source.includes('assertPeriodCloseable'), '关账必须校验门槛') assert.ok(source.includes('finance_period_close_blocked'), '关账失败必须给出明确错误码') assert.ok(source.includes('finance_period_already_closed'), '重复关账必须拒绝') assert.ok(source.includes('finance_period:'), '凭证写入与关账必须共用期间锁') assert.ok( source.includes('manual_cost_missing') || source.includes('未确认成本'), '必须拦人工缺成本', ) }) test('平台退款必须先校验可退金额并落退款意图', async () => { const source = await read(new URL('./order-refund-service.ts', import.meta.url)) const platformStart = source.indexOf('export async function approveAndRecordKuaishouRefund') const platformEnd = source.indexOf('type PlatformRefundIntentRow', platformStart) const body = source.slice(platformStart, platformEnd) assert.ok( body.indexOf('getRefundableFen') < body.indexOf('approveKuaishouIndustryRefund'), '可退金额校验必须发生在平台调用之前', ) assert.ok(body.includes('beginPlatformRefundIntent'), '必须先落退款意图') assert.ok(source.includes('finance_refund_intents'), '必须有平台退款状态机') assert.ok(source.includes('order_refund_external_ref_exists'), '外部退款单号必须幂等') assert.ok(source.includes('nextPayStatus'), '全额退款撤销必须恢复订单支付状态') assert.ok(source.includes('订单已退款,成本异常自动关闭'), '撤销必须重新打开成本异常') }) test('备用金对账确认必须按当前余额重算差额', async () => { const source = await read(new URL('../admin/admin-fund-service.ts', import.meta.url)) const start = source.indexOf('export async function confirmAdminFundReconciliation') const end = source.indexOf('export async function getAdminFundSupervisorOptions', start) const body = source.slice(start, end) assert.ok(body.includes('actualBalanceFen - currentBalanceFen'), '必须用确认时点余额重算') assert.ok(body.includes('system_balance_fen = $5'), '必须回写确认时点的系统余额') assert.ok(body.includes('difference_fen = $6'), '必须回写确认时点的差额') }) test('迁移 104 提供退款/支出幂等与凭证完整性约束', async () => { const migration = await read( new URL('../../db/migrations/104_finance_controls.sql', import.meta.url), ) assert.ok(migration.includes('uq_order_refunds_source_external_ref')) assert.ok(migration.includes('uq_manual_expenses_order_item')) assert.ok(migration.includes('finance_refund_intents')) assert.ok(migration.includes('trg_finance_journal_balanced')) assert.ok(migration.includes('trg_finance_journal_immutable')) assert.ok(migration.includes('trg_fund_entries_balance')) assert.ok(migration.includes('trg_fund_accounts_balance')) assert.ok(migration.includes("'finance.post'")) assert.ok(migration.includes("'finance.close'")) assert.ok(migration.includes("'finance.reconcile'")) }) test('财务写路由使用拆分后的权限,人工履约包含 finance', async () => { const [ledgerRoute, financeRoute, orderRoute] = await Promise.all([ read(new URL('../../routes/admin/finance-ledger.ts', import.meta.url)), read(new URL('../../routes/admin/finance.ts', import.meta.url)), read(new URL('../../routes/admin/orders.ts', import.meta.url)), ]) assert.ok(ledgerRoute.includes("requireAdminPermission('finance.post')")) assert.ok(ledgerRoute.includes("requireAdminPermission('finance.close')")) assert.ok(ledgerRoute.includes("requireAdminPermission('finance.reconcile')")) assert.ok( financeRoute.includes("requireAdminRoles(['admin', 'operator', 'support', 'finance'])"), '文档承诺财务可代录,路由必须允许 finance', ) assert.ok(orderRoute.includes("requireAdminPermission('finance.post')")) }) test('P1:资金/积分写命令支持 requestId 幂等', async () => { const [fund, credit, migration] = await Promise.all([ read(new URL('../admin/admin-fund-service.ts', import.meta.url)), read(new URL('../cost-center/platform-credit-service.ts', import.meta.url)), read(new URL('../../db/migrations/104_finance_controls.sql', import.meta.url)), ]) assert.ok(fund.includes('requestId') && fund.includes('fund_request_duplicate')) assert.ok(credit.includes('platform_credit_request_duplicate')) assert.ok(migration.includes('uq_fund_entries_account_request')) assert.ok(migration.includes('uq_platform_credit_entries_account_request')) }) test('P1:成本版本追溯改价退休旧版本而不是覆盖金额', async () => { const [product, affiliate] = await Promise.all([ read(new URL('../cost-center/product-catalog-service.ts', import.meta.url)), read(new URL('../cost-center/affiliate-product-service.ts', import.meta.url)), ]) assert.ok(product.includes('新增一个从 targetTime 起生效的版本')) assert.ok(product.includes("status = 'retired'")) assert.ok(affiliate.includes('新增追溯版本')) assert.ok(affiliate.includes("status = 'retired'")) }) test('P1:平台对账支持订单项/平台明细维度', async () => { const [service, migration] = await Promise.all([ read(new URL('./finance-reconciliation-service.ts', import.meta.url)), read(new URL('../../db/migrations/104_finance_controls.sql', import.meta.url)), ]) assert.ok(service.includes('orderItemId') && service.includes('platformItemId')) assert.ok(service.includes('order_item_id')) assert.ok(migration.includes('platform_item_id')) assert.ok(migration.includes('order_item_id')) }) test('L1:钱包金额 BIGINT、非负约束与奖励流水幂等', async () => { const migration = await read( new URL('../../db/migrations/104_finance_controls.sql', import.meta.url), ) assert.ok(migration.includes('ALTER COLUMN total_amount TYPE BIGINT')) assert.ok(migration.includes('ALTER COLUMN available_amount TYPE BIGINT')) assert.ok(migration.includes('chk_worker_wallets_nonnegative')) assert.ok(migration.includes('chk_worker_wallet_ledgers_nonnegative_after')) assert.ok(migration.includes('worker_wallet_ledger_event_key')) assert.ok(migration.includes('uq_worker_wallet_ledger_event_key')) assert.ok(migration.includes('v_worker_wallet_duplicate_rewards')) assert.ok(migration.includes("NOT (NEW.payload_json ? 'inventoryId')")) assert.ok(migration.includes('GROUP BY worker_id, related_work_order_id')) }) test('销售毛利必须同时暴露缺失成本收入,避免只看毛利绝对值', async () => { const source = await read(new URL('./sales-facts-service.ts', import.meta.url)) assert.ok(source.includes('cost_missing_revenue_fen')) assert.ok(source.includes('costMissingRevenueFen')) })