Ir al contenido

Reintentar Envíos Fallidos

Reenvía masivamente todas las facturas con errores temporales (ERROR o PENDING_RETRY).

  1. Ve a VeriFactu Dashboard.
  2. Revisa las facturas con errores en la tabla — columna “VeriFactu”.
  3. Clic en “Reintentar Fallidas” en la sección Acciones — se abre confirmación.
  4. Confirma — el sistema reinicia el envío de todas las facturas con error.
  5. Espera — aparece toast con resultado: “Exitosos: X, Errores: Y”.
  6. Revisa la tabla actualizada — facturas exitosas cambian a SENT (verde).
Estado actualSe reintentaMotivo
ERRORError temporal recuperable
PENDING_RETRYYa en cola, se acelera el reintento
FAILEDNoError permanente (max 5 reintentos agotados)
SENTNoYa enviada correctamente
NULLNoVeriFactu no activo o borrador
  • Toast muestra: “Exitosos: 8, Errores: 2”.
  • Las facturas exitosas aparecen con badge SENT (verde).
  • Las facturas que siguen con error mantienen badge rojo.
  • El contador de “Enviadas” en las tarjetas aumenta.
MensajeCausaSolución
”Sin facturas para reintentar”No hay facturas con ERROR o PENDING_RETRYNo es necesario reintentar
Botón deshabilitadoNo hay facturas con erroresEspera a que aparezcan errores

Detalles tecnicos — Reintentar Envios Fallidos

Sección titulada «Detalles tecnicos — Reintentar Envios Fallidos»
Función: handleBulkRetry

Ubicación: VeriFactuDashboard.tsx

Flujo:

  1. Filtra facturas con verifactu_status IN ('ERROR', 'PENDING_RETRY')
  2. Para cada factura:
    const { data: response, error } = await supabase.functions.invoke(
    'update-invoice-status',
    {
    body: {
    invoice_id: invoice.id,
    new_status: invoice.status, // Mantiene status actual (sent/paid)
    },
    }
    );
  3. El edge function update-invoice-status detecta que new_status no cambia
  4. Vuelve a ejecutar lógica de VeriFactu
  5. Si éxito: verifactu_status = 'SENT', incrementa successCount
  6. Si error: mantiene ERROR, incrementa errorCount
  7. Rate limiting: 500ms entre requests
  8. Al finalizar, muestra toast y recarga dashboard

Rate limiting:

await new Promise(resolve => setTimeout(resolve, 500));

Evita saturar API de VeriFactu con múltiples requests simultáneos.

Edge Function: update-invoice-status (lógica VeriFactu)

Trigger: Cambio de status de factura.

Condiciones para reenviar VeriFactu:

  1. new_status IN ('sent', 'paid')
  2. isVeriFactuEnabled(businessId) === true
  3. Factura no está en status SENT ya

Flujo de reintento:

const verifactuService = new VeriFactuService(supabase);
const response = await verifactuService.sendInvoice(
invoice,
business,
customer,
items
);
if (response?.ResultCode === 0) {
// Éxito
await supabase
.from('invoices')
.update({
verifactu_status: 'SENT',
verifactu_csv: response.Return.CSV,
verifactu_qr_code: response.Return.QrCode,
verifactu_sent_at: new Date().toISOString(),
verifactu_error_code: null,
verifactu_error_description: null,
})
.eq('id', invoice.id);
} else {
// Error
await supabase
.from('invoices')
.update({
verifactu_status: 'ERROR',
verifactu_error_code: response.Return.ErrorCode,
verifactu_error_description: response.Return.ErrorDescription,
verifactu_retry_count: (invoice.verifactu_retry_count || 0) + 1,
verifactu_last_retry_at: new Date().toISOString(),
})
.eq('id', invoice.id);
}
Cron: verifactu-retry

Trigger: Cada 5 minutos (configurado en Supabase Cron).

Query de facturas pendientes:

SELECT * FROM verifactu_retry_queue
WHERE next_retry_at <= NOW()
AND retry_count < 5
ORDER BY next_retry_at
LIMIT 50;

Lógica de backoff exponencial:

const delays = [5, 15, 30, 60, 120]; // minutos
const nextRetryMinutes = delays[retry_count] || 120;
const next_retry_at = new Date(Date.now() + nextRetryMinutes * 60 * 1000);

Marcado como FAILED:

UPDATE invoices
SET verifactu_status = 'FAILED'
WHERE id IN (
SELECT invoice_id FROM verifactu_retry_queue
WHERE retry_count >= 5
);
DELETE FROM verifactu_retry_queue
WHERE retry_count >= 5;