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

    File:           api_opdrsoap.asp
    Description:    API voor ORD-soap berichten
                    Interpreteert een bericht zodanig dat een opdracht wordt aangemaakt
                    (incl. evt. bovenliggende melding) of aangepast.
                    Dat is: qua omschrijving (voortgang), kosten of status.
                    Als een status wordt meegegeven, dan is ook vereist dat dat een
                    geldige statusovergang is, anders wordt het hele bericht genegeerd.

    Parameters:     Een xml
    Context:
    Notes:
*/
    DOCTYPE_Disable = 1;
    THIS_FILE = "appl/api/api_opdrsoap.asp";
%>
<!-- #include file="../Shared/common.inc" -->
<!-- #include file="../Shared/xml_converter.inc" -->
<!-- #include file="../Shared/save2db.inc" -->
<!-- #include file="../Shared/flexfiles.inc" -->
<!-- #include file="../Shared/upload.inc" -->
<!-- #include file="../api/api.inc" -->
<!-- #include file="../mld/mld.inc" -->
<%
// We sturen het antwoord in UTF-8.
Session.Codepage = 65001;
Response.Charset = 'utf-8';

var API = new API_func();

var MLDremark = 0; // 0= negeer, 1=append bij autoorder, 2=overwrite bij autoorder, 5=append altijd, 6=overwrite altijd
var ORDremark = 2; //

/* API options voorbeeld:
  {
    MLDremark: 0,
    ORDremark: 2
  }
*/

API.apidata.options = API.apidata.options || {};

if ("MLDremark" in API.apidata.options)
    MLDremark = API.apidata.options["MLDremark"];

if ("ORDremark" in API.apidata.options)
    ORDremark = API.apidata.options["ORDremark"];

if (API.apidata.loglevel > 1) // Zet maar op 3 als je HTML logging wilt
    Session("logging") = API.apidata.loglevel||0;

//user.checkAutorisation("WEB_MLDUSE"); // Dit is nog ongeacht de melding.

var tsql = "-";     // Voor tijdelijke statement.
var sql = "-";      // De uiteindelijke insert/update-sql.
var xmlReq = Server.CreateObject("MSXML2.DOMDocument.6.0");
if (API.apidata.stylesheet)
{
  var iXsl = Server.CreateObject("MSXML2.DOMDocument.6.0");
  if( ! iXsl.load(Server.MapPath(API.apidata.stylesheet)) )
  {
      API.error("Could not load XSL " + API.apidata.stylesheet + "\n" + iXsl.parseError.reason);
  }
  var inputXML = Server.CreateObject("MSXML2.DOMDocument.6.0");
  inputXML.load(Request);

  if (inputXML.parseError.errorCode != 0)
  {
    __DoLog( "Error loading XML: "
                 + inputXML.parseError.errorCode
                 + "\n" + inputXML.parseError.reason
                 + " regel " + inputXML.parseError.line
                 + "(" + inputXML.parseError.linepos + ")"
             , "#ff0000");
  }
  if (API.apidata.loglevel) __Log2File(inputXML.xml, API.APIname + "_IN");

  inputXML.transformNodeToObject(iXsl, xmlReq);
}
else
  xmlReq.load(Request);

if (API.apidata.loglevel) __Log2File(xmlReq.xml, API.APIname + "_TUSSEN");

var xmlResp = new ActiveXObject("MSXML2.DOMDocument.6.0");
xmlResp.appendChild(xmlResp.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""))

// The response.
var FCLTElement = xmlResp.createElement("facilitor");
// The response header.
var now = new Date();
var nowtxt = now.getFullYear()+'-'+padout(now.getMonth()+1) +'-'+padout(now.getDate()) +' '
                       +padout(now.getHours()) +':'+padout(now.getMinutes())+':'+padout(now.getSeconds());
var elmHeader = xmlResp.createElement("header");
var headerinfo = {
//             file: String(Request.ServerVariables("SCRIPT_NAME")).toLowerCase(),
             datum: nowtxt,
             naam: user.naam(),
             custId: customerId,
             language: user.lang()
           }
for (param in headerinfo)
{
  var FCLTdata = xmlResp.createElement(param);
  FCLTdata.appendChild(xmlResp.createTextNode(headerinfo[param]));
  elmHeader.appendChild(FCLTdata);
}
FCLTElement.appendChild(elmHeader);

// Hier zou het echte werk moeten gebeuren nav. xmlReq
// en FCLTElement moeten we uitbreiden met antwoorden.
var detected ="?";

// Dit is de opdrachtenloop (mochten er ooit nog anderen gaan volgen).
var opdrachten = xmlReq.getElementsByTagName("opdracht");
var wasMLDremark = MLDremark;
var wasORDremark = ORDremark;
for (i=0; i < opdrachten.length; i++)
{
  MLDremark = wasMLDremark; // Resetten voor elke opdracht. Tweede opdracht hoeft namelijk geen autoorder te zijn
  ORDremark = wasORDremark;

  var resultcode = -1;   /* Zolang deze -1 is, is het nog goed. Uiteindelijk eindigt het met 0 (als goed). */
  var resulttekst = "";

  // Lees per node de (optionele) tags en waarden.
  var opdrid          = opdrachten[i].getAttribute("key"); // UPD
  var opdraction      = opdrachten[i].getAttribute("type").toLowerCase(); // NEW/UPD

  var externnr        = XMLval(opdrachten[i], "externnr"); // NEW
  var plandatum       = XMLval(opdrachten[i], "plandatum");
  var voor_key        = parseInt(XMLval(opdrachten[i], "voor"), 10); // NEW
  var stdm_key        = parseInt(XMLval(opdrachten[i], "stdmelding_key"), 10); // NEW
  var topdr_key       = parseInt(XMLval(opdrachten[i], "typeopdr_key"), 10); // NEW
  var uitv_key        = parseInt(XMLval(opdrachten[i], "bedrijf_key"), 10); // NEW
  var opdrachttekst   = XMLval(opdrachten[i], "opdrachttekst"); // NEW

  var txt_mut_datum   = XMLval(opdrachten[i], "mut_datum"); // UPD
  var opdrstatus      = XMLval(opdrachten[i], "status"); // UPD
  var opdropmerking   = XMLval(opdrachten[i], "opmerking"); // UPD

  var opdrgereed      = XMLval(opdrachten[i], "datumgereed"); // NEW/UPD
  var opdrkosten      = XMLval(opdrachten[i], "kosten"); // NEW/UPD
  var opdrkenmerken   = (opdrachten[i].getElementsByTagName("kenmerk")); // NEW/UPD

  var kpn_key         = -1;
  var mld_key         = -1;   // Maken we aan of bepalen we uit de melding/volgnr.
  var opdrvolgnr      = -1;   // Maken we aan of bepalen we uit de melding/volgnr.
  var opdr_key        = -1;   // Maken we aan of bepalen we uit de melding/volgnr.
  var oldstatus       = -1;
  var mld_fields      = [];   // Bij te werken velden.
  var opdr_fields     = [];   // Bij te werken velden.

  if (opdrid == null)
  { // Voorkom problemen als key-attribuut ontbreekt/leeg!
    opdrid = '';
  }
  if (externnr == null)
  { // Voorkom problemen als externnr-node ontbreekt/leeg!
    externnr = '';
  }

  if (opdraction == "insert")
  {
    // Let op: mld_melding_externnr is niet gegarandeerd uniek: meerdere externe systemen
    //         kunnen dezelfde (externe) nummering gebruiken
    // TODO: Bepalen meldingen  beperken tot alleen die meldingen die zijn aangemaakt door betreffende API-user!
    //       Of beter: WHERE ORDBOF schrijfrechten op de melding
    // Wel: verderop controleren we al wel of je canAddOpdr hebt
    tsql = "SELECT MIN(mld_melding_key) mld_melding_key, COUNT(*) aantal"
         + "  FROM mld_melding"
         + " WHERE mld_melding_externnr="+ safe.quoted_sql(externnr);
    var oRs = Oracle.Execute(tsql);
    switch (oRs("aantal").value)
    {
      case 0: // Automatisch melding aanmaken.
              // We ondersteunen hier alleen extreem simpele meldingen (alles default).
              // Wil je meer? Dan maak je maar zelf een melding aan via de MLDAPI.
          if (stdm_key && stdm_key > 0)
          {
            tsql = "SELECT sm.mld_stdmelding_t_uitvoertijd.tijdsduur tijdsduur"
                + "      , sm.mld_stdmelding_t_uitvoertijd.eenheid eenheid"
                + "   FROM mld_stdmelding sm"
                + "  WHERE sm.mld_stdmelding_key = " + stdm_key
                + "    AND sm.mld_stdmelding_verwijder IS NULL";
            oRs = Oracle.Execute(tsql);
            if (oRs.eof)
            {
              resultcode = 3;
              resulttekst = "Undefined stdmelding " + stdm_key;
            }

            // Hier heb ik een geldige stdm_key.
            if (resultcode == -1) // Nog steeds geen fouten.
            { // Bepaal kostenplaats via voor-user
              // Als die voor exact één kostenplaats is gemandateerd dan gebruiken
              // we die kostenplaats. Anders laten we de kostenplaats gewoon leeg.
              sql = "SELECT pk.prs_kostenplaats_key, prs_kostenplaats_nr"
                  + "  FROM prs_perslidkostenplaats ppk,"
                  + "       prs_kostenplaats pk"
                  + " WHERE pk.prs_kostenplaats_key = ppk.prs_kostenplaats_key"
                  + "   AND ppk.prs_perslid_key = " + voor_key
                  + "   AND prs_kostenplaats_verwijder IS NULL"
                  + "   AND prs_perslidkostenplaats_boeken = 1";
              var oRs = Oracle.Execute(sql);
              if (!oRs.Eof)
              {
                kpn_key = oRs("prs_kostenplaats_key").Value || -1; // Kan leeg zijn als voor alles gemandateerd
                kpn_nr = oRs("prs_kostenplaats_nr").Value;
                oRs.MoveNext();
                if (!oRs.Eof) // Er zijn er meerdere
                {
                    kpn_key = -1;
                    __Log("Gemandateerd voor meerdere kostenplaatsen dus genegeerd.");
                }
                else
                    __Log("Uitsluitend gemandateerd voor kostenplaats: " + kpn_nr);
              }
            }
            if (resultcode == -1) // Nog steeds geen fouten.
            {
              var meld_oms = "Automatisch aangemaakte melding tbv. werkzaamheden geïnitieerd in extern systeem met referentie: "+ externnr;
              mld_key = mld.insertmelding(stdm_key,
                      {
                          kostenplaats_key: kpn_key,
                          perslid_key: voor_key,
                          fields: [{ dbs: "mld_melding_externnr",     typ: "varchar",  val: externnr },
                                   { dbs: "mld_melding_omschrijving", typ: "varchar",  val: meld_oms }
                                  ]
                      });

              // mld.insertmelding heeft al op status 2 (nieuw) gezet
              mld.setmeldingstatus(mld_key, 4);
            }
          }
          break;
      case 1:
          mld_key = oRs("mld_melding_key").Value;
          break;
      default:
          {
            // Te veel kunnen we nog niet echt aan?
          }
    }
    oRs.Close();
    if (mld_key < 0)
    { // Tja, dan wordt het lastig?
      resultcode = 7;
      resulttekst = "Melding '{0}' cannot be identified uniquely".format(externnr);
    }


    if (resultcode == -1) // Nog steeds geen fouten.
    {
      var this_melding = mld.func_enabled_melding(mld_key);
      if (!this_melding.canAddOpdr)
      {
        resultcode = 4;
        resulttekst = "Not authorized";
      }
    }
    // Hier heb ik een geldige mld_key (nieuw of bestaand).
    if (resultcode == -1) // Nog steeds geen fouten.
    { // Bepaal opdrachttype.
      tsql = "SELECT mld_typeopdr_key"
           + "  FROM mld_typeopdr"
           + " WHERE mld_typeopdr_key="+ topdr_key;
      var oRs = Oracle.Execute(tsql);
      if (oRs.eof)
      {
        resultcode = 8;
        resulttekst = "Undefined opdrachttype "+ topdr_key;
      }
      oRs.Close();
    }

    // Hier heb ik een geldige topdr_key.
    if (resultcode == -1) // Nog steeds geen fouten.
    { // Bepaal uitvoerende.
      tsql = "SELECT prs_bedrijf_key"
           + "  FROM prs_bedrijf"
           + " WHERE prs_bedrijf_key="+ uitv_key
           + "   AND prs_bedrijf_verwijder IS NULL";
      var oRs = Oracle.Execute(tsql);
      if (oRs.eof)
      {
        resultcode = 8;
        resulttekst = "Undefined uitvoerende "+ uitv_key;
      }
      oRs.Close();
    }

    // Hier heb ik een geldige uitv_key.
    if (resultcode == -1) // Nog steeds geen fouten.
    { // Alvast de nieuwe opdracht aanmaken. Rest komt later.
      var mld_info = mld.mld_melding_info(mld_key);
      var fields = [ { dbs: "mld_opdr_key",                typ: "key",      seq: "mld_s_mld_opdr_key" },
                     { dbs: "mld_opdr_module",             typ: "varchar",  val: "MLD" },
                     { dbs: "mld_melding_key",             typ: "key",      val: mld_key },
                     { dbs: "prs_kostenplaats_key",        typ: "key",      val: mld_info.kostenpl_key },
                     { dbs: "mld_uitvoerende_keys",        typ: "key",      val: uitv_key },
                     { dbs: "mld_typeopdr_key",            typ: "key",      val: topdr_key },
                     { dbs: "mld_opdr_bedrijfopdr_volgnr", typ: "sql",      val: "mld.bepaalopdrmeldingvolgnr(" + mld_key +")" },
                     { dbs: "mld_opdr_datumbegin",         typ: "datetime", val: new Date() }
                   ];

      if (opdrachttekst != null)
      {
        fields.push({ dbs: "mld_opdr_omschrijving",      typ: "varchar",  val: opdrachttekst, len: 4000 });
      }

      var mldIns = buildInsert("mld_opdr", fields, { noValidateToken: true });
      var sql = mldIns.sql;
      var err = Oracle.Execute(sql, true);
      if (err.friendlyMsg)
      {
        resultcode = 9;
        resulttekst = "Database error: "+ err.friendlyMsg;
      }

      opdr_key = mldIns.sequences["mld_opdr_key"]; // Hier heb ik de geldige opdr_key (igv. insert).
      mld.setopdrachtstatus (opdr_key, 5);
      mld.updatemeldingstatus (mld_key, 0);
    }
  }
  else if (opdraction == "update")
  {   // Bestaande opdracht zoeken
    var idarr = opdrid.split('/');
    mld_key = parseInt(idarr[0], 10);
    opdrvolgnr = parseInt(idarr[1], 10);

    if (isNaN (mld_key) || isNaN (opdrvolgnr))
    {
      resultcode = 2;
      resulttekst = "Invalid opdracht id (key="+ opdrid +")";
    }
    else
    {
      tsql = "SELECT mld_opdr_key"
          + "   FROM mld_opdr"
          + "  WHERE mld_melding_key="+ mld_key
          + "    AND mld_opdr_bedrijfopdr_volgnr="+ opdrvolgnr;
      var oRs = Oracle.Execute(tsql);
      if (oRs.eof)
      {
          resultcode = 5;
          resulttekst = "Non existent opdracht";
      }
      else
      {   // Hier heb ik de geldige opdr_key (igv. update).
          opdr_key = oRs("mld_opdr_key").value;
      }
      oRs.Close();
    }
  }
  else
  {
    resultcode = 2;
    resulttekst = "Undefined operation (type="+ opdraction +")";
  }

  if (resultcode == -1)
  {  // Hier heb ik een geldige opdr_key.
    var this_opdr = mld.func_enabled_opdracht(opdr_key);
    if (!this_opdr.canChange)
    {
      resultcode = 4;
      resulttekst = "Not authorized";
    }

    var mld_opdr = mld.mld_opdr_info(opdr_key); // Bevat alle info van de opdracht.
    var stdm_info = mld.mld_stdmeldinginfo(mld_opdr.stdm_key);

    // Initialiseer (nog eens) enkele opdrachtgegevens tbv. de response of vervolg.
    opdrid = mld_key + "/" + mld_opdr.mld_opdr_bedrijfopdr_volgnr;
    oldstatus = mld_opdr.opdr_status;
    topdr_key = mld_opdr.opdr_type;

    var autoorder = stdm_info.autoorder;
    if (autoorder)
    {
        if (MLDremark > 0)
            MLDremark |= 4; // 'Altijd' bitje zetten
        if (ORDremark > 0)
            ORDremark |= 4; // 'Altijd' bitje zetten
    }

    var mut_datum = new Date();
    if (txt_mut_datum && mld_opdr.typeopdr_afmeldmarge>0)
    {
      var mut_datum = XMLtoJsDate(txt_mut_datum);
      var maxmarge = new Date();
      maxmarge.setDate(maxmarge.getDate() - mld_opdr.typeopdr_afmeldmarge);
      if (mut_datum < maxmarge)
          mut_datum = new Date(); // te lang geleden
    }

    // Dit zijn de wijzigingen, die voeren we alleen uit bij een geldige statuswijziging
    // of geen statuswijziging
    if (opdropmerking != null)
    { // opmerking bij de opdracht
      var new_opm = opdropmerking;
      if (ORDremark == 5) // Append
      {
          sql = "SELECT mld_opdr_opmerking"
              + "  FROM mld_opdr"
              + " WHERE mld_opdr_key = " + opdr_key;
          oRs = Oracle.Execute(sql);
          if (oRs("mld_opdr_opmerking").Value)
              new_opm = oRs("mld_opdr_opmerking").Value + "\n" + new_opm;
          oRs.Close();
      }
      if (ORDremark == 5 || ORDremark == 6)
      {
        opdr_fields.push({ dbs: "mld_opdr_opmerking",  typ: "varchar", val: new_opm,        track: L("lcl_mld_inf_Opmerking"), len: 4000 });
      }

      // opmerking bij de melding
      var new_mld_opm = opdropmerking;
      if (MLDremark == 5) // Append
      {
          sql = "SELECT mld_melding_opmerking"
              + "  FROM mld_melding"
              + " WHERE mld_melding_key = " + mld_opdr.mld_key;
          oRs = Oracle.Execute(sql);
          if (oRs("mld_melding_opmerking").Value)
            new_mld_opm = oRs("mld_melding_opmerking").Value + "\n" + new_mld_opm;
          oRs.Close();
      }
      if (MLDremark == 5 || MLDremark == 6)
      {
        mld_fields.push({ dbs: "mld_melding_opmerking",  typ: "varchar", val: new_mld_opm,        track: L("lcl_mld_inf_Opmerking"), len: 4000 });
      }
    }

    if (opdrkosten != null)
        opdr_fields.push({ dbs: "mld_opdr_kosten",     typ: "float",   val: opdrkosten,     track: L("lcl_total_cost") });

    if (plandatum != null)
    {
      var plandatumdate = XMLtoJsDate(plandatum);
      opdr_fields.push({ dbs: "mld_opdr_plandatum",  typ: "datetime",    val: plandatumdate, track: L("lcl_opdr_plandate") });
    }

    if (opdrgereed != null)
    {
      var opdrgereeddate = XMLtoJsDate(opdrgereed);
      opdr_fields.push({ dbs: "mld_opdr_einddatum",  typ: "date",    val: opdrgereeddate, track: L("lcl_opdr_enddate") });
      if (autoorder) // Ooit: net als appendRemark via json configureerbaar maken?
        mld_fields.push({ dbs: "mld_melding_einddatum",  typ: "date",    val: opdrgereeddate, track: L("lcl_mld_enddate") });
    }
    // We weten nu de updates, straks voeren we deze pas uit
    // Eerst de eventuele statuswijzigingen
    var newstatus = -1;
    if (opdrstatus != null)
    { // Er is dus wel een status meegegeven
      switch (opdrstatus)
      {
        case 'ORDACP' :
            if (this_opdr.canAccept) {
                if (oldstatus == 5) {
                    newstatus = 8;
                } else {
                    resultcode = 2;
                    resulttekst = "Invalid status change";
                }
            } else {
                resultcode = 4;
                resulttekst = "Not authorized for ORDACP";
            }
            break;
        case 'ORDCAN' :
            if (this_opdr.canCancel) {
                if (oldstatus == 5 || oldstatus == 8) {
                    newstatus = 1;
                } else {
                    resultcode = 2;
                    resulttekst = "Invalid status change";
                }
            } else {
                resultcode = 4;
                resulttekst = "Not authorized for ORDCAN";
            }
            break;
        case 'ORDAFM' :
             if (this_opdr.canClose) {
                if (oldstatus == 5 || oldstatus == 8 ) {
                    newstatus = 6;
                } else {
                    resultcode = 2;
                    resulttekst = "Invalid status change";
                }
            } else {
                resultcode = 4;
                resulttekst = "Not authorized for ORDAFM";
            }
            break;
        case 'ORDAFR' :
            if (this_opdr.canFinish) {
                if (oldstatus == 6 ) {
                    newstatus = 9;
                } else {
                    resultcode = 2;
                    resulttekst = "Invalid status change";
                }
            } else {
                resultcode = 4;
                resulttekst = "Not authorized for ORDAFR";
            }
            break;
        default:
            resultcode = 3;
            resulttekst = "Invalid status";
      }  // switch
    }

    if (resultcode == -1)
    { // Nog steeds geen fouten
      // Construct the update
      if (this_opdr.canChange)
      {
        if (opdr_fields.length>0)
        {
          var mldUpd = buildTrackingUpdate("mld_opdr", "mld_opdr_key = " + opdr_key, opdr_fields, { noValidateToken: true });
          Oracle.Execute(mldUpd.sql);
          mld.trackopdrachtupdate(opdr_key, L("lcl_ord_is_updatedbysoap") + "\n" + mldUpd.trackarray.join("\n"));
          if (mut_datum) // Antedateren voor SLA rapportages.
          {
              var sql = "BEGIN fac.backtrackaction('ORDUPD', " + opdr_key + ", " + user_key + ", " + mut_datum.toSQL(true) +"); END;"
              Oracle.Execute(sql);
          }
        }
      }

      var this_mld = mld.func_enabled_melding(mld_opdr.mld_key);
      // mag ik de melding ook aanpassen?
      if (this_mld.canClose && (autoorder || MLDremark > 0))
      {
        if (mld_fields.length>0)
        {
          var mldUpd = buildTrackingUpdate("mld_melding", "mld_melding_key = " + mld_opdr.mld_key, mld_fields, { noValidateToken: true });
          Oracle.Execute(mldUpd.sql);

          var formattedID = stdm_info.ins_srtdiscipline_prefix+mld_opdr.mld_key + " ("+ stdm_info.discipline_omschrijving + "/"+ stdm_info.stdmelding_omschrijving +")";
          mld.trackmeldingupdate(mld_opdr.mld_key, L("lcl_mld_is_updatedbysoap").format(formattedID) + "\n" + mldUpd.trackarray.join("\n"));

          if (mut_datum) // Antedateren voor SLA rapportages.
          {
              var sql = "BEGIN fac.backtrackaction('MLDUPD', " + mld_opdr.mld_key + ", " + user_key + ", " + mut_datum.toSQL(true) +"); END;"
              Oracle.Execute(sql);
          }
        }
      }

      //Response.Write("lengte:"+ opdrkenmerken.length);
      for (j=0; j < opdrkenmerken.length; j++)
      {
        var kenmerk_naam = opdrkenmerken[j].getAttribute("naam");
        if (opdrkenmerken[j].childNodes.length > 0)
           var kenmerk_waarde = opdrkenmerken[j].childNodes[0].nodeValue;
        else
           var kenmerk_waarde = "";
        //Response.Write(kenmerk_naam);
        //Response.Write(kenmerk_waarde);
        ksql = "SELECT k.mld_kenmerk_key, sk.mld_srtkenmerk_kenmerktype, sk.mld_srtkenmerk_lengte "
             + "  FROM mld_kenmerk k, mld_srtkenmerk sk "
             + " WHERE k.mld_typeopdr_key = " + topdr_key
             + "   AND k.mld_srtkenmerk_key = sk.mld_srtkenmerk_key "
             + "   AND k.mld_kenmerk_verwijder IS NULL "
             + "   AND sk.mld_srtkenmerk_upper = " + safe.quoted_sql_upper(kenmerk_naam);
        var oRs = Oracle.Execute(ksql);

        if (!oRs.eof)
        {
          var kenmerk_key = oRs("mld_kenmerk_key").value;
          var kenmerk_type = oRs("mld_srtkenmerk_kenmerktype").value;
          var kenmerk_lengte = oRs("mld_srtkenmerk_lengte").value;

          ksql = "SELECT ko.mld_kenmerkopdr_key "
               + "  FROM mld_kenmerkopdr ko "
               + " WHERE ko.mld_opdr_key =  " + opdr_key
               + "   AND ko.mld_kenmerk_key = " + kenmerk_key;
          var oRs = Oracle.Execute(ksql);

          switch (kenmerk_type)
          {
            case 'C':
            case 'X':
            case 'N':
            { // We ondersteunen alleen nog maar karakter- en bestandsnaam-velden.
              // AEG: Maar wat maakt een nummer nu anders dan een karakter ?
              if (!oRs.eof)
              {
                var kenmerkopdr_key = oRs("mld_kenmerkopdr_key").value;
                ksql = "UPDATE mld_kenmerkopdr SET mld_kenmerkopdr_waarde = " + safe.quoted_sql(kenmerk_waarde) + " WHERE mld_kenmerkopdr_key = " + kenmerkopdr_key;
              }
              else
              {
                ksql = "INSERT INTO mld_kenmerkopdr (mld_kenmerk_key, mld_opdr_key, mld_kenmerkopdr_waarde) "
                     + "VALUES (" + kenmerk_key + ", " + opdr_key + ", " + safe.quoted_sql(kenmerk_waarde) + ")";
              }
              Oracle.Execute(ksql);
            }
            case "M": // Folder met bijlagen
            { //Response.Write(kenmerk_naam);
              var bijlagen = opdrkenmerken[j].getElementsByTagName("bijlage");
              var bi;
              __Log ('bijlagen.length:' + bijlagen.length);
              for (bi = 0; bi < bijlagen.length; bi++)
              {
                var Attachment = XMLval(bijlagen[bi], "attachment");
                var Name = XMLval(bijlagen[bi], "name");
                var Size = XMLval(bijlagen[bi], "size");
                //Response.Write("Name: " + Name + " size: " + Size);
                if (Attachment && Name && Size)
                {
                  var SafeName = safe.filename(Name);
                  var params = flexProps("MLD", opdr_key, String(kenmerk_key), "O");
                  if (!params.isAllowedName(SafeName))
                  {
                    __DoLog("Unsafe SOAP file '{0}' ignored.".format(SafeName), "#FFFF00");
                  }
                  else
                  {
                    __Log("Start saving: " + params.AttachPath + SafeName);
                    CreateFullPath(params.AttachPath);
                    encodedString2File(params.AttachPath + SafeName, Attachment, "bin.hex");
                    __Log("Done saving: " + params.AttachPath + SafeName);
                  }
                }
              }
            }
          }
        }
      }

      if (newstatus != -1)
      {
        mld.setopdrachtstatus(opdr_key, newstatus);
        // Hier terugchecken van de status
        tsql = "SELECT mld_statusopdr_key FROM mld_opdr"
             + " WHERE mld_opdr_key="+ opdr_key;
        oRs = Oracle.Execute(tsql);
        if (oRs("mld_statusopdr_key").value == newstatus)
        {
          resulttekst = "Status set to "+opdrstatus;
          if (mut_datum && opdrstatus) // Tracking antedateren voor SLA rapportages.
          { // 'Toevallig' loopt opdrstatus 1-op-1 met onze trackingcodes
            var sql = "BEGIN fac.backtrackaction("+safe.quoted_sql(opdrstatus)+", " + opdr_key + ", " + user_key + ", " + mut_datum.toSQL(true) +"); END;"
            Oracle.Execute(sql); // Statuswijzigingen wel even tracken
            var txt = { "ORDAFM": L("lcl_ord_is_ordafm"),
                        "ORDACP": L("lcl_ord_is_ordacp"),
                        "ORDAFR": L("lcl_ord_is_ordafr")
                      }[opdrstatus];
            mld.trackopdrachtupdate(opdr_key, L("lcl_ord_is_ordupd") + "\n" + txt + L("lcl_trackto") + toDateTimeString(mut_datum));
          }

          // Zijn er nog lopende opdrachten
          tsql = "SELECT COUNT ( * ) lopend FROM  mld_opdr"
               + " WHERE mld_melding_key = " + mld_key
               + " AND mld_statusopdr_key NOT IN (1, 2, 6, 7, 9)"; // (1=afgewezen, 2=niet akkoord, 6=afgemeld, 7=verwerkt en 9=afgerond)
          oRs = Oracle.Execute(tsql);

          if (oRs("lopend").value == 0)
          { // Er zijn alleen opdrachten met status 1 (Afgewezen) of 6/9 (Afgemeld/Afgerond)
            // Check of setting bij opdrachttype automatisch sluiten ALTIJD (= 2) toestaat.
            tsql = "SELECT mld_typeopdr_sluitmelding FROM mld_typeopdr"
                 + " WHERE mld_typeopdr_key = " + topdr_key;
            var oRs = Oracle.Execute(tsql);

            // Afhankelijk van sluitmelding nu melding status zetten (0=nooit, 1=vragen en 2=altijd)
            // Als de laatste opdracht een cancel was dan wordt de melding niet afgemeld.
            if ((oRs("mld_typeopdr_sluitmelding").value == 2 || oRs("mld_typeopdr_sluitmelding").value == 1)
                 && this_mld.canClose
                 && opdrstatus != 'ORDCAN')
            {
              mld.setmeldingstatus (mld_key, 5); // Afgemeld
              var sql = "BEGIN fac.backtrackaction('MLDAFM', " + mld_key + ", " + user_key + ", " + mut_datum.toSQL(true) +"); END;"
              Oracle.Execute(sql); // Statuswijzigingen wel even tracken
              mld.trackmeldingupdate(mld_key, L("lcl_mld_is_mldupd") + "\n" + L("lcl_mld_is_mldafm") + L("lcl_trackto") + toDateTimeString(mut_datum));
            }
            else
              // Dan zetten we de Melding hier terug naar Geaccepteerd indien die Uitgegeven was
              // Zodat die bij de FO weer onder Inbehandeling valt.
              mld.setmeldingstatus (mld_key, 4); // Geaccepteerd
          }
          // else status van de melding niet aanpassen.
          resultcode = 0;
        }
        else
        {
          resultcode = 1;
          resulttekst = "Status not set to "+opdrstatus+" (is "+oRs("mld_statusopdr_key").value+")";
        }
      }
    }
  }

  if (resultcode == -1) // Nog steeds geen fouten.
  {
    resultcode = 0; // Ik heb gedaan wat ik moest en mocht doen voor deze opdracht.
  }

  var binfo = {
               returncode: resultcode,
               returntekst: resulttekst,
               // executed:sql,   // debug
               datum: nowtxt,
               externnr: externnr
              }

  var FCLTBody = xmlResp.createElement("opdracht");   // type=response
  FCLTBody.setAttribute('key', opdrid);
  FCLTBody.setAttribute('type', 'response');
  for (param in binfo)
  {
    var FCLTdata = xmlResp.createElement(param);
    FCLTdata.appendChild(xmlResp.createTextNode(binfo[param]));
    FCLTBody.appendChild(FCLTdata);
  }

  FCLTElement.appendChild(FCLTBody);
} // end for
// Alle opdracht-nodes zijn behandeld.


xmlResp.appendChild(FCLTElement);

if (API.apidata.stylesheet)
{ // Niet super efficient dat we eerst naar tekstuele xml gaan maar ach...
  STR2Stream(xmlResp.xml, API.apidata.stylesheet, Response, {});
}
else
{
  Response.ContentType = "text/xml";
  Response.Write(xmlResp.xml)
}
%>
