Skip to content

Generar PDFs

El paquete UruFactura.Pdf genera la representación impresa de un CfeEmitido según la normativa de la DGI: datos del emisor y del receptor, detalle, totales, código QR y el pie con el código de seguridad, el CAE, el rango y el vencimiento.

Terminal window
dotnet add package UruFactura.Pdf

Formato Método Uso recomendado
A4 CfePdf.GenerarA4(emitido) Email, archivo digital, impresora de oficina
Térmico 80 mm CfePdf.GenerarTermico(emitido) Impresora de punto de venta (ticket)
QR (PNG) CfePdf.GenerarQr(emitido) Para insertarlo en un diseño propio
var emitido = await client.EmitirAsync(cfe);
byte[] a4 = CfePdf.GenerarA4(emitido);
byte[] ticket = CfePdf.GenerarTermico(emitido);
await File.WriteAllBytesAsync($"facturas/{emitido.Numero:D8}.pdf", a4);
await File.WriteAllBytesAsync($"tickets/{emitido.Numero:D8}_80mm.pdf", ticket);

Son métodos estáticos y puros: no necesitan el cliente ni configuración, así que se puede reimprimir un CFE recuperado del almacenamiento (por ejemplo, entidad.ToCfeEmitido() con EF Core). Si la DGI ya lo aceptó (emitido.AceptadoPorDgi), el A4 lo indica.

Las leyendas opcionales del pie salen del emisor: Emisor.FechaIncorporacion (“Fecha emisor”) y Emisor.UrlVerificacion (sitio de verificación de los e-Tickets; por defecto el de la DGI).

El contenido se adapta al tipo de comprobante:

Tipo Detalle Totales
e-Ticket, e-Factura y sus notas Cantidad, descripción, precio, IVA de cada línea y total Ajustes globales, netos e IVA por tasa, total
Exportación (e-Factura y e-Remito) Sin columna de IVA Total en la moneda del comprobante
e-Remito Cantidad y descripción, sin precios Sin montos
e-Resguardo Las retenciones/percepciones (código, tasa, monto sujeto y valor) Total retenido

En moneda extranjera se imprime el código ISO y el tipo de cambio; las notas de crédito y débito muestran a qué comprobante refieren (tipo, serie, número, fecha, monto y razón).


public class FacturaService(IUruFacturaClient client, IEmailService email)
{
public async Task EmitirYEnviarAsync(string emailCliente, IReadOnlyList<LineaDetalle> detalle)
{
var emitido = await client.EmitirAsync(new Cfe(TipoCfe.ETicket) { Detalle = detalle });
// Recibido = la DGI recibió el sobre; la aceptación del CFE se consulta después
var acuse = await client.EnviarAsync(emitido);
if (!acuse.Recibido)
throw new InvalidOperationException(acuse.Mensaje); // "Sobre rechazado (BS): motivos"
await email.SendAsync(new EmailMessage
{
To = emailCliente,
Subject = $"Tu e-Ticket {emitido.Serie}-{emitido.Numero}",
Body = "Adjuntamos tu comprobante fiscal electrónico.",
Attachment = new EmailAttachment
{
FileName = $"eticket_{emitido.Numero:D8}.pdf",
ContentType = "application/pdf",
Data = CfePdf.GenerarA4(emitido),
},
});
}
}

var blob = containerClient.GetBlobClient($"facturas/{emitido.Numero:D8}.pdf");
await blob.UploadAsync(new BinaryData(CfePdf.GenerarA4(emitido)), overwrite: true);