/// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            var rockContext                   = new RockContext();
            var groupRequirementService       = new GroupRequirementService(rockContext);
            var groupMemberRequirementService = new GroupMemberRequirementService(rockContext);
            var groupMemberService            = new GroupMemberService(rockContext);

            // we only need to consider group requirements that are based on a DataView or SQL
            var groupRequirementQry = groupRequirementService.Queryable()
                                      .Where(a => a.GroupRequirementType.RequirementCheckType != RequirementCheckType.Manual)
                                      .AsNoTracking();

            var calculationExceptions = new List <Exception>();
            int groupRequirementsCalculatedMemberCount = 0;

            foreach (var groupRequirement in groupRequirementQry.Include(i => i.GroupRequirementType).AsNoTracking().ToList())
            {
                try
                {
                    var currentDateTime = RockDateTime.Now;
                    var qryGroupMemberRequirementsAlreadyOK = groupMemberRequirementService.Queryable().Where(a => a.GroupRequirementId == groupRequirement.Id);

                    if (groupRequirement.GroupRequirementType.CanExpire && groupRequirement.GroupRequirementType.ExpireInDays.HasValue)
                    {
                        // Expirable: don't recalculate members that already met the requirement within the expiredays (unless they are flagged with a warning)
                        var expireDaysCount = groupRequirement.GroupRequirementType.ExpireInDays.Value;
                        qryGroupMemberRequirementsAlreadyOK = qryGroupMemberRequirementsAlreadyOK.Where(a => !a.RequirementWarningDateTime.HasValue && a.RequirementMetDateTime.HasValue && SqlFunctions.DateDiff("day", a.RequirementMetDateTime, currentDateTime) < expireDaysCount);
                    }
                    else
                    {
                        // No Expiration: don't recalculate members that already met the requirement
                        qryGroupMemberRequirementsAlreadyOK = qryGroupMemberRequirementsAlreadyOK.Where(a => a.RequirementMetDateTime.HasValue);
                    }

                    var groupMemberQry = groupMemberService.Queryable().Where(a => a.GroupId == groupRequirement.GroupId).AsNoTracking();
                    var personQry      = groupMemberQry.Where(a => !qryGroupMemberRequirementsAlreadyOK.Any(r => r.GroupMemberId == a.Id)).Select(a => a.Person);

                    var results = groupRequirement.PersonQueryableMeetsGroupRequirement(rockContext, personQry, groupRequirement.GroupRoleId).ToList();
                    groupRequirementsCalculatedMemberCount += results.Select(a => a.PersonId).Distinct().Count();
                    foreach (var result in results)
                    {
                        // use a fresh rockContext per Update so that ChangeTracker doesn't get bogged down
                        var rockContextUpdate = new RockContext();
                        groupRequirement.UpdateGroupMemberRequirementResult(rockContextUpdate, result.PersonId, result.MeetsGroupRequirement);
                        rockContextUpdate.SaveChanges();
                    }
                }
                catch (Exception ex)
                {
                    calculationExceptions.Add(new Exception(string.Format("Exception when calculating group requirement: {0} ", groupRequirement), ex));
                }
            }

            context.Result = string.Format("Group member requirements re-calculated for {0} group members", groupRequirementsCalculatedMemberCount);

            if (calculationExceptions.Any())
            {
                throw new AggregateException("One or more group requirement calculations failed ", calculationExceptions);
            }
        }
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute( IJobExecutionContext context )
        {
            var rockContext = new RockContext();
            var groupRequirementService = new GroupRequirementService( rockContext );
            var groupMemberRequirementService = new GroupMemberRequirementService( rockContext );
            var groupMemberService = new GroupMemberService( rockContext );

            // we only need to consider group requirements that are based on a DataView or SQL
            var groupRequirementQry = groupRequirementService.Queryable()
                .Where( a => a.GroupRequirementType.RequirementCheckType != RequirementCheckType.Manual )
                .AsNoTracking();

            var calculationExceptions = new List<Exception>();
            int groupRequirementsCalculatedMemberCount = 0;

            foreach ( var groupRequirement in groupRequirementQry.Include( i => i.GroupRequirementType ).AsNoTracking().ToList() )
            {
                try
                {
                    var currentDateTime = RockDateTime.Now;
                    var qryGroupMemberRequirementsAlreadyOK = groupMemberRequirementService.Queryable().Where( a => a.GroupRequirementId == groupRequirement.Id );

                    if ( groupRequirement.GroupRequirementType.CanExpire && groupRequirement.GroupRequirementType.ExpireInDays.HasValue )
                    {
                        // Expirable: don't recalculate members that already met the requirement within the expiredays (unless they are flagged with a warning)
                        var expireDaysCount = groupRequirement.GroupRequirementType.ExpireInDays.Value;
                        qryGroupMemberRequirementsAlreadyOK = qryGroupMemberRequirementsAlreadyOK.Where( a => !a.RequirementWarningDateTime.HasValue && a.RequirementMetDateTime.HasValue && SqlFunctions.DateDiff( "day", a.RequirementMetDateTime, currentDateTime ) < expireDaysCount );
                    }
                    else
                    {
                        // No Expiration: don't recalculate members that already met the requirement
                        qryGroupMemberRequirementsAlreadyOK = qryGroupMemberRequirementsAlreadyOK.Where( a => a.RequirementMetDateTime.HasValue );
                    }

                    var groupMemberQry = groupMemberService.Queryable().Where( a => a.GroupId == groupRequirement.GroupId ).AsNoTracking();
                    var personQry = groupMemberQry.Where( a => !qryGroupMemberRequirementsAlreadyOK.Any( r => r.GroupMemberId == a.Id ) ).Select( a => a.Person );

                    var results = groupRequirement.PersonQueryableMeetsGroupRequirement( rockContext, personQry, groupRequirement.GroupRoleId ).ToList();
                    groupRequirementsCalculatedMemberCount += results.Select( a => a.PersonId ).Distinct().Count();
                    foreach ( var result in results )
                    {
                        // use a fresh rockContext per Update so that ChangeTracker doesn't get bogged down
                        var rockContextUpdate = new RockContext();
                        groupRequirement.UpdateGroupMemberRequirementResult( rockContextUpdate, result.PersonId, result.MeetsGroupRequirement );
                        rockContextUpdate.SaveChanges();
                    }
                }
                catch ( Exception ex )
                {
                    calculationExceptions.Add( new Exception( string.Format( "Exception when calculating group requirement: {0} ", groupRequirement ), ex ) );
                }
            }

            context.Result = string.Format( "Group member requirements re-calculated for {0} group members", groupRequirementsCalculatedMemberCount );

            if ( calculationExceptions.Any() )
            {
                throw new AggregateException( "One or more group requirement calculations failed ", calculationExceptions );
            }
        }
示例#3
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            var errors      = new List <string>();
            var rockContext = new RockContext();

            JobDataMap dataMap         = context.JobDetail.JobDataMap;
            Guid?      systemEmailGuid = dataMap.GetString("NotificationEmailTemplate").AsGuidOrNull();

            if (systemEmailGuid.HasValue)
            {
                var selectedGroupTypes = new List <Guid>();
                if (!string.IsNullOrWhiteSpace(dataMap.GetString("GroupTypes")))
                {
                    selectedGroupTypes = dataMap.GetString("GroupTypes").Split(',').Select(Guid.Parse).ToList();
                }

                var notificationOption = dataMap.GetString("NotifyParentLeaders").ConvertToEnum <NotificationOption>(NotificationOption.None);

                var accountAbilityGroupGuid = dataMap.GetString("AccountabilityGroup").AsGuid();

                var groupRequirementsQry = new GroupRequirementService(rockContext).Queryable();


                // get groups matching of the types provided
                GroupService groupService = new GroupService(rockContext);
                var          groups       = groupService.Queryable().AsNoTracking()
                                            .Where(g => selectedGroupTypes.Contains(g.GroupType.Guid) &&
                                                   g.IsActive == true &&
                                                   groupRequirementsQry.Any(a => (a.GroupId.HasValue && a.GroupId == g.Id) || (a.GroupTypeId.HasValue && a.GroupTypeId == g.GroupTypeId)));

                foreach (var group in groups)
                {
                    // check for members that don't meet requirements
                    var groupMembersWithIssues = groupService.GroupMembersNotMeetingRequirements(group, true);

                    if (groupMembersWithIssues.Count > 0)
                    {
                        // add issues to issue list
                        GroupsMissingRequirements groupMissingRequirements = new GroupsMissingRequirements();
                        groupMissingRequirements.Id   = group.Id;
                        groupMissingRequirements.Name = group.Name;
                        if (group.GroupType != null)
                        {
                            groupMissingRequirements.GroupTypeId   = group.GroupTypeId;
                            groupMissingRequirements.GroupTypeName = group.GroupType.Name;
                        }
                        groupMissingRequirements.AncestorPathName = groupService.GroupAncestorPathName(group.Id);

                        // get list of the group leaders
                        groupMissingRequirements.Leaders = group.Members
                                                           .Where(m => m.GroupRole.ReceiveRequirementsNotifications)
                                                           .Select(m => new GroupMemberResult
                        {
                            Id       = m.Id,
                            PersonId = m.PersonId,
                            FullName = m.Person.FullName
                        })
                                                           .ToList();


                        List <GroupMembersMissingRequirements> groupMembers = new List <GroupMembersMissingRequirements>();

                        foreach (var groupMemberIssue in groupMembersWithIssues)
                        {
                            GroupMembersMissingRequirements groupMember = new GroupMembersMissingRequirements();
                            groupMember.FullName        = groupMemberIssue.Key.Person.FullName;
                            groupMember.Id              = groupMemberIssue.Key.Id;
                            groupMember.PersonId        = groupMemberIssue.Key.PersonId;
                            groupMember.GroupMemberRole = groupMemberIssue.Key.GroupRole.Name;

                            List <MissingRequirement> missingRequirements = new List <MissingRequirement>();
                            foreach (var issue in groupMemberIssue.Value)
                            {
                                MissingRequirement missingRequirement = new MissingRequirement();
                                missingRequirement.Id             = issue.Key.GroupRequirement.GroupRequirementType.Id;
                                missingRequirement.Name           = issue.Key.GroupRequirement.GroupRequirementType.Name;
                                missingRequirement.Status         = issue.Key.MeetsGroupRequirement;
                                missingRequirement.OccurrenceDate = issue.Value;

                                switch (issue.Key.MeetsGroupRequirement)
                                {
                                case MeetsGroupRequirement.Meets:
                                    missingRequirement.Message = issue.Key.GroupRequirement.GroupRequirementType.PositiveLabel;
                                    break;

                                case MeetsGroupRequirement.MeetsWithWarning:
                                    missingRequirement.Message = issue.Key.GroupRequirement.GroupRequirementType.WarningLabel;
                                    break;

                                case MeetsGroupRequirement.NotMet:
                                    missingRequirement.Message = issue.Key.GroupRequirement.GroupRequirementType.NegativeLabel;
                                    break;
                                }

                                missingRequirements.Add(missingRequirement);
                            }

                            groupMember.MissingRequirements = missingRequirements;

                            groupMembers.Add(groupMember);
                        }
                        groupMissingRequirements.GroupMembersMissingRequirements = groupMembers;

                        _groupsMissingRequriements.Add(groupMissingRequirements);

                        // add leaders as people to notify
                        foreach (var leader in group.Members.Where(m => m.GroupRole.ReceiveRequirementsNotifications))
                        {
                            NotificationItem notification = new NotificationItem();
                            notification.GroupId = group.Id;
                            notification.Person  = leader.Person;
                            _notificationList.Add(notification);
                        }

                        // notify parents
                        if (notificationOption != NotificationOption.None)
                        {
                            var parentLeaders = new GroupMemberService(rockContext).Queryable("Person").AsNoTracking()
                                                .Where(m => m.GroupRole.ReceiveRequirementsNotifications);

                            if (notificationOption == NotificationOption.DirectParent)
                            {
                                // just the parent group
                                parentLeaders = parentLeaders.Where(m => m.GroupId == group.ParentGroupId);
                            }
                            else
                            {
                                // all parents in the hierarchy
                                var parentIds = groupService.GetAllAncestorIds(group.Id);
                                parentLeaders = parentLeaders.Where(m => parentIds.Contains(m.GroupId));
                            }

                            foreach (var parentLeader in parentLeaders.ToList())
                            {
                                NotificationItem parentNotification = new NotificationItem();
                                parentNotification.Person  = parentLeader.Person;
                                parentNotification.GroupId = group.Id;
                                _notificationList.Add(parentNotification);
                            }
                        }
                    }
                }

                // send out notifications
                int recipients             = 0;
                var notificationRecipients = _notificationList.GroupBy(p => p.Person.Id).ToList();
                foreach (var recipientId in notificationRecipients)
                {
                    var recipient = _notificationList.Where(n => n.Person.Id == recipientId.Key).Select(n => n.Person).FirstOrDefault();

                    if (!recipient.IsEmailActive || recipient.Email.IsNullOrWhiteSpace() || recipient.EmailPreference == EmailPreference.DoNotEmail)
                    {
                        continue;
                    }

                    var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null);
                    mergeFields.Add("Person", recipient);
                    var notificationGroupIds = _notificationList
                                               .Where(n => n.Person.Id == recipient.Id)
                                               .Select(n => n.GroupId)
                                               .ToList();
                    var missingRequirements = _groupsMissingRequriements.Where(g => notificationGroupIds.Contains(g.Id)).ToList();
                    mergeFields.Add("GroupsMissingRequirements", missingRequirements);

                    var emailMessage = new RockEmailMessage(systemEmailGuid.Value);
                    emailMessage.AddRecipient(new RecipientData(recipient.Email, mergeFields));
                    var emailErrors = new List <string>();
                    emailMessage.Send(out emailErrors);
                    errors.AddRange(emailErrors);

                    recipients++;
                }

                // add accountability group members
                if (!accountAbilityGroupGuid.IsEmpty())
                {
                    var accountabilityGroupMembers = new GroupMemberService(rockContext).Queryable().AsNoTracking()
                                                     .Where(m => m.Group.Guid == accountAbilityGroupGuid)
                                                     .Select(m => m.Person);

                    var emailMessage = new RockEmailMessage(systemEmailGuid.Value);
                    foreach (var person in accountabilityGroupMembers)
                    {
                        var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null);
                        mergeFields.Add("Person", person);
                        mergeFields.Add("GroupsMissingRequirements", _groupsMissingRequriements);
                        emailMessage.AddRecipient(new RecipientData(person.Email, mergeFields));
                        recipients++;
                    }
                    var emailErrors = new List <string>();
                    emailMessage.Send(out emailErrors);
                    errors.AddRange(emailErrors);
                }

                context.Result = string.Format("{0} requirement notification {1} sent", recipients, "email".PluralizeIf(recipients != 1));

                if (errors.Any())
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine();
                    sb.Append(string.Format("{0} Errors: ", errors.Count()));
                    errors.ForEach(e => { sb.AppendLine(); sb.Append(e); });
                    string errorMessage = sb.ToString();
                    context.Result += errorMessage;
                    var         exception = new Exception(errorMessage);
                    HttpContext context2  = HttpContext.Current;
                    ExceptionLogService.LogException(exception, context2);
                    throw exception;
                }
            }
            else
            {
                context.Result = "Warning: No NotificationEmailTemplate found";
            }
        }
示例#4
0
        /// <summary>
        /// Binds the group members grid.
        /// </summary>
        protected void BindGroupMembersGrid()
        {
            if ( _group != null )
            {
                pnlGroupMembers.Visible = true;

                lHeading.Text = string.Format( "{0} {1}", _group.GroupType.GroupTerm, _group.GroupType.GroupMemberTerm.Pluralize() );

                if ( _group.GroupType.Roles.Any() )
                {
                    nbRoleWarning.Visible = false;
                    rFilter.Visible = true;
                    gGroupMembers.Visible = true;

                    var rockContext = new RockContext();

                    GroupMemberService groupMemberService = new GroupMemberService( rockContext );
                    var qry = groupMemberService.Queryable( "Person,GroupRole", true ).AsNoTracking()
                        .Where( m => m.GroupId == _group.Id );

                    // Filter by First Name
                    string firstName = tbFirstName.Text;
                    if ( !string.IsNullOrWhiteSpace( firstName ) )
                    {
                        qry = qry.Where( m => m.Person.FirstName.StartsWith( firstName ) );
                    }

                    // Filter by Last Name
                    string lastName = tbLastName.Text;
                    if ( !string.IsNullOrWhiteSpace( lastName ) )
                    {
                        qry = qry.Where( m => m.Person.LastName.StartsWith( lastName ) );
                    }

                    // Filter by role
                    var validGroupTypeRoles = _group.GroupType.Roles.Select( r => r.Id ).ToList();
                    var roles = new List<int>();
                    foreach ( string role in cblRole.SelectedValues )
                    {
                        if ( !string.IsNullOrWhiteSpace( role ) )
                        {
                            int roleId = int.MinValue;
                            if ( int.TryParse( role, out roleId ) && validGroupTypeRoles.Contains( roleId ) )
                            {
                                roles.Add( roleId );
                            }
                        }
                    }

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

                    // Filter by Status
                    var statuses = new List<GroupMemberStatus>();
                    foreach ( string status in cblStatus.SelectedValues )
                    {
                        if ( !string.IsNullOrWhiteSpace( status ) )
                        {
                            statuses.Add( status.ConvertToEnum<GroupMemberStatus>() );
                        }
                    }

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

                    // Filter query by any configured attribute filters
                    if ( AvailableAttributes != null && AvailableAttributes.Any() )
                    {
                        var attributeValueService = new AttributeValueService( rockContext );
                        var parameterExpression = attributeValueService.ParameterExpression;

                        foreach ( var attribute in AvailableAttributes )
                        {
                            var filterControl = phAttributeFilters.FindControl( "filter_" + attribute.Id.ToString() );
                            if ( filterControl != null )
                            {
                                var filterValues = attribute.FieldType.Field.GetFilterValues( filterControl, attribute.QualifierValues, Rock.Reporting.FilterMode.SimpleFilter );
                                var expression = attribute.FieldType.Field.AttributeFilterExpression( attribute.QualifierValues, filterValues, parameterExpression );
                                if ( expression != null )
                                {
                                    var attributeValues = attributeValueService
                                        .Queryable()
                                        .Where( v => v.Attribute.Id == attribute.Id );

                                    attributeValues = attributeValues.Where( parameterExpression, expression, null );

                                    qry = qry.Where( w => attributeValues.Select( v => v.EntityId ).Contains( w.Id ) );
                                }
                            }
                        }
                    }

                    _inactiveStatus = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE );

                    SortProperty sortProperty = gGroupMembers.SortProperty;

                    bool hasGroupRequirements = new GroupRequirementService( rockContext ).Queryable().Where( a => a.GroupId == _group.Id ).Any();

                    // If there are group requirements that that member doesn't meet, show an icon in the grid
                    bool includeWarnings = false;
                    var groupMemberIdsThatLackGroupRequirements = new GroupService( rockContext ).GroupMembersNotMeetingRequirements( _group.Id, includeWarnings ).Select( a => a.Key.Id );

                    List<GroupMember> groupMembersList = null;

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

                    // Since we're not binding to actual group member list, but are using AttributeField columns,
                    // we need to save the workflows into the grid's object list
                    gGroupMembers.ObjectList = new Dictionary<string, object>();
                    groupMembersList.ForEach( m => gGroupMembers.ObjectList.Add( m.Id.ToString(), m ) );
                    gGroupMembers.EntityTypeId = EntityTypeCache.Read( Rock.SystemGuid.EntityType.GROUP_MEMBER.AsGuid() ).Id;

                    gGroupMembers.DataSource = groupMembersList.Select( m => new
                    {
                        m.Id,
                        m.Guid,
                        m.PersonId,
                        Name = m.Person.NickName + " " + m.Person.LastName
                            + ( hasGroupRequirements && groupMemberIdsThatLackGroupRequirements.Contains( m.Id )
                                ? " <i class='fa fa-exclamation-triangle text-warning'></i>"
                                : string.Empty )
                            + ( !string.IsNullOrEmpty( m.Note )
                            ? " <i class='fa fa-file-text-o text-info'></i>"
                            : string.Empty ),
                        GroupRole = m.GroupRole.Name,
                        m.GroupMemberStatus,
                        RecordStatusValueId = m.Person.RecordStatusValueId,
                        IsDeceased = m.Person.IsDeceased
                    } ).ToList();

                    gGroupMembers.DataBind();
                }
                else
                {
                    nbRoleWarning.Text = string.Format(
                        "{0} cannot be added to this {1} because the '{2}' group type does not have any roles defined.",
                        _group.GroupType.GroupMemberTerm.Pluralize(),
                        _group.GroupType.GroupTerm,
                        _group.GroupType.Name );

                    nbRoleWarning.Visible = true;
                    rFilter.Visible = false;
                    gGroupMembers.Visible = false;
                }
            }
            else
            {
                pnlGroupMembers.Visible = false;
            }
        }
        /// <summary>
        /// Binds the group members grid.
        /// </summary>
        protected void BindGroupMembersGrid(bool selectAll = false)
        {
            if (_group != null)
            {
                pnlGroupMembers.Visible = true;

                lHeading.Text = string.Format("{0} {1}", _group.GroupType.GroupTerm, _group.GroupType.GroupMemberTerm.Pluralize());

                if (_group.GroupType.Roles.Any())
                {
                    nbRoleWarning.Visible = false;
                    rFilter.Visible       = true;
                    gGroupMembers.Visible = true;

                    var rockContext = new RockContext();

                    GroupMemberService groupMemberService = new GroupMemberService(rockContext);
                    var qry = groupMemberService.Queryable("Person,GroupRole", true).AsNoTracking()
                              .Where(m => m.GroupId == _group.Id);

                    // Filter by First Name
                    string firstName = tbFirstName.Text;
                    if (!string.IsNullOrWhiteSpace(firstName))
                    {
                        qry = qry.Where(m => m.Person.FirstName.StartsWith(firstName));
                    }

                    // Filter by Last Name
                    string lastName = tbLastName.Text;
                    if (!string.IsNullOrWhiteSpace(lastName))
                    {
                        qry = qry.Where(m => m.Person.LastName.StartsWith(lastName));
                    }

                    // Filter by role
                    var validGroupTypeRoles = _group.GroupType.Roles.Select(r => r.Id).ToList();
                    var roles = new List <int>();
                    foreach (string role in cblRole.SelectedValues)
                    {
                        if (!string.IsNullOrWhiteSpace(role))
                        {
                            int roleId = int.MinValue;
                            if (int.TryParse(role, out roleId) && validGroupTypeRoles.Contains(roleId))
                            {
                                roles.Add(roleId);
                            }
                        }
                    }

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

                    // Filter by Status
                    var statuses = new List <GroupMemberStatus>();
                    foreach (string status in cblStatus.SelectedValues)
                    {
                        if (!string.IsNullOrWhiteSpace(status))
                        {
                            statuses.Add(status.ConvertToEnum <GroupMemberStatus>());
                        }
                    }

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

                    // Filter query by any configured attribute filters
                    if (AvailableAttributes != null && AvailableAttributes.Any())
                    {
                        var attributeValueService = new AttributeValueService(rockContext);
                        var parameterExpression   = attributeValueService.ParameterExpression;

                        foreach (var attribute in AvailableAttributes)
                        {
                            var filterControl = phAttributeFilters.FindControl("filter_" + attribute.Id.ToString());
                            if (filterControl != null)
                            {
                                var filterValues = attribute.FieldType.Field.GetFilterValues(filterControl, attribute.QualifierValues, Rock.Reporting.FilterMode.SimpleFilter);
                                var expression   = attribute.FieldType.Field.AttributeFilterExpression(attribute.QualifierValues, filterValues, parameterExpression);
                                if (expression != null)
                                {
                                    var attributeValues = attributeValueService
                                                          .Queryable()
                                                          .Where(v => v.Attribute.Id == attribute.Id);

                                    attributeValues = attributeValues.Where(parameterExpression, expression, null);

                                    qry = qry.Where(w => attributeValues.Select(v => v.EntityId).Contains(w.Id));
                                }
                            }
                        }
                    }

                    _inactiveStatus = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE);

                    SortProperty sortProperty = gGroupMembers.SortProperty;

                    bool hasGroupRequirements = new GroupRequirementService(rockContext).Queryable().Where(a => a.GroupId == _group.Id).Any();

                    // If there are group requirements that that member doesn't meet, show an icon in the grid
                    bool includeWarnings = false;
                    var  groupMemberIdsThatLackGroupRequirements = new GroupService(rockContext).GroupMembersNotMeetingRequirements(_group.Id, includeWarnings).Select(a => a.Key.Id);

                    List <GroupMember> groupMembersList = null;

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

                    // Since we're not binding to actual group member list, but are using AttributeField columns,
                    // we need to save the workflows into the grid's object list
                    gGroupMembers.ObjectList = new Dictionary <string, object>();
                    groupMembersList.ForEach(m => gGroupMembers.ObjectList.Add(m.Id.ToString(), m));
                    gGroupMembers.EntityTypeId = EntityTypeCache.Read(Rock.SystemGuid.EntityType.GROUP_MEMBER.AsGuid()).Id;

                    var homePhoneType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME);
                    var cellPhoneType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_MOBILE);

                    // If exporting to Excel, the selectAll option will be true, and home location should be calculated
                    var homeLocations = new Dictionary <int, Location>();
                    if (selectAll)
                    {
                        foreach (var m in groupMembersList)
                        {
                            homeLocations.Add(m.Id, m.Person.GetHomeLocation(rockContext));
                        }
                    }

                    gGroupMembers.DataSource = groupMembersList
                                               .ToList().Select(m => new
                    {
                        m.Id,
                        m.Guid,
                        m.PersonId,
                        Name = m.Person.NickName + " " + m.Person.LastName
                               + (hasGroupRequirements && groupMemberIdsThatLackGroupRequirements.Contains(m.Id)
                                ? " <i class='fa fa-exclamation-triangle text-warning'></i>"
                                : string.Empty)
                               + (!string.IsNullOrEmpty(m.Note)
                            ? " <i class='fa fa-file-text-o text-info'></i>"
                            : string.Empty),
                        Email     = m.Person.Email,
                        HomePhone = homePhoneType != null ?
                                    m.Person.PhoneNumbers
                                    .Where(p => p.NumberTypeValueId.HasValue && p.NumberTypeValueId.Value == homePhoneType.Id)
                                    .Select(p => p.NumberFormatted)
                                    .FirstOrDefault() : string.Empty,
                        CellPhone = cellPhoneType != null ?
                                    m.Person.PhoneNumbers
                                    .Where(p => p.NumberTypeValueId.HasValue && p.NumberTypeValueId.Value == cellPhoneType.Id)
                                    .Select(p => p.NumberFormatted)
                                    .FirstOrDefault() : string.Empty,
                        HomeAddress = homeLocations.ContainsKey(m.Id) && homeLocations[m.Id] != null ?
                                      homeLocations[m.Id].FormattedAddress : string.Empty,
                        Latitude = homeLocations.ContainsKey(m.Id) && homeLocations[m.Id] != null ?
                                   homeLocations[m.Id].Latitude : (double?)null,
                        Longitude = homeLocations.ContainsKey(m.Id) && homeLocations[m.Id] != null ?
                                    homeLocations[m.Id].Longitude : (double?)null,
                        GroupRole = m.GroupRole.Name,
                        m.GroupMemberStatus,
                        RecordStatusValueId = m.Person.RecordStatusValueId,
                        IsDeceased          = m.Person.IsDeceased
                    }).ToList();
                    gGroupMembers.DataBind();
                }
                else
                {
                    nbRoleWarning.Text = string.Format(
                        "{0} cannot be added to this {1} because the '{2}' group type does not have any roles defined.",
                        _group.GroupType.GroupMemberTerm.Pluralize(),
                        _group.GroupType.GroupTerm,
                        _group.GroupType.Name);

                    nbRoleWarning.Visible = true;
                    rFilter.Visible       = false;
                    gGroupMembers.Visible = false;
                }
            }
            else
            {
                pnlGroupMembers.Visible = false;
            }
        }
示例#6
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            var rockContext                   = new RockContext();
            var groupRequirementService       = new GroupRequirementService(rockContext);
            var groupMemberRequirementService = new GroupMemberRequirementService(rockContext);
            var groupMemberService            = new GroupMemberService(rockContext);
            var groupService                  = new GroupService(rockContext);

            // we only need to consider group requirements that are based on a DataView or SQL
            var groupRequirementQry = groupRequirementService.Queryable()
                                      .Where(a => a.GroupRequirementType.RequirementCheckType != RequirementCheckType.Manual)
                                      .AsNoTracking();

            var        calculationExceptions = new List <Exception>();
            List <int> groupRequirementsCalculatedPersonIds = new List <int>();

            foreach (var groupRequirement in groupRequirementQry.Include(i => i.GroupRequirementType).Include(a => a.GroupRequirementType.DataView).Include(a => a.GroupRequirementType.WarningDataView).AsNoTracking().ToList())
            {
                // Only calculate group requirements for Active groups (if an inactive group becomes active again, this job will take care of re-calculating the requirements again)
                var groupQuery = groupService.Queryable().Where(a => a.IsActive);
                if (groupRequirement.GroupId.HasValue)
                {
                    groupQuery = groupQuery.Where(g => g.Id == groupRequirement.GroupId);
                }
                else if (groupRequirement.GroupTypeId.HasValue)
                {
                    groupQuery = groupQuery.Where(g => g.GroupTypeId == groupRequirement.GroupTypeId);
                }
                else
                {
                    // shouldn't happen, but Group Requirement doesn't have a groupId or a GroupTypeId
                    break;
                }

                var groupList  = groupQuery.Select(a => new { a.Id, a.Name }).ToList();
                var groupCount = groupList.Count();
                foreach (var group in groupList)
                {
                    context.UpdateLastStatusMessage($"Calculating group requirement '{groupRequirement.GroupRequirementType.Name}' for {group.Name}");
                    try
                    {
                        var currentDateTime = RockDateTime.Now;
                        var qryGroupMemberRequirementsAlreadyOK = groupMemberRequirementService.Queryable().Where(a => a.GroupRequirementId == groupRequirement.Id && a.GroupMember.GroupId == group.Id);

                        if (groupRequirement.GroupRequirementType.CanExpire && groupRequirement.GroupRequirementType.ExpireInDays.HasValue)
                        {
                            // Group requirement can expire: don't recalculate members that already met the requirement within the expire days (unless they are flagged with a warning)
                            var expireDaysCount = groupRequirement.GroupRequirementType.ExpireInDays.Value;
                            qryGroupMemberRequirementsAlreadyOK = qryGroupMemberRequirementsAlreadyOK.Where(a => !a.RequirementWarningDateTime.HasValue && a.RequirementMetDateTime.HasValue && SqlFunctions.DateDiff("day", a.RequirementMetDateTime, currentDateTime) < expireDaysCount);
                        }
                        else
                        {
                            // No Expiration: don't recalculate members that already met the requirement
                            qryGroupMemberRequirementsAlreadyOK = qryGroupMemberRequirementsAlreadyOK.Where(a => a.RequirementMetDateTime.HasValue);
                        }

                        var groupMemberQry = groupMemberService.Queryable();

                        if (groupRequirement.GroupId.HasValue)
                        {
                            groupMemberQry = groupMemberQry.Where(g => g.GroupId == groupRequirement.GroupId);
                        }
                        else if (groupRequirement.GroupTypeId.HasValue)
                        {
                            groupMemberQry = groupMemberQry.Where(g => (g.Group.GroupTypeId == groupRequirement.GroupTypeId) && g.GroupId == group.Id);
                        }
                        else
                        {
                            // shouldn't happen, but Group Requirement doesn't have a groupId or a GroupTypeId
                            break;
                        }


                        var personQry = groupMemberQry.Where(a => !qryGroupMemberRequirementsAlreadyOK.Any(r => r.GroupMemberId == a.Id)).Select(a => a.Person);


                        var results = groupRequirement.PersonQueryableMeetsGroupRequirement(rockContext, personQry, group.Id, groupRequirement.GroupRoleId).ToList();

                        groupRequirementsCalculatedPersonIds.AddRange(results.Select(a => a.PersonId).Distinct());
                        foreach (var result in results)
                        {
                            try
                            {
                                // use a fresh rockContext per result so that ChangeTracker doesn't get bogged down
                                using (var rockContextUpdate = new RockContext())
                                {
                                    groupRequirement.UpdateGroupMemberRequirementResult(rockContextUpdate, result.PersonId, group.Id, result.MeetsGroupRequirement);
                                    rockContextUpdate.SaveChanges();
                                }
                            }
                            catch (Exception ex)
                            {
                                calculationExceptions.Add(new Exception($"Exception when updating group requirement result: {groupRequirement} for person.Id { result.PersonId }", ex));
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        calculationExceptions.Add(new Exception(string.Format("Exception when calculating group requirement: {0} ", groupRequirement), ex));
                    }
                }
            }

            context.UpdateLastStatusMessage($"{groupRequirementQry.Count()} group member requirements re-calculated for {groupRequirementsCalculatedPersonIds.Distinct().Count()} people");

            if (calculationExceptions.Any())
            {
                throw new AggregateException("One or more group requirement calculations failed ", calculationExceptions);
            }
        }
        /// <summary>
        /// Binds the group members grid.
        /// </summary>
        protected void BindGroupMembersGrid( bool isExporting = false )
        {
            if ( _group != null )
            {
                pnlGroupMembers.Visible = true;

                lHeading.Text = string.Format( "{0} {1}", _group.GroupType.GroupTerm, _group.GroupType.GroupMemberTerm.Pluralize() );

                if ( _group.GroupType.Roles.Any() )
                {
                    nbRoleWarning.Visible = false;
                    rFilter.Visible = true;
                    gGroupMembers.Visible = true;

                    var rockContext = new RockContext();

                    if ( _group != null &&
                        _group.RequiredSignatureDocumentTemplateId.HasValue )
                    {
                        Signers = new SignatureDocumentService( rockContext )
                            .Queryable().AsNoTracking()
                            .Where( d =>
                                d.SignatureDocumentTemplateId == _group.RequiredSignatureDocumentTemplateId.Value &&
                                d.Status == SignatureDocumentStatus.Signed &&
                                d.BinaryFileId.HasValue &&
                                d.AppliesToPersonAlias != null )
                            .OrderByDescending( d => d.LastStatusDate )
                            .Select( d => d.AppliesToPersonAlias.PersonId )
                            .ToList();
                    }

                    GroupMemberService groupMemberService = new GroupMemberService( rockContext );
                    var qry = groupMemberService.Queryable( "Person,GroupRole", true ).AsNoTracking()
                        .Where( m => m.GroupId == _group.Id );

                    // Filter by First Name
                    string firstName = tbFirstName.Text;
                    if ( !string.IsNullOrWhiteSpace( firstName ) )
                    {
                        qry = qry.Where( m =>
                            m.Person.FirstName.StartsWith( firstName ) ||
                            m.Person.NickName.StartsWith( firstName ) );
                    }

                    // Filter by Last Name
                    string lastName = tbLastName.Text;
                    if ( !string.IsNullOrWhiteSpace( lastName ) )
                    {
                        qry = qry.Where( m => m.Person.LastName.StartsWith( lastName ) );
                    }

                    // Filter by role
                    var validGroupTypeRoles = _group.GroupType.Roles.Select( r => r.Id ).ToList();
                    var roles = new List<int>();
                    foreach ( var roleId in cblRole.SelectedValues.AsIntegerList() )
                    {
                        if ( validGroupTypeRoles.Contains( roleId ) )
                        {
                            roles.Add( roleId );
                        }
                    }

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

                    // Filter by Group Member Status
                    var statuses = new List<GroupMemberStatus>();
                    foreach ( string status in cblGroupMemberStatus.SelectedValues )
                    {
                        if ( !string.IsNullOrWhiteSpace( status ) )
                        {
                            statuses.Add( status.ConvertToEnum<GroupMemberStatus>() );
                        }
                    }

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

                    var genders = new List<Gender>();
                    foreach ( var item in cblGenderFilter.SelectedValues )
                    {
                        var gender = item.ConvertToEnum<Gender>();
                        genders.Add( gender );
                    }

                    if ( genders.Any() )
                    {
                        qry = qry.Where( m => genders.Contains( m.Person.Gender ) );
                    }

                    // Filter by Campus
                    if ( cpCampusFilter.SelectedCampusId.HasValue )
                    {
                        Guid familyGuid = new Guid( Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY );
                        int campusId = cpCampusFilter.SelectedCampusId.Value;
                        var qryFamilyMembersForCampus = new GroupMemberService( rockContext ).Queryable().Where( a => a.Group.GroupType.Guid == familyGuid && a.Group.CampusId == campusId );
                        qry = qry.Where( a => qryFamilyMembersForCampus.Any( f => f.PersonId == a.PersonId ) );
                    }

                    // Filter by signed documents
                    if ( Signers != null )
                    {
                        if ( ddlSignedDocument.SelectedValue.AsBooleanOrNull() == true )
                        {
                            qry = qry.Where( m => Signers.Contains( m.PersonId ) );
                        }
                        else if ( ddlSignedDocument.SelectedValue.AsBooleanOrNull() == false )
                        {
                            qry = qry.Where( m => !Signers.Contains( m.PersonId ) );
                        }
                    }

                    // Filter query by any configured attribute filters
                    if ( AvailableAttributes != null && AvailableAttributes.Any() )
                    {
                        var attributeValueService = new AttributeValueService( rockContext );
                        var parameterExpression = attributeValueService.ParameterExpression;

                        foreach ( var attribute in AvailableAttributes )
                        {
                            var filterControl = phAttributeFilters.FindControl( "filter_" + attribute.Id.ToString() );
                            if ( filterControl != null )
                            {
                                var filterValues = attribute.FieldType.Field.GetFilterValues( filterControl, attribute.QualifierValues, Rock.Reporting.FilterMode.SimpleFilter );
                                var expression = attribute.FieldType.Field.AttributeFilterExpression( attribute.QualifierValues, filterValues, parameterExpression );
                                if ( expression != null )
                                {
                                    var attributeValues = attributeValueService
                                        .Queryable()
                                        .Where( v => v.Attribute.Id == attribute.Id );

                                    attributeValues = attributeValues.Where( parameterExpression, expression, null );

                                    qry = qry.Where( w => attributeValues.Select( v => v.EntityId ).Contains( w.Id ) );
                                }
                            }
                        }
                    }

                    _inactiveStatus = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE );

                    SortProperty sortProperty = gGroupMembers.SortProperty;

                    bool hasGroupRequirements = new GroupRequirementService( rockContext ).Queryable().Where( a => a.GroupId == _group.Id ).Any();

                    // If there are group requirements that that member doesn't meet, show an icon in the grid
                    bool includeWarnings = false;
                    var groupMemberIdsThatLackGroupRequirements = new GroupService( rockContext ).GroupMembersNotMeetingRequirements( _group.Id, includeWarnings ).Select( a => a.Key.Id );

                    List<GroupMember> groupMembersList = null;
                    if ( sortProperty != null && sortProperty.Property != "FirstAttended" && sortProperty.Property != "LastAttended" )
                    {
                        groupMembersList = qry.Sort( sortProperty ).ToList();
                    }
                    else
                    {
                        groupMembersList = qry.OrderBy( a => a.GroupRole.Order ).ThenBy( a => a.Person.LastName ).ThenBy( a => a.Person.FirstName ).ToList();
                    }

                    // If there is a required signed document that member has not signed, show an icon in the grid
                    var personIdsThatHaventSigned = new List<int>();
                    if ( Signers != null )
                    {
                        var memberPersonIds = groupMembersList.Select( m => m.PersonId ).ToList();
                        personIdsThatHaventSigned = memberPersonIds.Where( i => !Signers.Contains( i ) ).ToList();
                    }

                    // Since we're not binding to actual group member list, but are using AttributeField columns,
                    // we need to save the group members into the grid's object list
                    gGroupMembers.ObjectList = new Dictionary<string, object>();
                    groupMembersList.ForEach( m => gGroupMembers.ObjectList.Add( m.Id.ToString(), m ) );
                    gGroupMembers.EntityTypeId = EntityTypeCache.Read( Rock.SystemGuid.EntityType.GROUP_MEMBER.AsGuid() ).Id;

                    var homePhoneType = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME );
                    var cellPhoneType = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_MOBILE );

                    // If exporting to Excel, the selectAll option will be true, and home location should be calculated
                    var homeLocations = new Dictionary<int, Location>();
                    if ( isExporting )
                    {
                        foreach ( var m in groupMembersList )
                        {
                            homeLocations.Add( m.Id, m.Person.GetHomeLocation( rockContext ) );
                        }
                    }

                    var groupMemberIds = groupMembersList.Select( m => m.Id ).ToList();

                    // Get all the group members with any associated registrations
                    _groupMembersWithRegistrations = new RegistrationRegistrantService( rockContext )
                        .Queryable().AsNoTracking()
                        .Where( r =>
                            r.Registration != null &&
                            r.Registration.RegistrationInstance != null &&
                            r.GroupMemberId.HasValue &&
                            groupMemberIds.Contains( r.GroupMemberId.Value ) )
                        .ToList()
                        .GroupBy( r => r.GroupMemberId.Value )
                        .Select( g => new
                        {
                            GroupMemberId = g.Key,
                            Registrations = g.ToList()
                                .Select( r => new
                                {
                                    Id = r.Registration.Id,
                                    Name = r.Registration.RegistrationInstance.Name
                                } ).Distinct()
                                .ToDictionary( r => r.Id, r => r.Name )
                        } )
                        .ToDictionary( r => r.GroupMemberId, r => r.Registrations );

                    var registrationField = gGroupMembers.ColumnsOfType<RockTemplateFieldUnselected>().FirstOrDefault();
                    if ( registrationField != null )
                    {
                        registrationField.Visible = _groupMembersWithRegistrations.Any();
                    }

                    var connectionStatusField = gGroupMembers.ColumnsOfType<DefinedValueField>().FirstOrDefault( a => a.DataField == "ConnectionStatusValueId" );
                    if ( connectionStatusField != null )
                    {
                        connectionStatusField.Visible = _group.GroupType.ShowConnectionStatus;
                    }

                    string photoFormat = "<div class=\"photo-icon photo-round photo-round-xs pull-left margin-r-sm js-person-popover\" personid=\"{0}\" data-original=\"{1}&w=50\" style=\"background-image: url( '{2}' ); background-size: cover; background-repeat: no-repeat;\"></div>";

                    var attendanceFirstLast = new Dictionary<int, DateRange>();
                    bool showAttendance = GetAttributeValue( "ShowAttendance" ).AsBoolean() && _group.GroupType.TakesAttendance;
                    gGroupMembers.ColumnsOfType<DateField>().First( a => a.DataField == "FirstAttended" ).Visible = showAttendance;
                    gGroupMembers.ColumnsOfType<DateField>().First( a => a.DataField == "LastAttended" ).Visible = showAttendance;
                    if ( showAttendance )
                    {
                        foreach ( var attendance in new AttendanceService( rockContext )
                            .Queryable().AsNoTracking()
                            .Where( a =>
                                a.GroupId.HasValue && a.GroupId.Value == _group.Id &&
                                a.DidAttend.HasValue && a.DidAttend.Value )
                            .GroupBy( a => a.PersonAlias.PersonId )
                            .Select( g => new
                            {
                                PersonId = g.Key,
                                FirstAttended = g.Min( a => a.StartDateTime ),
                                LastAttended = g.Max( a => a.StartDateTime )
                            } )
                            .ToList() )
                        {
                            attendanceFirstLast.Add( attendance.PersonId, new DateRange( attendance.FirstAttended, attendance.LastAttended ) );
                        }
                    }

                    var dataSource = groupMembersList.Select( m => new
                    {
                        m.Id,
                        m.Guid,
                        m.PersonId,
                        m.Person.NickName,
                        m.Person.LastName,
                        Name =
                        ( isExporting ? m.Person.LastName + ", " + m.Person.NickName : string.Format( photoFormat, m.PersonId, m.Person.PhotoUrl, ResolveUrl( "~/Assets/Images/person-no-photo-male.svg" ) ) +
                            m.Person.NickName + " " + m.Person.LastName
                            + ( ( hasGroupRequirements && groupMemberIdsThatLackGroupRequirements.Contains( m.Id ) )
                                ? " <i class='fa fa-exclamation-triangle text-warning'></i>"
                                : string.Empty )
                            + ( !string.IsNullOrEmpty( m.Note )
                                ? " <i class='fa fa-file-text-o text-info'></i>"
                                : string.Empty )
                            + ((personIdsThatHaventSigned.Contains( m.PersonId ))
                                ? " <i class='fa fa-pencil-square-o text-danger'></i>"
                                : string.Empty)),
                        m.Person.BirthDate,
                        m.Person.Age,
                        m.Person.ConnectionStatusValueId,
                        m.DateTimeAdded,
                        FirstAttended = attendanceFirstLast.Where( a => a.Key == m.PersonId ).Select( a => a.Value.Start ).FirstOrDefault(),
                        LastAttended = attendanceFirstLast.Where( a => a.Key == m.PersonId ).Select( a => a.Value.End ).FirstOrDefault(),
                        Email = m.Person.Email,
                        HomePhone = isExporting && homePhoneType != null ?
                            m.Person.PhoneNumbers
                                .Where( p => p.NumberTypeValueId.HasValue && p.NumberTypeValueId.Value == homePhoneType.Id )
                                .Select( p => p.NumberFormatted )
                                .FirstOrDefault() : string.Empty,
                        CellPhone = isExporting && cellPhoneType != null ?
                            m.Person.PhoneNumbers
                                .Where( p => p.NumberTypeValueId.HasValue && p.NumberTypeValueId.Value == cellPhoneType.Id )
                                .Select( p => p.NumberFormatted )
                                .FirstOrDefault() : string.Empty,
                        HomeAddress = homeLocations.ContainsKey( m.Id ) && homeLocations[m.Id] != null ?
                            homeLocations[m.Id].FormattedAddress : string.Empty,
                        Latitude = homeLocations.ContainsKey( m.Id ) && homeLocations[m.Id] != null ?
                            homeLocations[m.Id].Latitude : (double?)null,
                        Longitude = homeLocations.ContainsKey( m.Id ) && homeLocations[m.Id] != null ?
                            homeLocations[m.Id].Longitude : (double?)null,
                        GroupRole = m.GroupRole.Name,
                        m.GroupMemberStatus,
                        RecordStatusValueId = m.Person.RecordStatusValueId,
                        IsDeceased = m.Person.IsDeceased
                    } ).ToList();

                    if ( sortProperty != null )
                    {
                        if ( sortProperty.Property == "FirstAttended" )
                        {
                            if ( sortProperty.Direction == SortDirection.Descending )
                            {
                                dataSource = dataSource.OrderByDescending( a => a.FirstAttended ?? DateTime.MinValue ).ToList();
                            }
                            else
                            {
                                dataSource = dataSource.OrderBy( a => a.FirstAttended ?? DateTime.MinValue ).ToList();
                            }
                        }

                        if ( sortProperty.Property == "LastAttended" )
                        {
                            if ( sortProperty.Direction == SortDirection.Descending )
                            {
                                dataSource = dataSource.OrderByDescending( a => a.LastAttended ?? DateTime.MinValue ).ToList();
                            }
                            else
                            {
                                dataSource = dataSource.OrderBy( a => a.LastAttended ?? DateTime.MinValue ).ToList();
                            }
                        }
                    }

                    gGroupMembers.DataSource = dataSource;
                    gGroupMembers.DataBind();
                }
                else
                {
                    nbRoleWarning.Text = string.Format(
                        "{0} cannot be added to this {1} because the '{2}' group type does not have any roles defined.",
                        _group.GroupType.GroupMemberTerm.Pluralize(),
                        _group.GroupType.GroupTerm,
                        _group.GroupType.Name );

                    nbRoleWarning.Visible = true;
                    rFilter.Visible = false;
                    gGroupMembers.Visible = false;
                }
            }
            else
            {
                pnlGroupMembers.Visible = false;
            }
        }
示例#8
0
        /// <summary>
        /// Handles the Click event of the btnSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        protected void btnSave_Click( object sender, EventArgs e )
        {
            Group group;
            bool wasSecurityRole = false;
            bool triggersUpdated = false;

            RockContext rockContext = new RockContext();

            GroupService groupService = new GroupService( rockContext );
            GroupLocationService groupLocationService = new GroupLocationService( rockContext );
            GroupRequirementService groupRequirementService = new GroupRequirementService( rockContext );
            GroupMemberWorkflowTriggerService groupMemberWorkflowTriggerService = new GroupMemberWorkflowTriggerService( rockContext );
            ScheduleService scheduleService = new ScheduleService( rockContext );
            AttributeService attributeService = new AttributeService( rockContext );
            AttributeQualifierService attributeQualifierService = new AttributeQualifierService( rockContext );
            CategoryService categoryService = new CategoryService( rockContext );

            var roleGroupType = GroupTypeCache.Read( Rock.SystemGuid.GroupType.GROUPTYPE_SECURITY_ROLE.AsGuid() );
            int roleGroupTypeId = roleGroupType != null ? roleGroupType.Id : int.MinValue;

            if ( CurrentGroupTypeId == 0 )
            {
                ddlGroupType.ShowErrorMessage( Rock.Constants.WarningMessage.CannotBeBlank( GroupType.FriendlyTypeName ) );
                return;
            }

            int groupId = hfGroupId.Value.AsInteger();

            if ( groupId == 0 )
            {
                group = new Group();
                group.IsSystem = false;
                group.Name = string.Empty;
            }
            else
            {
                group = groupService.Queryable( "Schedule,GroupLocations.Schedules" ).Where( g => g.Id == groupId ).FirstOrDefault();
                wasSecurityRole = group.IsActive && ( group.IsSecurityRole || group.GroupTypeId == roleGroupTypeId );

                // remove any locations that removed in the UI
                var selectedLocations = GroupLocationsState.Select( l => l.Guid );
                foreach ( var groupLocation in group.GroupLocations.Where( l => !selectedLocations.Contains( l.Guid ) ).ToList() )
                {
                    group.GroupLocations.Remove( groupLocation );
                    groupLocationService.Delete( groupLocation );
                }

                // remove any group requirements that removed in the UI
                var selectedGroupRequirements = GroupRequirementsState.Select( a => a.Guid );
                foreach ( var groupRequirement in group.GroupRequirements.Where( a => !selectedGroupRequirements.Contains( a.Guid ) ).ToList() )
                {
                    group.GroupRequirements.Remove( groupRequirement );
                    groupRequirementService.Delete( groupRequirement );
                }

                // Remove any triggers that were removed in the UI
                var selectedTriggerGuids = MemberWorkflowTriggersState.Select( r => r.Guid );
                foreach ( var trigger in group.GroupMemberWorkflowTriggers.Where( r => !selectedTriggerGuids.Contains( r.Guid ) ).ToList() )
                {
                    group.GroupMemberWorkflowTriggers.Remove( trigger );
                    groupMemberWorkflowTriggerService.Delete( trigger );
                    triggersUpdated = true;
                }
            }

            // add/update any group requirements that were added or changed in the UI (we already removed the ones that were removed above)
            foreach ( var groupRequirementState in GroupRequirementsState )
            {
                GroupRequirement groupRequirement = group.GroupRequirements.Where( a => a.Guid == groupRequirementState.Guid ).FirstOrDefault();
                if ( groupRequirement == null )
                {
                    groupRequirement = new GroupRequirement();
                    group.GroupRequirements.Add( groupRequirement );
                }

                groupRequirement.CopyPropertiesFrom( groupRequirementState );
            }

            // add/update any group locations that were added or changed in the UI (we already removed the ones that were removed above)
            foreach ( var groupLocationState in GroupLocationsState )
            {
                GroupLocation groupLocation = group.GroupLocations.Where( l => l.Guid == groupLocationState.Guid ).FirstOrDefault();
                if ( groupLocation == null )
                {
                    groupLocation = new GroupLocation();
                    group.GroupLocations.Add( groupLocation );
                }
                else
                {
                    groupLocationState.Id = groupLocation.Id;
                    groupLocationState.Guid = groupLocation.Guid;

                    var selectedSchedules = groupLocationState.Schedules.Select( s => s.Guid ).ToList();
                    foreach ( var schedule in groupLocation.Schedules.Where( s => !selectedSchedules.Contains( s.Guid ) ).ToList() )
                    {
                        groupLocation.Schedules.Remove( schedule );
                    }
                }

                groupLocation.CopyPropertiesFrom( groupLocationState );

                var existingSchedules = groupLocation.Schedules.Select( s => s.Guid ).ToList();
                foreach ( var scheduleState in groupLocationState.Schedules.Where( s => !existingSchedules.Contains( s.Guid ) ).ToList() )
                {
                    var schedule = scheduleService.Get( scheduleState.Guid );
                    if ( schedule != null )
                    {
                        groupLocation.Schedules.Add( schedule );
                    }
                }
            }

            foreach ( var triggerState in MemberWorkflowTriggersState )
            {
                GroupMemberWorkflowTrigger trigger = group.GroupMemberWorkflowTriggers.Where( r => r.Guid == triggerState.Guid ).FirstOrDefault();
                if ( trigger == null )
                {
                    trigger = new GroupMemberWorkflowTrigger();
                    group.GroupMemberWorkflowTriggers.Add( trigger );
                }
                else
                {
                    triggerState.Id = trigger.Id;
                    triggerState.Guid = trigger.Guid;
                }

                trigger.CopyPropertiesFrom( triggerState );

                triggersUpdated = true;
            }

            group.Name = tbName.Text;
            group.Description = tbDescription.Text;
            group.CampusId = ddlCampus.SelectedValueAsInt();
            group.GroupTypeId = CurrentGroupTypeId;
            group.ParentGroupId = gpParentGroup.SelectedValueAsInt();
            group.GroupCapacity = nbGroupCapacity.Text.AsIntegerOrNull();
            group.RequiredSignatureDocumentTemplateId = ddlSignatureDocumentTemplate.SelectedValueAsInt();
            group.IsSecurityRole = cbIsSecurityRole.Checked;
            group.IsActive = cbIsActive.Checked;
            group.IsPublic = cbIsPublic.Checked;
            group.MustMeetRequirementsToAddMember = cbMembersMustMeetRequirementsOnAdd.Checked;

            // save sync settings
            group.SyncDataViewId = dvpSyncDataview.SelectedValue.AsIntegerOrNull();
            group.WelcomeSystemEmailId = ddlWelcomeEmail.SelectedValue.AsIntegerOrNull();
            group.ExitSystemEmailId = ddlExitEmail.SelectedValue.AsIntegerOrNull();
            group.AddUserAccountsDuringSync = rbCreateLoginDuringSync.Checked;

            string iCalendarContent = string.Empty;

            // If unique schedule option was selected, but a schedule was not defined, set option to 'None'
            var scheduleType = rblScheduleSelect.SelectedValueAsEnum<ScheduleType>( ScheduleType.None );
            if ( scheduleType == ScheduleType.Custom )
            {
                iCalendarContent = sbSchedule.iCalendarContent;
                var calEvent = ScheduleICalHelper.GetCalenderEvent( iCalendarContent );
                if ( calEvent == null || calEvent.DTStart == null )
                {
                    scheduleType = ScheduleType.None;
                }
            }

            if ( scheduleType == ScheduleType.Weekly )
            {
                if ( !dowWeekly.SelectedDayOfWeek.HasValue )
                {
                    scheduleType = ScheduleType.None;
                }
            }

            int? oldScheduleId = hfUniqueScheduleId.Value.AsIntegerOrNull();
            if ( scheduleType == ScheduleType.Custom || scheduleType == ScheduleType.Weekly )
            {
                if ( !oldScheduleId.HasValue || group.Schedule == null )
                {
                    group.Schedule = new Schedule();
                }

                if ( scheduleType == ScheduleType.Custom )
                {
                    group.Schedule.iCalendarContent = iCalendarContent;
                    group.Schedule.WeeklyDayOfWeek = null;
                    group.Schedule.WeeklyTimeOfDay = null;
                }
                else
                {
                    group.Schedule.iCalendarContent = null;
                    group.Schedule.WeeklyDayOfWeek = dowWeekly.SelectedDayOfWeek;
                    group.Schedule.WeeklyTimeOfDay = timeWeekly.SelectedTime;
                }
            }
            else
            {
                // If group did have a unique schedule, delete that schedule
                if ( oldScheduleId.HasValue )
                {
                    var schedule = scheduleService.Get( oldScheduleId.Value );
                    if ( schedule != null && string.IsNullOrEmpty( schedule.Name ) )
                    {
                        // Make sure this is the only group trying to use this schedule.
                        if ( !groupService.Queryable().Where( g => g.ScheduleId == schedule.Id && g.Id != group.Id ).Any() )
                        {
                            scheduleService.Delete( schedule );
                        }
                    }
                }

                if ( scheduleType == ScheduleType.Named )
                {
                    group.ScheduleId = spSchedule.SelectedValueAsId();
                }
                else
                {
                    group.ScheduleId = null;
                }
            }

            if ( group.ParentGroupId == group.Id )
            {
                gpParentGroup.ShowErrorMessage( "Group cannot be a Parent Group of itself." );
                return;
            }

            group.LoadAttributes();

            Rock.Attribute.Helper.GetEditValues( phGroupAttributes, group );

            group.GroupType = new GroupTypeService( rockContext ).Get( group.GroupTypeId );
            if ( group.ParentGroupId.HasValue )
            {
                group.ParentGroup = groupService.Get( group.ParentGroupId.Value );
            }

            // Check to see if group type is allowed as a child of new parent group.
            if ( group.ParentGroup != null )
            {
                var allowedGroupTypeIds = GetAllowedGroupTypes( group.ParentGroup, rockContext ).Select( t => t.Id ).ToList();
                if ( !allowedGroupTypeIds.Contains( group.GroupTypeId ) )
                {
                    var groupType = CurrentGroupTypeCache;
                    nbInvalidParentGroup.Text = string.Format( "The '{0}' group does not allow child groups with a '{1}' group type.", group.ParentGroup.Name, groupType != null ? groupType.Name : string.Empty );
                    nbInvalidParentGroup.Visible = true;
                    return;
                }
            }

            // Check to see if user is still allowed to edit with selected group type and parent group
            if ( !group.IsAuthorized( Authorization.EDIT, CurrentPerson ) )
            {
                nbNotAllowedToEdit.Visible = true;
                return;
            }

            if ( !Page.IsValid )
            {
                return;
            }

            // if the groupMember IsValid is false, and the UI controls didn't report any errors, it is probably because the custom rules of GroupMember didn't pass.
            // So, make sure a message is displayed in the validation summary
            cvGroup.IsValid = group.IsValid;

            if ( !cvGroup.IsValid )
            {
                cvGroup.ErrorMessage = group.ValidationResults.Select( a => a.ErrorMessage ).ToList().AsDelimited( "<br />" );
                return;
            }

            // use WrapTransaction since SaveAttributeValues does it's own RockContext.SaveChanges()
            rockContext.WrapTransaction( () =>
            {
                var adding = group.Id.Equals( 0 );
                if ( adding )
                {
                    groupService.Add( group );
                }

                rockContext.SaveChanges();

                if ( adding )
                {
                    // add ADMINISTRATE to the person who added the group
                    Rock.Security.Authorization.AllowPerson( group, Authorization.ADMINISTRATE, this.CurrentPerson, rockContext );
                }

                group.SaveAttributeValues( rockContext );

                /* Take care of Group Member Attributes */
                var entityTypeId = EntityTypeCache.Read( typeof( GroupMember ) ).Id;
                string qualifierColumn = "GroupId";
                string qualifierValue = group.Id.ToString();

                // Get the existing attributes for this entity type and qualifier value
                var attributes = attributeService.Get( entityTypeId, qualifierColumn, qualifierValue );

                // Delete any of those attributes that were removed in the UI
                var selectedAttributeGuids = GroupMemberAttributesState.Select( a => a.Guid );
                foreach ( var attr in attributes.Where( a => !selectedAttributeGuids.Contains( a.Guid ) ) )
                {
                    Rock.Web.Cache.AttributeCache.Flush( attr.Id );

                    attributeService.Delete( attr );
                }

                // Update the Attributes that were assigned in the UI
                foreach ( var attributeState in GroupMemberAttributesState )
                {
                    Rock.Attribute.Helper.SaveAttributeEdits( attributeState, entityTypeId, qualifierColumn, qualifierValue, rockContext );
                }

                rockContext.SaveChanges();

                if ( group.IsActive == false && cbInactivateChildGroups.Checked )
                {
                    var allActiveChildGroupsId = groupService.GetAllDescendents( group.Id ).Where( a => a.IsActive ).Select( a => a.Id ).ToList();
                    var allActiveChildGroups = groupService.GetByIds( allActiveChildGroupsId );
                    foreach ( var childGroup in allActiveChildGroups )
                    {
                        if ( childGroup.IsActive )
                        {
                            childGroup.IsActive = false;
                        }
                    }

                    rockContext.SaveChanges();
                }
            } );

            bool isNowSecurityRole = group.IsActive && ( group.IsSecurityRole || group.GroupTypeId == roleGroupTypeId );

            if ( group != null && wasSecurityRole )
            {
                if ( !isNowSecurityRole )
                {
                    // if this group was a SecurityRole, but no longer is, flush
                    Rock.Security.Role.Flush( group.Id );
                    Rock.Security.Authorization.Flush();
                }
            }
            else
            {
                if ( isNowSecurityRole )
                {
                    // new security role, flush
                    Rock.Security.Authorization.Flush();
                }
            }

            AttributeCache.FlushEntityAttributes();

            if ( triggersUpdated )
            {
                GroupMemberWorkflowTriggerService.FlushCachedTriggers();
            }

            var qryParams = new Dictionary<string, string>();
            qryParams["GroupId"] = group.Id.ToString();
            qryParams["ExpandedIds"] = PageParameter( "ExpandedIds" );

            NavigateToPage( RockPage.Guid, qryParams );
        }
示例#9
0
        /// <summary>
        /// Binds the group members grid.
        /// </summary>
        protected void BindGroupMembersGrid(bool selectAll = false)
        {
            if (_group != null)
            {
                pnlGroupMembers.Visible = true;

                lHeading.Text = string.Format("{0} {1}", _group.GroupType.GroupTerm, _group.GroupType.GroupMemberTerm.Pluralize());

                if (_group.GroupType.Roles.Any())
                {
                    nbRoleWarning.Visible = false;
                    rFilter.Visible       = true;
                    gGroupMembers.Visible = true;

                    var rockContext = new RockContext();

                    GroupMemberService groupMemberService = new GroupMemberService(rockContext);
                    var qry = groupMemberService.Queryable("Person,GroupRole", true).AsNoTracking()
                              .Where(m => m.GroupId == _group.Id);

                    // Filter by First Name
                    string firstName = tbFirstName.Text;
                    if (!string.IsNullOrWhiteSpace(firstName))
                    {
                        qry = qry.Where(m =>
                                        m.Person.FirstName.StartsWith(firstName) ||
                                        m.Person.NickName.StartsWith(firstName));
                    }

                    // Filter by Last Name
                    string lastName = tbLastName.Text;
                    if (!string.IsNullOrWhiteSpace(lastName))
                    {
                        qry = qry.Where(m => m.Person.LastName.StartsWith(lastName));
                    }

                    // Filter by role
                    var validGroupTypeRoles = _group.GroupType.Roles.Select(r => r.Id).ToList();
                    var roles = new List <int>();
                    foreach (var roleId in cblRole.SelectedValues.AsIntegerList())
                    {
                        if (validGroupTypeRoles.Contains(roleId))
                        {
                            roles.Add(roleId);
                        }
                    }

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

                    // Filter by Group Member Status
                    var statuses = new List <GroupMemberStatus>();
                    foreach (string status in cblGroupMemberStatus.SelectedValues)
                    {
                        if (!string.IsNullOrWhiteSpace(status))
                        {
                            statuses.Add(status.ConvertToEnum <GroupMemberStatus>());
                        }
                    }

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

                    // Filter by Campus
                    if (cpCampusFilter.SelectedCampusId.HasValue)
                    {
                        Guid familyGuid = new Guid(Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY);
                        int  campusId   = cpCampusFilter.SelectedCampusId.Value;
                        var  qryFamilyMembersForCampus = new GroupMemberService(rockContext).Queryable().Where(a => a.Group.GroupType.Guid == familyGuid && a.Group.CampusId == campusId);
                        qry = qry.Where(a => qryFamilyMembersForCampus.Any(f => f.PersonId == a.PersonId));
                    }

                    // Filter query by any configured attribute filters
                    if (AvailableAttributes != null && AvailableAttributes.Any())
                    {
                        var attributeValueService = new AttributeValueService(rockContext);
                        var parameterExpression   = attributeValueService.ParameterExpression;

                        foreach (var attribute in AvailableAttributes)
                        {
                            var filterControl = phAttributeFilters.FindControl("filter_" + attribute.Id.ToString());
                            if (filterControl != null)
                            {
                                var filterValues = attribute.FieldType.Field.GetFilterValues(filterControl, attribute.QualifierValues, Rock.Reporting.FilterMode.SimpleFilter);
                                var expression   = attribute.FieldType.Field.AttributeFilterExpression(attribute.QualifierValues, filterValues, parameterExpression);
                                if (expression != null)
                                {
                                    var attributeValues = attributeValueService
                                                          .Queryable()
                                                          .Where(v => v.Attribute.Id == attribute.Id);

                                    attributeValues = attributeValues.Where(parameterExpression, expression, null);

                                    qry = qry.Where(w => attributeValues.Select(v => v.EntityId).Contains(w.Id));
                                }
                            }
                        }
                    }

                    _inactiveStatus = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE);

                    SortProperty sortProperty = gGroupMembers.SortProperty;

                    bool hasGroupRequirements = new GroupRequirementService(rockContext).Queryable().Where(a => a.GroupId == _group.Id).Any();

                    // If there are group requirements that that member doesn't meet, show an icon in the grid
                    bool includeWarnings = false;
                    var  groupMemberIdsThatLackGroupRequirements = new GroupService(rockContext).GroupMembersNotMeetingRequirements(_group.Id, includeWarnings).Select(a => a.Key.Id);

                    List <GroupMember> groupMembersList = null;

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

                    // Since we're not binding to actual group member list, but are using AttributeField columns,
                    // we need to save the workflows into the grid's object list
                    gGroupMembers.ObjectList = new Dictionary <string, object>();
                    groupMembersList.ForEach(m => gGroupMembers.ObjectList.Add(m.Id.ToString(), m));
                    gGroupMembers.EntityTypeId = EntityTypeCache.Read(Rock.SystemGuid.EntityType.GROUP_MEMBER.AsGuid()).Id;

                    var homePhoneType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME);
                    var cellPhoneType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_MOBILE);

                    // If exporting to Excel, the selectAll option will be true, and home location should be calculated
                    var homeLocations = new Dictionary <int, Location>();
                    if (selectAll)
                    {
                        foreach (var m in groupMembersList)
                        {
                            homeLocations.Add(m.Id, m.Person.GetHomeLocation(rockContext));
                        }
                    }

                    var groupMemberIds = groupMembersList.Select(m => m.Id).ToList();

                    // Get all the group members with any associated registrations
                    _groupMembersWithRegistrations = new RegistrationRegistrantService(rockContext)
                                                     .Queryable().AsNoTracking()
                                                     .Where(r =>
                                                            r.Registration != null &&
                                                            r.Registration.RegistrationInstance != null &&
                                                            r.GroupMemberId.HasValue &&
                                                            groupMemberIds.Contains(r.GroupMemberId.Value))
                                                     .ToList()
                                                     .GroupBy(r => r.GroupMemberId.Value)
                                                     .Select(g => new
                    {
                        GroupMemberId = g.Key,
                        Registrations = g.ToList()
                                        .Select(r => new {
                            Id   = r.Registration.Id,
                            Name = r.Registration.RegistrationInstance.Name
                        })
                                        .ToDictionary(r => r.Id, r => r.Name)
                    })
                                                     .ToDictionary(r => r.GroupMemberId, r => r.Registrations);

                    var registrationField = gGroupMembers.ColumnsOfType <RockTemplateFieldUnselected>().FirstOrDefault();
                    if (registrationField != null)
                    {
                        registrationField.Visible = _groupMembersWithRegistrations.Any();
                    }

                    var connectionStatusField = gGroupMembers.ColumnsOfType <DefinedValueField>().FirstOrDefault(a => a.DataField == "ConnectionStatusValueId");
                    if (connectionStatusField != null)
                    {
                        connectionStatusField.Visible = _group.GroupType.ShowConnectionStatus;
                    }

                    string photoFormat = "<div class=\"photo-icon photo-round photo-round-xs pull-left margin-r-sm js-person-popover\" personid=\"{0}\" data-original=\"{1}&w=50\" style=\"background-image: url( '{2}' ); background-size: cover; background-repeat: no-repeat;\"></div>";

                    gGroupMembers.DataSource = groupMembersList.Select(m => new
                    {
                        m.Id,
                        m.Guid,
                        m.PersonId,
                        m.Person.NickName,
                        m.Person.LastName,
                        Name =
                            (selectAll ? m.Person.LastName + ", " + m.Person.NickName : string.Format(photoFormat, m.PersonId, m.Person.PhotoUrl, ResolveUrl("~/Assets/Images/person-no-photo-male.svg")) +
                             m.Person.NickName + " " + m.Person.LastName
                             + (hasGroupRequirements && groupMemberIdsThatLackGroupRequirements.Contains(m.Id)
                                ? " <i class='fa fa-exclamation-triangle text-warning'></i>"
                                : string.Empty)
                             + (!string.IsNullOrEmpty(m.Note)
                            ? " <i class='fa fa-file-text-o text-info'></i>"
                            : string.Empty)),
                        m.Person.ConnectionStatusValueId,
                        Email     = m.Person.Email,
                        HomePhone = selectAll && homePhoneType != null ?
                                    m.Person.PhoneNumbers
                                    .Where(p => p.NumberTypeValueId.HasValue && p.NumberTypeValueId.Value == homePhoneType.Id)
                                    .Select(p => p.NumberFormatted)
                                    .FirstOrDefault() : string.Empty,
                        CellPhone = selectAll && cellPhoneType != null ?
                                    m.Person.PhoneNumbers
                                    .Where(p => p.NumberTypeValueId.HasValue && p.NumberTypeValueId.Value == cellPhoneType.Id)
                                    .Select(p => p.NumberFormatted)
                                    .FirstOrDefault() : string.Empty,
                        HomeAddress = homeLocations.ContainsKey(m.Id) && homeLocations[m.Id] != null ?
                                      homeLocations[m.Id].FormattedAddress : string.Empty,
                        Latitude = homeLocations.ContainsKey(m.Id) && homeLocations[m.Id] != null ?
                                   homeLocations[m.Id].Latitude : (double?)null,
                        Longitude = homeLocations.ContainsKey(m.Id) && homeLocations[m.Id] != null ?
                                    homeLocations[m.Id].Longitude : (double?)null,
                        GroupRole = m.GroupRole.Name,
                        m.GroupMemberStatus,
                        RecordStatusValueId = m.Person.RecordStatusValueId,
                        IsDeceased          = m.Person.IsDeceased
                    }).ToList();

                    gGroupMembers.DataBind();
                }
                else
                {
                    nbRoleWarning.Text = string.Format(
                        "{0} cannot be added to this {1} because the '{2}' group type does not have any roles defined.",
                        _group.GroupType.GroupMemberTerm.Pluralize(),
                        _group.GroupType.GroupTerm,
                        _group.GroupType.Name);

                    nbRoleWarning.Visible = true;
                    rFilter.Visible       = false;
                    gGroupMembers.Visible = false;
                }
            }
            else
            {
                pnlGroupMembers.Visible = false;
            }
        }
示例#10
0
        /// <summary>
        /// Groups the members not meeting requirements.
        /// </summary>
        /// <param name="groupId">The group identifier.</param>
        /// <param name="includeWarnings">if set to <c>true</c> [include warnings].</param>
        /// <returns></returns>
        public Dictionary<GroupMember, Dictionary<PersonGroupRequirementStatus, DateTime>> GroupMembersNotMeetingRequirements( int groupId, bool includeWarnings )
        {
            Dictionary<GroupMember, Dictionary<PersonGroupRequirementStatus, DateTime>> results = new Dictionary<GroupMember, Dictionary<PersonGroupRequirementStatus, DateTime>>();

            var rockContext = this.Context as RockContext;
            var groupRequirementService = new GroupRequirementService( rockContext );
            var groupMemberService = new GroupMemberService( rockContext );
            var groupMemberRequirementService = new GroupMemberRequirementService( rockContext );

            var qryGroupRequirements = groupRequirementService.Queryable().Where( a => a.GroupId == groupId );
            bool hasGroupRequirements = qryGroupRequirements.Any();
            if ( !hasGroupRequirements )
            {
                // if no group requirements, then there are no members that don't meet the requirements, so return an empty dictionary
                return new Dictionary<GroupMember, Dictionary<PersonGroupRequirementStatus, DateTime>>();
            }

            var qryGroupMembers = groupMemberService.Queryable().Where( a => a.GroupId == groupId );
            var qryGroupMemberRequirements = groupMemberRequirementService.Queryable().Where( a => a.GroupMember.GroupId == groupId );

            // get a list of group member ids that don't meet all the requirements
            IQueryable<int> qryGroupMemberIdsThatLackGroupRequirements = qryGroupMembers.Where(
                                a => !qryGroupRequirements.Select(x => x.Id).All(
                                    r => a.GroupMemberRequirements.Where( mr => mr.RequirementMetDateTime.HasValue ).Select( x => x.GroupRequirementId ).Contains( r ) ) ).Select(a => a.Id);

            IQueryable<GroupMember> qryMembersWithIssues;

            if ( includeWarnings )
            {
                IQueryable<int> qryGroupMemberIdsWithRequirementWarnings = qryGroupMemberRequirements.Where( a => a.RequirementWarningDateTime != null || a.RequirementFailDateTime != null ).Select( a => a.GroupMemberId ).Distinct();
                qryMembersWithIssues = qryGroupMembers.Where( a => qryGroupMemberIdsThatLackGroupRequirements.Contains( a.Id ) || qryGroupMemberIdsWithRequirementWarnings.Contains( a.Id ) );
            }
            else
            {
                qryMembersWithIssues = qryGroupMembers.Where( a => qryGroupMemberIdsThatLackGroupRequirements.Contains( a.Id ) );
            }

            var qry = qryMembersWithIssues.Select( a => new
            {
                GroupMember = a,
                GroupRequirementStatuses = qryGroupMemberRequirements.Where( x => x.GroupMemberId == a.Id )
            } );

            var currentDateTime = RockDateTime.Now;

            foreach (var groupMemberWithIssues in qry)
            {
                Dictionary<PersonGroupRequirementStatus, DateTime> statuses = new Dictionary<PersonGroupRequirementStatus, DateTime>();

                // populate where the status is known
                foreach ( var requirementStatus in groupMemberWithIssues.GroupRequirementStatuses )
                {
                    PersonGroupRequirementStatus status = new PersonGroupRequirementStatus();
                    status.GroupRequirement = requirementStatus.GroupRequirement;
                    status.PersonId = groupMemberWithIssues.GroupMember.PersonId;

                    DateTime occuranceDate = new DateTime();

                    if ( requirementStatus.RequirementMetDateTime == null)
                    {
                        status.MeetsGroupRequirement = MeetsGroupRequirement.NotMet;
                        occuranceDate = requirementStatus.RequirementFailDateTime ?? currentDateTime;
                    }
                    else if (requirementStatus.RequirementWarningDateTime.HasValue)
                    {
                        status.MeetsGroupRequirement = MeetsGroupRequirement.MeetsWithWarning;
                        occuranceDate = requirementStatus.RequirementWarningDateTime.Value;
                    }
                    else
                    {
                        status.MeetsGroupRequirement = MeetsGroupRequirement.Meets;
                        occuranceDate = requirementStatus.RequirementMetDateTime.Value;
                    }

                    statuses.Add( status, occuranceDate );
                }

                // also add any groupRequirements that they don't have statuses for (and therefore haven't met)
                foreach (var groupRequirement in qryGroupRequirements)
                {
                    if ( !statuses.Any( x => x.Key.GroupRequirement.Id == groupRequirement.Id) )
                    {
                        PersonGroupRequirementStatus status = new PersonGroupRequirementStatus();
                        status.GroupRequirement = groupRequirement;
                        status.PersonId = groupMemberWithIssues.GroupMember.PersonId;
                        status.MeetsGroupRequirement = MeetsGroupRequirement.NotMet;
                        statuses.Add( status, currentDateTime );
                    }
                }

                var statusesWithIssues = statuses.Where( a => a.Key.MeetsGroupRequirement != MeetsGroupRequirement.Meets ).ToDictionary( k => k.Key, v => v.Value );

                if ( statusesWithIssues.Any() )
                {
                    results.Add( groupMemberWithIssues.GroupMember, statusesWithIssues );
                }
            }

            return results;
        }