Skip to content
Snippets Groups Projects
process.js 13.52 KiB
import("system.datetime");
import("system.logging");
import("KeywordData_lib");
import("Sql_lib");
import("system.neon");
import("system.vars");
import("system.util");
import("system.translate");
import("system.db");
import("system.eMath");
import("system.question");
import("Util_lib");
import("Keyword_lib");
import("system.neonTools");
import("KeywordRegistry_basic");

/**
 * Methods used by the Salesproject.
 * Do not create an instance of this!
 * 
 * @class
 */
function Salesproject() {}

/**
 * Delivers the next valid project number (has to be unique)
 * 
 * @result {String} next valid project number
 */
Salesproject.getNextProjectNumber = function() {
    return NumberSequencingUtils.getNextUniqueNumber("PROJECTCODE", "SALESPROJECT");
}

/**
 * Checks if the passed project number is valid (has to be unique)
 * 
 * @param {String} projectNumber project number to check
 * 
 * @result {Boolean} passed number is valid
 */
Salesproject.validateProjectNumber = function(projectNumber) {
    return NumberSequencingUtils.validateUniqueNumber(projectNumber, "PROJECTCODE", "SALESPROJECT");
}

/**
 * Insert a new milestone.
 * 
 * @param {String} salesprojectId of the salesproject
 * @param {Integer} type can be any value of the keyword SALESPROJECT.MILESTONE.KIND
 * @param {Integer} value value of the phase or state
 * @param {Boolean} [notifyForecast=false] if true, notify user to update the forecast
 * 
 * @result {Boolean} true if inserted, else false
 */
Salesproject.insertMilestone = function(salesprojectId, type, value, notifyForecast) {
    if (KeywordUtils.exists(value, type)) {
        var id = newSelect("SALESPROJECT_MILESTONE.SALESPROJECT_MILESTONEID")
        .from("SALESPROJECT_MILESTONE")
        .where("SALESPROJECT_MILESTONE.SALESPROJECT_ID", salesprojectId)
        .and("SALESPROJECT_MILESTONE.KIND", type)
        .and("SALESPROJECT_MILESTONE.DATE_END is null")
        .cell();       
        
        newWhere("SALESPROJECT_MILESTONE.SALESPROJECT_ID", salesprojectId)
        .and("SALESPROJECT_MILESTONE.KIND", type)
        .and("SALESPROJECT_MILESTONE.DATE_END is null")
        .updateData(true, "SALESPROJECT_MILESTONE", ["DATE_END"], null, [vars.get("$sys.date")]);
        
        db.insertData(
            "SALESPROJECT_MILESTONE",
            ["SALESPROJECT_MILESTONEID", "SALESPROJECT_ID", "KIND", "MILESTONEVALUE", "DATE_START", "PARENT_ID"],
            null,
            [util.getNewUUID(), salesprojectId, type, value, vars.get("$sys.date"), id]);
        if (notifyForecast) {
            Salesproject.notifyToUpdateForecast()
        }
        return true;
    }
    return false;
}

/**
 * Notify the user to update the forecast
 */
Salesproject.notifyToUpdateForecast = function() {
    if (vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW)
    {
        // TODO: workflows
    }
}

/**
 * get the title of a salesproject by id
 * @param {String} pSalesProjectId
 * <br>
 * @return {String} title of the salesproject
 */
Salesproject.getSalesProjectTitleById = function(pSalesProjectId)
{
    return newSelect("PROJECTTITLE")
    .from("SALESPROJECT")
    .where("SALESPROJECT.SALESPROJECTID", pSalesProjectId)
    .cell();
}

/**
 * Create a new Salesproject and open the Salesproject context in NEW-mode
 */
Salesproject.createNewSalesproject= function(pRelationId)
{
    var params = {};
    
    if (pRelationId)
        params["ContactId_param"] = pRelationId;
    
    neon.openContext("Salesproject", null, null, neon.OPERATINGSTATE_NEW, params);
}

/**
 * Create a new Salesproject from a organisation
 */
Salesproject.createNewSalesprojectFromOrg = function(pRelationId, pSalesprojectName)
{
    var uid = util.getNewUUID();
    db.insertData(
        "SALESPROJECT",
        ["SALESPROJECTID", "CONTACT_ID", "PROJECTTITLE", "PROJECTCODE", "STARTDATE", "STATUS", "PHASE"],
        null,
        [uid, pRelationId, pSalesprojectName, Salesproject.getNextProjectNumber(), 
        vars.get("$sys.date"), $KeywordRegistry.salesprojectState$open(), $KeywordRegistry.salesprojectPhase$nqc()]); 
    return uid;        
                  
}

/**
 * Insert a new touchpoint for the salesproject 
 */
Salesproject.insertTouchPoint = function(pSalesprojectId, pTouchPoint, pInfo)
{
    var uid = util.getNewUUID();
    db.insertData(
        "SALESPROJECT_TOUCHPOINT",
        ["SALESPROJECT_TOUCHPOINTID", "SALESPROJECT_ID", "ENTRYDATE", "INFO", "TOUCHPOINT"],
        null,
        [uid, pSalesprojectId, vars.get("$sys.date"), pInfo, pTouchPoint]); 
    return uid;                         
}

/**
 * Set a new phase for the salesproject 
 */
Salesproject.updateSalesprojectPhase = function(pSalesprojectId, pPhase)
{
    newWhere("SALESPROJECT.SALESPROJECTID", pSalesprojectId)
    .updateData(true, "SALESPROJECT", ["PHASE"], null, [pPhase]);                      
}

/**
 * Methods used by the SalesprojectConversionRate.
 * Do not create an instance of this!
 * 
 * @class
 */
function SalesprojectConversionRate() {
    this.MILESTONES = {};
    this.isGrouping = null;
}

/**
 * Returns the Mapping of the Fields and FilterExtention for the grouping 
 * 
 * @param {Boolean} pRightOneTables if true you get the Mappings with the actual Tablenames 
 * 
 * @return {Object}
 */
SalesprojectConversionRate.groupMapping = function (pRightOneTables) 
{
    let sqlHelper = new SqlMaskingUtils();
    if (pRightOneTables)
    {
        return {
            "AB_KEYWORD_ENTRYID_KEYID": "AB_KEYWORD_ENTRY.KEYID", 
            "#EXTENSION.Year.Year#NUMBER" : sqlHelper.yearFromDate("SALESPROJECT_MILESTONE.DATE_START"), 
            "#EXTENSION.Month.Month#NUMBER" : sqlHelper.monthFromDate("SALESPROJECT_MILESTONE.DATE_START")
        }
    }
    
    let dateStartYear = sqlHelper.yearFromDate("SALESPROJECT_MILESTONE.DATE_START");
    let dateStartMonth = sqlHelper.monthFromDate("SALESPROJECT_MILESTONE.DATE_START");
    
    return {
        "AB_KEYWORD_ENTRYID_KEYID": ["AB_KEYWORD_ENTRY.KEYID", "AB_KEYWORD_ENTRY.TITLE", "AB_KEYWORD_ENTRY.SORTING"], 
        "#EXTENSION.Year.Year#NUMBER" : [dateStartYear, dateStartYear, dateStartYear], 
        "#EXTENSION.Month.Month#NUMBER" : [dateStartMonth, dateStartMonth, dateStartMonth]
    }
}

/**
 * Returns the FieldMappings for the FilterExtentions for the giffen Table
 * if there is a TableAlias used as pField there have to be a pTable
 * 
 * @param {String} pField the filtered Feld in the format Table.Column or TableAlias.Column
 * @param {Boolean} pIsAll if true you get the Mapping for all Fields
 * @param {Integer} pTable the Table of the used TableAlias
 * 
 * @return {Object} FieldMapping
 */
SalesprojectConversionRate.filterMapping = function(pField, pIsAll, pTable)
{
    let sqlHelper = new SqlMaskingUtils();
    if (pField == null){
        return {
        
            "AB_KEYWORD_ENTRYID_KEYID": "AB_KEYWORD_ENTRY.KEYID", 
            "#EXTENSION.Year.Year#NUMBER" : null, 
            "#EXTENSION.Month.Month#NUMBER" : null,
            "#EXTENSION.DATE_START.DATE_START#DATE" : null
        }
    } else {
        let mapping = {
            "AB_KEYWORD_ENTRYID_KEYID": null, 
            "#EXTENSION.Year.Year#NUMBER" : function (pValue, pOperator) {
                return _getFilterByFunction(pValue, pOperator,  sqlHelper.yearFromDate(pField));
            }
            , 
            "#EXTENSION.Month.Month#NUMBER" : function (pValue, pOperator) {
                return _getFilterByFunction(pValue, pOperator, sqlHelper.monthFromDate(pField));
            }
            ,
            "#EXTENSION.DATE_START.DATE_START#DATE" : pField
        };
        if (pIsAll){
            mapping.AB_KEYWORD_ENTRYID_KEYID = "AB_KEYWORD_ENTRY.KEYID";
        }
        
        if (pTable) {
            let arr = pField.split(".");
            mapping["#EXTENSION.DATE_START.DATE_START#DATE"] = [pTable, arr[1], arr[0]];
        }
        
        return mapping;
                
    }
    
    function _getFilterByFunction (pValue, pOperator, pAggregate) {
        let sqlCond = "" + pAggregate;

        if (pOperator == "EQUAL")
            sqlCond += " = " + pValue + "";
        else if (pOperator == "NOT_EQUAL")
            sqlCond += " <> " + pValue + ""; 
        else
            sqlCond = "1=1";

        return  sqlCond;
    }
    
}

/**
 * Returns the Phases Keywordkeys
 * 
 * @return {Array} Phases Keywordkeys
 */
SalesprojectConversionRate.prototype.PHASE = function () {
    return KeywordData.getSimpleData($KeywordRegistry.salesprojectPhase()).map(function (r) {
        return r[0];
    });
}

/**
 * Add Milestones to the Phases of the given Grouping. 
 * The Milestone is adding to the given and overlying Phases.
 * 
 * @param {String} [pSalesprojectID] the ID of the Salesproject
 * @param {String} [pPhase] the phase of the milestone
 * @param {String} [pGrouping] the grouping Field
 */
SalesprojectConversionRate.prototype.insertMilestone = function (pSalesprojectID, pPhase, pGrouping) {
    let logDetail = ["SALESPROJECT_MILESTONEID: " + pSalesprojectID, "PHASE: " + pPhase, "GROUPING: " + pGrouping]
    let indexPhase = this.PHASE().indexOf(pPhase)
    if (indexPhase > -1) {
        let tempPhases;
        if (pGrouping)
        {
            if ((!this.isGrouping) && this.isGrouping != null){
                logging.log(translate.text("The grouping is not active, but there is one given!"), logging.ERROR, logDetail);
                return;
            }
            if (!this.MILESTONES[pGrouping])
                this.MILESTONES[pGrouping] = {};
            this.isGrouping = true;
            tempPhases = this.MILESTONES[pGrouping];
        }
        else if (this.isGrouping && this.isGrouping != null)
        {
            logging.log(translate.text("The grouping is active, but there is no one given!"), logging.ERROR, logDetail);
            return;
        }
        else 
        {
            tempPhases = this.MILESTONES;
            this.isGrouping = false;
        }
                
            
        if (!tempPhases[pPhase])
        {
            tempPhases[pPhase] = {};
            tempPhases[pPhase].size = 0;
        } 
            
        if (!tempPhases[pPhase][pSalesprojectID])
        {
            tempPhases[pPhase][pSalesprojectID] = true;
            tempPhases[pPhase].size++;
        }
            
        if (indexPhase - 1 != -1)
            this.insertMilestone(pSalesprojectID, this.PHASE()[indexPhase - 1], pGrouping);
    }
    else 
    {
        logging.log(translate.withArguments("The given Phase \"%0\" can not be found.", [pPhase]), logging.ERROR, logDetail);
    }
}

/**
 * Calculates the Conversion Rate for evry grouping field
 * 
 * @param {Array} [pFilter] the ids of the phases, which has to be filtered
 * 
 */
SalesprojectConversionRate.prototype.getConversionRates = function (pFilter) {
    if (this.isGrouping == null)
        logging.log(translate.text("You have to use the insertMilestone Function before."), logging.ERROR);
    else if (this.isGrouping)
    {
        let groupingResults = [];
        Object.keys(this.MILESTONES).forEach(function (grouping) {
            let count = 0;
            let sum = 0.0;
            let sumMilestones = 0;
            this._getConversionRatesofPhases(this.MILESTONES[grouping], pFilter).forEach(function (phase) {
                sum += phase[3];
                sumMilestones += phase[0]
                count++;
            }, this);
            if (sumMilestones != 0)
                groupingResults.push(["" + sumMilestones, grouping, this._getTitleOfKey(grouping, true), (sum / count)])
        }, this);
        return groupingResults
    }
    else
    {
        return this._getConversionRatesofPhases(this.MILESTONES, pFilter);
    }
    return [];
}

/**
 * Calculates the Conversion Rate for the phases
 * 
 * @param {Array} [pPhases] the phases of the current grouping
 * @param {Array} [pFilter] the ids of the phases, which has to be filtered
 * 
 */
SalesprojectConversionRate.prototype._getConversionRatesofPhases = function (pPhases, pFilter) {
    let results = [];
    this._addToResult(pPhases[this.PHASE()[0]].size, this.PHASE()[0], -1,  results, pFilter);
    for (let i = 1; i < Object.keys(pPhases).length ;i++)
    {
        this._addToResult(pPhases[this.PHASE()[i]].size, this.PHASE()[i], pPhases[this.PHASE()[i-1]].size,  results, pFilter);
    }
    return results;
}
    
/**
 * Adds the Values to the result array
 * 
 * @param {Array} [pCount] the count of the phase
 * @param {Array} [pId] the id of the phase
 * @param {Array} [pPreCount] the count of the previous phase
 * @param {Array} [pResult] the array into which the data will be added
 * @param {Array} [pFilter] the ids of the phases, which has to be filtered
 */
SalesprojectConversionRate.prototype._addToResult = function (pCount, pId, pPreCount, pResult, pFilter){
    if ((pFilter && pFilter.indexOf(pId)> -1) || !pFilter)
        // COUNT, ID, TITLE, CONVERSION_RATE
        pResult.push([this.isGrouping ? pCount : ("" + pCount), pId, this._getTitleOfKey(pId), pPreCount == -1 ? 0 : (pCount /pPreCount)]);
}
   
/**
 * gets the title of the key
 * @param {Array} [pKey] the key, which has to translate
 * @param {Array} [pIsGrouping] is this title of a grouping
 */
SalesprojectConversionRate.prototype._getTitleOfKey = function (pKey, pIsGrouping) {
    if (pIsGrouping)
    {
        if (pKey <= 12)
        {
            // When convert the Number of the Month to the Month name it doesn't matter which Year is used, so here is the Year 2020 hard-coded.
            let monthDate = new Date(2020, parseInt(pKey)-1);
            return translate.text(datetime.toDate(monthDate.getTime(), "MMMM", "UTC"));
        }
    }
    else
        return KeywordUtils.getViewValue($KeywordRegistry.salesprojectPhase(),pKey);
        
    return pKey;
}