diff --git a/.liquibase/Data_alias/basic/2019.2/changelog.xml b/.liquibase/Data_alias/basic/2019.2/changelog.xml index 17c4d2d7674c173220d39f66e1f2bbfe31895cfb..2f7b975b9e14b63fbdf9c4d035ba408ce0cceff0 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 0000000000000000000000000000000000000000..83081ee094303aef88ca871bfbcbc6a55bc6eb61 --- /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 0000000000000000000000000000000000000000..5e7cbd6ac0376eb634046a65ee1b9468154061fc --- /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 0000000000000000000000000000000000000000..5827d6bbe88171d09a90f2236fd8bafbdec0cc98 --- /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