Skip to content
Snippets Groups Projects
process.js 19.32 KiB
import("ClassificationIndicatorFieldRegistry_basic");
import("AttributeFilter_lib");
import("Attribute_lib");
import("Dependency_lib");
import("Sql_lib");
import("system.db");
import("system.neon");
import("system.text");
import("system.translate");
import("system.util");
import("system.vars");

/**
 * Methods to manage classifications.<br>
 * <b>Do not create an instance of this!</b>
 *
 * @class
 */
function ClassificationUtils() {}

/**
 * Formats the summary title for one specific group <br/>
 * e.g: "1. Target Group: 45/120 points = B"
 * so: groupName: achievedPoints/possibleMaxPoints points = gradingChar
 * 

 * @param {Number|String} pAchievedScore   <p/>Current score that is reached for a group, e.g. 45
 * @param {Number|String} pBestPossibleScore   <p/>Current score that is reached for a group, e.g. 45
 * @param {String} pGroupName               <p/>Name of the group that was passed as ID. This is used as display value and will not be translated,
 *                                          you have to pass this value already translated to the target locale. <br/>
 *                                          The reason for not loading this value based on the groupId is: better performance optimization
 * @param {Number|String} pGrading          <p/>Current score that is reached for a group, e.g. 45
 * @return {String}                         <p/>formated and translated title, e.g.: "1. Target Group: 45/120 points = B"
 */
ClassificationUtils.formatDisplaySummaryForGroup = function(pAchievedScore, pBestPossibleScore, pGroupName, pGrading) 
{
    pCurrentScore = text.formatDouble(pAchievedScore, "#");
    pBestPossibleScore = text.formatDouble(pBestPossibleScore, "#");
    var res = translate.withArguments("%0: %1/%2 points = %3", [pGroupName, pAchievedScore, pBestPossibleScore, pGrading]);
    return res;
};

/**
 * Get all possible groupnames for a classificationtype.<br>
 * Either as [["group", "group"]] (for the possible items process).
 * Or as [["group"]].<br>
 * 
 * @param {String} pObjectType                      <p>
 *                                                  The object type.<br>
 */
ClassificationUtils.getAllGroups = function(pObjectType)
{
    var sql = new SqlBuilder()
                    .select(["distinct CLASSIFICATIONGROUP.CLASSIFICATIONGROUPID", "CLASSIFICATIONGROUP.TITLE"])
                                .from("CLASSIFICATIONGROUP")
                                .join("CLASSIFICATIONTYPE", "CLASSIFICATIONTYPE.CLASSIFICATIONGROUP_ID = CLASSIFICATIONGROUP.CLASSIFICATIONGROUPID")
                                .where("CLASSIFICATIONTYPE.OBJECT_TYPE", pObjectType)
                                .orderBy("CLASSIFICATIONGROUP.TITLE");
    
    return sql.table();
}


/**
 * Set a value for a classification type
 * 
 * @param {String} pObjectType 
 * @param {String} pObjectId
 * @param {String} pClassificationTypeId
 * @param {String} pClassificationScoreId 
 */
ClassificationUtils.setClassificationValue = function(pObjectType, pObjectId, pClassificationTypeId, pClassificationScoreId)
{   
    var newId = util.getNewUUID();
    db.insertData("CLASSIFICATION", ["CLASSIFICATIONID", "OBJECT_TYPE", "OBJECT_ROWID", "CLASSIFICATIONTYPE_ID", "VALUE"], null, [
        newId,
        pObjectType,
        pObjectId,
        pClassificationTypeId,
        pClassificationScoreId,
    ]);
    newWhere("CLASSIFICATIONSTORAGE.OBJECT_ROWID", pObjectId).updateData(true, "CLASSIFICATIONSTORAGE", ["OUTDATED"], null, 1)
}


/**
 * Gets the classificationGradingTable for a classificationGroup as Array.<br>
 * ordered by the MinPercent       descending              <br>
 * 
 * @param {String} pClassificationGroupId                   <p>
 *                                                          The classificationgroup you want the grading for <br>
 *                                                          
* @return {Array}                                           <p>
*                                                           The resulting gradingTable. <br>
 */
ClassificationUtils.getGradingTableByGroupId = function(pClassificationGroupId)
{

    var classificationGroupId = pClassificationGroupId;
    var gradingObject = {};
    var gradingTable = newSelect("CLASSIFICATIONGRADING.CLASSIFICATIONGRADINGID, CLASSIFICATIONGRADING.MINPERCENT, CLASSIFICATIONGRADING.GRADING")
                                        .from("CLASSIFICATIONGRADING")
                                        .where("CLASSIFICATIONGRADING.CLASSIFICATIONGROUP_ID", classificationGroupId)
                                        .orderBy("CLASSIFICATIONGRADING.MINPERCENT asc")
                                        .table()
                                        
    for (let i = 0; i < gradingTable.length; i++) 
    {
        if (gradingObject[classificationGroupId] == undefined)
        {
            gradingObject[classificationGroupId] = [];
        }
        
        gradingObject[classificationGroupId].push([gradingTable[i][1], gradingTable[i][2]]);
    }
    return gradingObject;
}

/**
 * Gets the classificationgroupId of a classification type as String.<br>
 * 
 * @param {String} pClassificationType                   <p>
 *                                                          The classification-type (usage)<br>
 *                                                          (e.g. the key id from keyword ClassificationType)
* @return {String}                                          <p>
*                                                           The classificationgroupId of the chosen classificationtype<br>
 */
ClassificationUtils.getClassificationGroup = function(pClassificationType)
{
    var classificationGroupId = newSelect("CLASSIFICATIONTYPE.CLASSIFICATIONGROUP_ID")
                                        .from("CLASSIFICATIONTYPE")
                                        .where("CLASSIFICATIONTYPE.CLASSIFICATIONTYPEID", pClassificationType)
                                        .groupBy("CLASSIFICATIONGROUP_ID")
                                        .cell();
    return classificationGroupId;                                        
}

/**
 * Gets the classificationTypeIds of a classification group.<br>
 * 
 * @param {String} pClassificationGroupId                   <p>
 *                                                          The classificationGroupId<br>
* @return {Array}                                          <p>
*                                                           The classificationTypeIds of the chosen pClassificationGroupId<br>
 */
ClassificationUtils.getClassificationTypesOfGroup = function(pClassificationGroupId)
{
    var classificationTypeIds = newSelect("CLASSIFICATIONTYPE.CLASSIFICATIONTYPEID")
                                        .from("CLASSIFICATIONTYPE")
                                        .where("CLASSIFICATIONTYPE.CLASSIFICATIONGROUP_ID", pClassificationGroupId)
                                        .arrayRow();
    return classificationTypeIds;                                        
}

/**
 * Get all classification type ids for a score using it's unique classification score id.<br>
 * 
 * @param {String} pClassificationScoreId                   <p>
 *                                                          The classification score id 
* @return {String}                                          <p>
*                                                           The resulting classification type.<br>
 */
ClassificationUtils.getClassificationType = function(pClassificationScoreId)
{
    var classificationType = newSelect("CLASSIFICATIONSCORE.CLASSIFICATIONTYPE_ID")
                                        .from("CLASSIFICATIONSCORE")
                                        .where("CLASSIFICATIONSCORE.CLASSIFICATIONSCOREID", pClassificationScoreId)
                                        .arrayColumn();
    return classificationType;
}

/**
 * Gets the Grading of a score for a group using an object that contains all the gradings and the greatest possible score.<br>
 * 
 * @param {String} pGradingObject                          <p>
 *                                                          The classification grading object 
 * @param {String} pGroupId                                <p>
 *                                                          The classification group id 
 * @param {String} pScore                                  <p>
 *                                                          The achieved score 
 * @param {String} pMaxPossibleScore                       <p>
 *                                                         The greatest possible score
* @return {String}                                         <p>
*                                                          The resulting classification grading.<br>
 */
ClassificationUtils.getGradingFromObject = function(pGradingObject, pGroupId, pScore, pMaxPossibleScore)
{
    var gradingObject = pGradingObject;
    if (gradingObject == null)
    {
        gradingObject = ClassificationUtils.getGradingTableByGroupId(pGroupId);
    }
    
    var groupId = pGroupId;
    var scorePercent = pScore/(pMaxPossibleScore/100); //the score in percent in relation to the maxScore
    var grading = "-";
    for (var index in gradingObject[groupId])
    {
        if (Number(scorePercent) >= Number(gradingObject[groupId][index][0]) && scorePercent != 0)
        {
            grading = gradingObject[groupId][index][1];
        }
    }
    return grading;
}

/**
 * This function is used in the workflowExtention_serverProcess.
 * It checks whether or not the change has any influence on stored classificationStorage datasets
 * by checking if the entity itself is classificationRelevant or the entity has an relation with an classificationRelevant entity
 * <p/>
 * For further context behind why we use this outdated flag see also the documentation properties of "updateClassifications_serverProcess" and the classification_entities
 * 
 * 
 * @param {Array} pTargetIds                    <p/> TargetIds
 * @param {String} pEntityName                  <p/> Entity name
 * @param {Object} pRowData                     <p/> row data
 * @param {Object} pChangedRows                 <p/> changed rows
 *                                      
 * @return {void}
 * @static 
 */
ClassificationUtils.setClassificationStorageDatasetsOutdated = function (pTargetIds, pEntityName, pRowData, pChangedRows)
{
    var relevantForClassification = false;
    var classificationStorageIds = [];
    var entityName = pEntityName;

    if (entityName == "Organisation_entity" || entityName == "Salesproject_entity")
    {
        relevantForClassification = true;
        classificationStorageIds.push(pTargetIds);
    }
    if (Dependency.getDependency(entityName).includes("Organisation_entity"))
    {
        relevantForClassification = true;
        classificationStorageIds.push(Dependency.mapping()[entityName]["Organisation_entity"].getUIDsfn(pRowData, pChangedRows));
    }
    if (Dependency.getDependency(entityName).includes("Salesproject_entity"))
    {
        relevantForClassification = true;
        classificationStorageIds.push(Dependency.mapping()[entityName]["Salesproject_entity"].getUIDsfn(pRowData, pChangedRows));
    }

//we have to remove empty arrays, since otherwise it would lead to an error when trying to use the condition for updating
//empty arrays occur when e.g. inserting something that doesn't have any classificationStorageIds even though it is classificationrelevant
    for (let i = 0; i < classificationStorageIds.length; i++)
    {
        if (classificationStorageIds[i][0] == undefined)
        {
            classificationStorageIds.splice(i, 1);
            i--;
        }
    }

    //set outdated flag for the classificationStorage datasets
    if (relevantForClassification && classificationStorageIds.length > 0) // also check for the classificationStorageIds.length since it could be empty
    {
        for (let i = 0; i < classificationStorageIds.length; i++) 
        {
            var cond = newWhere("CLASSIFICATIONSTORAGE.OBJECT_ROWID", classificationStorageIds[i], SqlBuilder.IN());
            cond.updateData(true, "CLASSIFICATIONSTORAGE", ["OUTDATED"], null, [1]);
        }
    }
};

/**
 * This function is used in the FIELD.dropDownProcess in ClassificationAdmin.
 * Concats and reruns the entityfields specified in $ClassificationIndicatorRegistry.getEntityNumberFields(), $ClassificationIndicatorRegistry.getEntityDropDownFields()
 * <p/>
 * @param {Object} pObjectType                 <p/> object type we want the fields for
 *                                      
 * @return {Array} Array with array of [[value], [displayvalue]] (like in a dropdownproess)
 */
ClassificationUtils.getEntityFields = function (pObjectType)
{
    var entityNumberFields = $ClassificationIndicatorRegistry.getEntityNumberFields(pObjectType);
    var entityDropDownFields = $ClassificationIndicatorRegistry.getEntityDropDownFields(pObjectType);
    var res = entityNumberFields.concat(entityDropDownFields);
    
    return res;
};

/**
 * Returns the entity dropdown fields of pObjectType
 * <p/>
 * @param {Array[][]} pFields           <p/> two dimensional Array with key and displayvalue
 * @param {String} pKey                 <p/> key we want the displayvalue for
 * 
 * @return {String} displayvalue, empty string if pKey isn't included in pFields
 */
ClassificationUtils.getFieldDisplayValue = function (pFields, pKey)
{
    for (let i = 0; i < pFields.length; i++)
    {
        if (pFields[i][0] == pKey)
        {
            return pFields[i][1];
        }
    }
    return "";
}

/**
 * Returns the attribute dropdown, number and integer fields of pObjectType using AttributeFilterExtensionMaker.makeFilterFields(pObjectType) and checking for their contentType
 * <p/>
 * @param {Object} pObjectType                 <p/> object type we want the Attributes for
 *                                      
 * @return {Array} Array with Objects for each attribute (see also AttributeFilterExtensionMaker.makeFilterFields())
 */
ClassificationUtils.getEntityAttributes = function (pObjectType)
{
    let attributeFields = JSON.parse(AttributeFilterExtensionMaker.makeFilterFields(pObjectType));
    for (i = 0; i < attributeFields.length; i++)
    {
        if (!(attributeFields[i]["contentType"] == AttributeTypes.TEXT() && attributeFields[i]["hasDropDownValues"] === true)
        && !(attributeFields[i]["contentType"] == AttributeTypes.BOOLEAN())
        && !(attributeFields[i]["contentType"] == AttributeTypes.COMBO())
        && !(attributeFields[i]["contentType"] == AttributeTypes.KEYWORD())
        && !(attributeFields[i]["contentType"] == AttributeTypes.NUMBER())
        && !(attributeFields[i]["contentType"] == AttributeTypes.INTEGER()))
        {
            attributeFields.splice(i, 1);
            i--;
        }
    }
    return attributeFields;
};


/**
 * This function is used in the FIELD.dropDownProcess in ClassificationAdmin.
 * Turns the object array that ClassificationUtils.getEntityAttributes() returns into a useable twodimensional Array
 * <p/>
 * @param {Object} pAttributeFilterFields                 <p/> object you get from ClassificationUtils.getEntityAttributes()
 *                                      
 * @return {Array} Array with array of [[value], [displayvalue]] (like in a dropdownproess)
 */
ClassificationUtils.getEntityAttributesArray = function (pAttributeFilterFields)
{
    var attributeFields = pAttributeFilterFields;
    var resArray = [];
    for (i = 0; i < attributeFields.length; i++)
    {
        resArray.push([attributeFields[i]["name"], attributeFields[i]["title"]]);
    }

    return resArray;
};
/**
 * This function is used in the stateprocess of multiple fields of classificationScore_entity
 * We check if the pFieldTypes includes the one we have in pClassificationTypeInfo and set the recordstate according to the current pRecordState
 * <p/>
 * @param {String} pRecordState                 <p/> the record state as in the $sys.recordState-variable; e.g. neon.OPERATINGSTATE_NEW
 * 
 * @param {Array} pFieldTypes                   <p/> the field types
 * 
 * @param {Object} pClassificationTypeInfo      <p/> classification type info (object with field, fieldType and IndicatorType) (JSON.parse(vars.getString("$param.ClassificationTypeInfo_param")))
 * 
 * @param {Array} [pIndicatorTypes]             <p/> the indicator types (see also $ClassificationIndicatorTypes)
 * 
 * @param {Object} [pFilterValue]               <p/> filter value (only needed for displayValueForTitleField)
 *                                      
 * @return {String} resulting recordState<br/>
 */
ClassificationUtils.getClassificationScoreStateProcess = function (pRecordState, pFieldTypes, pClassificationTypeInfo, pIndicatorTypes, pFilterValue)
{
    var state = neon.COMPONENTSTATE_INVISIBLE;
    if (!pFieldTypes)//special case for displayValueForTitleField
    {
        state = neon.COMPONENTSTATE_INVISIBLE;
        if (pRecordState == neon.OPERATINGSTATE_VIEW
            || ((pRecordState == neon.OPERATINGSTATE_NEW || pRecordState == neon.OPERATINGSTATE_EDIT)
                && pFilterValue && JSON.parse(filterValue)["filter"]["childs"].length > 0))
        {
            state = neon.COMPONENTSTATE_READONLY;
        }
        return state;
    }

    var fieldType = pClassificationTypeInfo["fieldType"];
    var indicatorType = pClassificationTypeInfo["indicatorType"];
    
    if (pRecordState == neon.OPERATINGSTATE_NEW || vars.get("$sys.recordstate") == neon.OPERATINGSTATE_EDIT)
    {
        if (pFieldTypes.includes(fieldType) && (!pIndicatorTypes || pIndicatorTypes.length == 0 || pIndicatorTypes.includes(indicatorType)))
        {
            state = neon.COMPONENTSTATE_EDITABLE;
        }
    }
    
    return state;
};

/*this is right now (2020-08-15) the only way to get something like a constant with 
 - a prober name
 - autocomplete support within the ADITO Designer
 - and proper packageing all constants together
This may change in the future, if there is something better feel free to improve this */
function $ClassificationRecordCategories(){}
$ClassificationRecordCategories.CLASSIFICATION_OBJECT_TYPE =             function(){return "ClassificationObject_Type"};
$ClassificationRecordCategories.CLASSIFICATION_CLASSIFICATION_GROUP =    function(){return "ClassificationGroup"};
$ClassificationRecordCategories.CLASSIFICATION_CLASSIFICATION_TYPE =     function(){return "ClassificationType"};
$ClassificationRecordCategories.CLASSIFICATION_GROUP_EXISTS =            function(){return "ClassificationGroupExists"};
$ClassificationRecordCategories.CLASSIFICATION_GROUP_DOESNT_EXIST =      function(){return "ClassificationGroupDoesntExist"};

function $ClassificationPlaceholder(){}
$ClassificationPlaceholder.TOPSECRETPLACEHOLDER =                        function(){return "T0PS3CR3TPL4CEH0LD3R"};

function $ClassificationFieldTypes(){}
$ClassificationFieldTypes.NUMBER =                                       function(){return "number"};
$ClassificationFieldTypes.INTEGER =                                      function(){return "integer"};
$ClassificationFieldTypes.DROPDOWN =                                     function(){return "dropDown"};
$ClassificationFieldTypes.DATE =                                         function(){return "date"};

function $ClassificationIndicatorTypes(){}
$ClassificationIndicatorTypes.ENTITYFIELD =                              function(){return "entityField"};
$ClassificationIndicatorTypes.ATTRIBUTE =                                function(){return "attribute"};
$ClassificationIndicatorTypes.COMPLEX =                                  function(){return "complex"};