Facturación por Hito
Exportar contenido
Sistema de auto-generación de facturas al completar hitos del proyecto.
Ubicación
Sección titulada «Ubicación»- Componente:
MilestoneInvoiceConfig.tsx - Integración: Dentro de
MilestoneForm.tsx - Trigger: Cambio de estado de hito a “completed”
Configuración
Sección titulada «Configuración»Toggle de Auto-facturación
Sección titulada «Toggle de Auto-facturación»interface MilestoneInvoiceConfig { auto_invoice: boolean; // Activar/desactivar invoice_amount: number; // Monto a facturar invoice_description?: string; // Descripción en factura invoice_id?: string; // ID de factura generada invoiced_at?: string; // Timestamp de facturación}Campos de Configuración
Sección titulada «Campos de Configuración»-
Monto a Facturar (€)
- Input numérico con 2 decimales
- Mínimo: 0.01
- Icono de Euro en el input
- Validación: No puede ser 0 si auto-invoice está activo
-
Descripción para la Factura
- Textarea para detallar el servicio
- Hasta 500 caracteres
- Se incluye como línea de factura
- Texto sugerido: “Servicios correspondientes al hito: [nombre_hito]”
-
Cálculo Automático de IVA
- IVA del 21% por defecto
- Muestra subtotal, IVA y total
- Preview en tiempo real
Flujo de Facturación
Sección titulada «Flujo de Facturación»Fase 1: Configuración (Al crear/editar hito)
Sección titulada «Fase 1: Configuración (Al crear/editar hito)»1. Usuario activa toggle "auto_invoice"2. Ingresa monto y descripción3. Se guarda configuración en el hito4. Estado: "Configurado pero no facturado"Fase 2: Trigger (Al completar hito)
Sección titulada «Fase 2: Trigger (Al completar hito)»1. Usuario cambia estado del hito a "completed"2. Sistema detecta auto_invoice = true3. Genera factura automáticamente: - Cliente: Del proyecto - Línea: invoice_description - Monto: invoice_amount - IVA: 21% - Estado: Borrador4. Asocia invoice_id al hito5. Registra invoiced_at con timestampFase 3: Revisión (Post-generación)
Sección titulada «Fase 3: Revisión (Post-generación)»1. Usuario recibe notificación2. Factura en estado "borrador"3. Puede editar antes de enviar4. Opción de enviar o eliminarEstados de Facturación
Sección titulada «Estados de Facturación»- Sin configurar:
auto_invoice: false - Configurado:
auto_invoice: true, sininvoice_id - Facturado:
auto_invoice: true, coninvoice_id - Cancelado: Hito cancelado, no se genera factura
Vista de Estado
Sección titulada «Vista de Estado»El componente muestra diferentes vistas según el estado:
Estado: No Configurado
Sección titulada «Estado: No Configurado»[ ] Facturar automáticamente al completar Se generará una factura cuando este hito se marque como completadoEstado: Configurado
Sección titulada «Estado: Configurado»[✓] Facturar automáticamente al completar
Monto: €1,200.00Descripción: Desarrollo de módulo de usuariosIVA (21%): €252.00Total: €1,452.00
ℹ️ La factura se generará automáticamente cuando este hito se marque como completado.Estado: Facturado
Sección titulada «Estado: Facturado»✅ Factura generada Facturado el 15/02/2024
[Ver Factura] → /invoices/{invoice_id}Consideraciones Importantes
Sección titulada «Consideraciones Importantes»Seguridad:
- Solo usuarios con permisos de facturación pueden configurar
- Validación de montos y cliente válido
- No se puede facturar si el proyecto no tiene cliente
Edición:
- Una vez facturado, no se puede editar la config
- El toggle y campos se deshabilitan
- Botón para ver factura generada
Cancelación:
- Si se cancela el hito después de facturar, la factura NO se elimina
- Requiere eliminar factura manualmente si es necesario
Lógica de generación de factura
// Trigger al completar hito (conceptual)const handleMilestoneComplete = async (milestoneId: string) => { // Obtener hito const { data: milestone } = await supabase .from('project_milestones') .select('*, project:projects(client_id)') .eq('id', milestoneId) .single();
// Si auto_invoice está activado if (milestone.auto_invoice && !milestone.invoice_id) { // Crear factura const { data: invoice } = await supabase .from('invoices') .insert({ user_id: userId, customer_id: milestone.project.client_id, status: 'draft', issue_date: new Date().toISOString(), items: [{ description: milestone.invoice_description, quantity: 1, unit_price: milestone.invoice_amount, tax_rate: 21, total: milestone.invoice_amount * 1.21 }], subtotal: milestone.invoice_amount, tax_total: milestone.invoice_amount * 0.21, total: milestone.invoice_amount * 1.21 }) .select() .single();
// Actualizar hito con invoice_id await supabase .from('project_milestones') .update({ invoice_id: invoice.id, invoiced_at: new Date().toISOString() }) .eq('id', milestoneId);
// Notificación toast.success('Factura generada automáticamente'); }};