En 2015 haciendo mis prácticas profesionales en un despacho contable, conocí lo que era CFDI 3.2 y en mi afán de aprender, desarrollé una librería que generaba el XML sellado para su timbrado.
Pero justo al terminar mis prácticas, me contrató una empresa local dedicada a la facturación electrónica, donde laboré por más de 3 años dando soporte técnico al SDK para CFDI que comercializaban.
Con esa experiencia decidí volver a crear una librería para facturación electrónica, que coincidió con la llegada del Cfdi 3.3 y pude venderla cuando entró en vigor (ver aquí).
Además, al mismo tiempo en la empresa que trabajaba desarrollé una nueva versión del SDK, que también soportaba Cfdi 3.3, que entre sus características más resaltables eran:
- Retro compatibilidad con los proyectos que ya usaban el SDK anterior (prácticamente era quitar el viejo e incorporar el nuevo)
- Su nueva estructura le permitía darle soporte de forma mucho más facil
- Implementé un sistema de plugins que le permitía al SDK realizar operaciones antes, durante y después de generar y timbrar el Cfdi.
Con esos casi 4 años de experiencia y los casi 7 años de experiencia profesional, decidí crear una librería para CFDI 4.0.
Actualmente estoy desarrollando una librería que soporta las versiones 3.3 (aún vigente) y 4.0 de CFDI. Esta librería podrá incluir cualquier complemento que necesites por medio de librerías extra que iré desarrollando y liberando tan pronto como me sea posible.
¿Cómo consigo la librería?
La librería la puedes conseguir desde la nuget gallery o puedes buscarla en Visual Studio, desde nuget package manager, igual que los complementos.
Compatibilidad
¿De verdad es gratis?
Si, la librería para CFDI junto con las librerías para complementos son totalmente gratuitas. Este es un proyecto personal y deseó poder implementar la mayor cantidad de complementos posibles (a ser posible, todos).
Soporte Técnico
Actualmente no dispongo del tiempo que me gustaría para darle soporte a un proyecto como este y no puedo ofrecer soporte 24/7.
Como dije anteriormente, mi idea es implementar la mayoría de los complementos, por lo que si necesitasl alguno en concreto hazmelo saber.
Importante
- Actualmente estoy utilizando el ambiente de pruebas de Solución Factible para timbrar los CFDI y validar que las librerías estén trabajando correctamente.
- Pronto publicaré un repositorio de GitHub con los ejemplos que timbré para validar las librerías, está atento a este sitio para que puedas descargarlo.
Ejemplos
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
// Archivo XSLT necesario para la Cadena Original string xsltFile = @"cadenaoriginal_4_0.xslt"; // Certificados string cerFile = @"EKU9003173C9.cer"; string keyFile = @"EKU9003173C9.key"; string password = "12345678a"; // Se lee el Certificado var cerInfo = CsdUtils.LeerCertificado(cerFile); // Se crea el Comprobante IsaRoGaMX.Cfdi.v40.Comprobante cfdi = new IsaRoGaMX.Cfdi.v40.Comprobante(); // Datos de la Factura cfdi["Serie"] = "F"; cfdi["Folio"] = "1234"; cfdi["Fecha"] = DateTime.Now.ToString("s"); cfdi["CondicionesDePago"] = "CondicionesDePago"; cfdi["SubTotal"] = "200"; cfdi["Descuento"] = "1"; cfdi["Moneda"] = "MXN"; cfdi["TipoCambio"] = "1"; cfdi["Total"] = "198.95"; cfdi["TipoDeComprobante"] = "I"; cfdi["Exportacion"] = "01"; cfdi["MetodoPago"] = "PPD"; cfdi["FormaPago"] = "99"; cfdi["LugarExpedicion"] = "20000"; cfdi["Certificado"] = cerInfo.Certificado; cfdi["NoCertificado"] = cerInfo.NoCertificado; // Emisor cfdi.Emisor["Rfc"] = "EKU9003173C9"; cfdi.Emisor["Nombre"] = "ESCUELA KEMPER URGATE"; cfdi.Emisor["RegimenFiscal"] = "601"; // Receptor cfdi.Receptor["Rfc"] = "URE180429TM6"; cfdi.Receptor["Nombre"] = "UNIVERSIDAD ROBOTICA ESPAÑOLA"; cfdi.Receptor["DomicilioFiscalReceptor"] = "65000"; cfdi.Receptor["RegimenFiscalReceptor"] = "601"; cfdi.Receptor["UsoCFDI"] = "G01"; // Concepto cfdi.Conceptos[0]["ClaveProdServ"] = "50211503"; cfdi.Conceptos[0]["Cantidad"] = "1"; cfdi.Conceptos[0]["ClaveUnidad"] = "H87"; cfdi.Conceptos[0]["Unidad"] = "Pieza"; cfdi.Conceptos[0]["Descripcion"] = "Cigarros"; cfdi.Conceptos[0]["ValorUnitario"] = "200.00"; cfdi.Conceptos[0]["Descuento"] = "1"; cfdi.Conceptos[0]["Importe"] = "200.00"; cfdi.Conceptos[0]["ObjetoImp"] = "02"; cfdi.Conceptos[0].Impuestos.Traslados[0]["Base"] = "1"; cfdi.Conceptos[0].Impuestos.Traslados[0]["Importe"] = "0.16"; cfdi.Conceptos[0].Impuestos.Traslados[0]["Impuesto"] = "002"; cfdi.Conceptos[0].Impuestos.Traslados[0]["TasaOCuota"] = "0.160000"; cfdi.Conceptos[0].Impuestos.Traslados[0]["TipoFactor"] = "Tasa"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["Base"] = "1"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["Impuesto"] = "001"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["TipoFactor"] = "Tasa"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["TasaOCuota"] = "0.100000"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["Importe"] = "0.10"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["Base"] = "1"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["Impuesto"] = "002"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["TipoFactor"] = "Tasa"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["TasaOCuota"] = "0.106666"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["Importe"] = "0.11"; cfdi.Impuestos["TotalImpuestosRetenidos"] = "0.21"; cfdi.Impuestos["TotalImpuestosTrasladados"] = "0.16"; cfdi.Impuestos.Retenciones[0]["Impuesto"] = "001"; cfdi.Impuestos.Retenciones[0]["Importe"] = "0.10"; cfdi.Impuestos.Retenciones[1]["Impuesto"] = "002"; cfdi.Impuestos.Retenciones[1]["Importe"] = "0.11"; cfdi.Impuestos.Traslados[0]["Base"] = "1"; cfdi.Impuestos.Traslados[0]["Importe"] = "0.16"; cfdi.Impuestos.Traslados[0]["Impuesto"] = "002"; cfdi.Impuestos.Traslados[0]["TasaOCuota"] = "0.160000"; cfdi.Impuestos.Traslados[0]["TipoFactor"] = "Tasa"; // Genera cadena original string cadenaOriginal = XsltTransform.GeneraCadenaOriginal(cfdi.Documento, xsltFile); // Genera sello cfdi["Sello"] = CsdUtils.GeneraSelloFiscalDigital(cadenaOriginal, keyFile, password); // Se guarda el Xml cfdi.Documento.Save("F1234.xml"); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
// Archivo XSLT necesario para la Cadena Original string xsltFile = @"E:\Descargas\cadenaoriginal_4_0.xslt"; // Certificados string cerFile = @"EKU9003173C9.cer"; string keyFile = @"EKU9003173C9.key"; string password = "12345678a"; // Se lee el Certificado var cerInfo = CsdUtils.LeerCertificado(cerFile); // Se crea el comprobante IsaRoGaMX.Cfdi.v40.Comprobante cfdi = new IsaRoGaMX.Cfdi.v40.Comprobante(); // Datos del Comprobante cfdi["Serie"] = "NOM"; cfdi["Folio"] = "789"; cfdi["Fecha"] = DateTime.Now.ToString("s"); cfdi["SubTotal"] = "5000.00"; cfdi["Descuento"] = "200"; cfdi["Moneda"] = "MXN"; cfdi["Total"] = "4800"; cfdi["TipoDeComprobante"] = "N"; cfdi["Exportacion"] = "01"; cfdi["MetodoPago"] = "PUE"; cfdi["LugarExpedicion"] = "20000"; cfdi["Certificado"] = cerInfo.Certificado; cfdi["NoCertificado"] = cerInfo.NoCertificado; // Emisor cfdi.Emisor["Rfc"] = "URE180429TM6"; cfdi.Emisor["Nombre"] = "UNIVERSIDAD ROBOTICA ESPAÑOLA"; cfdi.Emisor["RegimenFiscal"] = "601"; // Receptor cfdi.Receptor["Rfc"] = "XOJI740919U48"; cfdi.Receptor["Nombre"] = "INGRID XODAR JIMENEZ"; cfdi.Receptor["DomicilioFiscalReceptor"] = "88965"; cfdi.Receptor["RegimenFiscalReceptor"] = "605"; cfdi.Receptor["UsoCFDI"] = "CN01"; // Conceptos cfdi.Conceptos[0]["ClaveProdServ"] = "84111505"; cfdi.Conceptos[0]["Cantidad"] = "1"; cfdi.Conceptos[0]["ClaveUnidad"] = "ACT"; cfdi.Conceptos[0]["Descripcion"] = "Pago de nómina"; cfdi.Conceptos[0]["ValorUnitario"] = "5000.00"; cfdi.Conceptos[0]["Descuento"] = "200"; cfdi.Conceptos[0]["Importe"] = "5000.00"; cfdi.Conceptos[0]["ObjetoImp"] = "01"; // Complemento Nomina var nomina = new IsaRoGaMX.Cfdi.Nomina.v12.Nomina(); nomina["TipoNomina"] = "O"; nomina["FechaPago"] = "2021-12-24"; nomina["FechaInicialPago"] = "2021-12-09"; nomina["FechaFinalPago"] = "2021-12-24"; nomina["NumDiasPagados"] = "15"; nomina["TotalPercepciones"] = "5000.0"; nomina["TotalDeducciones"] = "200"; // Emisor nomina.Emisor["RegistroPatronal"] = "B5510768108"; nomina.Emisor["RfcPatronOrigen"] = "URE180429TM6"; // Receptor nomina.Receptor["Curp"] = "XEXX010101HNEXXXA4"; nomina.Receptor["NumSeguridadSocial"] = "000000"; nomina.Receptor["FechaInicioRelLaboral"] = "2015-01-01"; nomina.Receptor["Antigüedad"] = "P364W"; nomina.Receptor["TipoContrato"] = "01"; nomina.Receptor["TipoJornada"] = "01"; nomina.Receptor["TipoRegimen"] = "03"; nomina.Receptor["NumEmpleado"] = "120"; nomina.Receptor["Departamento"] = "Desarrollo"; nomina.Receptor["Puesto"] = "Ingeniero de Software"; nomina.Receptor["RiesgoPuesto"] = "1"; nomina.Receptor["PeriodicidadPago"] = "04"; nomina.Receptor["CuentaBancaria"] = "1111111111"; nomina.Receptor["Banco"] = "002"; nomina.Receptor["SalarioBaseCotApor"] = "490.22"; nomina.Receptor["SalarioDiarioIntegrado"] = "146.47"; nomina.Receptor["ClaveEntFed"] = "JAL"; // Percepciones nomina.Percepciones["TotalSueldos"] = "5000.0"; nomina.Percepciones["TotalGravado"] = "2808.8"; nomina.Percepciones["TotalExento"] = "2191.2"; nomina.Percepciones[0]["TipoPercepcion"] = "001"; nomina.Percepciones[0]["Clave"] = "00500"; nomina.Percepciones[0]["Concepto"] = "Sueldos; Salarios Rayas y Jornales"; nomina.Percepciones[0]["ImporteGravado"] = "2808.8"; nomina.Percepciones[0]["ImporteExento"] = "2191.2"; // Deducciones nomina.Deducciones["TotalOtrasDeducciones"] = "200"; nomina.Deducciones[0]["TipoDeduccion"] = "001"; nomina.Deducciones[0]["Clave"] = "00301"; nomina.Deducciones[0]["Concepto"] = "Seguridad Social"; nomina.Deducciones[0]["Importe"] = "200"; // Se agrega el complemento cfdi.AgregaComplemento(nomina); // Genera cadena original string cadenaOriginal = XsltTransform.GeneraCadenaOriginal(cfdi.Documento, xsltFile); // Genera sello cfdi["Sello"] = CsdUtils.GeneraSelloFiscalDigital(cadenaOriginal, keyFile, password); cfdi.Documento.Save("NUM789.xml"); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
// ARchivo XSLT necesario para la Cadena Original string xsltFile = @"cadenaoriginal_4_0.xslt"; // Certificados string cerFile = @"EKU9003173C9.cer"; string keyFile = @"EKU9003173C9.key"; string password = "12345678a"; // Se lee el Certificado var cerInfo = CsdUtils.LeerCertificado(cerFile); // Se crea el Comprobante IsaRoGaMX.Cfdi.v40.Comprobante cfdi = new IsaRoGaMX.Cfdi.v40.Comprobante(); // Datos de la Factura cfdi["Serie"] = "F"; cfdi["Folio"] = "1234"; cfdi["Fecha"] = DateTime.Now.ToString("s"); cfdi["CondicionesDePago"] = "CondicionesDePago"; cfdi["SubTotal"] = "200"; cfdi["Descuento"] = "1"; cfdi["Moneda"] = "MXN"; cfdi["TipoCambio"] = "1"; cfdi["Total"] = "198.95"; cfdi["TipoDeComprobante"] = "I"; cfdi["Exportacion"] = "01"; cfdi["MetodoPago"] = "PPD"; cfdi["FormaPago"] = "99"; cfdi["LugarExpedicion"] = "20000"; cfdi["Certificado"] = cerInfo.Certificado; cfdi["NoCertificado"] = cerInfo.NoCertificado; // Emisor cfdi.Emisor["Rfc"] = "EKU9003173C9"; cfdi.Emisor["Nombre"] = "ESCUELA KEMPER URGATE"; cfdi.Emisor["RegimenFiscal"] = "601"; // Receptor cfdi.Receptor["Rfc"] = "URE180429TM6"; cfdi.Receptor["Nombre"] = "UNIVERSIDAD ROBOTICA ESPAÑOLA"; cfdi.Receptor["DomicilioFiscalReceptor"] = "65000"; cfdi.Receptor["RegimenFiscalReceptor"] = "601"; cfdi.Receptor["UsoCFDI"] = "G01"; // Concepto cfdi.Conceptos[0]["ClaveProdServ"] = "50211503"; cfdi.Conceptos[0]["Cantidad"] = "1"; cfdi.Conceptos[0]["ClaveUnidad"] = "H87"; cfdi.Conceptos[0]["Unidad"] = "Pieza"; cfdi.Conceptos[0]["Descripcion"] = "Cigarros"; cfdi.Conceptos[0]["ValorUnitario"] = "200.00"; cfdi.Conceptos[0]["Descuento"] = "1"; cfdi.Conceptos[0]["Importe"] = "200.00"; cfdi.Conceptos[0]["ObjetoImp"] = "02"; cfdi.Conceptos[0].Impuestos.Traslados[0]["Base"] = "1"; cfdi.Conceptos[0].Impuestos.Traslados[0]["Importe"] = "0.16"; cfdi.Conceptos[0].Impuestos.Traslados[0]["Impuesto"] = "002"; cfdi.Conceptos[0].Impuestos.Traslados[0]["TasaOCuota"] = "0.160000"; cfdi.Conceptos[0].Impuestos.Traslados[0]["TipoFactor"] = "Tasa"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["Base"] = "1"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["Impuesto"] = "001"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["TipoFactor"] = "Tasa"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["TasaOCuota"] = "0.100000"; cfdi.Conceptos[0].Impuestos.Retenciones[0]["Importe"] = "0.10"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["Base"] = "1"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["Impuesto"] = "002"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["TipoFactor"] = "Tasa"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["TasaOCuota"] = "0.106666"; cfdi.Conceptos[0].Impuestos.Retenciones[1]["Importe"] = "0.11"; // Complemento de Instituciones Educativas var iedu = new IsaRoGaMX.Cfdi.Iedu.v10.InstEducativas(); iedu["CURP"] = "AAAA010101HNLRNL09"; iedu["autRVOE"] = "PEFHS821923KSDJ823"; iedu["nivelEducativo"] = "Secundaria"; iedu["nombreAlumno"] = "Nombre Alumno"; iedu["rfcPago"] = "BBB010101AAA"; // Se agrega al concepto cfdi.Conceptos[0].AgregaComplemento(iedu); // Impuestos cfdi.Impuestos["TotalImpuestosRetenidos"] = "0.21"; cfdi.Impuestos["TotalImpuestosTrasladados"] = "0.16"; cfdi.Impuestos.Retenciones[0]["Impuesto"] = "001"; cfdi.Impuestos.Retenciones[0]["Importe"] = "0.10"; cfdi.Impuestos.Retenciones[1]["Impuesto"] = "002"; cfdi.Impuestos.Retenciones[1]["Importe"] = "0.11"; cfdi.Impuestos.Traslados[0]["Base"] = "1"; cfdi.Impuestos.Traslados[0]["Importe"] = "0.16"; cfdi.Impuestos.Traslados[0]["Impuesto"] = "002"; cfdi.Impuestos.Traslados[0]["TasaOCuota"] = "0.160000"; cfdi.Impuestos.Traslados[0]["TipoFactor"] = "Tasa"; // Genera cadena original string cadenaOriginal = XsltTransform.GeneraCadenaOriginal(cfdi.Documento, xsltFile); // Genera sello cfdi["Sello"] = CsdUtils.GeneraSelloFiscalDigital(cadenaOriginal, keyFile, password); // Se guarda el XML cfdi.Documento.Save("F1234.xml"); |
11/08/2022 a las 10:31 AM
Estimado Amigo:
al estar realizando las pruebas con tu código se esta generando el siguiente error al llegar a la ejecución de:
string cadenaOriginal = XsltTransform.GeneraCadenaOriginal(cfdi.Documento, xsltFile);
el error es:
XmlException: Por razones de seguridad, la DTD está prohibida en este documento XML. Para habilitar el procesamiento de la DTD, establezca la propiedad DtdProcessing de XmlReaderSettings en Parse y pase la configuración al método XmlReader.Create.
sabrás a que se deba?
le busque y comentan que hay que cambiar ProhibitDtd = False
30/08/2022 a las 9:59 AM
Buen dia, no he podido reproducir el error, siempre me genera el sello correctamente, me ayudaria bastante si haces un pequeño proyecto de prueba donde te genere el error para poder revisarlo, por favor incluye tu archivo xslt.
22/08/2023 a las 6:47 PM
Excelente aporte… lo probe con nomina y lo genera muy bien. Solo que trate de hacer una de donatarias, pero genera mal el schemalocation, falta el donat11.xsd. ¿Se puede modificar el schemalocation de alguna forma?
01/09/2023 a las 9:48 PM
Perdón no había visto tu comentario, me puedes decir específicamente cual es el error? para corregirlo y subirte la actualización, según yo se estaba generando correctamente el XML
20/07/2024 a las 8:41 AM
Buen día, ya fue corregido ese error
11/12/2024 a las 12:46 PM
Hechandole un vistazo