From b6cf6d6258e5600cd1368277dc2e1be127eadb3a Mon Sep 17 00:00:00 2001
From: "S.Listl" <S.Listl@SLISTL.aditosoftware.local>
Date: Tue, 13 Aug 2019 14:51:51 +0200
Subject: [PATCH] Keyword fix

---
 .../KeywordEntry_entity.aod                   | 19 +----
 .../keywordattributerelations/onValidation.js | 82 +++++++++++++++++++
 .../keywordentryid_param/valueProcess.js      |  4 -
 .../documentation.adoc                        |  2 -
 4 files changed, 84 insertions(+), 23 deletions(-)
 create mode 100644 entity/KeywordEntry_entity/entityfields/keywordattributerelations/onValidation.js
 delete mode 100644 entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/children/keywordentryid_param/valueProcess.js
 delete mode 100644 entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/documentation.adoc

diff --git a/entity/KeywordEntry_entity/KeywordEntry_entity.aod b/entity/KeywordEntry_entity/KeywordEntry_entity.aod
index 1025fac614..609c83dc2e 100644
--- a/entity/KeywordEntry_entity/KeywordEntry_entity.aod
+++ b/entity/KeywordEntry_entity/KeywordEntry_entity.aod
@@ -475,7 +475,7 @@
           <fieldName>KeywordGuarantee</fieldName>
           <isConsumer v="false" />
         </entityDependency>
-         <entityDependency>
+        <entityDependency>
           <name>2443c7e3-9e66-41dc-99c7-3283e9315000</name>
           <entityName>Campaign_entity</entityName>
           <fieldName>KeywordCurrency</fieldName>
@@ -530,6 +530,7 @@
     </entityParameter>
     <entityConsumer>
       <name>KeywordAttributeRelations</name>
+      <onValidation>%aditoprj%/entity/KeywordEntry_entity/entityfields/keywordattributerelations/onValidation.js</onValidation>
       <dependency>
         <name>dependency</name>
         <entityName>KeywordAttributeRelation_entity</entityName>
@@ -543,22 +544,6 @@
         </entityParameter>
       </children>
     </entityConsumer>
-    <entityConsumer>
-      <name>KeywordAttributeRelationsReadOnly</name>
-      <documentation>%aditoprj%/entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/documentation.adoc</documentation>
-      <state>READONLY</state>
-      <dependency>
-        <name>dependency</name>
-        <entityName>KeywordAttributeRelation_entity</entityName>
-        <fieldName>AttributesForKeywordEntry</fieldName>
-      </dependency>
-      <children>
-        <entityParameter>
-          <name>KeywordEntryId_param</name>
-          <valueProcess>%aditoprj%/entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/children/keywordentryid_param/valueProcess.js</valueProcess>
-        </entityParameter>
-      </children>
-    </entityConsumer>
     <entityParameter>
       <name>ExcludedKeyIdsSubquery_param</name>
       <expose v="true" />
diff --git a/entity/KeywordEntry_entity/entityfields/keywordattributerelations/onValidation.js b/entity/KeywordEntry_entity/entityfields/keywordattributerelations/onValidation.js
new file mode 100644
index 0000000000..ff0553af7e
--- /dev/null
+++ b/entity/KeywordEntry_entity/entityfields/keywordattributerelations/onValidation.js
@@ -0,0 +1,82 @@
+import("system.translate");
+import("system.result");
+import("system.vars");
+import("Sql_lib");
+import("system.db");
+
+if (!_areUnique())
+    result.string(translate.text("Attributes must be unique!"));
+
+function _areUnique ()
+{
+    var insertedRows = vars.get("$field.KeywordAttributeRelations.insertedRows");
+    var changedRows = vars.get("$field.KeywordAttributeRelations.changedRows");
+    var deletedRows = vars.get("$field.KeywordAttributeRelations.deletedRows");
+
+    var storedRows = db.table(SqlCondition.begin()
+        .andPrepare("AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ENTRY_ID", vars.get("$field.AB_KEYWORD_ENTRYID"))
+        .buildSql("select AB_KEYWORD_ATTRIBUTERELATIONID, AB_KEYWORD_ATTRIBUTE_ID from AB_KEYWORD_ATTRIBUTERELATION"));
+    
+    var attributeChanges = {};
+
+    if (deletedRows)
+        deletedRows.forEach(function (row)
+        {
+            this[row.AB_KEYWORD_ATTRIBUTERELATIONID] = "";
+        }, attributeChanges);
+    
+    if (changedRows)
+        changedRows.forEach(function (row)
+        {
+            this[row.AB_KEYWORD_ATTRIBUTERELATIONID] = row.AB_KEYWORD_ATTRIBUTE_ID;
+        }, attributeChanges);
+    
+    var countObj = {};
+
+    storedRows.forEach(function ([storedAttrRelationId, storedAttributeId]) {
+        var currentAttributeId = storedAttributeId;
+        //merging the data that is stored in the DB and the provided changes
+        if (attributeChanges && storedAttrRelationId in attributeChanges)
+            currentAttributeId = attributeChanges[storedAttrRelationId];
+        
+        // it doesn't matter if a row has been deleted or if the attribute has been set to "nothing"
+        if (currentAttributeId == "")
+            _decrCount(storedAttributeId);
+        else
+        {
+            _incrCount(currentAttributeId);
+            if (currentAttributeId != storedAttributeId)
+                _decrCount(storedAttributeId);
+        }
+    });
+    
+    if (insertedRows) //append the new rows
+    {
+        insertedRows.forEach(function (row)
+        {
+            this[row.AB_KEYWORD_ATTRIBUTE_ID] = (this[row.AB_KEYWORD_ATTRIBUTE_ID] || 0) + 1;
+        }, countObj);
+    }
+    
+    for (let id in countObj)
+        if (countObj[id] > 1)
+            return false;
+    
+    return true;
+
+    function _incrCount (pAttributeId)
+    {
+        if (countObj[pAttributeId])
+            countObj[pAttributeId]++;
+        else
+            countObj[pAttributeId] = 1;
+    }
+    
+    function _decrCount (pAttributeId)
+    {
+        if (countObj[pAttributeId])
+            countObj[pAttributeId]--;
+        else
+            countObj[pAttributeId] = 0;
+    }
+}
diff --git a/entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/children/keywordentryid_param/valueProcess.js b/entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/children/keywordentryid_param/valueProcess.js
deleted file mode 100644
index 53afbdfbbf..0000000000
--- a/entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/children/keywordentryid_param/valueProcess.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import("system.vars");
-import("system.result");
-
-result.string(vars.get("$field.AB_KEYWORD_ENTRYID"));
\ No newline at end of file
diff --git a/entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/documentation.adoc b/entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/documentation.adoc
deleted file mode 100644
index 99874edc30..0000000000
--- a/entity/KeywordEntry_entity/entityfields/keywordattributerelationsreadonly/documentation.adoc
+++ /dev/null
@@ -1,2 +0,0 @@
-Since it's not possible to limit the keywordAttributeRelation to a distinctive list (use a KeywordAttributeRelation "category" only once per keyowrd-entry) within the generic-multiple-template / titledList-template use this readonly consumer there.
-For editing use the not-read-only consumer in a list-template. In a list-template only one row can be changed (and stored) which means we can exlucde already stored entries.
\ No newline at end of file
-- 
GitLab