Skip to content

Generador de PDF

El paquete @arcasdk/pdf permite generar comprobantes electrónicos en formato PDF con el diseño oficial de ARCA (ex AFIP). Soporta Facturas, Notas de Crédito, Notas de Débito y comprobantes MiPyME en letras A, B, C, E y M.

Paquete independiente

@arcasdk/pdf es un paquete independiente de @arcasdk/core. Podés usarlo sin el SDK core construyendo los datos manualmente, o combinarlo con @arcasdk/core para generar PDFs a partir de comprobantes ya emitidos.


Instalación

bash
npm i @arcasdk/pdf
bash
yarn add @arcasdk/pdf
bash
pnpm add @arcasdk/pdf

Requisito

Este paquete usa Puppeteer para renderizar el HTML a PDF. Puppeteer descarga Chromium automáticamente al instalar. En entornos serverless o CI, podés necesitar configurar Puppeteer para usar un binario externo.


Uso básico

ts
import { InvoicePdfGenerator, InvoiceData } from "@arcasdk/pdf";
import { writeFileSync } from "fs";

const data: InvoiceData = {
  emisor: {
    razonSocial: "Empresa de Prueba S.A.",
    domicilioComercial: "Av. Corrientes 1234, CABA",
    condicionIva: "IVA Responsable Inscripto",
    cuit: "20111111117",
    iibb: "12-3456789-0",
    fechaInicioActividades: "20180301",
  },
  receptor: {
    razonSocial: "Cliente de Prueba S.R.L.",
    domicilio: "Calle Falsa 456, Rosario",
    condicionIva: "IVA Responsable Inscripto",
    documentoTipo: "CUIT",
    documentoNro: "30111111118",
  },
  cbteTipo: 1,
  cbteLetra: "A",
  puntoVenta: 3,
  cbteDesde: 152,
  cbteHasta: 152,
  cbteFecha: "20240515",
  concepto: 1,
  moneda: "PES",
  condicionVenta: "Contado",
  items: [
    {
      descripcion: "Servicio de consultoría",
      cantidad: 10,
      unidadMedida: "horas",
      precioUnitario: 5000,
      subtotal: 50000,
      alicuotaIva: 21,
    },
  ],
  importeNetoGravado: 50000,
  importeIva: 10500,
  iva: [{ id: 5, descripcion: "21%", baseImponible: 50000, importe: 10500 }],
  importeTotal: 60500,
  cae: "74512345678901",
  caeFechaVencimiento: "20240525",
};

const generator = new InvoicePdfGenerator();
const pdfBuffer = await generator.generate(data);
writeFileSync("factura.pdf", pdfBuffer);

Opciones de configuración

Se pasan al constructor de InvoicePdfGenerator:

ts
const generator = new InvoicePdfGenerator({
  pageSize: "A4",
  margin: 10,
  includeQr: true,
  footerText: "Documento no válido como factura",
  logo: "data:image/png;base64,...",
  logoWidth: 80,
});
OpciónTipoDefaultDescripción
pageSize"A4" | "LETTER" | "LEGAL""A4"Tamaño de página
marginnumber10Márgenes en mm
includeQrbooleantrueIncluir código QR de verificación ARCA
copyCopyType"ORIGINAL"Banner de copia (ORIGINAL, DUPLICADO, etc.)
copiesCopyType[]Generar múltiples copias en un solo PDF
logostringLogo del emisor como data URL (data:image/png;base64,...)
logoWidthnumber60Ancho del logo en px
footerTextstringTexto adicional en el pie de cada página
templatestring | ((props: InvoiceTemplateProps) => string)Template personalizado (Handlebars string o función)

CopyType

ts
type CopyType = "ORIGINAL" | "DUPLICADO" | "TRIPLICADO" | "CUADRUPLICADO";

Múltiples copias

Para generar ORIGINAL + DUPLICADO + TRIPLICADO en un solo PDF:

ts
const generator = new InvoicePdfGenerator({
  copies: ["ORIGINAL", "DUPLICADO", "TRIPLICADO"],
});

const pdfBuffer = await generator.generate(data);

Stream

Para obtener un Readable stream en lugar de un Buffer:

ts
const generator = new InvoicePdfGenerator();
const stream = await generator.generateStream(data);

// Ejemplo con Express
res.setHeader("Content-Type", "application/pdf");
stream.pipe(res);

Estructura de datos

InvoiceData

CampoTipoRequeridoDescripción
emisorEmisorDataDatos del emisor
receptorReceptorDataDatos del receptor
cbteTiponumberTipo de comprobante (1, 6, 11, 19, etc.)
cbteLetrastringLetra del comprobante (A, B, C, E, M)
puntoVentanumberPunto de venta
cbteDesdenumberNúmero de comprobante
cbteHastanumberNúmero de comprobante hasta
cbteFechastringFecha (YYYYMMDD)
conceptonumber1=Productos, 2=Servicios, 3=Ambos
itemsInvoiceItem[]Items de la factura
importeNetoGravadonumberImporte neto gravado
importeIvanumberImporte total de IVA
importeTotalnumberImporte total
caestringCAE
caeFechaVencimientostringVencimiento del CAE (YYYYMMDD)
monedastringMoneda ("PES", "DOL")
cotizacionnumberCotización de la moneda
condicionVentastringCondición de venta
fechaServicioDesdestringPeríodo desde (conceptos 2 y 3)
fechaServicioHastastringPeríodo hasta (conceptos 2 y 3)
fechaVtoPagostringVencimiento de pago
importeNetoNoGravadonumberImporte no gravado
importeExentonumberImporte exento
ivaIvaDetail[]Desglose de IVA por alícuota
tributosTributoDetail[]Otros tributos
importeTributosnumberImporte total de tributos
cbtesAsociadosComprobanteAsociado[]Comprobantes asociados (NC/ND)
observacionesstringObservaciones
cbteDescripcionstringDescripción personalizada del comprobante
importeTotalPesosnumberTotal en ARS pre-calculado (moneda extranjera)
divisastringDivisa (Factura E)
destinoComprobantestringPaís destino (Factura E)
formaPagostringForma de pago (Factura E)
incotermsstringIncoterms (Factura E)
fechaPagostringFecha de pago YYYYMMDD (Factura E)
condicionIvaExportacionstringLeyenda IVA exportación (Factura E)

EmisorData

CampoTipoRequeridoDescripción
razonSocialstringRazón social
domicilioComercialstringDomicilio comercial
condicionIvastringCondición frente al IVA
cuitstringCUIT (11 dígitos sin guiones)
iibbstringIngresos Brutos
fechaInicioActividadesstringFecha inicio actividades (YYYYMMDD)
contactostringContacto (email, teléfono, web)

ReceptorData

CampoTipoRequeridoDescripción
razonSocialstringRazón social
condicionIvastringCondición frente al IVA
documentoTipostringTipo de documento ("CUIT", "DNI")
documentoNrostringNúmero de documento
domiciliostringDomicilio
cuitPaisstringCUIT país destino (Factura E)
idImpositivostringID impositivo exterior (Factura E)

InvoiceItem

CampoTipoRequeridoDescripción
descripcionstringDescripción del producto/servicio
cantidadnumberCantidad
unidadMedidastringUnidad de medida
precioUnitarionumberPrecio unitario
subtotalnumberSubtotal del item
codigostringCódigo del producto
bonificacionnumberPorcentaje de bonificación
importeBonificacionnumberImporte bonificación pre-calculado (si no se provee, se calcula)
alicuotaIvanumberAlícuota de IVA (solo Factura A)

IvaDetail

CampoTipoRequeridoDescripción
idnumberID de la alícuota
descripcionstringDescripción ("21%", "10.5%", etc.)
baseImponiblenumberBase imponible
importenumberImporte del IVA

TributoDetail

CampoTipoRequeridoDescripción
idnumberID del tributo
descripcionstringDescripción del tributo
baseImponiblenumberBase imponible
alicuotanumberAlícuota en porcentaje
importenumberImporte del tributo

ComprobanteAsociado

CampoTipoRequeridoDescripción
tiponumberTipo de comprobante
puntoVentanumberPunto de venta
numeronumberNúmero de comprobante
cuitstringCUIT del emisor original
fechastringFecha del comprobante

Diferencias por letra

Factura A

  • 7 columnas: Cantidad, Producto/Servicio, Precio unit, %Bonif., $ Bonif., %IVA, Subtotal s/IVA
  • Tabla de Otros Tributos con 5 filas fijas
  • Desglose de IVA por alícuota (27%, 21%, 10.5%, 5%, 2.5%, 0%)
  • Leyenda "Son PESOS ARGENTINOS..."

Factura B

  • 6 columnas (sin %IVA)
  • Tabla de Otros Tributos con 5 filas fijas
  • Subtotal + Importe Otros Tributos + Importe Total
  • Leyenda "Son PESOS ARGENTINOS..."

Factura C

  • 6 columnas (sin %IVA)
  • Sin tabla de tributos
  • Importe Neto Gravado + Importe Total
  • Leyenda "Son PESOS ARGENTINOS..."

Factura E (Exportación)

  • 5 columnas: Ítem, Descripción, Cantidad, Precio Unit. (USD), Total por ítem (USD)
  • Sección receptor con "Señor(es)", CUIT País, ID Impositivo, Divisa, Destino del Comprobante
  • Tabla de Forma de Pago / Fecha de Pago / Incoterms
  • Tipo de Cambio + Divisa en el footer
  • Importe Total en moneda extranjera

Factura M

  • Mismo layout que Factura B (6 columnas, sin desglose IVA)

Cálculos automáticos

El template muestra los valores que le pasás, sin recalcular totales. Hay dos excepciones con override opcional:

CálculoSe calcula comoOverride
Bonificación ($) por itemprecioUnitario × cantidad × (bonificacion / 100)item.importeBonificacion
Total en ARS (moneda ext.)importeTotal × cotizacionimporteTotalPesos

Si proveés el campo de override, se usa directamente sin calcular.


Ejemplo Factura B

ts
const facturaB: InvoiceData = {
  emisor: {
    razonSocial: "Emisor de Prueba",
    domicilioComercial: "Av. Belgrano 789, CABA",
    condicionIva: "IVA Responsable Inscripto",
    cuit: "20111111117",
    iibb: "901-234567-0",
    fechaInicioActividades: "20150601",
  },
  receptor: {
    razonSocial: "Receptor de Prueba",
    condicionIva: "Consumidor Final",
    documentoTipo: "DNI",
    documentoNro: "31456789",
  },
  cbteTipo: 6,
  cbteLetra: "B",
  puntoVenta: 1,
  cbteDesde: 500,
  cbteHasta: 500,
  cbteFecha: "20240610",
  concepto: 2,
  fechaServicioDesde: "20240501",
  fechaServicioHasta: "20240531",
  fechaVtoPago: "20240625",
  items: [
    {
      descripcion: "Liquidación de sueldos - Mayo 2024",
      cantidad: 1,
      unidadMedida: "servicio",
      precioUnitario: 25000,
      subtotal: 25000,
    },
  ],
  importeNetoGravado: 25000,
  importeIva: 0,
  importeTotal: 25000,
  cae: "74512345678902",
  caeFechaVencimiento: "20240620",
};

Ejemplo Factura E (Exportación)

ts
const facturaE: InvoiceData = {
  emisor: {
    razonSocial: "Exportadora de Prueba S.A.",
    domicilioComercial: "Puerto Madero 100, CABA",
    condicionIva: "IVA Responsable Inscripto",
    cuit: "30111111118",
    iibb: "12-3456789-0",
    fechaInicioActividades: "20200101",
  },
  receptor: {
    razonSocial: "Empresa Exterior de Prueba",
    domicilio: "1234 Market St, San Francisco, CA, USA",
    condicionIva: "Cliente del Exterior",
    documentoTipo: "CUIT",
    documentoNro: "55000000000",
    cuitPais: "55000002126 (ESTADOS UNIDOS - Persona Jurídica)",
    idImpositivo: "261907945",
  },
  cbteTipo: 19,
  cbteLetra: "E",
  puntoVenta: 5,
  cbteDesde: 10,
  cbteHasta: 10,
  cbteFecha: "20240701",
  concepto: 1,
  moneda: "DOL",
  cotizacion: 1391.5,
  condicionIvaExportacion: "IVA EXENTO OPERACIÓN DE EXPORTACIÓN",
  divisa: "USD - Dólar Estadounidense",
  destinoComprobante: "ESTADOS UNIDOS",
  formaPago: "Transferencia SWIFT - Moneda Extranjera",
  fechaPago: "20240715",
  incoterms: "FOB",
  items: [
    {
      descripcion: "Consulting services",
      cantidad: 40,
      unidadMedida: "horas",
      precioUnitario: 150,
      subtotal: 6000,
    },
  ],
  importeNetoGravado: 6000,
  importeIva: 0,
  importeTotal: 6000,
  cae: "74512345678903",
  caeFechaVencimiento: "20240711",
};

Template personalizado

Template Handlebars (string)

ts
const miTemplate = `
<html>
<body>
  <h1>{{data.emisor.razonSocial}}</h1>
  <p>{{descTipo data.cbteTipo}} {{data.cbteLetra}}</p>
  <p>Nro: {{voucherNumber data.puntoVenta data.cbteDesde}}</p>
  <p>Fecha: {{formatDate data.cbteFecha}}</p>
  <p>Total: {{formatCurrency data.importeTotal data.moneda}}</p>
  {{#if qrDataUrl}}<img src="{{qrDataUrl}}" width="100" />{{/if}}
</body>
</html>
`;

const generator = new InvoicePdfGenerator({ template: miTemplate });

Template función

ts
function MiTemplate({ data, options, qrDataUrl }: InvoiceTemplateProps): string {
  return `
    <html>
      <body>
        <h1>${data.emisor.razonSocial}</h1>
        <p>Total: $${data.importeTotal}</p>
      </body>
    </html>
  `;
}

const generator = new InvoicePdfGenerator({ template: MiTemplate });

Helpers Handlebars disponibles

HelperDescripciónEjemplo
formatDateYYYYMMDD → DD/MM/YYYY{{formatDate data.cbteFecha}}
formatCuitCUIT con guiones{{formatCuit data.emisor.cuit}}
formatCurrencyImporte con símbolo de moneda{{formatCurrency data.importeTotal data.moneda}}
formatUnitPricePrecio unitario formateado{{formatUnitPrice item.precioUnitario}}
formatCotizacionCotización con 3 decimales{{formatCotizacion data.cotizacion}}
voucherNumberNro comprobante (00003-00000152){{voucherNumber data.puntoVenta data.cbteDesde}}
descTipoDescripción del tipo de comprobante{{descTipo data.cbteTipo}}
currencyNameNombre completo de la moneda{{currencyName data.moneda}}
currencyCodeCódigo ISO de la moneda (ARS, USD){{currencyCode data.moneda}}
currencyShortNameNombre corto de la moneda{{currencyShortName data.moneda}}
numberToWordsImporte en letras (español){{numberToWords data.importeTotal}}
docNumberFormatea doc (CUIT con guiones si 11 dígitos){{docNumber data.receptor.documentoNro}}
padStartRellena con ceros{{padStart data.puntoVenta 5}}
bonAmountCalcula bonificación (con override){{bonAmount precio cant bonif importeBonif}}
ivaImporteBusca importe de IVA por descripción{{ivaImporte data.iva "21%"}}
tributoImporteBusca importe de tributo por descripción{{tributoImporte data.tributos "..."}}
multiplyMultiplicación{{multiply data.importeTotal data.cotizacion}}
eq, neqIgualdad / desigualdad{{#if (eq data.cbteLetra "A")}}
gt, gteMayor / mayor o igual{{#if (gt data.importeTotal 1000)}}
or, and, notOperadores lógicos{{#or condA condB}}...{{/or}}
defaultValor por defecto si falsy{{default data.moneda "PES"}}
isNullComprueba si es null/undefined{{#if (isNull val)}}
lenLargo de un array{{len data.tributos}}

Monedas soportadas

CódigoMonedaSímbolo
PESPesos Argentinos (ARS)$
DOLDólares Estadounidenses (USD)US$

Cuando la moneda no es PES y se provee cotizacion, el PDF muestra una línea de conversión a pesos argentinos al pie del comprobante.

Made by Rodrigo Alcorta with ❤️