> ## Documentation Index
> Fetch the complete documentation index at: https://facturas-sdk.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Comprobante impreso

> Armá con buildVoucherDocument() todo lo que el PDF de un comprobante autorizado tiene que mostrar, y dibujalo con @facturas/pdf en el formato de la RG 1415.

ARCA no genera el PDF de un comprobante emitido por web service. Lo arma tu
sistema, y las normas fijan qué datos lleva y dónde van. `buildVoucherDocument()`
toma el comprobante autorizado, los mismos ítems con los que lo emitiste y los
datos del emisor, y devuelve todo lo que el comprobante impreso tiene que
mostrar. `@facturas/pdf` lo dibuja en A4 con la ubicación que fija la norma.

Si preferís tu propia plantilla, el modelo ya viene derivado y controlado, sin
I/O, para que no tenga que saber de clases, leyendas ni IVA.

## Del comprobante autorizado al modelo

Este bloque es [examples/comprobante-impreso.ts](https://github.com/LaPyme/facturas/blob/main/examples/comprobante-impreso.ts):

```ts theme={null}
import { buildVoucherDocument, createArcaClient, type VatItem } from "facturas";

const arca = createArcaClient();

const items = [
  {
    description: "Taladro percutor 13 mm",
    quantity: 2,
    unitPrice: "605.00",
    gross: 121_000,
    vat: 21,
  },
  { description: "Mechas para metal", gross: 2420, vat: 10.5 },
] satisfies VatItem[];

const factura = await arca.issue({
  issuer: "responsable_inscripto",
  salesPoint: 3,
  to: { condition: "consumidor_final" },
  items,
});

if (factura.kind === "authorized") {
  const comprobante = buildVoucherDocument({
    voucher: factura.voucher,
    items,
    issuer: {
      legalName: "Ferretería del Sur SRL",
      address: "Av. Rivadavia 1234, CABA",
      taxId: "20-12345678-9",
      condition: "responsable_inscripto",
      grossIncome: "901-123456-7",
      activitiesStartDate: "2019-10-01",
    },
    saleConditions: "Contado",
  });
}
```

Sirve para cualquier resultado `authorized`, directo o recuperado, y para las
notas de crédito y débito. Guardá los ítems junto a la venta: si se reimprime
más tarde, el modelo sale igual.

## Qué te pide

| Campo | Qué es |
| - | - |
| `voucher` | El `IssuedVoucher` de un resultado `authorized`. |
| `items` | Los mismos ítems de la emisión, cada uno con `description`. Si un ítem trae `quantity`, también trae `unitPrice`: sin IVA en la clase A y con IVA en la clase B. Sin cantidad, la línea sale como una unidad por su importe. Con `globalDiscount`, los ítems antes del descuento. |
| `globalDiscount` | Un descuento sobre todo el comprobante, en centavos, que ya restaste de los ítems al emitir. En las clases A y B va por id de alícuota de ARCA, como las filas de IVA autorizadas: sin IVA en la A y con IVA en la B, igual que las líneas. En la clase C es un solo importe. Ver [Descuento global](#descuento-global). |
| `issuer.legalName`, `issuer.address` | La razón social y el domicilio comercial del lugar donde se emite. |
| `issuer.tradeName` | El nombre de fantasía, solo si tenés uno. |
| `issuer.taxId` | Tu CUIT. Se controla contra el QR del comprobante. |
| `issuer.condition` | `responsable_inscripto`, `exento`, `no_alcanzado`, `monotributo`, `monotributo_social` o `monotributo_trabajador_independiente_promovido`. Tiene que poder emitir la clase del comprobante. |
| `issuer.grossIncome` | El número de ingresos brutos, o la condición de no contribuyente. |
| `issuer.activitiesStartDate` | `YYYY-MM-DD`. `null` solo para profesionales universitarios que facturan honorarios y para quien presta servicios sin local. |
| `issuer.paymentToInformedCbu` | `true` si ARCA te habilitó comprobantes A con leyenda `PAGO EN CBU INFORMADA` (RG 5762). |
| `receiver.name`, `receiver.address` | Obligatorios salvo para un consumidor final. |
| `saleConditions` | Contado, cuenta corriente o la que corresponda. |
| `remitos` | Los remitos vinculados a la operación, si los hay. |
| `observations` | Las observaciones con las que ARCA autorizó el comprobante, tal como vienen en `authorization.observations` del resultado `authorized`. En la clase A se imprimen sus códigos. |

Si falta un dato obligatorio, tira `ArcaInputError` con
`ARCA_INPUT_MISSING_FIELD` y el `field` que falta.

## Qué devuelve

* La letra, el código de tres dígitos, el título y el número con punto de
  venta, como `00003-00000041`. En `letterLegend`, la leyenda que va junto a
  la letra A: `OPERACIÓN SUJETA A RETENCIÓN` para los tipos 51 a 53 o
  `PAGO EN CBU INFORMADA`.
* El emisor y el receptor con su leyenda de condición frente al IVA, por
  ejemplo `IVA RESPONSABLE INSCRIPTO` o `A CONSUMIDOR FINAL`, y el documento del
  receptor cuando está identificado.
* Las líneas. En la clase A van sin IVA y con su alícuota, en la clase B con
  IVA. Suman exactamente lo que autorizó ARCA.
* Los totales: el descuento global, el subtotal, el exento, el no gravado, el
  IVA por alícuota en la clase A, los tributos y el total. Si un ajuste de IVA de la cabecera no entra
  en ninguna línea, aparece en `totals.adjustment` para que lo muestres.
* En la clase B, el bloque del Régimen de Transparencia Fiscal al Consumidor
  con el IVA contenido y los otros impuestos nacionales indirectos.
* El CAE con su vencimiento, el QR y las leyendas que correspondan: la de la
  Ley 27.618 en una factura A a un monotributista y, en la clase A, los códigos
  de las observaciones de ARCA.

Los importes siguen en centavos y las fechas en `YYYY-MM-DD`. El formato de
moneda y el diseño quedan en tu plantilla.

`PRINTED_VOUCHER_TEXT` trae los textos fijos tal como los escriben las normas,
por ejemplo `C.A.E. N°` y el título de transparencia fiscal.

## Dónde va cada dato

La RG 1415, Anexo II, Apartado B ubica los datos. El SDK sigue esa ubicación
en el comprobante impreso aunque la RG 4291 dé por cumplidas las medidas de un
comprobante electrónico:

* Arriba a la izquierda: nombre de fantasía, razón social, domicilio y
  condición frente al IVA.
* Arriba en el centro y destacada: la letra, y debajo `Código Nº` con el código.
  Si hay `letterLegend`, va junto a la letra.
* Arriba a la derecha: número, fecha, CUIT, ingresos brutos e inicio de
  actividades. Estos datos y los de la izquierda van dentro de un recuadro de
  al menos 7 × 3 cm.
* Después: el receptor, las condiciones de venta y las líneas, con el IVA por
  alícuota a continuación en la clase A.
* Abajo a la izquierda: el bloque de transparencia fiscal.
* Abajo a la derecha: el CAE y `Fecha Vto.:` con su vencimiento, en letra de
  12 puntos o más (`PRINTED_CAE_DUE_DATE_MIN_FONT_SIZE_PT`).

El QR va en el frente sin tapar ningún dato obligatorio. No uses el logo de
ARCA: ninguna norma lo pide y presenta tu documento como si lo hubiera
generado ARCA.

## Dibujarlo con @facturas/pdf

`@facturas/pdf` es el paquete que dibuja el modelo. Sale siempre con la misma
versión que `facturas`, así que el modelo y el dibujo nunca quedan desfasados.

```bash theme={null}
pnpm add @facturas/pdf @react-pdf/renderer react
```

El ejemplo completo, de la emisión al archivo, es [examples/comprobante-pdf.ts](https://github.com/LaPyme/facturas/blob/main/examples/comprobante-pdf.ts):

```ts theme={null}
import { readFile, writeFile } from "node:fs/promises";
import { renderVoucherPdf } from "@facturas/pdf";

const pdf = await renderVoucherPdf(comprobante, {
  logo: await readFile("logo.png"),
  notes: "Garantía oficial de 6 meses. Cambios dentro de los 10 días.",
  theme: { accentColor: "#C00000" },
});
await writeFile("factura.pdf", pdf);
```

El comprobante sale con la ubicación de la sección anterior: el recuadro del
emisor de al menos 7 × 3 cm, la letra en el centro, el bloque de transparencia
abajo a la izquierda y el CAE con su vencimiento en 12 puntos abajo a la
derecha. El QR se dibuja en vectores y además es un link a la constatación de
ARCA. En un comprobante largo, el recuadro del emisor se repite en cada hoja y
el CAE va en la última.

Lo que podés cambiar:

* `theme`: tipografía y colores. Los tamaños no, porque la norma fija algunos.
* `logo`: va arriba a la izquierda, sobre la razón social.
* `notes`: garantía, cambios, CBU, condiciones o lo que quieras decir. Va
  después del receptor y antes de las líneas, fuera de las zonas fiscales, y
  puede ser tan largo como haga falta: sigue en la hoja siguiente.

Con JSX tenés más espacios. Cada uno va en un lugar fijo, fuera de las zonas
fiscales:

| Espacio | Dónde va | Para qué |
| - | - | - |
| `<VoucherBrand>` | En el recuadro del emisor, sobre la razón social | El logo |
| `<VoucherIssuerDetails>` | En el recuadro, después de los datos fiscales del emisor | Teléfono, email, sitio web |
| `<VoucherReceiverDetails>` | Después de los datos del receptor | Teléfono, email, número de cliente |
| `<VoucherAside>` | A la izquierda de los totales | Pagos recibidos, saldo de cuenta corriente. Tiene que ser breve: va con los totales |
| `<VoucherNotes>` | Después del receptor, antes de las líneas | Garantía, CBU, observaciones, condiciones. Puede ocupar varias hojas |

```tsx theme={null}
import { Image, Text } from "@react-pdf/renderer";
import {
  renderVoucherPdf,
  Voucher,
  VoucherAside,
  VoucherBrand,
  VoucherIssuerDetails,
  VoucherNotes,
} from "@facturas/pdf";

const pdf = await renderVoucherPdf(
  <Voucher doc={comprobante} theme={{ accentColor: "#C00000" }}>
    <VoucherBrand>
      <Image src="https://tu-dominio.com/logo.png" />
    </VoucherBrand>
    <VoucherIssuerDetails>
      <Text>Tel. 11 4321-5678</Text>
      <Text>ventas@tu-dominio.com</Text>
    </VoucherIssuerDetails>
    <VoucherAside>
      <Text>Saldo de cuenta corriente: $ 196.773,50</Text>
    </VoucherAside>
    <VoucherNotes>
      <Text>Garantía oficial de 6 meses.</Text>
    </VoucherNotes>
  </Voucher>
);
```

Los totales, las leyendas y el pie con el CAE van siempre juntos: si no entran
en la hoja, pasan juntos a la siguiente, así que el CAE nunca queda solo. Si el
desglose de impuestos es muy largo, sus renglones siguen en la hoja siguiente y
el importe total, con `<VoucherAside>` a su izquierda, queda con el CAE. Las
líneas y las notas, en cambio, siguen en la hoja siguiente cuando no entran,
aunque una sola descripción sea más larga que una hoja.

Los bloques fiscales no se exportan: `<Voucher>` los ubica solo. Cualquier
otro hijo de `<Voucher>`, o un espacio repetido, hace que `renderVoucherPdf()`
tire un error que nombra el problema antes de dibujar nada. Usá
`renderVoucherPdf()` también con JSX: si llamás directo a `renderToBuffer` de
react-pdf, ese error llega como un `TypeError` sin el mensaje.

## Descuento global

En las clases A, B y C, ARCA no tiene un campo para un descuento sobre todo el
comprobante: lo autoriza ya restado de los ítems. Para imprimir las líneas antes
del descuento y un renglón "Descuento global", pasá los ítems sin descontar y el
descuento como lo repartiste al emitir:

```ts theme={null}
const comprobante = buildVoucherDocument({
  voucher: result.voucher,
  // Los ítems antes del descuento: 100,00 al 21% y 40,00 al 10,5%.
  items: [
    { description: "Servicio de instalación", net: 10_000, vat: 21 },
    { description: "Repuestos", net: 4000, vat: 10.5 },
  ],
  // Se emitió con 90,00 al 21% y 38,00 al 10,5%. 5 es el id del 21% y 4 el del 10,5%.
  globalDiscount: { 5: 1000, 4: 200 },
  // ...
});
```

El SDK no reparte el descuento: lo decidiste vos al emitir, y si lo recalculara
con su redondeo podría quedar a un centavo de lo autorizado. Lo que hace es
comprobar, alícuota por alícuota, que las líneas menos su descuento den la base
que autorizó ARCA: sin IVA en la clase A y con IVA en la B. En la clase C,
`globalDiscount` es un número y se compara con el neto. El exento y el no
gravado no llevan descuento.

El PDF imprime un solo renglón "Descuento global" con la suma, antes del
importe neto gravado en la clase A y antes del subtotal en las clases B y C. Las
líneas conservan su importe y su bonificación propia, si la tienen.

## Qué rechaza

`buildVoucherDocument()` prefiere fallar a imprimir algo incorrecto:

* Ítems que no suman lo autorizado: `ARCA_INPUT_AMOUNT_MISMATCH`. Con
  `globalDiscount`, el `field` nombra la alícuota que no cierra, como
  `globalDiscount[5]`.
* Un `globalDiscount` con la forma de otra clase, una clave que no es un id de
  alícuota o que ningún ítem lleva, o un importe negativo o con decimales:
  `ARCA_INPUT_INVALID_VALUE`.
* Un receptor sin documento que no sea consumidor final:
  `ARCA_INPUT_MISSING_FIELD`.
* Una cantidad por precio unitario que no da el importe de la línea:
  `ARCA_INPUT_AMOUNT_MISMATCH`.
* Un emisor que no puede emitir esa clase o un CUIT distinto del comprobante:
  `ARCA_INPUT_INVALID_VALUE`.
* Comprobantes FCE, que todavía no arma, comprobantes M de los tipos 51 a 53
  anteriores al 1 de diciembre de 2025 y un comprobante sin QR:
  `ARCA_INPUT_INVALID_VALUE`.

Las fuentes de cada regla, con su norma, inciso y checksum, están en
[PRINTED\_VOUCHER\_SOURCES.md](https://github.com/LaPyme/facturas/blob/main/.github/PRINTED_VOUCHER_SOURCES.md).
Es una lectura técnica de las normas, no asesoramiento impositivo.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.