Files
MBS/WEBSERVICES/test/efactura_1.4gl
T

410 lines
12 KiB
Plaintext

IMPORT util
IMPORT com
IMPORT os
IMPORT security
IMPORT XML
CONSTANT dpy_verb=TRUE -- send messages to standard output
DEFINE doc xml.DomDocument
DEFINE req com.HTTPServiceRequest
DEFINE url,msg,method,headers,mensaje,filexml,tipoecf,rnc_e,rnc_c,e_ncf,fileacuse,resp,
ruta_firmados,fileafirmar_f STRING,
tout, n, x,rcode INTEGER,
start_time DATETIME YEAR TO SECOND
DEFINE d0 DATETIME YEAR TO SECOND
DEFINE a om.SaxAttributes
DEFINE out om.SaxDocumentHandler,
i INT,
fechaFirma DATETIME YEAR TO SECOND
MAIN
LET filexml = ".\\ArchRecibidos\\"
LET fileacuse = ".\\Acuses\\"
LET ruta_firmados = fgl_getenv("RUTA_XML_FIRMADOS")
CALL recepcion()
END MAIN
PUBLIC FUNCTION recepcion () ATTRIBUTES(WSGet,
WSPath="/{servicio}/api/ecf/",
WSDescription="Api para la recepcion de los e-NCF" )
#, WSThrows="400:Invalid,406:Should not happen"
DEFINE urlhost STRING
CALL check_utf8() RETURNING x, msg
IF x != 0 THEN
DISPLAY "ERROR: ", msg
EXIT PROGRAM 1
END IF
CALL show_verb("Inicio Api server: ...")
-- Normally, the port is set by the GAS for load balancing
-- For standalone tests you can set FGLAPPSERVER environment variable
CALL show_verb("Listening on port : "|| NVL(fgl_getenv("FGLAPPSERVER"),"GAS"))
CALL com.WebServiceEngine.Start()
LET start_time = CURRENT
LET tout=-1
IF tout=-1 THEN
LET msg="The Api server is listening (timeout = infinite wait)."
ELSE
LET msg="The Api server is listening (timeout =",tout USING "-<<<<<<&"," seconds)."
END IF
CALL show_verb(msg)
LET n=0
WHILE TRUE
LET req = com.WebServiceEngine.getHTTPServiceRequest(tout)
LET url = req.getUrl()
DISPLAY "url 1: ",url
IF req IS NULL THEN -- timeout
CALL show_verb( SFMT("HTTP request timeout...: %1", CURRENT YEAR TO FRACTION))
CONTINUE WHILE
ELSE
LET urlhost = req.getUrlHost()
DISPLAY "url host ",urlhost
CALL show_verb( SFMT("HTTP request SERVICIO...: %1", CURRENT YEAR TO FRACTION))
END IF
LET url = req.getURL()
LET method = req.getMethod()
DISPLAY "metodo: ",method
IF method IS NULL OR method != "POST" THEN
IF method = "GET" THEN
LET mensaje = "Bienvenido al API Server del servicio ",url clipped
CALL req.sendTextResponse(200,NULL,mensaje)
END IF
EXIT WHILE
END IF
CALL read_request(req) RETURNING rcode,resp
IF rcode <> "200" THEN
CALL req.sendTextResponse(501,NULL,"No pudimos procesar el file")
ELSE
LET doc = xml.DomDocument.Create()
CALL doc.setFeature("format-pretty-print",TRUE)
CALL doc.load(fileafirmar_f)
CALL req.sendXmlResponse(200,NULL,doc)
# CALL req.sendTextResponse(200,NULL,resp)
END IF
LET d0 = CURRENT
EXIT WHILE
END WHILE
#CALL limpiatmp()
END FUNCTION
FUNCTION check_utf8()
IF ORD("€") == 8364 AND LENGTH("€") == 1 THEN
RETURN 0, NULL
ELSE
RETURN -1, "Application locale must be UTF-8, with char length semantics"
END IF
END FUNCTION
FUNCTION show_verb(msg)
DEFINE msg STRING
IF dpy_verb THEN
DISPLAY msg
END IF
# IF log_verb THEN
# CALL errorlog(msg CLIPPED)
# END IF
END FUNCTION
FUNCTION getxmldata()
DEFINE i, l INTEGER
DEFINE r om.XmlReader
DEFINE e,tok STRING,
pfechafirmadigital VARCHAR(50),
facturainterna INT
DEFINE a om.SaxAttributes
DISPLAY "filexml: ",filexml
LET r = om.XmlReader.createFileReader(filexml)
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
# DISPLAY l SPACES," ",
# a.getName(i)," = ",
# a.getValueByIndex(i)
END IF
END FOR
WHEN "Characters"
IF r.getTagName() = "TipoeCF" THEN
LET tipoecf = r.getCharacters()
EXIT CASE
END IF
IF r.getTagName() = "FechaHoraFirma" THEN
LET pfechafirmadigital = r.getCharacters()
EXIT CASE
END IF
IF r.getTagName() = "RNCEmisor" THEN
LET rnc_e = r.getCharacters()
EXIT CASE
END IF
IF r.getTagName() = "eNCF" THEN
LET e_ncf = r.getCharacters()
EXIT CASE
END IF
IF r.getTagName() = "RNCComprador" THEN
LET rnc_c = r.getCharacters()
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 read_request(req)
# DEFINE doc xml.DomDocument
DEFINE req com.HttpServiceRequest
DEFINE cmd,recibido,tmpfile STRING,
p RECORD
oper STRING,
data RECORD
usuario STRING,
clave STRING,
codigo STRING
END RECORD
END RECORD
INITIALIZE cmd TO NULL
LET cmd = req.readFileRequest()
DISPLAY "request: ",cmd
# LET cmd = "cp ",cmd CLIPPED," /home/fourjs/gas/appdata/services/mbs/bin/tmp/recibido.xml"
LET cmd = "copy ",cmd CLIPPED, " C:\\ProgramData\\FourJs\\gas\\3.20.06-201906131721\\services\\ecf\\tmp\\recibido.xml"
RUN cmd
# LET tmpfile = "/home/fourjs/gas/appdata/services/mbs/bin/tmp/recibido.xml"
LET tmpfile = ".\\tmp\\recibido.xml"
LET recibido = filexml CLIPPED,"recibido.xml"
LET filexml = recibido
# TRY
LET doc = xml.DomDocument.Create()
CALL doc.setFeature("whitespace-in-element-content",FALSE)
IF os.Path.exists(tmpfile) THEN
CALL doc.load(tmpfile)
CALL doc.save(recibido)
CALL getxmldata()
LET filexml = filexml CLIPPED,rnc_e CLIPPED,e_ncf CLIPPED,".xml"
CALL doc.save(filexml)
CALL formaracuse() RETURNING filexml
CALL firmadocumento(filexml)
CALL doc.load(fileafirmar_f)
LET cmd = doc.saveToString()
RETURN 200,cmd
ELSE
RETURN 401,"Falla en el proceso del file"
END IF
# CATCH
# CALL show_err(SFMT("Unexpected HTTP request read exception: %1", STATUS))
# RETURN FALSE
# END TRY
END FUNCTION
FUNCTION show_err(msg)
DEFINE msg STRING
DISPLAY "ERROR:",msg
# CALL errorlog(msg CLIPPED)
END FUNCTION
FUNCTION formaracuse()
DEFINE chFechaFirma STRING
LET fileacuse = fileacuse CLIPPED,"acuse",rnc_c CLIPPED,".xml"
LET out=om.XmlWriter.createFileWriter(fileacuse)
LET a=om.SaxAttributes.create()
CALL out.startDocument()
CALL a.addAttribute("xmlns:xs","http://www.w3.org/2001/XMLSchema")
CALL out.startElement("ARECF",a)
CALL a.clear()
CALL out.startElement("DetalleAcusedeRecibo",a)
CALL out.startElement("Version",a)
CALL out.characters("1.0")
CALL out.endElement("Version")
CALL out.startElement("RNCEmisor",a)
CALL out.characters(rnc_e)
CALL out.endElement("RNCEmisor")
CALL out.startElement("RNCComprador",a)
CALL out.characters(rnc_c)
CALL out.endElement("RNCComprador")
CALL out.startElement("eNCF",a)
CALL out.characters(e_ncf)
CALL out.endElement("eNCF")
CALL out.startElement("Estado",a)
CALL out.characters("0")
CALL out.endElement("Estado")
LET chFechaFirma = util.Datetime.format(CURRENT, "%d-%m-%Y %H:%M:%S" )
DISPLAY "FECHA ",chFechaFirma
CALL out.startElement("FechaHoraAcuseRecibo",a)
CALL out.characters(chFechaFirma)
CALL out.endElement("FechaHoraAcuseRecibo")
CALL out.endElement("DetalleAcusedeRecibo")
CALL out.endElement("ARECF")
CALL out.endDocument()
RETURN fileacuse
END FUNCTION
FUNCTION limpiatmp()
DISPLAY "BORRANDO XML FILES..."
RUN 'rm /tmp/*.xml'
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,
codsecure VARCHAR(6)
# 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("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("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)
LET fileafirmar_f = fileafirmar
CATCH
DISPLAY "Unable to create an enveloped signature :",status," ",sqlca.sqlerrm
END TRY
END FUNCTION