<% /*
    $Revision$
    $Id$

    File:           model_invoicelines.inc

    Description:    Factuurregel model.
    Parameters:
    Context:

    Notes:          TODO: autorisaties voor scope=fo|bo
                    TODO on demand: PUT/POST/DELETE
*/

%>
<!-- #include file="../Shared/discxalg3d.inc"-->
<!-- #include file="../fin/fin.inc" -->
<!-- #include file="./model_custom_fields.inc"-->
<!-- #include file="./model_fac_tracking.inc"-->
<!-- #include file="./model_fin_kenmerk.inc"-->
<%

function model_invoicelines()
{
    this.module = "FIN";
    this.table = "fin_factuurregel";
    this.primary = "fin_factuurregel_key";
    this.records_name = "invoicelines";
    this.record_name = "invoiceline";
    this.fields = { "id"          : { dbs: "fin_factuurregel_key",          typ: "key" },
                    "name"        : { dbs: "fin_factuurregel_omschrijving", typ: "varchar",                                track: true, label: L("lcl_descr"),                    filter: "like" },
                    "line"        : { dbs: "fin_factuurregel_nr",           typ: "number" },
                    "total"       : { dbs: "fin_factuurregel_totaal",       typ: "float",   iscurrency: true,              track: true, label: L("lcl_fin_total_sum_exBTW") },
                    "vat"         : { dbs: "fin_factuurregel_btw",          typ: "float",   iscurrency: true,              track: true, label: L("lcl_fin_total_sum_inBTW") },
                    "reference"   : { dbs: "fin_factuurregel_referentie",   typ: "varchar",                                track: true, label: L("lcl_fin_referencecode"),        filter: "like" },
                    "vatvalue"    : { dbs: "fin_btwtabelwaarde_key",        typ: "key",     foreign: "fin_btwtabelwaarde", track: true, label: L("lcl_fin_btwtarief")},
                    "costtype"    : { dbs: "prs_kostensoort_key",           typ: "key",     foreign: "prs_kostensoort",    track: true, label: L("lcl_shared_charge_type") },
                    "invoice"     : { dbs: "fin_factuur_key",               typ: "key",     foreign: "fin_factuur",        insertonly: true },
                    "code"        : { dbs: "fin_factuurregel_code",         typ: "varchar",                                track: true, label: L("lcl_fin_article_code") },
                    "amount"      : { dbs: "fin_factuurregel_aantal",       typ: "float",                                  track: true, label: L("lcl_fin_amount") },
                    "unit"        : { dbs: "fin_factuurregel_eenheid",      typ: "varchar",                                track: true, label: L("lcl_fin_unit") },
                    "orderlineid" : { dbs: "fin_factuurregel_id",           typ: "number",                                 track: true, label: L("lcl_fin_orderline_id") }
                  };

    this.includes = {
        "custom_fields" : {
            model: new model_custom_fields(this, new model_fin_kenmerk("R", { internal: true }), { pNiveau: "R", readman: true, readuse: true }),
            joinfield: "flexparentkey",
            enable_update: true
        },
        "tracking": {
            model: new model_tracking(["factuur"]),
            joinfield: "trackingrefkey"
        }
    };

    function _pre_analyze_fields(params, jsondata) /* analyseer inkomende jsondata, common voor PUT en POST */
    {
        delete jsondata.line; // factuurregelnummer niet door de gebruiker laten zetten.
    };

    function _analyze_fields(dbfields, params, jsondata) /* analyseer inkomende data, common voor PUT en POST */
    {
    };

    function _validate_fields(dbfields, params, jsondata) /* valideer dbfields, alle constraints die niet door de database worden afgevangen */
    {
      //__Log(jsondata);
      //var factuurregel_key = parseInt(jsondata.id);
    };

    function _synchronize_totals_sql(factuur_key)
    {
        // Redundante info bijwerken. Door dat hier te doen hebben we redelijk consistentie-garantie.
        var sql = " UPDATE fin_factuur ff"
                + "    SET fin_factuur_totaal = (SELECT SUM(fin_factuurregel_totaal)"
                + "                                FROM fin_factuurregel fr"
                + "                               WHERE fr.fin_factuur_key = ff.fin_factuur_key)"
                + "      , fin_factuur_totaal_btw = (SELECT SUM(fin_factuurregel_btw)"
                + "                                    FROM fin_factuurregel fr"
                + "                                   WHERE fr.fin_factuur_key = ff.fin_factuur_key)"
                + "  WHERE fin_factuur_key = " + factuur_key;
        return sql;
    };

    function _renumber_invoicelines_sql(factuur_key)
    {
        // Regels hernummeren zodat ze weer opeenvolgend zijn.
        var sql = "UPDATE fin_factuurregel"
                + "   SET fin_factuurregel_nr = ROWNUM"
                + " WHERE fin_factuur_key = " + factuur_key;
        return sql;
    };


    this.REST_GET = function _GET(params)
    {
        var scope = params.filter.scope;
        if (scope)
        {
          var autfunction = { fe: "WEB_EXTFIN", fo: "WEB_FINFOF", bo: "WEB_FINBOF" } [scope];
        }
        else
        {
          var autfunction = ["WEB_EXTFIN", "WEB_FINFOF", "WEB_FINBOF"];
          var authparamsFINFOF = user.checkAutorisation("WEB_FINFOF", true);
          var authparamsFINBOF = user.checkAutorisation("WEB_FINBOF", true);
        }
        params.authparams = user.checkAutorisation(autfunction, null, null, true); // pessimistisch

        var query = api2.sqlfields(params, this);
        var parentexists = ["f.fin_factuur_verwijder IS NULL"];

        if (scope == "fe" || (!scope && !authparamsFINFOF && !authparamsFINBOF))
        { // Frontend.
          parentexists.push("f.prs_perslid_key_user=" + user_key);
        }
        else
        {
            // TODO: disc3d conditie voor de geldendende autfunction toevoegen
        }

        if (parentexists.length)
        {
            var sqlparent = " EXISTS (SELECT 1"
                                  + "   FROM fin_factuur f"
                                  + "  WHERE f.fin_factuur_key = fin_factuurregel.fin_factuur_key"
                                  + "    AND " + parentexists.join(" AND ") + ")";
            query.wheres.push(sqlparent);
        }

        var wheres = api2.sqlfilter(params, this);
        query.wheres = query.wheres.concat(wheres);

        var sql = "SELECT " + query.selects.join(", ")
                + "  FROM " + query.tables.join(", ")
                + " WHERE " + query.wheres.join(" AND " )
                + " ORDER BY fin_factuurregel_nr";
        var json = api2.sql2json (params, sql, this);

        return json;
    };

    this.REST_PUT = function (params, jsondata, the_key) /* update invoiceline */
    {
        var finregel_key = the_key;
        _pre_analyze_fields(params, jsondata);
        var dbfields = api2.update_fields(params, this, jsondata); // Build updater
        _analyze_fields(dbfields, params, jsondata);
        _validate_fields(dbfields, params, jsondata);
        //
        var sql = "SELECT fin_factuur_key"
                + "  FROM fin_factuurregel"
                + " WHERE fin_factuurregel_key = " + finregel_key;
        var oRs = Oracle.Execute(sql);
        var fin_factuur_key = oRs("fin_factuur_key").value;
        oRs.Close();

        var fin_factuur_old = fin.factuur_info(fin_factuur_key);
        var this_fin = fin.func_enabled_factuur(fin_factuur_key);
        user.auth_required_or_abort(this_fin.canChange);  // Geen wijzigingen toestaan bij onvoldoende rechten.

        var wheres = [" fin_factuurregel_key = " + finregel_key];
        var finUpd = buildTrackingUpdate("fin_factuurregel", wheres.join(" AND " ), dbfields, { noValidateToken: true });

        var sql = "BEGIN "
                + finUpd.sql + ";"
                + _synchronize_totals_sql(fin_factuur_key) + ";"
                + "END;";
        var err = Oracle.Execute(sql, true);
        if (err.friendlyMsg)
            abort_with_warning(err.friendlyMsg);

        var finUpdTrackarray = []; // Alle tracking van elke afzondelijke regel verzamelen.
        if (finUpd.trackarray.length > 0)
        {
          if (jsondata.name != "")
            finUpdTrackarray = finUpdTrackarray.concat([jsondata.name + ": "]); // Omschrijving van de regel noteren zodat ik weet welke regel is aangepast.
          finUpdTrackarray = finUpdTrackarray.concat(finUpd.trackarray);
        }

        var fin_factuur_new = fin.factuur_info(fin_factuur_key);
        if (fin_factuur_old.fin_totaal != fin_factuur_new.fin_totaal)
          finUpdTrackarray.push(L("lcl_fin_total_sum_inBTW") + ": " + safe.curr(fin_factuur_old.fin_totaal + fin_factuur_old.fin_totaal_btw) + " => " + safe.curr(fin_factuur_new.fin_totaal + fin_factuur_new.fin_totaal_btw))
        if (fin_factuur_old.fin_totaal_btw != fin_factuur_new.fin_totaal_btw)
          finUpdTrackarray.push(L("lcl_fin_BTW_total_sum") + ": " + safe.curr(fin_factuur_old.fin_totaal_btw) + " => " + safe.curr(fin_factuur_new.fin_totaal_btw))

        var fintrack = api2.process_includes(params, this, jsondata, the_key);

        // update nog tracken
        if (fin_factuur_key > 0)
        {
          fin.trackfactuurupdate(fin_factuur_key, L("lcl_fin_is_finupdtrack").format(fin_factuur_key) + ((finUpdTrackarray.length + fintrack.length) > 0? "\n" : "") + finUpdTrackarray.concat(fintrack).join("\n"));
        };

        return { key: finregel_key };
    };

    this.REST_POST = function (params, jsondata) /* new invoiceline */
    {
        params.isNew = true;

        var trackarray  = [];
        var factuur_key = (typeof jsondata.invoice == "object" ? jsondata.invoice.id : jsondata.invoice);

        var this_fin    = fin.func_enabled_factuur(factuur_key); // Wat heb ik zoal aan rechten op deze specifieke factuur
        var auth = ( (params.filter && params.filter.api2 && params.filter.api2 == "invoices"
                                    && params.include && inArray("invoicelines",params.include)
                     )
                   ? this_fin.canWriteAny   // Als dit een include van invoices is dan alleen naa rechten kijken.
                   : this_fin.canChange     // Geen nieuwe factuurregels bij een verwerkte factuur en onvoldoende rechten.
                   );
        user.auth_required_or_abort(auth);

        _pre_analyze_fields(params, jsondata);
        var dbfields = api2.update_fields(params, this, jsondata); // Build updater
        _analyze_fields(dbfields, params, jsondata);
        _validate_fields(dbfields, params, jsondata);

        // Zet volgnummer van de nieuwe factuurregel.
        var sql = "SELECT COALESCE(MAX(fin_factuurregel_nr),0) volgnr"
                + "  FROM fin_factuurregel"
                + " WHERE fin_factuur_key = " + factuur_key;
        var oRs = Oracle.Execute(sql);
        var volgnr = oRs("volgnr").value + 1;
        oRs.Close();

        if (dbfields.fin_factuur_key)
            dbfields["fin_factuur_key"].val = factuur_key;
        else
            dbfields["invoice"] = { dbs: "fin_factuur_key",      typ: "key",    val: factuur_key };

        dbfields["id"] = { dbs: "fin_factuurregel_key", typ: "key",    seq: "fin_s_fin_factuurregel_key" };
        dbfields["line"] = { dbs: "fin_factuurregel_nr",  typ: "number", val: volgnr };
        var finIns = buildInsert("fin_factuurregel", dbfields, { noValidateToken: true });
        var factuurregel_key = finIns.sequences["fin_factuurregel_key"];

        var sql = "BEGIN "
                + finIns.sql + ";"
                + _synchronize_totals_sql(factuur_key) + ";"
                + "END;";
        var err = Oracle.Execute(sql, true);
        if (err.friendlyMsg)
            abort_with_warning(err.friendlyMsg);

        var fintrack = api2.process_includes(params, this, jsondata, factuurregel_key);

        // Tracking toevoegen.
        trackarray.push(L("lcl_fin_invoicerow_add") + ": " + safe.quoted_sql(jsondata.name) + "/" + jsondata.total);
        shared.trackaction("FINNEW", factuur_key, trackarray.join("\n"));
        //
        return { key: factuurregel_key };
    };

    this.REST_DELETE = function (params, the_key) /* delete invoiceline */
    {
        var trackarray  = [];
        var factuurregel_key = the_key;

        var sql = "SELECT fin_factuur_key"
                + "     , fin_factuurregel_omschrijving"
                + "     , fin_factuurregel_totaal"
                + "  FROM fin_factuurregel"
                + " WHERE fin_factuurregel_key = " + factuurregel_key;
        var oRs = Oracle.Execute(sql);
        var factuur_key = oRs("fin_factuur_key").value;
        var desc = oRs("fin_factuurregel_omschrijving").value;
        var total = oRs("fin_factuurregel_totaal").value;
        oRs.Close();

        var this_fin = fin.func_enabled_factuur(factuur_key);
        user.auth_required_or_abort(this_fin.canDelete);

        // Alleen bij voldoende rechten op de factuur kan een factuurregel worden verwijderd.
        fin.deleteFactuurregel(factuurregel_key);

        var sql = "BEGIN "
                + _synchronize_totals_sql(factuur_key) + ";"
                + _renumber_invoicelines_sql(factuur_key) + ";"
                + "END;"
        var err = Oracle.Execute(sql, true);
        if (err.friendlyMsg)
            abort_with_warning(err.friendlyMsg);
        else
        {
            trackarray.push(L("lcl_fin_regel_del") + ": " + safe.quoted_sql(desc) + "/" + total);
            //shared.trackaction("FINDEL", factuur_key, trackarray.join("\n")); // srtnotificatie FINDEL bestaat (nog) niet
        }
    };
}
%>
