Skip to content

Commit 79520e4

Browse files
zwyyy456zwyyy456
andauthored
feat, test: 支持中国银行信用卡与借记卡,添加对应的测试用例 (#208)
* feat: 添加中国银行(BoC)账单解析支持 * test: 适配最新的测试用例组织方式,优化日志打印 --------- Co-authored-by: zwyyy456 <zwyyy456@gmail.com>
1 parent 0a5a235 commit 79520e4

19 files changed

Lines changed: 714 additions & 7 deletions

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ TEST_CONFIGS := \
5151
ccb:beancount,ledger:. \
5252
citic:beancount,ledger:credit \
5353
hxsec:beancount:. \
54-
spdb_debit:beancount:.
54+
spdb_debit:beancount:. \
55+
boc:beancount:credit,debit
5556

5657
# Current version of the project.
5758
GIT_COMMIT = $(shell git describe --tags --always --dirty)

example/boc/credit/config.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
defaultMinusAccount: Assets:FIXME
2+
defaultPlusAccount: Expenses:FIXME
3+
defaultCurrency: CNY
4+
title: boc
5+
boc:
6+
rules:
7+
- item: 公共交通
8+
sep: ","
9+
targetAccount: Expenses:Transport:Subway
10+
- item: xbox,steam,游戏
11+
sep: ","
12+
targetAccount: Expenses:Relax:Game
13+
- peer: 顾问有限公司
14+
sep: ","
15+
targetAccount: Expenses:Education:Training
16+
- peer: 张林
17+
sep: ","
18+
targetAccount: Expenses:Reside:Rent
19+
- peer: "0258"
20+
targetAccount: Assets:DC:BCM:0258
21+
- peer: "5669"
22+
targetAccount: Liabilities:CC:CMBC:5669
23+
- peer: "4664"
24+
targetAccount: Liabilities:CC:BCM:4664
25+
- peer: "4294"
26+
targetAccount: Liabilities:CC:CMB:4294
27+
28+
- peer: 支付宝,微信,钱袋宝,京东
29+
sep: ","
30+
ignore: true # 忽略支付宝和微信
31+
32+
- item: 支付宝,微信,钱袋宝,京东
33+
sep: ","
34+
ignore: true # 忽略支付宝和微信
35+
- item: 曾三
36+
ignore: true # 说明是信用卡还款,忽略它
37+
38+
- method: "3167"
39+
methodAccount: Assets:DC:BoC:3167
40+
- method: "2875"
41+
methodAccount: Liabilities:CC:BoC:2875
42+
- method: "4260"
43+
methodAccount: Liabilities:CC:BoC:4260
44+
- item: 网银在线CHN
45+
type: 收入
46+
targetAccount: Income:BoC:Rebate
47+
- item: 工资
48+
type: 收入
49+
targetAccount: Income:BoC:Salary
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
option "title" "boc"
2+
option "operating_currency" "CNY"
3+
4+
1970-01-01 open Assets:DC:BCM:0258
5+
1970-01-01 open Assets:DC:BoC:3167
6+
1970-01-01 open Assets:FIXME
7+
1970-01-01 open Expenses:Education:Training
8+
1970-01-01 open Expenses:FIXME
9+
1970-01-01 open Expenses:Relax:Game
10+
1970-01-01 open Expenses:Reside:Rent
11+
1970-01-01 open Expenses:Transport:Subway
12+
1970-01-01 open Income:BoC:Rebate
13+
1970-01-01 open Income:BoC:Salary
14+
1970-01-01 open Liabilities:CC:BCM:4664
15+
1970-01-01 open Liabilities:CC:BoC:2875
16+
1970-01-01 open Liabilities:CC:BoC:4260
17+
1970-01-01 open Liabilities:CC:CMB:4294
18+
1970-01-01 open Liabilities:CC:CMBC:5669
19+
20+
2024-12-14 * "" "上海公共交通卡股份有限CHN"
21+
Expenses:Transport:Subway 50.00 CNY
22+
Liabilities:CC:BoC:4260 -50.00 CNY
23+
24+
2024-12-20 * "" "存款利息"
25+
Expenses:FIXME 0.01 CNY
26+
Assets:FIXME -0.01 CNY
27+
28+
2024-12-24 * "" "MICROSOFT*XBOXJPN"
29+
Expenses:FIXME 3.72 USD
30+
Liabilities:CC:BoC:2875 -3.72 USD
31+
32+
2024-12-25 * "" "网银在线CHN"
33+
Liabilities:CC:BoC:2875 70.48 CNY
34+
Income:BoC:Rebate -70.48 CNY
35+
36+
2024-12-25 * "" "网银在线CHN"
37+
Liabilities:CC:BoC:2875 397.84 CNY
38+
Income:BoC:Rebate -397.84 CNY
39+
40+
2024-12-25 * "" "网银在线CHN"
41+
Liabilities:CC:BoC:2875 70.48 CNY
42+
Income:BoC:Rebate -70.48 CNY
43+
44+
2024-12-29 * "" "网银在线CHN"
45+
Liabilities:CC:BoC:2875 89.84 CNY
46+
Income:BoC:Rebate -89.84 CNY
47+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
中国银行信用卡账单(2025年01月)
2+
交易日,银行记账日,卡号后四位,交易描述,存入,支出,币种
3+
2024-12-13,2024-12-14,4260,上海公共交通卡股份有限CHN,,50.00,CNY
4+
2024-12-15,2024-12-16,2875,钱袋宝支付-大众点评App美团神会员CHN,,0.59,CNY
5+
2024-12-20,2024-12-20,,存款利息,0.01,,CNY
6+
2024-12-20,2024-12-20,2875,曾三,361.19,,CNY
7+
2024-12-21,2024-12-22,2875,网银在线-京东商城业务CHN,,68.19,CNY
8+
2024-12-24,2024-12-25,2875,网银在线-拓路者运*京东商城CHN,,468.32,CNY
9+
2024-12-24,2024-12-25,2875,网银在线-拓路者运*京东商城CHN,,448.32,CNY
10+
2024-12-24,2024-12-25,2875,网银在线CHN,70.48,,CNY
11+
2024-12-24,2024-12-25,2875,网银在线CHN,397.84,,CNY
12+
2024-12-24,2024-12-25,2875,网银在线CHN,70.48,,CNY
13+
2024-12-28,2024-12-29,2875,网银在线-京东商城业务CHN,,131.77,CNY
14+
2024-12-28,2024-12-29,2875,网银在线CHN,89.84,,CNY
15+
2024-12-30,2024-12-31,2875,网银在线-京东商城业务CHN,,60.90,CNY
16+
2024-12-22,2024-12-24,2875,MICROSOFT*XBOXJPN,,3.72,USD

example/boc/debit/config.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
defaultMinusAccount: Assets:FIXME
2+
defaultPlusAccount: Expenses:FIXME
3+
defaultCurrency: CNY
4+
title: boc
5+
boc:
6+
rules:
7+
- item: 公共交通
8+
sep: ","
9+
targetAccount: Expenses:Transport:Subway
10+
- item: xbox,steam,游戏
11+
sep: ","
12+
targetAccount: Expenses:Relax:Game
13+
- peer: 顾问有限公司
14+
sep: ","
15+
targetAccount: Expenses:Education:Training
16+
- peer: 张林
17+
sep: ","
18+
targetAccount: Expenses:Reside:Rent
19+
- peer: "0258"
20+
targetAccount: Assets:DC:BCM:0258
21+
- peer: "5669"
22+
targetAccount: Liabilities:CC:CMBC:5669
23+
- peer: "4664"
24+
targetAccount: Liabilities:CC:BCM:4664
25+
- peer: "4294"
26+
targetAccount: Liabilities:CC:CMB:4294
27+
28+
- peer: 支付宝,微信,钱袋宝,京东
29+
sep: ","
30+
ignore: true # 忽略支付宝和微信
31+
32+
- item: 支付宝,微信,钱袋宝,京东
33+
sep: ","
34+
ignore: true # 忽略支付宝和微信
35+
- item: 曾三
36+
ignore: true # 说明是信用卡还款,忽略它
37+
38+
- method: "3167"
39+
methodAccount: Assets:DC:BoC:3167
40+
- method: "2875"
41+
methodAccount: Liabilities:CC:BoC:2875
42+
- method: "4260"
43+
methodAccount: Liabilities:CC:BoC:4260
44+
- item: 网银在线CHN
45+
type: 收入
46+
targetAccount: Income:BoC:Rebate
47+
- item: 工资
48+
type: 收入
49+
targetAccount: Income:BoC:Salary
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
option "title" "boc"
2+
option "operating_currency" "CNY"
3+
4+
1970-01-01 open Assets:DC:BCM:0258
5+
1970-01-01 open Assets:DC:BoC:3167
6+
1970-01-01 open Assets:FIXME
7+
1970-01-01 open Expenses:Education:Training
8+
1970-01-01 open Expenses:FIXME
9+
1970-01-01 open Expenses:Relax:Game
10+
1970-01-01 open Expenses:Reside:Rent
11+
1970-01-01 open Expenses:Transport:Subway
12+
1970-01-01 open Income:BoC:Rebate
13+
1970-01-01 open Income:BoC:Salary
14+
1970-01-01 open Liabilities:CC:BCM:4664
15+
1970-01-01 open Liabilities:CC:BoC:2875
16+
1970-01-01 open Liabilities:CC:BoC:4260
17+
1970-01-01 open Liabilities:CC:CMB:4294
18+
1970-01-01 open Liabilities:CC:CMBC:5669
19+
20+
2025-08-01 * "张三6222******0258" "银联入账"
21+
Assets:DC:BoC:3167 1000.00 CNY
22+
Assets:DC:BCM:0258 -1000.00 CNY
23+
24+
2025-08-01 * "张林6205******2260" "无卡支付"
25+
Expenses:Reside:Rent 3000.00 CNY
26+
Assets:DC:BoC:3167 -3000.00 CNY
27+
28+
2025-08-04 * "张三6226******5669" "无卡支付"
29+
Liabilities:CC:CMBC:5669 2769.59 CNY
30+
Assets:DC:BoC:3167 -2769.59 CNY
31+
32+
2025-08-05 * "美金数据有限公司4520******1924" "工资"
33+
Assets:DC:BoC:3167 5771.00 CNY
34+
Income:BoC:Salary -5771.00 CNY
35+
36+
2025-08-12 * "上海十企业管理顾问有限公司3101******6787" "跨行转账"
37+
Expenses:Education:Training 2600.00 CNY
38+
Assets:DC:BoC:3167 -2600.00 CNY
39+
40+
2025-08-14 * "张三6225******4294" "无卡支付"
41+
Liabilities:CC:CMB:4294 68.14 CNY
42+
Assets:DC:BoC:3167 -68.14 CNY
43+
44+
2025-08-14 * "张三6222******4664" "无卡支付"
45+
Liabilities:CC:BCM:4664 206.80 CNY
46+
Assets:DC:BoC:3167 -206.80 CNY
47+
48+
2025-08-22 * "张三6226******5669" "无卡支付"
49+
Liabilities:CC:CMBC:5669 71.89 CNY
50+
Assets:DC:BoC:3167 -71.89 CNY
51+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
中国银行交易流水明细单
2+
记账日期,记账时间,币别,金额,余额,交易名称,渠道,网点名称,附言,对方账户名,对方卡号/账号,对方开户行,借记卡号
3+
2025-08-22,17:57:17,人民币,-71.89,"3,240.28",无卡支付,卡组织线上/无卡交易,-------------------,----------,张三,6226******5669,-------------------,3167
4+
2025-08-22,12:24:20,人民币,-326.00,"3,312.17",网上快捷支付,银企对接,-------------------,支付宝-李四,支付宝-李四,Z200******010N,-------------------,3167
5+
2025-08-22,12:23:04,人民币,50.00,"3,638.17",网上快捷退款,银企对接,-------------------,支付宝-李四,支付宝-李四,8000******1303,-------------------,3167
6+
2025-08-22,12:22:50,人民币,-50.00,"3,588.17",网上快捷支付,银企对接,-------------------,支付宝-李四,支付宝-李四,Z200******010N,-------------------,3167
7+
2025-08-19,10:52:29,人民币,-60.00,"3,638.17",网上快捷支付,银企对接,-------------------,支付宝-郑六,支付宝-郑六,Z200******010N,-------------------,3167
8+
2025-08-14,13:43:29,人民币,-206.80,"3,698.17",无卡支付,卡组织线上/无卡交易,-------------------,----------,张三,6222******4664,-------------------,3167
9+
2025-08-14,13:43:07,人民币,-68.14,"3,904.97",无卡支付,卡组织线上/无卡交易,-------------------,----------,张三,6225******4294,-------------------,3167
10+
2025-08-12,16:49:29,人民币,"-2,600.00","3,973.11",跨行转账,手机银行,------------------- 张三17670961139美金,数据有限公司,上海十企业管理顾问有限公司,3101******6787,浙江泰隆商业银行,3167
11+
2025-08-09,18:35:45,人民币,-13.50,"6,573.11",网上快捷支付,银企对接,-------------------,支付宝,支付宝,Z200******010N,-------------------,3167
12+
2025-08-07,08:07:59,人民币,-15.48,"6,586.61",网上快捷支付,银企对接,-------------------,支付宝-李一,支付宝-李一,4888******N,-------------------,3167
13+
2025-08-06,19:06:14,人民币,-16.00,"6,602.09",网上快捷支付,银企对接,-------------------,支付宝-朱二慈,支付宝-朱二慈,4888******N,-------------------,3167
14+
2025-08-05,16:00:44,人民币,"5,771.00","6,618.09",工资,柜台,中国银行上海市十厦支行,----------,美金数据有限公司,4520******1924,中国银行上海市十厦支行,3167
15+
2025-08-04,16:11:00,人民币,"-2,769.59",847.09,无卡支付,卡组织线上/无卡交易,-------------------,----------,张三,6226******5669,-------------------,3167
16+
2025-08-04,16:10:21,人民币,"3,000.00","3,616.68",网上快捷提现,银企对接,-------------------,支付宝-张三-张三支付宝余额提现-张三,支付宝-张三,2088******0156,支付宝,3167
17+
2025-08-03,16:46:40,人民币,-196.90,616.68,网上快捷支付,银企对接,-------------------,支付宝-朱十琦,支付宝-朱十琦,Z200******010N,-------------------,3167
18+
2025-08-01,08:57:22,人民币,"-3,000.00",813.58,无卡支付,卡组织线上/无卡交易,-------------------,----------,张林,6205******2260,-------------------,3167
19+
2025-08-01,08:57:00,人民币,"1,000.00","3,813.58",银联入账,卡组织线上/无卡交易,-------------------,转账,张三,6222******0258,-------------------,3167

pkg/analyser/boc/boc.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package boc
2+
3+
import (
4+
"log"
5+
"strings"
6+
7+
"github.com/deb-sig/double-entry-generator/v2/pkg/config"
8+
"github.com/deb-sig/double-entry-generator/v2/pkg/ir"
9+
"github.com/deb-sig/double-entry-generator/v2/pkg/util"
10+
)
11+
12+
type Boc struct {
13+
}
14+
15+
// GetAllCandidateAccounts returns all accounts defined in config.
16+
func (boc Boc) GetAllCandidateAccounts(cfg *config.Config) map[string]bool {
17+
uniqMap := make(map[string]bool)
18+
19+
if cfg.Boc == nil || len(cfg.Boc.Rules) == 0 {
20+
return uniqMap
21+
}
22+
23+
for _, r := range cfg.Boc.Rules {
24+
if r.MethodAccount != nil {
25+
uniqMap[*r.MethodAccount] = true
26+
}
27+
if r.TargetAccount != nil {
28+
uniqMap[*r.TargetAccount] = true
29+
}
30+
}
31+
uniqMap[cfg.DefaultPlusAccount] = true
32+
uniqMap[cfg.DefaultMinusAccount] = true
33+
return uniqMap
34+
}
35+
36+
// GetAccounts matches rules, returns minus and plus account for beancount or ledger.
37+
func (boc Boc) GetAccountsAndTags(o *ir.Order, cfg *config.Config, target, provider string) (bool, string, string, map[ir.Account]string, []string) {
38+
ignore := false
39+
if cfg.Boc == nil || len(cfg.Boc.Rules) == 0 {
40+
return ignore, cfg.DefaultMinusAccount, cfg.DefaultPlusAccount, nil, nil
41+
}
42+
resMinus := cfg.DefaultMinusAccount
43+
resPlus := cfg.DefaultPlusAccount
44+
var extraAccounts map[ir.Account]string
45+
var tags = make([]string, 0)
46+
47+
var err error
48+
for _, r := range cfg.Boc.Rules {
49+
match := true
50+
// get separator
51+
sep := ","
52+
if r.Separator != nil {
53+
sep = *r.Separator
54+
}
55+
56+
matchFunc := util.SplitFindContains // 匹配规则为包含
57+
if r.FullMatch {
58+
matchFunc = util.SplitFindEquals // 匹配规则为完全相等
59+
}
60+
if r.Type != nil { // 实际不生效,后续会根据 o.type 来判断
61+
match = matchFunc(*r.Type, o.TypeOriginal, sep, match)
62+
}
63+
if r.Item != nil {
64+
match = matchFunc(*r.Item, o.Item, sep, match)
65+
}
66+
if r.Method != nil {
67+
match = matchFunc(*r.Method, o.Method, sep, match)
68+
}
69+
if r.Peer != nil {
70+
match = matchFunc(*r.Peer, o.Peer, sep, match)
71+
}
72+
if r.Time != nil { // 检查支付时间是否在给定的时间范围中
73+
match, err = util.SplitFindTimeInterval(*r.Time, o.PayTime, match)
74+
if err != nil {
75+
log.Fatalf("%v", err)
76+
}
77+
}
78+
if r.TimestampRange != nil { // 检查支付时间是否在 unix 时间戳格式的时间范围中
79+
match, err = util.SplitFindTimeStampInterval(*r.TimestampRange, o.PayTime, match)
80+
if err != nil {
81+
log.Fatalf("%v", err)
82+
}
83+
}
84+
if r.MinPrice != nil && o.Money < *r.MinPrice {
85+
match = false
86+
}
87+
if r.MaxPrice != nil && o.Money > *r.MaxPrice {
88+
match = false
89+
}
90+
91+
if match {
92+
if r.Ignore {
93+
itemStr := ""
94+
if r.Item != nil {
95+
itemStr = *r.Item
96+
}
97+
peerStr := ""
98+
if r.Peer != nil {
99+
peerStr = *r.Peer
100+
}
101+
log.Println("boc: ignore ", itemStr, peerStr, o.Item)
102+
ignore = true
103+
break
104+
}
105+
// 目前看来,支付情况比较简单,只有消费与退款收入两种
106+
if r.TargetAccount != nil {
107+
if o.Type == ir.TypeRecv {
108+
resMinus = *r.TargetAccount
109+
} else {
110+
resPlus = *r.TargetAccount
111+
}
112+
}
113+
if r.MethodAccount != nil {
114+
if o.Type == ir.TypeRecv {
115+
resPlus = *r.MethodAccount
116+
} else {
117+
resMinus = *r.MethodAccount
118+
}
119+
}
120+
if r.Tags != nil {
121+
tags = strings.Split(*r.Tags, sep)
122+
}
123+
}
124+
}
125+
return ignore, resMinus, resPlus, extraAccounts, tags
126+
}

pkg/analyser/interface.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/deb-sig/double-entry-generator/v2/pkg/analyser/bocom_credit"
1010
"github.com/deb-sig/double-entry-generator/v2/pkg/analyser/bocom_debit"
1111
"github.com/deb-sig/double-entry-generator/v2/pkg/analyser/ccb"
12+
"github.com/deb-sig/double-entry-generator/v2/pkg/analyser/boc"
1213
"github.com/deb-sig/double-entry-generator/v2/pkg/analyser/citic"
1314
"github.com/deb-sig/double-entry-generator/v2/pkg/analyser/cmb"
1415
"github.com/deb-sig/double-entry-generator/v2/pkg/analyser/hsbchk"
@@ -71,7 +72,8 @@ func New(providerName string) (Interface, error) {
7172
return abc_debit.AbcDebit{}, nil
7273
case consts.ProviderSpdbDebit:
7374
return spdb_debit.SpdbDebit{}, nil
74-
75+
case consts.ProviderBoc:
76+
return boc.Boc{}, nil
7577
default:
7678
return nil, fmt.Errorf("Fail to create the analyser for the given name %s", providerName)
7779
}

0 commit comments

Comments
 (0)