// ******************************************
// * $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;
}