public XmlDocument GeneraFacturaXml(string certificado, string llave, bool incluirDetallista, bool incluirAddenda, bool incluirAlsuper, bool incluirEdifact, bool incluirComercExt, bool incluirPago, bool incluirAmazon, out string cadenaOriginal, out string sello) { int cantComplementos = 0; // tipoComplemento: detallista, addenda, alsuper string tipoComplemento = string.Empty; // Generamos el comprobante y agregamos el certificado GeneraComprobante(); _comprobante.Certificado = certificado; #region Agregamos el nodo detallista if (incluirDetallista) { tipoComplemento = "detallista"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento); _comprobante.Complemento = new Schemasv33modif.ComprobanteComplemento[1]; _comprobante.Complemento[0] = new Schemasv33modif.ComprobanteComplemento { Any = new[] { tempDocument["detallista:detallista"] } }; cantComplementos += 1; } #endregion #region Agrega Complemento Comercio Exterior if (incluirComercExt) { tipoComplemento = "comercExterior"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento); _comprobante.Complemento = new Schemasv33modif.ComprobanteComplemento[1]; _comprobante.Complemento[0] = new Schemasv33modif.ComprobanteComplemento { Any = new[] { tempDocument["cce11:ComercioExterior"] } }; cantComplementos += 1; } #endregion #region Agrega Complemento de Pago if (incluirPago) { tipoComplemento = "pago"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento); _comprobante.Complemento = new Schemasv33modif.ComprobanteComplemento[1]; _comprobante.Complemento[0] = new Schemasv33modif.ComprobanteComplemento { Any = new[] { tempDocument["pago10:Pagos"] } }; cantComplementos += 1; } #endregion #region Generamos un documento XML usando la información actual de comprobante, detallista, ComercExt y Pago XmlDocument doc = new XmlDocument(); using (MemoryStream tempStream = new MemoryStream()) { XmlSerializer serializer = new XmlSerializer(typeof(Schemasv33modif.Comprobante)); serializer.Serialize(tempStream, _comprobante); tempStream.Seek(0, SeekOrigin.Begin); doc.Load(tempStream); } #endregion #region Generamos la cadena original using (MemoryStream tempStream = new MemoryStream()) { using ( XmlTextWriter xmlWriter = new XmlTextWriter(tempStream, Encoding.UTF8)) { doc.WriteContentTo(xmlWriter); xmlWriter.Flush(); tempStream.Seek(0, SeekOrigin.Begin); XPathDocument xpathFactura = new XPathDocument(tempStream); xmlWriter.Close(); // Generamos la cadena original usando el archivo XSLT del SAT Ver33 XslCompiledTransform xslCadena = new XslCompiledTransform(); xslCadena.Load("cadenaoriginal_3_3_local.xslt"); using (MemoryStream cadenaStream = new MemoryStream()) { xslCadena.Transform(xpathFactura, null, cadenaStream); cadenaOriginal = cadenaStream.GetString(); } } } // Elimina saltos de linea y espacios en blanco entre los campos de la cadena original char[] crlf = new char[] { '\n', '\r' }; string[] cadenaLineas = cadenaOriginal.Split(crlf); cadenaOriginal = null; for (int i = 0; i < cadenaLineas.Length; i++) { if ((cadenaLineas[i].Length >= 2) || (cadenaLineas[i].StartsWith("-"))) { cadenaOriginal += cadenaLineas[i].Substring(2).Trim(); } } #endregion #region Generamos el sello de la factura // La encriptación de la versión 33 debe ser en SHA-256 RSACryptoServiceProvider provider = OpenSSL.GetRsaProviderFromPem(llave); if (provider == null) { throw new Exception( "No se pudo crear el proveedor de seguridad a partir del archivo fel"); } byte[] selloBytes = provider.SignData( Encoding.UTF8.GetBytes(cadenaOriginal), "SHA256"); sello = Convert.ToBase64String(selloBytes); // Actualizamos el documento original con el sello _comprobante.Sello = sello; #endregion #region Agregamos la addenda if (incluirAddenda) { tipoComplemento = "addenda"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento, cadenaOriginal); _comprobante.Addenda = new Schemasv33modif.ComprobanteAddenda { Any = new[] { tempDocument["Addenda"]["requestForPayment"] } }; } #endregion #region Agrega addenda Alsuper if (incluirAlsuper) { tipoComplemento = "alsuper"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento); _comprobante.Addenda = new Schemasv33modif.ComprobanteAddenda { Any = new[] { tempDocument["alsuper:Alsuper"] } }; } #endregion #region Agrega addenda EDIFACT if (incluirEdifact) { tipoComplemento = "edifact"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento, cadenaOriginal, sello); _comprobante.Addenda = new Schemasv33modif.ComprobanteAddenda { Any = new[] { tempDocument["lev1add:EDCINVOICE"] } }; } #endregion #region Agrega addenda Amazon if (incluirAmazon) { tipoComplemento = "amazon"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento, cadenaOriginal, sello); _comprobante.Addenda = new Schemasv33modif.ComprobanteAddenda { Any = new[] { tempDocument["amazon:ElementosAmazon"] } }; } #endregion #region Genera documento final using (MemoryStream tempStream = new MemoryStream()) { doc = new XmlDocument(); XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(); namespaces.Add("cfdi", "http://www.sat.gob.mx/cfd/3"); XmlSerializer serializer = new XmlSerializer(typeof(Schemasv33modif.Comprobante)); serializer.Serialize(tempStream, _comprobante, namespaces); tempStream.Seek(0, SeekOrigin.Begin); doc.Load(tempStream); } #endregion #region Agregar atributos finales al documento XmlAttribute xsiAttrib = doc.CreateAttribute("xsi:schemaLocation", "http://www.w3.org/2001/XMLSchema-instance"); string textoAtributo = "http://www.sat.gob.mx/cfd/3 " + "http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv33.xsd " + "http://www.sat.gob.mx/detallista " + "http://www.sat.gob.mx/sitio_internet/cfd/detallista/detallista.xsd"; if (incluirAlsuper) { textoAtributo = textoAtributo + " http://proveedores.alsuper.com/CFD " + "http://proveedores.alsuper.com/addenda/1.xsd"; } if (incluirComercExt) { textoAtributo = textoAtributo + " http://www.sat.gob.mx/ComercioExterior11 " + "http://www.sat.gob.mx/sitio_internet/cfd/ComercioExterior11/ComercioExterior11.xsd"; } if (incluirPago) { textoAtributo = textoAtributo + " http://www.sat.gob.mx/Pagos " + "http://www.sat.gob.mx/sitio_internet/cfd/Pagos/Pagos10.xsd"; } xsiAttrib.InnerText = textoAtributo; doc["cfdi:Comprobante"].Attributes.Append(xsiAttrib); #endregion return(doc); }
public XmlDocument GeneraFacturaXml(string certificado, string llave, bool incluirDetallista, bool incluirAddenda, bool incluirAlsuper, bool incluirEdifact, out string cadenaOriginal, out string sello) { // tipoComplemento: detallista, addenda, alsuper string tipoComplemento = string.Empty; // Generamos el comprobante y agregamos el certificado GeneraComprobante(); _comprobante.certificado = certificado; #region Agregamos el nodo detallista if (incluirDetallista) { tipoComplemento = "detallista"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento); _comprobante.Complemento = new Schemasv22.ComprobanteComplemento { Any = new[] { tempDocument["detallista:detallista"] } }; } #endregion #region Generamos un documento XML usando la información actual de comprobante y detallista XmlDocument doc = new XmlDocument(); using (MemoryStream tempStream = new MemoryStream()) { XmlSerializer serializer = new XmlSerializer(typeof(Schemasv22.Comprobante)); serializer.Serialize(tempStream, _comprobante); tempStream.Seek(0, SeekOrigin.Begin); doc.Load(tempStream); } #endregion #region Generamos la cadena original using (MemoryStream tempStream = new MemoryStream()) { using ( XmlTextWriter xmlWriter = new XmlTextWriter(tempStream, Encoding.UTF8)) { doc.WriteContentTo(xmlWriter); xmlWriter.Flush(); tempStream.Seek(0, SeekOrigin.Begin); XPathDocument xpathFactura = new XPathDocument(tempStream); xmlWriter.Close(); // Generamos la cadena original usando el archivo XSLT del SAT Ver22 XslCompiledTransform xslCadena = new XslCompiledTransform(); xslCadena.Load("cadenaoriginal22.xslt"); using (MemoryStream cadenaStream = new MemoryStream()) { xslCadena.Transform(xpathFactura, null, cadenaStream); cadenaOriginal = cadenaStream.GetString(); } } } // Elimina saltos de linea y espacios en blanco entre los campos de la cadena original char[] crlf = new char[] { '\n', '\r' }; string[] cadenaLineas = cadenaOriginal.Split(crlf); cadenaOriginal = null; for (int i = 0; i < cadenaLineas.Length; i++) { if ((cadenaLineas[i].Length >= 2) || (cadenaLineas[i].StartsWith("-"))) { cadenaOriginal += cadenaLineas[i].Substring(2).Trim(); } } #endregion #region Generamos el sello de la factura RSACryptoServiceProvider provider = OpenSSL.GetRsaProviderFromPem(llave); if (provider == null) { throw new Exception( "No se pudo crear el proveedor de seguridad a partir del archivo fel"); } // Si la fecha es menor al 1 de Enero 2011, codifica con MD5 sino codifica con SHA1 byte[] selloBytes; if (DateTime.Now < Convert.ToDateTime("2011-01-01")) { selloBytes = provider.SignData( Encoding.UTF8.GetBytes(cadenaOriginal), "MD5"); } else { selloBytes = provider.SignData( Encoding.UTF8.GetBytes(cadenaOriginal), "SHA1"); } sello = Convert.ToBase64String(selloBytes); // Actualizamos el documento original con el sello _comprobante.sello = sello; #endregion #region Agregamos la addenda if (incluirAddenda) { tipoComplemento = "addenda"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento, cadenaOriginal); _comprobante.Addenda = new Schemasv22.ComprobanteAddenda { Any = new[] { tempDocument["Addenda"]["requestForPayment"] } }; } #endregion #region Agrega addenda Alsuper if (incluirAlsuper) { tipoComplemento = "alsuper"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento); _comprobante.Addenda = new Schemasv22.ComprobanteAddenda { Any = new[] { tempDocument["alsuper:Alsuper"] } }; } #endregion #region Agrega addenda EDIFACT if (incluirEdifact) { tipoComplemento = "edifact"; ComplementoFE complemento = new ComplementoFE(_iniAdd); XmlDocument tempDocument = complemento.GeneraComplementoXml(tipoComplemento); _comprobante.Addenda = new Schemasv22.ComprobanteAddenda { Any = new[] { tempDocument["Addenda"]["Documento"] } }; } #endregion #region Generamos el documento final using (MemoryStream tempStream = new MemoryStream()) { doc = new XmlDocument(); XmlSerializer serializer = new XmlSerializer(typeof(Schemasv22.Comprobante)); serializer.Serialize(tempStream, _comprobante); tempStream.Seek(0, SeekOrigin.Begin); doc.Load(tempStream); } #endregion #region Agregamos otros atributos del documento XmlAttribute xsiAttrib = doc.CreateAttribute("xsi:schemaLocation", "http://www.w3.org/2001/XMLSchema-instance"); string textoAtributo = "http://www.sat.gob.mx/cfd/2 " + "http://www.sat.gob.mx/sitio_internet/cfd/2/cfdv22.xsd " + "http://www.sat.gob.mx/detallista " + "http://www.sat.gob.mx/sitio_internet/cfd/detallista/detallista.xsd"; if (incluirAlsuper) { textoAtributo = textoAtributo + " http://proveedores.alsuper.com/CFD " + "http://proveedores.alsuper.com/addenda/1.xsd"; } xsiAttrib.InnerText = textoAtributo; doc["Comprobante"].Attributes.Append(xsiAttrib); #endregion return(doc); }