diff --git a/.gitignore b/.gitignore index bc56c9a..ed220ec 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ *.out .vscode/ +.idea/ bin/ wasm-dist/ diff --git a/README.md b/README.md index f23ee31..e692d7d 100644 --- a/README.md +++ b/README.md @@ -427,6 +427,7 @@ alipay: > - `11:00-13:00` > - `11:00:00-13:00:00` > 24 小时制,起始时间和终止之间之间使用 `-` 分隔。 +- `minPrice`(最小金额)和 `maxPrice`(最大金额)的区间匹配。 在单条规则中可以使用分隔符(sep)填写多个关键字,在同一对象中,每个关键字之间是或的关系。 @@ -556,6 +557,7 @@ wechat: > - `11:00-13:00` > - `11:00:00-13:00:00` > 24 小时制,起始时间和终止之间之间使用 `-` 分隔。 +- `minPrice`(最小金额)和 `maxPrice`(最大金额)的区间匹配。 在单条规则中可以使用分隔符(sep)填写多个关键字,在同一对象中,每个关键字之间是或的关系。 diff --git a/example/alipay/config.yaml b/example/alipay/config.yaml index ce63c76..69abb57 100644 --- a/example/alipay/config.yaml +++ b/example/alipay/config.yaml @@ -15,7 +15,12 @@ alipay: methodAccount: Assets:Alipay - category: 日用百货 + minPrice: 10 targetAccount: Expenses:Groceries + - category: 日用百货 + minPrice: 0 + maxPrice: 9.99 + targetAccount: Expenses:Food:Drink - category: 餐饮美食 time: 11:00-14:00 targetAccount: Expenses:Food:Lunch diff --git a/example/alipay/example-alipay-output.beancount b/example/alipay/example-alipay-output.beancount index 84142cd..5945291 100644 --- a/example/alipay/example-alipay-output.beancount +++ b/example/alipay/example-alipay-output.beancount @@ -8,6 +8,7 @@ option "operating_currency" "CNY" 1970-01-01 open Expenses:Electronics 1970-01-01 open Expenses:FIXME 1970-01-01 open Expenses:Food:Dinner +1970-01-01 open Expenses:Food:Drink 1970-01-01 open Expenses:Food:Lunch 1970-01-01 open Expenses:Groceries 1970-01-01 open Expenses:Insurance @@ -75,3 +76,25 @@ option "operating_currency" "CNY" Expenses:FIXME 49.74 CNY Liabilities:CC:COMM:7449 -49.74 CNY +2023-07-10 * "xxxx" "xxxx" + category: "日用百货" + merchantId: "xxxx" + orderId: "xxxx" + payTime: "2023-07-10 13:10:16 +0800 CST" + source: "支付宝" + status: "交易成功" + type: "支出" + Expenses:Food:Drink 9.90 CNY + Assets:FIXME -9.90 CNY + +2023-07-10 * "xxxx" "xxxx" + category: "日用百货" + merchantId: "xxxx" + orderId: "xxxx" + payTime: "2023-07-10 13:20:16 +0800 CST" + source: "支付宝" + status: "交易成功" + type: "支出" + Expenses:Groceries 82.00 CNY + Assets:FIXME -82.00 CNY + diff --git a/example/alipay/example-alipay-output.ledger b/example/alipay/example-alipay-output.ledger index e699efd..faae03b 100644 --- a/example/alipay/example-alipay-output.ledger +++ b/example/alipay/example-alipay-output.ledger @@ -6,6 +6,7 @@ Expenses:Electronics 0 CNY Expenses:FIXME 0 CNY Expenses:Food:Dinner 0 CNY + Expenses:Food:Drink 0 CNY Expenses:Food:Lunch 0 CNY Expenses:Groceries 0 CNY Expenses:Insurance 0 CNY @@ -73,3 +74,25 @@ Expenses:FIXME 49.74 CNY Liabilities:CC:COMM:7449 - 49.74 CNY +2023/07/10 * xxxx - xxxx + ; category: "日用百货" + ; merchantId: "xxxx" + ; orderId: "xxxx" + ; payTime: "2023-07-10 13:10:16 +0800 CST" + ; source: "支付宝" + ; status: "交易成功" + ; type: "支出" + Expenses:Food:Drink 9.90 CNY + Assets:FIXME - 9.90 CNY + +2023/07/10 * xxxx - xxxx + ; category: "日用百货" + ; merchantId: "xxxx" + ; orderId: "xxxx" + ; payTime: "2023-07-10 13:20:16 +0800 CST" + ; source: "支付宝" + ; status: "交易成功" + ; type: "支出" + Expenses:Groceries 82.00 CNY + Assets:FIXME - 82.00 CNY + diff --git a/example/alipay/example-alipay-records.csv b/example/alipay/example-alipay-records.csv index 3e590d4..8fc55c3 100644 --- a/example/alipay/example-alipay-records.csv +++ b/example/alipay/example-alipay-records.csv @@ -31,3 +31,5 @@ 2023-01-10 13:10:16,ðٻ,xxxx,/,xxxx,֧,82.00,,׹ر,xxxx ,xxxx ,, 2023-01-09 18:22:28,˿,һͨ,fin***@jieyisoft.com,˿-һֵͨ,֧,50.00,,˿ɹ,2023xxxxx88_2023xx57 ,D12*****14 ,, 2023-01-09 18:21:50,ͨ,һͨ,fin***@jieyisoft.com,һֵͨ,֧,50.00,,׹ر,2023xxxxx88 ,D12*****14 ,, +2023-07-10 13:10:16,ðٻ,xxxx,/,xxxx,֧,9.90,,׳ɹ,xxxx ,xxxx ,, +2023-07-10 13:20:16,ðٻ,xxxx,/,xxxx,֧,82.00,,׳ɹ,xxxx ,xxxx ,, diff --git a/example/wechat/config.yaml b/example/wechat/config.yaml index fcf5973..5dbd90e 100644 --- a/example/wechat/config.yaml +++ b/example/wechat/config.yaml @@ -44,6 +44,16 @@ wechat: time: 23:50-00:05 # test T-1 targetAccount: Expenses:Food:Meal:MidNight + - peer: 美团平台商户 + type: 支出 + minPrice: 0 + maxPrice: 9.99 + targetAccount: Expenses:Food:Drink + - peer: 美团平台商户 + type: 支出 + minPrice: 10 + targetAccount: Expenses:Food:Meal + - peer: 房东 type: 支出 targetAccount: Expenses:Housing:Rent diff --git a/example/wechat/example-wechat-output.beancount b/example/wechat/example-wechat-output.beancount index b5ab792..3e7dd26 100644 --- a/example/wechat/example-wechat-output.beancount +++ b/example/wechat/example-wechat-output.beancount @@ -7,6 +7,8 @@ option "operating_currency" "CNY" 1970-01-01 open Assets:FIXME 1970-01-01 open Assets:Trade:Tencent:LiCaiTong 1970-01-01 open Expenses:FIXME +1970-01-01 open Expenses:Food:Drink +1970-01-01 open Expenses:Food:Meal 1970-01-01 open Expenses:Food:Meal:Dinner 1970-01-01 open Expenses:Food:Meal:Lunch 1970-01-01 open Expenses:Food:Meal:MidNight @@ -276,3 +278,27 @@ option "operating_currency" "CNY" Assets:Digital:Wechat:Cash 5.00 CNY Income:Wechat:RedPacket -5.00 CNY +2023-07-09 * "美团平台商户" "美团订单-12345" + merchantId: "654321" + method: "工商银行" + orderId: "123456" + payTime: "2023-07-09 13:25:22 +0800 CST" + source: "微信支付" + status: "支付成功" + txType: "商户消费" + type: "支出" + Expenses:Food:Drink 9.90 CNY + Assets:Bank:CN:ICBC:Savings -9.90 CNY + +2023-07-09 * "美团平台商户" "美团订单-54321" + merchantId: "654321" + method: "工商银行" + orderId: "123456" + payTime: "2023-07-09 13:30:22 +0800 CST" + source: "微信支付" + status: "支付成功" + txType: "商户消费" + type: "支出" + Expenses:Food:Meal 50.00 CNY + Assets:Bank:CN:ICBC:Savings -50.00 CNY + diff --git a/example/wechat/example-wechat-output.ledger b/example/wechat/example-wechat-output.ledger index ae7126c..797d162 100644 --- a/example/wechat/example-wechat-output.ledger +++ b/example/wechat/example-wechat-output.ledger @@ -5,6 +5,8 @@ Assets:FIXME 0 CNY Assets:Trade:Tencent:LiCaiTong 0 CNY Expenses:FIXME 0 CNY + Expenses:Food:Drink 0 CNY + Expenses:Food:Meal 0 CNY Expenses:Food:Meal:Dinner 0 CNY Expenses:Food:Meal:Lunch 0 CNY Expenses:Food:Meal:MidNight 0 CNY @@ -275,3 +277,27 @@ Assets:Digital:Wechat:Cash 5.00 CNY Income:Wechat:RedPacket - 5.00 CNY +2023/07/09 * 美团平台商户 - 美团订单-12345 + ; merchantId: "654321" + ; method: "工商银行" + ; orderId: "123456" + ; payTime: "2023-07-09 13:25:22 +0800 CST" + ; source: "微信支付" + ; status: "支付成功" + ; txType: "商户消费" + ; type: "支出" + Expenses:Food:Drink 9.90 CNY + Assets:Bank:CN:ICBC:Savings - 9.90 CNY + +2023/07/09 * 美团平台商户 - 美团订单-54321 + ; merchantId: "654321" + ; method: "工商银行" + ; orderId: "123456" + ; payTime: "2023-07-09 13:30:22 +0800 CST" + ; source: "微信支付" + ; status: "支付成功" + ; txType: "商户消费" + ; type: "支出" + Expenses:Food:Meal 50.00 CNY + Assets:Bank:CN:ICBC:Savings - 50.00 CNY + diff --git a/example/wechat/example-wechat-records.csv b/example/wechat/example-wechat-records.csv index 3317256..deb1faa 100644 --- a/example/wechat/example-wechat-records.csv +++ b/example/wechat/example-wechat-records.csv @@ -37,3 +37,5 @@ 2022-07-18 10:48:09,商户消费,测试时间戳,点击底部"多多视频","/",收入,¥0.07,/,充值成功,160572459521071810106004542906137497131422938 ,10101265586742107189275763431049 ,"/" 2022-09-24 02:24:20,赞赏码,YingDev,"/",支出,¥36.99,零钱,朋友已收钱,100010810122092400064222561891707533 ,1000108101202209241820542253348 ,"/" 2023-06-23 11:01:51,其他,赞赏作者的收款_20230623,"/",收入,¥5.00,/,已到账,180000737623062310106004541373333333333333333 ,10101008588132306239222222222222 ,"赞赏作者的收款_20230623" +2023-07-09 13:25:22,商户消费,美团平台商户,"美团订单-12345",支出,¥9.90,工商银行,支付成功,123456 ,654321 ,"/" +2023-07-09 13:30:22,商户消费,美团平台商户,"美团订单-54321",支出,¥50.0,工商银行,支付成功,123456 ,654321 ,"/" diff --git a/pkg/analyser/alipay/alipay.go b/pkg/analyser/alipay/alipay.go index 02a4b6a..3538787 100644 --- a/pkg/analyser/alipay/alipay.go +++ b/pkg/analyser/alipay/alipay.go @@ -81,15 +81,21 @@ func (a Alipay) GetAccountsAndTags(o *ir.Order, cfg *config.Config, target, prov if r.Time != nil { match, err = util.SplitFindTimeInterval(*r.Time, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("%v", err) } } if r.TimestampRange != nil { match, err = util.SplitFindTimeStampInterval(*r.TimestampRange, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("%v", err) } } + if r.MinPrice != nil && o.Money < *r.MinPrice { + match = false + } + if r.MaxPrice != nil && o.Money > *r.MaxPrice { + match = false + } if match { if r.Ignore { diff --git a/pkg/analyser/htsec/htsec.go b/pkg/analyser/htsec/htsec.go index 9322749..cad0753 100644 --- a/pkg/analyser/htsec/htsec.go +++ b/pkg/analyser/htsec/htsec.go @@ -79,13 +79,13 @@ func (h Htsec) GetAccountsAndTags(o *ir.Order, cfg *config.Config, target, provi if r.Time != nil { match, err = util.SplitFindTimeInterval(*r.Time, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("%v", err) } } if r.TimestampRange != nil { match, err = util.SplitFindTimeStampInterval(*r.TimestampRange, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("%v", err) } } diff --git a/pkg/analyser/huobi/huobi.go b/pkg/analyser/huobi/huobi.go index 545ab3c..742e57b 100644 --- a/pkg/analyser/huobi/huobi.go +++ b/pkg/analyser/huobi/huobi.go @@ -82,13 +82,13 @@ func (h Huobi) GetAccountsAndTags(o *ir.Order, cfg *config.Config, target, provi if r.Time != nil { match, err = util.SplitFindTimeInterval(*r.Time, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("%v", err) } } if r.TimestampRange != nil { match, err = util.SplitFindTimeStampInterval(*r.TimestampRange, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("%v", err) } } if match { diff --git a/pkg/analyser/jd/jd.go b/pkg/analyser/jd/jd.go index b9f893f..32ad4ec 100644 --- a/pkg/analyser/jd/jd.go +++ b/pkg/analyser/jd/jd.go @@ -81,13 +81,13 @@ func (a JD) GetAccountsAndTags(o *ir.Order, cfg *config.Config, target, provider if r.Time != nil { match, err = util.SplitFindTimeInterval(*r.Time, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("%v", err) } } if r.TimestampRange != nil { match, err = util.SplitFindTimeStampInterval(*r.TimestampRange, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("%v", err) } } diff --git a/pkg/analyser/wechat/wechat.go b/pkg/analyser/wechat/wechat.go index b9db72c..72def07 100644 --- a/pkg/analyser/wechat/wechat.go +++ b/pkg/analyser/wechat/wechat.go @@ -93,15 +93,24 @@ func (w Wechat) GetAccountsAndTags(o *ir.Order, cfg *config.Config, target, prov if r.Time != nil { match, err = util.SplitFindTimeInterval(*r.Time, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("Error in SplitFindTimeInterval: %v", err) } } if r.TimestampRange != nil { match, err = util.SplitFindTimeStampInterval(*r.TimestampRange, o.PayTime, match) if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("Error in SplitFindTimeStampInterval: %v", err) } } + if r.MinPrice != nil && r.MaxPrice != nil && *r.MinPrice > *r.MaxPrice { + log.Fatalf("Error rule: minPrice > maxPrice!") + } + if r.MinPrice != nil && o.Money < *r.MinPrice { + match = false + } + if r.MaxPrice != nil && o.Money > *r.MaxPrice { + match = false + } if match { if r.Ignore { diff --git a/pkg/provider/alipay/config.go b/pkg/provider/alipay/config.go index e43dda6..ca5f1e9 100644 --- a/pkg/provider/alipay/config.go +++ b/pkg/provider/alipay/config.go @@ -23,18 +23,20 @@ type Config struct { // Rule is the type for match rules. type Rule struct { - Peer *string `mapstructure:"peer,omitempty"` - Item *string `mapstructure:"item,omitempty"` - Category *string `mapstructure:"category,omitempty"` - Type *string `mapstructure:"type,omitempty"` - Method *string `mapstructure:"method,omitempty"` - Separator *string `mapstructure:"sep,omitempty"` // default: , - Time *string `mapstructure:"time,omitempty"` - TimestampRange *string `mapstructure:"timestamp_range,omitempty"` - MethodAccount *string `mapstructure:"methodAccount,omitempty"` - TargetAccount *string `mapstructure:"targetAccount,omitempty"` - PnlAccount *string `mapstructure:"pnlAccount,omitempty"` - FullMatch bool `mapstructure:"fullMatch,omitempty"` - Tags *string `mapstructure:"tags,omitempty"` - Ignore bool `mapstructure:"ignore,omitempty"` // default: false + Peer *string `mapstructure:"peer,omitempty"` + Item *string `mapstructure:"item,omitempty"` + Category *string `mapstructure:"category,omitempty"` + Type *string `mapstructure:"type,omitempty"` + Method *string `mapstructure:"method,omitempty"` + Separator *string `mapstructure:"sep,omitempty"` // default: , + Time *string `mapstructure:"time,omitempty"` + TimestampRange *string `mapstructure:"timestamp_range,omitempty"` + MethodAccount *string `mapstructure:"methodAccount,omitempty"` + TargetAccount *string `mapstructure:"targetAccount,omitempty"` + PnlAccount *string `mapstructure:"pnlAccount,omitempty"` + FullMatch bool `mapstructure:"fullMatch,omitempty"` + Tags *string `mapstructure:"tags,omitempty"` + Ignore bool `mapstructure:"ignore,omitempty"` // default: false + MinPrice *float64 `mapstructure:"minPrice,omitempty"` + MaxPrice *float64 `mapstructure:"maxPrice,omitempty"` } diff --git a/pkg/provider/wechat/config.go b/pkg/provider/wechat/config.go index 044d6ef..721dbfd 100644 --- a/pkg/provider/wechat/config.go +++ b/pkg/provider/wechat/config.go @@ -23,18 +23,20 @@ type Config struct { // Rule is the type for match rules. type Rule struct { - Peer *string `mapstructure:"peer,omitempty"` - Item *string `mapstructure:"item,omitempty"` - Type *string `mapstructure:"type,omitempty"` - TxType *string `mapstructure:"txType,omitempty"` - Separator *string `mapstructure:"sep,omitempty"` // default: , - Method *string `mapstructure:"method,omitempty"` - Time *string `mapstructure:"time,omitempty"` - TimestampRange *string `mapstructure:"timestamp_range,omitempty"` - MethodAccount *string `mapstructure:"methodAccount,omitempty"` - TargetAccount *string `mapstructure:"targetAccount,omitempty"` - CommissionAccount *string `mapstructure:"commissionAccount,omitempty"` - FullMatch bool `mapstructure:"fullMatch,omitempty"` - Tag *string `mapstructure:"tag,omitempty"` - Ignore bool `mapstructure:"ignore,omitempty"` // default: false + Peer *string `mapstructure:"peer,omitempty"` + Item *string `mapstructure:"item,omitempty"` + Type *string `mapstructure:"type,omitempty"` + TxType *string `mapstructure:"txType,omitempty"` + Separator *string `mapstructure:"sep,omitempty"` // default: , + Method *string `mapstructure:"method,omitempty"` + Time *string `mapstructure:"time,omitempty"` + TimestampRange *string `mapstructure:"timestamp_range,omitempty"` + MethodAccount *string `mapstructure:"methodAccount,omitempty"` + TargetAccount *string `mapstructure:"targetAccount,omitempty"` + CommissionAccount *string `mapstructure:"commissionAccount,omitempty"` + FullMatch bool `mapstructure:"fullMatch,omitempty"` + Tag *string `mapstructure:"tag,omitempty"` + Ignore bool `mapstructure:"ignore,omitempty"` // default: false + MinPrice *float64 `mapstructure:"minPrice,omitempty"` + MaxPrice *float64 `mapstructure:"maxPrice,omitempty"` } diff --git a/pkg/provider/wechat/util.go b/pkg/provider/wechat/util.go index 52ba952..e75cb12 100644 --- a/pkg/provider/wechat/util.go +++ b/pkg/provider/wechat/util.go @@ -50,7 +50,7 @@ func getTxType(tt string) TxType { return TxTypeFamilyCard } else if strings.Contains(tt, string(TxTypeSponsorCode)) { return TxTypeSponsorCode - } else if strings.Contains(tt, string(TxTypeOther)){ + } else if strings.Contains(tt, string(TxTypeOther)) { return TxTypeOther } else { return TxTypeUnknown