Beispiel #1
0
        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Load" /> event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            nbPeople.Visible = false;

            if (!Page.IsPostBack)
            {
                int?setId = PageParameter("Set").AsIntegerOrNull();
                if (setId.HasValue)
                {
                    var selectedPersonIds = new EntitySetItemService(new RockContext())
                                            .GetByEntitySetId(setId.Value)
                                            .Select(i => i.EntityId)
                                            .Distinct()
                                            .ToList();

                    // Get the people selected
                    var people = new PersonService(new RockContext()).Queryable("CreatedByPersonAlias.Person,Users", true)
                                 .Where(p => selectedPersonIds.Contains(p.Id))
                                 .ToList();

                    // Create the data structure used to build grid
                    MergeData = new MergeData(people, headingKeys);
                    BuildColumns();
                    BindGrid();
                }
            }
            else
            {
                var primaryColIndex = hfSelectedColumn.Value.AsIntegerOrNull();

                // Save the primary header radio button's selection
                foreach (var col in gValues.Columns.OfType <PersonMergeField>())
                {
                    col.OnDelete += personCol_OnDelete;
                    if (primaryColIndex.HasValue && primaryColIndex.Value == col.ColumnIndex)
                    {
                        MergeData.PrimaryPersonId = col.PersonId;
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Gets the merge object list for the current EntitySet
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="fetchCount">The fetch count.</param>
        /// <returns></returns>
        private List <object> GetMergeObjectList(RockContext rockContext, int?fetchCount = null)
        {
            int entitySetId      = hfEntitySetId.Value.AsInteger();
            var entitySetService = new EntitySetService(rockContext);
            var entitySet        = entitySetService.Get(entitySetId);
            Dictionary <int, object> mergeObjectsDictionary = new Dictionary <int, object>();

            // If this EntitySet contains IEntity Items, add those first
            if (entitySet.EntityTypeId.HasValue)
            {
                var qryEntity = entitySetService.GetEntityQuery(entitySetId);

                if (fetchCount.HasValue)
                {
                    qryEntity = qryEntity.Take(fetchCount.Value);
                }

                var  entityTypeCache         = EntityTypeCache.Read(entitySet.EntityTypeId.Value);
                bool isPersonEntityType      = entityTypeCache != null && entityTypeCache.Guid == Rock.SystemGuid.EntityType.PERSON.AsGuid();
                bool isGroupMemberEntityType = entityTypeCache != null && entityTypeCache.Guid == Rock.SystemGuid.EntityType.GROUP_MEMBER.AsGuid();
                bool combineFamilyMembers    = cbCombineFamilyMembers.Visible && cbCombineFamilyMembers.Checked;

                if ((isGroupMemberEntityType || isPersonEntityType) && combineFamilyMembers)
                {
                    IQueryable <IEntity> qryPersons;
                    if (isGroupMemberEntityType)
                    {
                        qryPersons = qryEntity.OfType <GroupMember>().Select(a => a.Person).Distinct();
                    }
                    else
                    {
                        qryPersons = qryEntity;
                    }

                    Guid familyGroupType       = Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY.AsGuid();
                    var  qryFamilyGroupMembers = new GroupMemberService(rockContext).Queryable("GroupRole,Person").AsNoTracking()
                                                 .Where(a => a.Group.GroupType.Guid == familyGroupType)
                                                 .Where(a => qryPersons.Any(aa => aa.Id == a.PersonId));

                    var qryCombined = qryFamilyGroupMembers.Join(
                        qryPersons,
                        m => m.PersonId,
                        p => p.Id,
                        (m, p) => new { GroupMember = m, Person = p })
                                      .GroupBy(a => a.GroupMember.GroupId)
                                      .Select(x => new
                    {
                        GroupId = x.Key,
                        // Order People to match ordering in the GroupMembers.ascx block.
                        Persons =
                            // Adult Male
                            x.Where(xx => xx.GroupMember.GroupRole.Guid.Equals(new Guid(Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT)) &&
                                    xx.GroupMember.Person.Gender == Gender.Male).OrderByDescending(xx => xx.GroupMember.Person.BirthDate).Select(xx => xx.Person)
                            // Adult Female
                            .Concat(x.Where(xx => xx.GroupMember.GroupRole.Guid.Equals(new Guid(Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT)) &&
                                            xx.GroupMember.Person.Gender != Gender.Male).OrderByDescending(xx => xx.GroupMember.Person.BirthDate).Select(xx => xx.Person))
                            // non-adults
                            .Concat(x.Where(xx => !xx.GroupMember.GroupRole.Guid.Equals(new Guid(Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT)))
                                    .OrderByDescending(xx => xx.GroupMember.Person.BirthDate).Select(xx => xx.Person))
                    });

                    foreach (var combinedFamilyItem in qryCombined)
                    {
                        object mergeObject;

                        string commaPersonIds = combinedFamilyItem.Persons.Select(a => a.Id).Distinct().ToList().AsDelimited(",");

                        var primaryGroupPerson = combinedFamilyItem.Persons.FirstOrDefault() as Person;

                        if (mergeObjectsDictionary.ContainsKey(primaryGroupPerson.Id))
                        {
                            foreach (var person in combinedFamilyItem.Persons)
                            {
                                if (!mergeObjectsDictionary.ContainsKey(person.Id))
                                {
                                    primaryGroupPerson = person as Person;
                                    break;
                                }
                            }
                        }

                        // if we are combining from a GroupMemberEntityType list add the GroupMember attributes of the primary person in the combined list
                        if (isGroupMemberEntityType)
                        {
                            var groupMember = qryEntity.OfType <GroupMember>().Where(a => a.PersonId == primaryGroupPerson.Id).FirstOrDefault();
                            primaryGroupPerson.AdditionalLavaFields = primaryGroupPerson.AdditionalLavaFields ?? new Dictionary <string, object>();
                            if (groupMember != null)
                            {
                                primaryGroupPerson.AdditionalLavaFields.AddOrIgnore("GroupMember", groupMember);
                            }
                        }

                        if (combinedFamilyItem.Persons.Count() > 1)
                        {
                            var combinedPerson = primaryGroupPerson.ToJson().FromJsonOrNull <MergeTemplateCombinedPerson>();

                            var familyTitle = RockUdfHelper.ufnCrm_GetFamilyTitle(rockContext, null, combinedFamilyItem.GroupId, commaPersonIds, true);
                            combinedPerson.FullName = familyTitle;

                            var firstNameList = combinedFamilyItem.Persons.Select(a => (a as Person).FirstName).ToList();
                            var nickNameList  = combinedFamilyItem.Persons.Select(a => (a as Person).NickName).ToList();

                            combinedPerson.FirstName     = firstNameList.AsDelimited(", ", " & ");
                            combinedPerson.NickName      = nickNameList.AsDelimited(", ", " & ");
                            combinedPerson.LastName      = primaryGroupPerson.LastName;
                            combinedPerson.SuffixValueId = null;
                            combinedPerson.SuffixValue   = null;
                            mergeObject = combinedPerson;
                        }
                        else
                        {
                            mergeObject = primaryGroupPerson;
                        }

                        mergeObjectsDictionary.AddOrIgnore(primaryGroupPerson.Id, mergeObject);
                    }
                }
                else if (isGroupMemberEntityType)
                {
                    foreach (var groupMember in qryEntity.AsNoTracking().OfType <GroupMember>())
                    {
                        var person = groupMember.Person;
                        person.AdditionalLavaFields = new Dictionary <string, object>();
                        person.AdditionalLavaFields.Add("GroupMember", groupMember);
                        mergeObjectsDictionary.AddOrIgnore(groupMember.PersonId, person);
                    }
                }
                else
                {
                    foreach (var item in qryEntity.AsNoTracking())
                    {
                        mergeObjectsDictionary.AddOrIgnore(item.Id, item);
                    }
                }
            }

            var entitySetItemService = new EntitySetItemService(rockContext);

            string[] emptyJson = new string[] { string.Empty, "{}" };
            var      entitySetItemMergeValuesQry = entitySetItemService.GetByEntitySetId(entitySetId, true).Where(a => !emptyJson.Contains(a.AdditionalMergeValuesJson));

            if (fetchCount.HasValue)
            {
                entitySetItemMergeValuesQry = entitySetItemMergeValuesQry.Take(fetchCount.Value);
            }

            // the entityId to use for NonEntity objects
            int nonEntityId = 1;

            // now, add the additional MergeValues regardless of if the EntitySet contains IEntity items or just Non-IEntity items
            foreach (var additionalMergeValuesItem in entitySetItemMergeValuesQry.AsNoTracking())
            {
                object mergeObject;
                int    entityId;
                if (additionalMergeValuesItem.EntityId > 0)
                {
                    entityId = additionalMergeValuesItem.EntityId;
                }
                else
                {
                    // not pointing to an actual EntityId, so use the nonEntityId for ti
                    entityId = nonEntityId++;
                }

                if (mergeObjectsDictionary.ContainsKey(entityId))
                {
                    mergeObject = mergeObjectsDictionary[entityId];
                }
                else
                {
                    if (entitySet.EntityTypeId.HasValue)
                    {
                        // if already have real entities in our list, don't add additional items to the mergeObjectsDictionary
                        continue;
                    }

                    // non-Entity merge object, so just use Dictionary
                    mergeObject = new Dictionary <string, object>();
                    mergeObjectsDictionary.AddOrIgnore(entityId, mergeObject);
                }

                foreach (var additionalMergeValue in additionalMergeValuesItem.AdditionalMergeValues)
                {
                    if (mergeObject is IEntity)
                    {
                        // add the additional fields to AdditionalLavaFields
                        IEntity mergeEntity = (mergeObject as IEntity);
                        mergeEntity.AdditionalLavaFields = mergeEntity.AdditionalLavaFields ?? new Dictionary <string, object>();
                        object mergeValueObject = additionalMergeValue.Value;

                        // if the mergeValueObject is a JArray (JSON Object), convert it into an ExpandoObject or List<ExpandoObject> so that Lava will work on it
                        if (mergeValueObject is JArray)
                        {
                            var jsonOfObject = mergeValueObject.ToJson();
                            try
                            {
                                mergeValueObject = Rock.Lava.RockFilters.FromJSON(jsonOfObject);
                            }
                            catch (Exception ex)
                            {
                                LogException(new Exception("MergeTemplateEntry couldn't do a FromJSON", ex));
                            }
                        }

                        mergeEntity.AdditionalLavaFields.AddOrIgnore(additionalMergeValue.Key, mergeValueObject);
                    }
                    else if (mergeObject is IDictionary <string, object> )
                    {
                        // anonymous object with no fields yet
                        IDictionary <string, object> nonEntityObject = mergeObject as IDictionary <string, object>;
                        nonEntityObject.AddOrIgnore(additionalMergeValue.Key, additionalMergeValue.Value);
                    }
                    else
                    {
                        throw new Exception(string.Format("Unexpected MergeObject Type: {0}", mergeObject));
                    }
                }
            }

            var result = mergeObjectsDictionary.Select(a => a.Value);

            if (fetchCount.HasValue)
            {
                // make sure the result is limited to fetchCount (even though the above queries are also limited to fetch count)
                result = result.Take(fetchCount.Value);
            }

            return(result.ToList());
        }
Beispiel #3
0
        /// <summary>
        /// Assigns the connection requests from the SelectedCampaign's entity set.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="selectedCampaignItem">The selected campaign item.</param>
        /// <param name="numberOfRequestsRemaining">The number of requests remaining.</param>
        /// <param name="connectorPerson">The connector person.</param>
        private static void AssignConnectionRequestsFromEntitySet(RockContext rockContext, CampaignItem selectedCampaignItem, ref int numberOfRequestsRemaining, Person connectorPerson)
        {
            var opportunityService            = new ConnectionOpportunityService(rockContext);
            ConnectionOpportunity opportunity = opportunityService.Get(selectedCampaignItem.OpportunityGuid);

            if (opportunity == null || !opportunity.IsActive)
            {
                return;
            }

            int?defaultStatusId = opportunity.ConnectionType.ConnectionStatuses
                                  .Where(s => s.IsDefault)
                                  .Select(s => ( int? )s.Id)
                                  .FirstOrDefault();

            // If opportunity doesn't have a default status, something is wrong
            if (defaultStatusId == null)
            {
                return;
            }

            var connectorCampusIds = GetConnectorCampusIds(selectedCampaignItem, connectorPerson);

            var connectionRequestService         = new ConnectionRequestService(rockContext);
            var connectionRequestActivityService = new ConnectionRequestActivityService(rockContext);

            // get previous connections for the connector that have the same campus of the connector, or if the person's campus or connector person's campus is null
            var previousConnectedPersonIdsForCurrentPerson = connectionRequestService.Queryable()
                                                             .Where(a => a.ConnectionOpportunityId == opportunity.Id)
                                                             .Where(a => a.ConnectorPersonAlias.PersonId == connectorPerson.Id)
                                                             .Where(a => (a.CampusId == null) || connectorCampusIds.Any(connectorCampusId => connectorCampusId == null || a.CampusId.Value == connectorCampusId))
                                                             .Select(a => a.PersonAlias.PersonId).Distinct().ToList();

            var entitySetId          = CampaignConnectionHelper.GetEntitySet(selectedCampaignItem);
            var entitySetItemService = new EntitySetItemService(rockContext);
            var entitySetItemList    = entitySetItemService.Queryable().Where(a => a.EntitySetId == entitySetId).OrderBy(a => a.Order).Select(a => new
            {
                PersonId        = a.EntityId,
                EntityItemOrder = a.Order
            }).ToList();

            if (selectedCampaignItem.PreferPreviousConnector)
            {
                // sort them by any where the current person was assigned to this person before
                entitySetItemList = entitySetItemList
                                    .OrderBy(a => previousConnectedPersonIdsForCurrentPerson.Any(x => x == a.PersonId))
                                    .ThenBy(a => a.EntityItemOrder).ToList();
            }
            else
            {
                entitySetItemList = entitySetItemList.OrderBy(a => a.EntityItemOrder).ToList();
            }

            var personService = new PersonService(rockContext);

            // get the last connection datetime.
            var lastConnectionDateTime = RockDateTime.Now.AddDays(-selectedCampaignItem.DaysBetweenConnection);

            // if DaysBetweenConnection is 0 then check for connection request for any time period.
            if (selectedCampaignItem.DaysBetweenConnection == default(int))
            {
                lastConnectionDateTime = DateTime.MinValue;
            }

            foreach (var entitySetItem in entitySetItemList)
            {
                var entitySetPerson = personService.Get(entitySetItem.PersonId);
                if (entitySetPerson == null)
                {
                    continue;
                }

                var entitySetPersonPrimaryCampusId = entitySetPerson.PrimaryCampusId;

                bool validCampus = IsValidCampus(connectorCampusIds, entitySetPersonPrimaryCampusId);
                if (!validCampus)
                {
                    continue;
                }

                // double check that they haven't already been added
                bool personAlreadyHasConnectionRequest = PersonAlreadyHasConnectionRequest(opportunity.Id, rockContext, lastConnectionDateTime, entitySetPerson.Id);

                if (personAlreadyHasConnectionRequest)
                {
                    continue;
                }

                var connectionRequest = new ConnectionRequest();
                connectionRequest.ConnectionOpportunityId = opportunity.Id;

                /*
                 *  3/30/2020 - NA
                 *
                 *  When setting the connection request's Requester, we have to use the PrimaryAlias
                 *  to set the connectionRequest.PersonAlias property because the ConnectionRequestChangeTransaction
                 *  https://github.com/SparkabilityGroup/Rock/blob/a556a9285b7fdfe5594441286242f4feaa5847f2/Rock/Transactions/ConnectionRequestChangeTransaction.cs#L123
                 *  (which handles triggered workflows) expects it.  Also, it needs to be tracked by
                 *  the current rockContext... hence the change from GetAsNoTracking() to just Get() above:
                 *  var entitySetPerson = personService.Get( entitySetItem.PersonId );
                 *
                 *  In other words, this will not work correctly:
                 *  connectionRequest.PersonAliasId = entitySetPerson.PrimaryAliasId.Value;
                 *
                 *  Reason: This plug-in cannot change Rock core assembly code.
                 */

                connectionRequest.PersonAlias            = entitySetPerson.PrimaryAlias;
                connectionRequest.ConnectionState        = ConnectionState.Active;
                connectionRequest.ConnectorPersonAliasId = connectorPerson.PrimaryAliasId;
                connectionRequest.CampusId           = entitySetPersonPrimaryCampusId;
                connectionRequest.ConnectionStatusId = defaultStatusId.Value;

                if (selectedCampaignItem.RequestCommentsLavaTemplate.IsNotNullOrWhiteSpace())
                {
                    var mergeFields = new Dictionary <string, object>();
                    mergeFields.Add("Person", entitySetPerson);
                    mergeFields.Add("Family", entitySetPerson.GetFamily());
                    connectionRequest.Comments = selectedCampaignItem.RequestCommentsLavaTemplate.ResolveMergeFields(mergeFields);
                }

                connectionRequestService.Add(connectionRequest);

                var connectionActivityTypeAssignedGuid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid();
                int?assignedActivityId = new ConnectionActivityTypeService(rockContext).GetId(connectionActivityTypeAssignedGuid);
                if (assignedActivityId.HasValue)
                {
                    var connectionRequestActivity = new ConnectionRequestActivity();
                    connectionRequestActivity.ConnectionRequest        = connectionRequest;
                    connectionRequestActivity.ConnectionOpportunityId  = connectionRequest.ConnectionOpportunityId;
                    connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId.Value;
                    connectionRequestActivity.ConnectorPersonAliasId   = connectorPerson.PrimaryAliasId;
                    connectionRequestActivityService.Add(connectionRequestActivity);
                }

                numberOfRequestsRemaining--;
                if (numberOfRequestsRemaining <= 0)
                {
                    break;
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// creates or updates the entity set on the basis of campaign connection configuration, and returns the Id of the entitySetId
        /// </summary>
        /// <param name="campaignConfiguration">The campaign configuration.</param>
        /// <returns></returns>
        public static int GetEntitySet(CampaignItem campaignConfiguration)
        {
            var rockContext = new RockContext();

            var connectionOpportunityService = new ConnectionOpportunityService(rockContext);
            var connectionRequestService     = new ConnectionRequestService(rockContext);
            var entitySetService             = new Rock.Model.EntitySetService(rockContext);

            var connectionOpportunity = connectionOpportunityService.Get(campaignConfiguration.OpportunityGuid);

            // list of person on the basis of Dataview result and optout group.
            var filteredPersonIds = GetFilteredPersonIds(campaignConfiguration, rockContext);

            // get the last connection datetime.
            var lastConnectionDateTime = RockDateTime.Now.AddDays(-campaignConfiguration.DaysBetweenConnection);

            // if DaysBetweenConnection is 0 then check for connection request for any time period.
            if (campaignConfiguration.DaysBetweenConnection == default(int))
            {
                lastConnectionDateTime = DateTime.MinValue;
            }

            // list of person that has active connection request OR has connection closed in the past number of days between connection.
            var excludedPersonIds = connectionRequestService
                                    .Queryable()
                                    .Where(a =>
                                           a.ConnectionOpportunityId == connectionOpportunity.Id && (
                                               a.ConnectionState == ConnectionState.Active ||
                                               a.ConnectionState == ConnectionState.FutureFollowUp ||
                                               ((a.ConnectionState == ConnectionState.Connected || a.ConnectionState == ConnectionState.Inactive) && a.ModifiedDateTime > lastConnectionDateTime)))
                                    .Select(a => a.PersonAlias.PersonId)
                                    .ToList();

            // filtered list of person removing all the personIds found in excludedPersonIds List
            filteredPersonIds = filteredPersonIds.Where(a => !excludedPersonIds.Contains(a)).ToList();

            // get the ordered list of personIds based on the oldest previous connection request and connection opportunity

            /* 2020-05-06 MDP
             * If there are many filteredPersonIds, we'll get a SQL Exception, so let's get *all* the Connected connection Requests first,
             * and then use C# to filter.
             */

            var orderedLastCompletedRequestForPerson = connectionRequestService
                                                       .Queryable()
                                                       .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id &&
                                                              a.ConnectionState == ConnectionState.Connected)
                                                       .GroupBy(a => a.PersonAlias.PersonId)
                                                       .Select(a => new
            {
                PersonId = a.Key,
                LastConnectionDateTime = a.OrderByDescending(b => b.ModifiedDateTime).Select(b => b.ModifiedDateTime).FirstOrDefault()
            })
                                                       .OrderBy(a => a.LastConnectionDateTime)
                                                       .Select(a => a.PersonId).ToList();

            // Use C# to filter persons so we can avoid a SQL Exception
            orderedLastCompletedRequestForPerson = orderedLastCompletedRequestForPerson.Where(a => filteredPersonIds.Contains(a)).ToList();

            var random = new Random();

            //// get the final ordered list of personIds based on the oldest previous connection request and
            //// connection opportunity otherwise order randomly for the person who don't have any previous connection request.
            var orderedPersonIds = filteredPersonIds
                                   .OrderBy(a =>
            {
                var index = orderedLastCompletedRequestForPerson.IndexOf(a);
                if (index == -1)
                {
                    return(random.Next(orderedLastCompletedRequestForPerson.Count, int.MaxValue));
                }
                else
                {
                    return(index);
                }
            }).ToList();

            EntitySet entitySet = null;

            if (campaignConfiguration.EntitySetId != default(int))
            {
                entitySet = entitySetService.Get(campaignConfiguration.EntitySetId);
            }

            List <Rock.Model.EntitySetItem> entitySetItems = new List <Rock.Model.EntitySetItem>();
            var personEntityTypeId = EntityTypeCache.Get <Rock.Model.Person>().Id;

            if (entitySet == null || entitySet.EntityTypeId != personEntityTypeId)
            {
                entitySet = new Rock.Model.EntitySet();
                entitySet.EntityTypeId   = personEntityTypeId;
                entitySet.ExpireDateTime = null;
                entitySetService.Add(entitySet);
            }
            else
            {
                var entitySetItemQry = new EntitySetItemService(rockContext)
                                       .Queryable().AsNoTracking()
                                       .Where(i => i.EntitySetId == entitySet.Id);
                rockContext.BulkDelete(entitySetItemQry);
            }

            // Update the EntitySet name
            entitySet.Name = campaignConfiguration.Name;

            var orderIndex = 0;

            foreach (var personId in orderedPersonIds)
            {
                try
                {
                    var item = new Rock.Model.EntitySetItem();
                    item.Order    = orderIndex++;
                    item.EntityId = personId;
                    entitySetItems.Add(item);
                }
                catch
                {
                    // ignore
                }
            }

            rockContext.SaveChanges();
            entitySetItems.ForEach(a =>
            {
                a.EntitySetId = entitySet.Id;
            });

            rockContext.BulkInsert(entitySetItems);

            return(entitySet.Id);
        }
Beispiel #5
0
        /// <summary>
        /// Creates the connection requests.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="campaignItem">The campaign item.</param>
        /// <returns></returns>
        private int CreateConnectionRequests(IJobExecutionContext context, CampaignItem campaignItem)
        {
            context.UpdateLastStatusMessage($"Processing create connection requests for {campaignItem.Name}");

            // Skip creating connection requests if set to "AsNeeded" and DailyLimitAssigned is 0 or null
            if (campaignItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded &&
                (campaignItem.DailyLimitAssigned <= 0 || campaignItem.DailyLimitAssigned == null))
            {
                return(0);
            }

            int recordsProcessed = 0;

            var rockContext = new RockContext();
            var connectionOpportunityService = new ConnectionOpportunityService(rockContext);
            var personAliasService           = new PersonAliasService(rockContext);
            var entitySetItemService         = new EntitySetItemService(rockContext);

            var connectionOpportunity = connectionOpportunityService.Get(campaignItem.OpportunityGuid);

            if (connectionOpportunity == null)
            {
                return(0);
            }

            // get cutoff for the last connection datetime.
            var lastConnectionDateTime = RockDateTime.Now.AddDays(-campaignItem.DaysBetweenConnection);

            // if DaysBetweenConnection is 0 then check for connection request for any time period.
            if (campaignItem.DaysBetweenConnection == default(int))
            {
                lastConnectionDateTime = DateTime.MinValue;
            }

            var entitySetItemsQry = entitySetItemService
                                    .Queryable()
                                    .Where(a => a.EntitySetId == campaignItem.EntitySetId)
                                    .OrderBy(a => a.Order);

            bool autoAssignment     = false;
            var  eligibleConnectors = new List <ConnectionConnector>();

            if (campaignItem.DailyLimitAssigned.HasValue &&
                campaignItem.DailyLimitAssigned != default(int))
            {
                autoAssignment     = true;
                eligibleConnectors = GetEligibleConnectorWithLimit(connectionOpportunity.Id, rockContext, campaignItem.DailyLimitAssigned.Value);
            }

            var connectionStatusId = GetConnectionStatus(connectionOpportunity);

            if (!connectionStatusId.HasValue)
            {
                return(0);
            }

            var entitySetItemList = entitySetItemsQry.ToList();

            foreach (var entitySetItem in entitySetItemList)
            {
                var entityItemPersonAlias = personAliasService.GetPrimaryAlias(entitySetItem.EntityId);

                int?connectorPersonId = null;
                if (autoAssignment)
                {
                    connectorPersonId = GetConnector(campaignItem, connectionOpportunity, eligibleConnectors, entityItemPersonAlias, rockContext);

                    if (campaignItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded && !connectorPersonId.HasValue)
                    {
                        continue;
                    }
                }

                // double check that they haven't already been added
                var personAlreadyHasConnectionRequest = CampaignConnectionHelper.PersonAlreadyHasConnectionRequest(connectionOpportunity.Id, rockContext, lastConnectionDateTime, entitySetItem.EntityId);

                if (personAlreadyHasConnectionRequest)
                {
                    continue;
                }

                int?connectorPersonAliasId = null;
                if (connectorPersonId.HasValue)
                {
                    foreach (var connectionConnector in eligibleConnectors.Where(a => a.PersonId == connectorPersonId.Value))
                    {
                        connectorPersonAliasId       = connectionConnector.PersonAliasId;
                        connectionConnector.Current += 1;
                    }
                }

                CreateConnectionRequest(entityItemPersonAlias, campaignItem.RequestCommentsLavaTemplate, connectionOpportunity.Id, connectionStatusId, connectorPersonAliasId, rockContext);

                recordsProcessed += 1;
            }

            return(recordsProcessed);
        }
Beispiel #6
0
        /// <summary>
        /// Creates the connection requests.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="campaignItem">The campaign item.</param>
        /// <returns></returns>
        private int CreateConnectionRequests(IJobExecutionContext context, CampaignItem campaignItem)
        {
            context.UpdateLastStatusMessage($"Processing create connection requests for {campaignItem.Name}");

            // Skip creating connection requests if set to "AsNeeded" and DailyLimitAssigned is 0 or null
            if (campaignItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded &&
                (campaignItem.DailyLimitAssigned <= 0 || campaignItem.DailyLimitAssigned == null))
            {
                return(0);
            }

            int recordsProcessed = 0;

            var rockContext = new RockContext();
            var connectionOpportunityService = new ConnectionOpportunityService(rockContext);
            var personAliasService           = new PersonAliasService(rockContext);
            var connectionRequestService     = new ConnectionRequestService(rockContext);

            var connectionOpportunity = connectionOpportunityService.Get(campaignItem.OpportunityGuid);

            if (connectionOpportunity == null)
            {
                return(0);
            }

            // get cutoff for the last connection datetime.
            var lastConnectionDateTime = RockDateTime.Now.AddDays(-campaignItem.DaysBetweenConnection);

            // if DaysBetweenConnection is 0 then check for connection request for any time period.
            if (campaignItem.DaysBetweenConnection == default(int))
            {
                lastConnectionDateTime = DateTime.MinValue;
            }

            var entitySetItemService = new EntitySetItemService(rockContext);

            var entitySetItemsQry = entitySetItemService
                                    .Queryable()
                                    .Where(a => a.EntitySetId == campaignItem.EntitySetId)
                                    .OrderBy(a => a.Order);

            bool autoAssignment     = false;
            var  eligibleConnectors = new List <ConnectionConnector>();

            if (campaignItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded &&
                campaignItem.DailyLimitAssigned.HasValue &&
                campaignItem.DailyLimitAssigned != default(int))
            {
                autoAssignment     = true;
                eligibleConnectors = GetEligibleConnectorWithLimit(connectionOpportunity.Id, rockContext, campaignItem.DailyLimitAssigned.Value);
            }

            int?connectionStatusId = connectionOpportunity.ConnectionType.ConnectionStatuses
                                     .Where(s => s.IsDefault)
                                     .Select(s => ( int? )s.Id)
                                     .FirstOrDefault();

            // If opportunity doesn't have a default status, something is wrong
            if (connectionStatusId == null)
            {
                ExceptionLogService.LogException(new Exception($"Unable to determine default connection status for {connectionOpportunity.Name} while processing campaigns", null));
                return(0);
            }

            var dayofWeek         = RockDateTime.Now.DayOfWeek;
            var entitySetItemList = entitySetItemsQry.ToList();

            foreach (var entitySetItem in entitySetItemList)
            {
                var personAlias            = personAliasService.GetPrimaryAlias(entitySetItem.EntityId);
                var defaultCampus          = personAlias.Person.GetCampus();
                int?connectorPersonAliasId = null;
                if (autoAssignment)
                {
                    int?connectorPersonId = null;
                    if (campaignItem.PreferPreviousConnector)
                    {
                        var personIds = eligibleConnectors
                                        .Where(a => a.Limit - a.Current > 0 &&
                                               (!a.DaysOfWeek.Any() || a.DaysOfWeek.Contains(dayofWeek)) &&
                                               (!a.CampusId.HasValue || (a.CampusId.HasValue && defaultCampus != null && defaultCampus.Id == a.CampusId.Value)))
                                        .Select(a => a.PersonId)
                                        .ToList();

                        if (personIds.Any())
                        {
                            var person = connectionRequestService
                                         .Queryable()
                                         .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id &&
                                                a.PersonAlias.PersonId == personAlias.PersonId &&
                                                a.ConnectionState == ConnectionState.Connected &&
                                                a.ConnectorPersonAliasId.HasValue &&
                                                personIds.Contains(a.ConnectorPersonAlias.PersonId))
                                         .Select(a => a.ConnectorPersonAlias.Person)
                                         .FirstOrDefault();

                            if (person != null)
                            {
                                connectorPersonId = person.Id;
                            }
                        }
                    }

                    if (!connectorPersonId.HasValue)
                    {
                        var eligibleConnector = eligibleConnectors
                                                .Where(a => a.Limit - a.Current > 0 &&
                                                       (!a.DaysOfWeek.Any() || a.DaysOfWeek.Contains(dayofWeek)) &&
                                                       (!a.CampusId.HasValue || (a.CampusId.HasValue && defaultCampus != null && defaultCampus.Id == a.CampusId.Value)))
                                                .OrderBy(a => a.Current)     // order from least assigned to most assigned
                                                .ThenBy(x => Guid.NewGuid()) // and then randomize
                                                .FirstOrDefault();

                        if (eligibleConnector != null)
                        {
                            connectorPersonId = eligibleConnector.PersonId;
                        }
                    }

                    if (!connectorPersonId.HasValue)
                    {
                        continue;
                    }

                    foreach (var connectionConnector in eligibleConnectors.Where(a => a.PersonId == connectorPersonId.Value))
                    {
                        connectorPersonAliasId       = connectionConnector.PersonAliasId;
                        connectionConnector.Current += 1;
                    }
                }

                using (var insertRockContext = new RockContext())
                {
                    try
                    {
                        /*
                         *  3/30/2020 - NA
                         *
                         *  When setting the connection request's Requester, we have to use the PrimaryAlias
                         *  to set the connectionRequest.PersonAlias property because the ConnectionRequestChangeTransaction
                         *  https://github.com/SparkabilityGroup/Rock/blob/a556a9285b7fdfe5594441286242f4feaa5847f2/Rock/Transactions/ConnectionRequestChangeTransaction.cs#L123
                         *  (which handles triggered workflows) expects it.  Also, it needs to be tracked by
                         *  the current rockContext...
                         *
                         *  In other words, this will not work correctly:
                         *  PersonAliasId = personAlias.Id,
                         *
                         *  Reason: This plug-in cannot change Rock core assembly code.
                         */

                        var personPrimaryAlias = new PersonAliasService(insertRockContext).GetPrimaryAlias(entitySetItem.EntityId);
                        var connectionRequestActivityService = new ConnectionRequestActivityService(insertRockContext);
                        var insertConnectionRequestService   = new ConnectionRequestService(insertRockContext);

                        // double check that they haven't already been added
                        var personAlreadyHasConnectionRequest = CampaignConnectionHelper.PersonAlreadyHasConnectionRequest(connectionOpportunity.Id, rockContext, lastConnectionDateTime, entitySetItem.EntityId);

                        if (personAlreadyHasConnectionRequest)
                        {
                            continue;
                        }

                        var connectionRequest = new ConnectionRequest()
                        {
                            ConnectionOpportunityId = connectionOpportunity.Id,
                            PersonAlias             = personPrimaryAlias,
                            ConnectionState         = ConnectionState.Active,
                            ConnectorPersonAliasId  = connectorPersonAliasId,
                            CampusId           = defaultCampus?.Id,
                            ConnectionStatusId = connectionStatusId.Value,
                        };

                        if (campaignItem.RequestCommentsLavaTemplate.IsNotNullOrWhiteSpace())
                        {
                            var mergeFields = new Dictionary <string, object>();
                            mergeFields.Add("Person", personAlias.Person);
                            mergeFields.Add("Family", personAlias.Person.GetFamily());
                            connectionRequest.Comments = campaignItem.RequestCommentsLavaTemplate.ResolveMergeFields(mergeFields);
                        }

                        insertConnectionRequestService.Add(connectionRequest);

                        if (connectorPersonAliasId.HasValue)
                        {
                            var connectionActivityTypeAssignedGuid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid();
                            int?assignedActivityId = new ConnectionActivityTypeService(rockContext).GetId(connectionActivityTypeAssignedGuid);
                            if (assignedActivityId.HasValue)
                            {
                                var connectionRequestActivity = new ConnectionRequestActivity();
                                connectionRequestActivity.ConnectionRequest        = connectionRequest;
                                connectionRequestActivity.ConnectionOpportunityId  = connectionRequest.ConnectionOpportunityId;
                                connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId.Value;
                                connectionRequestActivity.ConnectorPersonAliasId   = connectorPersonAliasId;
                                connectionRequestActivityService.Add(connectionRequestActivity);
                            }
                        }

                        insertRockContext.SaveChanges();
                    }
                    catch (Exception ex)
                    {
                        // Log exception and keep on trucking.
                        var exception = new Exception($"Exception occurred trying to create connection request:{personAlias.Id}.", ex);
                        createConnectionRequestExceptions.Add(exception);
                        ExceptionLogService.LogException(exception, null);
                    }
                }

                recordsProcessed += 1;
            }

            return(recordsProcessed);
        }
Beispiel #7
0
        /// <summary>
        /// Binds the grid.
        /// </summary>
        private void BindGrid()
        {
            var rockContext = new RockContext();

            var campaignConnectionItems = Rock.Web.SystemSettings.GetValue(CampaignConnectionKey.CAMPAIGN_CONNECTION_CONFIGURATION).FromJsonOrNull <List <CampaignItem> >() ?? new List <CampaignItem>();

            var relatedOpportunityIds = campaignConnectionItems.Select(a => a.OpportunityGuid).ToList();
            List <ConnectionOpportunity> relatedOpportunities      = new List <ConnectionOpportunity>();
            Dictionary <Guid, int>       activeOpportunityRequests = new Dictionary <Guid, int>();

            if (relatedOpportunityIds.Any())
            {
                var connectionOpportunityService = new ConnectionOpportunityService(rockContext);
                var connectionRequestService     = new ConnectionRequestService(rockContext);
                var connectionRequestsQry        = connectionRequestService.Queryable();
                relatedOpportunities = connectionOpportunityService.GetListByGuids(relatedOpportunityIds);
                foreach (var connectionOpportunity in relatedOpportunities)
                {
                    var activeRequestCount = connectionRequestsQry
                                             .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id &&
                                                    (a.ConnectionState == ConnectionState.Active ||
                                                     (a.ConnectionState == ConnectionState.FutureFollowUp && a.FollowupDate.HasValue && a.FollowupDate.Value < _midnightToday)))
                                             .Count();

                    activeOpportunityRequests.AddOrReplace(connectionOpportunity.Guid, activeRequestCount);
                }
            }

            var             relatedDataViewIds = campaignConnectionItems.Select(a => a.DataViewGuid).ToList();
            List <DataView> relatedDataViews   = new List <DataView>();

            if (relatedDataViewIds.Any())
            {
                var dataViewService = new DataViewService(rockContext);
                relatedDataViews = dataViewService.GetListByGuids(relatedDataViewIds);
            }

            var campaignConnectionRows = new List <CampaignConnectionRow>();
            var entitySetItemQry       = new EntitySetItemService(rockContext).Queryable();

            foreach (var campaignConnectionItem in campaignConnectionItems)
            {
                var campaignConnectionRow = new CampaignConnectionRow();
                campaignConnectionRow.Guid = campaignConnectionItem.Guid;
                campaignConnectionRow.Name = campaignConnectionItem.Name;
                campaignConnectionRow.ConnectionOpportunity = relatedOpportunities.FirstOrDefault(a => a.Guid == campaignConnectionItem.OpportunityGuid);
                campaignConnectionRow.DataView           = relatedDataViews.FirstOrDefault(a => a.Guid == campaignConnectionItem.DataViewGuid);
                campaignConnectionRow.ActiveRequests     = activeOpportunityRequests.GetValueOrNull(campaignConnectionItem.OpportunityGuid) ?? 0;
                campaignConnectionRow.PendingConnections = entitySetItemQry.Where(a => a.EntitySetId == campaignConnectionItem.EntitySetId).Count();
                campaignConnectionRow.IsActive           = campaignConnectionItem.IsActive;
                campaignConnectionRows.Add(campaignConnectionRow);
            }

            var qry = campaignConnectionRows.AsQueryable();

            SortProperty sortProperty = gCampaigns.SortProperty;

            if (sortProperty != null)
            {
                qry = qry.Sort(sortProperty);
            }
            else
            {
                qry = qry.OrderBy(g => g.Name);
            }

            gCampaigns.DataSource = qry.ToList();
            gCampaigns.DataBind();
        }
        /// <summary>
        /// Gets the merge object list for the current EntitySet
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="fetchCount">The fetch count.</param>
        /// <returns></returns>
        private List <object> GetMergeObjectList(RockContext rockContext, int?fetchCount = null)
        {
            int entitySetId      = hfEntitySetId.Value.AsInteger();
            var entitySetService = new EntitySetService(rockContext);
            var entitySet        = entitySetService.Get(entitySetId);
            Dictionary <int, object> mergeObjectsDictionary = new Dictionary <int, object>();

            // If this EntitySet contains IEntity Items, add those first
            if (entitySet.EntityTypeId.HasValue)
            {
                var qryEntity = entitySetService.GetEntityQuery(entitySetId);

                if (fetchCount.HasValue)
                {
                    qryEntity = qryEntity.Take(fetchCount.Value);
                }

                var  entityTypeCache         = EntityTypeCache.Read(entitySet.EntityTypeId.Value);
                bool isPersonEntityType      = entityTypeCache != null && entityTypeCache.Guid == Rock.SystemGuid.EntityType.PERSON.AsGuid();
                bool isGroupMemberEntityType = entityTypeCache != null && entityTypeCache.Guid == Rock.SystemGuid.EntityType.GROUP_MEMBER.AsGuid();
                bool combineFamilyMembers    = cbCombineFamilyMembers.Visible && cbCombineFamilyMembers.Checked;

                if (isPersonEntityType && combineFamilyMembers)
                {
                    var  qryPersons            = qryEntity;
                    Guid familyGroupType       = Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY.AsGuid();
                    var  qryFamilyGroupMembers = new GroupMemberService(rockContext).Queryable()
                                                 .Where(a => a.Group.GroupType.Guid == familyGroupType)
                                                 .Where(a => qryPersons.Any(aa => aa.Id == a.PersonId));

                    var qryCombined = qryFamilyGroupMembers.Join(
                        qryPersons,
                        m => m.PersonId,
                        p => p.Id,
                        (m, p) => new { GroupMember = m, Person = p })
                                      .GroupBy(a => a.GroupMember.GroupId)
                                      .Select(x => new
                    {
                        GroupId = x.Key,
                        Persons = x.Select(xx => xx.Person).Distinct()
                    });

                    foreach (var combinedFamilyItem in qryCombined)
                    {
                        object mergeObject;

                        string commaPersonIds = combinedFamilyItem.Persons.Select(a => a.Id).Distinct().ToList().AsDelimited(",");

                        var primaryGroupPerson = combinedFamilyItem.Persons.FirstOrDefault() as Person;

                        if (mergeObjectsDictionary.ContainsKey(primaryGroupPerson.Id))
                        {
                            foreach (var person in combinedFamilyItem.Persons)
                            {
                                if (!mergeObjectsDictionary.ContainsKey(person.Id))
                                {
                                    primaryGroupPerson = person as Person;
                                    break;
                                }
                            }
                        }

                        if (combinedFamilyItem.Persons.Count() > 1)
                        {
                            var combinedPerson = primaryGroupPerson.ToJson().FromJsonOrNull <MergeTemplateCombinedPerson>();

                            var familyTitle = RockUdfHelper.ufnCrm_GetFamilyTitle(rockContext, null, combinedFamilyItem.GroupId, commaPersonIds, true);
                            combinedPerson.FullName = familyTitle;

                            var firstNameList = combinedFamilyItem.Persons.Select(a => (a as Person).FirstName).ToList();
                            var nickNameList  = combinedFamilyItem.Persons.Select(a => (a as Person).NickName).ToList();

                            combinedPerson.FirstName     = firstNameList.AsDelimited(", ", " & ");
                            combinedPerson.NickName      = nickNameList.AsDelimited(", ", " & ");
                            combinedPerson.LastName      = primaryGroupPerson.LastName;
                            combinedPerson.SuffixValueId = null;
                            combinedPerson.SuffixValue   = null;
                            mergeObject = combinedPerson;
                        }
                        else
                        {
                            mergeObject = primaryGroupPerson;
                        }

                        mergeObjectsDictionary.AddOrIgnore(primaryGroupPerson.Id, mergeObject);
                    }
                }
                else if (isGroupMemberEntityType)
                {
                    foreach (var groupMember in qryEntity.AsNoTracking().OfType <GroupMember>())
                    {
                        var person = groupMember.Person;
                        person.AdditionalLavaFields = new Dictionary <string, object>();

                        foreach (var item in groupMember.ToDictionary())
                        {
                            if (item.Key == "Id")
                            {
                                person.AdditionalLavaFields.AddOrIgnore("GroupMemberId", item.Value);
                            }
                            else if (item.Key == "Guid")
                            {
                                person.AdditionalLavaFields.AddOrIgnore("GroupMemberGuid", item.Value.ToStringSafe());
                            }
                            else
                            {
                                person.AdditionalLavaFields.AddOrIgnore(item.Key, item.Value);
                            }
                        }

                        mergeObjectsDictionary.AddOrIgnore(groupMember.PersonId, person);
                    }
                }
                else
                {
                    foreach (var item in qryEntity.AsNoTracking())
                    {
                        mergeObjectsDictionary.AddOrIgnore(item.Id, item);
                    }
                }
            }

            var entitySetItemService = new EntitySetItemService(rockContext);

            string[] emptyJson = new string[] { string.Empty, "{}" };
            var      entitySetItemMergeValuesQry = entitySetItemService.GetByEntitySetId(entitySetId, true).Where(a => !emptyJson.Contains(a.AdditionalMergeValuesJson));

            if (fetchCount.HasValue)
            {
                entitySetItemMergeValuesQry = entitySetItemMergeValuesQry.Take(fetchCount.Value);
            }

            // the entityId to use for NonEntity objects
            int nonEntityId = 1;

            // now, add the additional MergeValues regardless of if the EntitySet contains IEntity items or just Non-IEntity items
            foreach (var additionalMergeValuesItem in entitySetItemMergeValuesQry.AsNoTracking())
            {
                object mergeObject;
                int    entityId;
                if (additionalMergeValuesItem.EntityId > 0)
                {
                    entityId = additionalMergeValuesItem.EntityId;
                }
                else
                {
                    // not pointing to an actual EntityId, so use the nonEntityId for ti
                    entityId = nonEntityId++;
                }

                if (mergeObjectsDictionary.ContainsKey(entityId))
                {
                    mergeObject = mergeObjectsDictionary[entityId];
                }
                else
                {
                    if (entitySet.EntityTypeId.HasValue)
                    {
                        // if already have real entities in our list, don't add additional items to the mergeObjectsDictionary
                        continue;
                    }

                    // non-Entity merge object, so just use Dictionary
                    mergeObject = new Dictionary <string, object>();
                    mergeObjectsDictionary.AddOrIgnore(entityId, mergeObject);
                }

                foreach (var additionalMergeValue in additionalMergeValuesItem.AdditionalMergeValues)
                {
                    if (mergeObject is IEntity)
                    {
                        // add the additional fields to AdditionalLavaFields
                        IEntity mergeEntity = (mergeObject as IEntity);
                        mergeEntity.AdditionalLavaFields = mergeEntity.AdditionalLavaFields ?? new Dictionary <string, object>();
                        object mergeValueObject = additionalMergeValue.Value;
                        mergeEntity.AdditionalLavaFields.AddOrIgnore(additionalMergeValue.Key, mergeValueObject);
                    }
                    else if (mergeObject is IDictionary <string, object> )
                    {
                        // anonymous object with no fields yet
                        IDictionary <string, object> nonEntityObject = mergeObject as IDictionary <string, object>;
                        nonEntityObject.AddOrIgnore(additionalMergeValue.Key, additionalMergeValue.Value);
                    }
                    else
                    {
                        throw new Exception(string.Format("Unexpected MergeObject Type: {0}", mergeObject));
                    }
                }
            }

            var result = mergeObjectsDictionary.Select(a => a.Value);

            if (fetchCount.HasValue)
            {
                // make sure the result is limited to fetchCount (even though the above queries are also limited to fetch count)
                result = result.Take(fetchCount.Value);
            }

            return(result.ToList());
        }