Ir al contenido

Gastos

El módulo de Gastos de Factux permite a los usuarios registrar, gestionar y conciliar sus gastos empresariales con las transacciones bancarias. Implementa automatización OCR para extracción de datos, conciliación automática con transacciones bancarias, y cálculo inteligente de deducibilidad del IVA según la normativa española (LIVA).

/owner/expenses

La página principal de gastos se organiza en dos pestañas principales:

Vista de lista con todos los gastos registrados en el sistema. Incluye:

  • Lista de gastos con información detallada
  • Filtros avanzados por estado, proveedor, categoría, fecha y monto
  • Búsqueda por texto en concepto y descripción
  • Acciones en línea para ver, editar y eliminar gastos
  • Indicadores visuales de estado y deducibilidad fiscal
  • Paginación para grandes volúmenes de datos

Vista dedicada a transacciones bancarias pendientes de conciliar:

  • Transacciones de tipo DEBIT (gastos) importadas desde bancos
  • Estados de conciliación: Pendiente, Conciliado, Ignorado
  • Sugerencias automáticas de coincidencias con gastos existentes
  • Acciones rápidas para crear gastos desde transacciones
  • Conciliación en lote con selección múltiple
  • Filtros por cuenta bancaria, fecha y monto
interface Expense {
id: string;
business_id: string;
user_id: string;
vendor_id?: string;
vendor_name?: string;
vendor_tax_id?: string;
vendor_email?: string;
category?: string;
description?: string;
name?: string;
amount?: number; // Base imponible
total_amount: number; // Total con IVA
tax_amount?: number; // IVA soportado
tax_rate?: number; // Tipo de IVA (%)
expense_date: string;
status: 'recorded' | 'verified';
payment_method?: string;
payment_status?: 'pending' | 'paid' | 'partial';
invoice_number?: string;
receipt_url?: string; // Ruta del archivo justificante
ocr_data?: Record<string, any>; // Datos extraídos por OCR
verified_at?: string;
verified_by?: string;
bank_transaction_id?: string; // Enlace con transacción bancaria
notes?: string;
source?: string;
source_type?: string;
source_metadata?: Record<string, any>;
is_recurring?: boolean;
created_at: string;
updated_at: string;
// Campos de deducibilidad IVA (Art. 95-97 LIVA)
document_type?: ExpenseDocumentType;
is_deductible?: boolean;
deductible_percentage?: number;
deductible_tax_amount?: number;
non_deductible_reason?: NonDeductibleReason;
is_investment?: boolean; // Bien de inversión
accounting_date?: string; // Fecha contable
}
type ExpenseDocumentType =
| 'invoice' // Factura completa (IVA deducible)
| 'simplified_invoice' // Factura simplificada/ticket (no deducible)
| 'receipt'; // Justificante simple (no deducible)
interface BankTransaction {
id: string;
business_id: string;
bank_connection_id: string;
transaction_id: string;
amount: number;
currency: string;
transaction_date: string;
description: string;
merchant_name?: string;
category?: string;
status: 'unmatched' | 'matched' | 'reconciled';
expense_id?: string;
raw_data?: Record<string, any>;
created_at: string;
updated_at: string;
}

El módulo implementa 7 funciones clave documentadas en detalle en la página Crear Gasto Manual.

  1. Crear Gasto Manual - Formulario completo con validación y cálculo de IVA
  2. Subir con OCR - Extracción automática de datos desde imágenes/PDFs
  3. Marcar Deducibilidad - Cálculo automático según normativa LIVA
  4. Asociar a Transacción Bancaria - Vinculación manual o automática
  5. Reconciliación - Proceso automático de coincidencias
  6. Exportar Gastos - Exportación a Excel por período
  7. Acciones Masivas - Verificación y operaciones en lote
Arquitectura del módulo

Página principal:

  • src/features/expenses/pages/Expenses.tsx - Componente principal con pestañas

Componentes de formulario:

  • ExpenseFormSheet.tsx - Formulario modal para crear/editar gastos
  • CreateExpenseSheet.tsx - Formulario optimizado para transacciones bancarias
  • ExpenseFormFromScan.tsx - Formulario con datos pre-cargados desde OCR

Componentes de lista:

  • ExpensesList.tsx - Lista principal de gastos con filtros
  • BankTransactionsTab.tsx - Vista de transacciones bancarias
  • ExpensePreviewSheet.tsx - Vista detallada de un gasto

Componentes visuales:

  • ExpenseStatusBadge.tsx - Badge de estado (Registrado/Verificado)
  • DeductibilityIndicator.tsx - Indicador visual de deducibilidad IVA
  • ExpenseConfidenceIndicator.tsx - Indicador de confianza OCR

Componentes de acciones:

  • ExpenseBulkActionsBar.tsx - Barra flotante para acciones en lote
  • TransactionBulkActionsBar.tsx - Acciones masivas para transacciones
  • VerificationActions.tsx - Botones de verificación
  • ExportSheet.tsx - Modal de exportación

Reconciliación:

  • TransactionMatchCard.tsx - Tarjeta de coincidencia sugerida
  • FindMatchSheet.tsx - Búsqueda manual de coincidencias

Escáner OCR:

  • DesktopExpenseScanner.tsx - Escáner para escritorio
  • MobileExpenseScanner.tsx - Escáner optimizado para móvil
  • MultiExpensePreviewGrid.tsx - Vista previa de múltiples documentos
  • MultiExpenseProcessingList.tsx - Cola de procesamiento OCR
  • MultiExpenseReview.tsx - Revisión de gastos escaneados

Adapter:

src/features/expenses/api/expense-adapter.ts
export class ExpenseAdapter {
async create(data: ExpenseCreateData): Promise<Expense>
async update(id: string, data: ExpenseUpdateData): Promise<Expense>
async getById(id: string): Promise<Expense | null>
async list(filters?: ExpenseListFilters): Promise<Expense[]>
async delete(id: string): Promise<void>
async verify(id: string, verifiedBy: string): Promise<Expense>
}

Hooks personalizados:

  • useExpenses.ts - Hook para operaciones CRUD de gastos
  • useOCRVendorMatch.ts - Matching automático de proveedores desde OCR
  • useReconciliation.ts - Lógica de conciliación bancaria

Utilidades:

  • deductibility.ts - Cálculos de deducibilidad IVA según LIVA
  • ocrProcessor.ts - Procesamiento de datos OCR
  • receiptUrl.ts - Gestión de URLs de justificantes

Tabla expenses:

  • Almacena todos los gastos registrados
  • Campos de auditoría: created_at, updated_at, verified_at, verified_by
  • Campos de deducibilidad fiscal: document_type, is_deductible, deductible_percentage, etc.
  • Foreign keys: business_id, user_id, vendor_id, bank_transaction_id

Tabla bank_transactions:

  • Importa transacciones de tipo DEBIT desde conexiones bancarias
  • Estados: pending, matched, ignored
  • Campo matched_expense_id vincula con tabla expenses
  • Campo match_confidence: high, medium, low

Tabla expense_verifications:

  • Registro de verificaciones de gastos
  • Método de verificación: manual, bank_match, receipt
  • Auditoría completa de quién y cuándo verificó

Storage bucket expense-receipts:

  • Almacena archivos justificantes (imágenes, PDFs)
  • Estructura: {user_id}/{expense_id}-{timestamp}.{ext}
  • Políticas de seguridad RLS habilitadas
Edge Functions

Propósito: Ejecuta el proceso de conciliación automática entre transacciones bancarias y gastos registrados.

Endpoint: POST /functions/v1/expense-reconciliation

Input:

{
businessId: string;
}

Output:

{
success: boolean;
matches: ExpenseMatch[];
processedCount: number;
}
interface ExpenseMatch {
expenseId: string;
transactionId: string;
confidence: number; // 0-1
matchReason: string; // Explicación del match
}

Algoritmo de matching:

  1. Compara montos con tolerancia de ±2%
  2. Compara fechas con ventana de ±3 días
  3. Similarity string en nombres de comercio (Levenshtein)
  4. Asigna score de confianza según coincidencias
  5. Actualiza estado a matched si confidence > 0.8

Optimizaciones:

  • Procesa solo transacciones pendientes (status = 'pending')
  • Usa índices en transaction_date y amount
  • Ejecuta en batch de 50 transacciones
Eventos del sistema

ExpenseCreated:

{
type: 'expense.created',
payload: {
expenseId: string;
amount: number;
category: string;
}
}

ExpenseVerified:

{
type: 'expense.verified',
payload: {
expenseId: string;
verifiedBy: string;
verifiedAt: string;
}
}

ExpenseReconciled:

{
type: 'expense.reconciled',
payload: {
expenseId: string;
transactionId: string;
confidence: number;
}
}
  • Módulo de Contabilidad: Genera asientos contables automáticos
  • Módulo de Reportes: Actualiza métricas de gastos
  • Sistema de Notificaciones: Alerta sobre gastos sin justificante

El módulo implementa cálculo automático de deducibilidad del IVA según la Ley 37/1992 del IVA española (artículos 95-97).

  1. Factura completa (no ticket ni factura simplificada)
  2. NIF/CIF del proveedor presente en el documento
  3. Actividad empresarial afecta al gasto
  4. Categoría deducible (no gastos personales)

Algunas categorías tienen deducibilidad limitada por ley:

  • Vehículos de uso mixto: 50% deducible (Art. 95.3 LIVA)
  • Combustible: 50% deducible si vehículo mixto
  • Comidas y representación: 50% deducible
  • Bienes de inversión: Normativa específica (umbral 3.005,06€)
type NonDeductibleReason =
| 'simplified_invoice' // Ticket sin NIF receptor
| 'missing_vendor_tax_id' // Falta NIF del proveedor
| 'personal_use' // Uso personal
| 'prorrata' // Prorrata aplicable
| 'exempt_activity' // Actividad exenta
| 'partial_category'; // Categoría parcialmente deducible

El proceso de conciliación vincula automáticamente transacciones bancarias con gastos registrados.

  1. Importación: Las transacciones DEBIT se importan desde bancos conectados
  2. Análisis: El sistema busca coincidencias con gastos existentes
  3. Sugerencias: Muestra matches con nivel de confianza (alto/medio/bajo)
  4. Confirmación: El usuario aprueba o rechaza las coincidencias
  5. Cierre: Transacción marcada como matched y vinculada al gasto
  • Monto: Coincidencia exacta o con margen ±2%
  • Fecha: Ventana de ±3 días desde la transacción
  • Comercio: Similitud en nombre del proveedor (algoritmo Levenshtein)
  • Categoría: Coincidencia opcional que mejora el score
  • pending: Pendiente de conciliar
  • matched: Conciliada con un gasto
  • ignored: Marcada como no relevante por el usuario

El módulo usa Zod para validación de esquemas:

src/schemas/validation.ts
const expenseSchema = z.object({
name: z.string().min(1, "El nombre es obligatorio"),
amount: z.number().positive("El importe debe ser positivo"),
category: z.string().min(1, "Selecciona una categoría"),
expense_date: z.string().min(1, "La fecha es obligatoria"),
tax_rate: z.number().min(0).max(100),
});

Tabla expenses:

  • SELECT: Usuario debe pertenecer al negocio (business_id)
  • INSERT: Usuario autenticado con business_id activo
  • UPDATE: Propietario del gasto o admin del negocio
  • DELETE: Solo propietario o admin

Storage expense-receipts:

  • SELECT: Usuario con acceso al gasto asociado
  • INSERT: Usuario autenticado con límite de 5MB por archivo
  • DELETE: Propietario del gasto

Todos los cambios en gastos se registran con:

  • Timestamp de creación y actualización
  • Usuario que realizó el cambio
  • Metadata de verificación (quién, cuándo, método)

El sistema incluye 13 categorías predefinidas alineadas con el Plan General Contable español:

  1. Servicios profesionales
  2. Material de oficina
  3. Suministros
  4. Alquiler
  5. Transporte
  6. Publicidad y marketing
  7. Seguros
  8. Software y tecnología
  9. Formación
  10. Reparaciones y mantenimiento
  11. Telecomunicaciones
  12. Viajes
  13. Otros gastos

Estas categorías se comparten con el módulo de Proveedores para mantener consistencia.

  • Proveedores: Autocompletado de datos fiscales y configuración por defecto
  • Bancos: Importación automática de transacciones
  • Contabilidad: Generación de asientos contables desde gastos
  • Reportes: Métricas agregadas y análisis de gastos
  • Fiscal: Cálculo de IVA deducible para modelos 303/390