Skip to content
Snippets Groups Projects
process.js 28.25 KiB
import("system.logging");
import("system.entities");
import("system.tools");
import("system.neon");
import("system.db");
import("system.translate");
import("system.project");
import("system.vars");
import("system.SQLTYPES");
import("Keyword_lib");
import("Sql_lib");
import("Proto_lib");
import("Contact_lib");
import("KeywordRegistry_basic");

/**
 * Methods to manage contexts.
 * Do not create an instance of this!
 *
 * @class
 */
function ContextUtils() {}

/**
 * Get the id of the current context
 * TODO: use a UUID of the current context which doesn't change
 *
 * @return {String} Id of the current context
 */
ContextUtils.getCurrentContextId = function()
{
   return vars.getString("$sys.currentcontextname");
}

ContextUtils.getTitle = function(pContextId)
{
    return project.getDataModel(project.DATAMODEL_KIND_CONTEXT, pContextId)[1];
}

ContextUtils.getIcon = function(pContextId)
{
    return project.getDataModel(project.DATAMODEL_KIND_CONTEXT, pContextId)[5];
}

/**
 * TODO: use System function. Currently the Name is also the id.
 * Returns the Name of a context by the Id
 *
 * @param {String} pContextId the id of a context
 * @return {String} Name of the current context
 */
ContextUtils.getContextName = function(pContextId)
{
    // TODO: currently the Id is the context name. This will be changed maybe
    return pContextId;
}

/**
 * Returns the Name of the correct Consumer or null
 *
 * @param {String} pContextId the id of a context
 * @return {String|null} Name of the correct Consumer
 */
ContextUtils.getContextConsumer = function(pContextId)
{
    // TODO: is there a better solution without a swiutch case? maybe metadata of context / entity
    switch(pContextId)
    {
        case ContextUtils.getContextName("Organisation"):
            return "Organisations";
        case ContextUtils.getContextName("Person"):
            return "Persons";
        case ContextUtils.getContextName("Offer"):
            return "Offers";
        case ContextUtils.getContextName("Order"):
            return "Orders";
        case ContextUtils.getContextName("Product"):
            return "Products";
        case ContextUtils.getContextName("Contract"):
            return "Contracts";
        case ContextUtils.getContextName("Salesproject"):
            return "Salesprojects";
        case ContextUtils.getContextName("Campaign"):
            return "Campaigns";
        case ContextUtils.getContextName("CampaignStep"):
            return "CampaignSteps";
        case ContextUtils.getContextName("PrivatePerson"):
            return "PrivatePersons";
        default:
            return "NO_CONSUMER_DEFINED_IN_CONTEXT_LIB_GETCONTEXTCONSUMER";
    }
}

/**
 * loads the contenttitle by using entities.getRow
 * @param {String} pEntity The entity name you want to load the title for
 * @param {String} pUid the uid for which to load the title
 * 
 * @return the #CONTENTTITLE or ""
 */
ContextUtils.loadContentTitle = function(pEntity, pUid)
{    
    if (!pUid)
    {
        return "";
    }
    
    var conf = entities.createConfigForLoadingRows()
                        .entity(pEntity)
                        .uid(pUid)
                        .fields(["#CONTENTTITLE"]);

    if (entities.getRowCount(conf) > 0)
    {
        return entities.getRow(conf)["#CONTENTTITLE"];
    }
     
    return "";
}

/**
 *
 * @param {Boolean} [pFilter=false] filter only for contexts which have a mapping in ContextUtils.getSelectMap 
 * @param {String[]} [pBlacklist] contextIds that shall not be included (so this is a additional filter to the pFilter param)
 * @param {Boolean} [pInvertBlacklist=false] decides whether the items in pBlacklist are excluded (false) or
 *                      everything that is NOT in pBlacklist is excluded (true) 
 *                      (-> if it is a whitelist or blacklist)
 *
 * @return {String[][]} the contexts [[contextId, contextName, contextTitle], [... ], ...]
 */
ContextUtils.getContexts = function(pFilter, pBlacklist, pInvertBlacklist)
{
    if (pFilter == undefined)
        pFilter = false;
    if (pInvertBlacklist == undefined)
        pInvertBlacklist = false;

    var contexts = project.getDataModels(project.DATAMODEL_KIND_CONTEXT);

    if (pFilter)
    {
        contexts = contexts.filter(function(pContext) {
            if (pBlacklist && pBlacklist.indexOf(pContext[0]) > -1 != pInvertBlacklist)
                return false;
            // filter only contexts which have defined mappings in Context_lib
            return ContextUtils.getSelectMap ()[pContext[0]] != undefined;
        });
    }
    else if (pBlacklist)
    {
        contexts = contexts.filter(function(pContext) {
            if (pBlacklist && pBlacklist.indexOf(pContext[0]) > -1 != pInvertBlacklist)
                return false;
            return true;
        });
    }

    return contexts.map(ContextUtils._contextDataMapping).sort(function(pContext1, pContext2)
        {
            // sort after ContextTitle
            if (pContext1[2] > pContext2[2])
                return 1;

            if (pContext1[2] < pContext2[2])
                return -1;

            return 0;
        });
}

/**
 * get the data of a context
 *
 * @param {String} pContextId the id of the context
 *
 * @return {String[]} the contextdata [contextId, contextName, contextTitle]
 */
ContextUtils.getContext = function(pContextId)
{
    return ContextUtils._contextDataMapping(project.getDataModel(project.DATAMODEL_KIND_CONTEXT, pContextId));
}

/**
 * map the contextData from the system.project-lib to [contextId, contextName, contextTitle]
 *
 * @param {String[]} pContext the data of a context (e.g. from project.getDataModel())
 *
 * @return {String[]} the contextdata [contextId, contextName, contextTitle]
 * @ignore
 */
ContextUtils._contextDataMapping = function(pContext)
{
    var contextName = ContextUtils.getContextName(pContext[0]);

    return [pContext[0], contextName, (pContext[1] ? pContext[1] : contextName)];
}

/**
 * represents a single context selection for one context
 * this is usefull for objectlinks and 360° definition
 * most properties are read only and can only be written with a setter
 * 
 * @param {String} [pTableName] presets the matching property of the object
 * @param {String} [pIdField] presets the matching property of the object
 * @param {String} [pTitleExpression] presets the matching property of the object
 * 
 * TODO: mostly temporary function until you can get fields from another Entity
 *
 * @class
 */
function ContextSelector(pTableName, pIdField, pTitleExpression)
{
    //the >>this.propertyX = null;<< is for autocomplete in the designer
    
    /**
     * title-definition; db-column or another sql-expression (like concating fields) as long as it returns one field
     * read-only property; set it with a matching setter
     * @property
     */
    this.titleExpression = null; ProtoPropertyUtils.makeSemiReadOnly(this, "titleExpression");
    this.setTitleExpression(pTitleExpression);

    /**
     * name of the database-table
     * read-only property; set it with a matching setter
     * @property
     */
    this.tableName = null; ProtoPropertyUtils.makeSemiReadOnly(this, "tableName");
    this.setTableName(pTableName);
    
    /**
     * db-field for the ID of one record (UID of matching context)
     * read-only property; set it with a matching setter
     * @property
     */
    this.idField = null; ProtoPropertyUtils.makeSemiReadOnly(this, "idField");
    this.setIdField(pIdField);
    
    /**
     * expression for additional joins to be made (addotopmaö pt table-name)
     * read-only property; set it with a matching setter
     * @property
     */
    this.joinExpression = null; ProtoPropertyUtils.makeSemiReadOnly(this, "joinExpression");
    /**
     * db-field for the ID of the relation to a CONTACT-record
     * read-only property; set it with a matching setter
     * @property
     */
    this.contactIdField = null; ProtoPropertyUtils.makeSemiReadOnly(this, "contactIdField");
    /**
     * db-field that represents the date of creation
     * read-only property; set it with a matching setter
     * @property
     */
    this.creationDateField = null; ProtoPropertyUtils.makeSemiReadOnly(this, "creationDateField");
    /**
     * db-field where the STATE-information (active/inactive) is stored (see the activeStates-property)
     * read-only property; set it with a matching setter
     * @property
     */
    this.stateField = null; ProtoPropertyUtils.makeSemiReadOnly(this, "stateField");
    /**
     * array that contains IDs of states that represent an "active"-state
     * read-only property; set it with a matching setter
     * @property
     */
    this.activeStates = null; ProtoPropertyUtils.makeSemiReadOnly(this, "activeStates");
    this.condition = null; ProtoPropertyUtils.makeSemiReadOnly(this, "condition");
    
    /**
     * an object which contains the subcontexts and the prepared select to get the contactIds of them.
     *                                                                                V--With Tablename!
     * {                       V-- before id-condition | add "and", if needed --V     V-IdCollumn name   V-- optional after-condition SQL (e.g. group by etc.)
     *   "Person": ["select PERSON_ID from CONTACT where PERSON_ID is not null and", "CONTACT.ORGANISATION_ID", '', ["Offer", "Contract"]],
     *                                                                                                            //  the contexts to show for this subcontext
     *   "Offer" ... // you can add as many subcontexts as you wish
     * }
     * read-only property; set it with a matching setter
     * @property
     */
    this.subContexts = null; ProtoPropertyUtils.makeSemiReadOnly(this, "subContexts");
}
/**
 * creates a new instance of a ContextSelector and returns it 
 * if given it also sets some properties (property names with matching function-parameters)
 * @static
 */
ContextSelector.create = function(pTableName, pIdField, pTitleExpression)
{
    return new ContextSelector(pTableName, pIdField, pTitleExpression);
};
/**
 * @param {String} pField the fieldname that shall be returned as full string
 * @return {String} full field containing tablename and the column; if the column itself is already a full qualified field that field is returned
 */
ContextSelector.prototype.getFullField = function(pField)
{
    //always keep undefined (and null) just undefined since it's never a fullQualifier and tablename.undefined is useless
    if (pField == undefined)
        return undefined;
    if (SqlUtils.isFullFieldQualifier(pField))
        return pField;
    else
        return this.tableName + "." + pField;
};
/**
 * @return {String} full id field containing tablename and column; if the column itself is already a full qualified field that field is returned
 */
ContextSelector.prototype.getFullIdField = function()
{
    return this.getFullField(this.idField);
};
/**
 * @return {String} full from-expression with tablename and join-part
 */
ContextSelector.prototype.getFullFromClause = function()
{
    if (this.joinExpression)
        return " " + this.tableName + " " + this.joinExpression + " ";
    else
        return this.tableName;
        
};
/**
 * @return {String} full from-expression with tablename and join-part
 */
ContextSelector.prototype.getSubContexts = function(pParentRowId)
{
    if (this.subContexts)
    {
        var sqls = {};
        
        for (contextId in this.subContexts)
        {
            sqls[contextId] = [SqlCondition.begin()
                               .andPrepare(this.subContexts[contextId][1], pParentRowId)
                               .buildSql(this.subContexts[contextId][0], "1=2", this.subContexts[contextId][2], false), this.subContexts[contextId][3]];
        }
        
        return sqls;
    }
    else
        return {};
        
};
//setters which to nothing special; no need to document them
ContextSelector.prototype.setTitleExpression = function(pValue)
{
    this._titleExpression = pValue;
    return this;
};
ContextSelector.prototype.setTableName = function(pValue)
{
    this._tableName = pValue;
    return this;
};
ContextSelector.prototype.setIdField = function(pValue)
{
    this._idField = pValue;
    return this;
};
ContextSelector.prototype.setJoinExpression = function(pValue)
{
    this._joinExpression = pValue;
    return this;
};
ContextSelector.prototype.setContactIdField = function(pValue)
{
    this._contactIdField = pValue;
    return this;
};
ContextSelector.prototype.setCreationDateField = function(pValue)
{
    this._creationDateField = pValue;
    return this;
};
ContextSelector.prototype.setStateField = function(pValue)
{
    this._stateField = pValue;
    return this;
};
ContextSelector.prototype.setActiveStates = function(pValue)
{
    this._activeStates = pValue;
    return this;
};
/**
 * sets the condition property of a ContextSelector-object
 * @param {Object} pSqlCondition condition as SqlCondition-object
 */
ContextSelector.prototype.setCondition = function(pSqlCondition)
{
    this._condition = pSqlCondition;
    return this;
};
ContextSelector.prototype.setSubContexts = function(pContexts)
{
    this._subContexts = pContexts;
    return this;
};

/**
 * TODO: !!!temporary function until you can get fields from another Entity!!!
 */
ContextUtils.getSelectMap  = function()
{
    var maskingUtils = new SqlMaskingUtils();
    return {
            "Organisation": ContextSelector.create("ORGANISATION", "CONTACT.CONTACTID", "ORGANISATION.NAME")
                                       .setJoinExpression("join CONTACT on ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID and CONTACT.PERSON_ID is null")
                                       .setCondition(SqlCondition.begin().and("ORGANISATION.ORGANISATIONID != '0'"))
                                       .setSubContexts({
                                           "Person": ["select CONTACTID from CONTACT where PERSON_ID is not null and", "CONTACT.ORGANISATION_ID", '', ["Offer", "Order", "Contract", "SupportTicket"]]
                                       })
            ,"Person": ContextSelector.create("CONTACT", "CONTACTID")
                                      .setTitleExpression(maskingUtils.concat([
                                                new ContactTitleRenderer(Contact.createWithColumnPreset()).asSql()
                                                ,"' - '"//looks pretty bad; TODO: workaround till Lookups can be loaded over a link-entity; then use displayProc
                                                ,"defaultAddress.ADDRESS", "defaultAddress.BUILDINGNO"
                                                ,"' - '"
                                                ,"defaultAddress.COUNTRY", "defaultAddress.ZIP", "defaultAddress.CITY"
                                               ]," "))
                                      .setJoinExpression("join PERSON on PERSON.PERSONID = CONTACT.PERSON_ID \n\
                                                          join ORGANISATION on ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID\n\
                                                          left join ADDRESS defaultAddress on defaultAddress.ADDRESSID = CONTACT.ADDRESS_ID")
            ,"PrivatePerson": ContextSelector.create("PERSON", "PERSONID")
                                      .setTitleExpression(maskingUtils.concat([
                                                new ContactTitleRenderer(Contact.createWithColumnPresetForPrivatePerson()).asSql()
                                                ,"' - '"//looks pretty bad; TODO: workaround till Lookups can be loaded over a link-entity; then use displayProc
                                                ,"defaultAddress.ADDRESS", "defaultAddress.BUILDINGNO"
                                                ,"' - '"
                                                ,"defaultAddress.COUNTRY", "defaultAddress.ZIP", "defaultAddress.CITY"
                                               ]," "))
                                      .setJoinExpression("left join CONTACT on PERSON.PERSONID = CONTACT.PERSON_ID and CONTACT.ORGANISATION_ID = '0' left join ADDRESS defaultAddress on defaultAddress.ADDRESSID = CONTACT.ADDRESS_ID")
                                      .setContactIdField("CONTACT.CONTACTID")
            ,"Activity": ContextSelector.create("ACTIVITY", "ACTIVITYID", "SUBJECT")
            ,"Salesproject": ContextSelector.create("SALESPROJECT", "SALESPROJECTID")
                                            .setTitleExpression(maskingUtils.concat([
                                                                "'" + translate.text("Salesproject") + "'",
                                                                "' '",
                                                                maskingUtils.cast("PROJECTCODE", SQLTYPES.VARCHAR, 10),
                                                                "' | '",
                                                                "PROJECTTITLE"
                                                                ], "", false))
                                            .setContactIdField("CONTACT_ID")
                                            .setCreationDateField("STARTDATE")
                                            .setStateField("STATUS")
                                            .setActiveStates([$KeywordRegistry.salesprojectState$open(), $KeywordRegistry.salesprojectState$postponed()])
            ,"Contract": ContextSelector.create("CONTRACT", "CONTRACTID")
                                        .setTitleExpression(maskingUtils.concat([
                                                                KeywordUtils.getResolvedTitleSqlPart("ContractType", "CONTRACTTYPE"),
                                                                maskingUtils.cast("CONTRACTCODE", SQLTYPES.VARCHAR, 10)
                                                                ], " "))
                                        .setContactIdField("CONTACT_ID")
                                        .setCreationDateField("CONTRACTSTART")
                                        .setStateField("CONTRACTSTATUS")
                                        .setActiveStates([$KeywordRegistry.contractState$validLimited(), $KeywordRegistry.contractState$validUnlimited(), $KeywordRegistry.contractState$notSigned()])
            ,"Offer": ContextSelector.create("OFFER", "OFFERID")
                                     .setTitleExpression(maskingUtils.concat([
                                                "'" + translate.text("Offer") + "'",
                                                "' '",
                                                maskingUtils.cast("OFFERCODE", SQLTYPES.VARCHAR, 10),
                                                "'-'",
                                                maskingUtils.cast("VERSNR", SQLTYPES.VARCHAR, 10)
                                                ], "", false))
                                     .setContactIdField("CONTACT_ID")
                                     .setCreationDateField("OFFERDATE")
                                     .setStateField("STATUS")
                                     .setActiveStates([$KeywordRegistry.offerStatus$open, $KeywordRegistry.offerStatus$checked, $KeywordRegistry.offerStatus$sent])
            ,"Order": ContextSelector.create("SALESORDER", "SALESORDERID")
                                     .setTitleExpression(maskingUtils.concat([
                                                        "'" + translate.text("Order") + "'",
                                                        "' '",
                                                        maskingUtils.cast("SALESORDERCODE", SQLTYPES.VARCHAR, 10),
                                                        "'-'",
                                                        maskingUtils.cast("VERSNR", SQLTYPES.VARCHAR, 10)
                                                        ], "", false))
                                     .setContactIdField("CONTACT_ID")
                                     .setCreationDateField("SALESORDERDATE")
                                     .setStateField("ORDERSTATUS")
                                     .setActiveStates([$KeywordRegistry.salesorderState$checked, $KeywordRegistry.salesorderState$sent])
            ,"Product": ContextSelector.create("PRODUCT", "PRODUCTID")
                                       .setTitleExpression(maskingUtils.concat([
                                            "PRODUCTCODE",
                                            "' | '",
                                            "PRODUCTNAME"
                                            ], "", false))
            ,"Task": ContextSelector.create("TASK", "TASKID", "SUBJECT")
            ,"Campaign": ContextSelector.create("CAMPAIGN", "CAMPAIGNID")
                         .setTitleExpression(maskingUtils.concat(["CAMPAIGN.NAME", "CAMPAIGNSTEP.NAME"], " - ", false))
                         .setContactIdField("CAMPAIGNPARTICIPANT.CONTACT_ID")
                         .setJoinExpression("left join CAMPAIGNPARTICIPANT on CAMPAIGNPARTICIPANT.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID " +
                                            "left join CAMPAIGNSTEP on CAMPAIGNSTEP.CAMPAIGNSTEPID = CAMPAIGNPARTICIPANT.CAMPAIGNSTEP_ID")
                        .setCreationDateField("CAMPAIGNSTEP.DATE_START")
                        .setStateField("CAMPAIGN.STATUS")
                        .setActiveStates([$KeywordRegistry.campaignState$planning(), $KeywordRegistry.campaignState$approved()])
            ,"CampaignStep" : ContextSelector.create("CAMPAIGNSTEP", "CAMPAIGNSTEPID", "NAME")
            ,"SupportTicket": ContextSelector.create("TICKET", "TICKETID", "TASK.SUBJECT")
                        .setJoinExpression("left join TASK on TASK.TASKID = TICKET.TASK_ID")
                        .setCondition(SqlCondition.begin().andPrepare("TICKET.TICKETTYPE", $KeywordRegistry.ticketType$supportTicket()))
                        .setContactIdField("TASK.REQUESTOR_CONTACT_ID")
                        .setStateField("TASK.STATUS")
                        .setActiveStates([
                            $KeywordRegistry.taskStatus$new(),
                            $KeywordRegistry.taskStatus$unassigned(),
                            $KeywordRegistry.taskStatus$assigned(),
                            $KeywordRegistry.taskStatus$inProgress(),
                            $KeywordRegistry.taskStatus$waiting(),
                            $KeywordRegistry.taskStatus$customerChecks(),
                        ])
                        .setCreationDateField("TASK.START_DATE")
            ,"BulkMail" : ContextSelector.create("BULKMAIL", "BULKMAILID", "NAME")
            ,"SerialLetter" : ContextSelector.create("SERIALLETTER", "SERIALLETTERID", "TITLE")
    }
}

/**
 * TODO: !!!temporary function until you can get fields from another Entity!!!
 */
ContextUtils.getNameSubselectSql = function(pContextIdDbField, pRowIdDbField)
{
    var select = "(case " + pContextIdDbField + " ";

    var selectMap = ContextUtils.getSelectMap ()
    for (let contextId in selectMap)
    {
        select += "when '" + contextId + "' then (select " + selectMap[contextId].titleExpression + " from " + selectMap[contextId].getFullFromClause() + (pRowIdDbField ? " where " + selectMap[contextId].getFullIdField() + " = " + pRowIdDbField : " ") + ") ";
    }

    select += "else 'Not defined in ContextUtils.getNameSql()!'";
    select += "end)";

    return select;
}

/**
 * TODO: !!!temporary function until you can get fields from another Entity!!!
 */
ContextUtils.getNameSql = function(pContextId, pRowId)
{
    var selectMap = ContextUtils.getSelectMap ()
    if (selectMap[pContextId] != undefined)
    {
        return SqlCondition.begin().andPrepare(selectMap[pContextId].getFullIdField(), pRowId)
                                   .buildSql("select " + selectMap[pContextId].titleExpression 
                                            + " from " + selectMap[pContextId].getFullFromClause(), "1 = 2");
    }
    else
        return "select 1 from person where 1=2";
}

/**
 * TODO: !!!temporary function until you can get fields from another Entity!!!
 */
ContextUtils.getContactId = function(pContextId, pRowId)
{
    var selectMap = ContextUtils.getSelectMap ()
    if (selectMap[pContextId] != undefined && selectMap[pContextId].contactIdField)
    {
        
        return db.cell(SqlCondition.begin().andPrepare(selectMap[pContextId].getFullIdField(), pRowId)
                                   .buildSql("select " + selectMap[pContextId].contactIdField
                                            + " from " + selectMap[pContextId].tableName, "1 = 2"));
    }
    else
        return "";
}

/**
 * TODO: !!!temporary function until you can get fields from another Entity!!!
 */
ContextUtils.getContextDataSql = function(pContextId, pContactId, pWithDate, pActive, pWithState, pExcludedObjectIds)
{
    var selectMap = ContextUtils.getSelectMap();
    var ownContextSelector = selectMap[pContextId];
    var cond = SqlCondition.begin();
    if (pContactId)
    {
        cond.andPrepare(ownContextSelector.getFullField(ownContextSelector.contactIdField), pContactId)
    }
    
    if (pActive != undefined)
    {
        var activeStates = ownContextSelector.activeStates;
        if(activeStates != null && activeStates.length > 0)
        {
            var condSub = SqlCondition.begin();
            activeStates.forEach(function (state) 
            {   
                if(pActive)
                    condSub.orPrepare(ownContextSelector.getFullField(ownContextSelector.stateField), state)
                else
                    condSub.andPrepare(ownContextSelector.getFullField(ownContextSelector.stateField), state, "# != ?")
            });
            cond.andSqlCondition(condSub);  
        }
    }
    
    if (pExcludedObjectIds)
    {
        var exludedIdsCond = new SqlCondition()
        
        pExcludedObjectIds.forEach(function(id)
        {
            this.andPrepare(ownContextSelector.getFullIdField(), id, "# <> ?");
        }, exludedIdsCond)
        
        cond.andSqlCondition(exludedIdsCond);
    }
    
    var dateColumn = "";
    if (pWithDate === true)
        dateColumn = ", " + (ownContextSelector.getFullField(ownContextSelector.creationDateField) || "''");
    var stateColumn = "";
    if (pWithState === true)
        stateColumn = ", " + (ownContextSelector.getFullField(ownContextSelector.stateField) || "''");
    if (ownContextSelector.condition)
        cond.andSqlCondition(ownContextSelector.condition);
    var res = cond.buildSql("select " + ownContextSelector.getFullIdField() + ", " + ownContextSelector.titleExpression + dateColumn + stateColumn 
            +  " from " + ownContextSelector.getFullFromClause(), "1=1");
    return res;
}

/**
 * TODO: !!!temporary function until you can get fields from another Entity!!!
 */
ContextUtils.getCountByContactId = function(pContextId, pContactId)
{
    var contextObject = ContextUtils.getSelectMap()[pContextId];
    var tableName = contextObject.tableName;
    var contactField = contextObject.getFullField(contextObject.contactIdField)
    var join = contextObject.joinExpression;
    if (tableName && contactField)
    {
        var sql = "select count(*) from " + tableName + (join ? join : "");
        var count = db.cell(SqlCondition.begin().andPrepare(contactField, pContactId).buildSql(sql, "1=2"));
        return count;
    }
    return 0;
}

function AdminViewUtils () {}

/**
 * opens the admin view
 * 
 * @param {String} [pUidField=UID] the title of the uid field (just the title, the uid itself is fetched automatically)
 * @param {String[][]} pFields Additional fields as an two dimensional array, the structure should be [[title, value, contenttype]],
 *                              the contenttype is optional (default is TEXT).
 */
AdminViewUtils.open = function (pUidField, pFields)
{
    var uid = vars.get("$sys.uid");
    if (!pUidField)
        pUidField = "UID";
    else
        pUidField += " (UID)";
    var rows = [
        [pUidField, pUidField, uid, "TEXT"]
    ];
    if (pFields)
    {
        pFields.forEach(function (field)
        {
            rows.push([field[0], field[0], field[1], field[2] || "TEXT"]);
        });
    }
    var params = {
        "Uid_param" : uid,
        "Rows_param" : JSON.stringify(rows)
    };
    neon.openContext("DefaultAdminView", "DefaultAdminView_view", [uid], neon.OPERATINGSTATE_VIEW, params);
}

AdminViewUtils.getActionState = function ()
{
    if (tools.currentUserHasRole("INTERNAL_ADMINISTRATOR"))
        return neon.COMPONENTSTATE_EDITABLE;
    return neon.COMPONENTSTATE_INVISIBLE;
}