Something went wrong on our end
-
Johannes Hörmann authoredJohannes Hörmann authored
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;
}