From a3add6893c0462fcc3bf4119f21094d3dfd70c5c Mon Sep 17 00:00:00 2001 From: rrene Date: Tue, 20 May 2025 17:14:02 -0700 Subject: [PATCH] - mejora --- Contabilidad/ContabilidadElectronica.aspx.vb | 155 ++++++++++++++----- 1 file changed, 113 insertions(+), 42 deletions(-) diff --git a/Contabilidad/ContabilidadElectronica.aspx.vb b/Contabilidad/ContabilidadElectronica.aspx.vb index 6774efaa5..126988874 100644 --- a/Contabilidad/ContabilidadElectronica.aspx.vb +++ b/Contabilidad/ContabilidadElectronica.aspx.vb @@ -1,9 +1,20 @@ Option Explicit On Option Strict On -Imports System.Data -Imports System.IO Imports Extensiones +Imports System +Imports System.IO +Imports System.Security.Cryptography +Imports System.Security.Cryptography.X509Certificates +Imports System.Text +Imports System.Xml +Imports System.Xml.Xsl +Imports System.Data +Imports CrystalDecisions.Web +Imports DocumentFormat.OpenXml.Wordprocessing +Imports Org.BouncyCastle.Asn1 +Imports Org.BouncyCastle.Tls.Crypto.Impl + Partial Class Contabilidad_ContabilidadElectronica Inherits ClsPaginas @@ -95,7 +106,7 @@ Partial Class Contabilidad_ContabilidadElectronica End If objconta.Dispose() Else - Dim ObjConpaq As New ClsContPAQi(UsuarioActual.Empresa) + Dim ObjConpaq As New ClsContPAQi(UsuarioActual.Empresa) If ObjConpaq.GetCuentasElectronica(MinFecha, FechaF) Then DtCuentas = ObjConpaq.DtResultados End If @@ -112,9 +123,6 @@ Partial Class Contabilidad_ContabilidadElectronica Str.AppendFormat("RFC=""{0}"" ", UsuarioActual.Empresa.RFC) Str.AppendFormat("Mes=""{0}"" ", DdlPeriodo.SelectedValue) Str.AppendFormat("Anio=""{0}"" ", DdlEjercicio.SelectedValue) - Str.AppendFormat("Sello=""{0}"" ", "123") - Str.AppendFormat("noCertificado=""{0}"" ", "123") - Str.AppendFormat("Certificado=""{0}"" ", "1234567890") Str.Append("xmlns:catalogocuentas=""www.sat.gob.mx/esquemas/ContabilidadE/1_3/CatalogoCuentas"">") 'DETALLES @@ -147,21 +155,15 @@ Partial Class Contabilidad_ContabilidadElectronica ArchivoCuentas = $"{UsuarioActual.Empresa.Ruta}/ContabilidadElectronica/{ UsuarioActual.Empresa.RFC}{DdlEjercicio.SelectedValue}{DdlPeriodo.SelectedValue.PadLeft(2, "0"c)}CT.xml" 'SOBREESCRIBE - If System.IO.File.Exists(ArchivoCuentas) Then - System.IO.File.Delete(ArchivoCuentas) - End If - - Dim fs As FileStream = File.Create(ArchivoCuentas) - Dim info As Byte() = New UTF8Encoding(True).GetBytes(Str.ToString) - fs.Write(info, 0, info.Length) - fs.Close() + If System.IO.File.Exists(ArchivoCuentas) Then System.IO.File.Delete(ArchivoCuentas) 'DESCARGA XML Dim DescargaZIP As Ionic.Zip.ZipFile = New Ionic.Zip.ZipFile() - If IO.File.Exists(ArchivoCuentas) Then - DescargaZIP.AddFile(ArchivoCuentas, "") - End If + 'generar el sello + SellarXML(Str.ToString, ArchivoCuentas, 1) + + If IO.File.Exists(ArchivoCuentas) Then DescargaZIP.AddFile(ArchivoCuentas, "") DescargaZIP.Save(Response.OutputStream) Response.AddHeader("content-Disposition", String.Format("attachment; filename={0}{1}{2}CT.zip", UsuarioActual.Empresa.RFC, DdlEjercicio.SelectedValue, DdlPeriodo.SelectedValue.PadLeft(2, "0"c))) @@ -172,6 +174,84 @@ Partial Class Contabilidad_ContabilidadElectronica End Sub + Private Function SellarXML(xmltexto As String, ArchivoCuentas As String, Opcion As Integer) As String + Dim ArchivoLLave As String = $"{UsuarioActual.Empresa.Ruta}Certificados\{UsuarioActual.Empresa.ArchivoKey}" + Dim Archivopfx As String = $"{UsuarioActual.Empresa.Ruta}Certificados\{UsuarioActual.Empresa.FielPFX }" + Dim Clavepfx As String = UsuarioActual.Empresa.FielPassword + + Dim xsltPath As String + Select Case Opcion + Case 1 + xsltPath = $"{AppDomain.CurrentDomain.BaseDirectory}Temp\CatalogoCuentas_1_3.xslt" + Case 2 + xsltPath = $"{AppDomain.CurrentDomain.BaseDirectory}Temp\BalanzaComprobacion_1_3.xslt" + End Select + + If Not File.Exists(ArchivoLLave) Then + Alert("El archivo de llave privada no existe", TipoMensaje.MsgError) + End If + + ' 1. Cargar y transformar el XML para obtener la Cadena Original + Dim originalCadena As String = GenerarCadenaOriginal(xmltexto, xsltPath) + + ' 2. Cargar tu certificado PFX (incluye la clave privada) + Dim cert As New X509Certificate2(Archivopfx, Clavepfx, X509KeyStorageFlags.MachineKeySet) + + ' 3. Firmar la cadena con SHA256 + Dim selloBytes As Byte() + Using rsa As RSA = cert.GetRSAPrivateKey() + selloBytes = rsa.SignData( + Encoding.UTF8.GetBytes(originalCadena), + HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1) + End Using + Dim selloBase64 As String = Convert.ToBase64String(selloBytes) + + ' 4. Obtener el certificado (público) en Base64 y el número de certificado + Dim certBase64 As String = Convert.ToBase64String(cert.RawData) + Dim noCertificado As String = cert.GetSerialNumberString() + + ' 5. Insertar atributos en el XML + Dim xmlDoc As New XmlDocument() + xmlDoc.PreserveWhitespace = True ' conserva espacios y saltos + xmlDoc.LoadXml(xmltexto) + + Dim root As XmlElement = xmlDoc.DocumentElement + root.SetAttribute("Sello", selloBase64) + root.SetAttribute("noCertificado", noCertificado) + root.SetAttribute("certificado", certBase64) + + ' 6. Guardar archivo sellado + Dim StrFinal As String = xmlDoc.OuterXml + Dim fs As FileStream = File.Create(ArchivoCuentas) + Dim info As Byte() = New UTF8Encoding(True).GetBytes(StrFinal) + fs.Write(info, 0, info.Length) + fs.Close() + 'xmlDoc.Save(ArchivoCuentas) + Return StrFinal + End Function + + ''' + ''' Aplica el XSLT para generar la Cadena Original según SAT. + ''' + Function GenerarCadenaOriginal(xmlContenido As String, xsltFile As String) As String + ' Carga la transformación XSLT + Dim xslt As New XslCompiledTransform() + xslt.Load(xsltFile) + + ' Prepara un StringReader sobre el contenido del XML + Using sr As New StringReader(xmlContenido), + xr As XmlReader = XmlReader.Create(sr), + sw As New StringWriter() + + ' Ejecuta la transformación + xslt.Transform(xr, Nothing, sw) + + ' Devuelve la cadena original (trim para quitar saltos extra) + Return sw.ToString().Trim() + End Using + End Function + Private Sub GeneraBalanza() Dim FechaI As Date = String.Format("01/{0}/{1}", DdlPeriodo.SelectedValue.PadLeft(2, "0"c), DdlEjercicio.SelectedValue).ToDate Dim FechaF As Date = FechaI.LastDayOfMonth @@ -186,10 +266,10 @@ Partial Class Contabilidad_ContabilidadElectronica If DtCuentas IsNot Nothing Then Dim Deudor As Decimal = DtCuentas.SUM("SaldoAD") Dim Acreedor As Decimal = DtCuentas.SUM("SaldoAA") - If Deudor <> Acreedor Then - Alert("los Saldos Actuales no cuadran.", TipoMensaje.MsgError) - Exit Sub - End If + 'If Deudor <> Acreedor Then + ' Alert("los Saldos Actuales no cuadran.", TipoMensaje.MsgError) + ' Exit Sub + 'End If End If Else Dim ObjConpaq As New ClsContPAQi(UsuarioActual.Empresa) @@ -204,24 +284,23 @@ Partial Class Contabilidad_ContabilidadElectronica 'CABECERA Str.Append("") - Str.Append("") - + Str.AppendFormat("FechaModBal=""{0}"" >", FechaF.ToString("yyyy-MM-dd")) 'DETALLES For Each Dr As DataRow In DtCuentas.Rows - Str.Append("") Next - DtCuentas.Dispose() 'FIN - Str.Append("") - + Str.Append("") 'GUARDA ARHIVO ArchivoBalanza = Server.MapPath(String.Format("~/Empresas/{0}/ContabilidadElectronica/{1}{2}{3}BN.xml", UsuarioActual.CveEmpresa, UsuarioActual.Empresa.RFC, DdlEjercicio.SelectedValue, DdlPeriodo.SelectedValue.PadLeft(2, "0"c))) @@ -251,14 +328,10 @@ Partial Class Contabilidad_ContabilidadElectronica 'SOBREESCRIBE If System.IO.File.Exists(ArchivoBalanza) Then System.IO.File.Delete(ArchivoBalanza) - - Dim fs As FileStream = File.Create(ArchivoBalanza) - Dim info As Byte() = New UTF8Encoding(True).GetBytes(Str.ToString) - fs.Write(info, 0, info.Length) - fs.Close() - 'DESCARGA XML Dim DescargaZIP As Ionic.Zip.ZipFile = New Ionic.Zip.ZipFile() + 'generar el sello + SellarXML(Str.ToString, ArchivoBalanza, 2) If IO.File.Exists(ArchivoBalanza) Then DescargaZIP.AddFile(ArchivoBalanza, "") @@ -275,6 +348,4 @@ Partial Class Contabilidad_ContabilidadElectronica #End Region - - End Class