From 3bd8c1ff8487f02d11b8af4dbc08c70e691d9acc Mon Sep 17 00:00:00 2001
From: "S.Listl" <S.Listl@SLISTL.aditosoftware.local>
Date: Wed, 12 Jun 2019 10:10:00 +0200
Subject: [PATCH] KeywordRegistry fix

---
 process/Address_lib/process.js           | 946 +++++++++++------------
 process/KeywordRegistry_basic/process.js |   7 +-
 2 files changed, 476 insertions(+), 477 deletions(-)

diff --git a/process/Address_lib/process.js b/process/Address_lib/process.js
index 5f543024e9..cc782a7e24 100644
--- a/process/Address_lib/process.js
+++ b/process/Address_lib/process.js
@@ -1,474 +1,474 @@
-import("system.swing");
-import("system.text");
-import("system.db");
-import("system.logging");
-import("system.vars");
-import("system.translate");
-import("Attribute_lib");
-import("Sql_lib");
-import("Util_lib");
-import("DocumentTemplate_lib");
-
-/*
-* Creates a Address Object
-* 
-* @param {String} pRelationID req relationid for which address should be retrieved
-* @param {String} pAddressID opt addressid for which address should be retrieved
-* @param {boolean} pPerson whether the address is from a person, not an organisation
-*  
-* @return {String} the formatted address
-*/
-
-function AddrObject( pRelationID, pPerson, pAddressID )
-{
-    this.Data = fetchAddressData( [ pRelationID ] , [["", "addressformat", ""]], pAddressID, pPerson );
-    this.fmt = this.Data[0][0][26]; 
-	
-    /*
-    * creates a formatted address
-    * 
-    * @param {boolean} pCountry whether the country should be displayed
-    * @param {String} pFormat a fixed format for the address
-    * 
-    * @return {String} formatted address
-    */
-    this.getFormattedAddress = function( pCountry, pFormat )
-    {	
-        return _formatAddrData( _getAddrData(  this.Data[0][0] ), pFormat, pCountry );
-    }
-}
-
-/*
-* creates address data
-* 
-* @param {String} pCondition req SQL-Where-Condition  
-* @param {Object []} pConfig req ( name, functionality, details )
-* @param {String} pSenderID opt UserRelationID
-* @param {String} pAddressID opt addressid
-* 
-* @return {[]}  Daten 
-*/
-function getAddressesData( pCondition, pConfig, pSenderID, pAddressID )
-{ 
-    var returndata = [];
-    var senderconfig = [];
-    var employeeconfig = [];
-    var config = [];
-    for (let i = 0; i < pConfig.length; i++)
-    {
-        switch (pConfig[i].target)
-        {
-            case PlaceholderUtils.targets.EMPLOYEE:
-                employeeconfig.push(pConfig[i]);
-                break;
-            case PlaceholderUtils.targets.SENDER:
-                senderconfig.push(pConfig[i]);
-                break;
-            case PlaceholderUtils.targets.RECIPIENT:
-            default:
-                config.push(pConfig[i]);
-                break;
-        } 
-    }
-    var data = getAddressData(pCondition, config, pAddressID);
-    if (pSenderID == undefined)  pSenderID = vars.get("$global.user").relationid;
-    if (senderconfig.length > 0) 
-        var senderdata = getAddressData([pSenderID], senderconfig);
-    if (employeeconfig.length > 0) 
-        var employeedata = getAddressData([vars.get("$global.user").relationid], employeeconfig);
-    if (data.length > 0 && (senderconfig.length > 0 || employeeconfig.length > 0))
-    { 
-        var ze = data[0];
-        if (employeeconfig.length > 0) ze = ze.concat(employeedata[0]);
-        if (senderconfig.length > 0) ze = ze.concat(senderdata[0]); 
-        returndata.push(ze);
-        for (let i = 1; i < data.length; i++)
-        {
-            ze = data[i];
-            if (employeeconfig.length > 0) ze = ze.concat(employeedata[1]);
-            if (senderconfig.length > 0) ze = ze.concat(senderdata[1]); 
-            returndata.push(ze);
-        }
-        return returndata;
-    }
-    else return data;
-}
-
-/*
-* creates
-* 
-* @param {String} pCondition req SQL-Where-Condition  
-* @param {Placeholder[]} pConfig req array of placeholders
-* @param {String} AddressID opt addressid
-* 
-* @return {[]}  Daten 
-*/
-function getAddressData( pCondition, pConfig, AddressID )
-{ 
-    return setAddressData( fetchAddressData( pCondition, pConfig, AddressID ) );
-}
-
-/*
-* reads data from the database
-* 
-* @param {String} pCondition req SQL-Where-Condition  
-* @param {Placeholder[]} pConfig req array of placeholders
-* @param {String} AddressID opt addressid
-* @param {boolean} pPerson opt if private person
-* 
-* @return {Array} 2d-Array, structure: [[ data, output, header, addrfields ]]
-*/
-function fetchAddressData( pCondition, pConfig, AddressID, pPerson )
-{ 
-    if ( typeof(pCondition) == "object") pCondition = "CONTACT.CONTACTID in ('" + pCondition.join("','") + "')";
-    if ( pConfig.length > 0 )
-    { 
-        var header = [];
-        var fields = [];
-        var output = [];
-        var pos = 0;
-        var posaddrfields = -1;
-        var functionCalls = [];
-        var addrfields = ["case when CONTACT.PERSON_ID is null then 1 else case when " + SqlMaskingUtils.prototype.trim("CONTACT.ORGANISATION_ID") + " = '0' then 2 else 3 end end", //0
-        "ADDRESS.ADDRESS", "ADDRESS.BUILDINGNO", "ADDRESS.ZIP", "ADDRESS.CITY", "ADDRESS.COUNTRY", "ADDRESS.ADDRESSADDITION",  // 1-6
-        "ADDRESS.ADDRIDENTIFIER", "ADDRESS.DISTRICT", "ADDRESS.REGION", "ADDRESS.STATE", "CONTACT.DEPARTMENT", "CONTACT.CONTACTROLE", // 7-12
-        "CONTACT.POSITION", "CONTACT.LETTERSALUTATION", "ORGANISATION.NAME", "PERSON.FIRSTNAME", "PERSON.MIDDLENAME", "PERSON.LASTNAME",  // 13-18
-        "PERSON.SALUTATION", "PERSON.TITLE", "PERSON.TITLESUFFIX", // 19-21
-        "coalesce( CONTACT.LANGUAGE, (select C.LANGUAGE from CONTACT C where C.ORGANISATION_ID = CONTACT.ORGANISATION_ID and PERSON_ID is null))", // 22
-        "''", "''", "''", "(select ADDR_FORMAT from AB_COUNTRYINFO where ISO2 = ADDRESS.COUNTRY)", "ADDRESS.ADDR_TYPE"]; // 23-27
-											
-        for (let i=0; i < pConfig.length; i++ )
-        {
-            switch( pConfig[i].type )
-            {
-                case PlaceholderUtils.types.SQLPART: //sql part
-                    fields.push( pConfig[i].valueDefinition ); //TODO: maybe do vars.resolveVariables
-                    output.push([pos++, pConfig[i].type]);
-                    header.push( pConfig[i].placeholderName );
-                    break;
-                case PlaceholderUtils.types.SQLPARTFUNCTION: // adito SQL functions
-                    fields.push(pConfig[i].valueDefinition.call());
-                    output.push([pos++, pConfig[i].type]);
-                    header.push( pConfig[i].placeholderName );
-                    break;
-                case "afunction": // adito functions
-                    try
-                    {
-                        fields.push( "'" + evalScript("Address_lib.fetchAddressData", vars.resolveVariables(pConfig[i].valueDefinition), {}, ["Attribute_lib", "Sql_lib", "Keyword_lib", "Person_lib"], true).replace(new RegExp("'","g"), "''") + "'" ); 
-                        output.push([pos++, pConfig[i].type]);
-                        header.push( pConfig[i].placeholderName );
-                    }
-                    catch( err )
-                    {                      
-                        logging.log( err )
-                    }
-                    break;
-                case "select": // Subselects
-                    fields.push( "(" + vars.resolveVariables(pConfig[i].valueDefinition) + " )" );
-                    output.push([pos++, pConfig[i].type]);
-                    header.push( pConfig[i].placeholderName );
-                    break;
-                case PlaceholderUtils.types.ADDRESSFORMAT:
-                    if ( posaddrfields == -1 )
-                    {        
-                        var sortfields = ["ORGANISATION.NAME", "PERSON.LASTNAME"];
-                        fields.push( addrfields.join(", ") );
-                        posaddrfields = pos;
-                        pos += addrfields.length;								
-                    }
-                    output.push([posaddrfields, pConfig[i].type, pConfig[i].valueDefinition]);
-                    header.push( pConfig[i].placeholderName );
-                    break;
-                case "resolveIDFunction":
-                    var configJSON = pConfig[i].valueDefinition;
-                    fields.push( configJSON.rowIDField );
-
-                    functionCalls.push([pos,
-                        configJSON.resolveFunction,
-                        configJSON.imports,
-                        configJSON.localVars]);
-                                    
-                    output.push([pos++, pConfig[i].type]);
-                    header.push( pConfig[i].placeholderName );                
-                    break;
-            }
-        }
-        if (!pPerson) {           
-            var sqlstr =  "select " + fields.join(",") 
-            + " from CONTACT join ORGANISATION on CONTACT.ORGANISATION_ID = ORGANISATION.ORGANISATIONID "
-            + " left join PERSON on CONTACT.PERSON_ID = PERSON.PERSONID "
-            + " left join ADDRESS on CONTACT.ADDRESS_ID = ";
-        } else {
-            
-            sqlstr = "select " + fields.join(",")
-            + " from CONTACT join PERSON on CONTACT.PERSON_ID = PERSON.PERSONID "
-            + " left join ORGANISATION on CONTACT.ORGANISATION_ID = ORGANISATION.ORGANISATIONID "
-            + " left join ADDRESS on CONTACT.ADDRESS_ID = ";
-        }
-        
-        if ( AddressID != undefined && AddressID != "" )  sqlstr += "'" + AddressID + "'"; 
-        else sqlstr += "ADDRESS.ADDRESSID";
-        if ( pCondition != "" ) sqlstr += " where " + pCondition;
-        var data = db.table(sqlstr + (sortfields != undefined ? " order by " + sortfields.join(", ") : "" ));
-
-        // loop over all returned datasets
-        for(let j = 0; j < data.length; j++)
-        {
-            // loop over all possible resolveFunction entries
-            for(let k = 0; k < functionCalls.length; k++ )
-            {
-                // get the local variables, which should be present in the function call
-                var localVars = functionCalls[k][3];
-                // add the row id value to the localVars Object so the funtion can gather the data for this dataset
-                localVars.rowIDValue = data[j][ functionCalls[k][0] ];
-                // replace the row id with its base64 string
-                data[j][ functionCalls[k][0] ] = evalScript("Address_lib.fetchAddressData.resolveFunction", 
-                    vars.resolveVariables( functionCalls[k][1]+"()" ), 
-                    localVars, 
-                    functionCalls[k][2], // imports
-                    true);
-            }
-        }
-        
-        if ( data.length == 0 ) 
-        {   
-            logging.log("Address_lib: " +  pCondition, logging.ERROR);
-            data = [[]];
-            for (let i = 0; i < addrfields.length + fields.length; i++ )   data[0].push("Err.");
-        }
-        data = [ data, output, header, addrfields ];
-    }
-    return data;
-}
-
-/*
-* reads data from the database
-* 
-* @param {String [[]]} pData req array of data
-* 
-* @return {String [[]]}  data 
-*/
-function setAddressData( pData )
-{ 
-    var sqlresult = pData[0];
-    var data = [];
-    if ( sqlresult.length > 0 )
-    {
-        var output = pData[1]; 
-        var header = pData[2];
-        var addrfields = pData[3];
-        data.push( header );
-        for ( var i = 0; i < sqlresult.length; i++ )
-        {		
-            var addrdata = [];
-            var row = [];	
-            for ( var z = 0; z < header.length; z++ )
-            {
-                switch( output[z][1] )
-                {
-                    case PlaceholderUtils.types.SQLPART:
-                    case PlaceholderUtils.types.SQLPARTFUNCTION:
-                    case "afunction":
-                    case "resolveIDFunction":
-                    case "select":
-                        row[z] = sqlresult[i][output[z][0]];
-                        break;
-                    case PlaceholderUtils.types.ADDRESSFORMAT:
-                        if (addrdata.length == 0) addrdata = _getAddrData( sqlresult[i].slice(output[z][0], output[z][0] + addrfields.length) );
-                        row[z] = _formatAddrData( addrdata, output[z][2] );
-                        break;
-                }
-            }
-            data.push( row );
-        }
-    }
-    return data;
-}
-/*
-*
-* returns formatted address data
-*
-* @param {String [[]]} pData req data 
-*
-* @return {String [[]]} formatted data
-*/
-function _getAddrData( pData )
-{
-    var lettersalutation = pData[14];
-    var salutation = pData[19];
-    var sformat = "";
-    switch( Number(pData[0]) )
-    {
-        case 1:
-            if ( lettersalutation == "" ) 
-            {
-                sformat = _getSalutation( pData[22] );
-                if ( sformat != undefined && sformat[1] != "" ) lettersalutation = _formatAddrData( pData,  sformat[1] );
-                else lettersalutation = "Sehr geehrte Damen und Herren";
-            }
-            break;
-        case 2:
-            // private -> orgname deleted
-            pData[15] = "";
-        case 3:
-            sformat = _getSalutation( pData[22] + pData[19] + pData[20] );
-            //no language defined
-            if ( sformat == undefined )  sformat = _getSalutation( pData[19] + pData[20] );
-            // no language specific entry in salutation
-            if ( sformat == undefined || sformat[0] == "" || sformat[1] == "" )	sformat = ["{sa} {ti} {fn} {la}", "{sa} {ti} {ln}"];
-            salutation = _formatAddrData( pData,  sformat[0] );
-            // lettersalutation if none existent yet
-            if( lettersalutation == "" ) lettersalutation = _formatAddrData( pData, sformat[1] );
-    }
-
-    pData[23] = salutation;
-    pData[24] = lettersalutation;
-    pData[25] = _getCountryName(pData[5]);
-    return pData;
-}
-
-/*
-* returns a formatted salutation
-* 
-* @param {String} pSalutCode req salutation code
-* 
-* @return {String} translated salutation
-*/
-function _getSalutation( pSalutCode )
-{
-    var salut = new Object();
-    if (vars.exists("$global.Salutation")) {
-        salut = vars.get("$global.Salutation");
-    }
-    else
-    {	
-        var list = db.table("select LANGUAGE, SALUTATION, TITLE, HEADLINE, LETTERSALUTATION from SALUTATION" );
-        for ( var i = 0; i < list.length; i++ )	
-        {   
-            salut[list[i][0] + list[i][1] + list[i][2]] = [list[i][3], list[i][4]];
-            salut[list[i][1] + list[i][2]] = [list[i][3], list[i][4]];
-        }
-        vars.set("$global.Salutation", salut);
-    }
-    return salut[pSalutCode];
-}
-
-/*
-* returns country names 
-*
-* @param {String} pCountryCode req countrycode
-*
-* @return {String} translated countryname
-*/
-function _getCountryName(pCountryCode)
-{
-    var countryname = new Object();
-    if ( vars.exists("$global.CountryName")) countryname = vars.get("$global.CountryName");
-    else
-    {	
-        var list = db.table("select ISO2, NAME_NATIVE from AB_COUNTRYINFO" );
-        for (var i=0; i < list.length; i++ )	countryname[list[i][0]] = translate.text(list[i][1]);
-        vars.set("$global.CountryName", countryname);
-    }
-    return countryname[pCountryCode];
-}
-
-/*
-* returns a formatted address
-*
-* @param {String [[]]} pAddrData req Address data 
-* @param {String} pFormat opt given format
-* @param {boolean} pCountry if the country should be displayed
-*
-* @return {String} formatted address
-*/
-function _formatAddrData( pAddrData, pFormat, pCountry )
-{
-    var placeholerInfo = {
-        "street":       {dataPosition: 1},
-        "buildingno":   {dataPosition: 2},
-        "zip":          {dataPosition: 3},
-        "city":         {dataPosition: 4},
-        "district":     {dataPosition: 8},
-        "region":       {dataPosition: 9},
-        "state":        {dataPosition: 10},
-        "firstname":    {dataPosition: 16},
-        "middlename":   {dataPosition: 17},
-        "lastname":     {dataPosition: 18},
-        "saluation":    {dataPosition: 19},
-        "title":        {dataPosition: 20},
-        "suffix":       {dataPosition: 21},
-        "country":      {dataPosition: 25},
-        "organisation_name":    {dataPosition: 15},
-        "salutation_name":      {dataPosition: 23},
-        "letter_salutation":    {dataPosition: 24}
-    };
-
-    var format = pFormat || pAddrData[26];       
-    format = _mapFormatPlaceholderTitles(format, pAddrData, pCountry);
-    
-    var res = format;    
-    for (var placeholder in placeholerInfo)
-    {
-        var currentAddrData = pAddrData[placeholerInfo[placeholder].dataPosition];
-        if (currentAddrData != undefined)
-        {
-            res = res.replace(new RegExp("{" + placeholder + "}", "g"), currentAddrData);
-            res = res.replace(new RegExp("{" + placeholder.toUpperCase() + "}", "g"), currentAddrData.toUpperCase());
-        }
-    }
-
-    res = res.replace(/^\n/, "");  // CR am Anfang entfernen;
-    res = res.replace(/  /g, " "); // doppelte leerzeichen entfernen
-    res = res.replace(/\\n/ig, "\n");	// newline marker ersetzen
-    res = res.replace(/ *\n */g, "\n");// leerzeichen am ende und Anfang entfernen
-    res = res.replace(/\s(?=\s)/g, "");	// leerzeilen rauswerfen
-    return res;
-}
-
-/*
-* returns the new format 
-*
-* @param {String [[]]} pAddrData req Daten 
-* @param {String} pFormat req the format string
-* @param {boolean} pCountry if the country should be displayed
-*
-* @return {String} new formate
-* 
-N – Name - salutation
-O – Organisation - orgname
-A – Street Address Line(s) - address + buildingno
-D – Dependent locality - district / region
-C – City or Locality - city
-S – Administrative area - state
-Z – Zip or postal code - zip
-X – Sorting code - not available
-*/
-function _mapFormatPlaceholderTitles(pFormat, pAddrData, pCountry) 
-{
-    //gstatic-paceholders
-    pFormat = pFormat.replace(new RegExp("%N", "g"), "{salutation_name}");
-    pFormat = pFormat.replace(new RegExp("%A", "g"), "{street} {buildingno}");  
-    pFormat = pFormat.replace(new RegExp("%C", "g"), "{city}");
-    pFormat = pFormat.replace(new RegExp("%S", "g"), "{state}");
-    pFormat = pFormat.replace(new RegExp("%Z", "g"), "{zip}");
-    pFormat = pFormat.replace(new RegExp("%O", "g"), "{organisation_name}");
-    pFormat = pFormat.replace(new RegExp("%X", "g"), "");   
-    pFormat = pFormat.replace(new RegExp("%n", "g"), "\n");
-    
-    //shortform adito-placeholders
-    pFormat = pFormat.replace(new RegExp("{fn}", "g"), "{firstname}");
-    pFormat = pFormat.replace(new RegExp("{ln}", "g"), "{lastname}");
-    pFormat = pFormat.replace(new RegExp("{ti}", "g"), "{title}");
-    pFormat = pFormat.replace(new RegExp("{sa}", "g"), "{salutation}");
-    
-    if (pAddrData[8] == pAddrData[9])
-        pFormat = pFormat.replace(new RegExp("%D", "g"), "{district}");
-    else
-        pFormat = pFormat.replace(new RegExp("%D", "g"), "{district} \n {region}");   
-    
-    if(pCountry == undefined || pCountry == null || pCountry == true)
-        pFormat = pFormat + "\n {country}";
-    
-    return pFormat;
+import("system.swing");
+import("system.text");
+import("system.db");
+import("system.logging");
+import("system.vars");
+import("system.translate");
+import("Attribute_lib");
+import("Sql_lib");
+import("Util_lib");
+import("DocumentTemplate_lib");
+
+/*
+* Creates a Address Object
+* 
+* @param {String} pRelationID req relationid for which address should be retrieved
+* @param {String} pAddressID opt addressid for which address should be retrieved
+* @param {boolean} pPerson whether the address is from a person, not an organisation
+*  
+* @return {String} the formatted address
+*/
+
+function AddrObject( pRelationID, pPerson, pAddressID )
+{
+    this.Data = fetchAddressData( [ pRelationID ] , [["", "addressformat", ""]], pAddressID, pPerson );
+    this.fmt = this.Data[0][0][26]; 
+	
+    /*
+    * creates a formatted address
+    * 
+    * @param {boolean} pCountry whether the country should be displayed
+    * @param {String} pFormat a fixed format for the address
+    * 
+    * @return {String} formatted address
+    */
+    this.getFormattedAddress = function( pCountry, pFormat )
+    {	
+        return _formatAddrData( _getAddrData(  this.Data[0][0] ), pFormat, pCountry );
+    }
+}
+
+/*
+* creates address data
+* 
+* @param {String} pCondition req SQL-Where-Condition  
+* @param {Object []} pConfig req ( name, functionality, details )
+* @param {String} pSenderID opt UserRelationID
+* @param {String} pAddressID opt addressid
+* 
+* @return {[]}  Daten 
+*/
+function getAddressesData( pCondition, pConfig, pSenderID, pAddressID )
+{ 
+    var returndata = [];
+    var senderconfig = [];
+    var employeeconfig = [];
+    var config = [];
+    for (let i = 0; i < pConfig.length; i++)
+    {
+        switch (pConfig[i].target)
+        {
+            case PlaceholderUtils.targets.EMPLOYEE:
+                employeeconfig.push(pConfig[i]);
+                break;
+            case PlaceholderUtils.targets.SENDER:
+                senderconfig.push(pConfig[i]);
+                break;
+            case PlaceholderUtils.targets.RECIPIENT:
+            default:
+                config.push(pConfig[i]);
+                break;
+        } 
+    }
+    var data = getAddressData(pCondition, config, pAddressID);
+    if (pSenderID == undefined)  pSenderID = vars.get("$global.user").relationid;
+    if (senderconfig.length > 0) 
+        var senderdata = getAddressData([pSenderID], senderconfig);
+    if (employeeconfig.length > 0) 
+        var employeedata = getAddressData([vars.get("$global.user").relationid], employeeconfig);
+    if (data.length > 0 && (senderconfig.length > 0 || employeeconfig.length > 0))
+    { 
+        var ze = data[0];
+        if (employeeconfig.length > 0) ze = ze.concat(employeedata[0]);
+        if (senderconfig.length > 0) ze = ze.concat(senderdata[0]); 
+        returndata.push(ze);
+        for (let i = 1; i < data.length; i++)
+        {
+            ze = data[i];
+            if (employeeconfig.length > 0) ze = ze.concat(employeedata[1]);
+            if (senderconfig.length > 0) ze = ze.concat(senderdata[1]); 
+            returndata.push(ze);
+        }
+        return returndata;
+    }
+    else return data;
+}
+
+/*
+* creates
+* 
+* @param {String} pCondition req SQL-Where-Condition  
+* @param {Placeholder[]} pConfig req array of placeholders
+* @param {String} AddressID opt addressid
+* 
+* @return {[]}  Daten 
+*/
+function getAddressData( pCondition, pConfig, AddressID )
+{ 
+    return setAddressData( fetchAddressData( pCondition, pConfig, AddressID ) );
+}
+
+/*
+* reads data from the database
+* 
+* @param {String} pCondition req SQL-Where-Condition  
+* @param {Placeholder[]} pConfig req array of placeholders
+* @param {String} AddressID opt addressid
+* @param {boolean} pPerson opt if private person
+* 
+* @return {Array} 2d-Array, structure: [[ data, output, header, addrfields ]]
+*/
+function fetchAddressData( pCondition, pConfig, AddressID, pPerson )
+{ 
+    if ( typeof(pCondition) == "object") pCondition = "CONTACT.CONTACTID in ('" + pCondition.join("','") + "')";
+    if ( pConfig.length > 0 )
+    { 
+        var header = [];
+        var fields = [];
+        var output = [];
+        var pos = 0;
+        var posaddrfields = -1;
+        var functionCalls = [];
+        var addrfields = ["case when CONTACT.PERSON_ID is null then 1 else case when " + SqlMaskingUtils.prototype.trim("CONTACT.ORGANISATION_ID") + " = '0' then 2 else 3 end end", //0
+        "ADDRESS.ADDRESS", "ADDRESS.BUILDINGNO", "ADDRESS.ZIP", "ADDRESS.CITY", "ADDRESS.COUNTRY", "ADDRESS.ADDRESSADDITION",  // 1-6
+        "ADDRESS.ADDRIDENTIFIER", "ADDRESS.DISTRICT", "ADDRESS.REGION", "ADDRESS.STATE", "CONTACT.DEPARTMENT", "CONTACT.CONTACTROLE", // 7-12
+        "CONTACT.POSITION", "CONTACT.LETTERSALUTATION", "ORGANISATION.NAME", "PERSON.FIRSTNAME", "PERSON.MIDDLENAME", "PERSON.LASTNAME",  // 13-18
+        "PERSON.SALUTATION", "PERSON.TITLE", "PERSON.TITLESUFFIX", // 19-21
+        "coalesce( CONTACT.LANGUAGE, (select C.LANGUAGE from CONTACT C where C.ORGANISATION_ID = CONTACT.ORGANISATION_ID and PERSON_ID is null))", // 22
+        "''", "''", "''", "(select ADDR_FORMAT from AB_COUNTRYINFO where ISO2 = ADDRESS.COUNTRY)", "ADDRESS.ADDR_TYPE"]; // 23-27
+											
+        for (let i=0; i < pConfig.length; i++ )
+        {
+            switch( pConfig[i].type )
+            {
+                case PlaceholderUtils.types.SQLPART: //sql part
+                    fields.push( pConfig[i].valueDefinition ); //TODO: maybe do vars.resolveVariables
+                    output.push([pos++, pConfig[i].type]);
+                    header.push( pConfig[i].placeholderName );
+                    break;
+                case PlaceholderUtils.types.SQLPARTFUNCTION: // adito SQL functions
+                    fields.push(pConfig[i].valueDefinition.call());
+                    output.push([pos++, pConfig[i].type]);
+                    header.push( pConfig[i].placeholderName );
+                    break;
+                case "afunction": // adito functions
+                    try
+                    {
+                        fields.push( "'" + evalScript("Address_lib.fetchAddressData", vars.resolveVariables(pConfig[i].valueDefinition), {}, ["Attribute_lib", "Sql_lib", "Keyword_lib", "Person_lib"], true).replace(new RegExp("'","g"), "''") + "'" ); 
+                        output.push([pos++, pConfig[i].type]);
+                        header.push( pConfig[i].placeholderName );
+                    }
+                    catch( err )
+                    {                      
+                        logging.log( err )
+                    }
+                    break;
+                case "select": // Subselects
+                    fields.push( "(" + vars.resolveVariables(pConfig[i].valueDefinition) + " )" );
+                    output.push([pos++, pConfig[i].type]);
+                    header.push( pConfig[i].placeholderName );
+                    break;
+                case PlaceholderUtils.types.ADDRESSFORMAT:
+                    if ( posaddrfields == -1 )
+                    {        
+                        var sortfields = ["ORGANISATION.NAME", "PERSON.LASTNAME"];
+                        fields.push( addrfields.join(", ") );
+                        posaddrfields = pos;
+                        pos += addrfields.length;								
+                    }
+                    output.push([posaddrfields, pConfig[i].type, pConfig[i].valueDefinition]);
+                    header.push( pConfig[i].placeholderName );
+                    break;
+                case "resolveIDFunction":
+                    var configJSON = pConfig[i].valueDefinition;
+                    fields.push( configJSON.rowIDField );
+
+                    functionCalls.push([pos,
+                        configJSON.resolveFunction,
+                        configJSON.imports,
+                        configJSON.localVars]);
+                                    
+                    output.push([pos++, pConfig[i].type]);
+                    header.push( pConfig[i].placeholderName );                
+                    break;
+            }
+        }
+        if (!pPerson) {           
+            var sqlstr =  "select " + fields.join(",") 
+            + " from CONTACT join ORGANISATION on CONTACT.ORGANISATION_ID = ORGANISATION.ORGANISATIONID "
+            + " left join PERSON on CONTACT.PERSON_ID = PERSON.PERSONID "
+            + " left join ADDRESS on CONTACT.ADDRESS_ID = ";
+        } else {
+            
+            sqlstr = "select " + fields.join(",")
+            + " from CONTACT join PERSON on CONTACT.PERSON_ID = PERSON.PERSONID "
+            + " left join ORGANISATION on CONTACT.ORGANISATION_ID = ORGANISATION.ORGANISATIONID "
+            + " left join ADDRESS on CONTACT.ADDRESS_ID = ";
+        }
+        
+        if ( AddressID != undefined && AddressID != "" )  sqlstr += "'" + AddressID + "'"; 
+        else sqlstr += "ADDRESS.ADDRESSID";
+        if ( pCondition != "" ) sqlstr += " where " + pCondition;
+        var data = db.table(sqlstr + (sortfields != undefined ? " order by " + sortfields.join(", ") : "" ));
+
+        // loop over all returned datasets
+        for(let j = 0; j < data.length; j++)
+        {
+            // loop over all possible resolveFunction entries
+            for(let k = 0; k < functionCalls.length; k++ )
+            {
+                // get the local variables, which should be present in the function call
+                var localVars = functionCalls[k][3];
+                // add the row id value to the localVars Object so the funtion can gather the data for this dataset
+                localVars.rowIDValue = data[j][ functionCalls[k][0] ];
+                // replace the row id with its base64 string
+                data[j][ functionCalls[k][0] ] = evalScript("Address_lib.fetchAddressData.resolveFunction", 
+                    vars.resolveVariables( functionCalls[k][1]+"()" ), 
+                    localVars, 
+                    functionCalls[k][2], // imports
+                    true);
+            }
+        }
+        
+        if ( data.length == 0 ) 
+        {   
+            logging.log("Address_lib: " +  pCondition, logging.ERROR);
+            data = [[]];
+            for (let i = 0; i < addrfields.length + fields.length; i++ )   data[0].push("Err.");
+        }
+        data = [ data, output, header, addrfields ];
+    }
+    return data;
+}
+
+/*
+* reads data from the database
+* 
+* @param {String [[]]} pData req array of data
+* 
+* @return {String [[]]}  data 
+*/
+function setAddressData( pData )
+{ 
+    var sqlresult = pData[0];
+    var data = [];
+    if ( sqlresult.length > 0 )
+    {
+        var output = pData[1]; 
+        var header = pData[2];
+        var addrfields = pData[3];
+        data.push( header );
+        for ( var i = 0; i < sqlresult.length; i++ )
+        {		
+            var addrdata = [];
+            var row = [];	
+            for ( var z = 0; z < header.length; z++ )
+            {
+                switch( output[z][1] )
+                {
+                    case PlaceholderUtils.types.SQLPART:
+                    case PlaceholderUtils.types.SQLPARTFUNCTION:
+                    case "afunction":
+                    case "resolveIDFunction":
+                    case "select":
+                        row[z] = sqlresult[i][output[z][0]];
+                        break;
+                    case PlaceholderUtils.types.ADDRESSFORMAT:
+                        if (addrdata.length == 0) addrdata = _getAddrData( sqlresult[i].slice(output[z][0], output[z][0] + addrfields.length) );
+                        row[z] = _formatAddrData( addrdata, output[z][2], false );
+                        break;
+                }
+            }
+            data.push( row );
+        }
+    }
+    return data;
+}
+/*
+*
+* returns formatted address data
+*
+* @param {String [[]]} pData req data 
+*
+* @return {String [[]]} formatted data
+*/
+function _getAddrData( pData )
+{
+    var lettersalutation = pData[14];
+    var salutation = pData[19];
+    var sformat = "";
+    switch( Number(pData[0]) )
+    {
+        case 1:
+            if ( lettersalutation == "" ) 
+            {
+                sformat = _getSalutation( pData[22] );
+                if ( sformat != undefined && sformat[1] != "" ) lettersalutation = _formatAddrData( pData,  sformat[1] );
+                else lettersalutation = "Sehr geehrte Damen und Herren";
+            }
+            break;
+        case 2:
+            // private -> orgname deleted
+            pData[15] = "";
+        case 3:
+            sformat = _getSalutation( pData[22] + pData[19] + pData[20] );
+            //no language defined
+            if ( sformat == undefined )  sformat = _getSalutation( pData[19] + pData[20] );
+            // no language specific entry in salutation
+            if ( sformat == undefined || sformat[0] == "" || sformat[1] == "" )	sformat = ["{sa} {ti} {fn} {la}", "{sa} {ti} {ln}"];
+            salutation = _formatAddrData( pData,  sformat[0] );
+            // lettersalutation if none existent yet
+            if( lettersalutation == "" ) lettersalutation = _formatAddrData( pData, sformat[1] );
+    }
+
+    pData[23] = salutation;
+    pData[24] = lettersalutation;
+    pData[25] = _getCountryName(pData[5]);
+    return pData;
+}
+
+/*
+* returns a formatted salutation
+* 
+* @param {String} pSalutCode req salutation code
+* 
+* @return {String} translated salutation
+*/
+function _getSalutation( pSalutCode )
+{
+    var salut = new Object();
+    if (vars.exists("$global.Salutation")) {
+        salut = vars.get("$global.Salutation");
+    }
+    else
+    {	
+        var list = db.table("select LANGUAGE, SALUTATION, TITLE, HEADLINE, LETTERSALUTATION from SALUTATION" );
+        for ( var i = 0; i < list.length; i++ )	
+        {   
+            salut[list[i][0] + list[i][1] + list[i][2]] = [list[i][3], list[i][4]];
+            salut[list[i][1] + list[i][2]] = [list[i][3], list[i][4]];
+        }
+        vars.set("$global.Salutation", salut);
+    }
+    return salut[pSalutCode];
+}
+
+/*
+* returns country names 
+*
+* @param {String} pCountryCode req countrycode
+*
+* @return {String} translated countryname
+*/
+function _getCountryName(pCountryCode)
+{
+    var countryname = new Object();
+    if ( vars.exists("$global.CountryName")) countryname = vars.get("$global.CountryName");
+    else
+    {	
+        var list = db.table("select ISO2, NAME_NATIVE from AB_COUNTRYINFO" );
+        for (var i=0; i < list.length; i++ )	countryname[list[i][0]] = translate.text(list[i][1]);
+        vars.set("$global.CountryName", countryname);
+    }
+    return countryname[pCountryCode];
+}
+
+/*
+* returns a formatted address
+*
+* @param {String [[]]} pAddrData req Address data 
+* @param {String} pFormat opt given format
+* @param {boolean} pCountry if the country should be displayed
+*
+* @return {String} formatted address
+*/
+function _formatAddrData( pAddrData, pFormat, pCountry )
+{
+    var placeholerInfo = {
+        "street":       {dataPosition: 1},
+        "buildingno":   {dataPosition: 2},
+        "zip":          {dataPosition: 3},
+        "city":         {dataPosition: 4},
+        "district":     {dataPosition: 8},
+        "region":       {dataPosition: 9},
+        "state":        {dataPosition: 10},
+        "firstname":    {dataPosition: 16},
+        "middlename":   {dataPosition: 17},
+        "lastname":     {dataPosition: 18},
+        "saluation":    {dataPosition: 19},
+        "title":        {dataPosition: 20},
+        "suffix":       {dataPosition: 21},
+        "country":      {dataPosition: 25},
+        "organisation_name":    {dataPosition: 15},
+        "salutation_name":      {dataPosition: 23},
+        "letter_salutation":    {dataPosition: 24}
+    };
+
+    var format = pFormat || pAddrData[26];       
+    format = _mapFormatPlaceholderTitles(format, pAddrData, pCountry);
+    
+    var res = format;    
+    for (var placeholder in placeholerInfo)
+    {
+        var currentAddrData = pAddrData[placeholerInfo[placeholder].dataPosition];
+        if (currentAddrData != undefined)
+        {
+            res = res.replace(new RegExp("{" + placeholder + "}", "g"), currentAddrData);
+            res = res.replace(new RegExp("{" + placeholder.toUpperCase() + "}", "g"), currentAddrData.toUpperCase());
+        }
+    }
+
+    res = res.replace(/^\n/, "");  // CR am Anfang entfernen;
+    res = res.replace(/  /g, " "); // doppelte leerzeichen entfernen
+    res = res.replace(/\\n/ig, "\n");	// newline marker ersetzen
+    res = res.replace(/ *\n */g, "\n");// leerzeichen am ende und Anfang entfernen
+    res = res.replace(/\s(?=\s)/g, "");	// leerzeilen rauswerfen
+    return res;
+}
+
+/*
+* returns the new format 
+*
+* @param {String [[]]} pAddrData req Daten 
+* @param {String} pFormat req the format string
+* @param {boolean} pCountry if the country should be displayed
+*
+* @return {String} new formate
+* 
+N – Name - salutation
+O – Organisation - orgname
+A – Street Address Line(s) - address + buildingno
+D – Dependent locality - district / region
+C – City or Locality - city
+S – Administrative area - state
+Z – Zip or postal code - zip
+X – Sorting code - not available
+*/
+function _mapFormatPlaceholderTitles(pFormat, pAddrData, pCountry) 
+{
+    //gstatic-paceholders
+    pFormat = pFormat.replace(new RegExp("%N", "g"), "{salutation_name}");
+    pFormat = pFormat.replace(new RegExp("%A", "g"), "{street} {buildingno}");  
+    pFormat = pFormat.replace(new RegExp("%C", "g"), "{city}");
+    pFormat = pFormat.replace(new RegExp("%S", "g"), "{state}");
+    pFormat = pFormat.replace(new RegExp("%Z", "g"), "{zip}");
+    pFormat = pFormat.replace(new RegExp("%O", "g"), "{organisation_name}");
+    pFormat = pFormat.replace(new RegExp("%X", "g"), "");   
+    pFormat = pFormat.replace(new RegExp("%n", "g"), "\n");
+    
+    //shortform adito-placeholders
+    pFormat = pFormat.replace(new RegExp("{fn}", "g"), "{firstname}");
+    pFormat = pFormat.replace(new RegExp("{ln}", "g"), "{lastname}");
+    pFormat = pFormat.replace(new RegExp("{ti}", "g"), "{title}");
+    pFormat = pFormat.replace(new RegExp("{sa}", "g"), "{salutation}");
+    
+    if (pAddrData[8] == pAddrData[9])
+        pFormat = pFormat.replace(new RegExp("%D", "g"), "{district}");
+    else
+        pFormat = pFormat.replace(new RegExp("%D", "g"), "{district} \n {region}");   
+    
+    if(pCountry == undefined || pCountry == null || pCountry == true)
+        pFormat = pFormat + "\n {country}";
+    
+    return pFormat;
 }
\ No newline at end of file
diff --git a/process/KeywordRegistry_basic/process.js b/process/KeywordRegistry_basic/process.js
index b910a20ea3..146e36621b 100644
--- a/process/KeywordRegistry_basic/process.js
+++ b/process/KeywordRegistry_basic/process.js
@@ -102,8 +102,7 @@ $KeywordRegistry.classificationType = function(){return "ClassificationType";};
 $KeywordRegistry.classificationType$salesproject = function(){return "968eafa3-3e76-4afa-8999-878e51cc3bab";};
 $KeywordRegistry.personGender = function(){return "PersonGender";};
 $KeywordRegistry.personGender$other = function(){return "o";};
-$KeywordRegistry.permissionCondType = function(){return "Perurn "PermissionAccessType";};
+$KeywordRegistry.permissionCondType = function(){return "PermissionCondType";};
+$KeywordRegistry.permissionAccessType = function(){return "PermissionAccessType";};
 
-$KeywordRegistry.textPlaceholder = function(){return "textPlaceholder";};
-
-$KeywordRegistry.communicationMediumCampaign = function(){return "CommunicationMediumCampaign";};
+$KeywordRegistry.communicationMediumCampaign = function(){return "CommunicationMediumCampaign";};
-- 
GitLab