51 lines
3.3 KiB
TypeScript
51 lines
3.3 KiB
TypeScript
import {it,expect,beforeEach,afterEach} from 'vitest'
|
|
import ExcelJS from 'exceljs'
|
|
import {mkdtemp,rm} from 'node:fs/promises'
|
|
import {tmpdir} from 'node:os'
|
|
import path from 'node:path'
|
|
import {XlsxReader,createWorkbookTemplate} from '../src/main/workbooks'
|
|
import {Ledger} from '../src/main/ledger'
|
|
import {defaultSettings} from '../src/shared/settings'
|
|
let dir:string
|
|
const headers=['收款日期','学校','年级','姓名','收费项目','金额','出纳','复核']
|
|
beforeEach(async()=>{dir=await mkdtemp(path.join(tmpdir(),'receipt-fields-'))})
|
|
afterEach(async()=>{await rm(dir,{recursive:true,force:true})})
|
|
async function workbook(row:unknown[],columns=headers){
|
|
const file=path.join(dir,'data.xlsx'),book=new ExcelJS.Workbook(),sheet=book.addWorksheet('收据数据')
|
|
sheet.addRow(columns);sheet.addRow(row);await book.xlsx.writeFile(file);return file
|
|
}
|
|
it('下载模板包含学校、年级、姓名,金额列和筛选范围随之调整',async()=>{
|
|
const file=path.join(dir,'template.xlsx');await createWorkbookTemplate(file)
|
|
const book=new ExcelJS.Workbook();await book.xlsx.readFile(file);const sheet=book.worksheets[0]
|
|
expect(sheet.getRow(1).values).toEqual([undefined,...headers])
|
|
expect(sheet.getColumn(6).numFmt).toBe('0.00');expect(sheet.autoFilter).toBe('A1:H1')
|
|
const draft=await new XlsxReader().read(file)
|
|
expect(draft.rows[0].errors).toEqual([])
|
|
expect(draft.rows[0].receipt.customer).toBe('某某学校 初二年级 张三')
|
|
})
|
|
it('三列去除首尾空白后,用单个空格拼接,并保留原字段用于扩展',async()=>{
|
|
const file=await workbook(['2026-10-16',' 巴南中学 ',' 高2028届 ',' 张三 ','服务费',3500])
|
|
const draft=await new XlsxReader().read(file),receipt=draft.rows[0].receipt
|
|
expect(receipt.customer).toBe('巴南中学 高2028届 张三')
|
|
expect(receipt).toMatchObject({school:'巴南中学',grade:'高2028届',studentName:'张三'})
|
|
expect(draft.rows[0].errors).toEqual([])
|
|
const store=new Ledger(path.join(dir,'db.sqlite'));await store.open()
|
|
const batch=await store.reserve({name:'data.xlsx',hash:'hash'},[receipt],defaultSettings(),null)
|
|
expect(store.get(batch.id).receipts[0]).toMatchObject({school:'巴南中学',grade:'高2028届',studentName:'张三',customer:'巴南中学 高2028届 张三'})
|
|
})
|
|
it.each([[1,'学校'],[2,'年级'],[3,'姓名']] as const)('%s 列缺失时,定位具体必填字段',async(index,label)=>{
|
|
const row:unknown[]=['2026-10-16','学校','年级','张三','服务费',3500];row[index]=' '
|
|
const draft=await new XlsxReader().read(await workbook(row))
|
|
expect(draft.rows[0].errors).toContain(label+'不能为空')
|
|
})
|
|
it('缺少拆分后的表头时提示重新下载模板',async()=>{
|
|
const file=await workbook(['2026-10-16','学校 年级 张三','服务费',3500],['收款日期','客户名称','收费项目','金额'])
|
|
await expect(new XlsxReader().read(file)).rejects.toThrow('第一行缺少表头:学校、年级、姓名')
|
|
})
|
|
it('按表头识别三列,而非依赖固定列序',async()=>{
|
|
const file=await workbook(['张三',3500,'高2028届','2026-10-16','服务费','学校'],['姓名','金额','年级','收款日期','收费项目','学校'])
|
|
const draft=await new XlsxReader().read(file)
|
|
expect(draft.rows[0].receipt.customer).toBe('学校 高2028届 张三')
|
|
expect(draft.rows[0].errors).toEqual([])
|
|
})
|