Exemple #1
0
        /// <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);
        }
Exemple #2
0
        /// <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());
            }
        }
Exemple #3
0
        /// <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);
            }
        }
Exemple #5
0
        /// <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());
        }
Exemple #6
0
        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);
        }
Exemple #7
0
        /// <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);
        }
Exemple #8
0
        /// <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;
                }
            }
        }
Exemple #11
0
        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();
        }
Exemple #15
0
        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;
                        }
                    }
                }
            }
        }
Exemple #20
0
        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);
        }
Exemple #21
0
        /// <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));
            }
        }
Exemple #23
0
        /// <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);
            }
        }
Exemple #24
0
 /// <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
            });
        }
Exemple #29
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);
     }
 }
Exemple #30
0
        /// <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);
        }