Files
ReceiptGenerator/tests/history-search.test.ts

65 lines
5.3 KiB
TypeScript

import {it,expect} from 'vitest'
import {mkdtemp,rm} from 'node:fs/promises'
import {tmpdir} from 'node:os'
import path from 'node:path'
import {Ledger} from '../src/main/ledger'
import {defaultSettings} from '../src/shared/settings'
function input(school:string|undefined,grade:string|undefined,studentName:string,item:string){return {date:'2026-10-19',school,grade,studentName,customer:[school,grade,studentName].filter(Boolean).join(' '),item,amountCents:100,cashier:'',reviewer:''}}
it('按同一张收据组合筛选,支持姓名和中间编号,并返回可直接预览的匹配信息',async()=>{
const dir=await mkdtemp(path.join(tmpdir(),'receipt-search-'))
try{
const ledger=new Ledger(path.join(dir,'db.sqlite'));await ledger.open()
const batch=await ledger.reserve({name:'收据模板.xlsx',hash:'a'},[input('甲学校','高一','张三','服务费'),input('乙学校','高二','李四','资料费'),input('甲学校','高一','王五','服务费')],defaultSettings(dir),null)
expect(ledger.summaries({school:'甲学校',grade:'高二',item:'资料费'})).toEqual([])
expect(ledger.summaries({search:'李四',school:'甲学校'})).toEqual([])
expect(ledger.summaries({search:' sj00000002 ',school:'乙学校',grade:'高二',item:'资料费'})[0]).toMatchObject({id:batch.id,count:3,match:{count:1,number:'SJ00000002',customer:'乙学校 高二 李四'}})
expect(ledger.summaries({search:'王五'})[0].match?.number).toBe('SJ00000003')
expect(ledger.summaries({school:'甲学校'})[0].match?.count).toBe(2)
expect(ledger.summaries({search:'收据模板.xlsx'})).toHaveLength(1)
expect(ledger.summaries()[0].groups).toEqual([{school:'甲学校',grade:'高一',item:'服务费',count:2,totalCents:200},{school:'乙学校',grade:'高二',item:'资料费',count:1,totalCents:100}])
expect(ledger.nextNumber('SJ')).toBe('SJ00000004')
}finally{await rm(dir,{recursive:true,force:true})}
})
it('查找和下拉选项覆盖超过最近 200 批的旧记录,旧数据缺失学校年级也能查找',async()=>{
const dir=await mkdtemp(path.join(tmpdir(),'receipt-old-search-'))
try{
const ledger=new Ledger(path.join(dir,'db.sqlite'));await ledger.open()
const oldest=await ledger.reserve({name:'旧记录.xlsx',hash:'old'},[input(undefined,undefined,'旧姓名','旧项目')],defaultSettings(dir),null)
oldest.outputDirectory=path.join(dir,'old-output');oldest.status='completed';await ledger.update(oldest)
for(let i=0;i<200;i++)await ledger.reserve({name:'新记录.xlsx',hash:String(i)},[input('新学校','高一','新姓名','新项目')],defaultSettings(dir),null)
expect(ledger.summaries()).toHaveLength(200)
expect(ledger.summaries().some(batch=>batch.id===oldest.id)).toBe(false)
expect(ledger.batchPage({page:41})).toMatchObject({total:201,page:41,pageSize:5,items:[{id:oldest.id}]})
expect(ledger.summaries({search:'旧姓名',school:'未分类学校',grade:'未分类年级',item:'旧项目'})[0].id).toBe(oldest.id)
expect(ledger.isOutputDirectory(oldest.outputDirectory)).toBe(true)
expect(ledger.isOutputDirectory(path.join(dir,'other'))).toBe(false)
expect(ledger.historyFilters()).toMatchObject({schools:expect.arrayContaining(['新学校','未分类学校']),grades:expect.arrayContaining(['高一','未分类年级']),items:expect.arrayContaining(['旧项目','新项目'])})
expect(ledger.nextNumber('SJ')).toBe('SJ00000202')
}finally{await rm(dir,{recursive:true,force:true})}
},20000)
it('默认每页五条,分页互不重复,按筛选结果计数,并在删除末页记录后回到有效页',async()=>{
const dir=await mkdtemp(path.join(tmpdir(),'receipt-pages-'))
try{
const ledger=new Ledger(path.join(dir,'db.sqlite'));await ledger.open()
const batches=[]
for(let i=1;i<=12;i++){
const batch=await ledger.reserve({name:'批次'+i,hash:String(i)},[input(i%2?'甲学校':'乙学校','高一','学生'+i,'服务费')],defaultSettings(dir),null)
batch.status='completed';await ledger.update(batch);batches.push(batch)
}
const first=ledger.batchPage(),second=ledger.batchPage({page:2}),last=ledger.batchPage({page:3})
expect(first).toMatchObject({total:12,page:1,pageSize:5})
expect(first.items.map(batch=>batch.sourceName)).toEqual(['批次12','批次11','批次10','批次9','批次8'])
expect(second.items).toHaveLength(5);expect(last.items).toHaveLength(2)
expect(new Set([...first.items,...second.items,...last.items].map(batch=>batch.id)).size).toBe(12)
expect(ledger.batchPage({page:2,pageSize:10})).toMatchObject({total:12,page:2,pageSize:10,items:expect.arrayContaining([{...last.items[0]},{...last.items[1]}])})
expect(ledger.batchPage({pageSize:50}).items).toHaveLength(12)
expect(ledger.batchPage({school:'甲学校',page:2})).toMatchObject({total:6,page:2,items:[{id:batches[0].id}]})
expect(ledger.batchPage({school:'甲学校',page:999})).toMatchObject({total:6,page:2,items:[{id:batches[0].id}]})
expect(ledger.batchPage({search:'不存在',page:999})).toEqual({items:[],total:0,page:1,pageSize:5})
await ledger.deleteBatch(batches[0].id);await ledger.deleteBatch(batches[1].id)
expect(ledger.batchPage({page:3})).toMatchObject({total:10,page:2,items:expect.any(Array)})
expect(ledger.batchPage({page:3}).items).toHaveLength(5)
expect(ledger.nextNumber('SJ')).toBe('SJ00000013')
}finally{await rm(dir,{recursive:true,force:true})}
})