/// <summary>
        /// Set this outlook item's duration, but also end time and location, from this CRM item.
        /// </summary>
        /// <param name="crmType">The type of the CRM item.</param>
        /// <param name="crmItem">The CRM item.</param>
        /// <param name="olItem">The Outlook item.</param>
        private void SetOutlookItemDuration(string crmType, EntryValue crmItem, Outlook.AppointmentItem olItem)
        {
            int minutes = 0, hours = 0;

            try
            {
                if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("duration_minutes")))
                {
                    minutes = int.Parse(crmItem.GetValueAsString("duration_minutes"));
                }
                if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("duration_hours")))
                {
                    hours = int.Parse(crmItem.GetValueAsString("duration_hours"));
                }

                int durationMinutes = minutes + hours * 60;

                if (crmType == AppointmentSyncing.CrmModule)
                {
                    olItem.Location = crmItem.GetValueAsString("location");
                    olItem.End      = olItem.Start.AddMinutes(durationMinutes);
                }

                olItem.Duration = durationMinutes;
            }
            catch (Exception any)
            {
                Log.Error("AppointmentSyncing.SetOutlookItemDuration", any);
            }
            finally
            {
                this.SaveItem(olItem);
            }
        }
示例#2
0
        protected override void UpdateOutlookDetails(string crmType, EntryValue crmItem, DateTime date_start, Outlook.AppointmentItem olItem)
        {
            try
            {
                olItem.Start = date_start;
                var minutesString = crmItem.GetValueAsString("duration_minutes");
                var hoursString   = crmItem.GetValueAsString("duration_hours");

                int minutes = string.IsNullOrWhiteSpace(minutesString) ? 0 : int.Parse(minutesString);
                int hours   = string.IsNullOrWhiteSpace(hoursString) ? 0 : int.Parse(hoursString);

                olItem.Duration = minutes + hours * 60;

                olItem.Location = crmItem.GetValueAsString("location");
                olItem.End      = olItem.Start;
                if (hours > 0)
                {
                    olItem.End.AddHours(hours);
                }
                if (minutes > 0)
                {
                    olItem.End.AddMinutes(minutes);
                }
                SetOutlookRecipientsFromCRM(olItem, crmItem, crmItem.GetValueAsString("id"), crmType);
            }
            finally
            {
                this.SaveItem(olItem);
            }
        }
示例#3
0
        /// <summary>
        /// Update an existing Outlook item with values taken from a corresponding CRM item. Note that
        /// this just overwrites all values in the Outlook item.
        /// </summary>
        /// <param name="crmItem">The CRM item from which values are to be taken.</param>
        /// <param name="itemSyncState">The sync state of an outlook item assumed to correspond with the CRM item.</param>
        /// <returns>An appropriate sync state.</returns>
        private SyncState <Outlook.ContactItem> UpdateExistingOutlookItemFromCrm(EntryValue crmItem, SyncState <Outlook.ContactItem> itemSyncState)
        {
            if (!itemSyncState.IsDeletedInOutlook)
            {
                Outlook.ContactItem  olItem           = itemSyncState.OutlookItem;
                Outlook.UserProperty dateModifiedProp = olItem.UserProperties[SyncStateManager.ModifiedDatePropertyName];
                Outlook.UserProperty shouldSyncProp   = olItem.UserProperties["SShouldSync"];
                this.LogItemAction(olItem, "ContactSyncing.UpdateExistingOutlookItemFromCrm");

                if (CrmItemChanged(crmItem, olItem))
                {
                    DateTime crmDate     = DateTime.Parse(crmItem.GetValueAsString("date_modified"));
                    DateTime outlookDate = dateModifiedProp == null ? DateTime.MinValue : DateTime.Parse(dateModifiedProp.Value.ToString());

                    if (crmDate > this.LastRunCompleted && outlookDate > this.LastRunCompleted)
                    {
                        MessageBox.Show(
                            $"Contact {olItem.FirstName} {olItem.LastName} has changed both in Outlook and CRM; please check which is correct",
                            "Update problem", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                    else if (crmDate > outlookDate)
                    {
                        this.SetOutlookItemPropertiesFromCrmItem(crmItem, olItem);
                    }
                }

                this.LogItemAction(olItem, "ContactSyncing.UpdateExistingOutlookItemFromCrm");
                itemSyncState.OModifiedDate = DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null);
            }

            return(itemSyncState);
        }
示例#4
0
        protected override SyncState <Outlook.TaskItem> AddOrUpdateItemFromCrmToOutlook(Outlook.MAPIFolder tasksFolder, string crmType, EntryValue crmItem)
        {
            SyncState <Outlook.TaskItem> result = null;

            Log.Debug($"TaskSyncing.AddOrUpdateItemFromCrmToOutlook\n\tSubject: {crmItem.GetValueAsString("name")}\n\tCurrent user id {RestAPIWrapper.GetUserId()}\n\tAssigned user id: {crmItem.GetValueAsString("assigned_user_id")}");

            DateTime dateStart = crmItem.GetValueAsDateTime("date_start");
            DateTime dateDue   = crmItem.GetValueAsDateTime("date_due");
            string   timeStart = ExtractTime(dateStart);
            string   timeDue   = ExtractTime(dateDue);

            var syncState = this.GetExistingSyncState(crmItem);

            if (syncState == null)
            {
                /* check for howlaround */
                var matches = this.FindMatches(crmItem);

                if (matches.Count == 0)
                {
                    /* didn't find it, so add it to Outlook */
                    result = AddNewItemFromCrmToOutlook(tasksFolder, crmItem, dateStart, dateDue, timeStart, timeDue);
                }
                else
                {
                    this.Log.Warn($"Howlaround detected? Task '{crmItem.GetValueAsString("name")}' offered with id {crmItem.GetValueAsString("id")}, expected {matches[0].CrmEntryId}, {matches.Count} duplicates");
                }
            }
            else
            {
                result = UpdateExistingOutlookItemFromCrm(crmItem, dateStart, dateDue, timeStart, timeDue, syncState);
            }

            return(result);
        }
        /// <summary>
        /// Update this Outlook appointment's start and duration from this CRM object.
        /// </summary>
        /// <param name="crmType">The CRM type of the item from which values are to be taken.</param>
        /// <param name="crmItem">The CRM item from which values are to be taken.</param>
        /// <param name="date_start">The state date/time of the item, adjusted for timezone.</param>
        /// <param name="olItem">The outlook item assumed to correspond with the CRM item.</param>
        private void UpdateOutlookStartAndDuration(string crmType, EntryValue crmItem, DateTime date_start, Outlook.AppointmentItem olItem)
        {
            try
            {
                olItem.Start = date_start;
                var minutesString = crmItem.GetValueAsString("duration_minutes");
                var hoursString   = crmItem.GetValueAsString("duration_hours");

                int minutes = string.IsNullOrWhiteSpace(minutesString) ? 0 : int.Parse(minutesString);
                int hours   = string.IsNullOrWhiteSpace(hoursString) ? 0 : int.Parse(hoursString);

                if (crmType == AppointmentSyncing.CrmModule)
                {
                    olItem.Location = crmItem.GetValueAsString("location");
                    olItem.End      = olItem.Start;
                    if (hours > 0)
                    {
                        olItem.End.AddHours(hours);
                    }
                    if (minutes > 0)
                    {
                        olItem.End.AddMinutes(minutes);
                    }
                    SetRecipients(olItem, crmItem.GetValueAsString("id"), crmType);
                }
                olItem.Duration = minutes + hours * 60;
            }
            finally
            {
                this.SaveItem(olItem);
            }
        }
示例#6
0
        private void SetOutlookItemPropertiesFromCrmItem(EntryValue crmItem, Outlook.TaskItem olItem)
        {
            try
            {
                DateTime dateStart = crmItem.GetValueAsDateTime("date_start");
                DateTime dateDue   = crmItem.GetValueAsDateTime("date_due");
                string   timeStart = ExtractTime(dateStart);
                string   timeDue   = ExtractTime(dateDue);

                olItem.Subject = crmItem.GetValueAsString("name");

                olItem.StartDate = MaybeChangeDate(dateStart, olItem.StartDate, "olItem.StartDate");

                olItem.DueDate = MaybeChangeDate(dateDue, olItem.DueDate, "olItem.DueDate");

                string body = crmItem.GetValueAsString("description");
                olItem.Body       = string.Concat(body, "#<", timeStart, "#", timeDue);
                olItem.Status     = GetStatus(crmItem.GetValueAsString("status"));
                olItem.Importance = GetImportance(crmItem.GetValueAsString("priority"));
                EnsureSynchronisationPropertiesForOutlookItem(olItem, crmItem.GetValueAsString("date_modified"), DefaultCrmModule, CrmId.Get(crmItem.id));
            }
            finally
            {
                this.SaveItem(olItem);
            }
        }
示例#7
0
 /// <summary>
 /// Set up synchronisation properties for this outlook item from this CRM item, assuming my default CRM module.
 /// </summary>
 /// <param name="olItem">The Outlook item.</param>
 /// <param name="crmItem">The CRM item.</param>
 /// <param name="type">The value for the SType property (CRM module name).</param>
 protected virtual void EnsureSynchronisationPropertiesForOutlookItem(OutlookItemType olItem, EntryValue crmItem, string type)
 {
     this.EnsureSynchronisationPropertiesForOutlookItem(
         olItem,
         crmItem.GetValueAsString("date_modified"),
         type,
         crmItem.GetValueAsString("id"));
 }
        /// <summary>
        /// Add an item existing in CRM but not found in Outlook to Outlook.
        /// </summary>
        /// <param name="appointmentsFolder">The Outlook folder in which the item should be stored.</param>
        /// <param name="crmType">The CRM type of the item from which values are to be taken.</param>
        /// <param name="crmItem">The CRM item from which values are to be taken.</param>
        /// <param name="date_start">The state date/time of the item, adjusted for timezone.</param>
        /// <returns>A sync state object for the new item.</returns>
        private SyncState <Outlook.AppointmentItem> AddNewItemFromCrmToOutlook(
            Outlook.MAPIFolder appointmentsFolder,
            string crmType,
            EntryValue crmItem,
            DateTime date_start)
        {
            AppointmentSyncState newState = null;

            Outlook.AppointmentItem olItem = null;
            try
            {
                var crmId = crmItem.GetValueAsString("id");

                /*
                 * There's a nasty little bug (#223) where Outlook offers us back in a different thread
                 * the item we're creating, before we're able to set up the sync state which marks it
                 * as already known. By locking on the enqueueing lock here, we should prevent that.
                 */
                lock (enqueueingLock)
                {
                    olItem = appointmentsFolder.Items.Add(Outlook.OlItemType.olAppointmentItem);

                    newState = new AppointmentSyncState(crmType)
                    {
                        OutlookItem   = olItem,
                        OModifiedDate = DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null),
                        CrmEntryId    = crmId
                    };

                    ItemsSyncState.Add(newState);

                    olItem.Subject = crmItem.GetValueAsString("name");
                    olItem.Body    = crmItem.GetValueAsString("description");
                    /* set the SEntryID property quickly, create the sync state and save the item, to reduce howlaround */
                    EnsureSynchronisationPropertiesForOutlookItem(olItem, crmItem, crmType);
                    this.SaveItem(olItem);
                }

                LogItemAction(olItem, "AppointmentSyncing.AddNewItemFromCrmToOutlook");
                if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("date_start")))
                {
                    olItem.Start = date_start;
                    SetOutlookItemDuration(crmType, crmItem, olItem);

                    Log.Info("\tdefault SetRecepients");
                    SetRecipients(olItem, crmId, crmType);
                }
            }
            finally
            {
                if (olItem != null)
                {
                    this.SaveItem(olItem);
                }
            }

            return(newState);
        }
示例#9
0
        private SyncState <Outlook.TaskItem> UpdateExistingOutlookItemFromCrm(EntryValue crmItem, SyncState <Outlook.TaskItem> syncStateForItem)
        {
            if (!syncStateForItem.IsDeletedInOutlook)
            {
                Outlook.TaskItem     olItem = syncStateForItem.OutlookItem;
                Outlook.UserProperty oProp  = olItem.UserProperties[SyncStateManager.ModifiedDatePropertyName];

                if (oProp.Value != crmItem.GetValueAsString("date_modified"))
                {
                    SetOutlookItemPropertiesFromCrmItem(crmItem, olItem);
                }
                syncStateForItem.OModifiedDate = DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null);
            }
            return(syncStateForItem);
        }
示例#10
0
        /// <summary>
        /// A CRM item is perceived to have changed if its modified date is different from
        /// that of its Outlook representation, or if its should sync flag is.
        /// </summary>
        /// <param name="crmItem">A CRM item.</param>
        /// <param name="olItem">An Outlook item, assumed to represent the same entity.</param>
        /// <returns>True if either of these propertyies differ between the representations.</returns>
        private bool CrmItemChanged(EntryValue crmItem, Outlook.ContactItem olItem)
        {
            Outlook.UserProperty dateModifiedProp = olItem.UserProperties[SyncStateManager.ModifiedDatePropertyName];

            return(dateModifiedProp.Value != crmItem.GetValueAsString("date_modified") ||
                   ShouldSyncFlagChanged(olItem, crmItem));
        }
        /// <summary>
        /// Update a single appointment in the specified Outlook folder with changes from CRM, but
        /// only if its start date is fewer than five days in the past.
        /// </summary>
        /// <param name="folder">The folder to synchronise into.</param>
        /// <param name="crmType">The CRM type of the candidate item.</param>
        /// <param name="crmItem">The candidate item from CRM.</param>
        /// <returns>The synchronisation state of the item updated (if it was updated).</returns>
        protected override SyncState <Outlook.AppointmentItem> AddOrUpdateItemFromCrmToOutlook(
            Outlook.MAPIFolder folder,
            string crmType,
            EntryValue crmItem)
        {
            SyncState <Outlook.AppointmentItem> result = null;
            DateTime dateStart = crmItem.GetValueAsDateTime("date_start");

            if (dateStart >= GetStartDate())
            {
                /* search for the item among the sync states I already know about */
                var syncState = this.GetExistingSyncState(crmItem);
                if (syncState == null)
                {
                    /* check for howlaround */
                    var matches = this.FindMatches(crmItem);

                    if (matches.Count == 0)
                    {
                        /* didn't find it, so add it to Outlook */
                        result = AddNewItemFromCrmToOutlook(folder, crmType, crmItem, dateStart);
                    }
                    else
                    {
                        this.Log.Warn($"Howlaround detected? Appointment '{crmItem.GetValueAsString("name")}' offered with id {crmItem.GetValueAsString("id")}, expected {matches[0].CrmEntryId}, {matches.Count} duplicates");
                    }
                }
                else
                {
                    /* found it, so update it from the CRM item */
                    result = UpdateExistingOutlookItemFromCrm(crmType, crmItem, dateStart, syncState);

                    result?.OutlookItem.Save();
                }

                if (crmItem?.relationships?.link_list != null)
                {
                    foreach (var list in crmItem.relationships.link_list)
                    {
                        foreach (var record in list.records)
                        {
                            var data = record.data.AsDictionary();
                            try
                            {
                                this.meetingRecipientsCache[data[AddressResolutionData.EmailAddressFieldName].ToString()] =
                                    new AddressResolutionData(list.name, data);
                                Log.Debug($"Successfully cached recipient {data[AddressResolutionData.EmailAddressFieldName]} => {list.name}, {data[AddressResolutionData.ModuleIdFieldName]}.");
                            }
                            catch (KeyNotFoundException kex)
                            {
                                Log.Error($"Key not found while caching meeting recipients.", kex);
                            }
                        }
                    }
                }
            }

            return(result);
        }
        private bool IsProbablySameItem(EntryValue result, ContactItem contactItem)
        {
            string crmIdStr = contactItem.GetCrmId().ToString();

            return(result != null &&
                   (result.id.Equals(crmIdStr) ||
                    result.GetValueAsString("outlook_id").Equals(contactItem.EntryID)));
        }
示例#13
0
        private void SetOutlookItemPropertiesFromCrmItem(EntryValue crmItem, Outlook.TaskItem olItem)
        {
            try
            {
                DateTime dateStart = crmItem.GetValueAsDateTime("date_start");
                DateTime dateDue   = crmItem.GetValueAsDateTime("date_due");
                string   timeStart = ExtractTime(dateStart);
                string   timeDue   = ExtractTime(dateDue);

                olItem.Subject = crmItem.GetValueAsString("name");

                try
                {
                    olItem.StartDate = MaybeChangeDate(dateStart, olItem.StartDate, "syncState.StartDate");
                }
                catch (COMException comx)
                {
#if DEBUG
                    Log.Debug($"COM Exception while trying to set start date of task: '{comx.Message}'. Some otherwise-valid tasks don't support this");
#endif
                }

                try {
                    olItem.DueDate = MaybeChangeDate(dateDue, olItem.DueDate, "syncState.DueDate");
                }
                catch (COMException comx)
                {
#if DEBUG
                    Log.Debug($"COM Exception while trying to set start date of task: '{comx.Message}'. Do some otherwise-valid tasks not support this?");
#endif
                }

                string body = crmItem.GetValueAsString("description");
                olItem.Body       = string.Concat(body, "#<", timeStart, "#", timeDue);
                olItem.Status     = GetStatus(crmItem.GetValueAsString("status"));
                olItem.Importance = GetImportance(crmItem.GetValueAsString("priority"));
                EnsureSynchronisationPropertiesForOutlookItem(olItem, crmItem.GetValueAsString("date_modified"), DefaultCrmModule, CrmId.Get(crmItem.id));
            }
            finally
            {
                this.SaveItem(olItem);
            }
        }
        protected override bool IsMatch(Outlook.AppointmentItem olItem, EntryValue crmItem)
        {
            var crmItemStart = crmItem.GetValueAsDateTime("date_start");
            var crmItemName  = crmItem.GetValueAsString("name");

            var olItemStart = olItem.Start;
            var subject     = olItem.Subject;

            return(subject == crmItemName &&
                   olItemStart == crmItemStart);
        }
示例#15
0
 protected override bool ShouldAddOrUpdateItemFromCrmToOutlook(Outlook.MAPIFolder folder, string crmType, EntryValue crmItem)
 {
     try
     {
         return(RestAPIWrapper.GetUserId().Equals(crmItem.GetValueAsString("assigned_user_id")));
     }
     catch (TypeInitializationException tix)
     {
         Log.Warn("Bad CRM id?", tix);
         return(false);
     }
 }
        /// <summary>
        /// Add an item existing in CRM but not found in Outlook to Outlook.
        /// </summary>
        /// <param name="contactFolder">The Outlook folder in which the item should be stored.</param>
        /// <param name="crmItem">The CRM item from which values are to be taken.</param>
        /// <returns>A sync state object for the new item.</returns>
        private SyncState <Outlook.ContactItem> AddNewItemFromCrmToOutlook(Outlook.MAPIFolder contactFolder, EntryValue crmItem)
        {
            Log.Info(
                (string)string.Format(
                    "ContactSyncing.AddNewItemFromCrmToOutlook, entry id is '{0}', creating in Outlook.",
                    crmItem.GetValueAsString("id")));

            Outlook.ContactItem olItem = contactFolder.Items.Add(Outlook.OlItemType.olContactItem);

            this.SetOutlookItemPropertiesFromCrmItem(crmItem, olItem);

            return(this.AddOrGetSyncState(olItem));
        }
示例#17
0
 /// <summary>
 /// Specialisation: also set end time and location.
 /// </summary>
 /// <param name="crmItem">The CRM item.</param>
 /// <param name="olItem">The Outlook item.</param>
 protected override void SetOutlookItemDuration(EntryValue crmItem, Outlook.AppointmentItem olItem)
 {
     try
     {
         base.SetOutlookItemDuration(crmItem, olItem);
         olItem.Location = crmItem.GetValueAsString("location");
         olItem.End      = olItem.Start.AddMinutes(olItem.Duration);
     }
     catch (System.Exception any)
     {
         ErrorHandler.Handle("Failed while setting Outlook item duration", any);
     }
 }
示例#18
0
        private SyncState <Outlook.TaskItem> UpdateExistingOutlookItemFromCrm(EntryValue crmItem, SyncState <Outlook.TaskItem> syncState)
        {
            if (!syncState.IsDeletedInOutlook)
            {
                Outlook.TaskItem olItem = syncState.OutlookItem;

                if (olItem.IsValid())
                {
                    Outlook.UserProperty oProp = olItem.UserProperties[SyncStateManager.ModifiedDatePropertyName];

                    if (oProp.Value != crmItem.GetValueAsString("date_modified"))
                    {
                        SetOutlookItemPropertiesFromCrmItem(crmItem, olItem);
                    }
                    syncState.OModifiedDate = DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null);
                }
                else
                {
                    Log.Error($"Attempting to update invalid Outlook item '{crmItem.GetValueAsString("name")}'");
                }
            }
            return(syncState);
        }
示例#19
0
        protected override SyncState <Outlook.TaskItem> AddOrUpdateItemFromCrmToOutlook(Outlook.MAPIFolder tasksFolder,
                                                                                        string crmType, EntryValue crmItem)
        {
            SyncState <Outlook.TaskItem> result = null;

            Log.Debug(
                $"TaskSyncing.AddOrUpdateItemFromCrmToOutlook\n\tSubject: {crmItem.GetValueAsString("name")}\n\tCurrent user id {RestAPIWrapper.GetUserId()}\n\tAssigned user id: {crmItem.GetValueAsString("assigned_user_id")}");

            var syncState = SyncStateManager.Instance.GetExistingSyncState(crmItem) as SyncState <Outlook.TaskItem>;

            result = syncState == null?MaybeAddNewItemFromCrmToOutlook(tasksFolder, crmItem) : UpdateExistingOutlookItemFromCrm(crmItem, syncState);

            return(result);
        }
        /// <summary>
        /// Add an item existing in CRM but not found in Outlook to Outlook.
        /// </summary>
        /// <param name="contactFolder">The Outlook folder in which the item should be stored.</param>
        /// <param name="crmItem">The CRM item from which values are to be taken.</param>
        /// <returns>A sync state object for the new item.</returns>
        private SyncState <Outlook.ContactItem> AddNewItemFromCrmToOutlook(Outlook.MAPIFolder contactFolder, EntryValue crmItem)
        {
            Log.Info(
                (string)string.Format(
                    "ContactSyncing.AddNewItemFromCrmToOutlook, entry id is '{0}', creating in Outlook.",
                    crmItem.GetValueAsString("id")));

            Outlook.ContactItem olItem = contactFolder.Items.Add(Outlook.OlItemType.olContactItem);

            this.SetOutlookItemPropertiesFromCrmItem(crmItem, olItem);

            var newState = new ContactSyncState
            {
                OutlookItem   = olItem,
                OModifiedDate = DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null),
                CrmEntryId    = crmItem.GetValueAsString("id"),
            };

            ItemsSyncState.Add(newState);

            LogItemAction(newState.OutlookItem, "AppointmentSyncing.AddNewItemFromCrmToOutlook, saved item");

            return(newState);
        }
        private SyncState <Outlook.TaskItem> AddNewItemFromCrmToOutlook(Outlook.MAPIFolder tasksFolder, EntryValue crmItem, DateTime?date_start, DateTime?date_due, string time_start, string time_due)
        {
            Outlook.TaskItem olItem   = tasksFolder.Items.Add(Outlook.OlItemType.olTaskItem);
            TaskSyncState    newState = null;

            try
            {
                this.SetOutlookItemPropertiesFromCrmItem(crmItem, date_start, date_due, time_start, time_due, olItem);

                newState = new TaskSyncState
                {
                    OutlookItem   = olItem,
                    OModifiedDate = DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null),
                    CrmEntryId    = crmItem.GetValueAsString("id"),
                };
                ItemsSyncState.Add(newState);
            }
            finally
            {
                this.SaveItem(olItem);
            }

            return(newState);
        }
        /// <summary>
        /// Get the existing sync state for this CRM item, if it exists, else null.
        /// </summary>
        /// <param name="crmItem">The item.</param>
        /// <returns>The appropriate sync state, or null if none.</returns>
        public SyncState GetExistingSyncState(EntryValue crmItem)
        {
            SyncState result;
            string    outlookId = crmItem.GetValueAsString("outlook_id");
            CrmId     crmId     = CrmId.Get(crmItem.id);

            if (this.byCrmId.ContainsKey(crmId))
            {
                result = this.byCrmId[crmId];
            }
            else if (this.byOutlookId.ContainsKey(outlookId))
            {
                result = this.byOutlookId[outlookId];
            }
            else if (this.byGlobalId.ContainsKey(outlookId))
            {
                result = this.byGlobalId[outlookId];
            }
            else
            {
                string simulatedGlobalId = SyncStateManager.SimulateGlobalId(crmId);

                if (this.byGlobalId.ContainsKey(simulatedGlobalId))
                {
                    result = this.byGlobalId[simulatedGlobalId];
                }
                else
                {
                    string distinctFields = GetDistinctFields(crmItem);

                    if (string.IsNullOrEmpty(distinctFields))
                    {
                        result = null;
                    }
                    else if (this.byDistinctFields.ContainsKey(distinctFields))
                    {
                        result = this.byDistinctFields[distinctFields];
                    }
                    else
                    {
                        result = null;
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// If a meeting was created in another Outlook we should NOT sync it with CRM because if we do we'll create
        /// duplicates. Only the Outlook which created it should sync it.
        /// </summary>
        /// <param name="folder">The folder to synchronise into.</param>
        /// <param name="crmType">The CRM type of the candidate item.</param>
        /// <param name="crmItem">The candidate item from CRM.</param>
        /// <returns>True if it's offered to us by CRM with its Outlook ID already populated.</returns>
        protected override bool ShouldAddOrUpdateItemFromCrmToOutlook(Outlook.MAPIFolder folder, string crmType, EntryValue crmItem)
        {
            var outlookId = crmItem.GetValueAsString("outlook_id");
            /* we're good if it's a meeting... */
            bool result = crmType == this.DefaultCrmModule;

            /* provided it doesn't already have an Outlook id */
            result &= string.IsNullOrWhiteSpace(outlookId);
            /* and we're also good if it's an appointment; */
            result |= crmType == AppointmentSyncing.AltCrmModule;
            /* and we're also good if we've already got it */
            result |= (this.GetExistingSyncState(crmItem) != null);

            if (!result)
            {
                Log.Debug($"ShouldAddOrUpdateItemFromCrmToOutlook: not syncing meeting `{crmItem.GetValueAsString("name")}` as it appears to originate from another Outlook instance.");
            }

            return(result);
        }
        /// <summary>
        /// Update a single appointment in the specified Outlook folder with changes from CRM, but
        /// only if its start date is fewer than five days in the past.
        /// </summary>
        /// <param name="folder">The folder to synchronise into.</param>
        /// <param name="crmType">The CRM type of the candidate item.</param>
        /// <param name="crmItem">The candidate item from CRM.</param>
        /// <returns>The synchronisation state of the item updated (if it was updated).</returns>
        protected override SyncState <Outlook.AppointmentItem> AddOrUpdateItemFromCrmToOutlook(
            Outlook.MAPIFolder folder,
            string crmType,
            EntryValue crmItem)
        {
            SyncState <Outlook.AppointmentItem> result = null;
            DateTime dateStart = crmItem.GetValueAsDateTime("date_start");

            if (dateStart >= GetStartDate())
            {
                /* search for the item among the sync states I already know about */
                var syncState = this.GetExistingSyncState(crmItem);
                if (syncState == null)
                {
                    /* check for howlaround */
                    var matches = this.FindMatches(crmItem);

                    if (matches.Count == 0)
                    {
                        /* didn't find it, so add it to Outlook */
                        result = AddNewItemFromCrmToOutlook(folder, crmType, crmItem, dateStart);
                    }
                    else
                    {
                        this.Log.Warn($"Howlaround detected? Appointment '{crmItem.GetValueAsString("name")}' offered with id {crmItem.GetValueAsString("id")}, expected {matches[0].CrmEntryId}, {matches.Count} duplicates");
                    }
                }
                else
                {
                    /* found it, so update it from the CRM item */
                    result = UpdateExistingOutlookItemFromCrm(crmType, crmItem, dateStart, syncState);
                }

                result?.OutlookItem.Save();

                // TODO TODO TODO TODO: pull and cache the recipients!
            }

            return(result);
        }
示例#25
0
        /// <summary>
        /// Item creation really ought to happen within the context of a lock, in order to prevent duplicate creation.
        /// </summary>
        /// <param name="tasksFolder">The folder in which the item should be created.</param>
        /// <param name="crmItem">The CRM item it will represent.</param>
        /// <returns>A syncstate whose Outlook item is the Outlook item representing this crmItem.</returns>
        private SyncState <Outlook.TaskItem> MaybeAddNewItemFromCrmToOutlook(Outlook.MAPIFolder tasksFolder, EntryValue crmItem)
        {
            SyncState <Outlook.TaskItem> result;

            lock (creationLock)
            {
                /* check for howlaround */
                var matches = this.FindMatches(crmItem);

                if (matches.Count == 0)
                {
                    /* didn't find it, so add it to Outlook */
                    result = AddNewItemFromCrmToOutlook(tasksFolder, crmItem);
                }
                else
                {
                    this.Log.Warn($"Howlaround detected? Task '{crmItem.GetValueAsString("name")}' offered with id {crmItem.GetValueAsString("id")}, expected {matches[0].CrmEntryId}, {matches.Count} duplicates");
                    result = matches[0];
                }
            }

            return(result);
        }
        /// <summary>
        /// Update an existing Outlook item with values taken from a corresponding CRM item. Note that
        /// this just overwrites all values in the Outlook item.
        /// </summary>
        /// <param name="crmType">The CRM type of the item from which values are to be taken.</param>
        /// <param name="crmItem">The CRM item from which values are to be taken.</param>
        /// <param name="date_start">The state date/time of the item, adjusted for timezone.</param>
        /// <param name="syncState">The outlook item assumed to correspond with the CRM item.</param>
        /// <returns>An appropriate sync state.</returns>
        private SyncState <Outlook.AppointmentItem> UpdateExistingOutlookItemFromCrm(
            string crmType,
            EntryValue crmItem,
            DateTime date_start,
            SyncState <Outlook.AppointmentItem> syncState)
        {
            LogItemAction(syncState.OutlookItem, "AppointmentSyncing.UpdateExistingOutlookItemFromCrm");

            if (!syncState.IsDeletedInOutlook)
            {
                Outlook.AppointmentItem olItem = syncState.OutlookItem;
                Outlook.UserProperty    olPropertyModifiedDate = olItem.UserProperties[ModifiedDatePropertyName];

                if (olPropertyModifiedDate.Value != crmItem.GetValueAsString("date_modified"))
                {
                    try
                    {
                        olItem.Subject = crmItem.GetValueAsString("name");
                        olItem.Body    = crmItem.GetValueAsString("description");
                        if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("date_start")))
                        {
                            UpdateOutlookStartAndDuration(crmType, crmItem, date_start, olItem);
                        }

                        EnsureSynchronisationPropertiesForOutlookItem(olItem, crmItem, crmType);
                        LogItemAction(syncState.OutlookItem, "AppointmentSyncing.UpdateExistingOutlookItemFromCrm, item saved");
                    }
                    finally
                    {
                        this.SaveItem(olItem);
                    }
                }
                Log.Warn((string)("Not default dResult.date_modified= " + crmItem.GetValueAsString("date_modified")));
                syncState.OModifiedDate = DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null);
            }

            return(syncState);
        }
示例#27
0
 /// <summary>
 /// Get a string representing the values of the distinct fields of this crmItem,
 /// as a final fallback for identifying an otherwise unidentifiable object.
 /// </summary>
 /// <param name="crmItem">An item received from CRM.</param>
 /// <returns>An identifying string.</returns>
 /// <see cref="SyncState{ItemType}.IdentifyingFields"/>
 internal static string GetDistinctFields(EntryValue crmItem)
 {
     return($"subject: '{crmItem.GetValueAsString("name")}'; start: '{crmItem.GetValueAsDateTime("date_start")}'");
 }
 /// <summary>
 /// Specialisation: in addition to the standard properties, meetings also require an organiser property.
 /// </summary>
 /// <param name="olItem">The Outlook item.</param>
 /// <param name="crmItem">The CRM item.</param>
 /// <param name="type">The value for the SType property (CRM module name).</param>
 protected override void EnsureSynchronisationPropertiesForOutlookItem(Outlook.AppointmentItem olItem, EntryValue crmItem, string type)
 {
     base.EnsureSynchronisationPropertiesForOutlookItem(olItem, crmItem, type);
     if (this.DefaultCrmModule.Equals(type))
     {
         this.EnsureSynchronisationPropertyForOutlookItem(olItem, OrganiserPropertyName, crmItem.GetValueAsString("assigned_user_id"));
     }
 }
示例#29
0
        /// <summary>
        /// Set all those properties of this outlook item whose values are different from the
        /// equivalent values on this CRM item. Update the synchronisation properties only if some
        /// other property has actually changed.
        /// </summary>
        /// <param name="crmItem">The CRM item from which to take values.</param>
        /// <param name="olItem">The Outlook item into which to insert values.</param>
        /// <returns>true if anything was changed.</returns>
        private void SetOutlookItemPropertiesFromCrmItem(EntryValue crmItem, Outlook.ContactItem olItem)
        {
            try
            {
                olItem.FirstName                 = crmItem.GetValueAsString("first_name");
                olItem.LastName                  = crmItem.GetValueAsString("last_name");
                olItem.Email1Address             = crmItem.GetValueAsString("email1");
                olItem.BusinessTelephoneNumber   = crmItem.GetValueAsString("phone_work");
                olItem.HomeTelephoneNumber       = crmItem.GetValueAsString("phone_home");
                olItem.MobileTelephoneNumber     = crmItem.GetValueAsString("phone_mobile");
                olItem.JobTitle                  = crmItem.GetValueAsString("title");
                olItem.Department                = crmItem.GetValueAsString("department");
                olItem.BusinessAddressCity       = crmItem.GetValueAsString("primary_address_city");
                olItem.BusinessAddressCountry    = crmItem.GetValueAsString("primary_address_country");
                olItem.BusinessAddressPostalCode = crmItem.GetValueAsString("primary_address_postalcode");
                olItem.BusinessAddressState      = crmItem.GetValueAsString("primary_address_state");
                olItem.BusinessAddressStreet     = crmItem.GetValueAsString("primary_address_street");
                olItem.Body = crmItem.GetValueAsString("description");
                if (crmItem.GetValue("account_name") != null)
                {
                    olItem.Account     = crmItem.GetValueAsString("account_name");
                    olItem.CompanyName = crmItem.GetValueAsString("account_name");
                }
                olItem.BusinessFaxNumber = crmItem.GetValueAsString("phone_fax");
                olItem.Title             = crmItem.GetValueAsString("salutation");

                if (olItem.Sensitivity != Outlook.OlSensitivity.olNormal)
                {
                    Log.Info($"ContactSyncing.SetOutlookItemPropertiesFromCrmItem: setting sensitivity of contact {crmItem.GetValueAsString("first_name")} {crmItem.GetValueAsString("last_name")} ({crmItem.GetValueAsString("email1")}) to normal");
                    olItem.Sensitivity = Outlook.OlSensitivity.olNormal;
                }

                EnsureSynchronisationPropertiesForOutlookItem(
                    olItem,
                    crmItem.GetValueAsString("date_modified"),
                    crmItem.GetValueAsString("sync_contact"),
                    CrmId.Get(crmItem.id));
            }
            finally
            {
                this.SaveItem(olItem);
            }
        }
示例#30
0
 protected override bool IsMatch(Outlook.ContactItem olItem, EntryValue crmItem)
 {
     return(olItem.FirstName == crmItem.GetValueAsString("first_name") &&
            olItem.LastName == crmItem.GetValueAsString("last_name") &&
            olItem.Email1Address == crmItem.GetValueAsString("email1"));
 }