From 42266985cc9fb2814d32a9250c062abc0ff574cd Mon Sep 17 00:00:00 2001
From: Michaela Kuhn <m.kuhn@adito.de>
Date: Wed, 3 Apr 2019 11:56:08 +0200
Subject: [PATCH] lib_address as Address_lib integration

---
 .../Data_alias/basic/2019.2/changelog.xml     |   1 +
 .../Contact_additionalColumns.xml             |   9 +
 process/Address_lib/Address_lib.aod           |   9 +
 process/Address_lib/process.js                | 445 ++++++++++++++++++
 4 files changed, 464 insertions(+)
 create mode 100644 .liquibase/Data_alias/basic/2019.2/miscellaneous/Contact_additionalColumns.xml
 create mode 100644 process/Address_lib/Address_lib.aod
 create mode 100644 process/Address_lib/process.js

diff --git a/.liquibase/Data_alias/basic/2019.2/changelog.xml b/.liquibase/Data_alias/basic/2019.2/changelog.xml
index 17c4d2d767..2f7b975b9e 100644
--- a/.liquibase/Data_alias/basic/2019.2/changelog.xml
+++ b/.liquibase/Data_alias/basic/2019.2/changelog.xml
@@ -148,4 +148,5 @@
     <include relativeToChangelogFile="true" file="addDefaultAddresses.xml" context="example"/>
     
     <include relativeToChangelogFile="true" file="activity_rename_Creator_to_Responsible.xml" />
+    <include relativeToChangelogFile="true" file="miscellaneous/Contact_additionalColumns.xml" />
 </databaseChangeLog>
diff --git a/.liquibase/Data_alias/basic/2019.2/miscellaneous/Contact_additionalColumns.xml b/.liquibase/Data_alias/basic/2019.2/miscellaneous/Contact_additionalColumns.xml
new file mode 100644
index 0000000000..83081ee094
--- /dev/null
+++ b/.liquibase/Data_alias/basic/2019.2/miscellaneous/Contact_additionalColumns.xml
@@ -0,0 +1,9 @@
+<?xml version="1.1" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
+    
+    <changeSet author="j.goderbauer" id="bd41fff1-d139-41ea-ad0f-b30b77d69690">
+        <addColumn tableName="CONTACT">
+            <column name="LETTERSALUTATION" type="NVARCHAR(200)" />
+        </addColumn>
+    </changeSet>
+</databaseChangeLog>
\ No newline at end of file
diff --git a/process/Address_lib/Address_lib.aod b/process/Address_lib/Address_lib.aod
new file mode 100644
index 0000000000..5e7cbd6ac0
--- /dev/null
+++ b/process/Address_lib/Address_lib.aod
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1">
+  <name>Address_lib</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <process>%aditoprj%/process/Address_lib/process.js</process>
+  <variants>
+    <element>LIBRARY</element>
+  </variants>
+</process>
diff --git a/process/Address_lib/process.js b/process/Address_lib/process.js
new file mode 100644
index 0000000000..5827d6bbe8
--- /dev/null
+++ b/process/Address_lib/process.js
@@ -0,0 +1,445 @@
+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");
+
+/*
+* 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 {String [[]]} 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 ( var i = 0; i < pConfig.length; i++ )
+    {
+        var type = pConfig[i][1].split(".");
+        switch( type[0] )
+        {
+            case "employee":
+                employeeconfig.push([pConfig[i][0], type[1], pConfig[i][2]]);
+                break;
+            case "sender":
+                senderconfig.push([pConfig[i][0], type[1], pConfig[i][2]]);
+                break;
+            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 ( 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 {String [[]]} pConfig req ( name, functionality, details )
+* @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 {String [[]]} pConfig req ( name, functionality, details )
+* @param {String} AddressID opt addressid
+* @param {boolean} pPerson opt if private person
+* 
+* @return {[]}  data 
+*/
+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 (var i=0; i < pConfig.length; i++ )
+        {
+            switch( pConfig[i][1] )
+            {
+                case "fieldname": // database fields
+                    fields.push( pConfig[i][2] );
+                    output.push([pos++, pConfig[i][1]]);
+                    header.push( pConfig[i][0] );
+                    break;
+                case "function": // adito SQL functions
+                    fields.push( evalScript("Address_lib.fetchAddressData", vars.resolveVariables(pConfig[i][2]), {}, ["Attribute_lib", "Sql_lib", "Keyword_lib", "Person_lib"], true) );
+                    output.push([pos++, pConfig[i][1]]);
+                    header.push( pConfig[i][0] );
+                    break;
+                case "afunction": // adito functions
+                    try
+                    {
+                        fields.push( "'" + evalScript("Address_lib.fetchAddressData", vars.resolveVariables(pConfig[i][2]), {}, ["Attribute_lib", "Sql_lib", "Keyword_lib", "Person_lib"], true).replace(new RegExp("'","g"), "''") + "'" ); 
+                        output.push([pos++, pConfig[i][1]]);
+                        header.push( pConfig[i][0] );
+                    }
+                    catch( err )
+                    {                      
+                        logging.log( err )
+                    }
+                    break;
+                case "select": // Subselects
+                    fields.push( "(" + vars.resolveVariables(pConfig[i][2]) + " )" );
+                    output.push([pos++, pConfig[i][1]]);
+                    header.push( pConfig[i][0] );
+                    break;
+                case "addressformat": // Addressformat
+                    if ( posaddrfields == -1 )
+                    {        
+                        var sortfields = ["ORGANISATION.NAME", "PERSON.LASTNAME"];
+                        fields.push( addrfields.join(", ") );
+                        posaddrfields = pos;
+                        pos += addrfields.length;								
+                    }
+                    output.push([posaddrfields, pConfig[i][1], pConfig[i][2]]);
+                    header.push( pConfig[i][0] );
+                    break;
+                case "resolveIDFunction":
+                    var configJSON = pConfig[i][2];
+                    fields.push( configJSON.rowIDField );
+
+                    functionCalls.push([pos,
+                        configJSON.resolveFunction,
+                        configJSON.imports,
+                        configJSON.localVars]);
+                                    
+                    output.push([pos++, pConfig[i][1]]);
+                    header.push( pConfig[i][0] );                
+                    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( var j = 0; j < data.length; j++)
+        {
+            // loop over all possible resolveFunction entries
+            for( var 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 ( 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 "fieldname":
+                    case "function":
+                    case "afunction":
+                    case "resolveIDFunction":
+                    case "select":
+                        row[z] = sqlresult[i][output[z][0]];
+                        break;
+                    case "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 placeholder = [["address_street", 1],["buildingno", 2],["zip", 3],["city", 4],["district", 8],["region", 9],["state", 10],["organisation_name", 15], //0-7
+    ["firstname", 16],["middlename", 17],["lastname", 18],["saluation", 19],["title", 20], ["suffix", 21], ["salutation_name", 23],["letter salutation", 24], ["country", 25]]; //8-16
+    var as = pAddrData[26];       
+    if ( pFormat != "" && pFormat != undefined) as = pFormat; 
+    as = _getFormatMapping(as, pAddrData, pCountry);
+    
+    for( var y = 0; y < placeholder.length; y++ )
+    {         
+        as = as.replace(new RegExp(placeholder[y][0], "g"), pAddrData[placeholder[y][1]]);
+        if (pAddrData[placeholder[y][1]] != undefined ) {
+            as = as.replace(new RegExp(placeholder[y][0].toUpperCase(), "g"), pAddrData[placeholder[y][1]].toUpperCase());         
+        }		
+    }
+	 	
+    as = as.replace(/^\n/, "");  // CR am Anfang entfernen;
+    as = as.replace(/  /g, " "); // doppelte leerzeichen entfernen
+    as = as.replace(/\\n/ig, "\n");	// newline marker ersetzen
+    as = as.replace(/ *\n */g, "\n");// leerzeichen am ende und Anfang entfernen
+    as = as.replace(/\s(?=\s)/g, "");	// leerzeilen rauswerfen
+    return as;
+}
+
+/*
+* returns the new format 
+*
+* @param {String [[]]} pAddrData req Daten 
+* @param {String} as 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 _getFormatMapping(as, pAddrData, pCountry) {
+    as = as.replace(new RegExp("%N", "g"), "salutation_name");   
+    as = as.replace(new RegExp("%A", "g"), "address_street buildingno");  
+    as = as.replace(new RegExp("%C", "g"), "city");
+    as = as.replace(new RegExp("%S", "g"), "state");
+    as = as.replace(new RegExp("%Z", "g"), "zip");
+    as = as.replace(new RegExp("%O", "g"), "organisation_name");
+    as = as.replace(new RegExp("%X", "g"), "");   
+    as = as.replace(new RegExp("%n", "g"), "\n");
+    as = as.replace(new RegExp("{fn}", "g"), "firstname");
+    as = as.replace(new RegExp("{ln}", "g"), "lastname");
+    as = as.replace(new RegExp("{ti}", "g"), "title");
+    as = as.replace(new RegExp("{sa}", "g"), "salutation");
+    
+    if (pAddrData[8] == pAddrData[9])  as = as.replace(new RegExp("%D", "g"), "district");
+    else as = as.replace(new RegExp("%D", "g"), "district \n region");   
+    if(pCountry == undefined || pCountry == null || pCountry == true) as = as + "\n country";
+    
+    return as;
+}
\ No newline at end of file
-- 
GitLab