Ir al contenido

Asociar a Transacción Bancaria

Vinculación manual o automática de gastos con transacciones bancarias importadas.

src/features/expenses/components/BankTransactionsTab.tsx
<BankTransactionsTab
onReconciliationComplete={handleReconciliation}
/>
  • Vista de transacciones tipo DEBIT (gastos)
  • Estados de conciliación: Pendiente, Conciliado, Ignorado
  • Sugerencias automáticas con nivel de confianza
  • Crear gasto desde transacción con datos pre-cargados
  • Confirmación de coincidencias con un clic
  • Búsqueda manual de coincidencias
  • Acciones en lote para múltiples transacciones
interface BankTransaction {
id: string;
business_id: string;
bank_account_id: string;
transaction_id: string; // ID del banco
amount: number;
currency: string;
transaction_date: string;
description: string;
merchant_name: string | null; // Nombre del comercio
category: string | null;
reconciliation_status: 'pending' | 'matched' | 'ignored';
matched_expense_id: string | null; // FK a expenses
match_confidence: 'high' | 'medium' | 'low' | null;
reconciled_at: string | null;
reconciled_by: string | null;
}
  1. Usuario selecciona transacción pendiente
  2. Click en botón “Ver/Crear gasto”
  3. Se abre CreateExpenseSheet con datos pre-cargados:
    • amount: Monto de la transacción
    • expense_date: Fecha de la transacción
    • name: merchant_name o description
  4. Usuario completa campos faltantes (categoría, IVA, proveedor)
  5. Al guardar, se crea el gasto y se vincula:
// Crear gasto
const { data: newExpense, error } = await supabase
.from('expenses')
.insert(expenseData)
.select()
.single();
// Vincular transacción
await supabase
.from('bank_transactions')
.update({
matched_expense_id: newExpense.id,
reconciliation_status: 'matched',
match_confidence: 'high',
reconciled_at: new Date().toISOString(),
reconciled_by: user.id,
})
.eq('id', transaction.id);

El sistema sugiere proveedores usando:

import { useBankTransactionVendorMatch } from '@/features/bank/hooks/useBankTransactionVendorMatch';
const { matchResult, createAutoAlias } = useBankTransactionVendorMatch(
transaction.merchant_name
);
// matchResult contiene:
// {
// vendor: Vendor | null,
// confidence: 'high' | 'medium' | 'low',
// matchedBy: 'alias' | 'name' | 'fuzzy'
// }

Algoritmo:

  1. Busca alias exactos en tabla vendor_aliases
  2. Si no encuentra, busca coincidencia de nombre
  3. Si no encuentra, usa fuzzy matching (Levenshtein)

Cuando el usuario selecciona un proveedor diferente al sugerido, el sistema aprende:

if (formData.vendor_id && transaction.merchant_name) {
await createAutoAlias(formData.vendor_id, transaction.merchant_name);
}
// Crea entrada en vendor_aliases:
// {
// vendor_id: 'uuid',
// alias: 'AMAZON EU',
// is_auto: true,
// business_id: 'uuid'
// }
src/features/expenses/components/FindMatchSheet.tsx
<FindMatchSheet
open={findMatchOpen}
onOpenChange={setFindMatchOpen}
transaction={selectedTransaction}
onSelectMatch={handleManualMatch}
/>

Permite:

  • Buscar gastos por texto, fecha, monto
  • Ver detalles de cada coincidencia posible
  • Asociar manualmente una transacción con un gasto existente