Reconciliación
Exportar contenido
Proceso automático de conciliación entre transacciones bancarias y gastos registrados.
Hook de reconciliación
Sección titulada «Hook de reconciliación»import { useReconciliation } from '@/features/bank/hooks/useReconciliation';
const { syncing, runReconciliation, confirmMatch, ignoreTransaction} = useReconciliation(businessId);Funciones disponibles
Sección titulada «Funciones disponibles»runReconciliation()
Sección titulada «runReconciliation()»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", }); }};confirmMatch(transactionId, expenseId)
Sección titulada «confirmMatch(transactionId, expenseId)»Confirma una coincidencia sugerida:
await confirmMatch(transaction.id, expense.id);
// Actualiza estado a 'matched'// Vincula expense_id con bank_transaction_idignoreTransaction(transactionId)
Sección titulada «ignoreTransaction(transactionId)»Marca una transacción como ignorada:
await ignoreTransaction(transaction.id);
// Cambia reconciliation_status a 'ignored'// La transacción no aparecerá en pendientesEdge Function: Reconciliación
Sección titulada «Edge Function: Reconciliación»POST /functions/v1/expense-reconciliationInput:
{ businessId: string;}Output:
{ success: boolean; matches: ExpenseMatch[]; processedCount: number;}
interface ExpenseMatch { expenseId: string; transactionId: string; confidence: number; // 0.0 - 1.0 matchReason: string;}Algoritmo de matching
Sección titulada «Algoritmo de matching»// 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 scorelet confidence = 0;if (amountMatch) confidence += 0.5;if (dateMatch) confidence += 0.3;if (textMatch) confidence += 0.2;
// 5. Decidir si es matchif (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 };}Tarjeta de coincidencia
Sección titulada «Tarjeta de coincidencia»<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
Acciones en lote
Sección titulada «Acciones en lote»<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