From fae5af446ffc17f5f6aa256e1bf504e03e57068d Mon Sep 17 00:00:00 2001 From: Kavi Date: Tue, 2 Jun 2026 04:23:43 -0400 Subject: [PATCH] Reclassify debt transfers and MACH/Servipag card payments as internal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Debt repayments (TRASPASO A/DE DEUDA, TRASPASO POR CIERRE DE CUENTA) are payments against an international credit card — the purchases already happened on that card, only fees/interest are new costs. Reclassify from expense → card_payment (internal) so they show in Cycles, not Spending. Same for MACH Comercios→Servipag and PAGO EN SERVIPAG.COM* which are Rappi card payments routed through Servipag, not utility bills. --- web/engine.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/web/engine.js b/web/engine.js index cb86e11..ff08489 100644 --- a/web/engine.js +++ b/web/engine.js @@ -130,6 +130,19 @@ if (s.account_last4) ACCT_LAST4.add(s.account_last4); } } + // Reclassify transactions that the raw parser tagged as 'expense' but are + // really internal movements — debt repayments to cards (the purchases already + // happened on those cards; only interest/fees are new costs) and known + // card-payment intermediaries (MACH→Servipag for Rappi card, etc.) + const DEBT_RE = /TRASPASO\s+(A\s+DEUDA|POR\s+CIERRE\s+DE\s+CUENTA|DE\s+DEUDA\b|DEUDA\s*(NACIONAL|INTERNACIONAL)?$)/i; + const CPAY_RE = /PAGO\s+EN\s+SERVIPAG\.COM|COMPRA\s+MACH\s+COMERCIOS.*SERVIPAG/i; + TX = TX.map(t => { + if (t.flow_type !== 'expense') return t; + if (DEBT_RE.test(t.description) || CPAY_RE.test(t.description)) { + return { ...t, flow_type: 'card_payment', internal: true }; + } + return t; + }); MONTHS = [...new Set(TX.map(t => t.ym))].sort(); BANKS = [...new Set(TX.map(t => t.bank))].sort(); return { months: MONTHS, banks: BANKS, totals: RAW.real_totals };