import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { describe, expect, it } from 'vitest' function source(path: string) { return readFileSync(resolve(process.cwd(), path), 'utf8') } describe('finance six-page delivery contract', () => { const routes = source('src/modules/finance/routes.ts') const navigation = source('src/core/navigation/adminNavigation.ts') const api = source('src/modules/finance/api/finance.ts') const pages = [ ['finance/customer-accounts', '客户账户'], ['finance/customer-arap', '客户应收应付'], ['finance/receivable-statistics', '应收款统计表'], ['finance/customer-statements', '客户对账单'], ['finance/settlement-receivables', '结算单应收'], ['finance/settlement-payables', '结算单应付'], ] as const it('registers the six menu routes plus hidden detail routes', () => { for (const [path, title] of pages) { expect(routes).toContain(`path: '${path}'`) expect(routes).toContain(`title: '${title}'`) expect(navigation).toContain(`path: '/${path}'`) expect(navigation).toContain(`title: '${title}'`) } expect(navigation.match(/path: '\/finance\//g)).toHaveLength(6) expect(routes.match(/path: 'finance\/customer-accounts\/:customerId'/g)).toHaveLength(1) expect(routes.match(/path: 'finance\/customer-arap\/:feeSourceId'/g)).toHaveLength(1) expect(navigation).not.toContain('/finance/customer-accounts/:customerId') expect(navigation).not.toContain('/finance/customer-arap/:feeSourceId') }) it('does not expose the old three routes or out-of-scope reports', () => { for (const forbidden of ['/finance/bills', '/finance/receipts', '/finance/costs', '费用分析', '利润表']) { expect(routes).not.toContain(forbidden) expect(navigation).not.toContain(forbidden) } }) it('keeps production reads on fixed DTO endpoints only', () => { for (const endpoint of ['customer-accounts', 'fee-pool', 'receivable-statistics', 'statements', 'receivable-settlements', 'payable-settlements']) { expect(api).toContain(`${basePathMarker(endpoint)}`) } expect(api).not.toContain('function listFinanceBills') expect(api).not.toContain('function listFinanceReceipts') expect(api).not.toContain('function listFinanceCosts') }) it('connects G1 customer accounts to the formal list and ledger operations', () => { const page = source('src/modules/finance/pages/FinanceCustomerAccountsView.vue') const types = source('src/modules/finance/types.ts') expect(api).toContain('`${basePath}/accounts`') expect(api).toContain('`${basePath}/accounts/${customerId}/ledger`') expect(page).toContain('listFinanceAccounts') expect(page).toContain('listFinanceAccountLedger') expect(page).not.toContain('getFinanceCustomerAccount') expect(page).not.toContain('接口尚未提供') expect(page).toContain("key: 'customerId', type: 'select', label: '客户名称'") expect(page).toContain('options: customers.value.filter') expect(page).toContain('label: item.tenantName') expect(page).not.toContain('tenantCode') expect(types).toContain('export interface FinanceOperatingFundsSummary') expect(types).toContain('export interface FinanceAccountSummary extends FinanceOperatingFundsSummary') expect(api).toContain('const records: FinanceAccountSummary[]') for (const metric of ['待收客户款', '待付供应商款', '已线下支付供应商款']) expect(page).toContain(metric) for (const forbidden of ['客户线下支付', '已收客户款', '已付成本']) expect(page).not.toContain(forbidden) const columns = page.slice(page.indexOf('const columns: DataTableColumn[]')) expect(columns.indexOf("key: 'actions'")).toBeLessThan(columns.indexOf("key: 'customerName'")) for (const state of ['客户账户加载失败', '暂无客户账户', '无权访问客户账户', '账户流水加载失败']) expect(page).toContain(state) }) it('connects fee sources to the real edit and review lifecycle', () => { const page = source('src/modules/finance/pages/FinanceCustomerArapView.vue') for (const marker of [ '`${basePath}/fee-sources/${feeSourceId}`', '`${basePath}/fee-sources/${feeSourceId}/review`', '`${basePath}/fee-sources/${feeSourceId}/submit`', '`${basePath}/fee-sources/${feeSourceId}/adjust`', '`${basePath}/fee-sources/${feeSourceId}/void`', ]) expect(api).toContain(marker) for (const operation of ['getFinanceFeeSource', 'reviewFinanceFeeSource', 'editFinanceFeeSource', 'submitFinanceFeeSource', 'adjustFinanceFeeSource', 'voidFinanceFeeSource']) expect(page).toContain(operation) for (const permission of ['platform:finance:customer-arap:list', 'platform:finance:fee-source:review', 'platform:finance:fee-source:edit']) expect(page).toContain(permission) expect(page).toContain('expectedVersion: detail.value.operationVersion') const columns = page.slice(page.indexOf('const columns:')) expect(columns.indexOf("key: 'actions'")).toBeLessThan(columns.indexOf("key: 'direction'")) expect(page).toContain('') expect(page).not.toContain('