Ejemplos

  • Requerimientos


     
    public class Principal{
        public static void main(String[] args)throws ParserConfigurationException, SAXException, IOException, FileNotFoundException, 
            CertificateException, TransformerException, GeneralSecurityException{
            
            ProcesaXML procesaXML = new ProcesaXML();
            File xml = new File("src/main/resources/cfdi_v40_generico.xml");
            File certificate = new File("src/main/resources/ESCUELA_KEMPER_URGATE_EKU9003173C9.cer");
            File privateKey = new File("src/main/resources/ESCUELA_KEMPER_URGATE_EKU9003173C9.key");
            procesaXMl.readXML(xml,ceritifcate,privateKey);
            
        }
    }
    
     
                                            

    Variables

    Variable Descripción
    xml Tiene cargado el documento con el que deseamos realizar el timbrado.
    certificate Se le asigna el archivo .cer del emisor con el que haremos la prueba.
    privateKey Tiene cargado el archivo .key de nuestro emisor de pruebas.

    En la clase ProcesaXML.java se tienen los métodos necesarios para obtener el número de certificado y el certificado en base64 y enviarlo al xml además de tener el método de generarCadenaOriginal el cual es necesario para poder usar el método de generarSello y colocarlo en el documento.

  • La clase ClienteFormasDigitales es la que nos va a permitir procesar y timbrar el xml.

    La clase se inicializa pasandole el path del xml.

                $clienteFD = new ClienteFormasDigitales($filexml);
                                            

    Una vez inicializada la clase ClienteFormasDigitales se llama a la función loadCertKey que permite obtener el los datos del certificado y como resultado obtiene el xml sellado.

                $parametros->comprobante=$clienteFD->loadCertKey($filecer,$filekey);
                                            

    Una vez obtenido el xml sellado se llama a la función timbrarXML mandando como parametro un objeto de parametros que incluye los accesos y el xml.

                $responseTimbre = $clienteFD->timbrarXML($parametros);
                                            

    Ya que se halla realizado el timbrado si no ocurrio ningún problema al momento de timbrar se mostrará el xml timbrado en caso contrario se mostrará el error en pantalla.

            if(isset($responseTimbre->acuseCFDI->error)){
                echo "codigoErr: " . $responseTimbre->acuseCFDI->error. "
    "; } if($responseTimbre->acuseCFDI->xmlTimbrado){ echo 'XML TMIBRADO:
    '; }
  • Se cuenta con la clase Procesaxml que es la que nos permitirá agregar los datos del certificado, generación de la cadena original y el sellado del xml para posteriormente enviar el xml a timbrar a nuestro servicio de webservice.

    Con el método loadxml permitira procesar el xml y enviar los datos necesarios del certificado asi como la fecha actual. Una vez actualizados los datos al xml se hace el llamado a los métodos generaCadenaOriginal, generaSello, timbrarXML. Si no ocurrio ningún error al momento de timbrar el xml se guardará en un documento y se mostrará en la consola en caso contrario el error se mostrará en la consola.

     
            public void loadxml() {
                doc.Load(pathxml);
                doc.GetElementsByTagName("cfdi:Comprobante").Item(0).Attributes.GetNamedItem("Fecha").Value = getCurrentTime();
                loadcertificates();
                doc.GetElementsByTagName("cfdi:Comprobante").Item(0).Attributes.GetNamedItem("Certificado").Value = certificado;
                doc.GetElementsByTagName("cfdi:Comprobante").Item(0).Attributes.GetNamedItem("NoCertificado").Value = numCertificado;
    
                generaCadenaOriginal();
                generaSello();
                timbrarXML();
            }
     
                                                

    getCurrentTime permite obtener la fecha actual en formato (yyyy-MM-ddTHH:mm:ss) y regresarla para agregar al xml.

     
                private String getCurrentTime() {
                    return DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss");
                }
     
                                            

    Se usa el métodoloadcertificates para obtener el número y el certificado en base64 y asignarlo al xml.

     
                private void loadcertificates() {
                    X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pathcert));
                    certificado = Convert.ToBase64String(cert.GetRawCertData());
                    numCertificado = getSerialNumber(Encoding.Default.GetString(cert.GetSerialNumber()));
                }
     
                                            

    para obtener la cadena original se hace el llamado al método generaCadenaOriginal cargando el xslt de la versión 4.0.

     
            private void generaCadenaOriginal() {
                XmlDocument xsltDoc = new XmlDocument();
                xsltDoc.Load(xslcadenoriginalv40);
    
                XsltSettings xsltSettings = new XsltSettings(true,true);
                XmlUrlResolver resolver = new XmlUrlResolver();
                XslCompiledTransform myxslTransform = new XslCompiledTransform();
                myxslTransform.Load(xsltDoc, xsltSettings, resolver);
    
                StringWriter sw = new StringWriter();
                myxslTransform.Transform(doc, null, sw);
                cadenaoriginal = sw.ToString().Replace("\r\n", "");
            }
     
                                            

    Una vez generada la cadena original se llama a generaSello para poder realizar el firmado del xml y asignarle el sello para posteriormente enviarlo a timbrar al webservice.

     
            private void generaSello() {
                byte[] keyBytes = File.ReadAllBytes(pathKey);
                SecureString passSecure = new SecureString();
                passSecure.Clear();
                foreach (char c in passkey.ToCharArray()) {
                    passSecure.AppendChar(c);
                }
                
                RSACryptoServiceProvider rsa = opensslkey.DecodeEncryptedPrivateKeyInfo(keyBytes,passSecure);
                SHA256 sha256 = SHA256.Create();
                UTF8Encoding utf8 = new UTF8Encoding();
                byte[] cadenabytes = utf8.GetBytes(cadenaoriginal);
                byte[] digets = sha256.ComputeHash(cadenabytes);
                RSAPKCS1SignatureFormatter rsaformatter = new RSAPKCS1SignatureFormatter(rsa);
                rsaformatter.SetHashAlgorithm("SHA256");
                byte[] signedhashvalue = rsaformatter.CreateSignature(digets);
                String sello = Convert.ToBase64String(signedhashvalue);
                doc.GetElementsByTagName("cfdi:Comprobante").Item(0).Attributes.GetNamedItem("Sello").Value = sello;
    
            }
     
                                            

    Para poder timbrar el xml se hace uso de timbrarXML en donde se crea un objeto de accesos solicitado por el webservice en donde se le asigna el usuario y password de nuestros servicios además de enviarle el xml en una cadena de texto.

     
            public void timbrarXML() {
                accesos accesos = new accesos();
    
                accesos.usuario = "pruebasWS";
                accesos.password = "pruebasWS";
    
                WSTimbradoCFDIChannel wSTimbradoCFDIChannel;
                WSTimbradoCFDI wSTimbradoCFDI = new WSTimbradoCFDIClient();
                TimbrarCFDIRequest timbrarCFDIRequest = new TimbrarCFDIRequest();
                timbrarCFDIRequest.accesos = accesos;
                timbrarCFDIRequest.comprobante = doc.OuterXml;
    
                
                System.Threading.Tasks.Task response = wSTimbradoCFDI.TimbrarCFDIAsync(timbrarCFDIRequest);
                acuseCFDI acuse= response.Result.acuseCFDI;
                if (acuse.error != null) {
                    Console.WriteLine(acuse.codigoError + " - " + acuse.error);
                }
                else{
                    Console.WriteLine(acuse.xmlTimbrado);
                }
            }
     
                                            
  • Requerimientos

    La clase timbradov40 se localizan todos los métodos necesarios para realizar el procesamiento necesarios para generar la cadena original, el sello del xml y obtener el número del certificado así como el certificado en base64.
    Para poder empezar se necesita inicializar la clase con el path del xml, certificado, llave privada además del usuario y contraseña de los servicios de formas digitales.

    	def __init__(self,xml,certificado,llave_privada,usuario,password,Debug=None):
    		self.certificado=certificado
    		self.xml=xml
    		self.llave_privada=llave_privada
    		self.usuario = usuario
    		self.password = password
    		if Debug is not None:
                        self.DEBUG = Debug
                                                

    El método procesaxml inicia el proceso del tratamiento del xml en donde se carga en un objeto DOM para posteriormente asignarle la fecha actual con el formato solicitado por el SAT además de llamar a los métodos CargaCertificados,generaSello y timbrar.

                def procesaxml(self,path_xml):
    		data = ET.parse(path_xml)
    		comprobante = data.getroot()
    		fechacurrent = datetime.today().strftime('%Y-%m-%dT%H:%M:%S')
    		comprobante.set("Fecha",fechacurrent)
    		self.comprobante = comprobante 
    		self.cargaCertificados(self.certificado)#Se llama al metodo cargaCertificados
    		self.generaSello()
    		self.timbrar(self.usuario,self.password)
                                                

    cargaCertificados permite obtener la información del certificado como es el número del certificado y el certificado en base64 además de hacer el llamado al método generaCadenaOriginal.

                def cargaCertificados(self,path_cer):
    		with open(path_cer,'rb') as f:
    			certfile = f.read()
    		
    		cert = x509.load_pem_x509_certificate(certfile)
    		no_certificado = self.get_num_certificado(hex(cert.serial_number))
    		comprobante = self.comprobante
    		comprobante.set("NoCertificado",no_certificado)
    		certificado = certfile.decode('utf-8').replace('-----BEGIN CERTIFICATE-----','').replace('-----END CERTIFICATE-----','').replace('\n','')
    		comprobante.set("Certificado",certificado)
    		self.generaCadenaOriginal(comprobante)
                                                

    Con el mégeneraCadenaOriginal se obtiene la cadena original haciendo uso del archivo xslt de la versión 4.0.

                def generaCadenaOriginal(self,comprobante):
    		xslt = ET.parse(self.path_xslt)
    		transform = ET.XSLT(xslt)
    		cadena_original = transform(comprobante)
    		self.cadenaoriginal = str(cadena_original).replace("\n","")
                                                

    para enviar a timbrar el comprobante se requiere usar el método timbrar en donde se crea un cliente SOAP con la clase zeep adm&aaacute;s de crear los accesos para el uso del webservice. Para poder enviar a timbrar se quiere pasar como parametros los accesos y el comprobante como una cadena de texto.

                    def timbrar(self,usuario,password):
                        cliente_formas = zeep.Client(wsdl = self.wsdl_url)#Se crea un cliente soap del WSDL de formas digitales
                        try:
    			#Timbra cfdi
    			accesos_type = cliente_formas.get_type("ns1:accesos")
    			accesos_formas = accesos_type(usuario=usuario,password=password)#se crea el objeto de accesos
    
    			cfdi_timbrado = cliente_formas.service.TimbrarCFDI(accesos = accesos_formas,comprobante=ET.tostring(self.comprobante).decode('UTF-8'))#Se le envian los parametros solicitados los cuales son accesos y comprobante o xml en una cadena
    
    			if cfdi_timbrado['error'] == None: #Si no ocurrio ningún error al momento de timbrar el xml generará un xml timbrado y se plasmará en la consola
    				xmlTimbrado = cfdi_timbrado['xmlTimbrado']
    				print(xmlTimbrado)
    				filename = "xmltimbrado.xml"
    			else:#En caso contrario se genera un xml con el error e igual se mostrara en la consola
    				xmlTimbrado = cfdi_timbrado['codigoError'] + ' - ' + cfdi_timbrado['error']
    				print(xmlTimbrado)
    				filename = "xml_error.xml"
    			path = os.path.dirname(os.path.abspath(__file__)) + '/resources/'+filename
    			self.guardaXML(path,xmlTimbrado)
    
    		except Exception as exception:
    			print("Message %s" % exception)