优化
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
import ElementPlus from 'element-plus'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils'
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { useAuthStore } from '@/core/auth/auth'
|
||||
import { listPlatformTenants, type PlatformTenantResource } from '@/modules/iam'
|
||||
import {
|
||||
actionReconciliationStatement,
|
||||
createFinanceReceipt,
|
||||
getFinanceSettlement,
|
||||
getReconciliationStatement,
|
||||
listFinancePayableSettlements,
|
||||
listFinanceReceivableSettlements,
|
||||
uploadFinanceVoucher,
|
||||
} from '../api/finance'
|
||||
import type { FinanceReconciliationDetail, FinanceSettlementDetail, FinanceStatementReadModel } from '../types'
|
||||
import FinanceCustomerStatementsView from './FinanceCustomerStatementsView.vue'
|
||||
import FinanceFormalSettlementPage from './FinanceFormalSettlementPage.vue'
|
||||
|
||||
vi.mock('@/modules/iam', () => ({ listPlatformTenants: vi.fn() }))
|
||||
vi.mock('../api/finance', () => ({
|
||||
actionReconciliationStatement: vi.fn(), createFinanceReceipt: vi.fn(), createFinanceSettlementPayment: vi.fn(),
|
||||
createPayableSettlement: vi.fn(), createReceivableSettlement: vi.fn(), createReconciliationStatement: vi.fn(),
|
||||
getFinanceSettlement: vi.fn(), getReconciliationStatement: vi.fn(), listFinanceFeePool: vi.fn(),
|
||||
listFinancePayableSettlements: vi.fn(), listFinanceReceivableSettlements: vi.fn(), listFinanceStatements: vi.fn(),
|
||||
uploadFinanceVoucher: vi.fn(),
|
||||
}))
|
||||
|
||||
class ResizeObserverStub implements ResizeObserver {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
disconnect() {}
|
||||
}
|
||||
|
||||
function createMemoryStorage(): Storage {
|
||||
const values = new Map<string, string>()
|
||||
return {
|
||||
get length() { return values.size }, clear: () => values.clear(), getItem: (key) => values.get(key) ?? null,
|
||||
key: (index) => [...values.keys()][index] ?? null, removeItem: (key) => values.delete(key), setItem: (key, value) => values.set(key, value),
|
||||
}
|
||||
}
|
||||
|
||||
function piniaWithPermissions(permissions: string[]) {
|
||||
const pinia = createPinia()
|
||||
setActivePinia(pinia)
|
||||
const auth = useAuthStore()
|
||||
auth.token = 'token'
|
||||
auth.permissions = permissions
|
||||
useAccessPreviewStore().initializeAfterLogin()
|
||||
return pinia
|
||||
}
|
||||
|
||||
const statement: FinanceStatementReadModel = {
|
||||
id: '501', customerId: '10001', billNo: 'REC-501', customerName: '客户A', billDate: '2026-08-31',
|
||||
dueDate: '2026-09-30', totalAmount: 300, receivedAmount: 0, outstandingAmount: 300,
|
||||
currency: 'CNY', status: 'ISSUED', version: 3,
|
||||
}
|
||||
|
||||
const reconciliation: FinanceReconciliationDetail = {
|
||||
...statement, paidAmount: 0, periodStart: '2026-08-01', periodEnd: '2026-08-31', creditDays: 30, settled: false,
|
||||
remark: '', lines: [
|
||||
{ statementLineId: '601', sourceFeeId: '41', sourceFeeVersion: 1, orderId: null, inboundId: '91', feeItemName: '运费', amount: 100 },
|
||||
{ statementLineId: '602', sourceFeeId: '42', sourceFeeVersion: 1, orderId: null, inboundId: '92', feeItemName: '操作费', amount: 200 },
|
||||
], paymentHistory: [], revisions: [],
|
||||
}
|
||||
|
||||
const receivable: FinanceSettlementDetail = {
|
||||
id: '701', settlementNo: 'AR-701', customerId: '10001', reconciliationStatementId: '501', direction: 'RECEIVABLE',
|
||||
amount: 300, paidAmount: 0, outstandingAmount: 300, currency: 'CNY', status: 'ISSUED', version: 0,
|
||||
lines: [], transactions: [], revisions: [],
|
||||
}
|
||||
|
||||
enableAutoUnmount(afterEach)
|
||||
afterAll(() => vi.unstubAllGlobals())
|
||||
|
||||
describe('finance G3/G4 page operations', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('ResizeObserver', ResizeObserverStub)
|
||||
vi.stubGlobal('localStorage', createMemoryStorage())
|
||||
vi.stubGlobal('sessionStorage', createMemoryStorage())
|
||||
document.body.innerHTML = ''
|
||||
const customer = { id: '10001', tenantName: '客户A', status: 'ACTIVE' } as PlatformTenantResource
|
||||
vi.mocked(listPlatformTenants).mockReset().mockResolvedValue({ records: [customer], page: 1, size: 200, total: 1, pages: 1 })
|
||||
vi.mocked(actionReconciliationStatement).mockReset().mockResolvedValue(reconciliation)
|
||||
vi.mocked(getReconciliationStatement).mockReset().mockResolvedValue(reconciliation)
|
||||
vi.mocked(getFinanceSettlement).mockReset().mockResolvedValue(receivable)
|
||||
vi.mocked(listFinanceReceivableSettlements).mockReset().mockResolvedValue([])
|
||||
vi.mocked(listFinancePayableSettlements).mockReset().mockResolvedValue([])
|
||||
vi.mocked(uploadFinanceVoucher).mockReset().mockResolvedValue({ fileId: '9001', customerId: '10001', fileName: 'receipt.png', contentType: 'image/png', sizeBytes: 100 })
|
||||
vi.mocked(createFinanceReceipt).mockReset().mockResolvedValue({ id: '801', customerId: '10001', customerName: '客户A', receivedDate: '2026-08-11', amount: 300, currency: 'CNY', paymentMethod: 'BANK_TRANSFER', voucherFileIds: ['9001'], allocationCount: 1 })
|
||||
})
|
||||
|
||||
it('loads frozen G3 detail and submits multiple selected adjustment lines', async () => {
|
||||
const pinia = piniaWithPermissions(['platform:finance:bill:view', 'platform:finance:reconciliation:adjust'])
|
||||
const wrapper = mount(FinanceCustomerStatementsView, { attachTo: document.body, global: { plugins: [pinia, ElementPlus] } })
|
||||
await flushPromises()
|
||||
const vm = wrapper.vm as unknown as {
|
||||
openAdjustment(row: FinanceStatementReadModel): Promise<void>
|
||||
submitAdjustment(): Promise<void>
|
||||
adjustReason: string
|
||||
adjustLines: Array<{ selected: boolean; adjustedAmount: number; reason: string }>
|
||||
}
|
||||
|
||||
await vm.openAdjustment(statement)
|
||||
vm.adjustReason = '账期复核调整'
|
||||
vm.adjustLines[0]!.selected = true; vm.adjustLines[0]!.adjustedAmount = 90; vm.adjustLines[0]!.reason = '运费更正'
|
||||
vm.adjustLines[1]!.selected = true; vm.adjustLines[1]!.adjustedAmount = 180; vm.adjustLines[1]!.reason = '操作费更正'
|
||||
await vm.submitAdjustment()
|
||||
|
||||
expect(getReconciliationStatement).toHaveBeenCalledWith('501')
|
||||
expect(actionReconciliationStatement).toHaveBeenCalledWith('501', {
|
||||
action: 'ADJUST', reason: '账期复核调整', expectedVersion: 3,
|
||||
adjustmentLines: [
|
||||
{ statementLineId: '601', adjustedAmount: 90, reason: '运费更正' },
|
||||
{ statementLineId: '602', adjustedAmount: 180, reason: '操作费更正' },
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
it('loads AR linkage, uploads a voucher and allocates a real receipt to its statement', async () => {
|
||||
const pinia = piniaWithPermissions(['platform:finance:settlement-ar:view', 'platform:finance:receipt:create'])
|
||||
const wrapper = mount(FinanceFormalSettlementPage, { props: { kind: 'receivable' }, attachTo: document.body, global: { plugins: [pinia, ElementPlus] } })
|
||||
await flushPromises()
|
||||
const vm = wrapper.vm as unknown as {
|
||||
openReceipt(row: Record<string, unknown>): Promise<void>
|
||||
submitReceipt(): Promise<void>
|
||||
receiptFile: File | null
|
||||
receiptForm: { receivedDate: string; amount: number; paymentMethod: 'BANK_TRANSFER'; remark: string }
|
||||
}
|
||||
|
||||
await vm.openReceipt({ id: '701' })
|
||||
vm.receiptFile = new File(['receipt'], 'receipt.png', { type: 'image/png' })
|
||||
vm.receiptForm.receivedDate = '2026-08-11'; vm.receiptForm.amount = 300; vm.receiptForm.remark = '全额到账'
|
||||
await vm.submitReceipt()
|
||||
|
||||
expect(uploadFinanceVoucher).toHaveBeenCalledWith('10001', vm.receiptFile)
|
||||
expect(createFinanceReceipt).toHaveBeenCalledWith({
|
||||
customerId: '10001', receivedDate: '2026-08-11', amount: 300, paymentMethod: 'BANK_TRANSFER', remark: '全额到账',
|
||||
allocations: [{ billId: '501', amount: 300 }],
|
||||
}, ['9001'])
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user