60 lines
1.9 KiB
JavaScript
60 lines
1.9 KiB
JavaScript
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;
|
|
}
|