Automatizando la Generación de Facturas con Node.js — TongoRender Blog
Volver al Blog
tutorialsinvoicenodejsautomation

Automatizando la Generación de Facturas con Node.js

Aprende a construir un pipeline automatizado de generación de facturas con Node.js. Cubre integración con Stripe, procesamiento por lotes, entrega por email y creación de PDF vía API.

TongoRender Team20 de febrero de 202611 min

Crear facturas manualmente es tedioso y propenso a errores. Ya sea que factures a clientes mensualmente, proceses pedidos de e-commerce o gestiones pagos de suscripción, automatizar tu pipeline de facturación ahorra tiempo, reduce errores y asegura un branding consistente. En este tutorial, construiremos un sistema completo de automatización de facturas con Node.js que integra con Stripe, genera PDFs profesionales vía TongoRender y los entrega por email.

Arquitectura del Sistema

  1. Fuente de datos — API de Stripe para datos de pago (adaptable a cualquier sistema de facturación)
  2. Motor de plantillas — Plantilla de factura HTML/CSS con inyección dinámica de datos
  3. Renderizador PDF — API de TongoRender para convertir HTML a PDF profesional
  4. Entrega — Nodemailer para entrega por email con PDF adjunto

Paso 1: Obtener Datos de Pago de Stripe

const Stripe = require('stripe');
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

async function getMonthlyInvoices(year, month) {
  const startTimestamp = Math.floor(new Date(year, month - 1, 1).getTime() / 1000);
  const endTimestamp = Math.floor(new Date(year, month, 0, 23, 59, 59).getTime() / 1000);

  const charges = await stripe.charges.list({
    created: { gte: startTimestamp, lte: endTimestamp },
    limit: 100,
    expand: ['data.customer'],
  });

  return charges.data
    .filter(charge => charge.status === 'succeeded')
    .map(charge => ({
      id: charge.id,
      amount: charge.amount / 100,
      currency: charge.currency.toUpperCase(),
      customerName: charge.customer?.name || 'Desconocido',
      customerEmail: charge.customer?.email,
      description: charge.description || 'Cargo por servicio',
      date: new Date(charge.created * 1000).toISOString().split('T')[0],
    }));
}

Paso 2: Diseño de la Plantilla de Factura

function invoiceHTML(invoice, companyInfo) {
  return `
  <!DOCTYPE html>
  <html lang="es">
  <head>
    <style>
      body { font-family: 'Segoe UI', sans-serif; color: #333; padding: 40px; }
      .header { display: flex; justify-content: space-between; margin-bottom: 40px; }
      .company-name { font-size: 24px; font-weight: 700; color: #1a1a2e; }
      .invoice-title { font-size: 32px; color: #e63946; text-align: right; }
      table { width: 100%; border-collapse: collapse; margin: 30px 0; }
      th { background: #1a1a2e; color: white; padding: 12px 15px; text-align: left; }
      td { padding: 12px 15px; border-bottom: 1px solid #eee; }
      .total-row td { font-weight: 700; border-top: 2px solid #1a1a2e; }
    </style>
  </head>
  <body>
    <div class="header">
      <div>
        <div class="company-name">${companyInfo.name}</div>
        <div>${companyInfo.address}</div>
        <div>RFC: ${companyInfo.taxId}</div>
      </div>
      <div>
        <div class="invoice-title">FACTURA</div>
        <div>Número: ${invoice.number}</div>
        <div>Fecha: ${invoice.date}</div>
        <div>Vencimiento: ${invoice.dueDate}</div>
      </div>
    </div>

    <table>
      <thead>
        <tr><th>Descripción</th><th>Cant.</th><th>Precio Unit.</th><th>Monto</th></tr>
      </thead>
      <tbody>
        ${invoice.items.map(item => \`
          <tr>
            <td>${item.description}</td>
            <td>${item.quantity}</td>
            <td>${item.unitPrice.toFixed(2)}</td>
            <td>${(item.quantity * item.unitPrice).toFixed(2)}</td>
          </tr>
        \`).join('')}
        <tr class="total-row">
          <td colspan="3" style="text-align:right">Total</td>
          <td>${invoice.total.toFixed(2)} ${invoice.currency}</td>
        </tr>
      </tbody>
    </table>
  </body>
  </html>`;
}

Paso 3: Generar PDF y Enviar por Email

async function generateInvoicePDF(invoice, companyInfo) {
  const html = invoiceHTML(invoice, companyInfo);
  const response = await fetch('https://api.tongorender.io/v1/pdf', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.TONGORENDER_API_KEY,
    },
    body: JSON.stringify({ html, format: 'A4', printBackground: true }),
  });
  return Buffer.from(await response.arrayBuffer());
}

async function sendInvoiceEmail(to, invoice, pdfBuffer) {
  await transporter.sendMail({
    from: '"Facturación" <facturacion@empresa.com>',
    to,
    subject: `Factura #${invoice.number}`,
    text: `Adjunto encontrará la factura #${invoice.number} por ${invoice.total.toFixed(2)}.`,
    attachments: [{ filename: `factura-${invoice.number}.pdf`, content: pdfBuffer }],
  });
}

Mejores Prácticas

  • Idempotencia — Registra qué facturas han sido generadas para evitar enviar duplicados al reintentar.
  • Manejo de errores — Envuelve cada factura en try-catch. Una falla no debería detener todo el lote.
  • Rate limiting — Espacia las llamadas a la API con un pequeño retraso para mantenerte dentro de los límites.
  • Almacenamiento — Siempre guarda una copia del PDF antes de enviarlo por email.
  • Cumplimiento fiscal — Incluye todos los campos legalmente requeridos: RFC, número secuencial de factura, montos desglosados e impuestos aplicables.

La renderización confiable de PDF de TongoRender asegura que tus facturas luzcan profesionales siempre.

Automatiza tus facturas con TongoRender — 100 renderizaciones gratuitas al mes, sin necesidad de tarjeta de crédito.

Comparte este artículoCompartir en Twitter