From 9a21f8bf12c1a0a975b43352f5433b3f2a353d5c Mon Sep 17 00:00:00 2001
From: "j.goderbauer" <j.goderbauer@adito.de>
Date: Fri, 8 Mar 2019 15:36:28 +0100
Subject: [PATCH] [Projekt: Entwicklung - Neon][TicketNr.:
 1035771][Kontaktmanagement - Firma / Kontaktperson + Adressen / Kommunikation
 - Nutzung des kompletten Moduls sicherstellen]

---
 .../AnyContact_entity/AnyContact_entity.aod   |  28 +-
 .../entityfields/contacttype/valueProcess.js  |   2 +-
 .../entityfields/image/valueProcess.js        |   2 +-
 .../recordcontainers/db/fromClauseProcess.js  |   2 +-
 entity/AnyContact_entity/titleProcess.js      |  17 +-
 entity/Contract_entity/Contract_entity.aod    |   4 -
 .../contact_id/displayValueProcess.js         |   2 +-
 .../contact_id/linkedContextProcess.js        |   2 +-
 .../contact_id/displayValueProcess.js         |   2 +-
 .../contact_id/linkedContextProcess.js        |   2 +-
 .../salesproject_id/mandatoryProcess.js       |   2 +-
 .../contact_id/displayValueProcess.js         |   2 +-
 .../contact_id/linkedContextProcess.js        |   2 +-
 entity/Person_entity/Person_entity.aod        |   1 -
 .../full_name_fieldgroup/valueProcess.js      |  17 +-
 .../SalesprojectCompetition_entity.aod        |   4 +-
 .../SalesprojectMember_entity.aod             |   4 +-
 .../AnyContactLookup_view.aod                 |   2 +-
 .../PersonPreview_view/PersonPreview_view.aod |   2 +-
 .../SalesprojectMemberFilter_view.aod         |   2 +-
 process/Contact_lib/process.js                | 249 +++++++++++++-----
 process/Person_lib/process.js                 |  10 +-
 process/PostalAddress_lib/process.js          |  19 +-
 process/Sql_lib/process.js                    |   5 +-
 process/Util_lib/process.js                   |  52 ++++
 25 files changed, 310 insertions(+), 126 deletions(-)

diff --git a/entity/AnyContact_entity/AnyContact_entity.aod b/entity/AnyContact_entity/AnyContact_entity.aod
index 79c21284961..179c872d486 100644
--- a/entity/AnyContact_entity/AnyContact_entity.aod
+++ b/entity/AnyContact_entity/AnyContact_entity.aod
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.2.0">
   <name>AnyContact_entity</name>
-  <description>former Relation</description>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <titleProcess>%aditoprj%/entity/AnyContact_entity/titleProcess.js</titleProcess>
   <recordContainer>db</recordContainer>
@@ -56,7 +55,7 @@
     <entityField>
       <name>contactType</name>
       <description>Relation type. Value is based on the existance or non-existance of ORGANISATION_ID and PERSON_ID.
-See RelationUtils.getRelationTypeByPersOrg for possible values</description>
+See ContactUtils.getRelationTypeByPersOrg for possible values</description>
       <contentType>NUMBER</contentType>
       <searchable v="false" />
       <valueProcess>%aditoprj%/entity/AnyContact_entity/entityfields/contactType/valueProcess.js</valueProcess>
@@ -92,7 +91,7 @@ See RelationUtils.getRelationTypeByPersOrg for possible values</description>
       </children>
     </entityConsumer>
     <entityField>
-      <name>ORG_NAME</name>
+      <name>ORGANISATION_NAME</name>
       <title>Organisation name</title>
     </entityField>
     <entityField>
@@ -152,6 +151,15 @@ See RelationUtils.getRelationTypeByPersOrg for possible values</description>
       <name>RELATIONSHIP</name>
       <description>TODO: Beziehung zu der Relation 1024846 (z.B. per Ampelsystem)</description>
     </entityField>
+    <entityField>
+      <name>PERSON_MIDDLENAME</name>
+    </entityField>
+    <entityField>
+      <name>PERSON_TITLE</name>
+    </entityField>
+    <entityField>
+      <name>PERSON_SALUTATION</name>
+    </entityField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -214,7 +222,7 @@ See RelationUtils.getRelationTypeByPersOrg for possible values</description>
           <recordfield>CONTACT.STATUS</recordfield>
         </dbRecordFieldMapping>
         <dbRecordFieldMapping>
-          <name>ORG_NAME.value</name>
+          <name>ORGANISATION_NAME.value</name>
           <recordfield>ORGANISATION.NAME</recordfield>
         </dbRecordFieldMapping>
         <dbRecordFieldMapping>
@@ -237,6 +245,18 @@ See RelationUtils.getRelationTypeByPersOrg for possible values</description>
           <name>RELATIONSHIP.value</name>
           <recordfield>CONTACT.RELATIONSHIP</recordfield>
         </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>PERSON_MIDDLENAME.value</name>
+          <recordfield>PERSON.MIDDLENAME</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>PERSON_TITLE.value</name>
+          <recordfield>PERSON.TITLE</recordfield>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>PERSON_SALUTATION.value</name>
+          <recordfield>PERSON.SALUTATION</recordfield>
+        </dbRecordFieldMapping>
       </recordFieldMappings>
     </dbRecordContainer>
   </recordContainers>
diff --git a/entity/AnyContact_entity/entityfields/contacttype/valueProcess.js b/entity/AnyContact_entity/entityfields/contacttype/valueProcess.js
index 51fe9740839..32bb8ca1976 100644
--- a/entity/AnyContact_entity/entityfields/contacttype/valueProcess.js
+++ b/entity/AnyContact_entity/entityfields/contacttype/valueProcess.js
@@ -2,4 +2,4 @@ import("system.result");
 import("system.vars");
 import("Contact_lib")
 
-result.object(RelationUtils.getRelationType(vars.get("$field.CONTACTID"), vars.get("$field.PERSON_ID"), vars.get("$field.ORGANISATION_ID")));
\ No newline at end of file
+result.object(ContactUtils.getRelationType(vars.get("$field.CONTACTID"), vars.get("$field.PERSON_ID"), vars.get("$field.ORGANISATION_ID")));
\ No newline at end of file
diff --git a/entity/AnyContact_entity/entityfields/image/valueProcess.js b/entity/AnyContact_entity/entityfields/image/valueProcess.js
index bc039e74557..d30dd866019 100644
--- a/entity/AnyContact_entity/entityfields/image/valueProcess.js
+++ b/entity/AnyContact_entity/entityfields/image/valueProcess.js
@@ -7,7 +7,7 @@ import("Contact_lib");
 
 if (vars.get("$field.contactType") == 1) // 1 == org, 2 == person, 3 == person
 {
-    result.string(OrgUtils.getImage(vars.get("$field.ORGANISATION_ID"), vars.getString("$field.ORG_NAME")));
+    result.string(OrgUtils.getImage(vars.get("$field.ORGANISATION_ID"), vars.getString("$field.ORGANISATION_NAME")));
 }
 else
 {
diff --git a/entity/AnyContact_entity/recordcontainers/db/fromClauseProcess.js b/entity/AnyContact_entity/recordcontainers/db/fromClauseProcess.js
index 754b510a957..c2008fc0d19 100644
--- a/entity/AnyContact_entity/recordcontainers/db/fromClauseProcess.js
+++ b/entity/AnyContact_entity/recordcontainers/db/fromClauseProcess.js
@@ -1,4 +1,4 @@
 import("system.result");
 import("Contact_lib")
 
-result.string(RelationUtils.getFullRelationFromString());
\ No newline at end of file
+result.string(ContactUtils.getFullRelationString());
\ No newline at end of file
diff --git a/entity/AnyContact_entity/titleProcess.js b/entity/AnyContact_entity/titleProcess.js
index 383efef8d54..54d51a48576 100644
--- a/entity/AnyContact_entity/titleProcess.js
+++ b/entity/AnyContact_entity/titleProcess.js
@@ -1,8 +1,15 @@
 import("system.vars");
 import("system.result");
+import("Util_lib");
+import("Contact_lib");
 
-if(vars.get("$field.PERSON_FIRSTNAME")) {
-    result.string(vars.get("$field.PERSON_FIRSTNAME") + " " + vars.get("$field.PERSON_LASTNAME"));
-} else {
-    result.string(vars.get("$field.ORG_NAME"));
-}
+var contact = new Contact();
+contact.organisationName = vars.get("$field.ORGANISATION_NAME");
+contact.salutation = vars.get("$field.PERSON_SALUTATION");
+contact.title = vars.get("$field.PERSON_TITLE");
+contact.firstname = vars.get("$field.PERSON_FIRSTNAME");
+contact.middlename = vars.get("$field.PERSON_MIDDLENAME");
+contact.lastname = vars.get("$field.PERSON_LASTNAME");
+
+var renderer = new ContactTitleRenderer(contact);
+result.string(renderer.asString());
\ No newline at end of file
diff --git a/entity/Contract_entity/Contract_entity.aod b/entity/Contract_entity/Contract_entity.aod
index 366d5e798f0..50bea07aae4 100644
--- a/entity/Contract_entity/Contract_entity.aod
+++ b/entity/Contract_entity/Contract_entity.aod
@@ -380,10 +380,6 @@
           <name>CONTACT_PERSON_ID.value</name>
           <recordfield>CONTACT.PERSON_ID</recordfield>
         </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>ORG_NAME.value</name>
-          <recordfield>ORGANISATION.NAME</recordfield>
-        </dbRecordFieldMapping>
         <dbRecordFieldMapping>
           <name>PERSON_FIRSTNAME.value</name>
           <recordfield>PERSON.FIRSTNAME</recordfield>
diff --git a/entity/Contract_entity/entityfields/contact_id/displayValueProcess.js b/entity/Contract_entity/entityfields/contact_id/displayValueProcess.js
index 5badfc772a9..85822946ab4 100644
--- a/entity/Contract_entity/entityfields/contact_id/displayValueProcess.js
+++ b/entity/Contract_entity/entityfields/contact_id/displayValueProcess.js
@@ -3,4 +3,4 @@ import("system.vars");
 import("Contact_lib");
 import("system.neon");
 
-result.string(RelationUtils.getNameByPersOrgWithRelationId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
+result.string(ContactUtils.getFullTitleByContactId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
diff --git a/entity/Contract_entity/entityfields/contact_id/linkedContextProcess.js b/entity/Contract_entity/entityfields/contact_id/linkedContextProcess.js
index 242297cdf0e..e678b842c5b 100644
--- a/entity/Contract_entity/entityfields/contact_id/linkedContextProcess.js
+++ b/entity/Contract_entity/entityfields/contact_id/linkedContextProcess.js
@@ -2,4 +2,4 @@ import("system.vars");
 import("system.result");
 import("Contact_lib");
 
-result.string(RelationUtils.getContextByRelationId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
+result.string(ContactUtils.getContextByRelationId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/contact_id/displayValueProcess.js b/entity/Offer_entity/entityfields/contact_id/displayValueProcess.js
index ef417d00db9..08ad146eeef 100644
--- a/entity/Offer_entity/entityfields/contact_id/displayValueProcess.js
+++ b/entity/Offer_entity/entityfields/contact_id/displayValueProcess.js
@@ -4,4 +4,4 @@ import("Contact_lib");
 import("system.neon");
 
 
-result.string(RelationUtils.getNameByPersOrgWithRelationId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
+result.string(ContactUtils.getFullTitleByContactId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/contact_id/linkedContextProcess.js b/entity/Offer_entity/entityfields/contact_id/linkedContextProcess.js
index 242297cdf0e..e678b842c5b 100644
--- a/entity/Offer_entity/entityfields/contact_id/linkedContextProcess.js
+++ b/entity/Offer_entity/entityfields/contact_id/linkedContextProcess.js
@@ -2,4 +2,4 @@ import("system.vars");
 import("system.result");
 import("Contact_lib");
 
-result.string(RelationUtils.getContextByRelationId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
+result.string(ContactUtils.getContextByRelationId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/salesproject_id/mandatoryProcess.js b/entity/Offer_entity/entityfields/salesproject_id/mandatoryProcess.js
index 419ee8c0b68..05b1f9bd5c0 100644
--- a/entity/Offer_entity/entityfields/salesproject_id/mandatoryProcess.js
+++ b/entity/Offer_entity/entityfields/salesproject_id/mandatoryProcess.js
@@ -2,7 +2,7 @@ import("system.vars");
 import("system.result");
 import("Contact_lib");
 
-var type = RelationUtils.getRelationType(vars.get("$field.CONTACT_ID"), vars.get("$field.CONTACT_PERSON_ID"), vars.get("$field.CONTACT_ORG_ID"));
+var type = ContactUtils.getRelationType(vars.get("$field.CONTACT_ID"), vars.get("$field.CONTACT_PERSON_ID"), vars.get("$field.CONTACT_ORG_ID"));
 
 result.string(type != 2);
 
diff --git a/entity/Order_entity/entityfields/contact_id/displayValueProcess.js b/entity/Order_entity/entityfields/contact_id/displayValueProcess.js
index 5badfc772a9..85822946ab4 100644
--- a/entity/Order_entity/entityfields/contact_id/displayValueProcess.js
+++ b/entity/Order_entity/entityfields/contact_id/displayValueProcess.js
@@ -3,4 +3,4 @@ import("system.vars");
 import("Contact_lib");
 import("system.neon");
 
-result.string(RelationUtils.getNameByPersOrgWithRelationId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
+result.string(ContactUtils.getFullTitleByContactId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
diff --git a/entity/Order_entity/entityfields/contact_id/linkedContextProcess.js b/entity/Order_entity/entityfields/contact_id/linkedContextProcess.js
index 242297cdf0e..e678b842c5b 100644
--- a/entity/Order_entity/entityfields/contact_id/linkedContextProcess.js
+++ b/entity/Order_entity/entityfields/contact_id/linkedContextProcess.js
@@ -2,4 +2,4 @@ import("system.vars");
 import("system.result");
 import("Contact_lib");
 
-result.string(RelationUtils.getContextByRelationId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
+result.string(ContactUtils.getContextByRelationId(vars.getString("$field.CONTACT_ID")));
\ No newline at end of file
diff --git a/entity/Person_entity/Person_entity.aod b/entity/Person_entity/Person_entity.aod
index bd05c9fadc0..3d0148e0b00 100644
--- a/entity/Person_entity/Person_entity.aod
+++ b/entity/Person_entity/Person_entity.aod
@@ -326,7 +326,6 @@ Usually this is used for filtering COMMUNICATION-entries by a specified contact
         <element>FIRSTNAME</element>
         <element>MIDDLENAME</element>
         <element>LASTNAME</element>
-        <element>TITLESUFFIX</element>
       </fields>
     </entityFieldGroup>
     <entityProvider>
diff --git a/entity/Person_entity/entityfields/full_name_fieldgroup/valueProcess.js b/entity/Person_entity/entityfields/full_name_fieldgroup/valueProcess.js
index c39d231e9c0..b3a098ff143 100644
--- a/entity/Person_entity/entityfields/full_name_fieldgroup/valueProcess.js
+++ b/entity/Person_entity/entityfields/full_name_fieldgroup/valueProcess.js
@@ -1,9 +1,14 @@
 import("system.vars");
 import("system.result");
+import("Util_lib");
+import("Contact_lib");
 
-result.string((vars.get("$field.SALUTATION") ? vars.get("$field.SALUTATION") + " " : "")
-            + (vars.get("$field.TITLE") ? vars.get("$field.TITLE") + " " : "")
-            + (vars.get("$field.FIRSTNAME") ? vars.get("$field.FIRSTNAME") + " " : "")
-            + (vars.get("$field.MIDDLENAME") ? vars.get("$field.MIDDLENAME") + " " : "")
-            + (vars.get("$field.LASTNAME") ? vars.get("$field.LASTNAME") + " " : "")
-            + vars.get("$field.TITLESUFFIX"))
\ No newline at end of file
+var contact = new Contact();
+contact.salutation = vars.get("$field.SALUTATION");
+contact.title = vars.get("$field.TITLE");
+contact.firstname = vars.get("$field.FIRSTNAME");
+contact.middlename = vars.get("$field.MIDDLENAME");
+contact.lastname = vars.get("$field.LASTNAME");
+
+var renderer = new ContactTitleRenderer(contact, null);
+result.string(renderer.asString());
\ No newline at end of file
diff --git a/entity/SalesprojectCompetition_entity/SalesprojectCompetition_entity.aod b/entity/SalesprojectCompetition_entity/SalesprojectCompetition_entity.aod
index d7defd58150..a19aebab162 100644
--- a/entity/SalesprojectCompetition_entity/SalesprojectCompetition_entity.aod
+++ b/entity/SalesprojectCompetition_entity/SalesprojectCompetition_entity.aod
@@ -72,7 +72,7 @@
       <linkedContext>Organisation</linkedContext>
     </entityField>
     <entityField>
-      <name>ORG_NAME</name>
+      <name>ORGANISATION_NAME</name>
       <state>READONLY</state>
       <onValueChangeTypes>
         <element>MASK</element>
@@ -262,7 +262,7 @@
           <recordfield>SALESPROJECT_COMPETITION.INFO</recordfield>
         </dbRecordFieldMapping>
         <dbRecordFieldMapping>
-          <name>ORG_NAME.value</name>
+          <name>ORGANISATION_NAME.value</name>
           <recordfield>ORGANISATION.NAME</recordfield>
         </dbRecordFieldMapping>
         <dbRecordFieldMapping>
diff --git a/entity/SalesprojectMember_entity/SalesprojectMember_entity.aod b/entity/SalesprojectMember_entity/SalesprojectMember_entity.aod
index 31b0b9d4890..5b62c806fc7 100644
--- a/entity/SalesprojectMember_entity/SalesprojectMember_entity.aod
+++ b/entity/SalesprojectMember_entity/SalesprojectMember_entity.aod
@@ -56,7 +56,7 @@
       <description>PARAMETER</description>
     </entityParameter>
     <entityField>
-      <name>ORG_NAME</name>
+      <name>ORGANISATION_NAME</name>
       <title>Company</title>
       <state>READONLY</state>
     </entityField>
@@ -211,7 +211,7 @@ TODO: intuitive möglichkeit, auf dend Stand aus Relation zurückzusetzen... akt
       </linkInformation>
       <recordFieldMappings>
         <dbRecordFieldMapping>
-          <name>ORG_NAME.value</name>
+          <name>ORGANISATION_NAME.value</name>
           <recordfield>ORGANISATION.NAME</recordfield>
         </dbRecordFieldMapping>
         <dbRecordFieldMapping>
diff --git a/neonView/AnyContactLookup_view/AnyContactLookup_view.aod b/neonView/AnyContactLookup_view/AnyContactLookup_view.aod
index 4273a0ee681..38784a6ed13 100644
--- a/neonView/AnyContactLookup_view/AnyContactLookup_view.aod
+++ b/neonView/AnyContactLookup_view/AnyContactLookup_view.aod
@@ -18,7 +18,7 @@
         </neonTableColumn>
         <neonTableColumn>
           <name>ca59a64a-adce-49c3-93ad-2978c81809f8</name>
-          <entityField>ORG_NAME</entityField>
+          <entityField>ORGANISATION_NAME</entityField>
         </neonTableColumn>
         <neonTableColumn>
           <name>814b3f18-106a-443e-8415-762669f862e6</name>
diff --git a/neonView/PersonPreview_view/PersonPreview_view.aod b/neonView/PersonPreview_view/PersonPreview_view.aod
index ae395531ab7..a46e953f3c5 100644
--- a/neonView/PersonPreview_view/PersonPreview_view.aod
+++ b/neonView/PersonPreview_view/PersonPreview_view.aod
@@ -11,7 +11,7 @@
     <cardViewTemplate>
       <name>PersHeader_template</name>
       <iconField>IMAGE</iconField>
-      <titleField>NAME_fieldGroup</titleField>
+      <titleField>FULL_NAME_fieldGroup</titleField>
       <descriptionField>ORGANISATION_ID</descriptionField>
       <entityField>#ENTITY</entityField>
     </cardViewTemplate>
diff --git a/neonView/SalesprojectMemberFilter_view/SalesprojectMemberFilter_view.aod b/neonView/SalesprojectMemberFilter_view/SalesprojectMemberFilter_view.aod
index bd7d56408d9..325028978da 100644
--- a/neonView/SalesprojectMemberFilter_view/SalesprojectMemberFilter_view.aod
+++ b/neonView/SalesprojectMemberFilter_view/SalesprojectMemberFilter_view.aod
@@ -15,7 +15,7 @@
       <columns>
         <neonTableColumn>
           <name>27e658bc-c134-4fef-a3a5-b172852d606e</name>
-          <entityField>ORG_NAME</entityField>
+          <entityField>ORGANISATION_NAME</entityField>
         </neonTableColumn>
         <neonTableColumn>
           <name>59e6aea1-9752-48b5-9d91-43edd0c1d670</name>
diff --git a/process/Contact_lib/process.js b/process/Contact_lib/process.js
index 019c9557e71..dfe2c88b7b0 100644
--- a/process/Contact_lib/process.js
+++ b/process/Contact_lib/process.js
@@ -3,6 +3,7 @@ import("system.vars");
 import("system.result");
 import("system.db");
 import("Sql_lib");
+import("Util_lib");
 import("Context_lib");
 
 /**
@@ -11,7 +12,7 @@ import("Context_lib");
  * Do not create an instance of this!
  * @class
  */
-function RelationUtils() {}
+function ContactUtils() {}
 
 /**
  * Get the type of contact. <br>
@@ -38,15 +39,15 @@ function RelationUtils() {}
  *                      2 if privat person <br>
  *                      3 if person of an organisation <br>
  */
-RelationUtils.getRelationType = function(pRelationId, pPersId, pOrgId)
+ContactUtils.getRelationType = function(pRelationId, pPersId, pOrgId)
 {
     if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW || vars.get("$sys.recordstate") == neon.OPERATINGSTATE_EDIT)
     {
-        return RelationUtils.getRelationTypeByRelation(pRelationId);
+        return ContactUtils.getRelationTypeByRelation(pRelationId);
     }
     else
     {
-        return RelationUtils.getRelationTypeByPersOrg(pPersId, pOrgId);
+        return ContactUtils.getRelationTypeByPersOrg(pPersId, pOrgId);
     }
 }
 
@@ -60,9 +61,9 @@ RelationUtils.getRelationType = function(pRelationId, pPersId, pOrgId)
  *                  2 if privat person <br>
  *                  3 if person of an organisation <br>
  */
-RelationUtils.getRelationTypeByRelation = function(pRelationId)
+ContactUtils.getRelationTypeByRelation = function(pRelationId)
 {
-    var relationData = RelationUtils.getPersOrgIds(pRelationId);
+    var relationData = ContactUtils.getPersOrgIds(pRelationId);
     if (relationData[0]) 
     {
         return this.getRelationTypeByPersOrg(relationData[1], relationData[2]);
@@ -95,7 +96,7 @@ RelationUtils.getRelationTypeByRelation = function(pRelationId)
  *                      2 if privat person <br>
  *                      3 if person of an organisation <br>
  */
-RelationUtils.getRelationTypeByPersOrg = function(pPersId, pOrgId)
+ContactUtils.getRelationTypeByPersOrg = function(pPersId, pOrgId)
 {
     if (!pPersId)
     {
@@ -138,9 +139,9 @@ RelationUtils.getRelationTypeByPersOrg = function(pPersId, pOrgId)
  * 
  * @return {String} contextname or "" if both ids are empty
  */
-RelationUtils.getContextByPersOrg = function(pPersId, pOrgId)
+ContactUtils.getContextByPersOrg = function(pPersId, pOrgId)
 {
-    switch (RelationUtils.getRelationTypeByPersOrg(pPersId, pOrgId))
+    switch (ContactUtils.getRelationTypeByPersOrg(pPersId, pOrgId))
     {
         case 1: // Org
             return ContextUtils.getContextName("Organisation");
@@ -159,10 +160,10 @@ RelationUtils.getContextByPersOrg = function(pPersId, pOrgId)
  * @param {String} pRelationId
  * @return {String} contextname or "" if contact not found
  */
-RelationUtils.getContextByRelationId = function(pRelationId)
+ContactUtils.getContextByRelationId = function(pRelationId)
 {
-    var relationData = RelationUtils.getPersOrgIds(pRelationId);
-    return RelationUtils.getContextByPersOrg(relationData[1], relationData[2])
+    var relationData = ContactUtils.getPersOrgIds(pRelationId);
+    return ContactUtils.getContextByPersOrg(relationData[1], relationData[2])
 }
 
 /**
@@ -171,7 +172,7 @@ RelationUtils.getContextByRelationId = function(pRelationId)
  * @param {String} pRelationId
  * @return {String[]} result as [persid, orgid] if one of them is null in the db, "" will be returned as the id.
  */
-RelationUtils.getPersOrgIds = function(pRelationId)
+ContactUtils.getPersOrgIds = function(pRelationId)
 {
     if (pRelationId) {
         return db.array(db.ROW, 
@@ -186,58 +187,27 @@ RelationUtils.getPersOrgIds = function(pRelationId)
 
 /**
  * get the name of the person or organisation
- * The parameters have to be selected from the same contact.
  * 
- * @param {String} pPersId value of the person_id selected from CONTACT
- * @param {String} pOrgId value of the org_id selected from CONTACT
- * @param {String} pPersFirstname value of the firstname selected from PERSON
- * @param {String} pPersLastname value of the lastname selected from PERSON
- * @param {String} pOrgname value of the name selected from ORGANISATION
- * @param {String} [pTitle=undefined] value of the title selected from PERSON. You can ommit this parameter if you do not want to append the title
+ * @param {String} pContactId the contact id where pers-name or orgname shall be loaded
  * 
  * @return {String} the name or ""
  */
-RelationUtils.getNameByPersOrg = function(pPersId, pOrgId, pPersFirstname, 
-                                            pPersLastname, pOrgname, pTitle)
+ContactUtils.getFullTitleByContactId = function(pContactId)
 {
-    if(!pPersId && !pOrgId)
-        return "";
-    else 
+    if (pContactId) 
     {
-        switch (RelationUtils.getRelationTypeByPersOrg(pPersId, pOrgId))
-        {
-            case 1: // Org   
-                return pOrgname;
-            case 2: // private Person
-            case 3: // Person
-                var name = "";
-                
-                if (pTitle != undefined && pTitle)
-                    name = pTitle + " ";
-               
-                return name + pPersFirstname.concat(" " , pPersLastname);
-            default:
-                return "";
-        }
-    }
-}
-
-/**
- * get the name of the person or organisation
- * 
- * @param {String} pRelationId the contact id
- * @param {Boolean} [pTitle=false] also add the title for persons
- * 
- * @return {String} the name or ""
- */
-RelationUtils.getNameByPersOrgWithRelationId = function(pRelationId, pTitle)
-{
-    if (pRelationId) {
         var data = db.array(db.ROW, SqlCondition.begin()
-                            .andPrepare("CONTACT.CONTACTID", pRelationId)
-                            .buildSql("select CONTACT.PERSON_ID, CONTACT.ORGANISATION_ID, PERSON.FIRSTNAME, PERSON.LASTNAME, PERSON.TITLE, ORGANISATION.NAME from CONTACT CONTACT join ORGANISATION on ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID left join PERSON on PERSON.PERSONID = CONTACT.PERSON_ID", "1 = 2"));                                    
- 
-        return RelationUtils.getNameByPersOrg(data[0], data[1], data[2], data[3], data[5], (pTitle ? data[4] : undefined));
+                .andPrepare("CONTACT.CONTACTID", pContactId)
+                .buildSql("select ORGANISATION.NAME, PERSON.SALUTATION, PERSON.TITLE, PERSON.FIRSTNAME, PERSON.MIDDLENAME, PERSON.LASTNAME "
+                    + "from CONTACT CONTACT "
+                    + "join ORGANISATION on ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID "
+                    + "left join PERSON on PERSON.PERSONID = CONTACT.PERSON_ID", "1 = 2"));
+        if (data.length == 0)
+            return "";
+        var contact = new Contact();
+        [contact.organisationName, contact.salutation, contact.title, contact.firstname, contact.middlename, contact.lastname] = data;
+        var renderer = new ContactTitleRenderer(contact);
+        return renderer.asString();
     }
     
     return "";
@@ -248,28 +218,165 @@ RelationUtils.getNameByPersOrgWithRelationId = function(pRelationId, pTitle)
  *
  * @return {String}
  */
-RelationUtils.getFullRelationFromString = function()
+ContactUtils.getFullRelationString = function()
 {
     return " CONTACT join ORGANISATION on ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID"
     + " left join PERSON on PERSON.PERSONID = CONTACT.PERSON_ID"
     + " left join ADDRESS on ADDRESS.ADDRESSID = CONTACT.ADDRESS_ID";
 }
 
+
 /**
- * returns the select string for the contact joined with org, person, address 
- *  
- * @param {String} pIdField field used as id
+ * object for handling of a single contact
+ * provides static- and instance-functions
+ * 
+ * @class
  *
- * @return {String}
  */
-RelationUtils.getFullRelationSelectString = function(pIdField)
+function Contact()
 {
-    if(pIdField == undefined)
-        pIdField = "CONTACTID";
+    //storage for information
+    this.salutation = "";
+    this.title = "";
+    this.firstname= "";
+    this.middlename = "";
+    this.lastname = "";
+    this.suffix = "";
 
-    var maskingUtils = new SqlMaskingUtils();
+    this.customercode = "";
+    this.organisationName = "";
+    
+    this._contactType = Contact.TYPES.Auto;
+}
 
-    return " " + pIdField + ","
-    + maskingUtils.concat( [ maskingUtils.concat(["SALUTATION", "TITLE", "FIRSTNAME", "LASTNAME"]) , "NAME"], " - " ) +  " as anzeige, "
-    + "CUSTOMERCODE, NAME, ZIP, CITY, TITLE, FIRSTNAME, LASTNAME ";
-}
\ No newline at end of file
+/**
+ * sets the contactType of a contact
+ * reserved for future implementation
+ * 
+ * @param {String} pContactType contactType that shall be set; value of Contact.TYPES.
+ *
+ * @return void
+ */
+Contact.prototype.setContactType = function (pContactType)
+{
+    if (! ObjectUtils.existsValue(Contact.TYPES, pContactType))
+        throw new TypeError("the given contact type is not a valid value and not a contact type");
+    
+    this._contactType = pContactType;
+};
+
+/**
+ * returns the contactType of a contact
+ * reserved for future implementation
+ * 
+ * @return {String} the contactType is a value of Contact.TYPES.
+ */
+Contact.prototype.getContactType = function ()
+{
+    return this._contactType;
+};
+
+/**
+ * constants for types of Contacts
+ * use only within functions
+ * reserved for future implementation
+ * 
+ * @static
+ */
+Contact.TYPES = {
+    Organisation: "organisation",
+    Contact: "contact",
+    Private: "private",
+    Auto: null
+};
+
+/**
+ * creates a new Contact-object with a preset of DB-columns
+ * 
+ * @static
+ */
+Contact.createWithColumnPreset = function()
+{
+    var contact = new Contact();
+    contact.salutation = "PERSON.SALUTATION";
+    contact.title = "PERSON.TITLE";
+    contact.firstname= "PERSON.FIRSTNAME";
+    contact.middlename = "PERSON.MIDDLENAME";
+    contact.lastname = "PERSON.LASTNAME";
+    contact.suffix = "PERSON.TITLESUFFIX";
+    contact.customercode = "ORGANISATION.CUSTOMERCODE";
+    contact.organisationName = "ORGANISATION.NAME";
+    return contact;
+};
+
+/**
+ * object for rendering a Contact-object into text representation or an sql that represents the text
+ * provides static- and instance-functions
+ * 
+ * @param {Contact} pContact The Contact-object to render
+ * @param {Number} pOptions additional options for rendering; use values of ContactTitleRenderer.OPTIONS and pass them by bitwise OR concatination; e.g.:
+ *                  OPTION_1 | OPTION_2 | OPTION_5
+ * 
+ * @class
+ *
+ */
+function ContactTitleRenderer(pContact, pOptions)
+{
+    this.contact = pContact;
+    if (pOptions !== undefined)//null means null which is "no option"; so check exactly for undefined
+        this._options = pOptions;
+    else 
+        this._options = ContactTitleRenderer.OPTIONS.IncludeOrganisation;
+    
+    //function that renders the contact into a sql expression (e.g. for a subselect)
+    this._asSqlFn = function(){
+        var maskingUtil = new SqlMaskingUtils();
+        var res = maskingUtil.concat([this.contact.salutation, this.contact.title, this.contact.firstname, this.contact.middlename, this.contact.lastname].filter(function (e){
+            return e != "";
+        }), " ");
+        if (this._options & ContactTitleRenderer.OPTIONS.IncludeOrganisation && this.contact.organisationName)
+            res = maskingUtil.concat([res, this.contact.organisationName], " | ");
+        return res;
+    };
+    
+    //function that renders the contact into a text  (e.g. for a displayValue)
+    this._asStringFn = function (){
+        var res = StringUtils.concat(" ", [this.contact.salutation, this.contact.title, this.contact.firstname, this.contact.middlename, this.contact.lastname]);
+
+        if (this._options & ContactTitleRenderer.OPTIONS.IncludeOrganisation && this.contact.organisationName)
+            res = StringUtils.concat(" | ", [res, this.contact.organisationName]);
+        return res;
+    }
+}
+
+/**
+ * constants for options for the ContactTitleRenderer
+ * use only within functions
+ * 
+ * @static
+ */
+ContactTitleRenderer.OPTIONS = {
+    IncludeOrganisation: 1
+};
+
+/**
+ * function that renders the contact into a sql expression (e.g. for a subselect)
+ * what this function exactly does depends on specified values and options specified in the Renderer-object
+ * 
+ * @return {String} sql-expression that can be placed inside a select statement
+ */
+ContactTitleRenderer.prototype.asSql = function ()
+{
+    return this._asSqlFn.apply(this, arguments);
+};
+
+/**
+ * function that renders the contact into text
+ * what this function exactly does depends on specified values and options specified in the Renderer-object
+ * 
+ * @return {String} rendered values as text
+ */
+ContactTitleRenderer.prototype.asString = function ()
+{
+    return this._asStringFn.apply(this, arguments);
+};
diff --git a/process/Person_lib/process.js b/process/Person_lib/process.js
index c5ad5751f56..2fe262fac3e 100644
--- a/process/Person_lib/process.js
+++ b/process/Person_lib/process.js
@@ -1,6 +1,7 @@
 import("system.result");
 import("Binary_lib");
 import("Sql_lib");
+import("Contact_lib");
 
 /**
  * a static Utility class for the Person context.
@@ -55,9 +56,12 @@ PersUtils.removeImage = function(pPersId)
  */
 PersUtils.getResolvingDisplaySubSql = function(pRelationIdField)
 {
-    var maskingHelper = new SqlMaskingUtils();
-    //TODO: verify if there is a better solution for the usage of this as a displayValueExpression --> automatic use of #TITLE
-    return "select " + maskingHelper.concat(["PERSON.FIRSTNAME", "PERSON.LASTNAME"]) + "from PERSON \n\
+    var contact = Contact.createWithColumnPreset();
+    var renderer = new ContactTitleRenderer(contact, null);
+    var selectExpression = renderer.asSql();
+
+    //TODO: verify if there is a better solution for the usage of this as a displayValueExpression --> automatic use of #TITLE | waiting vor implementation
+    return "select " + selectExpression + "from PERSON \n\
         join CONTACT on (PERSON.PERSONID = CONTACT.PERSON_ID) \n\
         where CONTACT.CONTACTID = " + pRelationIdField;
 }
\ No newline at end of file
diff --git a/process/PostalAddress_lib/process.js b/process/PostalAddress_lib/process.js
index c18e69398a8..2a57f0955fb 100644
--- a/process/PostalAddress_lib/process.js
+++ b/process/PostalAddress_lib/process.js
@@ -3,6 +3,7 @@ import("system.db");
 import("Sql_lib");
 import("Contact_lib");
 import("Keyword_lib");
+import("Util_lib");
 /**
  * Methods for addresses.
  * Todo: evtl. übernahme / anpassung der Adresslib aus altem Basic. 1030856
@@ -26,17 +27,7 @@ function AddressUtils(){}
  */
 AddressUtils.formatOneline = function (pCountry, pAddressLine, pBuildingNo, pZipCode, pCity)
 {
-    var country = pCountry || "";
-    var addressLine = pAddressLine || "";
-    var buildingNo = pBuildingNo || "";
-    var zipCode = pZipCode || "";
-    var city = pCity || "";
-    return [country, addressLine, buildingNo, zipCode, city]
-    .filter(function (v)
-    {
-        return v != "";
-    })
-    .join(", ");
+    return StringUtils.concat(", ", [pCountry, pAddressLine, pBuildingNo, pZipCode, pCity]);
 };
 
 /**
@@ -47,7 +38,7 @@ AddressUtils.formatOneline = function (pCountry, pAddressLine, pBuildingNo, pZip
  * @return {String}
  */
 AddressUtils.getAddress = function(pRelationId) {
-    var address = db.array(db.ROW, SqlCondition.begin().andPrepare("CONTACT.CONTACTID", pRelationId).buildSql('select CONTACTID, ADDRESS, BUILDINGNO, ZIP, CITY, "NAME", FIRSTNAME, LASTNAME, TITLE from' + RelationUtils.getFullRelationFromString(), "1=0"));
+    var address = db.array(db.ROW, SqlCondition.begin().andPrepare("CONTACT.CONTACTID", pRelationId).buildSql('select CONTACTID, ADDRESS, BUILDINGNO, ZIP, CITY, "NAME", FIRSTNAME, LASTNAME, TITLE from' + ContactUtils.getFullRelationString(), "1=0"));
     
     // TODO: currently there are some relations without standard address. Use Hardcoded one.
     if (!address[1]) {
@@ -58,7 +49,7 @@ AddressUtils.getAddress = function(pRelationId) {
         address[4] = dummyAddress[3];
         
     }
-    var type = RelationUtils.getRelationTypeByRelation(pRelationId);
+    var type = ContactUtils.getRelationTypeByRelation(pRelationId);
     
     return AddressUtils.formatAddress(type, address[1], address[2], address[3], address[4], address[5], address[6], address[7], address[8]);
 }
@@ -86,7 +77,7 @@ AddressUtils.getAddressById = function(pAddressId) {
         address[4] = dummyAddress[4];
         
     }
-    var type = RelationUtils.getRelationTypeByRelation(address[0]);   
+    var type = ContactUtils.getRelationTypeByRelation(address[0]);   
 
     var names = db.array(db.ROW, SqlCondition.begin()
                                              .andPrepare("CONTACT.CONTACTID", address[0])
diff --git a/process/Sql_lib/process.js b/process/Sql_lib/process.js
index bfe2e058415..e677069ded2 100644
--- a/process/Sql_lib/process.js
+++ b/process/Sql_lib/process.js
@@ -859,7 +859,10 @@ SqlMaskingUtils.prototype.concat = function(fields, separatorCharacter, autoTrim
             retSql += " case when " + _isNotEmpty(fields[i + 1]) + " then " + _trimIfAutoTrimEnabled(fields[i]) + separatorSql + " else " + _trimIfAutoTrimEnabled(fields[i]) + " end "; 
         else
             retSql += _trimIfAutoTrimEnabled(fields[i]);
-        retSql += " else '' end ";
+        //this blank is used just as in the old concat function which means this concat function has the same (wrong) behaviour
+        //TODO: find way to fix the case when separator is not a whitepsace (e.g. space)
+        //this concat-function does not work properly if you concat [<<value>>, <<null>>, <<value>>] by comma
+        retSql += " else ' ' end ";
     }
     return retSql;
 }
diff --git a/process/Util_lib/process.js b/process/Util_lib/process.js
index b27d5d9c3c8..3b5cc6b0949 100644
--- a/process/Util_lib/process.js
+++ b/process/Util_lib/process.js
@@ -14,6 +14,31 @@ import("system.datetime");
 import("Offer_lib");
 import("Date_lib");
 
+/**
+ * Class containing static utility functions for string-actions
+ * Do not create an instance of this
+ * 
+ * @class
+ */
+function StringUtils(){}
+
+/**
+ * concats severel elements by a separator; the separator is only applied if a element is not null and not an empty string "";
+ *
+ * @param {String} pSeparator specifies how the not empty elements shall be concatenated
+ * @param {String[]} pElements elements that shall be joined by the separator 
+ *
+ * @return {String} concatenated string; if all elements are empty an emtpy string is returned
+ * 
+ */
+StringUtils.concat = function(pSeparator, pElements)
+{
+   var res = pElements.filter(function(e){
+       return e != null && e != "";
+   }).join(pSeparator);
+   return res;
+};
+
 /**
  * Class containing static utility functions for use with arrays
  * Do not create an instance of this!
@@ -348,6 +373,33 @@ JSONUtils.customStringify = function(obj) {
     return stringify(obj);
 }
 
+/**
+ * Class containing functions for Javascript-Objects
+ * Do not create an instance of this
+ * 
+ * @class
+ */
+function ObjectUtils(){}
+
+/**
+ * checks if a value exists in the object
+ * mostly usefull for primitve datatypes
+ * 
+ * @param pObject {Object} the object where the value is searched
+ * @param pValue  {Boolean|Number|String} the value that is searched
+ * 
+ * @return {Boolean} true if the value was found, false if not
+ */
+ObjectUtils.existsValue = function(pObject, pValue)
+{
+    for (var key in pObject)
+    {
+        if (pObject[key] === pValue)
+            return true;
+    }
+    return false;
+};
+
 /**
  * Class containing functions for sequential numbers
  * Do not create an instance of this!
-- 
GitLab