// ****************************************** // * $Id$ // * // * UserException() // * RaiseAnError() // * TestAndRaiseAnXMLError() // * SafeLoadTextXML() // * SafeLoadFileXSL() // * XML2HTML() // * fetchXMLContent() // * mergeXMLAttachments() // * Hexify() // * // * XML en XSL functies. // * // ****************************************** // function UserException(number, source, message) { this.number = number; this.source = source; this.description = message; } function RaiseAnError(e, p) { throw new UserException(e + 1000, "UserException", p); } function TestAndRaiseAnXMLError(p, iXml, xmltext) // xmltext is optional for error logging { if (iXml.parseError.errorCode != 0) { if (xmltext) LogString2File(1, "Failed_XML", xmltext, "xml"); RaiseAnError( iXml.parseError.errorCode , p + "\n" + iXml.parseError.reason + " regel " + iXml.parseError.line + "(" + iXml.parseError.filepos + ")" ); } } function SafeLoadTextXML(xmlText) { var iXml = new ActiveXObject("Msxml2.DOMDocument.6.0"); iXml.async = false; iXml.loadXML(xmlText); TestAndRaiseAnXMLError("Error in xmlData", iXml); return iXml; } function SafeLoadFileXSL(xslPath) { var iXsl = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.6.0"); // Moet FreeThreaded voor XSLTemplate iXsl.async = false; iXsl.setProperty("AllowXsltScript", true); iXsl.load(custabspath + "/" + xslPath); iXsl.resolveExternals = true; // anders SOAP problemen om de template functie te vinden TestAndRaiseAnXMLError("Error loading file " + xslPath, iXsl); return iXsl; } // Vergelijk shared.inc versie var protectQS = { create: function (url, params) { var splitter = url.split("?"); var pad = splitter[0]; var qs = splitter.length>1?splitter[1]:"x=x"; var padsplitter = pad.split("/"); var file = padsplitter[padsplitter.length-1]; // laatste component // Let op dat protectQS.wsc hetzelfde doet voor Facmgt var str = file.toUpperCase() + "?" + qs; //var hmacced = protectHMAC.create(data, params); var ts = String(Math.round((new Date).getTime() / 1000)); var data = ts + ":" + str Log2File(2, "hmacdata: " + data); //__Log("sleutel: "+ params.sleutel); var oCrypto = new ActiveXObject("SLNKDWF.Crypto"); var sig = oCrypto.hex_hmac_sha1(params.sleutel, data); var hmac = oCrypto.hex2base64(sig, false, true); // no padding, urlsafe oCrypto = null; // Caching klinkt leuk maar Oracle sessies blijven langer hangen? var hmacced = ts+":"+hmac; var newurl = pad + "?" + qs + "&hmac="+encodeURIComponent(hmacced); return newurl; } } function XML2HTML( xmlDoc , xslPath , srtnotificatie , mode , p_bedrijfadres ) { // Transform body=xml according to xslPath=xslfilenaam with optionel srtnotification parameter (e.g. RESBEV) // Output is supposed to be a HTML string but really depends on the XSL content var xslt = new ActiveXObject("Msxml2.XSLTemplate.6.0"); var xslProc; var xslDoc = SafeLoadFileXSL(xslPath); var result = ""; xslDoc.resolveExternals = true; // anders op de volgende regel al: // A reference to variable or parameter 'srtnotificatiecode' cannot be resolved xslt.stylesheet = xslDoc; var xslProc = xslt.createProcessor(); xslProc.input = xmlDoc; xslProc.addParameter("srtnotificatiecode", srtnotificatie); xslProc.addParameter("mode", mode); /* plugindata: { "xlstransformparams": { "opzichter_variant": "1", "parameter2": "waarde2" } } */ if (p_bedrijfadres && p_bedrijfadres.plugindata && "xlstransformparams" in p_bedrijfadres.plugindata) { for (paramname in p_bedrijfadres.plugindata.xlstransformparams) { var paramval = p_bedrijfadres.plugindata.xlstransformparams[paramname]; xslProc.addParameter(paramname, paramval); } } xslProc.transform(); result = xslProc.output; // Let op: dezelfde code in xml_converter.inc // eerst lockeduser(xmlnode,key,bedrijf_key) vervangen // lockeduser(opdracht,12345,910) met 12345 opdracht_key en 910 bedrijf_key var hmacs = result && result.match(/(lockeduser\([^\)]*\))/g); // heeft nu array van lockeduser(opdracht,12345,910) for (var i =0; hmacs && i < hmacs.length; i++) { var params = hmacs[i].match(/\(([^,]+)\,(\d+),(\d+)\)/); if (!params) throw { description: "lockeduser is used in xsl but empty opdracht_key or bedrijf_key" }; if (params.length == 4) { var xmlnode = params[1]; // We ondersteunen alleen nog maar 'opdracht' var key = parseInt(params[2], 10); var bedrijf_key = parseInt(params[3], 10); // Let op: we pakken altijd het eerste bedrijfadres var sql = "SELECT prs_bedrijfadres_key," + " prs_bedrijfadres_lockuser_key," + " prs_bedrijfadres_locksecret" + " FROM prs_bedrijfadres" + " WHERE prs_bedrijf_key = " + bedrijf_key + " AND prs_bedrijfadres_startdatum <= SYSDATE" + " AND prs_bedrijfadres_lockuser_key IS NOT NULL" + " ORDER BY prs_bedrijfadres_startdatum DESC"; var oRs = Oracle.Execute(sql); if (oRs.Eof) { // Ergens in de bon staat // https://aqqa.facilitor.nl/lockeduser(opdracht,, // ) // maar bij de leverancier is geen 'Vaste gebruiker' en 'Gedeeld geheim' ingevuld throw { description: "lockeduser is used in xsl but missing prs_bedrijfadres_locksecret/prs_bedrijfadres_lockuser_key" }; } var bdradr_key = oRs("prs_bedrijfadres_key").Value; var lockuser_key = oRs("prs_bedrijfadres_lockuser_key").Value; var locksecret = oRs("prs_bedrijfadres_locksecret").Value; oRs.Close(); if (lockuser_key && !locksecret) { var oCrypto = new ActiveXObject("SLNKDWF.Crypto"); locksecret = oCrypto.hex_random(32); var sql = "UPDATE prs_bedrijfadres" + " SET prs_bedrijfadres_locksecret = " + safe.quoted_sql(locksecret) + " WHERE prs_bedrijfadres_key = " + bdradr_key; Oracle.Execute(sql); } var url = "?u={0}&k={1}&lbdr={2}".format(xmlnode, key, bdradr_key); var newurl = protectQS.create(url, { sleutel: locksecret, no_user_key: true }); result = result.replace(hmacs[i], newurl); } } // Let op: dezelfde code in xml_converter.inc // nu fclttoegang(xmlnode,key) vervangen // xmlnode mag zijn 'reservering', 'afspraak' of 'opdracht' zonder de quotes // fclttoegang(reservering,12345) geeft toegang tot rsv_ruimte_key 12345 (wat niet reservering 12345/1 hoeft te zijn) var hmacs = result && result.match(/(fclttoegang\([^\)]*\))/g); // heeft nu array van fclttoegang(reservering,12345) for (var i =0; hmacs && i < hmacs.length; i++) { var params = hmacs[i].match(/\(([^,]+)\,(\d+)\)/); if (!params) throw { description: "fclttoegang is used in xsl but empty xmlnode or key" }; if (params.length == 3) { var xmlnode = params[1]; // We ondersteunen alleen nog maar 'opdracht' var key = parseInt(params[2], 10); // Let op: zoek de laagste fac_tracking_key als (onderdeel van) de 'sleutel' var sql = "SELECT MIN(fac_tracking_key) fac_tracking_key," + " MIN(fac_tracking_datum) fac_tracking_datum" + " FROM fac_tracking ft, fac_srtnotificatie fsn" + " WHERE ft.fac_srtnotificatie_key = fsn.fac_srtnotificatie_key" + " AND fac_srtnotificatie_xmlnode = " + safe.quoted_sql(xmlnode) + " AND fac_tracking_refkey = " + key; var oRs = Oracle.Execute(sql); if (oRs.Eof) { // Ergens in de bon staat zo'n fclttoegang maar geen tracking gevonden? throw { description: "fclttoegang is used in xsl but no tracking found for " + xmlnode + "/" + key}; } var locksecret = String(oRs("fac_tracking_key").Value) + "|" + toDateTimeString(new Date(oRs("fac_tracking_datum").Value)); oRs.Close(); var url = "?u=toegang&k={1}&xmlnode={0}".format(xmlnode, key); var newurl = protectQS.create(url, { sleutel: locksecret, no_user_key: true }); result = result.replace(hmacs[i], newurl); } } return result; } // Resultaat is een xmlDoc object of null bij errors // één niveau van caching, is efficienter als 13 keer dezelfde MLD2BO var prev_XMLContent = {}; function fetchXMLContent( node , refkey , xrefkey , where , userlang , params ) { params = params || {}; if (prev_XMLContent.node == node && prev_XMLContent.refkey == refkey && prev_XMLContent.xrefkey == xrefkey && prev_XMLContent.where == where && prev_XMLContent.userlang == userlang && prev_XMLContent.aanmaak == params.aanmaak) // putorders loopt soms heel lang, oppassen met cachen van ORDUPD's { Log2File(2, "Re-using cached xmlDoc"); return prev_XMLContent.xmlDoc; } var xml_content = ""; try { // we geven de gewenste taal mee aan de Oracle sessie, die dat verder zal gebruiken var sql = "BEGIN lcl.setuserlanguage (" + safe.quoted_sql(userlang) + "); END;" Log2File(3, sql); Oracle.Execute(sql); // var sql_xtra = 'NULL'; // FCLT#81165 tijdelijke fix omdat xtrakey soms onverwacht een fac_tracking_key bevat // wat 95% van de bonnen niet verwacht (die verwachten een note_key van de // notitie die je bij het handmatig mailen hebt ingegeven) // Hieronder eigenlijk alle srtnotificatie codes benoemen die een notitie-key verwachten in extra_key // Correcte oplossing (alle bonnen aanpassen) is geregistreerd in FCLT#87598 if (xrefkey > 0 && (node != 'deel' || params.srtnotificatie == 'INSMAI') && (node != 'melding' || params.srtnotificatie == 'MLDMAI') && (node != 'opdracht' || params.srtnotificatie == 'ORDMAI' || params.srtnotificatie == 'ORDNOL') && (node != 'contract' || params.srtnotificatie == 'CNTMAI') && (node != 'factuur' || params.srtnotificatie == 'FINMAI') ) { sql_xtra = String(xrefkey); } var sql_params = safe.quoted_sql(node) + ", " + refkey + ", " + safe.quoted_sql(customerId) + ", '$PutOrdersSession$'" + ", " + sql_xtra + ", " + safe.quoted_sql(where); var sql = "SELECT xml.make_xml2(" + sql_params + ") xml_blob, sys_context('USERENV','SID') mysid FROM dual"; Log2File(typeof PUO_LOGPATH == "undefined"?2:1, sql); var tmstart = new Date(); var oRs = Oracle.Execute(sql); var tmend = new Date(); var xml_content = oRs("xml_blob").Value||""; var mysid = oRs("mysid").Value||""; oRs.Close(); if (xml_content) Log2File(typeof PUO_LOGPATH == "undefined"?2:1, "XML blob is {0} karakters in {1}ms for SID {2}.".format(xml_content.length, tmend.getTime() - tmstart.getTime(), mysid)); else Log2File(1, "XML blob is leeg. Verwijderd record?"); } catch(e) { Log2File(0, "fetchXMLContent error: " + e.description, "W"); xml_content = ""; } var xmlDoc = xml_content?SafeLoadTextXML(xml_content):null; xml_content = addLanguageNode(xmlDoc, { userlang: userlang }); LogString2File(3, "make_xml", xml_content, "xml"); prev_XMLContent.node = node; prev_XMLContent.refkey = refkey; prev_XMLContent.xrefkey = xrefkey; prev_XMLContent.where = where; prev_XMLContent.userlang = userlang; prev_XMLContent.aanmaak == params.aanmaak; prev_XMLContent.xmlDoc = xmlDoc; return xmlDoc; } function addLanguageNode(p_xml, params) { var lang_path = custabspath + "/xsl/language_" + params.userlang + ".xml"; var fso = new ActiveXObject("Scripting.FileSystemObject"); if (p_xml && fso.FileExists(lang_path)) { var xmlIns = new ActiveXObject("Msxml2.DOMDocument.6.0"); xmlIns.async = false; xmlIns.load(lang_path); TestAndRaiseAnXMLError("Error in "+lang_path, xmlIns); var langNode = xmlIns.selectSingleNode("/*"); // de root-node uit het zojuist geladen taal-bestand var clone = p_xml.importNode(langNode, true); var nodeParent = p_xml.selectSingleNode("//facilitor/lcl"); // In deze node moet het worden toegevoegd. nodeParent.appendChild(clone); Log2File(1, lang_path + " added to XML"); } return (p_xml?p_xml.documentElement.xml:""); } function mergeXMLAttachments(iXml, p_xslPath) { mergeXMLAttachments2(iXml, p_xslPath, "//FCLTmeldingattachment", "meldingkey", "M", "MLD"); mergeXMLAttachments2(iXml, p_xslPath, "//FCLTnotitieattachment", "notitiekey", "N", "MLDN"); mergeXMLAttachments2(iXml, p_xslPath, "//FCLTopdrachtattachment", "opdrachtkey", "O", "MLD"); mergeXMLAttachments2(iXml, p_xslPath, "//FCLTnotitieattachment", "notitiekey", "N", "ORDN"); } function mergeXMLAttachments2(iXml, p_xslPath, xmltag, keynaam, pNiveau, pModule) { // Doorzoek iXml op 345 // en vervang die door alle flexkenmerken er onder // <-- nodename = Iattachements // ...hexdata... // naam // 1235 // var NodeList = iXml.documentElement.selectNodes(xmltag); if (NodeList.length > 0) { Log2File(2, "*> mergeXMLAttachments"); for (var index=0; index < NodeList.length; index++) { var node = NodeList[index]; var meldingopdrachtkey = parseInt(trimall(node.attributes.getNamedItem(keynaam).text)); var bijlagemod = node.attributes.getNamedItem("bijlagemod")?(trimall(node.attributes.getNamedItem("bijlagemod").text)):""; var v_module = (bijlagemod?bijlagemod:pModule); if (v_module == "MLDN" || v_module == "ORDN") { var kenmerkkey = -1; // hardcoded } else { var kenmerkkey = parseInt(trimall(node.attributes.getNamedItem("kenmerkkey").text), 10) || 0; } var bijlagekey = node.attributes.getNamedItem("bijlagekey")?parseInt(trimall(node.attributes.getNamedItem("bijlagekey").text)):""; var nodename = trimall(node.attributes.getNamedItem("nodename").text); var node_encoding = node.attributes.getNamedItem("encoding"); // als die NIET is gevuld doen we default "hex" var encoding = "hex"; if (node_encoding){ encoding = trimall(node_encoding.text); } var node_templatenodename = node.attributes.getNamedItem("templatenodename"); // als die is gevuld doen we een post-parse met de stylesheet var templatenodename = ''; if (node_templatenodename){ templatenodename = trimall(node_templatenodename.text); } Log2File(1, "Searching attachments {0}{1} kenmerk {2}".format(pNiveau, meldingopdrachtkey, kenmerkkey)); var att_list = []; var sql = "SELECT r.fac_bijlagen_disk_directory" + " , r.fac_bijlagen_filename" + " , r.fac_bijlagen_file_size" + " FROM fac_bijlagen r" + " , fac_bijlagen b" + " WHERE b.fac_bijlagen_root_key = r.fac_bijlagen_key" + " AND b.fac_bijlagen_verwijder IS NULL" + " AND r.fac_bijlagen_verwijder IS NULL" + " AND b.fac_bijlagen_module = " + safe.quoted_sql(v_module) + " AND b.fac_bijlagen_refkey = " + meldingopdrachtkey + (kenmerkkey ? " AND b.fac_bijlagen_kenmerk_key = " + kenmerkkey : "") + (bijlagekey ? " AND b.fac_bijlagen_key = " + bijlagekey : ""); Log2File(3, sql); var oRs = Oracle.Execute(sql); while (!oRs.eof) { att_list.push( { f_disk: oRs("fac_bijlagen_disk_directory").Value , f_name: oRs("fac_bijlagen_filename").Value , f_size: oRs("fac_bijlagen_file_size").Value , f_path: S("flexfilespath") + "/" + oRs("fac_bijlagen_disk_directory").Value + "/" + oRs("fac_bijlagen_filename").Value } ); oRs.MoveNext(); } oRs.Close(); for (a=0; a< att_list.length; a++) { Log2File(1, "Embedding attachment: " + att_list[a].f_path + " (" + att_list[a].f_size + " bytes)"); // en hier de rest voor het invoegen van de bijlagen. var elemAttachments = iXml.createElement(nodename); var elemAtt = iXml.createElement("attachment"); switch (encoding) { case "hex": elemAtt.text = Hexify(att_list[a].f_path); break; case "base64": elemAtt.text = Base64fy(att_list[a].f_path); break; case "localpath": elemAtt.text = att_list[a].f_path; break; } Log2File(1, "{0} encoded it becomes {1} bytes".format(encoding, elemAtt.text.length)); elemAttachments.appendChild(elemAtt); elemAtt = iXml.createElement("encoding"); elemAtt.text = encoding; elemAttachments.appendChild(elemAtt); elemAtt = iXml.createElement("name"); elemAtt.text = att_list[a].f_name; elemAttachments.appendChild(elemAtt); elemAtt = iXml.createElement("size"); elemAtt.text = att_list[a].f_size; elemAttachments.appendChild(elemAtt); if (templatenodename != '') // post processing met de stylesheet { var elemWrapper = iXml.createElement(templatenodename); elemWrapper.appendChild(elemAttachments); var tmp_xmlDoc = SafeLoadTextXML(elemWrapper.xml); LogString2File(3, "PostProces", tmp_xmlDoc.xml, "xml"); var tmp_xmlResult = XML2HTML( tmp_xmlDoc , p_xslPath , "" , "processattachments" ); var tmp_xmlDoc = SafeLoadTextXML(tmp_xmlResult); LogString2File(3, "PostProcesAttach", tmp_xmlResult, "xml"); var NodeList2 = tmp_xmlDoc.documentElement.childNodes; for (var i=0; i < NodeList2.length; i++) { var tmp_node = NodeList2[i]; //Let op: niet appendChild gebruikt, want die voegt achteraan toe aan de parentnode, waardoor de volgorde wordt aangepast. //Door gebruikt van insertBefore blijft de volgorde intact, die wezenlijk voor Validatie tegen XSD (van externe partijen) kan zijn! node.parentNode.insertBefore(tmp_node, node); } } else { node.parentNode.appendChild(elemAttachments); } } node.parentNode.removeChild(node); // dummy fcltattachments weg } Log2File(2, "*< mergeXMLAttachments"); } return iXml; }