/// <summary> /// Fetch records in pages from CRM, and merge them into Outlook. /// </summary> /// <param name="folder">The folder to be synchronised.</param> /// <param name="crmModule">The name of the CRM module to synchronise with.</param> /// <param name="untouched">A list of all known Outlook items, from which those modified by this method are removed.</param> protected virtual void MergeRecordsFromCrm(Outlook.MAPIFolder folder, string crmModule, HashSet <SyncState <OutlookItemType> > untouched) { int thisOffset = 0; // offset of current page of entries int nextOffset = 0; // offset of the next page of entries, if any. /* get candidates for syncrhonisation from SuiteCRM one page at a time */ do { /* update the offset to the offset of the next page */ thisOffset = nextOffset; /* fetch the page of entries starting at thisOffset */ EntryList entriesPage = RestAPIWrapper.GetEntryList(crmModule, String.Format(fetchQueryPrefix, RestAPIWrapper.GetUserId()), 0, "date_start DESC", thisOffset, false, RestAPIWrapper.GetSugarFields(crmModule)); /* get the offset of the next page */ nextOffset = entriesPage.next_offset; /* when there are no more entries, we'll get a zero-length entry list and nextOffset * will have the same value as thisOffset */ AddOrUpdateItemsFromCrmToOutlook(entriesPage.entry_list, folder, untouched, crmModule); }while (thisOffset != nextOffset); }
/// <summary> /// Create a new instance of ProtoAppointment, taking values from this Outlook item. /// </summary> /// <param name="olItem">The Outlook item to take values from.</param> public ProtoAppointment(Outlook.AppointmentItem olItem) { this.body = olItem.Body; this.duration = olItem.Duration; this.end = olItem.End; this.location = olItem.Location; this.start = olItem.Start; this.subject = olItem.Subject; this.globalId = olItem.GlobalAppointmentID; this.status = olItem.MeetingStatus; var organiserProperty = olItem.UserProperties[AppointmentSyncing.OrganiserPropertyName]; if (organiserProperty == null || string.IsNullOrWhiteSpace(organiserProperty.Value)) { if (olItem.Organizer == clsGlobals.GetCurrentUsername()) { this.organiser = RestAPIWrapper.GetUserId(); } else { this.organiser = TryResolveOrganiser(olItem); } } else { this.organiser = organiserProperty.Value.ToString(); } foreach (Outlook.Recipient recipient in olItem.Recipients) { this.recipientAddresses.Add(recipient.GetSmtpAddress()); } }
/// <summary> /// Set the meeting acceptance status, in CRM, for this invitee to this meeting from /// their acceptance status in Outlook. /// </summary> /// <param name="meeting">The appointment item representing the meeting</param> /// <param name="invitee">The recipient item representing the invitee</param> /// <param name="acceptance">The acceptance status of this invitee of this meeting /// as a string recognised by CRM.</param> /// private int AddOrUpdateMeetingAcceptanceFromOutlookToCRM(Outlook.AppointmentItem meeting, Outlook.Recipient invitee, string acceptance) { int count = 0; string smtpAddress = invitee.GetSmtpAddress(); var meetingId = meeting.GetCrmId(); if (meetingId != null && !string.IsNullOrEmpty(acceptance) && SyncDirection.AllowOutbound(this.Direction)) { foreach (AddressResolutionData resolution in this.ResolveRecipient(meeting, invitee)) { try { RestAPIWrapper.SetMeetingAcceptance(meetingId.ToString(), resolution.ModuleName, resolution.ModuleId.ToString(), acceptance); count++; } catch (System.Exception any) { ErrorHandler.Handle($"Failed to resolve meeting invitee {smtpAddress}:", any); } } } return(count); }
/// <summary> /// Synchronise items in the specified folder with the specified SuiteCRM module. /// </summary> /// <remarks> /// TODO: candidate for refactoring upwards, in concert with ContactSyncing.SyncFolder. /// </remarks> /// <param name="folder">The folder.</param> /// <param name="crmModule">The module.</param> protected override void SyncFolder(Outlook.MAPIFolder folder, string crmModule) { Log.Info(String.Format("AppointmentSyncing.SyncFolder: '{0}'", crmModule)); try { /* this.ItemsSyncState already contains items to be synced. */ var untouched = new HashSet <SyncState <Outlook.AppointmentItem> >(this.ItemsSyncState); MergeRecordsFromCrm(folder, crmModule, untouched); EntryValue[] invited = RestAPIWrapper.GetRelationships("Users", RestAPIWrapper.GetUserId(), crmModule.ToLower(), RestAPIWrapper.GetSugarFields(crmModule)); if (invited != null) { AddOrUpdateItemsFromCrmToOutlook(invited, folder, untouched, crmModule); } try { this.ResolveUnmatchedItems(untouched, crmModule); } catch (Exception ex) { Log.Error("AppointmentSyncing.SyncFolder: Exception", ex); } } catch (Exception ex) { Log.Error("AppointmentSyncing.SyncFolder: Exception", ex); } }
/// <summary> /// If we really don't know anything about the module (which is likely with custom modules) /// the best we can do is see whether any of its text fields matches the search text. /// </summary> /// <param name="moduleName">The name of the module to search.</param> /// <param name="escapedSearchText">The text to search for, escaped for MySQL.</param> /// <returns>A query string.</returns> private static string ConstructQueryTextForUnknownModule(string moduleName, string escapedSearchText) { StringBuilder queryBuilder = new StringBuilder(); if (RestAPIWrapper.GetActivitiesLinks(moduleName, Objective.Email).Count() > 0) { string tableName = moduleName.ToLower(); foreach (string fieldName in RestAPIWrapper.GetCharacterFields(moduleName)) { switch (fieldName) { case "name": case "first_name": case "last_name": queryBuilder.Append($"{tableName}.{fieldName} LIKE '%{escapedSearchText}%' OR "); break; } } queryBuilder.Append($"{tableName}.id in (select eabr.bean_id from email_addr_bean_rel eabr ") .Append("INNER JOIN email_addresses ea on eabr.email_address_id = ea.id ") .Append($"where eabr.bean_module = '{moduleName}' ") .Append($" and ea.email_address LIKE '{escapedSearchText}')"); } return(queryBuilder.ToString()); }
private EntryList TryQuery(string searchText, string moduleName, List <string> fieldsToSeek) { EntryList queryResult = null; string queryText = ConstructQueryTextForModuleName(searchText, moduleName, fieldsToSeek); try { queryResult = RestAPIWrapper.GetEntryList(moduleName, queryText, Properties.Settings.Default.SyncMaxRecords, "date_entered DESC", 0, false, fieldsToSeek.ToArray()); } catch (System.Exception any) { Globals.ThisAddIn.Log.Error($"Failure when custom module included (1)\n\tQuery was '{queryText}'", any); queryText = queryText.Replace("%", string.Empty); try { queryResult = RestAPIWrapper.GetEntryList(moduleName, queryText, Properties.Settings.Default.SyncMaxRecords, "date_entered DESC", 0, false, fieldsToSeek.ToArray()); } catch (Exception secondFail) { Globals.ThisAddIn.Log.Error($"Failure when custom module included (2)\n\tQuery was '{queryText}'", secondFail); queryResult = null; throw; } if (queryResult == null) { throw; } } return(queryResult); }
/// <summary> /// Check meeting acceptances for all future meetings. /// </summary> private int CheckMeetingAcceptances() { int result = 0; foreach (MeetingSyncState state in SyncStateManager.Instance.GetSynchronisedItems <MeetingSyncState>().Where(s => s.VerifyItem())) { Outlook.AppointmentItem item = state.OutlookItem; try { if (CrmId.Get(item.UserProperties[OrganiserPropertyName]?.Value) .Equals(RestAPIWrapper.GetUserId()) && item.Start > DateTime.Now) { result += AddOrUpdateMeetingAcceptanceFromOutlookToCRM(item); } } catch (TypeInitializationException tix) { Log.Warn("Failed to create CrmId with value '{item.UserProperties[OrganiserPropertyName]?.Value}'", tix); } catch (COMException comx) { ErrorHandler.Handle($"Item with CRMid {state.CrmEntryId} appears to be invalid (HResult {comx.HResult})", comx); this.HandleItemMissingFromOutlook(state); } } return(result); }
/// <summary> /// Create a new instance of ProtoAppointment, taking values from this Outlook item. /// </summary> /// <param name="olItem">The Outlook item to take values from.</param> public ProtoAppointment(Outlook.AppointmentItem olItem) : base(olItem.MeetingStatus) { this.olItem = olItem; this.body = olItem.Body; this.CrmEntryId = olItem.GetCrmId(); this.duration = olItem.Duration; this.end = olItem.End; this.location = olItem.Location; this.start = olItem.Start; this.subject = olItem.Subject; this.globalId = olItem.GlobalAppointmentID; var organiserProperty = olItem.UserProperties[AppointmentsSynchroniser <SyncStateType> .OrganiserPropertyName]; if (organiserProperty == null || string.IsNullOrWhiteSpace(organiserProperty.Value)) { if (olItem.Organizer == Globals.ThisAddIn.Application.GetCurrentUsername()) { this.organiser = CrmId.Get(RestAPIWrapper.GetUserId()); } else { this.organiser = TryResolveOrganiser(olItem); } } else { this.organiser = CrmId.Get(organiserProperty.Value.ToString()); } foreach (Outlook.Recipient recipient in olItem.Recipients) { this.recipientAddresses.Add(recipient.GetSmtpAddress()); } }
/// <summary> /// Relate this email result (presumed to represent me) in CRM to these related records. /// </summary> /// <param name="relatedRecords">The records which should be related to my email result.</param> /// <param name="emailResult">An email result (presumed to represent me).</param> private void LinkRelatedRecords(IEnumerable <CrmEntity> relatedRecords, RESTObjects.SetEntryResult emailResult) { var restServer = SuiteCRMUserSession.RestServer; foreach (CrmEntity record in relatedRecords) { try { var success = RestAPIWrapper.TrySetRelationship( new SetRelationshipParams { module2 = "emails", module2_id = emailResult.id, module1 = ModuleToTableResolver.GetTableName(record.ModuleName), module1_id = record.EntityId, }, Objective.Email); if (success) { log.Debug($"Successfully bound {record.ModuleName} '{record.EntityId}' to email '{emailResult.id}' in CRM"); } else { log.Warn($"Failed to bind {record.ModuleName} '{record.EntityId}' to email '{emailResult.id}' in CRM"); } } catch (Exception any) { log.Error($"Failed to bind {record.ModuleName} '{record.EntityId}' to email '{emailResult.id}' in CRM", any); } } }
/// <summary> /// Replace the items in my items list, which is the list passed in by the caller, with /// the options returned for the 'category_id' field of the 'email' module. /// </summary> public override string Perform() { try { Field field = RestAPIWrapper.GetFieldsForModule("Emails").moduleFields.FirstOrDefault(x => x.name == "category_id"); if (field != null) { Properties.Settings.Default.EmailCategories.IsImplemented = true; Properties.Settings.Default.EmailCategories.Clear(); Properties.Settings.Default.EmailCategories.AddRange(field.Options.Keys.OrderBy(x => x)); } else { /* the CRM instance does not have the category_id field in its emails module */ Properties.Settings.Default.EmailCategories.IsImplemented = false; } Properties.Settings.Default.Save(); return("OK"); } catch (WebException wex) { if (wex.Status == WebExceptionStatus.Timeout) { throw new ActionRetryableException("Temporary network error", wex); } else { throw; } } }
private void frmCustomModules_Load(object sender, EventArgs e) { using (new WaitCursor(this)) { try { RestAPIWrapper.EnsureLoggedIn(Globals.ThisAddIn.SuiteCRMUserSession); if (Globals.ThisAddIn.SuiteCRMUserSession.NotLoggedIn) { MessageBox.Show("Please enter SuiteCRM details in General tab and try again", "Invalid Authentication"); base.Close(); return; } PopulateCustomModulesListView(this.lstViewAvailableModules, this.IgnoreModules); } catch (Exception ex) { Log.Warn("frmCustomModules_Load error", ex); base.Close(); MessageBox.Show(ex.Message, ex.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error); } } }
public override NameValueCollection AsNameValues() { return(new NameValueCollection { RestAPIWrapper.SetNameValuePair("email1", Email1Address), RestAPIWrapper.SetNameValuePair("title", JobTitle), RestAPIWrapper.SetNameValuePair("phone_work", BusinessTelephoneNumber), RestAPIWrapper.SetNameValuePair("phone_home", HomeTelephoneNumber), RestAPIWrapper.SetNameValuePair("phone_mobile", MobileTelephoneNumber), RestAPIWrapper.SetNameValuePair("phone_fax", BusinessFaxNumber), RestAPIWrapper.SetNameValuePair("department", Department), RestAPIWrapper.SetNameValuePair("primary_address_city", BusinessAddressCity), RestAPIWrapper.SetNameValuePair("primary_address_state", BusinessAddressState), RestAPIWrapper.SetNameValuePair("primary_address_postalcode", BusinessAddressPostalCode), RestAPIWrapper.SetNameValuePair("primary_address_country", BusinessAddressCountry), RestAPIWrapper.SetNameValuePair("primary_address_street", BusinessAddressStreet), RestAPIWrapper.SetNameValuePair("description", Body), RestAPIWrapper.SetNameValuePair("last_name", LastName), RestAPIWrapper.SetNameValuePair("first_name", FirstName), RestAPIWrapper.SetNameValuePair("account_name", CompanyName), RestAPIWrapper.SetNameValuePair("salutation", Title), CrmId.IsValid(CrmEntryId) ? RestAPIWrapper.SetNameValuePair("id", CrmEntryId.ToString()) : RestAPIWrapper.SetNameValuePair("assigned_user_id", RestAPIWrapper.GetUserId()), RestAPIWrapper.SetNameValuePair("sync_contact", this.isPublic) }); }
public override NameValueCollection AsNameValues(string entryId) { var data = new NameValueCollection(); data.Add(RestAPIWrapper.SetNameValuePair("email1", Email1Address)); data.Add(RestAPIWrapper.SetNameValuePair("title", JobTitle)); data.Add(RestAPIWrapper.SetNameValuePair("phone_work", BusinessTelephoneNumber)); data.Add(RestAPIWrapper.SetNameValuePair("phone_home", HomeTelephoneNumber)); data.Add(RestAPIWrapper.SetNameValuePair("phone_mobile", MobileTelephoneNumber)); data.Add(RestAPIWrapper.SetNameValuePair("phone_fax", BusinessFaxNumber)); data.Add(RestAPIWrapper.SetNameValuePair("department", Department)); data.Add(RestAPIWrapper.SetNameValuePair("primary_address_city", BusinessAddressCity)); data.Add(RestAPIWrapper.SetNameValuePair("primary_address_state", BusinessAddressState)); data.Add(RestAPIWrapper.SetNameValuePair("primary_address_postalcode", BusinessAddressPostalCode)); data.Add(RestAPIWrapper.SetNameValuePair("primary_address_country", BusinessAddressCountry)); data.Add(RestAPIWrapper.SetNameValuePair("primary_address_street", BusinessAddressStreet)); data.Add(RestAPIWrapper.SetNameValuePair("description", Body)); data.Add(RestAPIWrapper.SetNameValuePair("last_name", LastName)); data.Add(RestAPIWrapper.SetNameValuePair("first_name", FirstName)); data.Add(RestAPIWrapper.SetNameValuePair("account_name", CompanyName)); data.Add(RestAPIWrapper.SetNameValuePair("salutation", Title)); data.Add(string.IsNullOrEmpty(entryId) ? RestAPIWrapper.SetNameValuePair("assigned_user_id", RestAPIWrapper.GetUserId()) : RestAPIWrapper.SetNameValuePair("id", entryId)); return(data); }
public ArchiveModuleSelectFieldsDialog() { InitializeComponent(); _availableModules = RestAPIWrapper.GetModules(); this.AddStandardModules(); }
private bool TryAddRecipientInModule(string moduleName, CrmId meetingId, Outlook.Recipient recipient) { bool result; CrmId id = SetCrmRelationshipFromOutlook(this, meetingId, recipient, moduleName); if (CrmId.IsValid(id)) { string smtpAddress = recipient.GetSmtpAddress(); this.CacheAddressResolutionData( new AddressResolutionData(moduleName, id, smtpAddress)); CrmId accountId = CrmId.Get(RestAPIWrapper.GetRelationship( ContactSynchroniser.CrmModule, id.ToString(), "accounts")); if (CrmId.IsValid(accountId) && SetCrmRelationshipFromOutlook(this, meetingId, "Accounts", accountId)) { this.CacheAddressResolutionData( new AddressResolutionData("Accounts", accountId, smtpAddress)); } result = true; } else { result = false; } return(result); }
/// <summary> /// Delete my existing record and create a new one. /// </summary> /// <param name="relatedRecords">CRM module names/ids of records to which I should be related.</param> /// <param name="fails">Any previous failures in attempting to save me.</param> /// <returns>An archive result object describing the outcome of this attempt.</returns> private ArchiveResult TryUpdate(IEnumerable <CrmEntity> relatedRecords, Exception[] fails) { ArchiveResult result; try { // delete NameValue[] deletePacket = new NameValue[2]; deletePacket[0] = RestAPIWrapper.SetNameValuePair("id", this.CrmEntryId); deletePacket[1] = RestAPIWrapper.SetNameValuePair("deleted", "1"); RestAPIWrapper.SetEntry(deletePacket, "Emails"); // recreate result = this.TrySave(relatedRecords, fails); } catch (Exception any) { List <Exception> newFails = new List <Exception>(); newFails.Add(any); if (fails != null && fails.Any()) { newFails.AddRange(fails); } result = ArchiveResult.Failure(newFails.ToArray()); } return(result); }
private bool TryAddRecipientInModule(string moduleName, string meetingId, Outlook.Recipient recipient) { bool result; string id = SetCrmRelationshipFromOutlook(meetingId, recipient, moduleName); if (!string.IsNullOrWhiteSpace(id)) { string smtpAddress = recipient.GetSmtpAddress(); this.meetingRecipientsCache[recipient.GetSmtpAddress()] = new AddressResolutionData(moduleName, id, smtpAddress); string accountId = RestAPIWrapper.GetRelationship(ContactSyncing.CrmModule, id, "accounts"); if (!string.IsNullOrWhiteSpace(accountId) && SetCrmRelationshipFromOutlook(meetingId, "Accounts", accountId)) { this.meetingRecipientsCache[smtpAddress] = new AddressResolutionData("Accounts", accountId, smtpAddress); } result = true; } else { result = false; } return(result); }
/// <summary> /// Get contact ids of all email addresses in my From, To, or CC fields which /// are known to CRM and not included in these excluded addresses. /// </summary> /// <param name="excludedAddresses">email addresses for which contact ids should /// not be returned.</param> /// <returns>A list of strings representing CRM contact ids.</returns> private List <string> GetValidContactIds(List <string> excludedAddresses) { RestAPIWrapper.EnsureLoggedIn(SuiteCRMUserSession); List <string> result = new List <string>(); List <string> checkedAddresses = new List <string>(); try { foreach (string address in ConstructAddressList($"{this.From};{this.To};{this.CC}")) { if (!checkedAddresses.Contains(address) && !excludedAddresses.Contains(address.ToUpper())) { var contactReturn = SuiteCRMUserSession.RestServer.GetCrmResponse <RESTObjects.Contacts>("get_entry_list", ConstructGetContactIdByAddressPacket(address)); if (contactReturn.entry_list != null && contactReturn.entry_list.Count > 0) { result.Add(contactReturn.entry_list[0].id); } } checkedAddresses.Add(address); } } catch (Exception ex) { log.Warn("GetValidContactIDs error", ex); throw; } return(result); }
private void CheckMeetingAcceptances() { foreach (AppointmentSyncState state in this.ItemsSyncState) { Outlook.AppointmentItem item = state.OutlookItem; if (item.UserProperties[OrganiserPropertyName]?.Value == RestAPIWrapper.GetUserId() && item.Start > DateTime.Now) { foreach (Outlook.Recipient invitee in item.Recipients) { switch (invitee.MeetingResponseStatus) { case Outlook.OlResponseStatus.olResponseAccepted: this.AddOrUpdateMeetingAcceptanceFromOutlookToCRM(item, invitee, "Accept"); break; case Outlook.OlResponseStatus.olResponseDeclined: this.AddOrUpdateMeetingAcceptanceFromOutlookToCRM(item, invitee, "Decline"); break; case Outlook.OlResponseStatus.olResponseTentative: this.AddOrUpdateMeetingAcceptanceFromOutlookToCRM(item, invitee, "Tentative"); break; default: // nothing to do break; } } } } }
private void btnSave_Click(object sender, EventArgs e) { if (!ValidateDetails()) { this.DialogResult = DialogResult.None; return; } try { if (!SafelyGetText(txtURL).EndsWith(@"/")) { txtURL.Text = SafelyGetText(txtURL) + "/"; } string LDAPAuthenticationKey = SafelyGetText(txtLDAPAuthenticationKey); if (LDAPAuthenticationKey == string.Empty) { LDAPAuthenticationKey = null; } /* save settings before, and regardless of, test that login succeeds. * Otherwise in cases where login is impossible (e.g. network failure) * settings get lost. See bug #187 */ this.SaveSettings(); Globals.ThisAddIn.SuiteCRMUserSession = new SuiteCRMClient.UserSession( SafelyGetText(txtURL), SafelyGetText(txtUsername), SafelyGetText(txtPassword), LDAPAuthenticationKey, ThisAddIn.AddInTitle, Log, Properties.Settings.Default.RestTimeout); Globals.ThisAddIn.SuiteCRMUserSession.Login(); if (Globals.ThisAddIn.SuiteCRMUserSession.NotLoggedIn) { MessageBox.Show("Authentication failed!!!", "Authentication failed", MessageBoxButtons.OK, MessageBoxIcon.Error); this.DialogResult = DialogResult.None; return; } } catch (Exception ex) { Log.Warn("Unable to connect to SuiteCRM", ex); MessageBox.Show(ex.Message, "Unable to connect to SuiteCRM", MessageBoxButtons.OK, MessageBoxIcon.Error); this.DialogResult = DialogResult.None; return; } RestAPIWrapper.FlushUserIdCache(); base.Close(); this.SettingsChanged?.Invoke(this, EventArgs.Empty); }
/// <summary> /// Obtain the server version from the server, if specified, and write it to the log. /// </summary> private void LogServerVersion() { ServerInfo info = RestAPIWrapper.GetServerInfo(); if (!string.IsNullOrWhiteSpace(info.SuiteCRMVersion)) { log.Info($"Connected to an instance of SuiteCRM version {info.SuiteCRMVersion}."); } }
private void ProcessNewMeetingItem(Outlook.MeetingItem meetingItem) { string vCalId = meetingItem.GetVCalId(); if (CrmId.IsValid(vCalId) && RestAPIWrapper.GetEntry(MeetingsSynchroniser.DefaultCrmModule, vCalId, new string[] { "id" }) != null) { meetingItem.GetAssociatedAppointment(false).SetCrmId(CrmId.Get(vCalId)); } }
/// <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> /// Specialisation: also fetch names and email ids of recipients. /// </summary> /// <param name="offset">The offset into the resultset at which the page begins.</param> /// <returns>A set of entries.</returns> protected override EntryList GetEntriesPage(int offset) { return(RestAPIWrapper.GetEntryList(this.DefaultCrmModule, String.Format(fetchQueryPrefix, RestAPIWrapper.GetUserId()), Properties.Settings.Default.SyncMaxRecords, "date_start DESC", offset, false, RestAPIWrapper.GetSugarFields(this.DefaultCrmModule), new[] { new { @name = "users", @value = new[] { "id", "email1", "phone_work" } }, new { @name = "contacts", @value = new[] { "id", "account_id", "email1", "phone_work" } }, new { @name = "leads", @value = new[] { "id", "email1", "phone_work" } } })); }
private void btnSearch_Click(object sender, EventArgs e) { string[] strArray = new string[2]; string str = "OR"; using (WaitCursor.For(this)) { if (this.txtSearch.Text == string.Empty) { MessageBox.Show("Please enter something to search for", "Error"); } else { this.lstViewResults.Items.Clear(); string[] strArray2 = new string[] { "Leads", ContactSynchroniser.CrmModule }; if (this.txtSearch.Text.Contains <char>(' ')) { strArray = this.txtSearch.Text.Split(new char[] { ' ' }); } else { strArray[0] = this.txtSearch.Text; strArray[1] = this.txtSearch.Text; } if ((strArray[1] != string.Empty) && (strArray[0] != strArray[1])) { str = "AND"; } foreach (string str2 in strArray2) { string query = "(" + str2.ToLower() + ".first_name LIKE '%" + strArray[0] + "%' " + str + " " + str2.ToLower() + ".last_name LIKE '%" + strArray[1] + "%')"; bool flag1 = str2 == ContactSynchroniser.CrmModule; if (this.cbMyItems.Checked) { string str8 = query; query = str8 + "AND " + str2.ToLower() + ".assigned_user_id = '" + Globals.ThisAddIn.SuiteCRMUserSession.id + "'"; } foreach (EntryValue _value in RestAPIWrapper.GetEntryList(str2, query, 0, "date_entered DESC", 0, false, new string[] { "first_name", "last_name", "email1" }).entry_list) { string str4 = string.Empty; string str5 = string.Empty; string valueByKey = string.Empty; string str7 = string.Empty; valueByKey = RestAPIWrapper.GetValueByKey(_value, "first_name"); str7 = RestAPIWrapper.GetValueByKey(_value, "last_name"); RestAPIWrapper.GetValueByKey(_value, "id"); str5 = RestAPIWrapper.GetValueByKey(_value, "email1"); str4 = valueByKey + " " + str7; this.lstViewResults.Items.Add(new ListViewItem(new string[] { str4, str5, str2 })); } } } } }
/// <summary> /// Relate the email and the attachment /// </summary> /// <param name="emailId"></param> /// <param name="attachmentId"></param> /// <returns></returns> private bool BindAttachmentInCrm(string emailId, string attachmentId) { return(RestAPIWrapper.TrySetRelationship( new SetRelationshipParams { module2 = "emails", module2_id = emailId, module1 = "notes", module1_id = attachmentId, }, Objective.Email)); }
/// <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> /// Construct a packet representing my email. /// </summary> /// <returns>A packet which, when transmitted to CRM, will instantiate my email.</returns> private object ConstructPacket(string htmlBody) { List <RESTObjects.NameValue> emailData = new List <RESTObjects.NameValue> { new RESTObjects.NameValue() { name = "from_addr", value = this.From }, new RESTObjects.NameValue() { name = "to_addrs", value = this.To.Replace("\n", "") }, new RESTObjects.NameValue() { name = "name", value = this.Subject }, new RESTObjects.NameValue() { name = "date_sent", value = this.Sent.ToString(EmailDateFormat) }, new RESTObjects.NameValue() { name = "description", value = this.Body }, new RESTObjects.NameValue() { name = "description_html", value = htmlBody }, new RESTObjects.NameValue() { name = "assigned_user_id", value = RestAPIWrapper.GetUserId() }, new RESTObjects.NameValue() { name = "status", value = "archived" }, new RESTObjects.NameValue() { name = "category_id", value = this.Category }, new RESTObjects.NameValue() { name = "message_id", value = this.OutlookId } }; return(new { @session = SuiteCRMUserSession.id, @module_name = "Emails", @name_value_list = emailData }); }
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> /// AsNameValues is used in transmission to CRM as well as for comparison, so it should NOT /// access our cache of recipient addresses. /// </summary> /// <returns>A set of name/value pairs suitable for transmitting to CRM.</returns> public override NameValueCollection AsNameValues() { string statusString; string name; switch (this.Status) { case Outlook.OlMeetingStatus.olMeetingCanceled: statusString = "Not Held"; name = this.subject.StartsWith(CancelledPrefix) ? this.subject : $"{CancelledPrefix}: {this.subject}"; break; default: statusString = this.start < DateTime.Now ? "Held" : "Planned"; name = this.subject; break; } NameValueCollection data = new NameValueCollection { RestAPIWrapper.SetNameValuePair("name", name), RestAPIWrapper.SetNameValuePair("description", this.body), RestAPIWrapper.SetNameValuePair("location", this.location), RestAPIWrapper.SetNameValuePair("date_start", string.Format("{0:yyyy-MM-dd HH:mm:ss}", this.start.ToUniversalTime())), RestAPIWrapper.SetNameValuePair("date_end", string.Format("{0:yyyy-MM-dd HH:mm:ss}", this.end.ToUniversalTime())), RestAPIWrapper.SetNameValuePair("duration_minutes", (this.duration % 60).ToString()), RestAPIWrapper.SetNameValuePair("duration_hours", (this.duration / 60).ToString()), RestAPIWrapper.SetNameValuePair("outlook_id", this.globalId), RestAPIWrapper.SetNameValuePair("status", statusString) }; if (CrmId.IsValid(this.organiser)) { data.Add(RestAPIWrapper.SetNameValuePair("assigned_user_id", this.organiser.ToString())); } if (CrmId.IsInvalid(CrmEntryId)) { /* A Guid can be constructed from a 32 digit hex string. The globalId is a * 112 digit hex string. It appears from inspection that the least significant * bytes are those that vary between examples, with the most significant bytes * being invariant in the samples we have to hand. */ CrmEntryId = CrmId.Get(new Guid(this.globalId.Substring(this.globalId.Length - 32))); data.Add(RestAPIWrapper.SetNameValuePair("new_with_id", true)); } data.Add(RestAPIWrapper.SetNameValuePair("id", CrmEntryId.ToString())); return(data); }