This commit is contained in:
2026-08-17 19:52:04 +08:00
parent d618683467
commit ee4cd35927
42 changed files with 702 additions and 226 deletions
@@ -10,7 +10,7 @@ import { useAuthStore } from '@/core/auth/auth'
import { createPlatformExportTask } from '@/modules/downloads'
import { listPlatformTenants } from '@/modules/iam'
import { showExportTaskCreatedDialog } from '@/shared/components/exportTaskCreatedDialog'
import { getFinanceFeeSource, getReconciliationStatement, listFinanceStatements } from '../api/finance'
import { getReconciliationStatement, listFinanceStatements } from '../api/finance'
import type { FinanceReconciliationDetail, FinanceStatementReadModel } from '../types'
import FinanceCustomerStatementsView from './FinanceCustomerStatementsView.vue'
@@ -19,7 +19,7 @@ vi.mock('@/modules/downloads', () => ({ createPlatformExportTask: vi.fn() }))
vi.mock('@/shared/components/exportTaskCreatedDialog', () => ({ showExportTaskCreatedDialog: vi.fn() }))
vi.mock('../api/finance', () => ({
actionReconciliationStatement: vi.fn(), createReconciliationStatement: vi.fn(),
getFinanceFeeSource: vi.fn(), getReconciliationStatement: vi.fn(), listFinanceStatements: vi.fn(),
getReconciliationStatement: vi.fn(), listFinanceStatements: vi.fn(),
}))
class ResizeObserverStub implements ResizeObserver { observe() {} unobserve() {} disconnect() {} }
@@ -30,14 +30,17 @@ function memoryStorage(): Storage {
const statement: FinanceStatementReadModel = {
id: '501', customerId: '10001', billNo: 'REC-501', customerName: '客户A', billDate: '2026-08-31', dueDate: '',
periodStart: '2026-08-01', periodEnd: '2026-08-31', creditDays: 30, lineCount: 1, sourceCount: 1,
sourceAmount: 320, adjustmentAmount: -20, settled: false, lastReceiptAt: '2026-08-20 10:00:00',
submittedAt: '2026-08-02 09:00:00', reviewedAt: '2026-08-03 09:00:00', issuedAt: '2026-08-04 09:00:00', remark: '八月账单',
totalAmount: 300, receivedAmount: 100, outstandingAmount: 200, currency: 'CNY', status: 'ISSUED', version: 3,
createdBy: '7', createdByName: '创建人A', createdAt: '2026-08-01 09:00:00', updatedBy: '8', updatedByName: '更新人B', updatedAt: '2026-08-20 11:00:00',
}
const detail: FinanceReconciliationDetail = {
...statement, paidAmount: 100, periodStart: '2026-08-01', periodEnd: '2026-08-31', creditDays: 30, settled: false, remark: '八月账单',
createdBy: '7', createdByName: '创建人A', createdAt: '2026-08-01 09:00:00', updatedBy: '8', updatedByName: '更新人B', updatedAt: '2026-08-20 11:00:00',
lines: [{ statementLineId: '601', sourceFeeId: '81', sourceFeeVersion: 2, sourceHash: 'hash-81', orderId: '11', inboundId: '21', containerId: '31', feeItemName: '运费', sourceAmount: 320, amount: 300, adjustmentReason: '优惠调整' }],
paymentHistory: [{ transactionId: '701', transactionType: 'RECEIPT', transactionDate: '2026-08-20', amount: 100, method: 'BANK_TRANSFER', referenceNo: 'PAY-701', createdBy: '9', createdByName: '财务员', occurredAt: '2026-08-20 10:00:00' }],
lines: [{ statementLineId: '601', sourceFeeId: '81', sourceFeeVersion: 2, sourceHash: 'hash-81', direction: 'RECEIVABLE', sourceType: 'CONTAINER_FEE', sourceNo: 'CONT-31', orderId: '11', inboundId: '21', inboundCode: 'IN-21', containerId: '31', containerNo: 'CONT-31', businessDate: '2026-08-15', quantity: 10, unitPrice: 30, feeItemName: '运费', sourceAmount: 320, amount: 300, adjustmentReason: '优惠调整' }],
paymentHistory: [{ transactionId: '701', transactionType: 'RECEIPT', transactionDate: '2026-08-20', amount: 100, method: 'BANK_TRANSFER', referenceNo: 'PAY-701', voucherFileIds: ['9001'], createdBy: '9', createdByName: '财务员', occurredAt: '2026-08-20 10:00:00' }],
revisions: [{ revisionNo: 1, action: 'ADJUST', beforeAmount: 320, afterAmount: 300, reason: '优惠调整', operatorId: '10', operatorName: '调整人', occurredAt: '2026-08-20 09:00:00' }],
}
@@ -71,13 +74,6 @@ describe('FinanceCustomerStatementsView', () => {
vi.mocked(getReconciliationStatement).mockResolvedValue(detail)
vi.mocked(createPlatformExportTask).mockReset().mockResolvedValue({ taskName: '客户对账单', taskNo: 'EXP-STMT-1' } as never)
vi.mocked(showExportTaskCreatedDialog).mockReset().mockResolvedValue(false)
vi.mocked(getFinanceFeeSource).mockResolvedValue({
poolItemId: '81', feeSourceId: '81', customerId: '10001', customerName: '客户A', supplierId: null, supplierName: '',
direction: 'RECEIVABLE', sourceType: 'CONTAINER_FEE', sourceId: 'FEE-81', sourceFeeId: 'FEE-81', sourceVersion: 2,
orderId: '11', inboundId: '21', inboundCode: 'IN-21', containerId: '31', containerNo: 'CONT-31', businessDate: '2026-08-15',
feeItemName: '运费', quantity: 10, unitPrice: 30, amount: 300, currency: 'CNY', reviewStatus: 'APPROVED', settlementIncluded: true,
sourceStatus: 'AVAILABLE', status: 'AVAILABLE', statementGenerated: true, operationVersion: 2, createdAt: '2026-08-15',
})
})
it('opens statement details on a dedicated route instead of below the list', async () => {
@@ -101,7 +97,7 @@ describe('FinanceCustomerStatementsView', () => {
expect(document.querySelector('[aria-label="客户对账单列表"]')).toBeNull()
expect(document.querySelector('[aria-label="所选对账单联动明细"]')).toBeNull()
expect(document.querySelector('[aria-label="对账单摘要"]')?.textContent).toContain('200.00 CNY')
expect(document.querySelectorAll('.statement-summary-grid .statement-summary-item')).toHaveLength(11)
expect(document.querySelectorAll('.statement-summary-grid .statement-summary-item')).toHaveLength(17)
expect(document.querySelector('.statement-detail-head')?.textContent).toContain('REC-501')
expect(document.querySelector('[aria-label="客户对账单账单明细"]')).toBeTruthy()
expect(document.querySelector('.detail-table-scroll [aria-label="客户对账单账单明细"]')).toBeTruthy()
@@ -216,12 +212,12 @@ describe('FinanceCustomerStatementsView', () => {
expect(listPlatformTenants).not.toHaveBeenCalled()
})
it('uses statement list permission for fee-source details without exposing technical trace fields', async () => {
it('uses statement detail snapshots without a second fee-source request or technical trace fields', async () => {
const { wrapper } = await mountPage(['platform:finance:customer-statement:list'])
await (wrapper.vm as unknown as { openDetail(row: FinanceStatementReadModel): Promise<void> }).openDetail(statement)
await flushPromises()
expect(getFinanceFeeSource).toHaveBeenCalledWith('81')
expect(document.body.textContent).toContain('CONT-31')
expect(document.body.textContent).toContain('订单 11')
expect(document.body.textContent).not.toContain('hash-81')
})