Initial commit: intercompany ledger app
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
from bank_importer.parser import UnknownTemplateError, detect_header, parse_directory
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SAMPLES = ROOT / "流水模板"
|
||||
|
||||
|
||||
class StatementParserTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
cls.batches = parse_directory(SAMPLES)
|
||||
cls.by_file = {batch.source_file.name: batch for batch in cls.batches}
|
||||
|
||||
def test_all_current_bank_samples_are_recognized(self) -> None:
|
||||
expected = {
|
||||
"中信银行账户流水.xlsx": ("中信银行", 16, 4),
|
||||
"中国农业银行账户流水.xls": ("中国农业银行", 3, 4),
|
||||
"中国工商银行账户流水.xlsx": ("中国工商银行", 2, 5),
|
||||
"中国建设银行账户流水.xls": ("中国建设银行", 1, 1),
|
||||
"河南农商银行账户流水.xlsx": ("河南农商银行", 11, 1),
|
||||
"郑州银行账户流水.xls": ("郑州银行", 7, 5),
|
||||
}
|
||||
self.assertEqual(set(expected), set(self.by_file))
|
||||
for filename, (bank, header_row, transaction_count) in expected.items():
|
||||
with self.subTest(filename=filename):
|
||||
batch = self.by_file[filename]
|
||||
self.assertEqual(bank, batch.bank_name)
|
||||
self.assertEqual(header_row, batch.header_row)
|
||||
self.assertEqual(transaction_count, len(batch.transactions))
|
||||
|
||||
def test_known_statement_periods_are_extracted(self) -> None:
|
||||
expected = {
|
||||
"中信银行账户流水.xlsx": (date(2026, 4, 26), date(2026, 5, 23)),
|
||||
"中国农业银行账户流水.xls": (date(2025, 11, 26), date(2025, 12, 27)),
|
||||
"河南农商银行账户流水.xlsx": (date(2026, 2, 24), date(2026, 3, 28)),
|
||||
"郑州银行账户流水.xls": (date(2026, 2, 24), date(2026, 3, 27)),
|
||||
}
|
||||
for filename, period in expected.items():
|
||||
with self.subTest(filename=filename):
|
||||
batch = self.by_file[filename]
|
||||
self.assertEqual(period, (batch.period_start, batch.period_end))
|
||||
|
||||
def test_normalized_transactions_have_one_cash_direction(self) -> None:
|
||||
for batch in self.batches:
|
||||
for transaction in batch.transactions:
|
||||
with self.subTest(
|
||||
filename=batch.source_file.name, row=transaction.source_row
|
||||
):
|
||||
self.assertNotEqual(transaction.income > 0, transaction.expense > 0)
|
||||
|
||||
def test_current_samples_reconcile_by_running_balance(self) -> None:
|
||||
for batch in self.batches:
|
||||
with self.subTest(filename=batch.source_file.name):
|
||||
self.assertEqual((), batch.warnings)
|
||||
|
||||
def test_column_order_does_not_affect_header_detection(self) -> None:
|
||||
header = (
|
||||
"余额",
|
||||
"对方单位名称",
|
||||
"贷方发生额",
|
||||
"交易时间",
|
||||
"本方账号",
|
||||
"借方发生额",
|
||||
"凭证号",
|
||||
)
|
||||
template, row_index, columns = detect_header((header,))
|
||||
self.assertEqual("icbc-history-detail-v1", template.template_id)
|
||||
self.assertEqual(0, row_index)
|
||||
self.assertEqual(3, columns["transaction_at"])
|
||||
|
||||
def test_unknown_header_is_rejected(self) -> None:
|
||||
with self.assertRaises(UnknownTemplateError) as raised:
|
||||
detect_header((("日期", "金额", "备注"),))
|
||||
message = str(raised.exception)
|
||||
self.assertIn("未识别到受支持的银行表头", message)
|
||||
self.assertIn("第 1 行", message)
|
||||
self.assertIn("日期、金额、备注", message)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user