diff --git a/scrape.go b/scrape.go index 43ade4f..49ca49a 100755 --- a/scrape.go +++ b/scrape.go @@ -297,6 +297,9 @@ func (c *uccuScraper) scrape(m *mail.Message) ([]*Transaction, error) { 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 { @@ -315,6 +318,30 @@ func (c *uccuScraper) scrape(m *mail.Message) ([]*Transaction, error) { return []*Transaction{transaction}, nil } +func (c *uccuScraper) 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 := UCCU.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"]), UCCU) + return []*Transaction{transaction}, nil +} + func (c *amexScraper) scrape(m *mail.Message) ([]*Transaction, error) { b, err := ioutil.ReadAll(m.Body) if err != nil { diff --git a/scrape_test.go b/scrape_test.go index ed4b485..a079fc7 100644 --- a/scrape_test.go +++ b/scrape_test.go @@ -41,6 +41,38 @@ func TestScrapeAmex(t *testing.T) { t.Logf("%+v", got) } +func TestScrapeUCCUBalance(t *testing.T) { + b, _ := os.ReadFile("testdata/uccu.balance.txt") + + message := &mail.Message{ + Header: map[string][]string{ + "Subject": []string{"UCCU Account Alert Notification"}, + }, + } + + uccu := &uccuScraper{} + + gots, err := uccu.scrapeBalance(message, b) + if err != nil { + t.Fatal(err) + } + if len(gots) != 1 { + t.Fatal(gots) + } + got := gots[0] + + if got.Account != "UCCU-33350" { + t.Fatalf("bad account: %v: %+v", got.Account, got) + } + if got.Amount != "=231.20" { + t.Fatalf("bad amount: %v: %+v", got.Amount, got) + } + if got.Vendor != "*" { + t.Fatalf("bad vendor: %v: %+v", got.Vendor, got) + } + t.Logf("%+v", got) +} + func TestScrapeFidelityBalance(t *testing.T) { b, _ := os.ReadFile("testdata/fidelity.balance.txt") diff --git a/testdata/uccu.balance.txt b/testdata/uccu.balance.txt new file mode 100644 index 0000000..9d0fc8a --- /dev/null +++ b/testdata/uccu.balance.txt @@ -0,0 +1,113 @@ +Delivered-To: breellocaldev@gmail.com +Received: by 2002:ac0:d587:0:b0:36b:891d:d518 with SMTP id f7csp8195321imh; + Sun, 19 Oct 2025 20:12:12 -0700 (PDT) +X-Google-Smtp-Source: AGHT+IFUgpNCx0iWHjiZ2ACXymtPllyGTHFvg3AZWvOx3YrM5uMz8x77KC3VIs4hxjkggj+ZNRuB +X-Received: by 2002:a05:6214:1c43:b0:87c:836:8f21 with SMTP id 6a1803df08f44-87c20594815mr163096026d6.21.1760929932283; + Sun, 19 Oct 2025 20:12:12 -0700 (PDT) +ARC-Seal: i=1; a=rsa-sha256; t=1760929932; cv=none; + d=google.com; s=arc-20240605; + b=kApQs1Ymlz+s8G0nYujuPNSJ3cs97QI0fmmz5g3n2bcpxmONxDWSUFjDTYoAJeW+15 + i/KuwuU1VusVWtJvg7KKJWwkmp7qeYVlkQmxq/v3IaZAM5p+OtJx8WmTqKePpCK5ZuiR + qrKdGfZAfnKMvN12F59N0WgHV0+wEMvi6AS2yKzZsVdY7UEq4o//ve3INHO4OeJjo2Uy + aXaUxAXGQZeDlv/v4mSSE8I0utowTDiGpEyoSnFUhJk7hmiG26JRF4YHQA/vjAc32mUK + jrKNjc15y4vw8LOT2ATm/jgeaZIQ0/8Z0ymQG8sLoQVhWe3WkxUK7Y9MxzLyeWCyCvRV + qBhA== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; + h=to:message-id:date:subject:from:mime-version:dkim-signature + :dkim-signature; + bh=k7jGHJ2ljFiolAPU5T6OwM+LnPG+3HzBJixYSB6L+E8=; + fh=lrt9myTdNYNEckm/XjduC9YuGfYr3v7r45vYTr/7vKM=; + b=iJeycLvOEG6ySvr9T2fxpvTqIGeYBeDcVxW5nrqqdKELVdqBMgHL9axXUn8RdUP8pW + RoZSRuNlIOaqCYGtGPjGGD0pWl/wexytBnV6yoHNNwTExfVBr6XvTQ+JPjyTu/L11O09 + 9x2oaN3Dc/JGjKVMMGVcD/AEXrhSjjsQYpNqyq+DADqssWiVgioB4jKCInnjPIgWkqnK + i820QlMqRmzZzIi4kR4LFL5uM0MyNwc1SU/l0EUYDBF3BMdOCQ1i2JrAw2hWD28OHjTZ + ORHBrQY2THy573M0gL1j83XZz5ph3wBLnHXkYpQYOL/kv7tKdIhIs1aKYobFL7evEKTt + zyDw==; + dara=google.com +ARC-Authentication-Results: i=1; mx.google.com; + dkim=pass header.i=@uccu.com header.s=s1 header.b=ICj11Mxp; + dkim=pass header.i=@sendgrid.info header.s=smtpapi header.b=v2gr3NCY; + spf=pass (google.com: domain of bounces+14101083-c28a-breellocaldev=gmail.com@sg.uccu.com designates 149.72.182.202 as permitted sender) smtp.mailfrom="bounces+14101083-c28a-breellocaldev=gmail.com@sg.uccu.com"; + dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=uccu.com +Return-Path: +Received: from o1.em.sg.q2ebanking.com (o1.em.sg.q2ebanking.com. [149.72.182.202]) + by mx.google.com with ESMTPS id 6a1803df08f44-87d02d89698si21675916d6.731.2025.10.19.20.12.12 + for + (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); + Sun, 19 Oct 2025 20:12:12 -0700 (PDT) +Received-SPF: pass (google.com: domain of bounces+14101083-c28a-breellocaldev=gmail.com@sg.uccu.com designates 149.72.182.202 as permitted sender) client-ip=149.72.182.202; +Authentication-Results: mx.google.com; + dkim=pass header.i=@uccu.com header.s=s1 header.b=ICj11Mxp; + dkim=pass header.i=@sendgrid.info header.s=smtpapi header.b=v2gr3NCY; + spf=pass (google.com: domain of bounces+14101083-c28a-breellocaldev=gmail.com@sg.uccu.com designates 149.72.182.202 as permitted sender) smtp.mailfrom="bounces+14101083-c28a-breellocaldev=gmail.com@sg.uccu.com"; + dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=uccu.com +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=uccu.com; h=mime-version:from:subject:content-type:date:to:cc:content-type:date: feedback-id:from:subject:to; s=s1; bh=k7jGHJ2ljFiolAPU5T6OwM+LnPG+3HzBJixYSB6L+E8=; b=ICj11Mxph/4neYlK/LfDIN1I/A/STnJE9NBuDTPPuIU5SrWgvbrcHxdSRshjnygf1s6u RLkV/0jB1sMd/5hcmIQu0VLkJLbfpgLt9VAbP4+nNjVLn+YFNYWdgy8Y1eDsA8otUY5MPa E6Ojm1Dx1Z9AHZM/YS4cG5aK+090dDESsMnzpNRhGgLmnVhzR6J9rQj25u0G/g3trM0pNL mdadIuRde77nr/5OszQHLVNr1HRg6kbf4duco9blG05qWMpdbO9HZW83iPKZ5vLsnuTy9i tPxn+Hg6BNPHzI1PysBxgWsbV33VXt1v+J+PTQ5f/Bu4BSvF+fvtwK8Lo5UNRhAQ== +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sendgrid.info; h=mime-version:from:subject:content-type:date:to:cc:content-type:date: feedback-id:from:subject:to; s=smtpapi; bh=k7jGHJ2ljFiolAPU5T6OwM+LnPG+3HzBJixYSB6L+E8=; b=v2gr3NCY2aTS6WJkQB+uhaChiF3jnvSZDZpZrF4al1Fbm75q0wzWL4kt+m8jZyHzFflr +WpE8JcjyWo0jvhS6VjPUxQzIl2ZbOt0laHQMyQZEZbZQQCjVY8BGBx8wWJKfwRn9569wH +FuyXlox0CHwFCxqfeIVKKBeiIPrtMDsw= +Received: by recvd-7f4fb8995-jgz2d with SMTP id recvd-7f4fb8995-jgz2d-1-68F5A88B-E 2025-10-20 03:12:11.990860065 +0000 UTC m=+11874446.569028758 +Received: from use1-postfix-shs-prd-001a.q2.internal (unknown) by geopod-ismtpd-26 (SG) with ESMTP id 9Jzm7g1dQxW6QvcyQoTs6A for ; Mon, 20 Oct 2025 03:12:11.966 +0000 (UTC) +Received: from localhost (ip-10-233-152-95.ec2.internal [10.233.152.95]) by use1-postfix-shs-prd-001a.q2.internal (Postfix) with UTF8SMTP id C4917B4727 for ; Mon, 20 Oct 2025 03:12:11 +0000 (UTC) +MIME-Version: 1.0 +From: Notifications@uccu.com +Subject: UCCU Account Alert Notification +Content-Type: multipart/alternative; boundary=1c6f2f280d6200ff5d69ad23e6f5273369aefc9f9ac30cf0c16c4288a093 +Date: Mon, 20 Oct 2025 03:12:12 +0000 (UTC) +Message-ID: <9Jzm7g1dQxW6QvcyQoTs6A@geopod-ismtpd-26> +X-SG-EID: u001.g3f8YwzV+uExvNyHXs20qs20kPT4Xr5yKfd6Jo1DS06qVgodwVcYFczS2kDS38t+kK3dSvo5nZC1MPxUDC3ru0wgAcAHPFVQv8BD/b/gkmc5AuFBZcSIQClE4ZT0W+naP4PHr7dyrI5P8IsN5P6ujZD0kASrUjlUoRuemNpmREOkP4aiIOtJ2tuZrJAeh2feDTZY4aT4tGpvaYcbz3KKFg== +To: breellocaldev@gmail.com +X-Entity-ID: u001.dyI+c5ymAHdeWQ9Y++I+vA== + +--1c6f2f280d6200ff5d69ad23e6f5273369aefc9f9ac30cf0c16c4288a093 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; charset=us-ascii + +This is your requested account alert notification. + +Additional details are available in your online secure mailbox. + + +As this is an automated reminder, please do not reply to this email. + + +--1c6f2f280d6200ff5d69ad23e6f5273369aefc9f9ac30cf0c16c4288a093 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/html; charset=us-ascii + +Secure Banking: Requested Information<= +/head> +--1c6f2f280d6200ff5d69ad23e6f5273369aefc9f9ac30cf0c16c4288a093--
3D"Utah
This is your requested Current Balance alert n= +otification. Your Current Balance is greater than your specified alert valu= +e of 0.000 for Checking ending in 33350. The new Current Balance is $231.20= +.

Additional details are available in your online secure mailbox.<= +br/>

As this is an automated reminder, please do not reply to this= + email.

This email= + has been automatically generated by request. This electronic transmission = +is confidential and is intended for designated recipients only. If you have= + received this message in error, please delete the original and all copies = +and notify the sender immediately. To ensure that you continue receiving ou= +r emails, please add us to your address book or safe list.