Exemple #1
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute(RockContext rockContext, Model.WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            if (checkInState != null && checkInState.CheckIn.SearchType != null)
            {
                checkInState.CheckIn.Families = new List <CheckInFamily>();

                if (!string.IsNullOrWhiteSpace(checkInState.CheckIn.SearchValue))
                {
                    var personService = new PersonService(rockContext);
                    var memberService = new GroupMemberService(rockContext);
                    var groupService  = new GroupService(rockContext);

                    int personRecordTypeId = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.PERSON_RECORD_TYPE_PERSON.AsGuid()).Id;
                    int familyGroupTypeId  = GroupTypeCache.Get(Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY.AsGuid()).Id;
                    var dvInactive         = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE.AsGuid());

                    IQueryable <int> familyIdQry = null;

                    if (checkInState.CheckIn.SearchType.Guid.Equals(SystemGuid.DefinedValue.CHECKIN_SEARCH_TYPE_PHONE_NUMBER.AsGuid()))
                    {
                        string numericPhone = checkInState.CheckIn.SearchValue.AsNumeric();

                        var phoneQry = new PhoneNumberService(rockContext).Queryable().AsNoTracking();
                        if (checkInState.CheckInType == null || checkInState.CheckInType.PhoneSearchType == PhoneSearchType.EndsWith)
                        {
                            char[] charArray = numericPhone.ToCharArray();
                            Array.Reverse(charArray);
                            phoneQry = phoneQry.Where(o =>
                                                      o.NumberReversed.StartsWith(new string( charArray )));
                        }
                        else
                        {
                            phoneQry = phoneQry.Where(o =>
                                                      o.Number.Contains(numericPhone));
                        }

                        var tmpQry = phoneQry.Join(personService.Queryable().AsNoTracking(),
                                                   o => new { PersonId = o.PersonId, IsDeceased = false, RecordTypeValueId = personRecordTypeId },
                                                   p => new { PersonId = p.Id, IsDeceased = p.IsDeceased, RecordTypeValueId = p.RecordTypeValueId.Value },
                                                   (pn, p) => new { Person = p, PhoneNumber = pn })
                                     .Join(memberService.Queryable().AsNoTracking(),
                                           pn => pn.Person.Id,
                                           m => m.PersonId,
                                           (o, m) => new { PersonNumber = o.PhoneNumber, GroupMember = m });

                        familyIdQry = groupService.Queryable().Where(g => tmpQry.Any(o => o.GroupMember.GroupId == g.Id) && g.GroupTypeId == familyGroupTypeId)
                                      .Select(g => g.Id)
                                      .Distinct();
                    }
                    else
                    {
                        var familyMemberQry = memberService
                                              .AsNoFilter().AsNoTracking()
                                              .Where(m =>
                                                     m.Group.GroupTypeId == familyGroupTypeId &&
                                                     m.Person.RecordTypeValueId == personRecordTypeId);

                        if (checkInState.CheckIn.SearchType.Guid.Equals(SystemGuid.DefinedValue.CHECKIN_SEARCH_TYPE_NAME.AsGuid()))
                        {
                            var personIds = personService.GetByFullName(checkInState.CheckIn.SearchValue, false).AsNoTracking().Select(p => p.Id);
                            familyMemberQry = familyMemberQry.Where(f => personIds.Contains(f.PersonId));
                        }
                        else if (checkInState.CheckIn.SearchType.Guid.Equals(SystemGuid.DefinedValue.CHECKIN_SEARCH_TYPE_SCANNED_ID.AsGuid()))
                        {
                            var personIds = new List <int>();

                            var dv = DefinedValueCache.Get(SystemGuid.DefinedValue.PERSON_SEARCH_KEYS_ALTERNATE_ID.AsGuid());
                            if (dv != null)
                            {
                                var searchValueService = new PersonSearchKeyService(rockContext);
                                var personAliases      = searchValueService.Queryable().AsNoTracking()
                                                         .Where(v =>
                                                                v.SearchTypeValueId == dv.Id &&
                                                                v.SearchValue == checkInState.CheckIn.SearchValue)
                                                         .Select(v => v.PersonAlias);

                                if (personAliases.Any())
                                {
                                    checkInState.CheckIn.CheckedInByPersonAliasId = personAliases.First().Id;
                                    personIds = personAliases.Select(a => a.PersonId).ToList();
                                }
                            }

                            if (personIds.Any())
                            {
                                familyMemberQry = familyMemberQry.Where(f => personIds.Contains(f.PersonId));
                            }
                            else
                            {
                                // if there were no matches, try to find a family check-in identifier. V8 has a "run once" job that moves the family identifiers
                                // to person search values, but in case the job has not yet completed, will still do the check for family ids.
                                var entityIds = new List <int>();

                                var attributeValueService = new AttributeValueService(rockContext);
                                var attr = AttributeCache.Get("8F528431-A438-4488-8DC3-CA42E66C1B37".AsGuid());
                                if (attr != null)
                                {
                                    entityIds = new AttributeValueService(rockContext)
                                                .Queryable().AsNoTracking()
                                                .Where(v =>
                                                       v.AttributeId == attr.Id &&
                                                       v.EntityId.HasValue &&
                                                       ("|" + v.Value + "|").Contains("|" + checkInState.CheckIn.SearchValue + "|"))
                                                .Select(v => v.EntityId.Value)
                                                .ToList();
                                }

                                familyMemberQry = familyMemberQry.Where(f => entityIds.Contains(f.GroupId));
                            }
                        }
                        else if (checkInState.CheckIn.SearchType.Guid.Equals(SystemGuid.DefinedValue.CHECKIN_SEARCH_TYPE_FAMILY_ID.AsGuid()))
                        {
                            List <int> searchFamilyIds = checkInState.CheckIn.SearchValue.SplitDelimitedValues().AsIntegerList();
                            familyMemberQry = familyMemberQry.Where(f => searchFamilyIds.Contains(f.GroupId));
                        }
                        else
                        {
                            errorMessages.Add("Invalid Search Type");
                            return(false);
                        }

                        familyIdQry = familyMemberQry
                                      .Select(m => m.GroupId)
                                      .Distinct();
                    }

                    int maxResults = checkInState.CheckInType != null ? checkInState.CheckInType.MaxSearchResults : 100;
                    if (maxResults > 0)
                    {
                        familyIdQry = familyIdQry.Take(maxResults);
                    }

                    // You might think we should do a ToList() on the familyIdQry and use it below,
                    // but through some extensive testing, we discovered that the next SQL query is better
                    // optimized if it has the familyIdQry without being to-listed.  It was over 270% slower
                    // when querying names and 120% slower when querying phone numbers.

                    // Load the family members
                    var familyMembers = memberService
                                        .Queryable().AsNoTracking()
                                        .Where(m => m.Group.GroupTypeId == familyGroupTypeId && familyIdQry.Contains(m.GroupId)).Select(a =>
                                                                                                                                        new {
                        Group               = a.Group,
                        GroupId             = a.GroupId,
                        Order               = a.GroupRole.Order,
                        BirthYear           = a.Person.BirthYear,
                        BirthMonth          = a.Person.BirthMonth,
                        BirthDay            = a.Person.BirthDay,
                        Gender              = a.Person.Gender,
                        NickName            = a.Person.NickName,
                        RecordStatusValueId = a.Person.RecordStatusValueId
                    })
                                        .ToList();

                    // Add each family
                    foreach (int familyId in familyMembers.Select(fm => fm.GroupId).Distinct())
                    {
                        // Get each of the members for this family
                        var familyMemberQry = familyMembers
                                              .Where(m =>
                                                     m.GroupId == familyId &&
                                                     m.NickName != null);

                        if (checkInState.CheckInType != null && checkInState.CheckInType.PreventInactivePeople && dvInactive != null)
                        {
                            familyMemberQry = familyMemberQry
                                              .Where(m =>
                                                     m.RecordStatusValueId != dvInactive.Id);
                        }

                        var thisFamilyMembers = familyMemberQry.ToList();

                        if (thisFamilyMembers.Any())
                        {
                            var group = thisFamilyMembers
                                        .Select(m => m.Group)
                                        .FirstOrDefault();

                            var firstNames = thisFamilyMembers
                                             .OrderBy(m => m.Order)
                                             .ThenBy(m => m.BirthYear)
                                             .ThenBy(m => m.BirthMonth)
                                             .ThenBy(m => m.BirthDay)
                                             .ThenBy(m => m.Gender)
                                             .Select(m => m.NickName)
                                             .ToList();

                            var family = new CheckInFamily();
                            family.Group      = group.Clone(false);
                            family.Caption    = group.ToString();
                            family.FirstNames = firstNames;
                            family.SubCaption = firstNames.AsDelimited(", ");
                            checkInState.CheckIn.Families.Add(family);
                        }
                    }
                }

                return(true);
            }

            errorMessages.Add("Invalid Check-in State");
            return(false);
        }
        /// <summary>
        /// Updates GroupMemberHistorical for any group members in groups that have data group history enabled
        /// </summary>
        /// <param name="context">The context.</param>
        public void UpdateGroupMemberHistorical(IJobExecutionContext context)
        {
            var rockContext = new RockContext();
            var groupMemberHistoricalService = new GroupMemberHistoricalService(rockContext);
            var groupMemberService           = new GroupMemberService(rockContext);

            var groupMembersWithHistoryEnabledQuery = groupMemberService.AsNoFilter().Where(a => a.Group.GroupType.EnableGroupHistory == true).AsNoTracking();
            var groupMemberHistoricalsCurrentQuery  = groupMemberHistoricalService.Queryable().Where(a => a.CurrentRowIndicator == true).AsNoTracking();

            // Mark GroupMemberHistorical Rows as History ( CurrentRowIndicator = false, etc ) if any of the tracked field values change
            var groupMemberHistoricalNoLongerCurrent = groupMemberHistoricalsCurrentQuery.Join(
                groupMembersWithHistoryEnabledQuery,
                gmh => gmh.GroupMemberId,
                gm => gm.Id, (gmh, gm) => new
            {
                GroupMember           = gm,
                GroupMemberHistorical = gmh
            })
                                                       .Where(a =>
                                                              a.GroupMember.GroupRoleId != a.GroupMemberHistorical.GroupRoleId ||
                                                              a.GroupMember.GroupId != a.GroupMemberHistorical.GroupId ||
                                                              a.GroupMember.GroupRole.Name != a.GroupMemberHistorical.GroupRoleName ||
                                                              a.GroupMember.GroupRole.IsLeader != a.GroupMemberHistorical.IsLeader ||
                                                              a.GroupMember.GroupMemberStatus != a.GroupMemberHistorical.GroupMemberStatus ||
                                                              a.GroupMember.IsArchived != a.GroupMemberHistorical.IsArchived ||
                                                              a.GroupMember.ArchivedDateTime != a.GroupMemberHistorical.ArchivedDateTime ||
                                                              a.GroupMember.ArchivedByPersonAliasId != a.GroupMemberHistorical.ArchivedByPersonAliasId ||
                                                              a.GroupMember.InactiveDateTime != a.GroupMemberHistorical.InactiveDateTime
                                                              ).Select(a => a.GroupMemberHistorical).AsNoTracking();

            var effectiveExpireDateTime = RockDateTime.Now;

            int groupMembersLoggedToHistory      = 0;
            int groupMembersSaveToHistoryCurrent = 0;

            if (groupMemberHistoricalNoLongerCurrent.Any())
            {
                groupMembersLoggedToHistory = rockContext.BulkUpdate(groupMemberHistoricalNoLongerCurrent, gmh => new GroupMemberHistorical
                {
                    CurrentRowIndicator = false,
                    ExpireDateTime      = effectiveExpireDateTime
                });
            }

            // Insert Group Members (that have a group with GroupType.EnableGroupHistory) that don't have a CurrentRowIndicator row yet ( or don't have a CurrentRowIndicator because it was stamped with CurrentRowIndicator=false )
            var groupMembersToAddToHistoricalCurrentsQuery = groupMembersWithHistoryEnabledQuery.Where(gm => !groupMemberHistoricalsCurrentQuery.Any(gmh => gmh.GroupMemberId == gm.Id));

            if (groupMembersToAddToHistoricalCurrentsQuery.Any())
            {
                List <GroupMemberHistorical> groupMemberHistoricalCurrentsToInsert = groupMembersToAddToHistoricalCurrentsQuery
                                                                                     .Include(a => a.GroupRole)
                                                                                     .ToList()
                                                                                     .Select(gm => GroupMemberHistorical.CreateCurrentRowFromGroupMember(gm, effectiveExpireDateTime)).ToList();

                groupMembersSaveToHistoryCurrent = groupMemberHistoricalCurrentsToInsert.Count();

                rockContext.BulkInsert(groupMemberHistoricalCurrentsToInsert);
            }

            if (groupMembersLoggedToHistory > 0)
            {
                _jobStatusMessages.Add($"Logged {groupMembersLoggedToHistory} {"group member history snapshot".PluralizeIf( groupMembersLoggedToHistory != 0 )}");
            }

            if (groupMembersSaveToHistoryCurrent > 0)
            {
                int newGroupMembersAddedToHistory = groupMembersSaveToHistoryCurrent - groupMembersLoggedToHistory;
                if (newGroupMembersAddedToHistory > 0)
                {
                    _jobStatusMessages.Add($"Added {newGroupMembersAddedToHistory} new {"group member history snapshot".PluralizeIf( newGroupMembersAddedToHistory != 0 )}");
                }
            }
        }
        /// <summary>
        /// Binds the members grid.
        /// </summary>
        public void BindMembersGrid()
        {
            int groupId            = hfGroupId.Value.AsInteger();
            var rockContext        = new RockContext();
            var groupMemberService = new GroupMemberService(rockContext);
            var groupService       = new GroupService(rockContext);
            var group = groupService.Get(groupId);

            if (group != null)
            {
                lGroupTitle.Text = group.Name.FormatAsHtmlTitle();
            }

            lGroupGridTitle.Visible     = true;
            lGroupMemberPreHtml.Visible = false;
            lGroupMemberTitle.Visible   = false;

            // get the unfiltered list of group members, which includes archived and deceased
            var qryGroupMembers = groupMemberService.AsNoFilter().Where(a => a.GroupId == groupId);

            // don't include deceased
            qryGroupMembers = qryGroupMembers.Where(a => a.Person.IsDeceased == false);

            // Filter by First Name
            string firstName = tbFirstName.Text;

            if (!string.IsNullOrWhiteSpace(firstName))
            {
                qryGroupMembers = qryGroupMembers.Where(m =>
                                                        m.Person.FirstName.StartsWith(firstName) ||
                                                        m.Person.NickName.StartsWith(firstName));
            }

            // Filter by Last Name
            string lastName = tbLastName.Text;

            if (!string.IsNullOrWhiteSpace(lastName))
            {
                qryGroupMembers = qryGroupMembers.Where(m => m.Person.LastName.StartsWith(lastName));
            }

            // Filter by Date Added
            var dateAddedRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues(sdrDateAdded.DelimitedValues);

            if (dateAddedRange.Start.HasValue)
            {
                qryGroupMembers = qryGroupMembers.Where(a => a.DateTimeAdded >= dateAddedRange.Start.Value);
            }
            if (dateAddedRange.End.HasValue)
            {
                qryGroupMembers = qryGroupMembers.Where(a => a.DateTimeAdded < dateAddedRange.End.Value);
            }

            var dateRemovedRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues(sdrDateRemoved.DelimitedValues);

            if (dateRemovedRange.Start.HasValue)
            {
                qryGroupMembers = qryGroupMembers.Where(a => a.ArchivedDateTime >= dateRemovedRange.Start.Value);
            }
            if (dateRemovedRange.End.HasValue)
            {
                qryGroupMembers = qryGroupMembers.Where(a => a.ArchivedDateTime < dateRemovedRange.End.Value);
            }

            // Filter by role
            var roles = cblRole.SelectedValues.AsIntegerList();

            if (roles.Any())
            {
                qryGroupMembers = qryGroupMembers.Where(m => roles.Contains(m.GroupRoleId));
            }

            // Filter by Group Member Status
            var statuses = cblGroupMemberStatus.SelectedValues.Select(a => a.ConvertToEnumOrNull <GroupMemberStatus>()).Where(a => a.HasValue).Select(a => a.Value).ToList();

            if (statuses.Any())
            {
                qryGroupMembers = qryGroupMembers.Where(m => statuses.Contains(m.GroupMemberStatus));
            }

            var sortProperty = gGroupMembers.SortProperty;

            if (sortProperty != null)
            {
                qryGroupMembers = qryGroupMembers.Sort(sortProperty);
            }
            else
            {
                qryGroupMembers = qryGroupMembers.OrderBy(a => a.GroupRole.Order).ThenBy(a => a.Person.LastName).ThenBy(a => a.Person.FirstName);
            }

            qryGroupMembers = qryGroupMembers.Include(a => a.Person);

            gGroupMembers.SetLinqDataSource(qryGroupMembers);
            gGroupMembers.DataBind();
        }