plumas iff -banks=plumas

master
Bel LaPointe 2025-10-20 15:11:47 -06:00
parent d794a4db52
commit b920ea80c8
3 changed files with 62 additions and 0 deletions

View File

@ -9,6 +9,7 @@ const (
BankOfAmerica BankOfAmerica
Fidelity Fidelity
Amex Amex
Plumas
) )
func (b Bank) String() string { func (b Bank) String() string {
@ -25,6 +26,8 @@ func (b Bank) String() string {
return "UCCU" return "UCCU"
case Amex: case Amex:
return "AmericanExpress" return "AmericanExpress"
case Plumas:
return "Plumas"
} }
return "?" return "?"
} }

View File

@ -96,6 +96,7 @@ func NewConfig() Config {
UCCU: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(UCCU.String())), UCCU: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(UCCU.String())),
Fidelity: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Fidelity.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())), 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) log.Printf("config: %+v", config)

View File

@ -23,6 +23,7 @@ type chaseScraper struct{}
type citiScraper struct{} type citiScraper struct{}
type uccuScraper struct{} type uccuScraper struct{}
type amexScraper struct{} type amexScraper struct{}
type plumasScraper struct{}
func Scrape(m *mail.Message, banks map[Bank]bool) ([]*Transaction, error) { func Scrape(m *mail.Message, banks map[Bank]bool) ([]*Transaction, error) {
scraper, err := buildScraper(m, banks) 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] { if strings.Contains(from, "Notifications@uccu.com") && banks[UCCU] {
return newUCCUScraper(), nil 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] { if strings.Contains(strings.ToLower(from), strings.ToLower("AmericanExpress")) && banks[Amex] {
return newAmexScraper(), nil return newAmexScraper(), nil
} }
@ -83,6 +87,10 @@ func newAmexScraper() scraper {
return &amexScraper{} return &amexScraper{}
} }
func newPlumasScraper() scraper {
return &plumasScraper{}
}
func containsAny(a string, b ...string) bool { func containsAny(a string, b ...string) bool {
for i := range b { for i := range b {
if strings.Contains(a, b[i]) { if strings.Contains(a, b[i]) {
@ -531,6 +539,56 @@ func (c *bankOfAmericaScraper) scrapePayment(m *mail.Message) ([]*Transaction, e
return []*Transaction{transaction}, nil 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) { func findSubstringBetween(b []byte, prefix, suffix string) (string, bool) {
byPre := bytes.Split(b, []byte(prefix)) byPre := bytes.Split(b, []byte(prefix))
if len(byPre) < 2 { if len(byPre) < 2 {