Ir al contenido

Reconciliación

Proceso automático de conciliación entre transacciones bancarias y gastos registrados.

import { useReconciliation } from '@/features/bank/hooks/useReconciliation';
const {
syncing,
runReconciliation,
confirmMatch,
ignoreTransaction
} = useReconciliation(businessId);

Ejecuta el proceso de conciliación automática:

const handleReconciliation = async () => {
try {
await runReconciliation();
toast({
title: "Conciliación completada",
description: `${matchCount} coincidencias encontradas`,
});
} catch (error) {
toast({
title: "Error en conciliación",
variant: "destructive",
});
}
};

Confirma una coincidencia sugerida:

await confirmMatch(transaction.id, expense.id);
// Actualiza estado a 'matched'
// Vincula expense_id con bank_transaction_id

Marca una transacción como ignorada:

await ignoreTransaction(transaction.id);
// Cambia reconciliation_status a 'ignored'
// La transacción no aparecerá en pendientes
POST /functions/v1/expense-reconciliation

Input:

{
businessId: string;
}

Output:

{
success: boolean;
matches: ExpenseMatch[];
processedCount: number;
}
interface ExpenseMatch {
expenseId: string;
transactionId: string;
confidence: number; // 0.0 - 1.0
matchReason: string;
}
// 1. Comparación de monto (±2% tolerancia)
const amountMatch = Math.abs(transaction.amount - expense.total_amount) <= (expense.total_amount * 0.02);
// 2. Comparación de fecha (±3 días ventana)
const daysDiff = Math.abs(differenceInDays(transactionDate, expenseDate));
const dateMatch = daysDiff <= 3;
// 3. Similitud de texto (Levenshtein)
const merchantSimilarity = similarity(transaction.merchant_name, expense.vendor_name);
const textMatch = merchantSimilarity > 0.75;
// 4. Cálculo de score
let confidence = 0;
if (amountMatch) confidence += 0.5;
if (dateMatch) confidence += 0.3;
if (textMatch) confidence += 0.2;
// 5. Decidir si es match
if (confidence >= 0.8) {
// Alta confianza - Sugerir automáticamente
return { confidence: 'high', autoSuggest: true };
} else if (confidence >= 0.6) {
// Media confianza - Sugerir con precaución
return { confidence: 'medium', autoSuggest: true };
} else {
// Baja confianza - No sugerir
return { confidence: 'low', autoSuggest: false };
}
src/features/expenses/components/TransactionMatchCard.tsx
<TransactionMatchCard
transaction={transaction}
suggestedExpense={expense}
confidence="high"
onConfirm={() => confirmMatch(transaction.id, expense.id)}
onReject={() => ignoreTransaction(transaction.id)}
/>

Muestra:

  • Datos de la transacción
  • Datos del gasto sugerido
  • Nivel de confianza visual
  • Botones de confirmar/rechazar
src/features/expenses/components/TransactionBulkActionsBar.tsx
<TransactionBulkActionsBar
selectedCount={selectedIds.size}
pendingCount={pendingCount}
confirmableCount={confirmableCount}
onIgnore={handleBatchIgnore}
onConfirm={handleBatchConfirm}
onClearSelection={clearSelection}
isProcessing={isBatchProcessing}
/>

Permite:

  • Ignorar en lote: Marcar múltiples transacciones como ignoradas
  • Confirmar en lote: Confirmar múltiples coincidencias a la vez
  • Selección inteligente: Solo afecta transacciones pendientes