import { query } from './db.js'; import { normalizeRut } from './util.js'; // Extract a 6-char uppercase alphanumeric code from transfer description function extractCode(description) { if (!description) return null; const m = description.toUpperCase().match(/\b([A-Z0-9]{6})\b/); return m ? m[1] : null; } /** * Try to match an inbound payment against a pending intent. * Returns { intent, confidence } or null. * * Priority: * 1. Reference code in description — strongest signal, unambiguous * 2. Exact amount + sender RUT — reliable when RUT is available * 3. Exact amount only (same account) — weaker, flagged as 'amount_only' */ export async function matchInbound(inbound) { // 1. Reference code const code = extractCode(inbound.description); if (code) { const { rows } = await query( `SELECT * FROM payment_intents WHERE reference_code = $1 AND status = 'pending'`, [code] ); if (rows[0]) return { intent: rows[0], confidence: 'reference_code' }; } // 2. Exact amount + sender RUT const senderRut = normalizeRut(inbound.sender_rut); if (senderRut) { const { rows } = await query( `SELECT * FROM payment_intents WHERE exact_amount = $1 AND status = 'pending' AND ( sender_rut IS NULL OR replace(lower(sender_rut), '.', '') = $2 ) AND ($3::text IS NULL OR account_id = $3)`, [inbound.amount, senderRut, inbound.account_id ?? null] ); if (rows[0]) return { intent: rows[0], confidence: 'exact_amount_rut' }; } // 3. Exact amount on same account (weakest — no RUT confirmation) if (inbound.account_id) { const { rows } = await query( `SELECT * FROM payment_intents WHERE exact_amount = $1 AND account_id = $2 AND status = 'pending'`, [inbound.amount, inbound.account_id] ); if (rows[0]) return { intent: rows[0], confidence: 'amount_only' }; } return null; }