CFDI.BuildPdf
2.0.0
See the version list below for details.
dotnet add package CFDI.BuildPdf --version 2.0.0
NuGet\Install-Package CFDI.BuildPdf -Version 2.0.0
<PackageReference Include="CFDI.BuildPdf" Version="2.0.0" />
<PackageVersion Include="CFDI.BuildPdf" Version="2.0.0" />
<PackageReference Include="CFDI.BuildPdf" />
paket add CFDI.BuildPdf --version 2.0.0
#r "nuget: CFDI.BuildPdf, 2.0.0"
#:package CFDI.BuildPdf@2.0.0
#addin nuget:?package=CFDI.BuildPdf&version=2.0.0
#tool nuget:?package=CFDI.BuildPdf&version=2.0.0
📦 CFDI.BuildPdf
Descripción general
CFDI.BuildPdf es una librería .NET 6+ que genera una representación impresa en PDF a partir de un XML CFDI 4.0. Detecta automáticamente el tipo de complemento y soporta actualmente:
- Complemento Carta Porte 3.1
- Complemento Nómina 1.2
Es cross-platform (Windows, Linux, macOS, contenedores) y no tiene dependencias nativas: usa QuestPDF como motor de renderizado y QRCoder para el código QR del timbre fiscal.
📥 Instalación
dotnet add package CFDI.BuildPdf
🚀 Características
- ✔️ Soporte para CFDI 4.0 con complementos Carta Porte 3.1 y Nómina 1.2.
- ✔️ Detección automática del tipo de complemento.
- ✔️ Múltiples formatos de entrada: ruta de archivo,
string,byte[]yStream. - ✔️ Escritura directa a archivo o
Streamde salida (ideal para respuestas HTTP). - ✔️ Opciones configurables: mostrar/ocultar mercancías, condiciones del contrato, addenda; logotipo en Base64; orientación portrait/landscape.
- ✔️ Inyección de dependencias con
Microsoft.Extensions.DependencyInjection. - ✔️ Integración opcional con
ILoggerpara diagnóstico. - ✔️ Excepciones de dominio claras (
CfdiXmlInvalidoException,CfdiComplementoNoSoportadoException).
📁 Estructura del PDF generado
- Datos del emisor y receptor.
- UUID, fecha de certificación y certificados.
- Totales e impuestos del CFDI.
- Addenda genérica (si aplica).
- Complemento Carta Porte: ubicaciones, mercancías (detalle o resumen), autotransporte, seguros, remolques, figuras de transporte, página de condiciones del contrato.
- Complemento Nómina: datos del empleado, percepciones, deducciones, otros pagos, incapacidades, totales.
- QR y sellos digitales.
⚠️ Licencia QuestPDF (léeme antes de producción)
Esta librería usa QuestPDF, que tiene licencia dual:
- Community (gratuita) — apta para la mayoría de proyectos open-source y empresas que cumplan los criterios de elegibilidad vigentes del proveedor.
- Professional / Enterprise (de pago) — requerida por QuestPDF para el resto de organizaciones.
El consumidor de esta librería es responsable de elegir y adquirir la licencia correcta. Consulta los términos vigentes en https://www.questpdf.com/license/.
Por defecto, CFDI.BuildPdf declara Community. Para cambiarlo:
Con la fachada estática
using CFDI.BuildPdf.Abstractions;
using CFDI.BuildPdf.Service;
// Llamar una sola vez al iniciar el proceso, antes de generar cualquier PDF
CfdiPdf.ConfigureQuestPdfLicense(CfdiPdfLicenseType.Professional);
Con inyección de dependencias
builder.Services.AddCfdiPdfServices(
configure: opts => opts.MostrarMercancias = true,
licenseType: CfdiPdfLicenseType.Professional);
📚 Requisitos
- .NET 6.0 o superior.
- Sin dependencias nativas (no requiere
wkhtmltopdfni binarios de sistema).
🔵 Uso básico (fachada estática)
Desde una ruta de archivo
using CFDI.BuildPdf.Service;
var pdfBytes = await CfdiPdf.DesdeRutaAsync(@"C:\facturas\cfdi.xml");
await File.WriteAllBytesAsync("cfdi_output.pdf", pdfBytes);
Desde un string XML
var pdfBytes = await CfdiPdf.DesdeXmlStringAsync(xmlString);
Desde bytes
var pdfBytes = await CfdiPdf.DesdeXmlBytesAsync(xmlBytes);
Desde un Stream (por ejemplo, IFormFile en ASP.NET Core)
await using var stream = archivoXml.OpenReadStream();
var pdfBytes = await CfdiPdf.DesdeStreamAsync(stream);
Guardar directamente a archivo
await CfdiPdf.GuardarDesdeRutaAsync(
rutaXml: @"C:\facturas\cfdi.xml",
rutaPdfDestino: @"C:\facturas\cfdi.pdf");
Escribir en un Stream de salida (respuesta HTTP)
[HttpPost("generar-pdf")]
public async Task<IActionResult> GenerarPdf(IFormFile xml)
{
Response.ContentType = "application/pdf";
await using var xmlStream = xml.OpenReadStream();
await CfdiPdf.EscribirEnStreamAsync(xmlStream, Response.Body);
return new EmptyResult();
}
⚙️ Opciones de generación
var options = new CfdiPdfOptions
{
MostrarMercancias = true, // Carta Porte: mostrar detalle de mercancías
MostrarCondicionesContrato = true, // Carta Porte: incluir página de condiciones
MostrarAddenda = true, // Incluir sección de addenda
LogoBase64 = logoBase64, // Logo de la empresa (opcional)
Orientacion = PdfOrientation.Portrait
};
var pdfBytes = await CfdiPdf.DesdeRutaAsync(rutaXml, options);
💉 Uso con inyección de dependencias
Registro de servicios
using CFDI.BuildPdf.Abstractions;
using CFDI.BuildPdf.Configuration;
builder.Services.AddCfdiPdfServices(
configure: opts =>
{
opts.MostrarMercancias = true;
opts.MostrarCondicionesContrato = true;
},
licenseType: CfdiPdfLicenseType.Community);
Consumo desde un servicio
using CFDI.BuildPdf.Abstractions;
public class FacturaService
{
private readonly ICfdiPdfGenerator _generator;
public FacturaService(ICfdiPdfGenerator generator)
{
_generator = generator;
}
public Task<byte[]> GenerarPdfAsync(string rutaXml)
=> _generator.GenerarDesdeRutaAsync(rutaXml);
}
🛑 Manejo de errores
Los métodos públicos lanzan excepciones de dominio específicas para facilitar el diagnóstico:
| Excepción | Cuándo ocurre |
|---|---|
ArgumentNullException / ArgumentException |
Inputs nulos, vacíos o inválidos. |
FileNotFoundException |
La ruta del XML no existe. |
CfdiXmlInvalidoException |
El contenido no es un XML bien formado. |
CfdiComplementoNoSoportadoException |
El CFDI no contiene Carta Porte 3.1 ni Nómina 1.2. |
CfdiPdfException |
Clase base para cualquier error de dominio de la librería. |
try
{
var pdf = await CfdiPdf.DesdeRutaAsync(ruta);
}
catch (CfdiXmlInvalidoException ex)
{
logger.LogWarning(ex, "XML no válido: {Mensaje}", ex.Message);
}
catch (CfdiComplementoNoSoportadoException ex)
{
logger.LogWarning(ex, "Complemento no soportado: {Mensaje}", ex.Message);
}
📝 Licencia
Este proyecto está bajo licencia MIT. Recuerda que QuestPDF (dependencia interna) tiene su propia licencia dual — ver sección arriba.
👤 Autor
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net6.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 6.0.4)
- Microsoft.Extensions.Options (>= 6.0.0)
- QRCoder (>= 1.6.0)
- QuestPDF (>= 2024.3.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.8 | 110 | 4/29/2026 |
| 2.0.7 | 97 | 4/22/2026 |
| 2.0.6 | 104 | 4/19/2026 |
| 2.0.5 | 95 | 4/16/2026 |
| 2.0.4 | 116 | 4/12/2026 |
| 2.0.3 | 97 | 4/12/2026 |
| 2.0.2 | 96 | 4/12/2026 |
| 2.0.1 | 105 | 4/12/2026 |
| 2.0.0 | 103 | 4/12/2026 |
| 1.0.5 | 275 | 6/16/2025 |
| 1.0.4 | 253 | 5/1/2025 |
| 1.0.3 | 241 | 4/30/2025 |
| 1.0.2 | 239 | 4/30/2025 |
| 1.0.1 | 223 | 4/30/2025 |
| 1.0.0 | 218 | 4/30/2025 |