import os import com import xml import util DEFINE url_semilla, url_validasemilla,url_anulacion, url_recepcion,url_consulta,url_consulta_timbre STRING DEFINE codigo,tokenxml,nombreFile,filexml,token,respuesta,ruta_firmados,rutaSemilla,rutaCert STRING DEFINE doc xml.DomDocument, xfacturainterna,gsucid,gbodega INT, goperacion VARCHAR(30) FUNCTION procesoEncf(fileporfirmar,ambiente,tiporecepcion,xsucid,xbodega,xoperacion,krespuesta) DEFINE fileporfirmar,rtoken,ambiente,tiporecepcion,krespuesta STRING, xhash VARCHAR(6),xfechafirmadigital VARCHAR(50), xsucid,xbodega INT, xoperacion CHAR(30) DEFINE dtrackid RECORD trackId,error,mensaje STRING END RECORD, xfecha DATETIME YEAR TO minute CALL STARTLOG("procesoencf.txt") # LET ptipoRecepcion = tiporecepcion LET ruta_firmados = fgl_getenv("RUTA_XML_FIRMADOS") LET rutaSemilla = fgl_getenv("RUTA_SEMILLA") LET rutaCert = fgl_getenv("RUTA_CERT") DISPLAY "ruta firma ",ruta_firmados IF ambiente <> "produccion" THEN IF ambiente <> "test" THEN LET respuesta = "no llego bien ",ambiente RETURN ' ',respuesta,'400' END IF END IF # LET xambiente = ambiente CALL urls(ambiente,tiporecepcion) { SELECT a.valor,a.fecha INTO rtoken,xfecha FROM token a DISPLAY "tiempos: ",xfecha," ",CURRENT HOUR TO MINUTE} # IF CURRENT HOUR TO MINUTE- xfecha > "0:44" THEN CALL buscatoken() RETURNING codigo, tokenxml IF codigo <> "200" THEN LET respuesta = "respuesta buscatoken: ",tokenxml," ",codigo RETURN ' ',respuesta,'400' END IF LET gsucid = xsucid LET gbodega = xbodega LET goperacion = xoperacion # Create DomDocument object LET doc = xml.DomDocument.Create() # Notice that whitespaces are significant in cryptography, # therefore it is recommended to remove unnecessary ones CALL doc.setFeature("whitespace-in-element-content",FALSE) CALL doc.loadFromString(tokenxml) # CALL doc.save(".\\filesXML\\marmotech\\mtechTokenString.xml") CALL doc.save(rutaSemilla||"/TokenString.xml") #FIRMA SEMILLA IF os.Path.exists(rutaSemilla||"/TokenString.xml") THEN CALL firmasemilla() ELSE LET respuesta = "NO PUDE CREAR SEMILLA" RETURN ' ',respuesta,'400' END IF IF os.Path.exists(rutaSemilla||"/Signature.xml") THEN CALL validasemilla() RETURNING codigo,respuesta IF codigo = 400 THEN RETURN ' ',respuesta,'400' END IF ELSE LET respuesta = "NO ENCONTRE LA SEMILLA FIRMADA" RETURN ' ',respuesta,'400' END IF IF respuesta IS NOT NULL THEN LET doc = xml.DomDocument.Create() CALL doc.loadFromString(respuesta) CALL doc.save(rutaSemilla||"/RespuestaValida.xml") CALL gettoken() RETURNING rtoken LET token = rtoken # UPDATE token SET valor = rtoken,fecha=getdate() ELSE LET respuesta = "NO TENEMOS RESPUESTA DE VALIDA SEMILLA" RETURN ' ',respuesta,'400' END IF # ELSE # DISPLAY "en validar semilla" # CALL validasemilla() RETURNING codigo,respuesta # IF codigo = 400 THEN # RETURN ' ',respuesta,'400' # END IF # END IF DISPLAY "file a enviar1 :",fileporfirmar # CUANDO EL PROCESO NO ES FIRMAR EL DOCUMENTO IF xoperacion <> 'consultatrackid' AND xoperacion <> 'consultastatus' THEN LET filexml = fileporfirmar CALL firmadocumento(fileporfirmar) LET filexml = ruta_firmados CLIPPED,os.Path.baseName(fileporfirmar) DISPLAY "file a enviar :",filexml CALL enviafiles(token,filexml) RETURNING codigo,respuesta CALL gethash(filexml) RETURNING xhash,xfechafirmadigital,xfacturainterna DISPLAY "luego del gethash: ",xhash # UPDATE vetb00002 SET hash = xhash WHERE factura = xfacturainterna AND sucid = xsucid ELSE IF xoperacion = 'consultatrackid' THEN LET token = " Bearer ",token CALL consultaResultado(token,krespuesta) RETURNING codigo, respuesta END IF IF xoperacion = 'consultastatus' THEN LET token = " ApiKey ",token CALL obtenerStatus(token) END IF END IF RETURN xhash,respuesta,codigo END FUNCTION FUNCTION firmadocumento(fileafirmar) DEFINE doc xml.DomDocument DEFINE doc2 xml.DomDocument DEFINE root xml.DomNode DEFINE node xml.DomNode DEFINE signNode xml.DomNode DEFINE sig xml.Signature DEFINE key xml.CryptoKey DEFINE cert xml.CryptoX509 DEFINE index INTEGER, fileafirmar STRING LET rutaCert = fgl_getenv("RUTA_CERT") LET ruta_firmados = fgl_getenv("RUTA_XML_FIRMADOS") # Create DomDocument object LET doc = xml.DomDocument.Create() # Notice that whitespaces are significant in cryptography, # therefore it is recommended to remove unnecessary ones CALL doc.setFeature("whitespace-in-element-content",FALSE) DISPLAY "file ",fileafirmar LET filexml = fileafirmar CALL doc.load(fileafirmar) TRY # Create rsa key LET key = xml.CryptoKey.Create("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256") #CALL key.loadPEM(".\\cert\\marmotech\\onlyRSA.pem") CALL key.loadPEM(rutaCert clipped||"/onlyRSA.pem") # Create an X509 certificate with the constructor of the CryptoX509 class. LET cert = xml.CryptoX509.Create() CALL cert.setFeature("X509Certificate",TRUE) # Load the X509 certificate associated to the RSA or DSA private key into the CryptoKey object. # CALL cert.loadPEM("cert509.crt") CALL cert.loadPEM(rutaCert clipped||"/onlyCert.pem") # Create signature object with the key to use LET sig = xml.Signature.Create() # Assign the CryptoKey object to the Signature object. CALL sig.setKey(KEY) # Assign the CryptoX509 object to the Signature object. CALL sig.setCertificate(cert) # Set XML node to be signed. In our case, the entire document # LET index = sig.createReference("", # "http://www.w3.org/2001/04/xmlenc#sha256") LET index = sig.createReference('""', "http://www.w3.org/2001/04/xmlenc#sha256") # Add enveloped method to not take the XML signature node into account # when computing the entire document. CALL sig.appendReferenceTransformation(index, "http://www.w3.org/2000/09/xmldsig#enveloped-signature",doc.getDocumentElement()) # Set canonicalization method on the XML fragment to be signed. # Compute enveloped signature CALL sig.compute(doc) # Retrieve signature document LET doc2=sig.getDocument() # Append the signature node to the original document to get # a valid enveloped signature # Notice that the enveloped signature can be added anywhere in the # original document LET signNode = doc2.getDocumentElement() # Get Signature node # Import it into the original document LET node = doc.importNode(signNode,true) # Retrieve the original document root node LET root = doc.getDocumentElement() # Append the signature node as last child of the original document CALL root.appendChild(node) # Save document with enveloped signature back to disk CALL doc.setFeature("format-pretty-print",TRUE) LET fileafirmar = ruta_firmados CLIPPED,os.Path.baseName(fileafirmar) CALL doc.save(fileafirmar) DISPLAY "file firmado", fileafirmar CATCH DISPLAY "Unable to create an enveloped signature :",status," ",sqlca.sqlerrm DISPLAY "aqui" END TRY END FUNCTION FUNCTION firmasemilla() DEFINE doc xml.DomDocument DEFINE doc2 xml.DomDocument DEFINE root xml.DomNode DEFINE node xml.DomNode DEFINE signNode xml.DomNode DEFINE sig xml.Signature DEFINE key xml.CryptoKey DEFINE cert xml.CryptoX509 DEFINE index INTEGER LET rutaCert = fgl_getenv("RUTA_CERT") # Create DomDocument object LET doc = xml.DomDocument.Create() # Notice that whitespaces are significant in cryptography, # therefore it is recommended to remove unnecessary ones CALL doc.setFeature("whitespace-in-element-content",FALSE) LET filexml = rutaSemilla||"/TokenString.xml" IF os.Path.exists(filexml) THEN CALL doc.load(filexml) ELSE DISPLAY "NO LO ENCONTRE" RETURN END IF TRY # Create rsa key LET key = xml.CryptoKey.Create("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256") CALL key.loadPEM(rutaCert||"/onlyRSA.pem") # Create an X509 certificate with the constructor of the CryptoX509 class. LET cert = xml.CryptoX509.Create() CALL cert.setFeature("X509Certificate",TRUE) # Load the X509 certificate associated to the RSA or DSA private key into the CryptoKey object. # CALL cert.loadPEM("cert509.crt") CALL cert.loadPEM(rutaCert||"/onlyCert.pem") # Create signature object with the key to use LET sig = xml.Signature.Create() # Assign the CryptoKey object to the Signature object. CALL sig.setKey(KEY) # Assign the CryptoX509 object to the Signature object. CALL sig.setCertificate(cert) # Set XML node to be signed. In our case, the entire document # LET index = sig.createReference("", # "http://www.w3.org/2001/04/xmlenc#sha256") LET index = sig.createReference('""', "http://www.w3.org/2001/04/xmlenc#sha256") # Add enveloped method to not take the XML signature node into account # when computing the entire document. CALL sig.appendReferenceTransformation(index, "http://www.w3.org/2000/09/xmldsig#enveloped-signature",doc.getDocumentElement()) # Set canonicalization method on the XML fragment to be signed. # CALL sig.appendReferenceTransformation(index, # "http://www.w3.org/2001/10/xml-exc-c14n#") # Compute enveloped signature CALL sig.compute(doc) # Retrieve signature document LET doc2=sig.getDocument() # Append the signature node to the original document to get # a valid enveloped signature # Notice that the enveloped signature can be added anywhere in the # original document LET signNode = doc2.getDocumentElement() # Get Signature node # Import it into the original document LET node = doc.importNode(signNode,true) # Retrieve the original document root node LET root = doc.getDocumentElement() # Append the signature node as last child of the original document CALL root.appendChild(node) # Save document with enveloped signature back to disk CALL doc.setFeature("format-pretty-print",TRUE) CALL doc.save(rutaSemilla||"/Signature.xml") CATCH DISPLAY "Unable to create an enveloped signature :",status," ",sqlca.sqlerrm END TRY END FUNCTION FUNCTION validasemilla() DEFINE respuesta,codigo STRING, http_req com.HttpRequest, http_resp com.HTTPResponse LET http_req = com.HTTPRequest.Create(url_validasemilla) CALL http_req.setMethod("POST") CALL http_req.setCharset("UTF-8") CALL http_req.setHeader("accept","application/xml") CALL http_req.setMultipartType("form-data",NULL,NULL) CALL http_req.setConnectionTimeOut(10) IF os.Path.exists(rutaSemilla||"/Signature.xml") THEN # CALL http_req.setHeader("Content-Disposition", "form-data; name=\"xml\"; filename=\"naceSignature.xml\"") CALL http_req.setHeader("Content-Disposition", "form-data; name=\"xml\"; filename=\"Signature.xml\"") # TRY CALL http_req.doFileRequest(rutaSemilla||"/Signature.xml") # CATCH -- Intentar obtener la # RETURN 400, "NO OBTUVE RESPUESTA DEL SERICIO AL VALIDAR SEMILLA" # END TRY -- Continuar con la ejecución normal si no se produjo una excepción LET http_resp = http_req.getResponse() LET codigo = http_resp.getStatusCode() LET respuesta = http_resp.getTextResponse() DISPLAY "respuesta valida semilla: ",respuesta ELSE LET codigo=400 LET respuesta='NO ENCONTRE EL FILE PARA VALIDAR SEMILLA' END IF RETURN codigo, respuesta END FUNCTION FUNCTION enviafiles(btoken,archivo) DEFINE respuesta,btoken,codigo,archivo,contenido,consultaResp STRING, http_req com.HttpRequest, http_resp com.HTTPResponse, xresp RECORD codigo,estado,mensajes,encf,secuenciaUtilizada STRING END RECORD LET btoken =" Bearer ",btoken LET http_req = com.HTTPRequest.Create(url_recepcion) CALL http_req.setMethod("POST") CALL http_req.setCharset("UTF-8") CALL http_req.setHeader("accept","application/json") CALL http_req.setHeader("Authorization",btoken) CALL http_req.setConnectionTimeOut(10) CALL http_req.setMultipartType("form-data",NULL,NULL) # "form-data; name=\"xml\"; filename=\"naceSignature.xml\"" IF os.Path.exists(archivo) THEN DISPLAY "archivo a enviar: ",archivo," url ",url_recepcion LET contenido = "form-data; name=\"xml\"; filename=",os.path.basename(archivo) # DISPLAY "contenido: ",contenido # CALL http_req.setHeader("Content-Disposition", "form-data; name=\"xml\"; filename=\"131880681E310000000001.xml\"") CALL http_req.setHeader("Content-Disposition", contenido CLIPPED) CALL http_req.doFileRequest(archivo) LET http_resp= http_req.getResponse() LET codigo = http_resp.getStatusCode() LET respuesta= http_resp.getTextResponse() IF http_resp.getStatusCode() != 200 THEN DISPLAY "error: ",codigo," ", respuesta RETURN codigo, respuesta END IF ELSE RETURN 0,respuesta END IF # CALL http_req.setHeader("Content-Disposition", "form-data; name=\"xml\"; filename=\"naceSignature.xml\"") # CALL http_req.doFileRequest("naceSignature.xml") DISPLAY "envia respuesta: ", respuesta CALL util.JSON.parse(respuesta,xresp) # CALL consultaResultado(btoken,respuesta) RETURNING consultaResp # DISPLAY "responde consulta: ",consultaresp," ",xfacturainterna # LET respuesta = util.JSON.stringify(xresp) RETURN codigo, respuesta END FUNCTION FUNCTION consultaResultado(ctoken,data) DEFINE data,ctoken,mensaje_dgii,message_err STRING DEFINE crespuesta STRING, http_req com.HttpRequest, http_resp com.HTTPResponse DEFINE dtrackid RECORD trackId,error,mensaje STRING END RECORD DISPLAY "consultatrackid: ",ctoken," || ",data TRY CALL util.JSON.parse(data,dtrackid) CATCH LET message_Err ='Error EN JSON CONSULTA RESULTADO: ',STATUS CALL errorlog(message_Err) END TRY LET url_consulta = url_consulta CLIPPED,"?TrackId=",dtrackid.trackid CLIPPED LET http_req = com.HTTPRequest.Create(url_consulta) CALL http_req.setMethod("GET") CALL http_req.setCharset("UTF-8") CALL http_req.setConnectionTimeOut(10) CALL http_req.setHeader("accept","application/json") CALL http_req.setHeader("Authorization",ctoken) TRY CALL http_req.doRequest() LET http_resp= http_req.getResponse() LET crespuesta = http_resp.getTextResponse() LET mensaje_dgii = "Trackid: ", dtrackid.trackid CLIPPED," respuesta: ",crespuesta, " code: ",http_resp.getStatusCode() CATCH LET crespuesta = 'Servicio no responde, no consulta' RETURN 400,crespuesta END TRY RETURN http_resp.getStatusCode(),crespuesta END FUNCTION FUNCTION gettoken() DEFINE i, l INTEGER DEFINE r om.XmlReader DEFINE e,tok String DEFINE a om.SaxAttributes # DISPLAY "filexml: ",filexml LET r = om.XmlReader.createFileReader(rutaSemilla||"/RespuestaValida.xml") LET l = 0 LET e = r.read() WHILE e IS NOT NULL CASE e WHEN "StartDocument" # DISPLAY "StartDocument:" WHEN "StartElement" LET l=l+1 # DISPLAY l SPACES, "StartElement:", r.getTagName() LET a = r.getAttributes() FOR i=1 to a.getLength() IF a.getName(i) = "token" THEN # DISPLAY l SPACES," ", # a.getName(i)," = ", # a.getValueByIndex(i) END IF END FOR WHEN "Characters" IF r.getTagName() = "token" THEN LET tok = r.getCharacters() # DISPLAY "token dentro de gettoken: ",tok EXIT CASE END IF WHEN "SkippedEntity" # DISPLAY "Entity:'",r.skippedEntity(),"'" WHEN "EndElement" # DISPLAY l SPACES, "EndElement:", r.getTagName() LET l=l-1 WHEN "EndDocument" # DISPLAY "EndDocument:" OTHERWISE # DISPLAY "Invalid event: ",e END CASE LET e=r.read() END WHILE RETURN tok END FUNCTION FUNCTION gethash(envfile) DEFINE i, l INTEGER DEFINE r om.XmlReader DEFINE e,envfile STRING, phash VARCHAR(6), pfechafirmadigital VARCHAR(50), facturainterna INT DEFINE a om.SaxAttributes DISPLAY "filexml: ",envfile LET r = om.XmlReader.createFileReader(envfile) LET l = 0 LET e = r.read() WHILE e IS NOT NULL CASE e WHEN "StartDocument" # DISPLAY "StartDocument:" WHEN "StartElement" LET l=l+1 #DISPLAY l SPACES, "StartElement:", r.getTagName() LET a = r.getAttributes() FOR i=1 to a.getLength() IF a.getName(i) = "SignatureValue" THEN LET phash = r.getCharacters() # DISPLAY l SPACES," ", # a.getName(i)," = ", # a.getValueByIndex(i) END IF END FOR WHEN "Characters" IF r.getTagName() = "SignatureValue" THEN LET phash = r.getCharacters() # DISPLAY "token dentro de gettoken: ",tok EXIT CASE END IF IF r.getTagName() = "FechaHoraFirma" THEN LET pfechafirmadigital = r.getCharacters() # DISPLAY "token dentro de gettoken: ",tok EXIT CASE END IF IF r.getTagName() = "NumeroFacturaInterna" THEN LET facturainterna = r.getCharacters() DISPLAY "factura interna: ",facturainterna EXIT CASE END IF WHEN "SkippedEntity" # DISPLAY "Entity:'",r.skippedEntity(),"'" WHEN "EndElement" # DISPLAY l SPACES, "EndElement:", r.getTagName() LET l=l-1 WHEN "EndDocument" # DISPLAY "EndDocument:" OTHERWISE # DISPLAY "Invalid event: ",e END CASE LET e=r.read() END WHILE RETURN phash,pfechafirmadigital,facturainterna END FUNCTION FUNCTION buscatoken() DEFINE respuesta STRING, http_req com.HttpRequest, http_resp com.HTTPResponse #SELECT a.urltoken INTO url FROM companias a #"https://ecf.dgii.gov.do/testecf/autenticacion/api/autenticacion/semilla" #"https://ecf.dgii.gov.do/CerteCF/Autenticacion/api/Autenticacion/Semilla" DISPLAY "url semilla: ",url_semilla LET http_req = com.HTTPRequest.Create(url_semilla) CALL http_req.setMethod("GET") CALL http_req.setCharset("UTF-8") CALL http_req.setHeader("accept","application/xml") # CALL http_req.setConnectionTimeOut(10) # TRY CALL http_req.doRequest() LET http_resp= http_req.getResponse() LET respuesta = http_resp.getTextResponse() # CATCH # LET respuesta = 'No pude conseguir el token' # RETURN 400,respuesta # END TRY #DISPLAY "cod token ",http_resp.getTextResponse()," ",http_resp.getStatusCode() # IF http_resp.getStatusCode() != 200 THEN # RETURN http_resp.getStatusCode(), http_resp.getTextResponse() # END IF DISPLAY "busca token: ",respuesta RETURN http_resp.getStatusCode(),respuesta END FUNCTION FUNCTION urls(xambiente,ptipoRecepcion) DEFINE xambiente,ptipoRecepcion STRING IF xambiente = "produccion" THEN IF ptipoRecepcion = "normal" THEN LET url_recepcion ="https://ecf.dgii.gov.do/ecf/Recepcion/api/FacturasElectronicas" ELSE IF ptipoRecepcion = 'consumo' THEN LET url_recepcion ="https://ecf.dgii.gov.do/ecf/Recepcion/api/FacturasElectronicas" END IF END IF IF ptipoRecepcion = 'normal32' THEN LET url_recepcion ="https://fc.dgii.gov.do/ecf/RecepcionFC/api/Recepcion/ecf" END IF LET url_semilla ="https://ecf.dgii.gov.do/ecf/autenticacion/api/autenticacion/semilla" LET url_validasemilla ="https://ecf.dgii.gov.do/ecf/Autenticacion/api/Autenticacion/ValidarSemilla" LET url_consulta = "https://ecf.dgii.gov.do/ecf/ConsultaResultado/api/consultas/estado" LET url_anulacion = "https://ecf.dgii.gov.do/eCF/anulacionrangos/api/operaciones/anularRango" END IF IF xambiente = "certificacion" THEN IF ptipoRecepcion = "normal" THEN LET url_recepcion ="https://ecf.dgii.gov.do/CerteCF/Recepcion/api/FacturasElectronicas" ELSE IF ptipoRecepcion = 'consumo' THEN LET url_recepcion ="https://ecf.dgii.gov.do/CerteCF/Recepcion/api/FacturasElectronicas" END IF END IF IF ptipoRecepcion = 'normal32' THEN LET url_recepcion ="https://fc.dgii.gov.do/CerteCF/RecepcionFC/api/Recepcion/ecf" END IF LET url_semilla ="https://ecf.dgii.gov.do/CerteCF/autenticacion/api/autenticacion/semilla" LET url_validasemilla ="https://ecf.dgii.gov.do/CerteCF/Autenticacion/api/Autenticacion/ValidarSemilla" LET url_consulta = "https://ecf.dgii.gov.do/CerteCF/ConsultaResultado/api/consultas/estado" END IF IF xambiente = "test" THEN IF ptipoRecepcion = "normal" THEN LET url_recepcion ="https://ecf.dgii.gov.do/TesteCF/Recepcion/api/FacturasElectronicas" ELSE IF ptipoRecepcion = 'consumo' THEN LET url_recepcion ="https://fc.dgii.gov.do/TesteCF/RecepcionFC/api/Recepcion/ecf" END IF END IF IF ptipoRecepcion = 'normal32' THEN LET url_recepcion ="https://fc.dgii.gov.do/TesteCF/RecepcionFC/api/Recepcion/ecf" END IF LET url_semilla ="https://ecf.dgii.gov.do/TesteCF/autenticacion/api/autenticacion/semilla" LET url_validasemilla ="https://ecf.dgii.gov.do/TesteCF/Autenticacion/api/Autenticacion/ValidarSemilla" LET url_consulta = "https://ecf.dgii.gov.do/TesteCF/ConsultaResultado/api/consultas/estado" LET url_anulacion = "https://ecf.dgii.gov.do/TesteCF/anulacionrangos/api/operaciones/anularRango" END IF LET url_consulta_timbre ="https://ecf.dgii.gov.do/TesteCF/consultatimbre" # DISPLAY url_recepcion TO act_url END FUNCTION FUNCTION obtenerStatus(ctoken) DEFINE respuesta,btoken,codigo,archivo,contenido,consultaResp,ctoken STRING, http_req com.HttpRequest, http_resp com.HTTPResponse, xresp RECORD codigo,estado,mensajes,encf,secuenciaUtilizada STRING END RECORD LET http_req = com.HttpRequest.Create("https://statusecf.dgii.gov.do/api/estatusservicios/obtenerestatus") DISPLAY "ctoken: ",ctoken CALL http_req.setMethod("GET") CALL http_req.setCharset("UTF-8") CALL http_req.setConnectionTimeOut(10) CALL http_req.setHeader("accept","application/json") CALL http_req.setHeader("Authorization",ctoken) CALL http_req.doRequest() LET http_resp= http_req.getResponse() LET respuesta = http_resp.getTextResponse() LET codigo = http_resp.getStatusCode() DISPLAY "respuesta: ",respuesta ,"codigo ",codigo END FUNCTION