From e204a828637bc463bbfd1ae9516cdc05f9d538ac Mon Sep 17 00:00:00 2001 From: Zhenzhen Zhao Date: Tue, 1 Jun 2021 11:37:48 +0800 Subject: [PATCH] feat(wechat, alipay): support multiple keywords in rules (#16) change viper config `yaml` to `mapstructure`: https://github.com/spf13/viper/issues/385 Signed-off-by: Triple-Z --- example/alipay/config.yaml | 3 +- ...t.bean => example-alipay-output.beancount} | 36 ++++++++++--------- example/alipay/example-alipay-records.csv | 1 + example/wechat/config.yaml | 5 ++- ...t.bean => example-wechat-output.beancount} | 32 ++++++++--------- pkg/analyser/alipay/alipay.go | 14 ++++---- pkg/analyser/huobi/huobi.go | 24 +++---------- pkg/analyser/wechat/wechat.go | 25 ++++++------- pkg/provider/alipay/config.go | 15 ++++---- pkg/provider/huobi/config.go | 20 +++++------ pkg/provider/wechat/config.go | 19 +++++----- pkg/util/util.go | 18 ++++++++++ 12 files changed, 109 insertions(+), 103 deletions(-) rename example/alipay/{example-alipay-output.bean => example-alipay-output.beancount} (91%) rename example/wechat/{example-wechat-output.bean => example-wechat-output.beancount} (100%) create mode 100644 pkg/util/util.go diff --git a/example/alipay/config.yaml b/example/alipay/config.yaml index d8d8dcc..fb7b63f 100644 --- a/example/alipay/config.yaml +++ b/example/alipay/config.yaml @@ -4,7 +4,8 @@ defaultCurrency: CNY title: 测试 alipay: rules: - - peer: 肯德基 + - peer: 肯德基|麦当劳 + sep: '|' plusAccount: Expenses:Food - item: 收益 plusAccount: Assets:Alipay diff --git a/example/alipay/example-alipay-output.bean b/example/alipay/example-alipay-output.beancount similarity index 91% rename from example/alipay/example-alipay-output.bean rename to example/alipay/example-alipay-output.beancount index 4e4a275..699d296 100644 --- a/example/alipay/example-alipay-output.bean +++ b/example/alipay/example-alipay-output.beancount @@ -1,34 +1,38 @@ option "title" "测试" option "operating_currency" "CNY" -1970-01-01 open Expenses:Medical -1970-01-01 open Expenses:Test -1970-01-01 open Liabilities:CreditCard:Test 1970-01-01 open Expenses:Food 1970-01-01 open Income:Earnings 1970-01-01 open Assets:Alipay - -2019-09-30 * "肯德基(张江高科餐厅)" "张江高科餐厅" - Expenses:Food 27.00 CNY - Liabilities:CreditCard:Test -27.00 CNY +1970-01-01 open Expenses:Medical +1970-01-01 open Expenses:Test +1970-01-01 open Liabilities:CreditCard:Test 2019-09-30 * "中欧基金管理有限公司" "余额宝-2019.09.29-收益发放" Assets:Alipay 0.01 CNY Income:Earnings -0.01 CNY -2021-02-06 * "医院" "退款-住院预交金" - Liabilities:CreditCard:Test 2725.42 CNY - Expenses:Medical -2725.42 CNY +2019-09-30 * "肯德基(张江高科餐厅)" "张江高科餐厅" + Expenses:Food 27.00 CNY + Liabilities:CreditCard:Test -27.00 CNY -2021-02-06 * "医院" "住院预交金" - Expenses:Medical 3000.00 CNY - Liabilities:CreditCard:Test -3000.00 CNY +2019-09-30 * "麦当劳" "麦当劳" + Expenses:Food 27.00 CNY + Liabilities:CreditCard:Test -27.00 CNY + +2020-11-01 * "肯德基会员官方旗舰店" "【狂欢价】电子券码 Y132 肯德基 潮汉堡双人餐兑换券" + Expenses:Food 83.00 CNY + Liabilities:CreditCard:Test -83.00 CNY 2020-11-01 * "肯德基会员官方旗舰店" "退款-【狂欢价】电子券码 Y132 肯德基 潮汉堡双人餐兑换券" Liabilities:CreditCard:Test 83.00 CNY Expenses:Food -83.00 CNY -2020-11-01 * "肯德基会员官方旗舰店" "【狂欢价】电子券码 Y132 肯德基 潮汉堡双人餐兑换券" - Expenses:Food 83.00 CNY - Liabilities:CreditCard:Test -83.00 CNY +2021-02-06 * "医院" "住院预交金" + Expenses:Medical 3000.00 CNY + Liabilities:CreditCard:Test -3000.00 CNY + +2021-02-06 * "医院" "退款-住院预交金" + Liabilities:CreditCard:Test 2725.42 CNY + Expenses:Medical -2725.42 CNY diff --git a/example/alipay/example-alipay-records.csv b/example/alipay/example-alipay-records.csv index a9e2f14..564a193 100644 --- a/example/alipay/example-alipay-records.csv +++ b/example/alipay/example-alipay-records.csv @@ -4,6 +4,7 @@ ---------------------------------׼¼ϸб------------------------------------ ׺ ,̼Ҷ ,״ʱ ,ʱ ,޸ʱ ,Դ , ,׶Է ,Ʒ ,Ԫ ,/֧ ,״̬ ,ѣԪ ,ɹ˿Ԫ ,ע ,ʽ״̬ , 123456 ,S123456 ,2019-09-30 13:11:25 ,2019-09-30 13:11:25 ,2019-09-30 13:11:25 ,Ͱͺⲿ̼ң,ʱ˽ ,ϵ»(Ž߿Ʋ) ,Ž߿Ʋ ,27.00 ,֧ ,׳ɹ ,0.00 ,0.00 , ,֧ , +123456 ,S123456 ,2019-09-30 13:11:25 ,2019-09-30 13:11:25 ,2019-09-30 13:11:25 ,Ͱͺⲿ̼ң,ʱ˽ , , ,27.00 ,֧ ,׳ɹ ,0.00 ,0.00 , ,֧ , 123456 , ,2019-09-30 05:26:50 , ,2019-09-30 05:26:50 ,֧վ ,ʱ˽ ,ŷ޹˾ ,-2019.09.29-淢 ,0.01 , ,׳ɹ ,0.00 ,0.00 , , , 987654_321 ,S123456 ,2021-02-06 14:53:31 , ,2021-02-06 14:53:31 ,Ͱͺⲿ̼ң,ʱ˽ ,ҽԺ ,˿-סԺԤ ,2725.42 , ,˿ɹ ,0.00 ,0.00 , , , 987654 ,S123456 ,2021-02-06 10:01:39 ,2021-02-06 10:01:43 ,2021-02-06 14:53:30 ,Ͱͺⲿ̼ң,ʱ˽ ,ҽԺ ,סԺԤ ,3000.00 ,֧ ,׳ɹ ,0.00 ,2725.42 , ,֧ , diff --git a/example/wechat/config.yaml b/example/wechat/config.yaml index e823efe..250c479 100644 --- a/example/wechat/config.yaml +++ b/example/wechat/config.yaml @@ -14,9 +14,8 @@ wechat: item: / targetAccount: Assets:Digital:WeChat:Cash - - peer: 云膳过桥米线 - targetAccount: Expenses:Food:Meal - - peer: 餐厅 + - peer: 云膳过桥米线,餐厅 + sep: ',' targetAccount: Expenses:Food:Meal - peer: 房东 diff --git a/example/wechat/example-wechat-output.bean b/example/wechat/example-wechat-output.beancount similarity index 100% rename from example/wechat/example-wechat-output.bean rename to example/wechat/example-wechat-output.beancount index 567beaf..8b836ab 100644 --- a/example/wechat/example-wechat-output.bean +++ b/example/wechat/example-wechat-output.beancount @@ -1,32 +1,24 @@ option "title" "测试" option "operating_currency" "CNY" -1970-01-01 open Income:Wechat:RedPacket 1970-01-01 open Assets:Digital:WeChat:Cash 1970-01-01 open Income:Service -1970-01-01 open Assets:Bank:CN:ICBC:Savings +1970-01-01 open Expenses:FIXME +1970-01-01 open Assets:FIXME +1970-01-01 open Assets:Bank:CN:BOC:Savings +1970-01-01 open Income:Wechat:RedPacket 1970-01-01 open Expenses:Food:Meal 1970-01-01 open Expenses:Housing:Rent 1970-01-01 open Assets:Digital:Wechat:Cash -1970-01-01 open Assets:Bank:CN:BOC:Savings -1970-01-01 open Expenses:FIXME -1970-01-01 open Assets:FIXME - -2019-09-26 * "云膳过桥米线(传奇广场店)" "总共消费:28.16" - Expenses:Food:Meal 28.16 CNY - Assets:Bank:CN:BOC:Savings -28.16 CNY +1970-01-01 open Assets:Bank:CN:ICBC:Savings 2019-09-24 * "同性好友" "/" Assets:Digital:Wechat:Cash 0.35 CNY Income:Wechat:RedPacket -0.35 CNY -2021-01-17 * "某餐厅" "收款方备注:二维码收款" - Expenses:Food:Meal 12.00 CNY - Assets:Digital:Wechat:Cash -12.00 CNY - -2021-01-22 * "房东" "转账备注:微信转账" - Expenses:Housing:Rent 500.00 CNY - Assets:Digital:Wechat:Cash -500.00 CNY +2019-09-26 * "云膳过桥米线(传奇广场店)" "总共消费:28.16" + Expenses:Food:Meal 28.16 CNY + Assets:Bank:CN:BOC:Savings -28.16 CNY 2020-11-27 * "用户A" "收款方备注:二维码收款" Assets:Digital:Wechat:Cash 23.00 CNY @@ -36,3 +28,11 @@ option "operating_currency" "CNY" Assets:Digital:WeChat:Cash 2000.00 CNY Assets:Bank:CN:ICBC:Savings -2000.00 CNY +2021-01-17 * "某餐厅" "收款方备注:二维码收款" + Expenses:Food:Meal 12.00 CNY + Assets:Digital:Wechat:Cash -12.00 CNY + +2021-01-22 * "房东" "转账备注:微信转账" + Expenses:Housing:Rent 500.00 CNY + Assets:Digital:Wechat:Cash -500.00 CNY + diff --git a/pkg/analyser/alipay/alipay.go b/pkg/analyser/alipay/alipay.go index 6b30544..a5d01f2 100644 --- a/pkg/analyser/alipay/alipay.go +++ b/pkg/analyser/alipay/alipay.go @@ -5,6 +5,7 @@ import ( "github.com/gaocegege/double-entry-generator/pkg/config" "github.com/gaocegege/double-entry-generator/pkg/ir" + "github.com/gaocegege/double-entry-generator/pkg/util" ) type Alipay struct { @@ -41,15 +42,16 @@ func (a Alipay) GetAccounts(o *ir.Order, cfg *config.Config, target, provider st for _, r := range cfg.Alipay.Rules { match := true + // get seperator + sep := "," + if r.Separator != nil { + sep = *r.Separator + } if r.Peer != nil { - if !strings.Contains(o.Peer, *r.Peer) { - match = false - } + match = util.SplitFindContains(*r.Peer, o.Peer, sep, match) } if r.Item != nil { - if !strings.Contains(o.Item, *r.Item) { - match = false - } + match = util.SplitFindContains(*r.Item, o.Item, sep, match) } if r.StartTime != nil && r.EndTime != nil { // TODO(gaocegege): Support it. diff --git a/pkg/analyser/huobi/huobi.go b/pkg/analyser/huobi/huobi.go index cda137a..1fca157 100644 --- a/pkg/analyser/huobi/huobi.go +++ b/pkg/analyser/huobi/huobi.go @@ -1,10 +1,9 @@ package huobi import ( - "strings" - "github.com/gaocegege/double-entry-generator/pkg/config" "github.com/gaocegege/double-entry-generator/pkg/ir" + "github.com/gaocegege/double-entry-generator/pkg/util" ) type Huobi struct { @@ -38,13 +37,13 @@ func (h Huobi) GetAccounts(o *ir.Order, cfg *config.Config, target, provider str sep = *r.Seperator } if r.Type != nil { - match = SplitFindContains(*r.Type, o.TypeOriginal, sep, match) + match = util.SplitFindContains(*r.Type, o.TypeOriginal, sep, match) } if r.TxType != nil { - match = SplitFindContains(*r.TxType, o.TxTypeOriginal, sep, match) + match = util.SplitFindContains(*r.TxType, o.TxTypeOriginal, sep, match) } if r.Item != nil { - match = SplitFindContains(*r.Item, o.Item, sep, match) + match = util.SplitFindContains(*r.Item, o.Item, sep, match) } if match { @@ -70,18 +69,3 @@ func (h Huobi) GetAccounts(o *ir.Order, cfg *config.Config, target, provider str ir.PnlAccount: pnlAccount, } } - -func SplitFindContains(str, target, sep string, match bool) bool { - ss := strings.Split(str, sep) - isContain := false - for _, s := range ss { - if strings.Contains(target, s) { - isContain = true - break - } - } - if !isContain { - return false - } - return match -} diff --git a/pkg/analyser/wechat/wechat.go b/pkg/analyser/wechat/wechat.go index 12ea2f3..bad28aa 100644 --- a/pkg/analyser/wechat/wechat.go +++ b/pkg/analyser/wechat/wechat.go @@ -1,10 +1,9 @@ package wechat import ( - "strings" - "github.com/gaocegege/double-entry-generator/pkg/config" "github.com/gaocegege/double-entry-generator/pkg/ir" + "github.com/gaocegege/double-entry-generator/pkg/util" ) type Wechat struct { @@ -43,32 +42,28 @@ func (w Wechat) GetAccounts(o *ir.Order, cfg *config.Config, target, provider st for _, r := range cfg.Wechat.Rules { match := true + // get seperator + sep := "," + if r.Seperator != nil { + sep = *r.Seperator + } if r.Peer != nil { - if !strings.Contains(o.Peer, *r.Peer) { - match = false - } + match = util.SplitFindContains(*r.Peer, o.Peer, sep, match) } if r.Type != nil { - if !strings.Contains(o.TypeOriginal, *r.Type) { - match = false - } + match = util.SplitFindContains(*r.Type, o.TypeOriginal, sep, match) } if r.Method != nil { - if !strings.Contains(o.Method, *r.Method) { - match = false - } + match = util.SplitFindContains(*r.Method, o.Method, sep, match) } if r.Item != nil { - if !strings.Contains(o.Item, *r.Item) { - match = false - } + match = util.SplitFindContains(*r.Item, o.Item, sep, match) } if r.StartTime != nil && r.EndTime != nil { // TODO(gaocegege): Support it. } if match { // Support multiple matches, like one rule matches the minus accout, the other rule matches the plus account. - // FIXME(TripleZ): two-layer if... can u refact it? if r.TargetAccount != nil { if o.TxType == ir.TxTypeRecv { resMinus = *r.TargetAccount diff --git a/pkg/provider/alipay/config.go b/pkg/provider/alipay/config.go index e5b271c..a86df87 100644 --- a/pkg/provider/alipay/config.go +++ b/pkg/provider/alipay/config.go @@ -18,15 +18,16 @@ package alipay // Config is the configuration for Alipay. type Config struct { - Rules []Rule `yaml:"rules,omitempty"` + Rules []Rule `mapstructure:"rules,omitempty"` } // Rule is the type for match rules. type Rule struct { - Peer *string `yaml:"peer,omitempty"` - Item *string `yaml:"item,omitempty"` - StartTime *string `yaml:"startTime,omitempty"` - EndTime *string `yaml:"endTime,omitempty"` - MinusAccount *string `yaml:"minusAccount,omitempty"` - PlusAccount *string `yaml:"plusAccount,omitempty"` + Peer *string `mapstructure:"peer,omitempty"` + Item *string `mapstructure:"item,omitempty"` + Separator *string `mapstructure:"sep,omitempty"` // default: , + StartTime *string `mapstructure:"startTime,omitempty"` + EndTime *string `mapstructure:"endTime,omitempty"` + MinusAccount *string `mapstructure:"minusAccount,omitempty"` + PlusAccount *string `mapstructure:"plusAccount,omitempty"` } diff --git a/pkg/provider/huobi/config.go b/pkg/provider/huobi/config.go index 1e782ca..09aaed0 100644 --- a/pkg/provider/huobi/config.go +++ b/pkg/provider/huobi/config.go @@ -1,17 +1,17 @@ package huobi type Config struct { - Rules []Rule `yaml:"rules,omitempty"` + Rules []Rule `mapstructure:"rules,omitempty"` } type Rule struct { - // Peer *string `yaml:"peer,omitempty"` - Item *string `yaml:"item,omitempty"` // "BTC/USDT" - Type *string `yaml:"type,omitempty"` // "币币交易" - TxType *string `yaml:"txType,omitempty"` // "买入"、"卖出" - Seperator *string `yaml:"sep,omitempty"` // default: , - CashAccount *string `yaml:"cashAccount,omitempty"` - PositionAccount *string `yaml:"positionAccount,omitempty"` - CommissionAccount *string `yaml:"commissionAccount,omitempty"` - PnlAccount *string `yaml:"pnlAccount,omitempty"` + // Peer *string `mapstructure:"peer,omitempty"` + Item *string `mapstructure:"item,omitempty"` // "BTC/USDT" + Type *string `mapstructure:"type,omitempty"` // "币币交易" + TxType *string `mapstructure:"txType,omitempty"` // "买入"、"卖出" + Seperator *string `mapstructure:"sep,omitempty"` // default: , + CashAccount *string `mapstructure:"cashAccount,omitempty"` + PositionAccount *string `mapstructure:"positionAccount,omitempty"` + CommissionAccount *string `mapstructure:"commissionAccount,omitempty"` + PnlAccount *string `mapstructure:"pnlAccount,omitempty"` } diff --git a/pkg/provider/wechat/config.go b/pkg/provider/wechat/config.go index c79c545..fa12782 100644 --- a/pkg/provider/wechat/config.go +++ b/pkg/provider/wechat/config.go @@ -18,17 +18,18 @@ package wechat // Config is the configuration for Alipay. type Config struct { - Rules []Rule `yaml:"rules,omitempty"` + Rules []Rule `mapstructure:"rules,omitempty"` } // Rule is the type for match rules. type Rule struct { - Peer *string `yaml:"peer,omitempty"` - Item *string `yaml:"item,omitempty"` - Type *string `yaml:"type,omitempty"` - Method *string `yaml:"method,omitempty"` - StartTime *string `yaml:"startTime,omitempty"` - EndTime *string `yaml:"endTime,omitempty"` - MethodAccount *string `yaml:"methodAccount,omitempty"` - TargetAccount *string `yaml:"targetAccount,omitempty"` + Peer *string `mapstructure:"peer,omitempty"` + Item *string `mapstructure:"item,omitempty"` + Type *string `mapstructure:"type,omitempty"` + Seperator *string `mapstructure:"sep,omitempty"` // default: , + Method *string `mapstructure:"method,omitempty"` + StartTime *string `mapstructure:"startTime,omitempty"` + EndTime *string `mapstructure:"endTime,omitempty"` + MethodAccount *string `mapstructure:"methodAccount,omitempty"` + TargetAccount *string `mapstructure:"targetAccount,omitempty"` } diff --git a/pkg/util/util.go b/pkg/util/util.go new file mode 100644 index 0000000..00167e8 --- /dev/null +++ b/pkg/util/util.go @@ -0,0 +1,18 @@ +package util + +import "strings" + +func SplitFindContains(str, target, sep string, match bool) bool { + ss := strings.Split(str, sep) + isContain := false + for _, s := range ss { + if strings.Contains(target, s) { + isContain = true + break + } + } + if !isContain { + return false + } + return match +}