diff --git a/bank.go b/bank.go index a47c9c6..4bde762 100755 --- a/bank.go +++ b/bank.go @@ -9,6 +9,7 @@ const ( BankOfAmerica Fidelity Amex + Plumas ) func (b Bank) String() string { @@ -25,6 +26,8 @@ func (b Bank) String() string { return "UCCU" case Amex: return "AmericanExpress" + case Plumas: + return "Plumas" } return "?" } diff --git a/config.go b/config.go index 40aaed8..0ebd08a 100755 --- a/config.go +++ b/config.go @@ -96,6 +96,7 @@ func NewConfig() Config { UCCU: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(UCCU.String())), Fidelity: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Fidelity.String())), Amex: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Amex.String())), + Plumas: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Plumas.String())), }, } log.Printf("config: %+v", config) diff --git a/scrape.go b/scrape.go index 49ca49a..bbaf316 100755 --- a/scrape.go +++ b/scrape.go @@ -23,6 +23,7 @@ type chaseScraper struct{} type citiScraper struct{} type uccuScraper struct{} type amexScraper struct{} +type plumasScraper struct{} func Scrape(m *mail.Message, banks map[Bank]bool) ([]*Transaction, error) { scraper, err := buildScraper(m, banks) @@ -53,6 +54,9 @@ func buildScraper(m *mail.Message, banks map[Bank]bool) (scraper, error) { if strings.Contains(from, "Notifications@uccu.com") && banks[UCCU] { return newUCCUScraper(), nil } + if strings.Contains(from, "Notifications@plumasbank.com") && banks[Plumas] { + return newPlumasScraper(), nil + } if strings.Contains(strings.ToLower(from), strings.ToLower("AmericanExpress")) && banks[Amex] { return newAmexScraper(), nil } @@ -83,6 +87,10 @@ func newAmexScraper() scraper { return &amexScraper{} } +func newPlumasScraper() scraper { + return &plumasScraper{} +} + func containsAny(a string, b ...string) bool { for i := range b { if strings.Contains(a, b[i]) { @@ -531,6 +539,56 @@ func (c *bankOfAmericaScraper) scrapePayment(m *mail.Message) ([]*Transaction, e return []*Transaction{transaction}, nil } +func (c *plumasScraper) scrape(m *mail.Message) ([]*Transaction, error) { + b, err := ioutil.ReadAll(m.Body) + if err != nil { + return nil, err + } + if bytes.Contains(b, []byte(`alance alert`)) { + return c.scrapeBalance(m, b) + } + regexp := regexp.MustCompile(`\$([0-9]+,?)+\.[0-9][0-9]`) + match := regexp.Find(b) + if len(match) == 0 { + return nil, fmt.Errorf("no matches found") + } + match = match[1:] + match = bytes.ReplaceAll(match, []byte(","), []byte{}) + f, err := strconv.ParseFloat(string(match), 10) + if err != nil { + return nil, err + } + if !bytes.Contains(b, []byte("credit")) { + f *= -1.0 + } + transaction := NewTransaction(Plumas.String(), fmt.Sprintf("%.2f", f), "?", fmt.Sprint(m.Header["Date"]), Plumas) + return []*Transaction{transaction}, nil +} + +func (c *plumasScraper) scrapeBalance(m *mail.Message, b []byte) ([]*Transaction, error) { + re := regexp.MustCompile(`is \$([0-9]+,?)+\.[0-9][0-9]`) + match := re.Find(b) + if len(match) == 0 { + return nil, fmt.Errorf("no matches found") + } + match = match[4:] + match = bytes.ReplaceAll(match, []byte(","), []byte{}) + f, err := strconv.ParseFloat(string(match), 10) + if err != nil { + return nil, err + } + + acc := Plumas.String() + re = regexp.MustCompile(`ending in [0-9]*`) + match = re.Find(b) + if len(match) > 0 { + acc = fmt.Sprintf("%s-%s", acc, match[len(`ending in `):]) + } + + transaction := NewTransaction(acc, fmt.Sprintf("=%.2f", f), "*", fmt.Sprint(m.Header["Date"]), Plumas) + return []*Transaction{transaction}, nil +} + func findSubstringBetween(b []byte, prefix, suffix string) (string, bool) { byPre := bytes.Split(b, []byte(prefix)) if len(byPre) < 2 {