<%@ language = "JavaScript" %>
<% /*
     $Id$

     File:          BCTAdapter.asp
     Description:   Voor doorsturen facturen naar BCT om te scannen

     Parameters:    Een xml
     Status:
     Context:       vanuit \UTILS\mail_receive\EventHandlers.js omdat bij diverse email instellingen bijlagen staat ingesteld:
                    @/appl/marx/export/bctadapter.asp?eCapture=P&klantid=681&myapikey=VGSQ****&from={0}&to={1}&subject={2}&filename={filename}
     Notes:         De bijlage wordt gelezen uit de geposte body
                    Bij foutsituaties genereren we altijd een http 500 (via _AiAi)
                    Dat maakt dat EventHandlers.js de ontvangen e-mail zal bouncen naar de afzender
                    Als alles correct verloopt zal BCT uiteindelijk (asynchroon) een callback
                    doen naar API=FIN_FACTUUR_PDF met het resultaat
*/
DOCTYPE_Disable = 1;
// ANONYMOUS_Allowed uit te schakelen als MARX#73808 100% is doorgevoerd
// ofwel: bij elke e-mail setting naar BCTAdapter is myAPIKEY verwijderd
// uit de url en bij 'persoon' is de prs_perslid_contractant_key gekozen
ANONYMOUS_Allowed = 1;

%>
<!-- #include file="../../Shared/common.inc" -->
<!-- #include file="../../Shared/save2db.inc" -->
<!-- #include file="../../Shared/json2.js" -->
<%
Session.Abandon(); // Voor de zekerheid

// fac_email_setting @/appl/marx/export/bctadapter.asp?eCapture=P&klantid=1234&myapikey=*****&from={0}&to={1}&subject={2}&filename={filename}
__Log("BCT Adapter: ");

// eCapture is optionele parameter, mogelijke waarden zijn: leeg of T (T betekent connectie naar testomgeving eCapture), P (betekent connectie naar productie eCapture)
var eCapture = getQParam("eCapture", "T");
if (Application("otap_environment") == "O") // lokaal altijd naar T forceren
    eCapture = "T";

// default gaan we connecten naar de testomgeving van eCapture
// Tenzij nadrukkelijk is aangegeven dat het de productieomgeving moet zijn.

// MARX#62013: Klant ID meegeven aan factuur
var klantid = getQParam("klantid", "aareon");

var config_file = Server.MapPath(rooturl + "/cust/marx/export/test_bct.config");
if (eCapture == "p" || eCapture == "P"){
  var config_file = Server.MapPath(rooturl + "/cust/marx/export/prod_bct.config");
}

var fso = new ActiveXObject("Scripting.FileSystemObject");

var f = fso.OpenTextFile(config_file, 1); // ForReading
var config = JSON.parse(f.ReadAll());
f.Close();

__Log("config.BCT_Url : " + config.BCT_Url);

var from = getQParam("from");
var to = getQParam("to");
var subject = getQParam("subject");
var filename = getQParam("filename");

// Vanuit hMailserver kan filename utf-8 encoded zijn. Zet dat hier goed.
// (afgekeken uit api2_rest)
var fileStream = new ActiveXObject("ADODB.Stream");
fileStream.Open();
fileStream.Type = 2; // adTypeText
fileStream.Charset = 'Windows-1252';
fileStream.WriteText(filename);
fileStream.Position = 0;
fileStream.Charset = 'utf-8';
filename = fileStream.ReadText();
fileStream.Close();

__Log("BCT Adapter filename: " + filename);
var APIKEY = getQParam("myAPIKEY", ""); // van een contractant
if (APIKEY)
{
    __Log("BCT Adapter APIKEY: " + APIKEY.substr(0, 4) + "...");

    // Stap 1: Perslid van de contractant, dus de factuurscanning leverancier die facturen vanuit BCT ontvangt (retour)
    var sql = "SELECT prs_perslid_key"
            + "  FROM prs_perslid"
            + " WHERE prs_perslid_apikey ="  + safe.quoted_sql(APIKEY);
    var oRs = Oracle.Execute(sql);
    var prs_perslid_contractant_key = oRs("prs_perslid_key").Value;
    oRs.Close();
}
else if (user_key > 0) // person was netjes ingevuld bij fac_email_setting
{
    prs_perslid_contractant_key = user_key;
    // gebruik de APIKEY van _BCT voor de uiteindelijke api_bct_factuur_import.asp aanroep
    var sql = "SELECT prs_perslid_apikey"
            + "  FROM prs_perslid"
            + " WHERE prs_perslid_oslogin = '_BCT'";
    var oRs = Oracle.Execute(sql);
    APIKEY = oRs("prs_perslid_apikey").Value;
    oRs.Close();
}
else
{
    _AiAi("Missing parameter myAPIKEY (good) but you need to configure 'person' in fac_email_settings for {0}".format(to));
}

__Log("Contractant perslid-key: " + prs_perslid_contractant_key);

// Stap 2: Nu bepalen we het unieke contract bij de contractant uit stap 1
var sql = "SELECT check_of_contract_bestaat(" + prs_perslid_contractant_key + ") cnt_contract_key FROM dual";
var oRs = Oracle.Execute(sql);
var cnt_contract_key = oRs("cnt_contract_key").Value;
oRs.Close();
__Log("Bijbehorende Contractkey: " + cnt_contract_key);

// Stap 3: Nu bepalen we de woco (prs_bedrijf) die bij het contract (uit stap 2) staat geregistreerd.
var sql = "SELECT a.prs_bedrijf_key"
        + "  FROM cnt_contract c, prs_afdeling a"
        + " WHERE c.cnt_contract_key = " + cnt_contract_key
        + " AND c.prs_afdeling_key_eig = a.prs_afdeling_key";
var oRs = Oracle.Execute(sql);
var prs_bedrijf_woco_key = oRs("prs_bedrijf_key").Value;
oRs.Close();
__Log("Bijbehorende Woco bedrijfkey: " + prs_bedrijf_woco_key);

var bytes = Request.TotalBytes;
if (bytes == 0)
    _AiAi("Empty file uploaded");

var fileStream = Server.CreateObject("ADODB.Stream");
fileStream.Type = 1; // adTypeBinary eerst nog
fileStream.Open();
try
{
    "Error 'Operation not Allowed' op de volgende regel betekent meestal dat de upload te groot is";
    fileStream.Write(Request.BinaryRead(bytes));
}
catch(e)
{
    var msg = L("lcl_shared_upload_error_start") + e.description + L("lcl_shared_upload_error_end");
    _AiAi(msg);
}

var request_id = shared.random(32); // unieke identificatie van deze request

var filesize = fileStream.Size;
var oXML = new ActiveXObject("Msxml2.DOMDocument.6.0");
var oNode = oXML.createElement("encodeddata");
oNode.dataType = "bin.base64"; // of "bin.hex";
fileStream.Position = 0;
oNode.nodeTypedValue = fileStream.read(fileStream.Size);
var data64 = oNode.text.replace(/\n/g, ""); // Ik wil de newlines er niet in hebben
var backupfile = shared.tempFolder() + "\\BCTAdapter_" + request_id + "_" + filename;
fileStream.SaveToFile(backupfile); // bij success verwijderen we hem weer
fileStream.Close();

var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
var filehash = oCrypto.hex_sha1_file(backupfile);
// Hebben we deze request eerder gezien?
var sql = "SELECT mar_factuur_queue_aanmaak"
        + "     , mar_factuur_queue_filename"
        + "     , mar_factuur_queue_response"
        + "     , mar_factuur_queue_sent"
        + "  FROM mar_factuur_queue"
        + " WHERE mar_factuur_queue_klantid = " + safe.quoted_sql(klantid)
//        + "   AND mar_factuur_queue_apikey = " + safe.quoted_sql(APIKEY)
        + "   AND mar_factuur_queue_filehash = " + safe.quoted_sql(filehash)
        + " ORDER BY mar_factuur_queue_aanmaak DESC";
var oRs = Oracle.Execute(sql)
if (!oRs.EOF)
{
    var ddaanmaak = new Date(oRs("mar_factuur_queue_aanmaak").Value);
    __DoLog("Dubbel: deze factuur heb ik eerder {0} naar BCT gestuurd".format(toDateTimeString(ddaanmaak, true)), "#ff0");
    if (oRs("mar_factuur_queue_sent").Value == null)
    {
        __DoLog("Maar dat faalde met een '{0}'. Daarom probeer ik het nu opnieuw".format(oRs("mar_factuur_queue_response").Value));
        // verder doorvallen naar opnieuw proberen
    }
    else
    {
        var minago = Math.round((new Date().getTime() - ddaanmaak.getTime()) / 1000 / 60);
        if (minago > 30)
        {
            __DoLog("Dat is {0} minuten geleden (meer dan 30). Daarom probeer ik het nu opnieuw".format(minago));
            // verder doorvallen naar opnieuw proberen
        }
        else
        {
            __DoLog("Dat is {0} minuten geleden (minder dan 30). Ik negeer hem gewoon".format(minago));
            fso.DeleteFile(backupfile); // Dan mag die wel weg
            Response.Write("Dubbel: deze factuur heb ik eerder {0} naar BCT gestuurd. We negeren hem".format(toDateTimeString(ddaanmaak, true)));
            // Geen 500-error of zo, we negeren deze e-mail silent
            Response.End;
        }
    }
}
oRs.Close();

var fields =  [ { dbs: "mar_factuur_queue_key",         typ: "key",      seq: "mar_s_mar_factuur_queue_key" },
                { dbs: "prs_bedrijf_key",               typ: "key",      val: prs_bedrijf_woco_key},
                { dbs: "mar_factuur_queue_klantid",     typ: "varchar",  val: klantid,    len: 64 },
                { dbs: "mar_factuur_queue_from",        typ: "varchar",  val: from,       len: 64 },
                { dbs: "mar_factuur_queue_to",          typ: "varchar",  val: to,         len: 64 },
                { dbs: "mar_factuur_queue_subject",     typ: "varchar",  val: subject,    len: 4000 },
                { dbs: "mar_factuur_queue_filename",    typ: "varchar",  val: filename,   len: 256 },
                { dbs: "mar_factuur_queue_filesize",    typ: "number",   val: filesize },
                { dbs: "mar_factuur_queue_filehash",    typ: "varchar",  val: filehash,   len: 64 },
                { dbs: "mar_factuur_queue_backupfile",  typ: "varchar",  val: backupfile, len: 256 },
                { dbs: "mar_factuur_queue_requestid",   typ: "varchar",  val: request_id, len: 64 },
                { dbs: "prs_perslid_key",               typ: "key",      val: prs_perslid_contractant_key }
              ];
var marIns = buildInsert("mar_factuur_queue", fields, { noValidateToken: true});
var mar_queue_key = marIns.sequences["mar_factuur_queue_key"];
Oracle.Execute(marIns.sql);

// Documentatie in "z:\Operations\Leveranciers\BCT-IDT Scanning software\Whitepaper BCT Partner service v1.0.4.pdf"
__Log("BCT Adapter Before postdata");
var postdata =
{     "requestid": request_id, // deze komt met de XML response helaas niet terug
      "partner": config.BCT_partnerID,
      "partnertenant": klantid,
      "jobid": "Aareon_NL_invoice",
      "jobdescription": "invoice_mareon",
      "filename": filename,
      "contentsize": data64.length,
      "properties": [{ "key": "partnercallbackurl",
                       "value": HTTP.urlzelf() + "/?API=FIN_FACTUUR_PDF&APIKEY={0}".format(APIKEY)
                                               + "&sent_date={0}".format(toISODateTimeString(new Date())) // handig in IIS logfile
                                               + "&mar_queue_key={0}".format(mar_queue_key)               // Wordt in api_bct_factuur_import.asp uitgelezen
                                               + "&mar_queue_requestid={0}".format(request_id)            // Wordt in api_bct_factuur_import.asp uitgelezen
                     },
                     { "key": "partnercallbackformat",
                       "value": "XML"
                     }
                    ],
      "content": data64
}

var postdatastr = JSON.stringify(postdata, null, " ");
__Log("BCT Adapter postdata:" + postdatastr);

var start = us_timer();
try
{
    var objXMLHTTP = new ActiveXObject("MSXML2.ServerXMLHTTP");

    // SXH_PROXY_SET_DEFAULT is 0 en gebruikt default proxy
    if (config.proxymode == 1) // Direct
    {
        var SXH_PROXY_SET_DIRECT = 1;
        objXMLHTTP.setProxy(SXH_PROXY_SET_DIRECT); // omzeil proxy.
    }
    else if (config.proxymode == 2)
    {
        var SXH_PROXY_SET_PROXY = 2;
        objXMLHTTP.setProxy(SXH_PROXY_SET_PROXY, config.proxy_ip);
    }

    objXMLHTTP.open("POST", config.BCT_Url, false, config.BCT_Uid, config.BCT_Pwd);
    objXMLHTTP.setRequestHeader("Content-Type", "application/json; charset=windows-1252");

    // Forceer Basic Authentication. Voorkomt dat eerst een request met 401 resultaat wordt gedaan
    var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
    objXMLHTTP.setRequestHeader("Authorization", "Basic " + oCrypto.base64(config.BCT_Uid + ":" + config.BCT_Pwd));

    //objXMLHTTP.setRequestHeader ("Accept", "application/json");
    __Log("BCT Adapter Before send");
    objXMLHTTP.send(postdatastr);
    var sql = "UPDATE mar_factuur_queue"
            + "   SET mar_factuur_queue_response = " + safe.quoted_sql(objXMLHTTP.status + ": " + objXMLHTTP.statusText, 64)
            + " WHERE mar_factuur_queue_key = " + mar_queue_key;
    Oracle.Execute(sql);
    if (objXMLHTTP.status >= 200 && objXMLHTTP.status <= 299) // 201: successfully created
    {
          Response.Write("Ok " + objXMLHTTP.status);
          var sql = "UPDATE mar_factuur_queue"
                  + "   SET mar_factuur_queue_sent = SYSDATE"
                  + " WHERE mar_factuur_queue_key = " + mar_queue_key;
          Oracle.Execute(sql);
    }
    else // Waarschijnlijk 500-error. We weten niet of hij goed is overgekomen en laten mar_factuur_queue_sent daarom leeg
    {
        __DoLog("BCT Adapter return HTTP status: " + objXMLHTTP.status + ": " + objXMLHTTP.statusText);
        __DoLog("BCT Adapter HTTP responseText:\n" + objXMLHTTP.responseText);
        __DoLog("BCT Adapter HTTP responseHeaders:\n" + objXMLHTTP.getAllResponseHeaders);
        throw({ description: "HTTP statuscode " + objXMLHTTP.status });
    }
    __Log("BCT Adapter HTTP responseText:" + objXMLHTTP.responseText);
}
catch (e)
{
    __DoLog("BCT Adapter URL: " + config.BCT_Url);
    postdata.content = "<stripped {0} bytes for logfile>".format(postdata.content.length);
    __DoLog(postdata);
    var tm = (us_timer() - start) / 1000;
    __DoLog("BCT took {0} milliseconds for {1} bytes, speed <= {2} byte/s".format(Math.round(tm), postdatastr.length,
                                                                                  Math.round(postdatastr.length * 1000 / tm)));

    __DoLog("Backup file saved to:" + backupfile);
    var sql = "UPDATE mar_factuur_queue"
            + "   SET mar_factuur_queue_response = " + safe.quoted_sql(e.description, 64)
            + " WHERE mar_factuur_queue_key = " + mar_queue_key;
    Oracle.Execute(sql);

    _AiAi("Uploading invoice to BCT failed: " + e.description);
}
var tm = (us_timer() - start) / 1000;
if (config.logtiming)
{
    __DoLog("BCT took {0} milliseconds for {1} bytes, speed {2} byte/s".format(Math.round(tm), postdatastr.length,
                                                                               Math.round(postdatastr.length * 1000 / tm)));
}

fso.DeleteFile(backupfile); // Alles goed? Dan mag hij wel weer weg
var sql = "UPDATE mar_factuur_queue"
        + "   SET mar_factuur_queue_backupfile = NULL"
        + " WHERE mar_factuur_queue_key = " + mar_queue_key;
Oracle.Execute(sql);

Response.Write(objXMLHTTP.responseText); // komt terug in hMail logging
%>