diff --git a/.liquibase/Data_alias/basic/2021.0.0/EwsContactSync/create_ab_synccontact.xml b/.liquibase/Data_alias/basic/2021.0.0/EwsContactSync/create_ab_synccontact.xml new file mode 100644 index 0000000000000000000000000000000000000000..9de2f01cc35fba70afd6992a3995da9c8e1b7431 --- /dev/null +++ b/.liquibase/Data_alias/basic/2021.0.0/EwsContactSync/create_ab_synccontact.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd"> + <changeSet author="A.Riedl" id="9820d74b-1b58-4ffd-9f5d-8c4d670bda47"> + <createTable tableName="AB_SYNCCONTACT"> + <column name="SYNCCONTACTID" type="char(36)"> + <constraints primaryKey="true" primaryKeyName="PK_SYNCCONTACTID"/> + </column> + <column name="ASYS_FAVORITEID" type="char(36)"/> + <column name="EXCHANGEID" type="varchar(254)"/> + <column name="USER_ID" type="char(46)"/> + <column name="CONTACT_ID" type="char(36)"/> + <column name="DATE_DEL" type="datetime"/> + <column name="DATE_EDIT" type="datetime"/> + <column name="DATE_NEW" type="datetime"/> + </createTable> + <createIndex indexName="idx_exchangeId" tableName="AB_SYNCCONTACT"> + <column name="EXCHANGEID"/> + </createIndex> + <createIndex tableName="AB_SYNCCONTACT" indexName="idx_UserId"> + <column name="USER_ID"/> + </createIndex> + <createIndex tableName="AB_SYNCCONTACT" indexName="idx_ContactId"> + <column name="CONTACT_ID"/> + </createIndex> + <addUniqueConstraint + columnNames="ASYS_FAVORITEID" + constraintName="const_uniqueFavoriteId" + tableName="AB_SYNCCONTACT"/> + </changeSet> +</databaseChangeLog> diff --git a/.liquibase/Data_alias/basic/2021.0.0/changelog.xml b/.liquibase/Data_alias/basic/2021.0.0/changelog.xml index b020b1e6d1dcadcd1c6ddcff09cb36cf57dd4dca..21d9b6123c339868f578deb1c41f89eb8269b0d3 100644 --- a/.liquibase/Data_alias/basic/2021.0.0/changelog.xml +++ b/.liquibase/Data_alias/basic/2021.0.0/changelog.xml @@ -14,4 +14,5 @@ <include relativeToChangelogFile="true" file="Keywords/changelog.xml"/> <include relativeToChangelogFile="true" file="KeywordMigration/changelog.xml"/> <include relativeToChangelogFile="true" file="addDateNewToSalesproject.xml"/> + <include relativeToChangelogFile="true" file="EwsContactSync/create_ab_synccontact.xml"/> </databaseChangeLog> \ No newline at end of file diff --git a/entity/Campaign_entity/Campaign_entity.aod b/entity/Campaign_entity/Campaign_entity.aod index f5c04fb9aa81e250a12f0f2253e8201607d2aa53..8e4f23dc87086a0d65df0b391c3816b4f4641e26 100644 --- a/entity/Campaign_entity/Campaign_entity.aod +++ b/entity/Campaign_entity/Campaign_entity.aod @@ -498,8 +498,8 @@ </children> </entityConsumer> <entityField> - <name>CAMPAIGN_OBEJCTTYPE</name> - <valueProcess>%aditoprj%/entity/Campaign_entity/entityfields/campaign_obejcttype/valueProcess.js</valueProcess> + <name>CAMPAIGN_OBJECTTYPE</name> + <valueProcess>%aditoprj%/entity/Campaign_entity/entityfields/campaign_objecttype/valueProcess.js</valueProcess> </entityField> <entityConsumer> <name>PersonConsumer</name> @@ -687,6 +687,14 @@ <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/attribute_filter/filterConditionProcess.js</filterConditionProcess> <filtertype>BASIC</filtertype> </filterExtensionSet> + <filterExtension> + <name>Favorite_Filter</name> + <title>Favoritegroup</title> + <contentType>TEXT</contentType> + <filterValuesProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/favorite_filter/filterValuesProcess.js</filterValuesProcess> + <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js</filterConditionProcess> + <filtertype>BASIC</filtertype> + </filterExtension> </filterExtensions> </dbRecordContainer> </recordContainers> diff --git a/entity/Campaign_entity/entityfields/campaign_obejcttype/valueProcess.js b/entity/Campaign_entity/entityfields/campaign_objecttype/valueProcess.js similarity index 100% rename from entity/Campaign_entity/entityfields/campaign_obejcttype/valueProcess.js rename to entity/Campaign_entity/entityfields/campaign_objecttype/valueProcess.js diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..8c69112797b6d3dfddda65853554193ffd335918 --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js @@ -0,0 +1,12 @@ +import("system.vars"); +import("Favorites_lib"); +import("system.result"); +import("Sql_lib"); + +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); + +var objecttype = vars.get("$field.CAMPAIGN_OBJECTTYPE"); +var idcolumn = "CAMPAIGN.CAMPAIGNID"; + +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); \ No newline at end of file diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/favorite_filter/filterValuesProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/favorite_filter/filterValuesProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..419128ca73fe597afc7ca4aeed50b28e610206ec --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/favorite_filter/filterValuesProcess.js @@ -0,0 +1,5 @@ +import("Context_lib"); +import("system.result"); +import("Favorites_lib"); + +result.object(FavoritesUtil.getUserFavoriteGroupsByContext(ContextUtils.getCurrentContextId())); \ No newline at end of file diff --git a/entity/Communication_entity/Communication_entity.aod b/entity/Communication_entity/Communication_entity.aod index fa0187084e458d0756e6a7f8402b4504bba23bb5..6825e5edc558a5f1ce8fa754382231dd31d125e9 100644 --- a/entity/Communication_entity/Communication_entity.aod +++ b/entity/Communication_entity/Communication_entity.aod @@ -6,6 +6,7 @@ <majorModelMode>DISTRIBUTED</majorModelMode> <documentation>%aditoprj%/entity/Communication_entity/documentation.adoc</documentation> <contentTitleProcess>%aditoprj%/entity/Communication_entity/contentTitleProcess.js</contentTitleProcess> + <afterOperatingState>%aditoprj%/entity/Communication_entity/afterOperatingState.js</afterOperatingState> <recordContainer>db</recordContainer> <entityFields> <entityField> diff --git a/entity/Communication_entity/afterOperatingState.js b/entity/Communication_entity/afterOperatingState.js new file mode 100644 index 0000000000000000000000000000000000000000..7085e9f853c10e7ebaadcd76f44b8786c5d621ed --- /dev/null +++ b/entity/Communication_entity/afterOperatingState.js @@ -0,0 +1,5 @@ +import("system.vars"); +import("system.neon"); + +if(vars.get("$sys.operatingstate") == neon.OPERATINGSTATE_VIEW) + vars.set("$context.PushDataPrivacyNotification", "false"); \ No newline at end of file diff --git a/entity/Communication_entity/recordcontainers/db/onDBInsert.js b/entity/Communication_entity/recordcontainers/db/onDBInsert.js index 5497aac10e4c84e9d6f63bdd28012b0bfe75cc06..7d836ae39e0b9d809ba388111d4ab1ab4302a6f9 100644 --- a/entity/Communication_entity/recordcontainers/db/onDBInsert.js +++ b/entity/Communication_entity/recordcontainers/db/onDBInsert.js @@ -11,7 +11,11 @@ var rowdata = vars.get("$local.rowdata"); var standard = new StandardObject("Communication", vars.get("$local.uid"), "Person", rowdata["COMMUNICATION.CONTACT_ID"]) standard.onCommunicationInsert(rowdata["COMMUNICATION.MEDIUM_ID"]); -DataPrivacyUtils.notifyNeedDataPrivacyUpdate(rowdata["COMMUNICATION.CONTACT_ID"], vars.get("$param.ShowDsgvoMessage_param")); +if(vars.exists("$context.PushDataPrivacyNotification") && vars.get("$context.PushDataPrivacyNotification") == "false" && vars.get("$sys.isclient")) +{ + DataPrivacyUtils.notifyNeedDataPrivacyUpdate(rowdata["COMMUNICATION.CONTACT_ID"], vars.get("$param.ShowDsgvoMessage_param")); + vars.set("$context.PushDataPrivacyNotification", "true"); +} if (vars.exists("$param.AdditionalContactIds_param") && vars.get("$param.AdditionalContactIds_param")) { diff --git a/entity/Communication_entity/recordcontainers/db/onDBUpdate.js b/entity/Communication_entity/recordcontainers/db/onDBUpdate.js index da680f82c23c27da4f2cfb65488df9b1426b77bc..ebf288114b69f9c461bebc6ca31b2c39ada5b513 100644 --- a/entity/Communication_entity/recordcontainers/db/onDBUpdate.js +++ b/entity/Communication_entity/recordcontainers/db/onDBUpdate.js @@ -10,7 +10,11 @@ if (rowdata["COMMUNICATION.CONTACT_ID"] != null) var standard = new StandardObject("Communication", vars.get("$local.uid"), "Person", rowdata["COMMUNICATION.CONTACT_ID"]) standard.onCommunicationUpdate(rowdata["COMMUNICATION.MEDIUM_ID"]); } - -DataPrivacyUtils.notifyNeedDataPrivacyUpdate(rowdata["COMMUNICATION.CONTACT_ID"], vars.get("$param.ShowDsgvoMessage_param")); + +if(vars.exists("$context.PushDataPrivacyNotification") && vars.get("$context.PushDataPrivacyNotification") == "false" && vars.get("$sys.isclient")) +{ + DataPrivacyUtils.notifyNeedDataPrivacyUpdate(rowdata["COMMUNICATION.CONTACT_ID"], vars.get("$param.ShowDsgvoMessage_param")); + vars.set("$context.PushDataPrivacyNotification", "true"); +} WorkflowSignalSender.updated(); \ No newline at end of file diff --git a/entity/Contract_entity/Contract_entity.aod b/entity/Contract_entity/Contract_entity.aod index 3e3262421190782abc4d26f6b958f51acb4dc26b..49afa5872c3c02495fe5846da0a83f2234d4fa72 100644 --- a/entity/Contract_entity/Contract_entity.aod +++ b/entity/Contract_entity/Contract_entity.aod @@ -596,6 +596,7 @@ <contentType>TEXT</contentType> <filterValuesProcess>%aditoprj%/entity/Contract_entity/recordcontainers/db/filterextensions/favorite_filter/filterValuesProcess.js</filterValuesProcess> <filterConditionProcess>%aditoprj%/entity/Contract_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js</filterConditionProcess> + <groupedRecordField></groupedRecordField> <filtertype>BASIC</filtertype> </filterExtension> </filterExtensions> diff --git a/entity/Contract_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js b/entity/Contract_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js index 6b54c170684381c41d00387e9f2371c7d327d05a..8f9bf3561bdd112fd994940777b7e761b607f768 100644 --- a/entity/Contract_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js +++ b/entity/Contract_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js @@ -1,11 +1,12 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); -for(i = 0; i < rowIds.length; i++) - favoFilterCond.or("CONTRACT.CONTRACTID", rowIds[i], SqlBuilder.EQUAL()); +var objecttype = vars.get("$field.CONTRACT_OBJECTTYPE"); +var idcolumn = "CONTRACT.CONTRACTID"; -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); \ No newline at end of file diff --git a/entity/DocumentTemplate_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js b/entity/DocumentTemplate_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js index c3deb28e584154a76101902faaebb110e2c5d7d8..73410be03fab8d10e3ee99009855a5dcd5b4df12 100644 --- a/entity/DocumentTemplate_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js +++ b/entity/DocumentTemplate_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js @@ -1,11 +1,12 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); -for(i = 0; i < rowIds.length; i++) - favoFilterCond.or("DOCUMENTTEMPLATE.DOCUMENTTEMPLATEID", rowIds[i], SqlBuilder.EQUAL()); +var objecttype = vars.get("$field.DOCUMENTTEMPLATE_OBJECTTYPE"); +var idcolumn = "DOCUMENTTEMPLATE.DOCUMENTTEMPLATEID"; -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); diff --git a/entity/EwsSyncAddContacts_entity/EwsSyncAddContacts_entity.aod b/entity/EwsSyncAddContacts_entity/EwsSyncAddContacts_entity.aod new file mode 100644 index 0000000000000000000000000000000000000000..332169d840fba95e4b9a7507ede82835e4fda87e --- /dev/null +++ b/entity/EwsSyncAddContacts_entity/EwsSyncAddContacts_entity.aod @@ -0,0 +1,62 @@ +<?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.3.18" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.3.18"> + <name>EwsSyncAddContacts_entity</name> + <title>add contact to ewssync</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <titlePlural></titlePlural> + <recordContainer>datalessConfig</recordContainer> + <entityFields> + <entityProvider> + <name>#PROVIDER</name> + </entityProvider> + <entityProvider> + <name>#PROVIDER_AGGREGATES</name> + <useAggregates v="true" /> + </entityProvider> + <entityField> + <name>contactIds</name> + <state>EDITABLE</state> + <valueProcess>%aditoprj%/entity/EwsSyncAddContacts_entity/entityfields/contactids/valueProcess.js</valueProcess> + </entityField> + <entityField> + <name>countForSync</name> + <title>count</title> + <state>EDITABLE</state> + <valueProcess>%aditoprj%/entity/EwsSyncAddContacts_entity/entityfields/countforsync/valueProcess.js</valueProcess> + </entityField> + <entityParameter> + <name>ContactFilter_param</name> + <expose v="true" /> + </entityParameter> + <entityParameter> + <name>ContactIds_param</name> + <expose v="true" /> + </entityParameter> + <entityActionField> + <name>syncContacts</name> + <title>add to sync</title> + <onActionProcess>%aditoprj%/entity/EwsSyncAddContacts_entity/entityfields/synccontacts/onActionProcess.js</onActionProcess> + <iconId>VAADIN:REFRESH</iconId> + <stateProcess>%aditoprj%/entity/EwsSyncAddContacts_entity/entityfields/synccontacts/stateProcess.js</stateProcess> + <tooltip></tooltip> + </entityActionField> + <entityParameter> + <name>Mode_param</name> + <expose v="true" /> + </entityParameter> + <entityActionField> + <name>removeSyncContacts</name> + <title>remove from sync</title> + <onActionProcess>%aditoprj%/entity/EwsSyncAddContacts_entity/entityfields/removesynccontacts/onActionProcess.js</onActionProcess> + <isObjectAction v="true" /> + <iconId>NEON:RECURRING_APPOINTMENT_MOVED</iconId> + <stateProcess>%aditoprj%/entity/EwsSyncAddContacts_entity/entityfields/removesynccontacts/stateProcess.js</stateProcess> + </entityActionField> + </entityFields> + <recordContainers> + <datalessRecordContainer> + <name>datalessConfig</name> + <alias>Data_alias</alias> + </datalessRecordContainer> + </recordContainers> +</entity> diff --git a/entity/EwsSyncAddContacts_entity/entityfields/contactids/valueProcess.js b/entity/EwsSyncAddContacts_entity/entityfields/contactids/valueProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..373f61e18faccaead7724225f920d46437148b77 --- /dev/null +++ b/entity/EwsSyncAddContacts_entity/entityfields/contactids/valueProcess.js @@ -0,0 +1,10 @@ +import("system.result"); +import("system.vars"); +import("FilterViewAction_lib"); + +var contactIds = JSON.parse(vars.get("$param.ContactIds_param")); +var contactFilter = vars.get("$param.ContactFilter_param"); + +contactIds = FilterViewActionUtils.getUidsBySelectionOrFilter("Person", contactIds, contactFilter); + +result.string(JSON.stringify(contactIds)); \ No newline at end of file diff --git a/entity/EwsSyncAddContacts_entity/entityfields/countforsync/valueProcess.js b/entity/EwsSyncAddContacts_entity/entityfields/countforsync/valueProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..4d01818ca409c8b5746f74b408c7b4456931abe8 --- /dev/null +++ b/entity/EwsSyncAddContacts_entity/entityfields/countforsync/valueProcess.js @@ -0,0 +1,10 @@ +import("system.vars"); +import("system.result"); + +var res = ""; +if (vars.get("$field.contactIds")) +{ + res = JSON.parse(vars.getString("$field.contactIds")).length; +} + +result.string(res); diff --git a/entity/EwsSyncAddContacts_entity/entityfields/removesynccontacts/onActionProcess.js b/entity/EwsSyncAddContacts_entity/entityfields/removesynccontacts/onActionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..b0a2ce611876352836e323dcd13a38cc97f0a718 --- /dev/null +++ b/entity/EwsSyncAddContacts_entity/entityfields/removesynccontacts/onActionProcess.js @@ -0,0 +1,8 @@ +import("system.neon"); +import("system.tools"); +import("EwsClientSync_lib"); +import("system.vars"); + +var contactIds = JSON.parse(vars.get("$field.contactIds")); +EwsClientSyncUtils.removeFromFavorite(contactIds, tools.getCurrentUser()[tools.NAME]); +neon.closeImage(vars.get("$sys.currentimage"), true); \ No newline at end of file diff --git a/entity/EwsSyncAddContacts_entity/entityfields/removesynccontacts/stateProcess.js b/entity/EwsSyncAddContacts_entity/entityfields/removesynccontacts/stateProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..7ae3eef9a8407cd8e4edaee71f77b14a6c233d03 --- /dev/null +++ b/entity/EwsSyncAddContacts_entity/entityfields/removesynccontacts/stateProcess.js @@ -0,0 +1,11 @@ +import("system.neon"); +import("system.vars"); +import("system.result"); + +var mode = vars.get("$param.Mode_param"); +var ret = neon.COMPONENTSTATE_INVISIBLE; + +if(mode == "REMOVE") + ret = neon.COMPONENTSTATE_EDITABLE; + +result.string(ret); diff --git a/entity/EwsSyncAddContacts_entity/entityfields/synccontacts/onActionProcess.js b/entity/EwsSyncAddContacts_entity/entityfields/synccontacts/onActionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..34578d4b676914a1e2aa7b8ec83e9277bd82aea1 --- /dev/null +++ b/entity/EwsSyncAddContacts_entity/entityfields/synccontacts/onActionProcess.js @@ -0,0 +1,9 @@ +import("system.neon"); +import("EwsClientSync_lib"); +import("system.vars"); + +var toSncContacts = JSON.parse(vars.get("$field.contactIds")); + +//the handling of already Contacts in the Exchange is handeled by the function itself +EwsClientSyncUtils.addToEwsFavorite(toSncContacts); +neon.closeImage(vars.get("$sys.currentimage"), true); \ No newline at end of file diff --git a/entity/EwsSyncAddContacts_entity/entityfields/synccontacts/stateProcess.js b/entity/EwsSyncAddContacts_entity/entityfields/synccontacts/stateProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..c10e581fee4f5e13e064bbbb4a8faa11c9470aa3 --- /dev/null +++ b/entity/EwsSyncAddContacts_entity/entityfields/synccontacts/stateProcess.js @@ -0,0 +1,11 @@ +import("system.neon"); +import("system.vars"); +import("system.result"); + +var mode = vars.get("$param.Mode_param"); +var ret = neon.COMPONENTSTATE_INVISIBLE; + +if(mode == "ADD") + ret = neon.COMPONENTSTATE_EDITABLE; + +result.string(ret); diff --git a/entity/ExportTemplate_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js b/entity/ExportTemplate_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js index 27c569099821e96f51c9ab7e3e5c7a6db87d6e09..57784ebda7e75d58197542d071b5afb2a61cc74e 100644 --- a/entity/ExportTemplate_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js +++ b/entity/ExportTemplate_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js @@ -1,11 +1,12 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); -for(i = 0; i < rowIds.length; i++) - favoFilterCond.or("EXPORTTEMPLATE.EXPORTTEMPLATEID", rowIds[i], SqlBuilder.EQUAL()); +var objecttype = vars.get("$field.EXPORTTEMPLATE_OBJECTTYPE"); +var idcolumn = "EXPORTTEMPLATE.EXPORTTEMPLATEID"; -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); \ No newline at end of file diff --git a/entity/Leadimport_entity/Leadimport_entity.aod b/entity/Leadimport_entity/Leadimport_entity.aod index 1f79a0d182c36726786038ae468c2f973dd8066f..6dd8755383e13bf7bbebf6c77c00bf0e3f0688dc 100644 --- a/entity/Leadimport_entity/Leadimport_entity.aod +++ b/entity/Leadimport_entity/Leadimport_entity.aod @@ -68,7 +68,6 @@ <name>STATUS</name> <title>Status</title> <consumer>KeywordImportStatus</consumer> - <groupable v="true" /> <state>READONLY</state> <valueProcess>%aditoprj%/entity/Leadimport_entity/entityfields/status/valueProcess.js</valueProcess> <displayValueProcess>%aditoprj%/entity/Leadimport_entity/entityfields/status/displayValueProcess.js</displayValueProcess> @@ -131,7 +130,6 @@ <entityField> <name>IMPORTSOURCE</name> <title>Import source</title> - <groupable v="true" /> <mandatory v="true" /> </entityField> <entityConsumer> diff --git a/entity/Offer_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js b/entity/Offer_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js index 4157abe2c850e42fb49e06207d907884670e46e2..63107e39aba496b0175d11ffbcc930fcef263d46 100644 --- a/entity/Offer_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js +++ b/entity/Offer_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js @@ -1,11 +1,12 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); -for(i = 0; i < rowIds.length; i++) - favoFilterCond.or("OFFER.OFFERID", rowIds[i], SqlBuilder.EQUAL()); +var objecttype = vars.get("$field.OFFER_OBJECTTYPE"); +var idcolumn = "OFFER.OFFERID"; -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); diff --git a/entity/Order_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js b/entity/Order_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js index 647507498cf404c675a2a3225f36369d7012659d..7d1adc14150119dd7ff8be0b48535cccc4aadf52 100644 --- a/entity/Order_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js +++ b/entity/Order_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js @@ -1,11 +1,12 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); -for(i = 0; i < rowIds.length; i++) - favoFilterCond.or("SALESORDER.SALESORDERID", rowIds[i], SqlBuilder.EQUAL()); +var objecttype = vars.get("$field.ORDER_OBJECTTYPE"); +var idcolumn = "SALESORDER.SALESORDERID"; -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); diff --git a/entity/Organisation_entity/recordcontainers/db/filterextensions/favorites_filter/filterConditionProcess.js b/entity/Organisation_entity/recordcontainers/db/filterextensions/favorites_filter/filterConditionProcess.js index d42520a347c8e8d594fb1af389acb8af1a2e824c..888ac0657242f41866a37f471b9765b045b52594 100644 --- a/entity/Organisation_entity/recordcontainers/db/filterextensions/favorites_filter/filterConditionProcess.js +++ b/entity/Organisation_entity/recordcontainers/db/filterextensions/favorites_filter/filterConditionProcess.js @@ -1,19 +1,27 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); + +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); +var objecttype = vars.get("$field.ORGANISATION_OBJECTTYPE"); +var idcolumn = "ORGANISATION.ORGANISATIONID"; + + +var rowIds = FavoritesUtil.getRowIdsOfFavorites(objecttype, operator, rawvalue); +var preparedIds = []; for(i = 0; i < rowIds.length; i++) { - var orga_id = new SqlBuilder().select("CONTACT.ORGANISATION_ID") + var person_id = new SqlBuilder().select("CONTACT.ORGANISATION_ID") .from("CONTACT") .where(newWhere("CONTACT.CONTACTID", rowIds[i])) .arrayColumn(); - if(orga_id.length > 0) - favoFilterCond.or("ORGANISATION.ORGANISATIONID", orga_id[0], SqlBuilder.EQUAL()); + if(person_id.length > 0) + preparedIds.push(person_id[0]); } -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn, preparedIds)); \ No newline at end of file diff --git a/entity/Person_entity/Person_entity.aod b/entity/Person_entity/Person_entity.aod index ac6d2e755a3059859fd1adb11bc724f80856ea89..b5d6a079e7970a57ac684887b51d6c2edda3b287 100644 --- a/entity/Person_entity/Person_entity.aod +++ b/entity/Person_entity/Person_entity.aod @@ -1333,6 +1333,20 @@ <stateProcess>%aditoprj%/entity/Person_entity/entityfields/filterviewactiongroup/children/cancelobservation/stateProcess.js</stateProcess> <titleProcess>%aditoprj%/entity/Person_entity/entityfields/filterviewactiongroup/children/cancelobservation/titleProcess.js</titleProcess> </entityActionField> + <entityActionField> + <name>addToContactSync</name> + <title>add Contact to Sync</title> + <onActionProcess>%aditoprj%/entity/Person_entity/entityfields/filterviewactiongroup/children/addtocontactsync/onActionProcess.js</onActionProcess> + <iconId>NEON:RECURRING_APPOINTMENT</iconId> + <state>EDITABLE</state> + </entityActionField> + <entityActionField> + <name>removeFromContactSync</name> + <title>remove Contact from Sync</title> + <onActionProcess>%aditoprj%/entity/Person_entity/entityfields/filterviewactiongroup/children/removefromcontactsync/onActionProcess.js</onActionProcess> + <iconId>NEON:RECURRING_APPOINTMENT_MOVED</iconId> + <state>AUTO</state> + </entityActionField> </children> </entityActionGroup> <entityActionGroup> diff --git a/entity/Person_entity/entityfields/attributes/children/showdsgvomessage_param/valueProcess.js b/entity/Person_entity/entityfields/attributes/children/showdsgvomessage_param/valueProcess.js index fce9fde135bfde9221a9956f545862641098ff7c..c96eec50f67631c175c60d748ded5821644aea70 100644 --- a/entity/Person_entity/entityfields/attributes/children/showdsgvomessage_param/valueProcess.js +++ b/entity/Person_entity/entityfields/attributes/children/showdsgvomessage_param/valueProcess.js @@ -2,4 +2,4 @@ import("system.vars"); import("system.neon"); import("system.result"); -result.string(vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW); \ No newline at end of file +result.string(vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW && vars.get("$sys.recordstate") != neon.OPERATINGSTATE_EDIT); \ No newline at end of file diff --git a/entity/Person_entity/entityfields/communications/children/showdsgvomessage_param/valueProcess.js b/entity/Person_entity/entityfields/communications/children/showdsgvomessage_param/valueProcess.js index fce9fde135bfde9221a9956f545862641098ff7c..c96eec50f67631c175c60d748ded5821644aea70 100644 --- a/entity/Person_entity/entityfields/communications/children/showdsgvomessage_param/valueProcess.js +++ b/entity/Person_entity/entityfields/communications/children/showdsgvomessage_param/valueProcess.js @@ -2,4 +2,4 @@ import("system.vars"); import("system.neon"); import("system.result"); -result.string(vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW); \ No newline at end of file +result.string(vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW && vars.get("$sys.recordstate") != neon.OPERATINGSTATE_EDIT); \ No newline at end of file diff --git a/entity/Person_entity/entityfields/filterviewactiongroup/children/addtocontactsync/onActionProcess.js b/entity/Person_entity/entityfields/filterviewactiongroup/children/addtocontactsync/onActionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..3ba5646790e532ee17f5d19d6fd57fbaece4a4d1 --- /dev/null +++ b/entity/Person_entity/entityfields/filterviewactiongroup/children/addtocontactsync/onActionProcess.js @@ -0,0 +1,4 @@ +import("EwsClientSync_lib"); +import("system.vars"); + +EwsClientSyncUtils.openEwsSyncAddContactView(vars.get("$sys.selection"), vars.get("$sys.filter"), "ADD"); \ No newline at end of file diff --git a/entity/Person_entity/entityfields/filterviewactiongroup/children/removefromcontactsync/onActionProcess.js b/entity/Person_entity/entityfields/filterviewactiongroup/children/removefromcontactsync/onActionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..1c6e00c85cdc5ec2423caf9c9f046f3fb7305168 --- /dev/null +++ b/entity/Person_entity/entityfields/filterviewactiongroup/children/removefromcontactsync/onActionProcess.js @@ -0,0 +1,4 @@ +import("EwsClientSync_lib"); +import("system.vars"); + +EwsClientSyncUtils.openEwsSyncAddContactView(vars.get("$sys.selection"), vars.get("$sys.filter"), "REMOVE"); \ No newline at end of file diff --git a/entity/Person_entity/entityfields/persaddresses/children/showdsgvomessage_param/valueProcess.js b/entity/Person_entity/entityfields/persaddresses/children/showdsgvomessage_param/valueProcess.js index fce9fde135bfde9221a9956f545862641098ff7c..c96eec50f67631c175c60d748ded5821644aea70 100644 --- a/entity/Person_entity/entityfields/persaddresses/children/showdsgvomessage_param/valueProcess.js +++ b/entity/Person_entity/entityfields/persaddresses/children/showdsgvomessage_param/valueProcess.js @@ -2,4 +2,4 @@ import("system.vars"); import("system.neon"); import("system.result"); -result.string(vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW); \ No newline at end of file +result.string(vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW && vars.get("$sys.recordstate") != neon.OPERATINGSTATE_EDIT); \ No newline at end of file diff --git a/entity/Person_entity/recordcontainers/db/filterextensions/favorites_filter/filterConditionProcess.js b/entity/Person_entity/recordcontainers/db/filterextensions/favorites_filter/filterConditionProcess.js index 26e0adde33d17eab1378a9d8aa4cfee3eea401bb..0c4956dc698a76bdf4426e973ffeb5237ad7d641 100644 --- a/entity/Person_entity/recordcontainers/db/filterextensions/favorites_filter/filterConditionProcess.js +++ b/entity/Person_entity/recordcontainers/db/filterextensions/favorites_filter/filterConditionProcess.js @@ -1,9 +1,17 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); + +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); +var objecttype = vars.get("$field.PERSON_OBJECTTYPE"); +var idcolumn = "PERSON.PERSONID"; + + +var rowIds = FavoritesUtil.getRowIdsOfFavorites(objecttype, operator, rawvalue); +var preparedIds = []; for(i = 0; i < rowIds.length; i++) { @@ -13,7 +21,7 @@ for(i = 0; i < rowIds.length; i++) .arrayColumn(); if(person_id.length > 0) - favoFilterCond.or("PERSON.PERSONID", person_id[0], SqlBuilder.EQUAL()); + preparedIds.push(person_id[0]); } -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn, preparedIds)); diff --git a/entity/Product_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js b/entity/Product_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js index 2db1e9e36cfa068a562f0c1c253c874eb648f33a..d06b0214dc625cee8ca5f435880df2f5deae3b5c 100644 --- a/entity/Product_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js +++ b/entity/Product_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js @@ -1,11 +1,12 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); -for(i = 0; i < rowIds.length; i++) - favoFilterCond.or("PRODUCT.PRODUCTID", rowIds[i], SqlBuilder.EQUAL()); +var objecttype = vars.get("$field.PRODUCT_OBJECTTYPE"); +var idcolumn = "PRODUCT.PRODUCTID"; -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); diff --git a/entity/Productprice_entity/Productprice_entity.aod b/entity/Productprice_entity/Productprice_entity.aod index 20e53fc299aadd601a2a2fed53c8ab2ee8e05b96..32ad155d4473c1621475321e718f8af1d08e71be 100644 --- a/entity/Productprice_entity/Productprice_entity.aod +++ b/entity/Productprice_entity/Productprice_entity.aod @@ -25,6 +25,7 @@ <name>CURRENCY</name> <title>Currency</title> <consumer>KeywordCurrencies</consumer> + <groupable v="true" /> <mandatory v="true" /> <valueProcess>%aditoprj%/entity/Productprice_entity/entityfields/currency/valueProcess.js</valueProcess> <displayValueProcess>%aditoprj%/entity/Productprice_entity/entityfields/currency/displayValueProcess.js</displayValueProcess> @@ -58,6 +59,7 @@ <name>PRODUCT_ID</name> <title>Product</title> <consumer>Products</consumer> + <groupable v="true" /> <linkedContext>Product</linkedContext> <mandatory v="true" /> <stateProcess>%aditoprj%/entity/Productprice_entity/entityfields/product_id/stateProcess.js</stateProcess> @@ -93,6 +95,7 @@ <contentType>NUMBER</contentType> <outputFormat>#,##0.00</outputFormat> <inputFormat>#,##0.00</inputFormat> + <groupable v="true" /> <mandatory v="true" /> <stateProcess>%aditoprj%/entity/Productprice_entity/entityfields/vat/stateProcess.js</stateProcess> <valueProcess>%aditoprj%/entity/Productprice_entity/entityfields/vat/valueProcess.js</valueProcess> @@ -104,6 +107,7 @@ <title>Price list</title> <colorProcess>%aditoprj%/entity/Productprice_entity/entityfields/pricelist/colorProcess.js</colorProcess> <consumer>KeywordPricelists</consumer> + <groupable v="true" /> <state>AUTO</state> <stateProcess>%aditoprj%/entity/Productprice_entity/entityfields/pricelist/stateProcess.js</stateProcess> <titleProcess>%aditoprj%/entity/Productprice_entity/entityfields/pricelist/titleProcess.js</titleProcess> @@ -316,10 +320,6 @@ <name>CURRENCY.displayValue</name> <expression>%aditoprj%/entity/Productprice_entity/recordcontainers/db/recordfieldmappings/currency.displayvalue/expression.js</expression> </dbRecordFieldMapping> - <dbRecordFieldMapping> - <name>PRODUCT_ID.displayValue</name> - <expression>%aditoprj%/entity/Productprice_entity/recordcontainers/db/recordfieldmappings/product_id.displayvalue/expression.js</expression> - </dbRecordFieldMapping> <dbRecordFieldMapping> <name>FROMQUANTITY.displayValue</name> <expression>%aditoprj%/entity/Productprice_entity/recordcontainers/db/recordfieldmappings/fromquantity.displayvalue/expression.js</expression> diff --git a/entity/Productprice_entity/recordcontainers/db/filterextensions/favoritefilter/filterConditionProcess.js b/entity/Productprice_entity/recordcontainers/db/filterextensions/favoritefilter/filterConditionProcess.js index c657ebe1ac71578a6aa535aa58f3c953ae76ceeb..2b8c460855ed332f311597ff9151edecd5835c4e 100644 --- a/entity/Productprice_entity/recordcontainers/db/filterextensions/favoritefilter/filterConditionProcess.js +++ b/entity/Productprice_entity/recordcontainers/db/filterextensions/favoritefilter/filterConditionProcess.js @@ -1,11 +1,12 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); -for(i = 0; i < rowIds.length; i++) - favoFilterCond.or("PRODUCTPRICE.PRODUCTPRICEID", rowIds[i], SqlBuilder.EQUAL()); +var objecttype = vars.get("$field.PRODUCTPRICE_OBJECTTYPE"); +var idcolumn = "PRODUCTPRICE.PRODUCTPRICEID"; -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); diff --git a/entity/Productprice_entity/recordcontainers/db/recordfieldmappings/product_id.displayvalue/expression.js b/entity/Productprice_entity/recordcontainers/db/recordfieldmappings/product_id.displayvalue/expression.js deleted file mode 100644 index d43ca1490d74c4fc1baa5dd375e5c77f6a2b61fd..0000000000000000000000000000000000000000 --- a/entity/Productprice_entity/recordcontainers/db/recordfieldmappings/product_id.displayvalue/expression.js +++ /dev/null @@ -1,3 +0,0 @@ -import("system.result"); - -result.string("select PRODUCT.PRODUCTNAME from PRODUCT where PRODUCT.PRODUCTID = PRODUCTPRICE.PRODUCT_ID"); \ No newline at end of file diff --git a/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/contentProcess.js b/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/contentProcess.js index afa79b535cb636c95d551fedb42eb8aa4035fc97..d4d779b0c5261b8ad759fec03c049e544903aac1 100644 --- a/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/contentProcess.js @@ -13,8 +13,7 @@ var phasenManager = new SalesprojectConversionRate(); var sql = new SqlBuilder() .from("AB_KEYWORD_ENTRY") -.where("AB_KEYWORD_ENTRY.AB_KEYWORD_CATEGORY_ID", KeywordUtils.getCategoryIdByName($KeywordRegistry.salesprojectPhase())) -.and("AB_KEYWORD_ENTRY.KEYID", $KeywordRegistry.salesprojectPhase$nego(), SqlBuilder.NOT_EQUAL()); +.where("AB_KEYWORD_ENTRY.AB_KEYWORD_CATEGORY_ID", KeywordUtils.getCategoryIdByName($KeywordRegistry.salesprojectPhase())); if (filter != null) { diff --git a/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/rowCountProcess.js b/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/rowCountProcess.js index e6aab30159a1feb28c3a40b69c9c87559a4403af..9d19863bd9c26153fd71bfb7d5b648dee630245b 100644 --- a/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/rowCountProcess.js +++ b/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/rowCountProcess.js @@ -13,8 +13,7 @@ var phasenManager = new SalesprojectConversionRate(); var sql = new SqlBuilder() .from("AB_KEYWORD_ENTRY") -.where("AB_KEYWORD_ENTRY.AB_KEYWORD_CATEGORY_ID", KeywordUtils.getCategoryIdByName($KeywordRegistry.salesprojectPhase())) -.and("AB_KEYWORD_ENTRY.KEYID", $KeywordRegistry.salesprojectPhase$nego(), SqlBuilder.NOT_EQUAL()); +.where("AB_KEYWORD_ENTRY.AB_KEYWORD_CATEGORY_ID", KeywordUtils.getCategoryIdByName($KeywordRegistry.salesprojectPhase())); if (filter != null) { diff --git a/entity/Salesproject_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js b/entity/Salesproject_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js index bf9199d48642536122035a91a371f8193e23271c..157e471a8f17a97b96a9efe7098a4b2e12448118 100644 --- a/entity/Salesproject_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js +++ b/entity/Salesproject_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js @@ -1,11 +1,12 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); -for(i = 0; i < rowIds.length; i++) - favoFilterCond.or("SALESPROJECT.SALESPROJECTID", rowIds[i], SqlBuilder.EQUAL()); +var objecttype = vars.get("$field.SALESPROJECT_OBJECTTYPE"); +var idcolumn = "SALESPROJECT.SALESPROJECTID"; -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); diff --git a/entity/SupportTicket_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js b/entity/SupportTicket_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js index 765e2ce46b47b556bb602c68ad610db83b1195df..a49514ad69abfed288c70f506f3b9dd30bdd53de 100644 --- a/entity/SupportTicket_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js +++ b/entity/SupportTicket_entity/recordcontainers/db/filterextensions/favorite_filter/filterConditionProcess.js @@ -1,11 +1,12 @@ +import("system.vars"); import("Favorites_lib"); import("system.result"); import("Sql_lib"); -var favoFilterCond = newWhere(); -var rowIds = FavoritesUtil.getRowIdsOfFavoriteGroup(); +var operator = vars.get("$local.operator"); +var rawvalue = vars.get("$local.rawvalue"); -for(i = 0; i < rowIds.length; i++) - favoFilterCond.or("TICKET.TICKETID", rowIds[i], SqlBuilder.EQUAL()); +var objecttype = vars.get("$field.SUPPORTTICKET_OBJECTTYPE"); +var idcolumn = "TICKET.TICKETID"; -result.string(favoFilterCond.toString()); \ No newline at end of file +result.string(FavoritesUtil.getFilterDisplayCondition(objecttype, operator, rawvalue, idcolumn)); diff --git a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod index 3862818fc360f7faff3c17add78ff2a8d0eebf87..d83d2bfa5211143d335e6ea2407a6021157a1a49 100644 --- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod +++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod @@ -1297,7 +1297,7 @@ </entry> <entry> <key>VAT</key> - <value>UmsSt.</value> + <value>Ust.</value> </entry> <entry> <key>The expiry date must be after the start date!</key> @@ -4153,7 +4153,7 @@ </entry> <entry> <key>VAT in %</key> - <value>UmsSt. in %</value> + <value>Ust. in %</value> </entry> <entry> <key>Sales manager</key> diff --git a/neonContext/EwsSyncAddContacts/EwsSyncAddContacts.aod b/neonContext/EwsSyncAddContacts/EwsSyncAddContacts.aod new file mode 100644 index 0000000000000000000000000000000000000000..9f9809ee4ab68bc9abc7fd254e23aba11fb0b2c3 --- /dev/null +++ b/neonContext/EwsSyncAddContacts/EwsSyncAddContacts.aod @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.1.1"> + <name>EwsSyncAddContacts</name> + <majorModelMode>DISTRIBUTED</majorModelMode> + <editView>EwsSyncAddContactsEdit_view</editView> + <entity>EwsSyncAddContacts_entity</entity> + <references> + <neonViewReference> + <name>c4d8f240-388e-4a1d-9455-e100a33c4819</name> + <view>EwsSyncAddContactsEdit_view</view> + </neonViewReference> + </references> +</neonContext> diff --git a/neonView/CampaignPreview_view/CampaignPreview_view.aod b/neonView/CampaignPreview_view/CampaignPreview_view.aod index ec8f409750341079fcb3b9df759203224d129457..b593d6ee9b2adf5e547c89853ff5bcdd33bb79ae 100644 --- a/neonView/CampaignPreview_view/CampaignPreview_view.aod +++ b/neonView/CampaignPreview_view/CampaignPreview_view.aod @@ -24,7 +24,7 @@ </cardViewTemplate> <favoriteViewTemplate> <name>Favorites</name> - <objectType>CAMPAIGN_OBEJCTTYPE</objectType> + <objectType>CAMPAIGN_OBJECTTYPE</objectType> <rowId>#UID</rowId> <entityField>#ENTITY</entityField> <title>favorites</title> diff --git a/neonView/EwsSyncAddContactsEdit_view/EwsSyncAddContactsEdit_view.aod b/neonView/EwsSyncAddContactsEdit_view/EwsSyncAddContactsEdit_view.aod new file mode 100644 index 0000000000000000000000000000000000000000..74bbe50bf1c6529cfb43c1c895441220675f604e --- /dev/null +++ b/neonView/EwsSyncAddContactsEdit_view/EwsSyncAddContactsEdit_view.aod @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.8" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.8"> + <name>EwsSyncAddContactsEdit_view</name> + <majorModelMode>DISTRIBUTED</majorModelMode> + <size>SMALL</size> + <layout> + <boxLayout> + <name>layout</name> + </boxLayout> + </layout> + <children> + <scoreCardViewTemplate> + <name>ewsSyncScorecard</name> + <fields> + <entityFieldLink> + <name>bb922a4f-c170-4158-9241-8ba04ae92370</name> + <entityField>countForSync</entityField> + </entityFieldLink> + </fields> + </scoreCardViewTemplate> + <actionsViewTemplate> + <name>syncAction</name> + <actions> + <element>syncContacts</element> + <element>removeSyncContacts</element> + </actions> + </actionsViewTemplate> + </children> +</neonView> diff --git a/neonView/LeadimportFilter_view/LeadimportFilter_view.aod b/neonView/LeadimportFilter_view/LeadimportFilter_view.aod index 5d877503efcf5ae4bc33bfb5c893b37ee2a32312..3e22dae8dcc9dbd2598cc3bd9c2bbbd27d3cfbaa 100644 --- a/neonView/LeadimportFilter_view/LeadimportFilter_view.aod +++ b/neonView/LeadimportFilter_view/LeadimportFilter_view.aod @@ -36,32 +36,5 @@ </neonTableColumn> </columns> </tableViewTemplate> - <treeTableViewTemplate> - <name>Treetable</name> - <entityField>#ENTITY</entityField> - <favoriteActionGroup1>observeActionGroup</favoriteActionGroup1> - <columns> - <neonTreeTableColumn> - <name>5b550d07-b92f-4429-a9f7-e18013aa3280</name> - <entityField>#IMAGE</entityField> - </neonTreeTableColumn> - <neonTreeTableColumn> - <name>e25d671d-50c8-4c77-9a2b-8214b0b87814</name> - <entityField>NAME</entityField> - </neonTreeTableColumn> - <neonTreeTableColumn> - <name>3ffd6131-6064-4ca2-958b-50f7eef0b3e1</name> - <entityField>IMPORTSOURCE</entityField> - </neonTreeTableColumn> - <neonTreeTableColumn> - <name>5fe0eed1-ed45-478d-b84e-ad65e1e5fd0a</name> - <entityField>LEADIMPORT_DATE</entityField> - </neonTreeTableColumn> - <neonTreeTableColumn> - <name>9563e615-fc93-406f-8cbb-2eceafc5bcc4</name> - <entityField>STATUS</entityField> - </neonTreeTableColumn> - </columns> - </treeTableViewTemplate> </children> </neonView> diff --git a/neonView/SerialLetterFilter_view/SerialLetterFilter_view.aod b/neonView/SerialLetterFilter_view/SerialLetterFilter_view.aod index 3d50021ba764c65d7988291de910790a9c9f4e33..e4cd6299bc886c4b7d4e78d294cad6edfce3c4fe 100644 --- a/neonView/SerialLetterFilter_view/SerialLetterFilter_view.aod +++ b/neonView/SerialLetterFilter_view/SerialLetterFilter_view.aod @@ -38,34 +38,5 @@ </neonTableColumn> </columns> </tableViewTemplate> - <treeTableViewTemplate> - <name>Treetable</name> - <entityField>#ENTITY</entityField> - <linkedColumns> - <element>TITLE</element> - </linkedColumns> - <columns> - <neonTreeTableColumn> - <name>cae0d686-5109-4106-9b35-421e79e265db</name> - <entityField>ICON</entityField> - </neonTreeTableColumn> - <neonTreeTableColumn> - <name>a5a9f4f1-14ad-4997-94c7-f76de7c5f8da</name> - <entityField>TITLE</entityField> - </neonTreeTableColumn> - <neonTreeTableColumn> - <name>dc1a061a-95fa-499e-aee4-9b49aed28cfc</name> - <entityField>STATUS</entityField> - </neonTreeTableColumn> - <neonTreeTableColumn> - <name>ec667f9a-65e3-482c-a459-87545b22af2a</name> - <entityField>DOCUMENTTEMPLATE_ID</entityField> - </neonTreeTableColumn> - <neonTreeTableColumn> - <name>88b074e6-587a-477f-97d6-fde128cae267</name> - <entityField>DESCRIPTION</entityField> - </neonTreeTableColumn> - </columns> - </treeTableViewTemplate> </children> </neonView> diff --git a/process/Communication_lib/process.js b/process/Communication_lib/process.js index 055813cf362081fd583c1d8d2cd33fb0b4c0c4c4..f9e30868d8e9c816f642e8a383504605b2ba4990 100644 --- a/process/Communication_lib/process.js +++ b/process/Communication_lib/process.js @@ -31,11 +31,11 @@ CommUtil.getMediumIdsByCategory = function (pCategory) var keywordAttr = new KeywordAttribute($KeywordRegistry.communicationMedium(), "category"); //TODO: use getRows() via JDito var mediumIds = newSelect("AB_KEYWORD_ENTRY.KEYID") - .from("AB_KEYWORD_ATTRIBUTERELATION") - .join("AB_KEYWORD_ENTRY", "AB_KEYWORD_ENTRY.AB_KEYWORD_ENTRYID = AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ENTRY_ID") - .where("AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ATTRIBUTE_ID", keywordAttr.id) - .and("AB_KEYWORD_ATTRIBUTERELATION." + keywordAttr.dbField, pCategory) - .arrayColumn(); + .from("AB_KEYWORD_ATTRIBUTERELATION") + .join("AB_KEYWORD_ENTRY", "AB_KEYWORD_ENTRY.AB_KEYWORD_ENTRYID = AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ENTRY_ID") + .where("AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ATTRIBUTE_ID", keywordAttr.id) + .and("AB_KEYWORD_ATTRIBUTERELATION." + keywordAttr.dbField, pCategory) + .arrayColumn(); return mediumIds; }; @@ -73,19 +73,19 @@ CommUtil.setStandardForCategory = function(pAffectedRowId, pNewStandardCommId, p //set current standard comm-record as non-standard var cond = newWhere("ISSTANDARD = 1") - .and("COMMUNICATION.CONTACT_ID", pAffectedRowId) - .and("COMMUNICATION.MEDIUM_ID", mediumIds, SqlBuilder.IN()); + .and("COMMUNICATION.CONTACT_ID", pAffectedRowId) + .and("COMMUNICATION.MEDIUM_ID", mediumIds, SqlBuilder.IN()); - statements.push(["COMMUNICATION", cols, null, ["0"], cond.build()]); + statements.push(["COMMUNICATION", cols, null, ["0"], cond.build()]); //pNewStandardCommId can be an empty string if the standard has to only be removed if (pNewStandardCommId != "") { //set the new standard comm-record cond = newWhere("COMMUNICATION.COMMUNICATIONID", pNewStandardCommId) - //check communicationid, contactId and medium to prevent data-inconsistency when bad function params are passed by (e.g communicationid of a different category) - .and("COMMUNICATION.CONTACT_ID", pAffectedRowId) - .and("COMMUNICATION.MEDIUM_ID", mediumIds, SqlBuilder.IN()); + //check communicationid, contactId and medium to prevent data-inconsistency when bad function params are passed by (e.g communicationid of a different category) + .and("COMMUNICATION.CONTACT_ID", pAffectedRowId) + .and("COMMUNICATION.MEDIUM_ID", mediumIds, SqlBuilder.IN()); statements.push(["COMMUNICATION", cols, null, ["1"], cond.build()]); } @@ -148,8 +148,8 @@ CommUtil.getStandardSubSqlForCategory = function(pCategory, pContactField) return "''"; var selectStandardAddr = newSelect("max(COMMUNICATION.ADDR)") - .from("COMMUNICATION") - .where(); + .from("COMMUNICATION") + .where(); if (pContactField == undefined) selectStandardAddr.and("COMMUNICATION.CONTACT_ID = CONTACT.CONTACTID"); @@ -215,6 +215,41 @@ CommUtil.getStandardMail = function (pContactId) return db.cell(query); } +/** + * Returns a sub sql-string (without brackets) for getting the address of a COMMUNICATION.<br> + * + * @param {String} pMediumKey <p> + * Key of the keyword "COMMUNICATION.MEDIUM".<br> + * (custom.category; e.g. "PHONE")<br> + * @param {String|Object} pContactField=CONTACT.CONTACTID (optional) <p> + * SQL-fieldname that shall be used for filtering the CONTACT_ID, <br> + * this can be a string(fieldname) or an SqlBuilder object.<br> + * @return {String} <p> + * Sub-sql.<br> + */ +CommUtil.getMediumAddrSubSqlByKey = function(pMediumKey, pContactField) +{ + var selectAddr = newSelect("max(COMMUNICATION.ADDR)") + .from("COMMUNICATION") + .where(); + + if (pContactField == undefined) + selectAddr.and("COMMUNICATION.CONTACT_ID = CONTACT.CONTACTID"); + else if (typeof(pContactField) == "string") + selectAddr.and("COMMUNICATION.CONTACT_ID", pContactField); + else if (typeof(pContactField) == "object") + { + //you may want to sepcify a concrete value + selectAddr.and(pContactField); + } + else + return "''"; + + selectAddr.andIfSet("COMMUNICATION.MEDIUM_ID", pMediumKey); + + return selectAddr.toString(); +} + /** * Provides static methods for validation of communication data.<br> * <b>Do not create an instance of this!</b> diff --git a/process/EwsClientSync_lib/EwsClientSync_lib.aod b/process/EwsClientSync_lib/EwsClientSync_lib.aod new file mode 100644 index 0000000000000000000000000000000000000000..a53260007b9ecc486117433576e3c03b8723ff43 --- /dev/null +++ b/process/EwsClientSync_lib/EwsClientSync_lib.aod @@ -0,0 +1,10 @@ +<?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.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.2"> + <name>EwsClientSync_lib</name> + <majorModelMode>DISTRIBUTED</majorModelMode> + <process>%aditoprj%/process/EwsClientSync_lib/process.js</process> + <alias>Data_alias</alias> + <variants> + <element>LIBRARY</element> + </variants> +</process> diff --git a/process/EwsClientSync_lib/process.js b/process/EwsClientSync_lib/process.js new file mode 100644 index 0000000000000000000000000000000000000000..2366e6b5af77b5ba73399379f2f2d2c14fe88c1b --- /dev/null +++ b/process/EwsClientSync_lib/process.js @@ -0,0 +1,357 @@ +import("system.neon"); +import("Util_lib"); +import("system.translate"); +import("Communication_lib"); +import("Placeholder_lib"); +import("system.SQLTYPES"); +import("system.vars"); +import("system.datetime"); +import("system.util"); +import("system.tools"); +import("system.favorite"); +import("system.logging"); +import("Sql_lib"); +import("system.db"); +import("system.entities") + +/** + * Provides methods for handling and interacting with the EWS Plugin + * + * @class + */ +function EwsClientSyncUtils() {} + +/* + * Constant which contains the ewsSync Tag + * if the tag has to be changed a constant is the better way + */ +EwsClientSyncUtils.EWSSYNCTAG = function(){ + return "ewssync"; +} + +/* + * prepares the synctable, insert new entries and mark for deletion + * + */ +EwsClientSyncUtils.prepareContactSyncTable = function(){ + + var favoriteDataArray = EwsClientSyncUtils.getEwsFavorites(); + var ewsSyncData = newSelect("SYNCCONTACTID, ASYS_FAVORITEID, USER_ID, CONTACT_ID") + .from("ab_synccontact") + .table(); + + var dataIndex = { + index: new Map(), + add: function (pA, pB) + { + var idxMap = this.index; + if (!idxMap.has(pA)) + idxMap.set(pA, new Set()); + idxMap.get(pA).add(pB); + }, + has: function (pA, pB) + { + return this.index.has(pA) && this.index.get(pA).has(pB); + } + }; + + //preparing the value for inserting in ewsSync Table + var toInsertFavs = []; + for (let i = 0, l = ewsSyncData.length; i < l; i++) + { + //3 - contactID 2 userID + dataIndex.add(ewsSyncData[i][3], ewsSyncData[i][2]); + } + ​ + //we want to insert those which aren't in the sync table yet but which are tagged for sync + toInsertFavs = favoriteDataArray.filter(function (row) { + return !dataIndex.has(row[1], row[2]); + }); + + + //preparing values for updating entrys in the ewsSync Table + dataIndex.index.clear(); + + var toUpdate = []; + + for (let i = 0, l = favoriteDataArray.length; i < l; i++) + { + dataIndex.add(favoriteDataArray[i][1], favoriteDataArray[i][2]); + } + + ​//dataset which are in the synctable but aren't tagged for sync (favorites ewssync) has to be updated for deletion + toUpdate = ewsSyncData.filter(function (row){ + ​ + return !dataIndex.has(row[3], row[2]); + } + ​); + + + let statements = []; + let toInsert = []; + let cols = ["SYNCCONTACTID", "ASYS_FAVORITEID", "CONTACT_ID", "USER_ID"]; + let vals = []; + let table = "AB_SYNCCONTACT"; + let updStatements = []; + + for(let i = 0; i < toInsertFavs.length; i++) + { + vals = []; + vals = [util.getNewUUID(), toInsertFavs[i][0], toInsertFavs[i][1], toInsertFavs[i][2]] + + statements.push([table, cols, null, vals]); + } + for(let i = 0; i < toUpdate.length; i++) + { + updStatements.push([table, ["DATE_DEL"], null, [vars.get("$sys.date")], "ASYS_FAVORITEID = '" + toUpdate[i][1] + "'" ]); + } + + try{ + let count = db.inserts(statements, "Data_alias"); + let updCount = db.updates(updStatements, "Data_alias"); + } + catch(exc){ + logging.log(exc) + } +} + +/* + * get the contact which are marked with the ewssync favorite Tag + * + * @return [Array] favorite Data [[]] + */ +EwsClientSyncUtils.getEwsFavorites = function(){ + + + //get Favorites which are tagged with the Sync Tag + // var conf = favorite.createGetFavoritesConfig(); + // conf.setFavoriteGroupTitle(EwsClientSyncUtils.EWSSYNCTAG()); + // conf.setObjectType("Person"); + // + // var favoriteData = favorite.getFavorites(conf); + // var favoriteDataArray = []; + // + // for (var temp in favoriteData) + // { + // let favId = favoriteData[temp]["id"]; + // let rowId = favoriteData[temp]["rowid"]; + // let userID = favoriteData[temp]["group"]["groupuser"]; + // + // favoriteDataArray.push([favId, rowId, userID]); + // } + + + //in the current version it isn't possible to call the favorite API within a Serverprocess this will be implemented in the next RC + + var favoriteDataArray = new SqlBuilder("_____SYSTEMALIAS") + .selectDistinct("ASYS_RECORD.ID, ASYS_RECORD.ROW_ID, ASYS_RECORDGROUP.USER_ID") + .from("ASYS_RECORD") + .join("ASYS_RECORDGROUP", "ASYS_RECORDGROUP.ID = ASYS_RECORD.RECORDGROUP_ID") + .where("ASYS_RECORD.OBJECT_TYPE", "Person") + .and("ASYS_RECORDGROUP.TITLE", EwsClientSyncUtils.EWSSYNCTAG(), "LOWER(#) = ?") + .groupBy("ASYS_RECORDGROUP.USER_ID, ASYS_RECORD.ROW_ID, ASYS_RECORD.ID") + .table(); + + return favoriteDataArray; +} + +/* + * sets the editdate for the entrys in the synctable, in reason to get synced with exchange + * + * @param {String} pTableName + * @param {String} pDataSetID req + * @param {String} pDate req + * + * @return {void} + + */ +EwsClientSyncUtils.setContactToSync = function(pTableName, pDataSetID, pDate){ + + var affectedTables = ["ORGANISATION" , "PERSON", "CONTACT", "ADDRESS", "COMMUNICATION"]; + var affectedIDs = []; + + if (affectedTables.indexOf(pTableName) != -1) + { + switch(pTableName) + { + case "ORGANISATION": + affectedIDs = newSelect("CONTACT.CONTACTID").from("CONTACT").where("CONTACT.ORGANISATION_ID", pDataSetID).arrayColumn(); + break; + case "PERSON": + affectedIDs = newSelect("CONTACT.CONTACTID").from("CONTACT").where("CONTACT.PERSON_ID", pDataSetID).arrayColumn(); + break; + case "CONTACT": + affectedIDs = [pDataSetID]; + break; + case "ADDRESS": + affectedIDs = newSelect("ADDRESS.CONTACT_ID").from("ADDRESS") + .where("ADDRESS.ADDRESSID", pDataSetID) + .union(newSelect("CONTACT.CONTACT_ID").from("CONTACT").where("CONTACT.ADDRESS_ID", pDataSetID)).arrayColumn(); + break; + case "COMMUNICATION": + affectedIDs = newSelect("COMMUNICATION.CONTACT_ID").from("COMMUNICATION").where("COMMUNICATION.COMMUNICATIONID", pDataSetID).arrayColumn(); + break; + } + + if (affectedIDs.length > 0) + { + var upd = db.updateData("AB_SYNCCONTACT", ["DATE_EDIT"], null, [pDate], + "EXCHANGEID is not null and CONTACT_ID in ('" + affectedIDs.join("','") + "')"); + } + } +} + + +/* + * prepare Placholder for Exchange contacts + * + * @param {String} pUserId + */ +EwsClientSyncUtils.getPlaceholders = function(pUserId){ + var ewsPlaceholders = []; + + //EWS Sync Placeholder + //See EWS API Doc for other placeholder + //new Placeholder that has to be synced probably has also to be added in addDataToValueObjects() in the serverprocess + _addSqlPart("CONTACTID", "CONTACT.CONTACTID"); + _addSqlPart("EXCHANGEID", "select EXCHANGEID from ab_synccontact where Ab_synccontact.contact_id = contact.contactid and user_id = '"+ pUserId +"'", null, null) + + _addSqlPart("Givenname", "PERSON.FIRSTNAME"); + _addSqlPart("Surname", "PERSON.LASTNAME"); + _addSqlPart("Department", "CONTACT.DEPARTMENT"); + _addSqlPart("JobTitle", "CONTACT.CONTACTROLE"); + _addSqlPart("CompanyName", "ORGANISATION.NAME"); + + + _addAddressFormat("Business_street", "{street} {buildingno}"); + _addAddressFormat("Business_postalcode", "{zip}"); + _addAddressFormat("Business_city", "{city}"); + _addAddressFormat("Business_state", "{district}"); + _addAddressFormat("Business_countryorregion", "{country}"); + + _addSqlPart("EmailAddress1", CommUtil.getStandardSubSqlMail()); + + _addSqlPart("BusinessPhone", CommUtil.getStandardSubSqlPhone()); + _addSqlPart("BusinessHomepage", CommUtil.getMediumAddrSubSqlByKey("COMMINTERNET")); + + _addSqlPart("OtherFax", CommUtil.getMediumAddrSubSqlByKey("COMMFAX")); + _addSqlPart("MobilePhone", CommUtil.getMediumAddrSubSqlByKey("COMMMOBIL")); + _addSqlPart("FileAsMapping","case when PERSON_ID is not null then 'SurnameCommaGivenName' else 'Company' end" , null, null); + + + // _addSqlPart("HomePhone", "''"); + // _addSqlPart("HomeFax", "''"); + // _addSqlPart("EmailAddress2", "''"); + + + + return ewsPlaceholders; + + function _addSqlPart (pName, pSqlPart, pTarget, pTitle) + { + ewsPlaceholders.push(new Placeholder(pName, Placeholder.types.SQLPART, "(" + pSqlPart + ")", pTarget, pTitle)); + } + /** + * add an address format placeholder to placeholders + */ + function _addAddressFormat (pName, pFormat, pTarget, pTitle) + { + ewsPlaceholders.push(new Placeholder(pName, Placeholder.types.ADDRESSFORMAT, pFormat, pTarget, pTitle)); + } +} + +/* + * removes Person favorites with the EWS Tag + * + * @param {Array} pToDelete contains contact_ids for which the favorite should be removed + * @param {String} pUserId - User for which the favorites should be removed + * + * @return {Boolean} true if successfull + * + */ +EwsClientSyncUtils.removeFromFavorite = function(pToDelete, pUserId ){ + + //maybe in a future version there will be a way to remove favorites on a better way + + //all ews related Favorites for the user + var config = favorite.createGetFavoritesConfig() + .setFavoriteGroupTitle(EwsClientSyncUtils.EWSSYNCTAG()) + .setGroupType(favorite.FAVORITE_GROUP).setObjectType("Person") + .setUserId(pUserId); + + var ewsFavorite = favorite.getFavorites(config); + var favsToDelete = []; + + var dataIndex = { + index: new Map(), + add: function (pA) + { + var idxMap = this.index; + if (!idxMap.has(pA)) + idxMap.set(pA, new Set()); + }, + has: function (pA) + { + return this.index.has(pA); + } + }; + + for each(let row in pToDelete) + { + dataIndex.add(row) + } + + // delete those which are in the selection and are also in ewsFavorite + for each (let row in ewsFavorite) + { + if(dataIndex.has(row["rowid"])) + favsToDelete.push(row["id"]); + } + + var delConfig = favorite.createRemoveMultipleByIdConfig().setFavoriteRecordIds(favsToDelete); + + return favorite.remove(delConfig); +} + +/* + * Add contacts to favorites as ewssync group + * + * @param {Array} pToInsert Array with contactIds which should be added to the sync + */ +EwsClientSyncUtils.addToEwsFavorite = function(pToInsert){ + var userID = tools.getCurrentUser()[tools.NAME] + + var config = favorite.createAddFavoriteConfig(); + config.setFavoriteGroupTitle(EwsClientSyncUtils.EWSSYNCTAG()); + config.setObjectType("Person"); + config.setUserId(userID); + config.setGroupType(favorite.FAVORITE_GROUP) + + for(let i = 0, l = pToInsert.length; i < l; i++){ + config.setRowId(pToInsert[i]); + favorite.add(config); + } +} + +/** + * Opens a context to add or remove contacts from the ewssync<br> + * + * @param {String[]} pContactIds Contacts that should be added.<br> + * @param {String|Object} pFilter the filter for the contacts that should be used if no contact is selected + * @param {String} pMode the mode which should be used ("ADD" or "REMOVE") default ADD + */ +EwsClientSyncUtils.openEwsSyncAddContactView = function(pContactIds, pFilter, pMode) +{ + if (!Utils.isString(pContactIds)) + pContactIds = JSON.stringify(pContactIds); + if (!Utils.isString(pFilter)) + pFilter = JSON.stringify(pFilter); + + var params = { + "ContactIds_param": pContactIds, + "ContactFilter_param": pFilter, + "Mode_param": pMode + } + neon.openContext("EwsSyncAddContacts", "EwsSyncAddContactsEdit_view", null, neon.OPERATINGSTATE_VIEW, params); +} + \ No newline at end of file diff --git a/process/EwsClient_lib/process.js b/process/EwsClient_lib/process.js index 2de3addde44d76ac3ad80c4f264e837fc6d90e45..51dd088565b42911b3354abcf3b823cf6c1152f1 100644 --- a/process/EwsClient_lib/process.js +++ b/process/EwsClient_lib/process.js @@ -62,7 +62,10 @@ $EwsClientTaskDescriptions.GET_CONTACTS_BY_FOLDERS = function(){retur $EwsClientTaskDescriptions.GET_CONTACTSDEFAULTFOLDER = function(){return "GET_CONTACTSDEFAULTFOLDER"}; $EwsClientTaskDescriptions.GET_CONTACTFOLDERS = function(){return "GET_CONTACTFOLDERS"}; $EwsClientTaskDescriptions.UPDATE_CONTACT = function(){return "UPDATE_CONTACT"}; - +$EwsClientTaskDescriptions.INSERT_CONTACT_LIST_TO_FOLDER = function(){return "INSERT_CONTACT_LIST_TO_FOLDER"}; +$EwsClientTaskDescriptions.INSERT_CONTACT_LIST = function(){return "INSERT_CONTACT_LIST"}; +$EwsClientTaskDescriptions.UPDATE_CONTACT_LIST = function(){return "UPDATE_CONTACT_LIST"}; +$EwsClientTaskDescriptions.DELETE_CONTACT_LIST_BY_IDS = function(){return "DELETE_CONTACT_LIST_BY_IDS"}; function $EwsClientImpersonationModes(){} /** * Impersonation mode NONE should be set if no impersonation user is used and every user is authenticated per user-data @@ -400,4 +403,394 @@ EwsClientCalendarPermissionUtils._getCalendarPermissionFromResult = function (pP + "there exists a write but no read permission"); return retVal; +} + + + +/* + * provides static methods for the use of the exchange Contact Sync + * @class + */ +function EwsSyncContactUtils(){} + +EwsSyncContactUtils.getEwsSyncTag = function(){ + return "ewssync"; +} + + +/* + * returns the contact Folder for the passed mailbox + * requires the EWSClientPlugin + * + * @param {String} pAliasName name of the exchange alias + * @param {String} pMailbox mailbox of which the folder should be read + * + * @return {Array} array with maps [["id"], ["name"]] + */ +EwsSyncContactUtils.getContactFolders = function(pAliasName, pMailbox){ + + let taskDescription = $EwsClientTaskDescriptions.GET_CONTACTFOLDERS(); + + let task = <mailbox>{ + pMailbox + }</mailbox>; + + let pluginInput = EwsClientXMLUtils.getRequestXMLforAlias(taskDescription, task, $EwsClientImpersonationModes.SINGLE(), pAliasName); + let xmlOutput = EwsClientUtils.callPlugin(pluginInput); + let retVal = []; + + for each (folder in xmlOutput.folders.folder) + { + let map = {}; + map["id"] = folder.id; + map["name"] = folder.name; + retVal.push(map); + } + return retVal; +} + + +EwsSyncContactUtils.updateContacts = function(pAliasName, pMailbox, pObjects, doDebug ){ + let taskDescription = $EwsClientTaskDescriptions.UPDATE_CONTACT_LIST(); + + let tasks = <mailbox>{ + pMailbox + } + </mailbox>; + + let contactsXml = <contacts/> + + for each(let [pUniqueId, pData, pAddresses] in pObjects) + { + if(pUniqueId) + contactsXml.appendChild(EwsSyncContactXMLUtils.mapContactToXML(pData, pAddresses, pUniqueId, true)); + } + tasks += contactsXml; + + let pluginInput = EwsClientXMLUtils.getRequestXMLforAlias(taskDescription, tasks, $EwsClientImpersonationModes.SINGLE(), pAliasName); + + let xmlOutput = EwsClientUtils.callPlugin(pluginInput); + + return EwsSyncContactUtils.proceedPluginXmlOutput(xmlOutput, 2, doDebug); +} + + +/** + * Adds a contact in a specific folder + * requires EWSClientPlugin + * + * @param {String} pAliasName name of the Alias which contains connectiondata + * @param {String} pMailbox owner of the contact + * @param {String} pUniqueId defines folder + * @param {[[dataArray, adressArray]]} pObjects + * @param {boolean} doDebug + * + * @return {String} new unique ID of the contact (ExchangeID) + * + * pData array with maps with following structure: + * ["key"] + * ["value"] + * + * pAddresses array with following Maps + * ["addressKey"] + * ["value"] -> array with Maps with following structure ["key"] + * ["value] + * + * existing Key for a exchange Contact: + * title, givenname, middlename, surname + * jobtitle, officelocation, department, companyname, manager, assistentname, businesshomepage + * fileasmapping + * messagebody, categories + * id, changekey, lastmodifiedtime, datetimecreated (read only) + * + * - possible phone numbers: + * AssistantPhone, BusinessFax, BusinessPhone, BusinessPhone2, Callback, CarPhone, CompanyMainPhone, HomeFax, HomePhone, + * HomePhone2, Isdn, MobilePhone, OtherFax, OtherTelephone, Pager, PrimaryPhone, RadioPhone, Telex, TtyTddPhone + * + * - possible Mailing: + * EmailAddress1, EmailAddress2, EmailAddress3 + * + * - possible Instant Messaging: + * ImAddress1, ImAddress2, ImAddress3 + * + * - possible Adressen: + * Business, Home, Other + * - possible values of a adress: + * street, postalcode, city, state, countryorregion + * + * postaladdressindex + * - possible value for "postaladdressindex" + * None, Business, Home, Other + */ +EwsSyncContactUtils.insertContactsToFolder = function(pAliasName, pMailbox, pUniqueId, pObjects, doDebug) +{ + + let taskDescription = $EwsClientTaskDescriptions.INSERT_CONTACT_LIST_TO_FOLDER(); + + let task = <uniqueId>{ + pUniqueId + }</uniqueId> + + task += <mailbox>{ + pMailbox + }</mailbox> + + let contactsXml = <contacts/> + + for each(let [pData, pAddresses] in pObjects) + { + contactsXml.appendChild(EwsSyncContactXMLUtils.mapContactToXML(pData, pAddresses)); + } + task += contactsXml; + + let pluginInput = EwsClientXMLUtils.getRequestXMLforAlias(taskDescription, task, $EwsClientImpersonationModes.SINGLE(), pAliasName); + let xmlOutput = EwsClientUtils.callPlugin(pluginInput); + + return EwsSyncContactUtils.proceedPluginXmlOutput(xmlOutput, 1, doDebug); +} + +/** + * deletes unique Contacts out of EWS + * Voraussetzung ist EWSClientPlugin + * + * @param {String} pAliasName Name des Alias aus dem die Verbindungsdaten ausgelesen werden können + * @param {String} pUniqueIds Definiert Die Kontakte die + * @param {String} pMailBox opt falls angegen wird der ImpersonatedUser verwendet + * @param {boolean} doDebug + * + * @return {String[]} Array with results for Structure see Example + * @example + * Structure of the result from plugin + * [ + * [exchangeIdsWithNoError, n], + * [[id, "Error", "errorMsg", "Type"], [idn, "Error", "errorMsg", "Type"] ] + * ] + */ +EwsSyncContactUtils.deleteContactByID = function(pAliasName, pUniqueIds, pMailBox, doDebug) +{ + let taskDescription = $EwsClientTaskDescriptions.DELETE_CONTACT_LIST_BY_IDS(); + + let task = <uniqueIds/>; + + for each(let pUniqueId in pUniqueIds) + { + if(pUniqueId) + task.appendChild(<uniqueId>{ + pUniqueId + }</uniqueId>) + } + + let pluginInput; + + if ( pMailBox == undefined ) + { + pluginInput = EwsClientXMLUtils.getRequestXMLforAlias(taskDescription, task, $EwsClientImpersonationModes.NONE(), pAliasName); + } + else + { + task += <mailbox>{ + pMailBox + }</mailbox>; + pluginInput = EwsClientXMLUtils.getRequestXMLforAlias(taskDescription, task, $EwsClientImpersonationModes.SINGLE(), pAliasName); + } + + var xmlOutput = EwsClientUtils.callPlugin(pluginInput); + + return EwsSyncContactUtils.proceedPluginXmlOutput(xmlOutput, 3, doDebug); +} + +/* + * proceeds the plugin outputXMl and returns contactId and ExchangeID, + * + * @param {XML} pXmlOutput output of the plugin call + * @param {int} pMode controlls proceeding 1 - insert, 2 - update, 3 - delete + * @param {boolean} doDebug + * + * @return {Array} 2d Array with contactIds, unigueID(ExchangeID) and ErrorArray + * + */ +EwsSyncContactUtils.proceedPluginXmlOutput = function(pXmlOutput, pMode, doDebug){ + + var contactRes = []; + var failedIds = []; + var status, uniqueId, resultMessage, resultCode; + + //insert and Update + if(pMode < 3) + { + //for every contactResult in the contactResults list + for each( contactResult in pXmlOutput.contactResults.contactResult ) + { + var keyValues = contactResult.contact.keyValues.keyValue; + var contactid = ""; + + for each( keyValue in keyValues ) + { + if(keyValue.key.toString() == "CONTACTID")//we only need the contactid value + { + contactid = keyValue.value.toString(); + break; + } + } + + status = contactResult.result.toString(); + resultMessage = contactResult.resultMessage.toString(); + + //during update the xml structure is slightly different + uniqueId = (Number(pMode) == 2) ? contactResult.contact.@uniqueId.toString() : contactResult.uniqueId.toString(); + + if(status == "Success" && contactid != "" && uniqueId != "")//only if the action was successfull + { + if(pMode == 2)//update + contactRes.push(uniqueId); + else + contactRes.push([contactid, uniqueId]);//push for update/insert in AB_SYNCCONTACT + } + else + { + resultCode = contactResult.resultCode.toString(); + failedIds.push([contactid, status, resultMessage, resultCode, contactResult.contact.toString()]) + } + } + if(doDebug) logging.log("failedIds: " + failedIds.toSource()); + }//pMode < 3 + else + //the delete result xml differs from insert and update + if (pMode == 3) + { + for each( contactResult in pXmlOutput.resultBundles.resultBundle ) + { + //keyvalues + status = contactResult.result.toString(); + uniqueId = contactResult.uniqueId.toString(); + + if(status == "Success" && uniqueId != "") + { + contactRes.push(uniqueId);//push for deleting in AB_SYNCCONTACT + } + else + { + //get Keyvalues + resultMessage = contactResult.resultMessage.toString(); + resultCode = contactResult.resultCode.toString(); + + failedIds.push([uniqueId, status, resultMessage, resultCode]); + } + } + } + + return [contactRes, failedIds]; +} + +/* + *Class for handling ews XML + * + * @class + */ +function EwsSyncContactXMLUtils(){} + + +EwsSyncContactXMLUtils.mapContactToXML = function( pData, pAddresses, pExchangeId, isUpdate) +{ + var content = <contact> + <keyValues/> + <physicalAddresses/> + </contact>; + + if(isUpdate) + { + content = <contact uniqueId={ + pExchangeId + }> + <keyValues/> + <physicalAddresses/> + </contact>; + } + + //add contactData e.g. Name,Lastname, department etc. + for each (let map in pData) + { + let keyXml = <keyValue/> + let mapKey = map["key"]; + let mapVal = map["value"]; + + keyXml.appendChild(<key>{ + mapKey + }</key>); + keyXml.appendChild(<value>{ + mapVal + }</value>); + + //append contactdata to parent xml + content.keyValues.appendChild(keyXml); + } + + //TODO: refactor when for of Loop is available + for each( let outerMap in pAddresses ) + { + var adressXml = <physicalAddresse/> + var pAdressKey = outerMap["addressKey"]; + + adressXml.appendChild(<addressKey>{ + pAdressKey + }</addressKey>) + + var list = outerMap["value"]; + + adressXml.appendChild(<keyValues/>) + + for each( let innerMap in list ) + { + let keyXml = <keyValue/> + let innerMapKey = innerMap["key"]; + let innerMapValue = innerMap["value"]; + + + keyXml.appendChild(<key>{ + innerMapKey + }</key>); + keyXml.appendChild(<value>{ + innerMapValue + }</value>); + + adressXml.keyValues.appendChild(keyXml); + } + //append adressxml to parent + content.physicalAddresses.appendChild(adressXml); + } + return content; + } + +EwsSyncContactXMLUtils.mapContactFromXML = function( pContactXML ) +{ + let retVal = {}; + let shallow = []; + + for each (keyValue in pContactXML.keyValues.keyValue) + { + let map = {}; + map["key"] = keyValue.key; + map["value"] = keyValue.value; + shallow.push(map); + } + retVal["shallow"] = shallow; + + let addresses = []; + for each (physicalAddresse in pContactXML.physicalAddresses.physicalAddresse) + { + + let outerMap = {}; + outerMap["addressKey"] = physicalAddresse.addressKey; + let list = []; + for each(keyValue in physicalAddresse.keyValues) + { + let innerMap = {}; + innerMap["key"] = keyValue.key; + outerMap["value"] = keyValue.value; + list.push(innerMap); + } + outerMap["value"] = list; + } + retVal["addresses"] = addresses; + return retVal; } \ No newline at end of file diff --git a/process/Favorites_lib/process.js b/process/Favorites_lib/process.js index d5e32f5145cb4d324f5f47e69cfe2de852b52ca9..a02f3dfcc2146f31e6936f51870c92120f0f427c 100644 --- a/process/Favorites_lib/process.js +++ b/process/Favorites_lib/process.js @@ -30,30 +30,56 @@ FavoritesUtil.getUserFavoriteGroups = function() return Array.from(allTypes); } +/** + * Here we prepare the filtercondition for favorites of a certain pObjecttype, pOperator and pRowvalue. + * In certain circumstances, the rowids need to be prepared earlier (Person / Organisation). If so, they can be inserted by pPreparedRowIds. + * Then they won't be loaded again inside this method. + */ +FavoritesUtil.getFilterDisplayCondition = function(pObjecttype, pOperator, pRawvalue, pIdColumn, pPreparedRowIds) +{ + var favoFilterCond = newWhere(); + + if(pPreparedRowIds == null || pPreparedRowIds.length == 0) + pPreparedRowIds = FavoritesUtil.getRowIdsOfFavorites(pObjecttype, pOperator, pRawvalue); + if(pOperator == "1" || pOperator == "2" || pOperator == "11") // equal / not equal / not empty -> compare on result values + { + for(i = 0; i < pPreparedRowIds.length; i++) + favoFilterCond.or(pIdColumn, pPreparedRowIds[i], SqlBuilder.EQUAL()); + } + else if(pOperator == "12") // empty + favoFilterCond.and(pIdColumn, pPreparedRowIds, SqlBuilder.NOT_IN()); -FavoritesUtil.getRowIdsOfFavoriteGroup = function() + return favoFilterCond.toString(); +} +/** + * Gets all favorized datasetids by a given pObjecttype, pOperator and the Favoritegroup-Title it is stored with + */ +FavoritesUtil.getRowIdsOfFavorites = function(pObjecttype, pOperator, pRawvalue) { var sysAlias = favorite.getFavoritesAlias(); + var op = ""; - var value = vars.get("$local.rawvalue"); - var operator = vars.get("$local.operator") //noch zu implementieren + if(pOperator == "1") + op = SqlBuilder.EQUAL(); + else if(pOperator == "2") + op = SqlBuilder.NOT_EQUAL(); + else if(pOperator == "11") + op = SqlBuilder.IN(); + else if(pOperator == "12") + op = SqlBuilder.NOT_IN(); - if(value && operator) - { - var filterCond = newWhere("ASYS_RECORDGROUP.TITLE", value, null, null, sysAlias); //Operators fehlen noch - filterCond.and(newWhere("ASYS_RECORDGROUP.USER_ID", tools.getCurrentUser()["name"], null, null, sysAlias)); - - var rowIds = new SqlBuilder(sysAlias).selectDistinct("ASYS_RECORD.ROW_ID") - .from("ASYS_RECORD") - .join("ASYS_RECORDGROUP", "ASYS_RECORD.RECORDGROUP_ID = ASYS_RECORDGROUP.ID") - .where(filterCond) - .arrayColumn(); - - return rowIds; - } - - return null; + var filterCond = newWhereIfSet("ASYS_RECORDGROUP.TITLE", pRawvalue, op, null, sysAlias); //Operators fehlen noch + filterCond.and(newWhere("ASYS_RECORDGROUP.USER_ID", tools.getCurrentUser()["name"], null, null, sysAlias)); + filterCond.and(newWhere("ASYS_RECORD.OBJECT_TYPE", pObjecttype, null, null, sysAlias)); + + var rowIds = new SqlBuilder(sysAlias).selectDistinct("ASYS_RECORD.ROW_ID") + .from("ASYS_RECORD") + .join("ASYS_RECORDGROUP", "ASYS_RECORD.RECORDGROUP_ID = ASYS_RECORDGROUP.ID") + .where(filterCond) + .arrayColumn(); + + return rowIds; } FavoritesUtil.getUserFavoriteGroupsByContext = function(pContext) diff --git a/process/Sql_lib/process.js b/process/Sql_lib/process.js index 98fe8cc944264fe98c8ffc7a636128705da4ec35..f3708067a34ad01930d3ade922c9520011e1bb91 100644 --- a/process/Sql_lib/process.js +++ b/process/Sql_lib/process.js @@ -3527,7 +3527,8 @@ SqlMaskingUtils.prototype.cast = function (pField, pTargetDatatype, pTargetLengt switch(pTargetDatatype) { case SQLTYPES.TIMESTAMP: - return "datetime"; + sqlDataType = "datetime"; + break; case SQLTYPES.DATE: case SQLTYPES.DECIMAL: case SQLTYPES.INTEGER: diff --git a/process/ewsSyncContacts_serverProcess/ewsSyncContacts_serverProcess.aod b/process/ewsSyncContacts_serverProcess/ewsSyncContacts_serverProcess.aod new file mode 100644 index 0000000000000000000000000000000000000000..fbbe02fc2fff34c845acc1f03e22f34836da4ab6 --- /dev/null +++ b/process/ewsSyncContacts_serverProcess/ewsSyncContacts_serverProcess.aod @@ -0,0 +1,12 @@ +<?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.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.2"> + <name>ewsSyncContacts_serverProcess</name> + <title>Sync Exchange Contacts</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <process>%aditoprj%/process/ewsSyncContacts_serverProcess/process.js</process> + <alias>Data_alias</alias> + <variants> + <element>EXECUTABLE</element> + <element>LIBRARY</element> + </variants> +</process> diff --git a/process/ewsSyncContacts_serverProcess/process.js b/process/ewsSyncContacts_serverProcess/process.js new file mode 100644 index 0000000000000000000000000000000000000000..fd420916d9172146ce5f60943ae629bf8578cd82 --- /dev/null +++ b/process/ewsSyncContacts_serverProcess/process.js @@ -0,0 +1,588 @@ +import("Util_lib"); +import("system.project"); +import("system.favorite"); +import("system.db"); +import("system.result"); +import("EwsClient_lib"); +import("system.text"); +import("Address_lib"); +import("Communication_lib"); +import("system.vars"); +import("Sql_lib"); +import("system.tools"); +import("system.logging"); +import("EwsClientSync_lib"); + +//inserting new Data in the asys_synccontact table and deleting those which aren't anymore in the favorite context +EwsClientSyncUtils.prepareContactSyncTable(); + +//start Sync with Exchange +var msg = runSync(); + +if(msg.length){ + result.string(msg.join("\n")); +} + +function runSync(){ + var doDebug = false; + var retMsg = []; + + var syncUser = newSelect("distinct USER_ID").from("AB_SYNCCONTACT").arrayColumn(); + + for (var i= 0 ; i < syncUser.length; i++) + { + var user = tools.getUserByAttribute(tools.NAME, [syncUser[i]], tools.PROFILE_DEFAULT); + if (user) + { + var mailBox = user[tools.PARAMS][tools.EXCHANGE_EMAIL]; + + if(!mailBox)//use the mail of the user as backup exchangeMail adress + mailBox = user[tools.PARAMS][tools.EMAIL]; + + + var exAlias = user[tools.PARAMS][tools.CALENDAR_ALIAS]; + + if (!exAlias) + exAlias = project.getInstanceConfigValue("calendarAlias", null); + + var login = user[tools.TITLE]; + var lastRunDate = user[tools.PARAMS]["lastEwsSyncContact"]; + var runDate = vars.get("$sys.date"); + user[tools.PARAMS]["lastEwsSyncContact"] = runDate; + + if (mailBox != "" && exAlias != "") + { + if(doDebug) logging.log("ContactSync for User: " + login + " started") + + let delContacts = EWSdeleteContactsForUser(syncUser[i], mailBox, exAlias, login, doDebug); + let updateContacts = EWSupdateContactsForUser(syncUser[i], mailBox, exAlias, lastRunDate, login, doDebug); + let insertContacts = EWSinsertContactsForUser(syncUser[i], mailBox, exAlias, runDate, login, doDebug); + + if(delContacts.length) + retMsg.push(delContacts); + if(updateContacts.length) + retMsg.push(updateContacts); + if(insertContacts.length) + retMsg.push(insertContacts); + + tools.updateUser(user); + + if(doDebug) logging.log("ContactSync for User: " + login + " completed") + } + else + { + retMsg.push(["No exchange configuration exists for user " + login]); + } + } + } + if(doDebug) logging.log("EWSContactSync completed"); + + return retMsg; +} + +/**************************************************************************************************/ + +/* + * deletes the Synced Contacts for the passed User + * + * @param {String} pUserID ID of the User for which Contact should be removed from sync + * @param {String} pMailBox Exchange Mail + * @param {String} pAlias name of the Exchange Alias + * @param {String} pUser Login of the User + * @param {boolean} doDebug + * +*/ +function EWSdeleteContactsForUser(pUserID, pMailBox, pAlias, pUser, doDebug) +{ + //delete all Entrys with a DATE_DEL tag, those were removed between the last import and yet + var cond = newWhere("AB_SYNCCONTACT.DATE_DEL is not null").and("AB_SYNCCONTACT.USER_ID", pUserID); + + var delContacts = newSelect("AB_SYNCCONTACT.EXCHANGEID") + .from("AB_SYNCCONTACT") + .where(cond) + .and("AB_SYNCCONTACT.EXCHANGEID is not null") + .arrayColumn(); + + var deletions = Utils.clone(delContacts); + + var exchangeids = []; + while(deletions.length > 0) + { + let deletionPart = deletions.splice(0, 200); + try{ + exchangeids = exchangeids.concat(EwsSyncContactUtils.deleteContactByID(pAlias, deletionPart, pMailBox, doDebug)); + } + catch(ex) + { + let errMsg = "Error while calling the plugin: " + logging.toLogString(ex.rhinoException != undefined ? ex.rhinoException : ex, true) + "\r\n"; + logging.log(errMsg); + return [errMsg]; + } + } + + var errorItems = []; + var notFoundItems = []; + var deletedItems = []; + + if(exchangeids.length > 0) + { + //no errors during deletion in Exchange + while (exchangeids[0].length > 0) + { + let exchangeidsPart = exchangeids[0].splice(0, 30);//max limit 30 + + cond.and("AB_SYNCCONTACT.EXCHANGEID", exchangeidsPart, SqlBuilder.IN()).deleteData(); + deletedItems = deletedItems.concat(exchangeidsPart); + } + + //exchange Entrys with errors for deleting + while (exchangeids[1].length > 0) + { + if(doDebug) logging.log("Exchange Entrys with Errors: " + exchangeids[1].length); + var deletes = []; + + let exchangeidsPart = exchangeids[1].splice(0, 30);//max limit 30 + + for (let i = 0; i < exchangeidsPart.length; i++) + { + if(exchangeidsPart[i][3] == "ErrorItemNotFound") + { + deletes.push(exchangeidsPart[i][0]); + notFoundItems.push(exchangeidsPart[i][0] , pUserID); + } + else + { + errorItems.push(exchangeidsPart[i][0] , pUserID); + } + } + + if(deletes.length > 0) + { + let affectedRows = cond.and("AB_SYNCCONTACT.EXCHANGEID", deletes, SqlBuilder.IN()).deleteData(); + if(doDebug) logging.log("Anzahl der gelöschten Einträge: " + affectedRows); + deletedItems = deletedItems.concat(deletes); + } + + //clearing the where condition and preset it to it's origin condition + cond.clearWhere(); + cond.where("AB_SYNCCONTACT.DATE_DEL is not null").and("AB_SYNCCONTACT.USER_ID", pUserID); + } + + if(doDebug && notFoundItems.length > 0) + logging.log("EWSSYnc not found items: " + notFoundItems.toSource()); + + if(errorItems.length > 0) + logging.log("EWSSYnc error items: " + errorItems.toSource()); + + if(doDebug && deletedItems.length > 0) + logging.log("EWSSYnc deleted items: " + deletedItems.toSource()); + } + return errorItems; +} + + + +/* + * updates the Synced Contacts for the passed User + * + * @param {String} pUserID ID of the User for which Contact should be updated + * @param {String} pMailBox Exchange Mail + * @param {String} pAlias name of the Exchange Alias + * @param {String} pRunDate lastRunDate of the sync + * @param {String} pUser Login of the User + * @param {boolean} doDebug + * +*/ +function EWSupdateContactsForUser(pUserID, pMailBox, pAlias, pRunDate, pUser, doDebug) +{ + var runDate = (!pRunDate) ? 0 : pRunDate; + + //get Contacts for update + var cond = newWhere("AB_SYNCCONTACT.EXCHANGEID is not null") + .and("AB_SYNCCONTACT.USER_ID", pUserID) + .and("AB_SYNCCONTACT.DATE_EDIT", runDate, SqlBuilder.GREATER()); + + var contactsData = newSelect("AB_SYNCCONTACT.CONTACT_ID") + .from("AB_SYNCCONTACT") + .where(cond) + .arrayColumn(); + + var retMsg = []; + + if (contactsData.length > 0) + { + //get data with config + var config = EwsClientSyncUtils.getPlaceholders(pUserID); + var data = getAddressData(contactsData, config); + + //data pos 0 contains column Name - use them as key for the User object + var header = []; + for (let i = 0; i < data[0].length; i++) + { + header.push(data[0][i].replace(new RegExp("[{@}]","g"), "")); //replace start and end delimeter which are set in the getAdressData Method + } + + var dataObj, addrObj, addrValueObjBusiness, addrValueObjHome, addrValueObjOther, exchangeId; + var objects = []; + //loop through array at pos 1, header has been already collected + for (let i = 1; i < data.length; i++) + { + //dataObj at pos data[i][j] will match to the header[j] + dataObj = new Object(); + addrObj = new Object(); + addrValueObjBusiness = {}; + addrValueObjHome = {}; + addrValueObjOther = {}; + + //addressdata will allocated with tags (Business_, Home_, Other_) to each object + for (let j = 0; j < header.length; j++) + { + addDataToValueObjects(header[j], data[i][j], dataObj, addrValueObjBusiness, addrValueObjHome, addrValueObjOther); + } + + //build addr object out of the objects generated above + buildAddrObject(addrObj, addrValueObjHome, addrValueObjBusiness, addrValueObjOther); + + // Get the exchangeID from the data-object for update + let exchangeId = dataObj["EXCHANGEID"].value; + objects.push([exchangeId, dataObj, addrObj]); + } + + var errorItems = []; + var notFoundItems = []; + var deletedItems = []; + + while(objects.length > 0) + { + let objectsPart = objects.splice(0, 200);//currently max limit: 200 + try + { + exchangeIds = EwsSyncContactUtils.updateContacts(pAlias, pMailBox, objectsPart, doDebug);//run plugin + } + catch(ex) + { + let errMsg = "Error while calling the plugin: " + logging.toLogString(ex.rhinoException != undefined ? ex.rhinoException : ex, true) + "\r\n"; + logging.log(errMsg); + return [errMsg]; + } + + //exchangeIDs[1] array for the contacts which got an error + while(exchangeIds[1].length > 0) + { + var deletes = []; + + let exchangeIdsPart = exchangeIds[1].splice(0, 30); + + for (let i = 0; i < exchangeIdsPart.length; i++) + { + //contact which aren't in Exchange anymore can be deleted out of the sync + if(exchangeIdsPart[i][3] == "ErrorItemNotFound") + { + deletes.push(exchangeIdsPart[i][0]); + notFoundItems.push(exchangeIdsPart[i][0] , pUserID); + } + else + { + errorItems.push(exchangeIdsPart[i].toSource(), pUserID); + retMsg.push( exchangeIDs[1][0] + " : " + exchangeIDs[1][2] + " " + exchangeIDs[1][3] ); + } + } + + if(deletes.length > 0) + { + //delete out of sync table + db.deleteData("AB_SYNCCONTACT", " CONTACT_ID in ('" + deletes.join("', '") + "') and USER_ID = '" + pUserID + "'", "Data_alias", 300000); + + //remove set favorite for those which are delted - otherwise they would appear in the next run as 'new' Contacts + EwsClientSyncUtils.removeFromFavorite(deletes, pUserID); + deletedItems = deletedItems.concat(deletes); + } + } + }//while object > 0 + + if(doDebug && notFoundItems.length > 0) + logging.log("EWSSYnc not found items: " + notFoundItems.toSource()); + + if(errorItems.length > 0) + logging.log("EWSSYnc error items: " + errorItems.toSource()); + + if(doDebug && deletedItems.length > 0) + logging.log("EWSSYnc deleted items: " + deletedItems.toSource()); + }//contactsData.length > 0 + + return retMsg; +} + +/* + * updates the Synced Contacts for the passed User + * + * @param {String} pUserID ID of the User for which Contact should be updated + * @param {String} pMailBox Exchange Mail + * @param {String} pAlias name of the Exchange Alias + * @param {String} pRunDate lastRunDate of the sync + * @param {String} pUser Login of the User + * @param {boolean} doDebug + * +*/ +function EWSinsertContactsForUser(pUserID, pMailBox, pAlias, pRunDate, pUser, doDebug) +{ + var cond = newWhere("AB_SYNCCONTACT.EXCHANGEID is null") + .and("AB_SYNCCONTACT.USER_ID", pUserID); + + var contactsData = newSelect("AB_SYNCCONTACT.CONTACT_ID") + .from("AB_SYNCCONTACT") + .where(cond) + .arrayColumn(); + var retMsg = []; + if (contactsData.length > 0) + { + var config = EwsClientSyncUtils.getPlaceholders(pUserID) + var data = getAddressData(contactsData, config); + + var header = []; + for (let i = 0; i < data[0].length; i++) + { + header.push(data[0][i].replace(new RegExp("[{@}]","g"), "")) + } + + var dataObj; + var addrObj; + var objects = []; + var addrValueObjHome = {}; + var addrValueObjBusiness = {}; + var addrValueObjOther = {}; + + + //get ID of the ADITO-Ordners + var folderID = getExchangeFolderID(pAlias, pMailBox, "ADITO"); + if (folderID != "") + { + //loop through array at pos 1, header has been already collected + for (var i = 1; i < data.length; i++) + { + dataObj = new Object(); + addrObj = new Object(); + addrValueObjBusiness = {}; + addrValueObjHome = {}; + addrValueObjOther = {}; + + // The address data gets assigned to the respective object + for (let j = 0; j < header.length; j++) + { + addDataToValueObjects(header[j], data[i][j], dataObj, addrValueObjBusiness, addrValueObjHome, addrValueObjOther); + } + + buildAddrObject(addrObj, addrValueObjHome, addrValueObjBusiness, addrValueObjOther); + objects.push([dataObj, addrObj]); + } + + while(objects.length > 0) + { + let objectPart = objects.splice(0, 200); //current limit 200 + + + let exchangeIDs = EwsSyncContactUtils.insertContactsToFolder(pAlias, pMailBox, folderID, objectPart, doDebug); + + while(exchangeIDs[0].length > 0) + { + let exchangeIDsPart = exchangeIDs[0].splice(0, 30);//current limit 30 + updateADITOContactsAfterAction(exchangeIDsPart, pUserID); + } + + //when errors occured + while(exchangeIDs[1].length > 0) + { + retMsg.push( exchangeIDs[1][0] + " : " + exchangeIDs[1][2] + " " + exchangeIDs[1][3] ) + } + }//objects.length > 0 + } + else + return ["No folder 'ADITO' for account '" + pMailBox + "' and user '" + pUser + "' found"]; + } + return retMsg; +} + + +/* + * allocates passed headers/values to their object + * + * @param pHeader {String} fieldname in exchange + * @param pData {String} value for Header + * @param pDataObj {{}} object for contactdata + * @param pAddrValueObjBusiness {{}} adressobject Organisations + * @param pAddrValueObjHome {{}} adressobject homeadress + * @param pAddrValueObjOther {{}} adressobject others + * + */ +function addDataToValueObjects(pHeader, pData, pDataObj, pAddrValueObjBusiness, pAddrValueObjHome, pAddrValueObjOther) +{ + //with used appendChild method the pData values will be escaped automatically + + //differ contactdata and adressdata + //none of the abbreviation defined by the config + var headerNotNull = ["EmailAdress1", "EmailAddress2", "BusinessPhone", "BusinessHomepage", "HomePhone", "HomeFax", "OtherFax", "MobilePhone"]; + + if (pData != "" || headerNotNull.indexOf(pHeader) == -1) + { + if (pHeader.indexOf("Business_") == -1 && pHeader.indexOf("Home_") == -1 && pHeader.indexOf("Other_") == -1 && pData != "") + { + pDataObj[pHeader] = { + "key" : pHeader, + "value" : pData + }; + } + else + { + //Organisation Adress + if (pHeader.indexOf("Business") != -1) + { + pHeader = pHeader.replace("Business_", ""); + pAddrValueObjBusiness[pHeader] = { + "key" : pHeader, + "value" : pData + } + } + //Privatadress + else if (pHeader.indexOf("Home") != -1) + { + pHeader = pHeader.replace("Home_", ""); + pAddrValueObjHome[pHeader] = { + "key" : pHeader, + "value" : pData + } + } + //other Adress + else if (pHeader.indexOf("Other") != -1) + { + pHeader = pHeader.replace("Other_", ""); + pAddrValueObjOther[pHeader] = { + "key" : pHeader, + "value" : pData + } + } + } + } +} + +/* + * Build Address Object for the plugin call + * + * @param pAddrObject {{}} addressobject for call + * @param pAddrValueObjHome {{}} adressobject with Privatadresse + * @param pAddrValueObjBusiness {{}} adressobject for Organisation + * @param pAddrValueObjOther {{}} adressobject for other adresses + */ +function buildAddrObject(pAddrObject, pAddrValueObjHome, pAddrValueObjBusiness, pAddrValueObjOther) +{ + var homeOk = false; + var businessOk = false; + var otherOk = false; + + for each (var obj in pAddrValueObjHome) + { + if (obj["value"] != "") + { + homeOk = true; + break; + } + } + for each (obj in pAddrValueObjBusiness) + { + if (obj["value"] != "") + { + businessOk = true; + break; + } + } + for each (obj in pAddrValueObjOther) + { + if (obj["value"] != "") + { + otherOk = true; + break; + } + } + + if (homeOk) + { + pAddrObject["Home"] = { + "addressKey" : "Home", + "value" : pAddrValueObjHome + }; + } + if (businessOk) + { + pAddrObject["Business"] = { + "addressKey" : "Business", + "value" : pAddrValueObjBusiness + }; + } + if (otherOk) + { + pAddrObject["Other"] = { + "addressKey" : "Other", + "value" : pAddrValueObjOther + }; + } +} + +/* + * returns the exchangeID of the ADITO Folder of an exchange User + * if no folder is passed all folderIDs will be returned + * + * @param {String} pAlias exchange-alias + * @param {String} pMailBox mail-adress of the user + * @param {String} pFolderName name of the folder for which the ID should returned none if all + */ +function getExchangeFolderID(pAlias, pMailBox, pFolderName) +{ + var folders = EwsSyncContactUtils.getContactFolders(pAlias, pMailBox); + + for ( var i = 0; i < folders.length; i++) + { + if( folders[i].name.toUpperCase() == pFolderName.toUpperCase() ) + return folders[i].id; + } + return ""; +} + +function escapeValuesForXML(pValue){ + + var reps = {}; + reps["&"] = "&"; + reps["\""] = """; + reps["'"] = "&apos"; + reps["<"] = "<"; + reps[">"] = ">"; + + pValue = text.replaceAll(pValue, reps).trim(); + + return pValue +} + +/* +* Updates the Edit-Date and the exchangeID into the associated data set of AOSYS_SYNCCONTACT +* If the ExchangeID isn't passed, then it will just update DATE_EDIT +* +* @param {Array<Array>} pUpdateValues 2d-array in the following form: [[CONTACTID, matching new EXCHANGEID]] +* @param {String} pUserID ID of the corresponding user +*/ +function updateADITOContactsAfterAction(pUpdateValues, pUserID) +{ + var cols = ["EXCHANGEID"]; + var types = db.getColumnTypes("AB_SYNCCONTACT", cols); + var vals; + var cond = ""; + var updArr = []; + for (let i = 0; i < pUpdateValues.length; i++) + { + vals = []; + // Get EXCHANGEID + if (pUpdateValues[i][1]) + vals.push(pUpdateValues[i][1]); + + cond = "CONTACT_ID = '" + pUpdateValues[i][0] + "' and USER_ID = '" + pUserID + "'"; + updArr.push(["AB_SYNCCONTACT", cols, types, vals, cond]); + } + db.updates(updArr, "Data_alias", 300000); +}