- 版本化 SQLite 迁移(向前/回滚)与连接助手。 - 导入管线:上传文件按 SHA-256 内容哈希不可变保存,文件/行/批次 幂等;重复上传返回 duplicate 并复用已有批次,不产生第二份事实。 - 每条规范化源行反查文件、工作表、原始行号与模板版本。 - 解析失败保留 exception/failed 批次与诊断,不产生已确认交易。 - 决策记录见 docs/decisions/002-persistence.md。
180 lines
6.0 KiB
Python
180 lines
6.0 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
import unicodedata
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class BankTemplate:
|
|
template_id: str
|
|
bank_name: str
|
|
columns: dict[str, tuple[str, ...]]
|
|
required: tuple[str, ...]
|
|
version: int = 1
|
|
|
|
|
|
def normalize_header(value: object) -> str:
|
|
if value is None:
|
|
return ""
|
|
text = unicodedata.normalize("NFKC", str(value)).strip().casefold()
|
|
return "".join(text.split())
|
|
|
|
|
|
def _aliases(*values: str) -> tuple[str, ...]:
|
|
return tuple(normalize_header(value) for value in values)
|
|
|
|
|
|
TEMPLATES: tuple[BankTemplate, ...] = (
|
|
BankTemplate(
|
|
template_id="citic-account-detail-v1",
|
|
bank_name="中信银行",
|
|
columns={
|
|
"transaction_date": _aliases("交易日期"),
|
|
"transaction_time": _aliases("交易时间"),
|
|
"counterparty_account": _aliases("对方账号"),
|
|
"counterparty_name": _aliases("对方账户名称"),
|
|
"counterparty_bank": _aliases("对方账号开户网点名称"),
|
|
"expense": _aliases("借方发生额"),
|
|
"income": _aliases("贷方发生额"),
|
|
"balance": _aliases("账户余额"),
|
|
"summary": _aliases("摘要"),
|
|
"purpose": _aliases("附言"),
|
|
"currency": _aliases("币种"),
|
|
"own_account": _aliases("交易账号"),
|
|
"reference": _aliases("柜员交易号", "发起方流水号"),
|
|
},
|
|
required=(
|
|
"transaction_date",
|
|
"transaction_time",
|
|
"counterparty_account",
|
|
"expense",
|
|
"income",
|
|
"balance",
|
|
),
|
|
),
|
|
BankTemplate(
|
|
template_id="abc-account-detail-v1",
|
|
bank_name="中国农业银行",
|
|
columns={
|
|
"transaction_at": _aliases("交易时间"),
|
|
"income": _aliases("收入金额"),
|
|
"expense": _aliases("支出金额"),
|
|
"balance": _aliases("账户余额"),
|
|
"counterparty_account": _aliases("对方账号"),
|
|
"counterparty_name": _aliases("对方户名"),
|
|
"counterparty_bank": _aliases("对方开户行"),
|
|
"summary": _aliases("摘要"),
|
|
},
|
|
required=(
|
|
"transaction_at",
|
|
"income",
|
|
"expense",
|
|
"balance",
|
|
"counterparty_account",
|
|
"counterparty_name",
|
|
"summary",
|
|
),
|
|
),
|
|
BankTemplate(
|
|
template_id="icbc-history-detail-v1",
|
|
bank_name="中国工商银行",
|
|
columns={
|
|
"reference": _aliases("凭证号"),
|
|
"own_account": _aliases("本方账号"),
|
|
"counterparty_account": _aliases("对方账号"),
|
|
"transaction_at": _aliases("交易时间"),
|
|
"expense": _aliases("借方发生额"),
|
|
"income": _aliases("贷方发生额"),
|
|
"summary": _aliases("摘要"),
|
|
"purpose": _aliases("用途"),
|
|
"counterparty_name": _aliases("对方单位名称"),
|
|
"balance": _aliases("余额"),
|
|
},
|
|
required=(
|
|
"reference",
|
|
"own_account",
|
|
"transaction_at",
|
|
"expense",
|
|
"income",
|
|
"counterparty_name",
|
|
"balance",
|
|
),
|
|
),
|
|
BankTemplate(
|
|
template_id="ccb-account-detail-v1",
|
|
bank_name="中国建设银行",
|
|
columns={
|
|
"own_account": _aliases("客户账号"),
|
|
"own_name": _aliases("账户名称"),
|
|
"transaction_at": _aliases("交易时间"),
|
|
"expense": _aliases("借方发生额(支取)"),
|
|
"income": _aliases("贷方发生额(收入)"),
|
|
"balance": _aliases("余额"),
|
|
"currency": _aliases("币种"),
|
|
"counterparty_name": _aliases("对方户名"),
|
|
"counterparty_account": _aliases("对方账号"),
|
|
"counterparty_bank": _aliases("对方开户机构"),
|
|
"summary": _aliases("摘要"),
|
|
"purpose": _aliases("备注"),
|
|
},
|
|
required=(
|
|
"own_account",
|
|
"transaction_at",
|
|
"expense",
|
|
"income",
|
|
"balance",
|
|
"counterparty_account",
|
|
),
|
|
),
|
|
BankTemplate(
|
|
template_id="henan-rural-history-v1",
|
|
bank_name="河南农商银行",
|
|
columns={
|
|
"transaction_at": _aliases("交易时间"),
|
|
"reference": _aliases("交易流水号"),
|
|
"income": _aliases("收入"),
|
|
"expense": _aliases("支出"),
|
|
"balance": _aliases("账户余额"),
|
|
"summary": _aliases("交易类型"),
|
|
"counterparty_account": _aliases("对方帐号"),
|
|
"counterparty_name": _aliases("对方户名"),
|
|
"counterparty_bank": _aliases("交易网点"),
|
|
"purpose": _aliases("备注"),
|
|
},
|
|
required=(
|
|
"transaction_at",
|
|
"reference",
|
|
"income",
|
|
"expense",
|
|
"balance",
|
|
"counterparty_account",
|
|
"counterparty_name",
|
|
),
|
|
),
|
|
BankTemplate(
|
|
template_id="bank-of-zhengzhou-detail-v1",
|
|
bank_name="郑州银行",
|
|
columns={
|
|
"transaction_at": _aliases("交易时间"),
|
|
"income": _aliases("收入金额(元)"),
|
|
"expense": _aliases("支出金额(元)"),
|
|
"balance": _aliases("账户余额(元)"),
|
|
"counterparty_name": _aliases("对方户名"),
|
|
"counterparty_account": _aliases("对方账号"),
|
|
"counterparty_bank": _aliases("对方账户开户行"),
|
|
"purpose": _aliases("用途"),
|
|
"summary": _aliases("摘要"),
|
|
"currency": _aliases("币种"),
|
|
"reference": _aliases("交易流水号"),
|
|
},
|
|
required=(
|
|
"transaction_at",
|
|
"income",
|
|
"expense",
|
|
"balance",
|
|
"counterparty_account",
|
|
"reference",
|
|
),
|
|
),
|
|
)
|