105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
// 向测试环境灌入演示数据:登录测试账号,解析并确认导入样例账单。
|
|
import { readFile } from 'node:fs/promises'
|
|
import { basename, join, resolve } from 'node:path'
|
|
import axios from 'axios'
|
|
import { login } from './browser.js'
|
|
import { API_URL, ROOT } from './config.js'
|
|
|
|
/** 样例账单目录(doc-site 内的虚构样例,全部为虚假数据,禁止使用真实账单) */
|
|
const BILL_DIR = resolve(ROOT, 'scripts', 'samples')
|
|
|
|
/** 待导入样例:账单类型、相对路径、解压密码(仅使用虚构数据) */
|
|
const SAMPLES: Array<[string, string, string | null]> = [
|
|
['ALIPAY', 'alipay_fake.csv', null],
|
|
['TAOBAO', 'taobao_fake.xlsx', null],
|
|
['JD', 'jd_fake.csv', null],
|
|
]
|
|
|
|
interface ParsedRow {
|
|
externalNo: string
|
|
transactionTime: string
|
|
type: string
|
|
amount: number
|
|
counterparty?: string | null
|
|
product?: string | null
|
|
includeInStats?: boolean
|
|
importable?: boolean
|
|
rawData?: string | null
|
|
}
|
|
|
|
/**
|
|
* 调用解析接口解析账单文件。
|
|
*
|
|
* @param token 访问令牌
|
|
* @param billType 账单类型
|
|
* @param path 账单文件路径
|
|
* @param password 解压密码
|
|
* @returns 解析结果数据
|
|
*/
|
|
async function parseBill(token: string, billType: string, path: string, password: string | null): Promise<any> {
|
|
const buf = await readFile(path)
|
|
const form = new FormData()
|
|
form.append('file', new Blob([buf]), basename(path))
|
|
form.append('billType', billType)
|
|
if (password) form.append('password', password)
|
|
const res = await axios.post(`${API_URL}/transaction/import/parse`, form, {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
timeout: 120000,
|
|
})
|
|
if (res.data.code !== 200) throw new Error(res.data.message)
|
|
return res.data.data
|
|
}
|
|
|
|
/**
|
|
* 确认导入解析出的账单行。
|
|
*
|
|
* @param token 访问令牌
|
|
* @param billType 账单类型
|
|
* @param rows 解析结果行
|
|
* @returns 导入结果数据
|
|
*/
|
|
async function confirmBill(token: string, billType: string, rows: ParsedRow[]): Promise<any> {
|
|
const items = rows
|
|
.filter((r) => r.importable !== false)
|
|
.map((r) => ({
|
|
externalNo: r.externalNo,
|
|
transactionTime: r.transactionTime,
|
|
type: r.type,
|
|
amount: r.amount,
|
|
counterparty: r.counterparty ?? null,
|
|
product: r.product ?? null,
|
|
includeInStats: r.includeInStats ?? true,
|
|
rawData: r.rawData ?? null,
|
|
}))
|
|
const res = await axios.post(
|
|
`${API_URL}/transaction/import/confirm`,
|
|
{ billType, items },
|
|
{ headers: { Authorization: `Bearer ${token}` }, timeout: 120000 },
|
|
)
|
|
if (res.data.code !== 200) throw new Error(res.data.message)
|
|
return res.data.data
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
const token = await login()
|
|
console.log('登录成功')
|
|
for (const [billType, relPath, password] of SAMPLES) {
|
|
const path = join(BILL_DIR, relPath)
|
|
try {
|
|
const data = await parseBill(token, billType, path, password)
|
|
const rows: ParsedRow[] = data.rows ?? []
|
|
const importable = rows.filter((r) => r.importable !== false)
|
|
console.log(`[解析成功] ${billType}: 共 ${rows.length} 行,可导入 ${importable.length} 行`)
|
|
const result = await confirmBill(token, billType, rows)
|
|
console.log(`[导入成功] ${billType}: ${JSON.stringify(result)}`)
|
|
} catch (err) {
|
|
console.log(`[失败] ${billType}: ${err}`)
|
|
}
|
|
}
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error('FAIL', err)
|
|
process.exit(1)
|
|
})
|