From a8802fbc5cb624ea14503d1a7003120ca2693281 Mon Sep 17 00:00:00 2001
From: Daniel Tran <d.tran@adito.de>
Date: Wed, 29 Apr 2020 11:00:35 +0200
Subject: [PATCH] #1049797: Added some existing, needed functions from
 master-branch. #1049797: Added mandatory process to make company name
 mandatory, when an company address is given. #1049797: Added/Enabled missing
 valueProcess for ContactType_param

---
 .../QuickEntry_entity/QuickEntry_entity.aod   |   5 +
 .../organisation_name/mandatoryProcess.js     |   8 +
 process/Entity_lib/process.js                 | 197 +++++++++++++++++-
 3 files changed, 209 insertions(+), 1 deletion(-)
 create mode 100644 entity/QuickEntry_entity/entityfields/organisation_name/mandatoryProcess.js

diff --git a/entity/QuickEntry_entity/QuickEntry_entity.aod b/entity/QuickEntry_entity/QuickEntry_entity.aod
index 5a068896ab..8cc3408b69 100644
--- a/entity/QuickEntry_entity/QuickEntry_entity.aod
+++ b/entity/QuickEntry_entity/QuickEntry_entity.aod
@@ -17,6 +17,7 @@
       <name>ORGANISATION_NAME</name>
       <title>Company</title>
       <contentType>LONG_TEXT</contentType>
+      <mandatoryProcess>%aditoprj%/entity/QuickEntry_entity/entityfields/organisation_name/mandatoryProcess.js</mandatoryProcess>
     </entityField>
     <entityConsumer>
       <name>Adresses</name>
@@ -30,6 +31,10 @@
           <name>ContactId_param</name>
           <valueProcess>%aditoprj%/entity/QuickEntry_entity/entityfields/adresses/children/contactid_param/valueProcess.js</valueProcess>
         </entityParameter>
+        <entityParameter>
+          <name>ContactType_param</name>
+          <valueProcess>%aditoprj%/entity/QuickEntry_entity/entityfields/adresses/children/contacttype_param/valueProcess.js</valueProcess>
+        </entityParameter>
       </children>
     </entityConsumer>
     <entityConsumer>
diff --git a/entity/QuickEntry_entity/entityfields/organisation_name/mandatoryProcess.js b/entity/QuickEntry_entity/entityfields/organisation_name/mandatoryProcess.js
new file mode 100644
index 0000000000..4600073112
--- /dev/null
+++ b/entity/QuickEntry_entity/entityfields/organisation_name/mandatoryProcess.js
@@ -0,0 +1,8 @@
+import("system.result");
+import("system.neon");
+import("system.vars");
+
+var address = vars.get("$field.OrgAddresses.insertedRows");
+var isMandatory = address[0] != null || "" ? true : false;
+
+result.string(isMandatory);
\ No newline at end of file
diff --git a/process/Entity_lib/process.js b/process/Entity_lib/process.js
index 15acae96dc..72e4a77460 100644
--- a/process/Entity_lib/process.js
+++ b/process/Entity_lib/process.js
@@ -1,3 +1,4 @@
+import("system.translate");
 import("system.result");
 import("system.neon");
 import("system.vars");
@@ -173,4 +174,198 @@ FieldChanges._getStorage = function()
 FieldChanges._setStorage = function(pAllChanges)
 {
     return vars.set("$context.FieldChanges", pAllChanges);
-};
\ No newline at end of file
+};
+
+/**
+ * Object for testing if linked datasets exists. You can add validations with the provided methods, note that these validations will be done in the
+ * same order you added them until one of them results in false. Therefore, you should add the tests that are most likely to fail first.
+ * 
+ * @param {String[]} pConsumers names of the consumers to be tested
+ */
+function HasLinkedObjectTester (pConsumers)
+{
+    //This array will contain objects that are used for the validation. You can put any object in this array as long as it provides
+    //a method 'checkForObjects' that can be invoked.
+    this._validationObjects = [];
+
+    if (pConsumers)
+        pConsumers.forEach(this.andNoConsumerRows, this);
+
+    Object.defineProperty(this, "length", {
+        get : function () {return this._validationObjects.length;}
+    });
+}
+
+/**
+ * @ignore
+ */
+HasLinkedObjectTester._testForEntity = function ()
+{
+    entities.createConfigForLoadingConsumerRows()
+    var loadConfig = entities.createConfigForLoadingRows()
+        .entity(this.entity)
+        .provider(this.provider)
+        .ignorePermissions(true);
+
+    if (this.parameters)
+    {
+        for (let param in this.parameters)
+            loadConfig.addParameter(param, this.parameters[param]);
+    }
+    return entities.getRowCount(loadConfig) == 0;
+}
+
+/**
+ * @ignore
+ */
+HasLinkedObjectTester._testForConsumer = function ()
+{
+    //TODO: implement when possible
+    return false;
+}
+
+/**
+ * @ignore
+ */
+HasLinkedObjectTester._testForCallback = function ()
+{
+    fnResult = this.callbackFn();
+    return this.failValue
+        ? fnResult != this.failValue
+        : fnResult;
+}
+
+/**
+ * @ignore
+ */
+HasLinkedObjectTester._testForSqlCount = function ()
+{
+    //also works for empty string because Number("") returns 0
+    return Number(this.sqlQuery.cell()) === 0;
+}
+
+/**
+ * !!! YOU CAN'T USE THIS FUNCTION YET !!!
+ * 
+ * Adds a consumer to test for rows to the object.
+ * 
+ * @ignore
+ * 
+ * @param {String} pConsumer name of the consumer
+ * @return {HasLinkedObjectTester} current object
+ */
+HasLinkedObjectTester.prototype.andNoConsumerRows = function (pConsumer)
+{
+    throw new Error("HasLinkedObjectTester.prototype.andNoConsumerRows does not work yet")
+    this._validationObjects.push({
+        checkForObjects : HasLinkedObjectTester._testForConsumer,
+        consumer : pConsumer
+    });
+    return this;
+}
+
+/**
+ * Adds a entity with provider to test for rows. You have to set the parameters by yourself.
+ * 
+ * @param {String} pEntity name of the entity
+ * @param {String} pProvider provider that should be used
+ * @param {Object} [pParameters] parameters to set
+ * @return {HasLinkedObjectTester} current object
+ * @example
+ *  new HasLinkedObjectTester()
+ *      .andNoEntityRows("Activity_entity", "LinkedObjects", {ObjectId_param : currentContext, RowId_param : contactId})
+ */
+HasLinkedObjectTester.prototype.andNoEntityRows = function (pEntity, pProvider, pParameters)
+{
+    this._validationObjects.push({
+        checkForObjects : HasLinkedObjectTester._testForEntity,
+        entity : pEntity,
+        provider : pProvider,
+        parameters : pParameters
+    });
+    return this;
+}
+
+/**
+ * Adds a custom callback function that tests for linked objects. The reason for using a callback function here is that it will only be called if
+ * necessary.
+ * 
+ * @param {Function} pCallbackFn validation function, it should return true if NO linked objects were found, but the expected value can be changed
+ *                             by providing an own 'pFailValue'
+ * @param {Object} [pFailValue=false] if the given function returns this value, the ovarall validation will fail and return false
+ * @return {HasLinkedObjectTester} current object
+ */
+HasLinkedObjectTester.prototype.and = function (pCallbackFn, pFailValue)
+{
+    if (typeof pCallbackFn !== "function")
+        throw new TypeError(translate.text("pCallbackFn is not a function"));
+        
+    this._validationObjects.push({
+        checkForObjects : HasLinkedObjectTester._testForCallback,
+        callbackFn : pCallbackFn,
+        failValue : pFailValue
+    });
+    return this;
+}
+
+/**
+ * Adds a SqlBuilder object to the validation that should return a single number (e. g. "select count(*) ..."). If the result of the SQL is not 0,
+ * the overall validation will return false.
+ * 
+ * @param {SqlBuilder} pSqlQuery the SqlBuilder object, the SQL will be executed with SqlBuilder.prototype.cell() and is expected to result in a number
+ * @return {HasLinkedObjectTester} current object
+ */
+HasLinkedObjectTester.prototype.andSqlYieldsZero = function (pSqlQuery)
+{
+    if (!(pSqlQuery instanceof SqlBuilder))
+        throw new TypeError(translate.text("pSqlQuery must be of type SqlBuilder"));
+    
+    this._validationObjects.push({
+        checkForObjects : HasLinkedObjectTester._testForSqlCount,
+        sqlQuery : pSqlQuery
+    });
+    return this;
+}
+
+/**
+ * Executes the validation of all tests that have been added to the object. If every test returns true, the result will also be true,
+ * but if any test returns false, the execution will stop and false is returned.
+ * 
+ * @return {Boolean} true, if NO linked objects were found
+ */
+HasLinkedObjectTester.prototype.validate = function ()
+{
+    return this._validationObjects.every(function (duck)
+    {
+        return duck.checkForObjects();
+    });
+}
+
+/**
+ * @return {String} validation result as String, so that .validate() does not always have to be called explicitly
+ */
+HasLinkedObjectTester.prototype.toString = function ()
+{
+    return String(this.validate());
+};
+
+/**
+* Provides static methods for special handling of consumer in entities.
+* 
+* @class
+*/
+function EntityConsumerUtils(){}
+
+/**
+ * Method wich clears all fields behind the consumer.
+ * @param pConsumer the consumer which fields will be cleared.
+ * @return {void}
+ */
+EntityConsumerUtils.rmInsertedConsumerRows = function(pConsumer)
+{
+    var insertedRows = vars.get("$field." + pConsumer + ".insertedRows");
+    insertedRows.forEach(function(row)
+    {
+        neon.deleteRecord(pConsumer, row["#UID"]);
+    });
+};
-- 
GitLab