feat(watcher): add Tokopedia order parsing and rules

Implement parsing for Tokopedia "Pesanan Selesai" messages, including support for single and multi-item orders. Update rules to recognize Tokopedia order completion and enhance spending record mapping. Add tests to validate new functionality.
This commit is contained in:
2026-09-13 23:58:23 +07:00
parent 0fa0ed3380
commit c446d794a8
9 changed files with 338 additions and 1 deletions
+2
View File
@@ -39,6 +39,7 @@ Resolve original sender:
| `grab.ereceipt.food` | same From/Subject; body has GrabFood / `Selamat menikmati makanan` | `Pesanan ID` as invoice_id |
| `bri.transfer.success` | `bankbri@bri.co.id` | `Pemindahan Dana Sesama Rekening BRI` |
| `bri.qris.success` | `bankbri@bri.co.id` | `Pembelian QRIS Berhasil` |
| `tokopedia.order.completed` | `noreply@tokopedia.com` | `Pesanan Selesai` |
Production path is **direct provider mail**. Forwards still work via the Fwd header. Do **not** match on the forwarder envelope From.
@@ -50,6 +51,7 @@ Rules: `apps/watcher/src/rules/`. Parsers: `apps/watcher/src/parsers/`.
- **Livin:** support clean forwarded lines and jammed HTML-stripped labels (`Tanggal13 Sep 2026`, `Tanggal15 Agu 2026`). Indonesian month names/abbreviations (`Agu`/`Agustus`, `Des`, …) are accepted. When merchant and city are glued on one line, keep the whole string as `merchant`; only split location when it is already a separate line ending in `- ID`. Do not maintain a city-name list.
- **Grab:** plain text often has date-only `Picked up on …`; pickup/dropoff times (`10:47AM`) live in HTML. Watcher keeps `message.html` and merges the first standalone AM/PM time into `occurredAt` (WIB). Tip receipts (`Your tip goes a long way…`, timestamp like `13 Sep 26 10:47 +0700`) become `grab.ereceipt.tip` with `invoice_id` `{bookingId}:tip` so they do not collide with the ride.
- **BRI / BRImo:** transfer (`Pemindahan Dana Sesama Rekening BRI`) — amount from `Nominal`, `invoice_id` from `Nomor Referensi`, `description` from `Nama Tujuan`, datetime from `Tanggal`. QRIS (`Pembelian QRIS Berhasil`) — amount from `Nominal` (fallback `Total Transaksi`), `description` from `Nama Merchant`, datetime from `Tanggal Transaksi`. Other BRI subjects stay out of scope until samples appear.
- **Tokopedia:** `Pesanan Selesai` — one row per `No.Invoice`; amount from `Total belanja` (not fee lines); `description` = `{Toko} - Tokopedia`; line items (1+) in `details.items`; `trx_date` from `Tanggal Terima` (date-only).
- Open-ended text (names, products, driver, compliments) is best-effort optional `details`.
## PocketBase