-
-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feat] 增加对海外银行 bmo provider 的支持 (#113)
- Loading branch information
1 parent
108fca1
commit 75d1e35
Showing
22 changed files
with
624 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
defaultMinusAccount: Assets:FIXME | ||
defaultPlusAccount: Expenses:FIXME | ||
defaultCashAccount: Liabilities:CreditCard:BMO | ||
defaultCurrency: CAD | ||
title: 测试 | ||
bmo: | ||
rules: | ||
- item: "T T" | ||
targetAccount: Expenses:Grocery | ||
tag: tt_tag | ||
- item: "COSTCO" | ||
targetAccount: Expenses:Grocery | ||
- item: "T&T SUPERMARKET" | ||
targetAccount: Expenses:Grocery | ||
- item: "JOLLIBEE" | ||
targetAccount: Expenses:Food:Lunch | ||
- item: "DOLLARAMA" | ||
targetAccount: Expenses:Grocery | ||
tag: grocery_tag1,cheap_tag2 | ||
- item: "DEVELOPM MSP" | ||
targetAccount: Income:Salary | ||
- type: 收入 | ||
item: "SEND E-TFR" | ||
targetAccount: Income:FIXME |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
option "title" "测试" | ||
option "operating_currency" "CAD" | ||
|
||
1970-01-01 open Assets:FIXME | ||
1970-01-01 open Expenses:FIXME | ||
1970-01-01 open Expenses:Food:Lunch | ||
1970-01-01 open Expenses:Grocery | ||
1970-01-01 open Income:FIXME | ||
1970-01-01 open Income:Salary | ||
|
||
2023-05-11 * "BMO" "COSTCO WHOLESALE W54 SURREY BC" | ||
Expenses:Grocery 3.27 CAD | ||
Liabilities:CreditCard:BMO -3.27 CAD | ||
|
||
2023-05-11 * "BMO" "COSTCO WHOLESALE W54 SURREY BC" | ||
Expenses:Grocery 85.06 CAD | ||
Liabilities:CreditCard:BMO -85.06 CAD | ||
|
||
2023-05-12 * "BMO" "T&T SUPERMARKET #026 SURREY BC" | ||
Expenses:Grocery 6.00 CAD | ||
Liabilities:CreditCard:BMO -6.00 CAD | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
1970/01/01 * Open Balance | ||
Assets:FIXME 0 CAD | ||
Expenses:FIXME 0 CAD | ||
Expenses:Food:Lunch 0 CAD | ||
Expenses:Grocery 0 CAD | ||
Income:FIXME 0 CAD | ||
Income:Salary 0 CAD | ||
Equity:Opening Balances | ||
2023/05/11 * BMO - COSTCO WHOLESALE W54 SURREY BC | ||
Expenses:Grocery 3.27 CAD | ||
Liabilities:CreditCard:BMO - 3.27 CAD | ||
|
||
2023/05/11 * BMO - COSTCO WHOLESALE W54 SURREY BC | ||
Expenses:Grocery 85.06 CAD | ||
Liabilities:CreditCard:BMO - 85.06 CAD | ||
|
||
2023/05/12 * BMO - T&T SUPERMARKET #026 SURREY BC | ||
Expenses:Grocery 6.00 CAD | ||
Liabilities:CreditCard:BMO - 6.00 CAD | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Following data is valid as of 202304230942432: | ||
|
||
Item #,Card #,Transaction Date,Posting Date,Transaction Amount,Description | ||
1,'5191230567984561',20230511,20230512,3.27,COSTCO WHOLESALE W54 SURREY BC | ||
2,'5191230567984561',20230511,20230512,85.06,COSTCO WHOLESALE W54 SURREY BC | ||
3,'5191230567984561',20230512,20230515,6.0,T&T SUPERMARKET #026 SURREY BC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
defaultMinusAccount: Assets:FIXME | ||
defaultPlusAccount: Expenses:FIXME | ||
defaultCashAccount: Assets:DebitCard:BMOChequing | ||
defaultCurrency: CAD | ||
title: 测试 | ||
bmo: | ||
rules: | ||
- item: "T T" | ||
targetAccount: Expenses:Grocery | ||
tag: tt_tag | ||
- item: "DOLLARAMA" | ||
targetAccount: Expenses:Grocery | ||
tag: grocery_tag1,cheap_tag2 | ||
- item: "DEVELOPM MSP" | ||
targetAccount: Income:Salary | ||
- type: 收入 | ||
item: "SEND E-TFR" | ||
targetAccount: Income:FIXME |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
option "title" "测试" | ||
option "operating_currency" "CAD" | ||
|
||
1970-01-01 open Assets:FIXME | ||
1970-01-01 open Expenses:FIXME | ||
1970-01-01 open Expenses:Grocery | ||
1970-01-01 open Income:FIXME | ||
1970-01-01 open Income:Salary | ||
|
||
2023-05-01 * "BMO" "[DN]ACFS MSP/DIV" | ||
Assets:DebitCard:BMOChequing 0.01 CAD | ||
Assets:FIXME -0.01 CAD | ||
|
||
2023-05-18 * "BMO" "[CW]TELUS MOB" | ||
Expenses:FIXME 68.32 CAD | ||
Assets:DebitCard:BMOChequing -68.32 CAD | ||
|
||
2023-05-23 * "BMO" "[CW]BC HYDRO" | ||
Expenses:FIXME 50.00 CAD | ||
Assets:DebitCard:BMOChequing -50.00 CAD | ||
|
||
2023-06-12 * "BMO" "[IB] 6088 #3 ROAD" | ||
Expenses:FIXME 40.00 CAD | ||
Assets:DebitCard:BMOChequing -40.00 CAD | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
1970/01/01 * Open Balance | ||
Assets:FIXME 0 CAD | ||
Expenses:FIXME 0 CAD | ||
Expenses:Grocery 0 CAD | ||
Income:FIXME 0 CAD | ||
Income:Salary 0 CAD | ||
Equity:Opening Balances | ||
2023/05/01 * BMO - [DN]ACFS MSP/DIV | ||
Assets:DebitCard:BMOChequing 0.01 CAD | ||
Assets:FIXME - 0.01 CAD | ||
|
||
2023/05/18 * BMO - [CW]TELUS MOB | ||
Expenses:FIXME 68.32 CAD | ||
Assets:DebitCard:BMOChequing - 68.32 CAD | ||
|
||
2023/05/23 * BMO - [CW]BC HYDRO | ||
Expenses:FIXME 50.00 CAD | ||
Assets:DebitCard:BMOChequing - 50.00 CAD | ||
|
||
2023/06/12 * BMO - [IB] 6088 #3 ROAD | ||
Expenses:FIXME 40.00 CAD | ||
Assets:DebitCard:BMOChequing - 40.00 CAD | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Following data is valid as of 20239810344234 (Year/Month/Day/Hour/Minute/Second) | ||
|
||
|
||
First Bank Card,Transaction Type,Date Posted, Transaction Amount,Description | ||
|
||
|
||
'5678653123124124',CREDIT,20230501,0.01,[DN]ACFS MSP/DIV | ||
'5678653123124124',DEBIT,20230518,-68.32,[CW]TELUS MOB | ||
'5678653123124124',DEBIT,20230523,-50.0,[CW]BC HYDRO | ||
'5678653123124124',DEBIT,20230612,-40.0,[IB] 6088 #3 ROAD |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package bmo | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/deb-sig/double-entry-generator/pkg/config" | ||
"github.com/deb-sig/double-entry-generator/pkg/ir" | ||
"github.com/deb-sig/double-entry-generator/pkg/util" | ||
) | ||
|
||
type Bmo struct { | ||
} | ||
|
||
// GetAllCandidateAccounts returns all accounts defined in config. | ||
func (bmo Bmo) GetAllCandidateAccounts(cfg *config.Config) map[string]bool { | ||
// uniqMap will be used to create the concepts. | ||
uniqMap := make(map[string]bool) | ||
|
||
if cfg.Bmo == nil || len(cfg.Bmo.Rules) == 0 { | ||
return uniqMap | ||
} | ||
|
||
for _, rule := range cfg.Bmo.Rules { | ||
if rule.MethodAccount != nil { | ||
uniqMap[*rule.MethodAccount] = true | ||
} | ||
if rule.TargetAccount != nil { | ||
uniqMap[*rule.TargetAccount] = true | ||
} | ||
} | ||
uniqMap[cfg.DefaultPlusAccount] = true | ||
uniqMap[cfg.DefaultMinusAccount] = true | ||
return uniqMap | ||
} | ||
|
||
// GetAccountsAndTags GetAccounts returns minus and plus account. | ||
func (bmo Bmo) GetAccountsAndTags(order *ir.Order, cfg *config.Config, target, provider string) (bool, string, string, map[ir.Account]string, []string) { | ||
ignore := false | ||
|
||
if cfg.Bmo == nil || len(cfg.Bmo.Rules) == 0 { | ||
return ignore, cfg.DefaultMinusAccount, cfg.DefaultPlusAccount, nil, nil | ||
} | ||
|
||
var tags = make([]string, 0) | ||
resMinus := cfg.DefaultMinusAccount | ||
resPlus := cfg.DefaultPlusAccount | ||
cashAccount := cfg.DefaultCashAccount | ||
|
||
// method account (bank card account) | ||
if order.Type == ir.TypeRecv { | ||
resPlus = cashAccount | ||
} else { | ||
resMinus = cashAccount | ||
} | ||
|
||
for _, rule := range cfg.Bmo.Rules { | ||
match := true | ||
// get separator | ||
sep := "," | ||
if rule.Separator != nil { | ||
sep = *rule.Separator | ||
} | ||
|
||
matchFunc := util.SplitFindContains | ||
if rule.FullMatch { | ||
matchFunc = util.SplitFindEquals | ||
} | ||
|
||
if rule.Item != nil { | ||
match = matchFunc(*rule.Item, order.Item, sep, match) | ||
} | ||
if rule.Type != nil { | ||
match = matchFunc(*rule.Type, order.TypeOriginal, sep, match) | ||
} | ||
|
||
if match { | ||
if rule.Ignore { | ||
ignore = true | ||
break | ||
} | ||
// Support multiple matches, like one rule matches the minus account, the other rule matches the plus account. | ||
if rule.TargetAccount != nil { | ||
if order.Type == ir.TypeRecv { | ||
resMinus = *rule.TargetAccount | ||
} else { | ||
resPlus = *rule.TargetAccount | ||
} | ||
} | ||
|
||
if rule.Tag != nil { | ||
tags = strings.Split(*rule.Tag, sep) | ||
} | ||
|
||
} | ||
|
||
} | ||
return ignore, resMinus, resPlus, nil, tags | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package bmo | ||
|
||
import ( | ||
"encoding/csv" | ||
"fmt" | ||
"io" | ||
"log" | ||
|
||
"github.com/deb-sig/double-entry-generator/pkg/io/reader" | ||
"github.com/deb-sig/double-entry-generator/pkg/ir" | ||
) | ||
|
||
type Bmo struct { | ||
Statistics Statistics `json:"statistics,omitempty"` | ||
LineNum int `json:"line_num,omitempty"` | ||
Orders []Order `json:"orders,omitempty"` | ||
CardName string `json:"card_name,omitempty"` | ||
Mode CardMode `json:"mode,omitempty"` | ||
} | ||
|
||
func New() *Bmo { | ||
return &Bmo{ | ||
Statistics: Statistics{}, | ||
LineNum: 0, | ||
Orders: make([]Order, 0), | ||
CardName: "", | ||
Mode: DebitMode, | ||
} | ||
} | ||
|
||
// Translate the bmo bill records to IR. | ||
func (bmo *Bmo) Translate(filename string) (*ir.IR, error) { | ||
log.SetPrefix("[Provider-BMO] ") | ||
|
||
billReader, err := reader.GetReader(filename) | ||
if err != nil { | ||
return nil, fmt.Errorf("can't get bill reader, err: %v", err) | ||
} | ||
|
||
csvReader := csv.NewReader(billReader) | ||
csvReader.LazyQuotes = true | ||
// If FieldsPerRecord is negative, no check is made and records | ||
// may have a variable number of fields. | ||
csvReader.FieldsPerRecord = -1 | ||
|
||
for { | ||
line, err := csvReader.Read() | ||
|
||
if err == io.EOF { | ||
break | ||
} else if err != nil { | ||
return nil, err | ||
} | ||
|
||
bmo.LineNum++ | ||
|
||
if bmo.LineNum == 2 { | ||
// 借记卡(default) or 信用卡 | ||
if line[0] == "Item #" { | ||
bmo.Mode = CreditMode | ||
continue | ||
} | ||
} | ||
|
||
if bmo.Mode == DebitMode && bmo.LineNum <= 2 { | ||
// bypass the useless | ||
continue | ||
} | ||
|
||
if bmo.Mode == DebitMode { | ||
err = bmo.translateDebitToOrders(line) | ||
if err != nil { | ||
return nil, fmt.Errorf("Failed to translate debit bill: line %d: %v", bmo.LineNum, err) | ||
} | ||
} else { | ||
err = bmo.translateCreditToOrders(line) | ||
if err != nil { | ||
return nil, fmt.Errorf("Failed to translate credit bill: line %d: %v", bmo.LineNum, err) | ||
} | ||
} | ||
} | ||
log.Printf("Finished to parse the file %s", filename) | ||
return bmo.convertToIR(), nil | ||
} |
Oops, something went wrong.