/// <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="oItem">The outlook item assumed to correspond with the CRM item.</param> /// <returns>An appropriate sync state.</returns> private SyncState <Outlook.AppointmentItem> UpdateExistingOutlookItemFromCrm( string crmType, eEntryValue crmItem, DateTime date_start, SyncState <Outlook.AppointmentItem> oItem) { LogItemAction(oItem.OutlookItem, "AppointmentSyncing.UpdateExistingOutlookItemFromCrm"); if (!oItem.IsDeletedInOutlook) { Outlook.AppointmentItem olAppointment = oItem.OutlookItem; Outlook.UserProperty olPropertyModifiedDate = olAppointment.UserProperties[ModifiedDatePropertyName]; MaybeAddAcceptDeclineLinks(crmItem, oItem.OutlookItem, crmType); if (olPropertyModifiedDate.Value != crmItem.GetValueAsString("date_modified")) { olAppointment.Subject = crmItem.GetValueAsString("name"); olAppointment.Body = crmItem.GetValueAsString("description"); if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("date_start"))) { UpdateOutlookStartAndDuration(crmType, crmItem, date_start, olAppointment); } EnsureSynchronisationPropertiesForOutlookItem(olAppointment, crmItem, crmType); olAppointment.Save(); LogItemAction(oItem.OutlookItem, "AppointmentSyncing.UpdateExistingOutlookItemFromCrm, item saved"); } Log.Warn((string)("Not default dResult.date_modified= " + crmItem.GetValueAsString("date_modified"))); oItem.OModifiedDate = DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null); } return(oItem); }
/// <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="candidateItem">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, eEntryValue crmItem) { SyncState <Outlook.AppointmentItem> result = null; DateTime date_start = DateTime.ParseExact(crmItem.GetValueAsString("date_start"), "yyyy-MM-dd HH:mm:ss", null); date_start = date_start.Add(new DateTimeOffset(DateTime.Now).Offset); // correct for offset from UTC. if (date_start >= GetStartDate()) { /* search for the item among the sync states I already know about */ var syncState = this.GetExistingSyncState(crmItem); if (syncState == null) { /* didn't find it, so add it to Outlook */ result = AddNewItemFromCrmToOutlook(folder, crmType, crmItem, date_start); } else { /* found it, so update it from the CRM item */ result = UpdateExistingOutlookItemFromCrm(crmType, crmItem, date_start, syncState); } result.OutlookItem.Save(); } 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(); } 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); }
/// <summary> /// Add the item implied by this SyncState, which may not exist in CRM, to CRM. /// </summary> /// <param name="syncState">The sync state.</param> /// <returns>The id of the entry added or updated.</returns> internal override string AddOrUpdateItemFromOutlookToCrm(SyncState <Outlook.AppointmentItem> syncState) { Outlook.AppointmentItem olItem = syncState.OutlookItem; Outlook.UserProperty olPropertyType = olItem.UserProperties[TypePropertyName]; var itemType = olPropertyType != null?olPropertyType.Value.ToString() : this.DefaultCrmModule; return(this.AddOrUpdateItemFromOutlookToCrm(syncState, itemType, syncState.CrmEntryId)); }
/// <summary> /// Override: we get notified of a removal, for a Meeting item, when the meeting is /// cancelled. We do NOT want to remove such an item; instead, we want to update it. /// </summary> /// <param name="state"></param> protected override void RemoveFromCrm(SyncState state) { var meeting = state as MeetingSyncState; if (meeting != null) { meeting.Cache.Status = OlMeetingStatus.olMeetingCanceled; RestAPIWrapper.SetEntry(meeting.Cache.AsNameValues(), DefaultCrmModule); } }
/// <summary> /// TODO: I (AF) do not understand the purpose of this logic. (Pre-existing code, slightly cleaned-up.) /// </summary> /// <param name="contact"></param> /// <returns></returns> private bool ShouldPerformSyncNow(SyncState <Outlook.ContactItem> contact) { var modifiedSinceSeconds = Math.Abs((DateTime.UtcNow - contact.OModifiedDate).TotalSeconds); if (modifiedSinceSeconds > 5 || modifiedSinceSeconds > 2 && contact.IsUpdate == 0) { contact.OModifiedDate = DateTime.UtcNow; contact.IsUpdate = 1; } return(IsCurrentView && contact.IsUpdate == 1); }
/// <summary> /// Add the Outlook item referenced by this sync state, which may not exist in CRM, to CRM. /// </summary> /// <param name="syncState">The sync state referencing the outlook item to add.</param> /// <param name="crmType">The CRM type ('module') to which it should be added</param> /// <param name="entryId">The id of this item in CRM, if known (in which case I should be doing /// an update, not an add).</param> /// <returns>The id of the entry added o</returns> internal override string AddOrUpdateItemFromOutlookToCrm(SyncState <Outlook.AppointmentItem> syncState, string crmType, string entryId = "") { string result = entryId; Outlook.AppointmentItem olItem = syncState.OutlookItem; if (this.ShouldAddOrUpdateItemFromOutlookToCrm(olItem, crmType)) { if (ShouldDeleteFromCrm(olItem)) { LogItemAction(olItem, "AppointmentSyncing.AddOrUpdateItemFromOutlookToCrm: Deleting"); DeleteFromCrm(olItem); } else if (ShouldDespatchToCrm(olItem)) { lock (enqueueingLock) { result = base.AddOrUpdateItemFromOutlookToCrm(syncState, crmType, entryId); if (String.IsNullOrEmpty(result)) { Log.Warn("AppointmentSyncing.AddOrUpdateItemFromOutlookToCrm: Invalid CRM Id returned; item may not have been stored."); } else { if (string.IsNullOrEmpty(entryId)) { /* i.e. this was a new item saved to CRM for the first time */ SetCrmRelationshipFromOutlook(result, "Users", RestAPIWrapper.GetUserId()); this.SaveItem(olItem); if (olItem.Recipients != null) { AddMeetingRecipientsFromOutlookToCrm(olItem, result); } } } } } else { LogItemAction(olItem, "AppointmentSyncing.AddItemFromOutlookToCrm, Not despatching"); } } else { LogItemAction(olItem, "AppointmentSyncing.AddItemFromOutlookToCrm, Not enabled"); } return(result); }
/// <summary> /// Remove an outlook item and its associated sync state. /// </summary> /// <remarks> /// TODO: candidate for refactoring to superclass. /// </remarks> /// <param name="syncState">The sync state of the item to remove.</param> private void RemoveItemAndSyncState(SyncState <Outlook.AppointmentItem> syncState) { this.LogItemAction(syncState.OutlookItem, "AppointmentSyncing.SyncFolder, deleting item"); try { syncState.OutlookItem.Delete(); } catch (Exception ex) { Log.Error("AppointmentSyncing.SyncFolder: Exception oItem.oItem.Delete", ex); } this.RemoveItemSyncState(syncState); }
/// <summary> /// Remove an outlook item and its associated sync state. /// </summary> /// <param name="syncState">The sync state of the item to remove.</param> protected void RemoveItemAndSyncState(SyncState <OutlookItemType> syncState) { this.LogItemAction(syncState.OutlookItem, "Synchroniser.RemoveItemAndSyncState, deleting item"); try { syncState.DeleteItem(); } catch (Exception ex) { Log.Error("Synchroniser.RemoveItemAndSyncState: Exception oItem.oItem.Delete", ex); } this.RemoveItemSyncState(syncState); }
/// <summary> /// Constructs a new SyncState object for this Outlook item and adds it to my /// collection of sync states. /// </summary> /// <param name="olItem">The Outlook item to wrap</param> /// <returns>The sync state added.</returns> private SyncState <OutlookItemType> ConstructAndAddSyncState(OutlookItemType olItem) { try { SyncState <OutlookItemType> newState = ConstructSyncState(olItem); ItemsSyncState.Add(newState); return(newState); } finally { this.SaveItem(olItem); } }
protected override SyncState <Outlook.TaskItem> AddOrUpdateItemFromCrmToOutlook(Outlook.MAPIFolder tasksFolder, string crmType, eEntryValue crmItem) { SyncState <Outlook.TaskItem> result = null; Log.Debug($"TaskSyncing.AddOrUpdateItemFromCrmToOutlook\n\tSubject: {crmItem.GetValueAsString("name")}\n\tCurrent user id {clsSuiteCRMHelper.GetUserId()}\n\tAssigned user id: {crmItem.GetValueAsString("assigned_user_id")}"); if (clsSuiteCRMHelper.GetUserId() == crmItem.GetValueAsString("assigned_user_id")) { DateTime?date_start = null; DateTime?date_due = null; string time_start = "--:--", time_due = "--:--"; if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("date_start"))) { Log.Warn("\tSET date_start = dResult.date_start"); date_start = DateTime.ParseExact(crmItem.GetValueAsString("date_start"), "yyyy-MM-dd HH:mm:ss", null); date_start = date_start.Value.Add(new DateTimeOffset(DateTime.Now).Offset); time_start = TimeSpan.FromHours(date_start.Value.Hour) .Add(TimeSpan.FromMinutes(date_start.Value.Minute)) .ToString(@"hh\:mm"); } if (date_start != null && date_start >= GetStartDate()) { if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("date_due"))) { date_due = DateTime.ParseExact(crmItem.GetValueAsString("date_due"), "yyyy-MM-dd HH:mm:ss", null); date_due = date_due.Value.Add(new DateTimeOffset(DateTime.Now).Offset); time_due = TimeSpan.FromHours(date_due.Value.Hour).Add(TimeSpan.FromMinutes(date_due.Value.Minute)).ToString(@"hh\:mm"); ; } var syncState = this.GetExistingSyncState(crmItem); if (syncState == null) { result = AddNewItemFromCrmToOutlook(tasksFolder, crmItem, date_start, date_due, time_start, time_due); } else { result = UpdateExistingOutlookItemFromCrm(crmItem, date_start, date_due, time_start, time_due, syncState); } } } return(result); }
protected override SyncState <Outlook.ContactItem> AddOrUpdateItemFromCrmToOutlook(Outlook.MAPIFolder folder, string crmType, eEntryValue crmItem) { SyncState <Outlook.ContactItem> result; String id = crmItem.GetValueAsString("id"); SyncState <Outlook.ContactItem> syncStateForItem = GetExistingSyncState(crmItem); if (ShouldSyncContact(crmItem)) { Log.Info( string.Format( "ContactSyncing.UpdateFromCrm, entry id is '{0}', sync_contact is true, syncing", id)); if (syncStateForItem == null) { result = AddNewItemFromCrmToOutlook(folder, crmItem); } else { result = UpdateExistingOutlookItemFromCrm(crmItem, syncStateForItem); } } else if (syncStateForItem != null && syncStateForItem.OutlookItem != null) { /* The date_modified value in CRM does not get updated when the sync_contact value * is changed. But seeing this value can only be updated at the CRM side, if it * has changed the change must have been at the CRM side. It doesn't change to false, * it simply ceases to be sent. Set the item to Private in Outlook. */ if (syncStateForItem.OutlookItem.Sensitivity != Outlook.OlSensitivity.olPrivate) { Log.Info($"ContactSyncing.UpdateFromCrm: setting sensitivity of contact {crmItem.GetValueAsString("first_name")} {crmItem.GetValueAsString("last_name")} ({crmItem.GetValueAsString("email1")}) to private"); syncStateForItem.OutlookItem.Sensitivity = Outlook.OlSensitivity.olPrivate; } result = syncStateForItem; } else { Log.Info( string.Format( "ContactSyncing.UpdateFromCrm, entry id is '{0}', sync_contact is false, not syncing", id)); result = syncStateForItem; } return(result); }
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> /// Delete this Outlook item from CRM, and tidy up afterwards. /// </summary> /// <param name="olItem">The Outlook item to delete.</param> private void DeleteFromCrm(Outlook.AppointmentItem olItem) { if (olItem != null) { /* Remove the magic properties */ RemoveSynchronisationPropertiesFromOutlookItem(olItem); SyncState <Outlook.AppointmentItem> syncStateForItem = GetExistingSyncState(olItem); if (syncStateForItem != null) { this.RemoveFromCrm(syncStateForItem); RemoveItemSyncState(syncStateForItem); } } }
protected override SyncState <Outlook.TaskItem> UpdateFromCrm(Outlook.MAPIFolder tasksFolder, string crmType, eEntryValue crmItem) { SyncState <Outlook.TaskItem> result = null; if (clsSuiteCRMHelper.GetUserId() == crmItem.GetValueAsString("assigned_user_id")) { DateTime?date_start = null; DateTime?date_due = null; string time_start = "--:--", time_due = "--:--"; if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("date_start"))) { Log.Warn("\tSET date_start = dResult.date_start"); date_start = DateTime.ParseExact(crmItem.GetValueAsString("date_start"), "yyyy-MM-dd HH:mm:ss", null); date_start = date_start.Value.Add(new DateTimeOffset(DateTime.Now).Offset); time_start = TimeSpan.FromHours(date_start.Value.Hour) .Add(TimeSpan.FromMinutes(date_start.Value.Minute)) .ToString(@"hh\:mm"); } if (date_start != null && date_start >= GetStartDate()) { if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("date_due"))) { date_due = DateTime.ParseExact(crmItem.GetValueAsString("date_due"), "yyyy-MM-dd HH:mm:ss", null); date_due = date_due.Value.Add(new DateTimeOffset(DateTime.Now).Offset); time_due = TimeSpan.FromHours(date_due.Value.Hour).Add(TimeSpan.FromMinutes(date_due.Value.Minute)).ToString(@"hh\:mm"); ; } var oItem = ItemsSyncState.FirstOrDefault(a => a.CrmEntryId == crmItem.GetValueAsString("id")); if (oItem == null) { result = AddNewItemFromCrmToOutlook(tasksFolder, crmItem, date_start, date_due, time_start, time_due); } else { result = UpdateExistingOutlookItemFromCrm(crmItem, date_start, date_due, time_start, time_due, oItem); } } } return(result); }
/// <summary> /// Get a sync state for this item, creating it if necessary. /// </summary> /// <remarks>Outlook items are not true objects and don't have a common superclass, /// so we have to use this rather clumsy despatch.</remarks> /// <param name="item">the item.</param> /// <returns>an appropriate sync state.</returns> /// <exception cref="UnexpectedSyncStateClassException">if the sync state found is not of the expected class (shouldn't happen).</exception> public SyncState <ItemType> GetOrCreateSyncState <ItemType>(ItemType item) where ItemType : class { lock (this.creationLock) { SyncState <ItemType> result = this.GetExistingSyncState(item); if (result == null) { result = CreateSyncStateForItem(item); } return(result); } }
/// <summary> /// Delete this Outlook item from CRM, and tidy up afterwards. /// </summary> /// <param name="olItem">The Outlook item to delete.</param> private void DeleteFromCrm(Outlook.AppointmentItem olItem) { if (olItem != null) { /* Remove the magic properties */ RemoveSynchronisationPropertiesFromOutlookItem(olItem); SyncState <Outlook.AppointmentItem> syncStateForItem = GetSyncStateForItem(olItem); if (syncStateForItem != null) { this.RemoveFromCrm(syncStateForItem); /* TODO: Not at all sure I should remove the sync state */ RemoveItemSyncState(syncStateForItem); } } }
/// <summary> /// Add the Outlook item referenced by this sync state, which may not exist in CRM, to CRM. /// </summary> /// <param name="syncState">The sync state referencing the outlook item to add.</param> /// <param name="crmType">The CRM type ('module') to which it should be added</param> /// <param name="entryId">The id of this item in CRM, if known (in which case I should be doing /// an update, not an add).</param> /// <returns>The id of the entry added o</returns> internal virtual string AddOrUpdateItemFromOutlookToCrm(SyncState <OutlookItemType> syncState, string crmType, string entryId = "") { string result = entryId; if (this.ShouldAddOrUpdateItemFromOutlookToCrm(syncState.OutlookItem, crmType)) { OutlookItemType outlookItem = syncState.OutlookItem; try { lock (this.TransmissionLock) { LogItemAction(outlookItem, "Synchroniser.AddOrUpdateItemFromOutlookToCrm, Despatching"); if (syncState != null) { syncState.SetTransmitted(); } result = ConstructAndDespatchCrmItem(outlookItem, crmType, entryId); if (!string.IsNullOrEmpty(result)) { var utcNow = DateTime.UtcNow; EnsureSynchronisationPropertiesForOutlookItem(outlookItem, utcNow.ToString(), crmType, result); this.SaveItem(outlookItem); syncState.SetSynced(result); } else { Log.Warn("AppointmentSyncing.AddItemFromOutlookToCrm: Invalid CRM Id returned; item may not be stored."); syncState.SetPending(); } } } catch (Exception ex) { Log.Error("Synchroniser.AddOrUpdateItemFromOutlookToCrm", ex); syncState.SetPending(); } finally { this.SaveItem(outlookItem); } } return(result); }
/// <summary> /// Find the SyncState whose item is this item; if it does not already exist, construct and return it. /// </summary> /// <param name="oItem">The item to find.</param> /// <returns>the SyncState whose item is this item</returns> protected SyncState <OutlookItemType> AddOrGetSyncState(OutlookItemType oItem) { var existingState = GetExistingSyncState(oItem); if (existingState != null) { existingState.OutlookItem = oItem; return(existingState); } else { SyncState <OutlookItemType> newState = ConstructSyncState(oItem); ItemsSyncState.Add(newState); return(newState); } }
/// <summary> /// (Don't actually) remove the item implied by this sync state from CRM. /// </summary> /// <remarks> /// After considerable thought we've decided that contacts should never actually be deleted from CRM /// by the action of the plugin. /// </remarks> /// <param name="state">A sync state wrapping an item which has been deleted or marked private in Outlook.</param> protected override void RemoveFromCrm(SyncState state) { if (state is ContactSyncState) { /* which it most definitely should be */ if (state.ExistedInCrm && (state.IsDeletedInOutlook || !state.IsPublic)) { /* remove sync_contact relationship in CRM */ EnsureSyncWithOutlookSetInCRM(state.CrmEntryId, null, false); } } else { base.RemoveFromCrm(state); } }
/// <summary> /// Check whether there exists a sync state other than this state whose CRM id is /// this CRM id or the CRM id of this state. /// </summary> /// <param name="state">The sync state to be checked.</param> /// <param name="crmId">A candidate CRM id.</param> /// <returns>A better guess at the CRM id.</returns> /// <exception cref="DuplicateSyncStateException">If a duplicate is detected.</exception> private CrmId CheckForDuplicateSyncState(SyncState state, CrmId crmId) { CrmId result = CrmId.IsInvalid(crmId) && state != null ? state.CrmEntryId : crmId; if (result != null) { SyncState byCrmState = this.byCrmId.ContainsKey(crmId) ? this.byCrmId[crmId] : null; if (state != null && byCrmState != null && state != byCrmState) { throw new DuplicateSyncStateException(state); } } return(result); }
/// <summary> /// Remove the item implied by this sync state from CRM. /// </summary> /// <param name="state">A sync state wrapping an item which has been deleted or marked private in Outlook.</param> protected virtual void RemoveFromCrm(SyncState state) { if (SyncDirection.AllowOutbound(Direction)) { var crmEntryId = state.CrmEntryId; if (state.ExistedInCrm && this.permissionsCache.HasImportAccess(state.CrmType)) { eNameValue[] data = new eNameValue[2]; data[0] = clsSuiteCRMHelper.SetNameValuePair("id", crmEntryId); data[1] = clsSuiteCRMHelper.SetNameValuePair("deleted", "1"); clsSuiteCRMHelper.SetEntryUnsafe(data, state.CrmType); } state.RemoveCrmLink(); } }
protected void RemoveFromCrm(SyncState state) { if (!SyncingEnabled) { return; } var crmEntryId = state.CrmEntryId; if (!string.IsNullOrEmpty(crmEntryId) && this.HasImportAccess(state.CrmType)) { eNameValue[] data = new eNameValue[2]; data[0] = clsSuiteCRMHelper.SetNameValuePair("id", crmEntryId); data[1] = clsSuiteCRMHelper.SetNameValuePair("deleted", "1"); clsSuiteCRMHelper.SetEntryUnsafe(data, state.CrmType); } state.RemoveCrmLink(); }
/// <summary> /// Add the Outlook item referenced by this sync state, which may not exist in CRM, to CRM. /// </summary> /// <param name="syncState">The sync state referencing the outlook item to add.</param> /// <param name="crmType">The CRM type ('module') to which it should be added</param> /// <param name="entryId">The id of this item in CRM, if known (in which case I should be doing /// an update, not an add).</param> /// <returns>The id of the entry added o</returns> internal override string AddOrUpdateItemFromOutlookToCrm(SyncState <Outlook.ContactItem> syncState, string crmType, string entryId = "") { string result = entryId; var olItem = syncState.OutlookItem; if (this.ShouldAddOrUpdateItemFromOutlookToCrm(olItem)) { result = base.AddOrUpdateItemFromOutlookToCrm(syncState, crmType, entryId); Outlook.UserProperty syncProperty = olItem.UserProperties["SShouldSync"]; string shouldSync = syncProperty == null? Boolean.TrueString.ToLower() : syncProperty.Value; EnsureSyncWithOutlookSetInCRM(result, syncProperty); } return(result); }
// TODO: this is very horrible and should be reworked. 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")}"); if (RestAPIWrapper.GetUserId() == crmItem.GetValueAsString("assigned_user_id")) { DateTime dateStart = crmItem.GetValueAsDateTime("newValue"); DateTime dateDue = crmItem.GetValueAsDateTime("dateDue"); string timeStart = TimeSpan.FromHours(dateStart.Hour) .Add(TimeSpan.FromMinutes(dateStart.Minute)) .ToString(@"hh\:mm"); string timeDue = TimeSpan.FromHours(dateDue.Hour) .Add(TimeSpan.FromMinutes(dateDue.Minute)) .ToString(@"hh\:mm"); 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> /// Add the Outlook item referenced by this sync state, which may not exist in CRM, to CRM. /// </summary> /// <param name="syncState">The sync state referencing the outlook item to add.</param> /// an update, not an add).</param> /// <returns>The id of the entry added o</returns> internal override CrmId AddOrUpdateItemFromOutlookToCrm(SyncState <Outlook.ContactItem> syncState) { CrmId result = CrmId.Empty; var olItem = syncState.OutlookItem; if (this.ShouldAddOrUpdateItemFromOutlookToCrm(olItem)) { result = base.AddOrUpdateItemFromOutlookToCrm(syncState); Outlook.UserProperty syncProperty = olItem.UserProperties["SShouldSync"]; string shouldSync = syncProperty == null? Boolean.TrueString.ToLower() : syncProperty.Value; EnsureSyncWithOutlookSetInCRM(result, syncProperty); } return(result); }
internal override CrmId AddOrUpdateItemFromOutlookToCrm(SyncState <Outlook.AppointmentItem> syncState) { CrmId previousCrmId = syncState.CrmEntryId; CrmId result = base.AddOrUpdateItemFromOutlookToCrm(syncState); if (CrmId.IsValid(result)) { if (CrmId.IsInvalid(previousCrmId)) /* i.e., it's new */ { if (syncState.OutlookItem.Recipients != null) { AddMeetingRecipientsFromOutlookToCrm(syncState.OutlookItem, result); } this.AddOrUpdateMeetingAcceptanceFromOutlookToCRM(syncState.OutlookItem); } } 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); }
/// <summary> /// Entry point from event handler when an item is added in Outlook. /// </summary> /// <remarks>Should always run in the 'VSTA_main' thread.</remarks> /// <param name="olItem">The item that has been added.</param> protected virtual void OutlookItemAdded(OutlookItemType olItem) { LogItemAction(olItem, "Synchroniser.OutlookItemAdded"); if (Globals.ThisAddIn.IsLicensed) { try { if (olItem != null) { lock (enqueueingLock) { if (IsCurrentView && this.GetExistingSyncState(olItem) == null) { SyncState <OutlookItemType> state = this.ConstructAndAddSyncState(olItem); DaemonWorker.Instance.AddTask(new TransmitNewAction <OutlookItemType>(this, state, this.DefaultCrmModule)); } else { Log.Warn($"Synchroniser.OutlookItemAdded: item {this.GetOutlookEntryId(olItem)} had already been added"); } } } } finally { if (olItem != null) { SaveItem(olItem); } } } else { Log.Warn($"Synchroniser.OutlookItemAdded: item {this.GetOutlookEntryId(olItem)} not added because not licensed"); } }
/// <summary> /// Remove all references to this sync state, if I hold any. /// </summary> /// <param name="state">The state to remove.</param> internal void RemoveSyncState(SyncState state) { lock (this.creationLock) { SyncState ignore; try { if (this.byOutlookId[state.OutlookItemEntryId] == state) { this.byOutlookId.TryRemove(state.OutlookItemEntryId, out ignore); } } catch (KeyNotFoundException) { } catch (COMException) { } try { if (CrmId.IsValid(state.CrmEntryId) && this.byCrmId[state.CrmEntryId] == state) { this.byCrmId.TryRemove(state.CrmEntryId, out ignore); } } catch (KeyNotFoundException) { } } }