protected void attendanceDelete_Click(object sender, RowEventArgs e) { RockContext editContext = new RockContext(); AttendanceService editAttServe = new AttendanceService(editContext); var attendItem = editAttServe.Queryable().Where(x => x.Id == e.RowKeyId).FirstOrDefault(); if (attendItem.IsAuthorized("Edit", CurrentPerson)) { attendItem.DidAttend = !attendItem.DidAttend; attendItem.DidNotOccur = !attendItem.DidAttend; editContext.SaveChanges(); } _rockContext = new RockContext(); attendServ = new AttendanceService(_rockContext); doStuff(); }
/// <summary> /// Handles the Click event of the lbSave 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 lbSave_Click( object sender, EventArgs e ) { if ( _group != null && _occurrence != null ) { var rockContext = new RockContext(); var attendanceService = new AttendanceService( rockContext ); var personAliasService = new PersonAliasService( rockContext ); var locationService = new LocationService( rockContext ); bool dateAdjusted = false; DateTime startDate = _occurrence.Date; // If this is a manuall entered occurrence, check to see if date was changed if ( !_occurrence.ScheduleId.HasValue ) { DateTime? originalDate = PageParameter( "Date" ).AsDateTime(); if ( originalDate.HasValue && originalDate.Value.Date != startDate.Date ) { startDate = originalDate.Value.Date; dateAdjusted = true; } } DateTime endDate = startDate.AddDays( 1 ); var existingAttendees = attendanceService .Queryable( "PersonAlias" ) .Where( a => a.GroupId == _group.Id && a.LocationId == _occurrence.LocationId && a.ScheduleId == _occurrence.ScheduleId && a.StartDateTime >= startDate && a.StartDateTime < endDate ); if ( dateAdjusted ) { foreach ( var attendee in existingAttendees ) { attendee.StartDateTime = _occurrence.Date; } } // If did not meet was selected and this was a manually entered occurrence (not based on a schedule/location) // then just delete all the attendance records instead of tracking a 'did not meet' value if ( cbDidNotMeet.Checked && !_occurrence.ScheduleId.HasValue ) { foreach ( var attendance in existingAttendees ) { attendanceService.Delete( attendance ); } } else { int? campusId = locationService.GetCampusIdForLocation( _occurrence.LocationId ); if ( !campusId.HasValue ) { campusId = _group.CampusId; } if ( !campusId.HasValue && _allowCampusFilter ) { var campus = CampusCache.Read( bddlCampus.SelectedValueAsInt() ?? 0 ); if ( campus != null ) { campusId = campus.Id; } } if ( cbDidNotMeet.Checked ) { // If the occurrence is based on a schedule, set the did not meet flags foreach ( var attendance in existingAttendees ) { attendance.DidAttend = null; attendance.DidNotOccur = true; } } foreach ( var attendee in _attendees ) { var attendance = existingAttendees .Where( a => a.PersonAlias.PersonId == attendee.PersonId ) .FirstOrDefault(); if ( attendance == null ) { int? personAliasId = personAliasService.GetPrimaryAliasId( attendee.PersonId ); if ( personAliasId.HasValue ) { attendance = new Attendance(); attendance.GroupId = _group.Id; attendance.ScheduleId = _group.ScheduleId; attendance.PersonAliasId = personAliasId; attendance.StartDateTime = _occurrence.Date.Date.Add( _occurrence.StartTime ); attendance.LocationId = _occurrence.LocationId; attendance.CampusId = campusId; attendance.ScheduleId = _occurrence.ScheduleId; // check that the attendance record is valid cvAttendance.IsValid = attendance.IsValid; if ( !cvAttendance.IsValid ) { cvAttendance.ErrorMessage = attendance.ValidationResults.Select( a => a.ErrorMessage ).ToList().AsDelimited( "<br />" ); return; } attendanceService.Add( attendance ); } } if ( attendance != null ) { if ( cbDidNotMeet.Checked ) { attendance.DidAttend = null; attendance.DidNotOccur = true; } else { attendance.DidAttend = attendee.Attended; attendance.DidNotOccur = null; } } } } if ( _occurrence.LocationId.HasValue ) { Rock.CheckIn.KioskLocationAttendance.Flush( _occurrence.LocationId.Value ); } rockContext.SaveChanges(); WorkflowType workflowType = null; Guid? workflowTypeGuid = GetAttributeValue( "Workflow" ).AsGuidOrNull(); if ( workflowTypeGuid.HasValue ) { var workflowTypeService = new WorkflowTypeService( rockContext ); workflowType = workflowTypeService.Get( workflowTypeGuid.Value ); if ( workflowType != null ) { try { var workflow = Workflow.Activate( workflowType, _group.Name ); workflow.SetAttributeValue( "StartDateTime", _occurrence.Date.ToString( "o" ) ); workflow.SetAttributeValue( "Schedule", _group.Schedule.Guid.ToString() ); List<string> workflowErrors; new WorkflowService( rockContext ).Process( workflow, _group, out workflowErrors ); } catch ( Exception ex ) { ExceptionLogService.LogException( ex, this.Context ); } } } var qryParams = new Dictionary<string, string> { { "GroupId", _group.Id.ToString() } }; var groupTypeIds = PageParameter( "GroupTypeIds" ); if ( !string.IsNullOrWhiteSpace( groupTypeIds ) ) { qryParams.Add( "GroupTypeIds", groupTypeIds ); } NavigateToParentPage( qryParams ); } }
/// <summary> /// Gets the chart data. /// </summary> /// <returns></returns> private IEnumerable<Rock.Chart.IChartData> GetAttendanceChartData() { var dateRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues( drpSlidingDateRange.DelimitedValues ); string groupIds = GetSelectedGroupIds().AsDelimited( "," ); var selectedCampusIds = clbCampuses.SelectedValues; string campusIds = selectedCampusIds.AsDelimited( "," ); var chartData = new AttendanceService( _rockContext ).GetChartData( hfGroupBy.Value.ConvertToEnumOrNull<ChartGroupBy>() ?? ChartGroupBy.Week, hfGraphBy.Value.ConvertToEnumOrNull<AttendanceGraphBy>() ?? AttendanceGraphBy.Total, dateRange.Start, dateRange.End, groupIds, campusIds, dvpDataView.SelectedValueAsInt() ); return chartData; }
/// <summary> /// Binds the grid. /// </summary> protected void BindGrid() { var rockContext = new RockContext(); var attendanceService = new AttendanceService( rockContext ); var qryAttendance = attendanceService.Queryable(); var personField = gHistory.Columns.OfType<PersonField>().FirstOrDefault(); if ( personField != null ) { personField.Visible = _person == null; } var groupField = gHistory.Columns.OfType<RockBoundField>().FirstOrDefault( a => a.HeaderText == "Group" ); if ( groupField != null ) { groupField.Visible = _group == null; } if ( _person != null ) { qryAttendance = qryAttendance.Where( a => a.PersonAlias.PersonId == _person.Id ); if ( _group != null ) { qryAttendance = qryAttendance.Where( a => a.GroupId == _group.Id ); } else { int? groupId = ddlAttendanceGroup.SelectedValueAsInt(); if ( groupId.HasValue ) { qryAttendance = qryAttendance.Where( a => a.GroupId == groupId.Value ); } } } else { int? personId = ppPerson.SelectedValue; if ( personId.HasValue ) { qryAttendance = qryAttendance.Where( a => a.PersonAlias.PersonId == personId.Value ); } } // Filter by Date Range if ( drpDates.LowerValue.HasValue ) { qryAttendance = qryAttendance.Where( t => t.StartDateTime >= drpDates.LowerValue.Value ); } if ( drpDates.UpperValue.HasValue ) { DateTime upperDate = drpDates.UpperValue.Value.Date.AddDays( 1 ); qryAttendance = qryAttendance.Where( t => t.StartDateTime < upperDate ); } // Filter by Schedule int? scheduleId = spSchedule.SelectedValue.AsIntegerOrNull(); if ( scheduleId.HasValue && scheduleId.Value > 0 ) { qryAttendance = qryAttendance.Where( h => h.ScheduleId == scheduleId.Value ); } // Filter by DidAttend int? didAttend = ddlDidAttend.SelectedValueAsInt( false ); if ( didAttend.HasValue ) { if ( didAttend.Value == 1 ) { qryAttendance = qryAttendance.Where( a => a.DidAttend == true ); } else { qryAttendance = qryAttendance.Where( a => a.DidAttend == false ); } } var qry = qryAttendance .Select( a => new { LocationId = a.LocationId, LocationName = a.Location.Name, CampusId = a.CampusId, CampusName = a.Campus.Name, ScheduleName = a.Schedule.Name, Person = a.PersonAlias.Person, GroupName = a.Group.Name, GroupTypeId = a.Group.GroupTypeId, StartDateTime = a.StartDateTime, EndDateTime = a.EndDateTime, DidAttend = a.DidAttend } ); SortProperty sortProperty = gHistory.SortProperty; if ( sortProperty != null ) { qry = qry.Sort( sortProperty ); } else { qry = qry.OrderByDescending( p => p.StartDateTime ); } // build a lookup for _groupTypePaths for OnRowDatabound _groupTypePaths = new GroupTypeService( rockContext ).GetAllCheckinGroupTypePaths().ToList(); // build a lookup for _locationpaths for OnRowDatabound _locationPaths = new Dictionary<int, string>(); var qryLocations = new LocationService( rockContext ).Queryable().Where( a => qry.Any( b => b.LocationId == a.Id ) ); foreach (var location in qryLocations) { var parentLocation = location.ParentLocation; var locationNames = new List<string>(); while (parentLocation != null) { locationNames.Add( parentLocation.Name ); parentLocation = parentLocation.ParentLocation; } string locationPath = string.Empty; if ( locationNames.Any() ) { locationNames.Reverse(); locationPath = locationNames.AsDelimited( " > " ); } _locationPaths.AddOrIgnore( location.Id, locationPath ); } gHistory.EntityTypeId = EntityTypeCache.Read<Attendance>().Id; gHistory.DataSource = qry.ToList(); gHistory.DataBind(); }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="action">The workflow action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> public override bool Execute( Model.WorkflowAction action, Object entity, out List<string> errorMessages ) { var checkInState = GetCheckInState( entity, out errorMessages ); if ( checkInState != null ) { DateTime sixMonthsAgo = DateTime.Today.AddMonths( -6 ); var attendanceService = new AttendanceService(); foreach ( var family in checkInState.CheckIn.Families.Where( f => f.Selected ) ) { foreach ( var person in family.People ) { foreach ( var groupType in person.GroupTypes ) { var groupTypeCheckIns = attendanceService.Queryable() .Where( a => a.PersonId == person.Person.Id && a.Group.GroupTypeId == groupType.GroupType.Id && a.StartDateTime >= sixMonthsAgo ) .ToList(); if ( groupTypeCheckIns.Any() ) { groupType.LastCheckIn = groupTypeCheckIns.Select( a => a.StartDateTime ).Max(); foreach ( var group in groupType.Groups ) { var groupCheckIns = groupTypeCheckIns.Where( a => a.GroupId == group.Group.Id ).ToList(); if ( groupCheckIns.Any() ) { group.LastCheckIn = groupCheckIns.Select( a => a.StartDateTime ).Max(); } foreach ( var location in group.Locations ) { var locationCheckIns = groupCheckIns.Where( a => a.LocationId == location.Location.Id ).ToList(); if ( locationCheckIns.Any() ) { location.LastCheckIn = locationCheckIns.Select( a => a.StartDateTime ).Max(); } foreach ( var schedule in location.Schedules ) { var scheduleCheckIns = locationCheckIns.Where( a => a.ScheduleId == schedule.Schedule.Id ).ToList(); if ( scheduleCheckIns.Any() ) { schedule.LastCheckIn = scheduleCheckIns.Select( a => a.StartDateTime ).Max(); } } } } } } if ( person.GroupTypes.Any() ) { person.LastCheckIn = person.GroupTypes.Select( g => g.LastCheckIn ).Max(); } } } return true; } return false; }
protected void bindGrid() { if ( String.IsNullOrWhiteSpace( CheckinCode ) ) { ShowPanel( 0 ); } else { rlCheckinCode.Text = CheckinCode + " <a href='?'><i class='fa fa-times'></i></a>"; if ( !SelectedAttendanceGuid.IsEmpty() ) { ShowPanel( 2 ); var SelectedAttendance = new AttendanceService( rockContext ).Get( SelectedAttendanceGuid ); SelectedAttendance.LoadAttributes(); var attSearch = SelectedAttendance.GetAttributeValue( "SearchValue" ); var hasSearch = !String.IsNullOrWhiteSpace( attSearch ); if ( hasSearch ) attSearch = attSearch.AsNumeric(); var SelectedPerson = SelectedAttendance.PersonAlias.Person; rlSelectedPerson.Text = SelectedPerson.FullName + " <a href='?CheckinCode=" + CheckinCode + "'><i class='fa fa-times'></i></a>"; var groupRoleServ = new GroupTypeRoleService( rockContext ); var knownRelationship_GroupMemberships = new GroupMemberService( rockContext ).Queryable() .Where( gm => gm.Group.GroupTypeId == 11 && gm.PersonId == SelectedPerson.Id ); var shownRelationships = GetAttributeValue( "IncludedRelationships" ).Split( ',' ).Select( g => g.AsGuid() ); gReleventPeople.DataSource = SelectedPerson.GetFamilyMembers( false, rockContext ) .Select( m => new { Person = m.Person, Role = m.GroupRole, Priority = 100 } ) .ToList() .Union( knownRelationship_GroupMemberships .Where( gm => gm.GroupRole.Guid == GUID_OwnerRole ) .SelectMany( gm => gm.Group.Members.Where( gm2 => gm2.PersonId != SelectedPerson.Id ) ) .ToList() .Select( gm => new { Person = gm.Person, Role = GetInverseRole( gm.GroupRole, groupRoleServ ), Priority = 50 } ) ) .Union( knownRelationship_GroupMemberships .Where( gm => gm.GroupRole.Guid != GUID_OwnerRole ) .Select( gm => new { Person = gm.Group.Members.Where( gm2 => gm2.GroupRole.Guid == GUID_OwnerRole ).FirstOrDefault().Person, Role = gm.GroupRole, Priority = 40 } ).ToList() ) .Where( r => shownRelationships.Contains( r.Role.Guid ) ) .GroupBy( x => x.Person ) .Select( x => new PersonRelationship { PersonAliasGuid = x.Key.PrimaryAlias.Guid, FullName = x.Key.FullName, Roles = String.Join( " ,", x.Select( y => y.Role.Name ) ), Priority = x.Select( y => y.Priority ).Max(), HomePhone = GetFormatedNumber( x.Key, GUID_HomePhone ), MobilePhone = GetFormatedNumber( x.Key, GUID_MobilePhone ), Highlight = hasSearch && x.Key.PhoneNumbers.Any( y => y.Number.Contains( attSearch ) ) } ) .OrderByDescending( r => r.Priority + ( r.Highlight ? 100 : 0) ); gReleventPeople.DataKeyNames = new string[] { "PersonAliasGuid" }; gReleventPeople.DataBind(); } else { ShowPanel( 1 ); int daysBacktoSearch = GetAttributeValue( "DaysBacktoSearch" ).AsInteger(); var searchDate = DateTime.Now.Date.AddDays( -daysBacktoSearch ); gSearchResults.SetLinqDataSource( new AttendanceCodeService( rockContext ) .Queryable() .Where( c => c.Code == CheckinCode && c.IssueDateTime > searchDate ) .SelectMany( c => c.Attendances ) .OrderByDescending( "StartDateTime" ) ); gSearchResults.DataKeyNames = new string[] { "Guid" }; gSearchResults.DataBind(); } } }
/// <summary> /// Reads the specified id. /// </summary> /// <param name="id">The id.</param> /// <returns></returns> public static KioskLocationAttendance Read( int id ) { string cacheKey = KioskLocationAttendance.CacheKey( id ); ObjectCache cache = MemoryCache.Default; KioskLocationAttendance locationAttendance = cache[cacheKey] as KioskLocationAttendance; if ( locationAttendance != null ) { return locationAttendance; } else { var rockContext = new Rock.Data.RockContext(); var location = new LocationService(rockContext).Get( id ); if ( location != null ) { locationAttendance = new KioskLocationAttendance(); locationAttendance.LocationId = location.Id; locationAttendance.LocationName = location.Name; locationAttendance.Groups = new List<KioskGroupAttendance>(); var attendanceService = new AttendanceService(rockContext); foreach ( var attendance in attendanceService.GetByDateAndLocation( RockDateTime.Today, location.Id ) ) { AddAttendanceRecord( locationAttendance, attendance ); } var cachePolicy = new CacheItemPolicy(); cachePolicy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds( 60 ); cache.Set( cacheKey, locationAttendance, cachePolicy ); return locationAttendance; } } return null; }
/// <summary> /// Binds the grid. /// </summary> protected void BindGrid() { var attendanceService = new AttendanceService( new RockContext() ); var attendanceQuery = attendanceService.Queryable(); if ( _person != null ) { attendanceQuery = attendanceQuery.Where( a => a.PersonId == _person.Id ); } else if ( _group != null ) { attendanceQuery = attendanceQuery.Where( a => a.GroupId == _group.Id ); } var attendanceList = attendanceQuery.ToList(); var qry = attendanceList.AsQueryable() .Select( a => new { Location = a.Location, Schedule = a.Schedule, FullName = a.Person.FullName, Group = a.Group, StartDateTime = a.StartDateTime, EndDateTime = a.EndDateTime } ); // Filter by Date Range var drp = new DateRangePicker(); drp.DelimitedValues = rFilter.GetUserPreference( "Date Range" ); if ( drp.LowerValue.HasValue ) { qry = qry.Where( t => t.StartDateTime >= drp.LowerValue.Value ); } if ( drp.UpperValue.HasValue ) { DateTime upperDate = drp.UpperValue.Value.Date.AddDays( 1 ); qry = qry.Where( t => t.EndDateTime < upperDate ); } // Filter by Person if ( ddlPeople.SelectedIndex > 0 ) { if ( ddlPeople.SelectedValue.ToLower() != "all" ) { qry = qry.Where( h => h.FullName == ddlPeople.SelectedValue ); } } // Filter by Group if ( ddlGroups.SelectedIndex > 0 ) { if ( ddlGroups.SelectedValue.ToLower() != "all" ) { qry = qry.Where( h => h.Group.Name == ddlGroups.SelectedValue ); } } // Filter by Schedule if ( ddlSchedules.SelectedIndex > 0 ) { if ( ddlSchedules.SelectedValue.ToLower() != "all" ) { qry = qry.Where( h => h.Schedule.Name == ddlSchedules.SelectedValue ); } } SortProperty sortProperty = gHistory.SortProperty; if ( sortProperty != null ) { qry = qry.Sort( sortProperty ); } else { qry = qry.OrderByDescending( p => p.StartDateTime ); } gHistory.DataSource = qry.ToList(); gHistory.DataBind(); }
/// <summary> /// Gets occurrence data for the selected group /// </summary> /// <param name="group">The group.</param> /// <param name="fromDateTime">From date time.</param> /// <param name="toDateTime">To date time.</param> /// <param name="locationIds">The location ids.</param> /// <param name="scheduleIds">The schedule ids.</param> /// <param name="loadSummaryData">if set to <c>true</c> [load summary data].</param> /// <returns></returns> public List<ScheduleOccurrence> GetGroupOccurrences( Group group, DateTime? fromDateTime, DateTime? toDateTime, List<int> locationIds, List<int> scheduleIds, bool loadSummaryData ) { var occurrences = new List<ScheduleOccurrence>(); if ( group != null ) { var rockContext = (RockContext)this.Context; var attendanceService = new AttendanceService( rockContext ); var scheduleService = new ScheduleService( rockContext ); var locationService = new LocationService( rockContext ); // Set up an 'occurrences' query for the group var qry = attendanceService .Queryable().AsNoTracking() .Where( a => a.GroupId == group.Id ); // Filter by date range if ( fromDateTime.HasValue ) { var fromDate = fromDateTime.Value.Date; qry = qry.Where( a => DbFunctions.TruncateTime( a.StartDateTime ) >= ( fromDate ) ); } if ( toDateTime.HasValue ) { var toDate = toDateTime.Value.Date; qry = qry.Where( a => DbFunctions.TruncateTime( a.StartDateTime ) < ( toDate ) ); } // Location Filter if ( locationIds.Any() ) { qry = qry.Where( a => a.LocationId.HasValue && locationIds.Contains( a.LocationId.Value ) ); } // Schedule Filter if ( scheduleIds.Any() ) { qry = qry.Where( a => a.ScheduleId.HasValue && scheduleIds.Contains( a.ScheduleId.Value ) ); } // Get the unique combination of location/schedule/date for the selected group var occurrenceDates = qry .Select( a => new { a.LocationId, a.ScheduleId, Date = DbFunctions.TruncateTime( a.StartDateTime ) } ) .Distinct() .ToList(); // Get the locations for each unique location id var selectedlocationIds = occurrenceDates.Select( o => o.LocationId ).Distinct().ToList(); var locations = locationService .Queryable().AsNoTracking() .Where( l => selectedlocationIds.Contains( l.Id ) ) .Select( l => new { l.Id, l.ParentLocationId, l.Name } ) .ToList(); var locationNames = new Dictionary<int, string>(); locations.ForEach( l => locationNames.Add( l.Id, l.Name ) ); // Get the parent location path for each unique location var parentlocationPaths = new Dictionary<int, string>(); locations .Where( l => l.ParentLocationId.HasValue ) .Select( l => l.ParentLocationId.Value ) .Distinct() .ToList() .ForEach( l => parentlocationPaths.Add( l, locationService.GetPath( l ) ) ); var locationPaths = new Dictionary<int, string>(); locations .Where( l => l.ParentLocationId.HasValue ) .ToList() .ForEach( l => locationPaths.Add( l.Id, parentlocationPaths[l.ParentLocationId.Value] ) ); // Get the schedules for each unique schedule id var selectedScheduleIds = occurrenceDates.Select( o => o.ScheduleId ).Distinct().ToList(); var schedules = scheduleService .Queryable().AsNoTracking() .Where( s => selectedScheduleIds.Contains( s.Id ) ) .ToList(); var scheduleNames = new Dictionary<int, string>(); var scheduleStartTimes = new Dictionary<int, TimeSpan>(); schedules .ForEach( s => { scheduleNames.Add( s.Id, s.Name ); scheduleStartTimes.Add( s.Id, s.StartTimeOfDay ); }); foreach ( var occurrence in occurrenceDates.Where( o => o.Date.HasValue ) ) { occurrences.Add( new ScheduleOccurrence( occurrence.Date.Value, occurrence.ScheduleId.HasValue && scheduleStartTimes.ContainsKey( occurrence.ScheduleId.Value ) ? scheduleStartTimes[occurrence.ScheduleId.Value] : new TimeSpan(), occurrence.ScheduleId, occurrence.ScheduleId.HasValue && scheduleNames.ContainsKey( occurrence.ScheduleId.Value ) ? scheduleNames[occurrence.ScheduleId.Value] : string.Empty, occurrence.LocationId, occurrence.LocationId.HasValue && locationNames.ContainsKey( occurrence.LocationId.Value ) ? locationNames[occurrence.LocationId.Value] : string.Empty, occurrence.LocationId.HasValue && locationPaths.ContainsKey( occurrence.LocationId.Value ) ? locationPaths[occurrence.LocationId.Value] : string.Empty ) ); } // Load the attendance data for each occurrence if ( loadSummaryData && occurrences.Any()) { var minDate = occurrences.Min( o => o.Date ); var maxDate = occurrences.Max( o => o.Date ).AddDays( 1 ); foreach( var summary in attendanceService .Queryable().AsNoTracking() .Where( a => a.PersonAliasId.HasValue && a.GroupId.HasValue && a.GroupId == group.Id && a.StartDateTime >= minDate && a.StartDateTime < maxDate ) .GroupBy( a => new { a.LocationId, a.ScheduleId, Date = DbFunctions.TruncateTime( a.StartDateTime ) } ) .Select( a => new { a.Key.LocationId, a.Key.ScheduleId, a.Key.Date, DidAttendCount = a .Where( t => t.DidAttend.HasValue && t.DidAttend.Value ) .Select( t => t.PersonAliasId.Value ) .Distinct() .Count(), DidNotOccurCount = a .Where( t => t.DidNotOccur.HasValue && t.DidNotOccur.Value ) .Select( t => t.PersonAliasId.Value ) .Distinct() .Count(), TotalCount = a .Select( t => t.PersonAliasId ) .Distinct() .Count() } ) ) { var occurrence = occurrences .Where( o => o.ScheduleId.Equals( summary.ScheduleId ) && o.LocationId.Equals( summary.LocationId ) && o.Date.Equals( summary.Date ) ) .FirstOrDefault(); if ( occurrence != null ) { occurrence.DidAttendCount = summary.DidAttendCount; occurrence.DidNotOccurCount = summary.DidNotOccurCount; occurrence.TotalCount = summary.TotalCount; } } } // Create any missing occurrences from the group's schedule (not location schedules) Schedule groupSchedule = null; if ( group.ScheduleId.HasValue ) { groupSchedule = group.Schedule; if ( groupSchedule == null ) { groupSchedule = new ScheduleService( rockContext ).Get( group.ScheduleId.Value ); } } if ( groupSchedule != null ) { var newOccurrences = new List<ScheduleOccurrence>(); var existingDates = occurrences .Where( o => o.ScheduleId.Equals( groupSchedule.Id ) ) .Select( o => o.Date ) .Distinct() .ToList(); var startDate = fromDateTime.HasValue ? fromDateTime.Value : RockDateTime.Today.AddMonths( -2 ); var endDate = toDateTime.HasValue ? toDateTime.Value : RockDateTime.Today.AddDays( 1 ); DDay.iCal.Event calEvent = groupSchedule.GetCalenderEvent(); if ( calEvent != null ) { // If schedule has an iCal schedule, get all the past occurrences foreach ( var occurrence in calEvent.GetOccurrences( startDate, endDate ) ) { var scheduleOccurrence = new ScheduleOccurrence( occurrence.Period.StartTime.Date, occurrence.Period.StartTime.TimeOfDay, groupSchedule.Id, groupSchedule.Name ); if ( !existingDates.Contains( scheduleOccurrence.Date ) ) { newOccurrences.Add( scheduleOccurrence ); } } } else { // if schedule does not have an iCal, then check for weekly schedule and calculate occurrences starting with first attendance or current week if ( groupSchedule.WeeklyDayOfWeek.HasValue ) { // default to start with date 2 months earlier startDate = fromDateTime.HasValue ? fromDateTime.Value : RockDateTime.Today.AddMonths( -2 ); if ( existingDates.Any( d => d < startDate ) ) { startDate = existingDates.Min(); } // Back up start time to the correct day of week while ( startDate.DayOfWeek != groupSchedule.WeeklyDayOfWeek.Value ) { startDate = startDate.AddDays( -1 ); } // Add the start time if ( groupSchedule.WeeklyTimeOfDay.HasValue ) { startDate = startDate.Add( groupSchedule.WeeklyTimeOfDay.Value ); } // Create occurrences up to current time while ( startDate < endDate ) { if ( !existingDates.Contains( startDate.Date ) ) { var scheduleOccurrence = new ScheduleOccurrence( startDate.Date, startDate.TimeOfDay, groupSchedule.Id, groupSchedule.Name ); newOccurrences.Add( scheduleOccurrence ); } startDate = startDate.AddDays( 7 ); } } } if ( newOccurrences.Any() ) { // Filter Exclusions var groupType = GroupTypeCache.Read( group.GroupTypeId ); foreach ( var exclusion in groupType.GroupScheduleExclusions ) { if ( exclusion.Start.HasValue && exclusion.End.HasValue ) { foreach ( var occurrence in newOccurrences.ToList() ) { if ( occurrence.Date >= exclusion.Start.Value && occurrence.Date < exclusion.End.Value.AddDays( 1 ) ) { newOccurrences.Remove( occurrence ); } } } } } foreach( var occurrence in newOccurrences ) { occurrences.Add( occurrence ); } } } return occurrences; }
/// <summary> /// Loads the attendance data. /// </summary> /// <param name="group">The group.</param> /// <param name="occurrence">The occurrence.</param> public void LoadSummaryData( Group group, ScheduleOccurrence occurrence ) { if ( group != null && occurrence != null ) { var attendances = new AttendanceService( (RockContext)this.Context ) .Queryable().AsNoTracking() .Where( a => a.PersonAliasId.HasValue && a.GroupId.HasValue && a.GroupId == group.Id && a.LocationId.Equals( occurrence.LocationId ) && a.ScheduleId.Equals( occurrence.ScheduleId ) && DbFunctions.TruncateTime( a.StartDateTime ).Equals( occurrence.Date ) ) .ToList(); if ( attendances.Any() ) { occurrence.DidAttendCount = attendances .Where( t => t.DidAttend.HasValue && t.DidAttend.Value ) .Select( t => t.PersonAliasId.Value ) .Distinct() .Count(); occurrence.DidNotOccurCount = attendances .Where( t => t.DidNotOccur.HasValue && t.DidNotOccur.Value ) .Select( t => t.PersonAliasId.Value ) .Distinct() .Count(); occurrence.TotalCount = attendances .Select( t => t.PersonAliasId ) .Distinct() .Count(); } } }
protected void btnSave_Click(object sender, EventArgs e) { btnDone.Visible = true; lblPeople.Visible = true; //Create List to Save Registered People var peopleList = new List<string>(); if (Session["peopleList"] != null) { peopleList = (List<string>)Session["peopleList"]; } AttendanceCodeService attendanceCodeService = new AttendanceCodeService(rockContext); AttendanceService attendanceService = new AttendanceService(rockContext); GroupMemberService groupMemberService = new GroupMemberService(rockContext); PersonAliasService personAliasService = new PersonAliasService(rockContext); Session["person"] = ppPerson.SelectedValue.ToString(); // Only create one attendance record per day for each person/schedule/group/location DateTime theTime = Convert.ToDateTime(Session["startDateTime"]); var attendance = attendanceService.Get(theTime, int.Parse(Session["location"].ToString()), int.Parse(Session["schedule"].ToString()), int.Parse(Session["group"].ToString()), int.Parse(ppPerson.SelectedValue.ToString())); var primaryAlias = personAliasService.GetPrimaryAlias(int.Parse(ppPerson.SelectedValue.ToString())); if (attendance == null) { if (primaryAlias != null) { attendance = rockContext.Attendances.Create(); attendance.LocationId = int.Parse(Session["location"].ToString()); attendance.CampusId = int.Parse(Session["campus"].ToString()); attendance.ScheduleId = int.Parse(Session["schedule"].ToString()); attendance.GroupId = int.Parse(Session["group"].ToString()); attendance.PersonAlias = primaryAlias; attendance.PersonAliasId = primaryAlias.Id; attendance.DeviceId = null; attendance.SearchTypeValueId = 1; attendanceService.Add(attendance); } } attendance.AttendanceCodeId = null; attendance.StartDateTime = Convert.ToDateTime(Session["startDateTime"]); attendance.EndDateTime = null; attendance.DidAttend = true; //KioskLocationAttendance.AddAttendance(attendance); rockContext.SaveChanges(); //Add Person to Dictionary peopleList.Add( ppPerson.PersonName ); repLinks.DataSource = peopleList; repLinks.DataBind(); Session["peopleList"] = peopleList; //Clear Person field ppPerson.PersonId = null; ppPerson.PersonName = null; //Update Current Participants List }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="action">The workflow action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> public override bool Execute(RockContext rockContext, Rock.Model.WorkflowAction action, Object entity, out List<string> errorMessages) { var checkInState = GetCheckInState(entity, out errorMessages); if (checkInState == null) { return false; } int peopleWithoutAssignments = 0; bool roomBalance = GetAttributeValue(action, "RoomBalance").AsBoolean(); int balanceOverride = GetAttributeValue(action, "DifferentialOverride").AsIntegerOrNull() ?? 10; int previousMonthsNumber = GetAttributeValue(action, "PreviousMonthsAttendance").AsIntegerOrNull() ?? 3; int maxAssignments = GetAttributeValue(action, "MaxAssignments").AsIntegerOrNull() ?? 5; var cutoffDate = Rock.RockDateTime.Today.AddMonths(previousMonthsNumber * -1); var attendanceService = new AttendanceService(rockContext); var family = checkInState.CheckIn.Families.FirstOrDefault(f => f.Selected); if (family != null) { // get the number of people checking in, including visitors or first-timers peopleWithoutAssignments = family.People.Where(p => p.Selected).Count(); foreach (var previousAttender in family.People.Where(p => p.Selected && !p.FirstTime)) { var personGroupTypeIds = previousAttender.GroupTypes.Select(gt => gt.GroupType.Id); var lastDateAttendances = attendanceService.Queryable() .Where(a => a.PersonAlias.PersonId == previousAttender.Person.Id && personGroupTypeIds.Contains(a.Group.GroupTypeId) && a.StartDateTime >= cutoffDate && a.DidAttend == true) .OrderByDescending(a => a.StartDateTime).Take(maxAssignments) .ToList(); if (lastDateAttendances.Any()) { bool createdMatchingAssignment = false; var isSpecialNeeds = previousAttender.Person.GetAttributeValue("IsSpecialNeeds").AsBoolean(); var lastAttended = lastDateAttendances.Max(a => a.StartDateTime).Date; foreach (var groupAttendance in lastDateAttendances.Where(a => a.StartDateTime >= lastAttended)) { // Start with filtered groups unless they have abnormal age and grade parameters (1%) var groupType = previousAttender.GroupTypes.FirstOrDefault(gt => gt.GroupType.Id == groupAttendance.Group.GroupTypeId && (!gt.ExcludedByFilter || isSpecialNeeds)); if (groupType != null) { CheckInGroup group = null; if (groupType.Groups.Count == 1) { // Only a single group is open group = groupType.Groups.FirstOrDefault(g => !g.ExcludedByFilter || isSpecialNeeds); } else { // Pick the group they last attended group = groupType.Groups.FirstOrDefault(g => g.Group.Id == groupAttendance.GroupId && (!g.ExcludedByFilter || isSpecialNeeds)); if (group != null && roomBalance && !isSpecialNeeds) { var currentAttendance = group.Locations.Select(l => KioskLocationAttendance.Read(l.Location.Id).CurrentCount).Sum(); var lowestAttendedGroup = groupType.Groups.Where(g => !g.ExcludedByFilter) .Select(g => new { Group = g, Attendance = g.Locations.Select(l => KioskLocationAttendance.Read(l.Location.Id).CurrentCount).Sum() }) .OrderBy(g => g.Attendance) .FirstOrDefault(); if (lowestAttendedGroup != null && lowestAttendedGroup.Attendance < (currentAttendance - balanceOverride)) { group = lowestAttendedGroup.Group; } } } if (group != null) { CheckInLocation location = null; if (group.Locations.Count == 1) { // Only a single location is open location = group.Locations.FirstOrDefault(l => !l.ExcludedByFilter || isSpecialNeeds); } else { // Pick the location they last attended location = group.Locations.FirstOrDefault(l => l.Location.Id == groupAttendance.LocationId && (!l.ExcludedByFilter || isSpecialNeeds)); if (location != null && roomBalance && !isSpecialNeeds) { var currentAttendance = KioskLocationAttendance.Read(location.Location.Id).CurrentCount; var lowestAttendedLocation = group.Locations.Where(l => !l.ExcludedByFilter) .Select(l => new { Location = l, Attendance = KioskLocationAttendance.Read(location.Location.Id).CurrentCount }) .OrderBy(l => l.Attendance) .FirstOrDefault(); if (lowestAttendedLocation != null && lowestAttendedLocation.Attendance < (currentAttendance - balanceOverride)) { location = lowestAttendedLocation.Location; } } } if (location != null) { CheckInSchedule schedule = null; if (location.Schedules.Count == 1) { schedule = location.Schedules.FirstOrDefault(s => !s.ExcludedByFilter || isSpecialNeeds); } else if (groupAttendance.ScheduleId != null) { schedule = location.Schedules.FirstOrDefault(s => s.Schedule.Id == groupAttendance.ScheduleId && (!s.ExcludedByFilter || isSpecialNeeds)); } else { // if the schedule doesn't exactly match but everything else does, select it schedule = location.Schedules.FirstOrDefault(s => (!s.ExcludedByFilter && !isSpecialNeeds)); } if (schedule != null) { schedule.Selected = true; schedule.PreSelected = true; schedule.LastCheckIn = groupAttendance.StartDateTime; location.Selected = true; location.PreSelected = true; location.LastCheckIn = groupAttendance.StartDateTime; group.Selected = true; group.PreSelected = true; group.LastCheckIn = groupAttendance.StartDateTime; groupType.Selected = true; groupType.PreSelected = true; group.LastCheckIn = groupAttendance.StartDateTime; groupType.LastCheckIn = groupAttendance.StartDateTime; groupType.Selected = true; groupType.PreSelected = true; previousAttender.PreSelected = true; previousAttender.LastCheckIn = groupAttendance.StartDateTime; createdMatchingAssignment = true; } } } } } if (createdMatchingAssignment) { peopleWithoutAssignments--; } } } } // true condition will continue to the next auto-assignment // false condition will stop processing auto-assignments if (action.Activity.AttributeValues.Any() && action.Activity.AttributeValues.ContainsKey("ContinueAssignments")) { var continueAssignments = peopleWithoutAssignments > 0; action.Activity.AttributeValues["ContinueAssignments"].Value = continueAssignments.ToString(); } return true; }
/// <summary> /// Binds the filter. /// </summary> private void BindFilter() { drpDates.DelimitedValues = rFilter.GetUserPreference( "Date Range" ); ppPerson.Visible = _person == null; ddlAttendanceGroup.Visible = _group == null && _person != null; ddlAttendanceGroup.Items.Clear(); ddlAttendanceGroup.Items.Add( new ListItem() ); if ( _person != null ) { var rockContext = new RockContext(); var qryGroup = new GroupService( rockContext ).Queryable(); var qryPersonAttendance = new AttendanceService( rockContext ).Queryable().Where( a => a.PersonAlias.PersonId == _person.Id ); // only list groups that this person has attended before var groupList = qryGroup.Where( g => qryPersonAttendance.Any( a => a.GroupId == g.Id ) ) .OrderBy( a => a.Name ) .Select( a => new { a.Name, a.Id } ).ToList(); foreach ( var group in groupList ) { ddlAttendanceGroup.Items.Add( new ListItem( group.Name, group.Id.ToString() ) ); } ddlAttendanceGroup.SetValue( rFilter.GetUserPreference( "Group" ).AsIntegerOrNull() ); } spSchedule.SetValue( rFilter.GetUserPreference( "Schedule" ).AsIntegerOrNull() ); }
/// <summary> /// Binds the grid. /// </summary> private void BindGrid() { var dateRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues( drpSlidingDateRange.DelimitedValues ); string groupTypeIds = null; string campusIds = cpCampuses.SelectedCampusIds.AsDelimited( "," ); SortProperty sortProperty = gAttendance.SortProperty; var chartData = new AttendanceService( new RockContext() ).GetChartData( hfGroupBy.Value.ConvertToEnumOrNull<AttendanceGroupBy>() ?? AttendanceGroupBy.Week, hfGraphBy.Value.ConvertToEnumOrNull<AttendanceGraphBy>() ?? AttendanceGraphBy.Total, dateRange.Start, dateRange.End, groupTypeIds, campusIds ); if ( sortProperty != null ) { gAttendance.DataSource = chartData.AsQueryable().Sort( sortProperty ).ToList(); } else { gAttendance.DataSource = chartData.OrderBy( a => a.DateTimeStamp ).ToList(); } gAttendance.DataBind(); }
/// <summary> /// Handles printing labels for the given parameters using the /// label data stored on the AttendanceData model. /// </summary> /// <param name="fileGuids">The file guids of the label types to print.</param> /// <param name="personId">The person whose labels to print.</param> /// <param name="selectedAttendanceIds">The attendance Ids that have the labels to be reprinted.</param> /// <param name="control">The control to register/inject the client side printing into. This should be /// a control that is inside an UpdatePanel control so that the ScriptManager can register the needed client script block.</param> /// <param name="request">The HTTP Request so that the request's URL can be used when needed for client printing.</param> /// <param name="printerAddress">The IP Address of a printer to send the print job to, overriding what is in the label.</param> /// <returns> /// A list of any messages that occur during printing. /// </returns> public static List <string> ReprintZebraLabels(List <Guid> fileGuids, int personId, List <int> selectedAttendanceIds, Control control, System.Web.HttpRequest request, string printerAddress = null) { // Fetch the actual labels and print them var rockContext = new RockContext(); var attendanceService = new Rock.Model.AttendanceService(rockContext); // Get the selected attendance records var attendanceRecords = attendanceService.GetByIds(selectedAttendanceIds); var printFromClient = new List <CheckInLabel>(); var printFromServer = new List <CheckInLabel>(); // Now grab only the selected label types (matching fileGuids) from those record's AttendanceData // for the selected person foreach (var attendance in attendanceRecords) { var attendanceData = attendance.AttendanceData; var json = attendanceData.LabelData.Trim(); // skip if the return type is not an array if (json.Substring(0, 1) != "[") { continue; } // De-serialize the JSON into a list of objects var checkinLabels = JsonConvert.DeserializeObject <List <CheckInLabel> >(json); // skip if no labels were found if (checkinLabels == null) { continue; } // Take only the labels that match the selected person (or if they are Family type labels) and file guids). checkinLabels = checkinLabels.Where(l => (l.PersonId == personId || l.LabelType == KioskLabelType.Family) && fileGuids.Contains(l.FileGuid)).ToList(); // Override the printer by printing to the given printerAddress? if (!string.IsNullOrEmpty(printerAddress)) { checkinLabels.ToList().ForEach(l => l.PrinterAddress = printerAddress); printFromServer.AddRange(checkinLabels); } else { printFromClient.AddRange(checkinLabels.Where(l => l.PrintFrom == Rock.Model.PrintFrom.Client)); printFromServer.AddRange(checkinLabels.Where(l => l.PrintFrom == Rock.Model.PrintFrom.Server)); } } // Print client labels if (printFromClient.Any()) { var urlRoot = string.Format("{0}://{1}", request.Url.Scheme, request.Url.Authority); printFromClient .OrderBy(l => l.PersonId) .ThenBy(l => l.Order) .ToList() .ForEach(l => l.LabelFile = urlRoot + l.LabelFile); AddLabelScript(printFromClient.ToJson(), control); } var messages = new List <string>(); // Print server labels if (printFromServer.Any()) { messages = ZebraPrint.PrintLabels(printFromServer); } // No messages is "good news". if (messages.Count == 0) { messages.Add("The labels have been printed."); } return(messages); }
/// <summary> /// Handles printing labels for the given parameters using the /// label data stored on the AttendanceData model. /// </summary> /// <param name="fileGuids">The file guids.</param> /// <param name="personId">The person identifier.</param> /// <param name="selectedAttendanceIds">The selected attendance ids.</param> /// <param name="control">The control.</param> /// <param name="request">The request.</param> /// <param name="reprintLabelOptions">The reprint label options.</param> /// <returns></returns> public static List <string> ReprintZebraLabels(List <Guid> fileGuids, int personId, List <int> selectedAttendanceIds, Control control, System.Web.HttpRequest request, ReprintLabelOptions reprintLabelOptions) { // Fetch the actual labels and print them var rockContext = new RockContext(); var attendanceService = new Rock.Model.AttendanceService(rockContext); reprintLabelOptions = reprintLabelOptions ?? new ReprintLabelOptions(); // Get the selected attendance records (but only the ones that have label data) var labelDataList = attendanceService .GetByIds(selectedAttendanceIds) .Where(a => a.AttendanceData.LabelData != null) .Select(a => a.AttendanceData.LabelData); var printFromClient = new List <CheckInLabel>(); var printFromServer = new List <CheckInLabel>(); // Now grab only the selected label types (matching fileGuids) from those record's AttendanceData // for the selected person foreach (var labelData in labelDataList) { var json = labelData.Trim(); // skip if the return type is not an array if (json.Substring(0, 1) != "[") { continue; } // De-serialize the JSON into a list of objects var checkinLabels = JsonConvert.DeserializeObject <List <CheckInLabel> >(json); // skip if no labels were found if (checkinLabels == null) { continue; } // Take only the labels that match the selected person (or if they are Family type labels) and file guids). checkinLabels = checkinLabels.Where(l => (l.PersonId == personId || l.LabelType == KioskLabelType.Family) && fileGuids.Contains(l.FileGuid)).ToList(); if (reprintLabelOptions.PrintFrom == PrintFrom.Server && reprintLabelOptions.ServerPrinterIPAddress.IsNotNullOrWhiteSpace()) { // Override the printer by printing to the given printerAddress? checkinLabels.ToList().ForEach(l => l.PrinterAddress = reprintLabelOptions.ServerPrinterIPAddress); printFromServer.AddRange(checkinLabels); } else if (reprintLabelOptions.PrintFrom == PrintFrom.Client) { // Override the printer by printing to the client // send the checkin labels to ZebraPrint.js, which the ClientApp will use to print it // IP Address of the printer will stay the same IP Address as where the original label was, printFromClient.AddRange(checkinLabels); } else { // Print to label's printer printFromClient.AddRange(checkinLabels.Where(l => l.PrintFrom == Rock.Model.PrintFrom.Client)); printFromServer.AddRange(checkinLabels.Where(l => l.PrintFrom == Rock.Model.PrintFrom.Server)); } } // Print client labels if (printFromClient.Any()) { var urlRoot = string.Format("{0}://{1}", request.UrlProxySafe().Scheme, request.UrlProxySafe().Authority); /* * // This is extremely useful when debugging with ngrok and an iPad on the local network. * // X-Original-Host will contain the name of your ngrok hostname, therefore the labels will * // get a LabelFile url that will actually work with that iPad. * if ( request.Headers["X-Original-Host"] != null ) * { * var scheme = request.Headers["X-Forwarded-Proto"] ?? "http"; * urlRoot = string.Format( "{0}://{1}", scheme, request.Headers.GetValues( "X-Original-Host" ).First() ); * } */ printFromClient .OrderBy(l => l.PersonId) .ThenBy(l => l.Order) .ToList() .ForEach(l => l.LabelFile = urlRoot + l.LabelFile); AddLabelScript(printFromClient.ToJson(), control); } var messages = new List <string>(); // Print server labels if (printFromServer.Any()) { messages = ZebraPrint.PrintLabels(printFromServer); } // No messages is "good news". if (messages.Count == 0) { messages.Add("The labels have been printed."); } return(messages); }
private void ShowDetail(Guid personGuid) { using ( var rockContext = new RockContext() ) { var personService = new PersonService( rockContext ); var person = personService.Queryable( "PhoneNumbers.NumberTypeValue,RecordTypeValue", true, true ) .FirstOrDefault( a => a.Guid == personGuid ); if ( person != null ) { lName.Text = person.FullName; string photoTag = Rock.Model.Person.GetPersonPhotoImageTag( person, 120, 120 ); if ( person.PhotoId.HasValue ) { lPhoto.Text = string.Format( "<div class='photoframe'><a href='{0}'>{1}</a></div>", person.PhotoUrl, photoTag ); } else { lPhoto.Text = photoTag; } lGender.Text = person.Gender != Gender.Unknown ? person.Gender.ConvertToString() : ""; if ( person.BirthDate.HasValue ) { string ageText = ( person.BirthYear.HasValue && person.BirthYear != DateTime.MinValue.Year ) ? string.Format( "{0} yrs old ", person.BirthDate.Value.Age() ) : string.Empty; lAge.Text = string.Format( "{0} <small>({1})</small><br/>", ageText, person.BirthDate.Value.ToShortDateString() ); } else { lAge.Text = string.Empty; } lGrade.Text = person.GradeFormatted; lEmail.Visible = !string.IsNullOrWhiteSpace( person.Email ); lEmail.Text = person.GetEmailTag( ResolveRockUrl( "/" ), "btn btn-default", "<i class='fa fa-envelope'></i>" ); // Get all family member from all families ( including self ) var allFamilyMembers = personService.GetFamilyMembers( person.Id, true ).ToList(); // Add flag for this person in each family indicating if they are a child in family. var childGuid = Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_CHILD.AsGuid(); var isFamilyChild = new Dictionary<int, bool>(); foreach ( var thisPerson in allFamilyMembers.Where( m => m.PersonId == person.Id ) ) { isFamilyChild.Add( thisPerson.GroupId, thisPerson.GroupRole.Guid.Equals( childGuid ) ); } // Get the current url's root (without the person's guid) string urlRoot = Request.Url.ToString().ReplaceCaseInsensitive( personGuid.ToString(), "" ); // Get the other family members and the info needed for rendering var familyMembers = allFamilyMembers.Where( m => m.PersonId != person.Id ) .OrderBy( m => m.GroupId ) .ThenBy( m => m.Person.BirthDate ) .Select( m => new { Url = urlRoot + m.Person.Guid.ToString(), FullName = m.Person.FullName, Gender = m.Person.Gender, FamilyRole = m.GroupRole, Note = isFamilyChild[m.GroupId] ? ( m.GroupRole.Guid.Equals( childGuid ) ? " (Sibling)" : "(Parent)" ) : ( m.GroupRole.Guid.Equals( childGuid ) ? " (Child)" : "" ) } ) .ToList(); rcwFamily.Visible = familyMembers.Any(); rptrFamily.DataSource = familyMembers; rptrFamily.DataBind(); rptrPhones.DataSource = person.PhoneNumbers.Where( p => !p.IsUnlisted ).ToList(); rptrPhones.DataBind(); var schedules = new ScheduleService( rockContext ) .Queryable().AsNoTracking() .Where( s => s.CheckInStartOffsetMinutes.HasValue ) .ToList(); var scheduleIds = schedules.Select( s => s.Id ).ToList(); var activeScheduleIds = new List<int>(); foreach ( var schedule in schedules ) { if ( schedule.IsScheduleOrCheckInActive ) { activeScheduleIds.Add( schedule.Id ); } } int? personAliasId = person.PrimaryAliasId; if ( !personAliasId.HasValue ) { personAliasId = new PersonAliasService( rockContext ).GetPrimaryAliasId( person.Id ); } var attendances = new AttendanceService( rockContext ) .Queryable( "Schedule,Group,Location,AttendanceCode" ) .Where( a => a.PersonAliasId.HasValue && a.PersonAliasId == personAliasId && a.ScheduleId.HasValue && a.GroupId.HasValue && a.LocationId.HasValue && a.DidAttend.HasValue && a.DidAttend.Value && scheduleIds.Contains( a.ScheduleId.Value ) ) .OrderByDescending( a => a.StartDateTime ) .Take( 20 ) .ToList() // Run query to get recent most 20 checkins .OrderByDescending( a => a.StartDateTime ) // Then sort again by startdatetime and schedule start (which is not avail to sql query ) .ThenByDescending( a => a.Schedule.StartTimeOfDay ) .Select( a => new AttendanceInfo { Date = a.StartDateTime, GroupId = a.Group.Id, Group = a.Group.Name, LocationId = a.LocationId.Value, Location = a.Location.Name, Schedule = a.Schedule.Name, IsActive = a.StartDateTime > DateTime.Today && activeScheduleIds.Contains( a.ScheduleId.Value ), Code = a.AttendanceCode != null ? a.AttendanceCode.Code : "" } ).ToList(); // Set active locations to be a link to the room in manager page var qryParam = new Dictionary<string, string>(); qryParam.Add( "Group", "" ); qryParam.Add( "Location", "" ); foreach ( var attendance in attendances.Where( a => a.IsActive ) ) { qryParam["Group"] = attendance.GroupId.ToString(); qryParam["Location"] = attendance.LocationId.ToString(); attendance.Location = string.Format( "<a href='{0}'>{1}</a>", LinkedPageUrl( "ManagerPage", qryParam ), attendance.Location ); } rcwCheckinHistory.Visible = attendances.Any(); gHistory.DataSource = attendances; gHistory.DataBind(); } } }
/// <summary> /// Handles adding families from the given XML element snippet /// </summary> /// <param name="elemFamilies">The xml element containing all the families.</param> /// <param name="rockContext">The rock context.</param> private void AddFamilies( XElement elemFamilies, RockContext rockContext ) { if ( elemFamilies == null ) { return; } // Persist the storage type's settings specific to the photo binary file type var settings = new Dictionary<string, string>(); if ( _personImageBinaryFileType.Attributes == null ) { _personImageBinaryFileType.LoadAttributes(); } foreach ( var attributeValue in _personImageBinaryFileType.AttributeValues ) { settings.Add( attributeValue.Key, attributeValue.Value.Value ); } _personImageBinaryFileTypeSettings = settings.ToJson(); bool fabricateAttendance = GetAttributeValue( "FabricateAttendance" ).AsBoolean(); GroupService groupService = new GroupService( rockContext ); var allFamilies = rockContext.Groups; List<Group> allGroups = new List<Group>(); var attendanceData = new Dictionary<Guid, List<Attendance>>(); // Next create the family along with its members and related data foreach ( var elemFamily in elemFamilies.Elements( "family" ) ) { Guid guid = elemFamily.Attribute( "guid" ).Value.Trim().AsGuid(); var familyMembers = BuildFamilyMembersFromXml( elemFamily.Element( "members" ), rockContext ); // Call replica of groupService's SaveNewFamily method in an attempt to speed things up Group family = CreateNewFamily( familyMembers, campusId: 1 ); family.Guid = guid; // add the family to the context's list of groups allFamilies.Add( family ); // add the families address(es) AddFamilyAddresses( groupService, family, elemFamily.Element( "addresses" ), rockContext ); // add their attendance data if ( fabricateAttendance ) { AddFamilyAttendance( family, elemFamily, rockContext, attendanceData ); } allGroups.Add( family ); _stopwatch.Stop(); AppendFormat( "{0:00}:{1:00}.{2:00} added {3}<br/>", _stopwatch.Elapsed.Minutes, _stopwatch.Elapsed.Seconds, _stopwatch.Elapsed.Milliseconds / 10, family.Name ); _stopwatch.Start(); } rockContext.ChangeTracker.DetectChanges(); rockContext.SaveChanges( disablePrePostProcessing: true ); // Now save each person's attributevalues (who had them defined in the XML) // and add each person's ID to a dictionary for use later. _stopwatch.Stop(); AppendFormat( "{0:00}:{1:00}.{2:00} saving attributes for everyone...<br/>", _stopwatch.Elapsed.Minutes, _stopwatch.Elapsed.Seconds, _stopwatch.Elapsed.Milliseconds / 10 ); _stopwatch.Start(); AttributeValueService attributeValueService = new AttributeValueService( rockContext ); foreach ( var gm in allGroups.SelectMany( g => g.Members ) ) { // Put the person's id into the people dictionary for later use. if ( !_peopleDictionary.ContainsKey( gm.Person.Guid ) ) { _peopleDictionary.Add( gm.Person.Guid, gm.Person.Id ); } // Only save if the person had attributes, otherwise it will error. if ( _personWithAttributes.ContainsKey( gm.Person.Guid ) ) { foreach ( var attributeCache in gm.Person.Attributes.Select( a => a.Value ) ) { var newValue = gm.Person.AttributeValues[attributeCache.Key]; if ( newValue != null ) { var attributeValue = new AttributeValue(); attributeValue.AttributeId = newValue.AttributeId; attributeValue.EntityId = gm.Person.Id; attributeValue.Value = newValue.Value; rockContext.AttributeValues.Add( attributeValue ); } } } } rockContext.ChangeTracker.DetectChanges(); rockContext.SaveChanges( disablePrePostProcessing: true ); _stopwatch.Stop(); AppendFormat( "{0:00}:{1:00}.{2:00} attributes saved<br/>", _stopwatch.Elapsed.Minutes, _stopwatch.Elapsed.Seconds, _stopwatch.Elapsed.Milliseconds / 10 ); _stopwatch.Start(); // Create person alias records for each person manually since we set disablePrePostProcessing=true on save PersonService personService = new PersonService( rockContext ); foreach ( var person in personService.Queryable( "Aliases", true ) .Where( p => _peopleDictionary.Keys.Contains( p.Guid ) && !p.Aliases.Any() ) ) { person.Aliases.Add( new PersonAlias { AliasPersonId = person.Id, AliasPersonGuid = person.Guid } ); } rockContext.ChangeTracker.DetectChanges(); rockContext.SaveChanges( disablePrePostProcessing: true ); _stopwatch.Stop(); AppendFormat( "{0:00}:{1:00}.{2:00} added person aliases<br/>", _stopwatch.Elapsed.Minutes, _stopwatch.Elapsed.Seconds, _stopwatch.Elapsed.Milliseconds / 10 ); _stopwatch.Start(); // Put the person alias ids into the people alias dictionary for later use. PersonAliasService personAliasService = new PersonAliasService( rockContext ); foreach ( var personAlias in personAliasService.Queryable( "Person" ) .Where( a => _peopleDictionary.Keys.Contains( a.Person.Guid ) && a.PersonId == a.AliasPersonId ) ) { _peopleAliasDictionary.Add( personAlias.Person.Guid, personAlias.Id ); } // Now that person aliases have been saved, save the attendance records var attendanceService = new AttendanceService( rockContext ); var attendanceGuids = attendanceData.Select( a => a.Key ).ToList(); foreach ( var aliasKeyValue in _peopleAliasDictionary .Where( a => attendanceGuids.Contains( a.Key )) ) { foreach ( var attendance in attendanceData[aliasKeyValue.Key] ) { attendance.PersonAliasId = aliasKeyValue.Value; attendanceService.Add( attendance ); } } rockContext.ChangeTracker.DetectChanges(); rockContext.SaveChanges( disablePrePostProcessing: true ); _stopwatch.Stop(); AppendFormat( "{0:00}:{1:00}.{2:00} added attendance records<br/>", _stopwatch.Elapsed.Minutes, _stopwatch.Elapsed.Seconds, _stopwatch.Elapsed.Milliseconds / 10 ); _stopwatch.Start(); // Now re-process the family section looking for any giving data. // We do this last because we need the personAliases that were just added. // Persist the storage type's settings specific to the contribution binary file type settings = new Dictionary<string, string>(); if ( _checkImageBinaryFileType.Attributes == null ) { _checkImageBinaryFileType.LoadAttributes(); } foreach ( var attributeValue in _checkImageBinaryFileType.AttributeValues ) { settings.Add( attributeValue.Key, attributeValue.Value.Value ); } _checkImageBinaryFileTypeSettings = settings.ToJson(); foreach ( var elemFamily in elemFamilies.Elements( "family" ) ) { // add the families giving data if ( GetAttributeValue( "EnableGiving" ).AsBoolean() ) { // Support multiple giving elements per family foreach ( var elementGiving in elemFamily.Elements( "giving" ) ) { AddFamilyGiving( elementGiving, elemFamily.Attribute( "name" ).Value, rockContext ); } } } if ( GetAttributeValue( "EnableGiving" ).AsBoolean() ) { // Now add the batches to the service to be persisted var financialBatchService = new FinancialBatchService( rockContext ); foreach ( var financialBatch in _contributionBatches ) { financialBatchService.Add( financialBatch.Value ); } } rockContext.ChangeTracker.DetectChanges(); rockContext.SaveChanges( disablePrePostProcessing: true ); }
protected void lbSearch_Click( object sender, EventArgs e ) { using ( var rockContext = new RockContext() ) { // Get all the schedules that allow checkin var schedules = new ScheduleService( rockContext ) .Queryable().AsNoTracking() .Where( s => s.CheckInStartOffsetMinutes.HasValue ) .ToList(); // Get a lit of the schedule ids var scheduleIds = schedules.Select( s => s.Id ).ToList(); // Get a list of the schedule id that are currently active for checkin var activeScheduleIds = new List<int>(); foreach ( var schedule in schedules ) { if ( schedule.IsScheduleOrCheckInActive ) { activeScheduleIds.Add( schedule.Id ); } } // Get a list of all the groups that we're concerned about var groupIds = NavData.Groups.Select( g => g.Id ).ToList(); // Get a list of all the people that are currently checked in var today = RockDateTime.Today; var attendanceService = new AttendanceService( rockContext ); var currentAttendeeIds = attendanceService .Queryable().AsNoTracking() .Where( a => a.ScheduleId.HasValue && a.GroupId.HasValue && a.LocationId.HasValue && a.PersonAlias != null && a.DidAttend.HasValue && a.DidAttend.Value && a.StartDateTime > today && activeScheduleIds.Contains( a.ScheduleId.Value ) && groupIds.Contains( a.GroupId.Value ) ) .Select( a => a.PersonAlias.PersonId ) .Distinct(); // Create a qry to get the last checkin date (used in next statement's join) var attendanceQry = attendanceService .Queryable().AsNoTracking() .Where( a => a.ScheduleId.HasValue && a.GroupId.HasValue && a.LocationId.HasValue && a.PersonAliasId.HasValue && a.DidAttend.Value && scheduleIds.Contains( a.ScheduleId.Value ) && groupIds.Contains( a.GroupId.Value ) ) .GroupBy( a => new { PersonId = a.PersonAlias.PersonId } ) .Select( g => new PersonResult { Id = g.Key.PersonId, Guid = Guid.Empty, Name = "", PhotoId = null, LastCheckin = g.Max( a => a.StartDateTime ), CheckedInNow = false, ScheduleGroupNames = "" } ); // Do the person search bool reversed = false; var results = new PersonService( rockContext ) .GetByFullName( tbSearch.Text, false, false, false, out reversed ) .ToList() .GroupJoin( attendanceQry, p => p.Id, a => a.Id, ( p, a ) => a .Select( c => new PersonResult { Id = p.Id, Guid = p.Guid, Name = ( reversed ? p.LastName + ", " + p.NickName : p.NickName + " " + p.LastName ), PhotoId = p.PhotoId, Age = p.Age.ToString() ?? "", LastCheckin = c.LastCheckin, CheckedInNow = currentAttendeeIds.Contains( p.Id ), ScheduleGroupNames = "" } ) .DefaultIfEmpty( new PersonResult { Id = p.Id, Guid = p.Guid, Name = ( reversed ? p.LastName + ", " + p.NickName : p.NickName + " " + p.LastName ), PhotoId = p.PhotoId, Age = p.Age.ToString() ?? "", LastCheckin = null, CheckedInNow = false, ScheduleGroupNames = "" } ) ) .SelectMany( a => a ) .Distinct() .OrderByDescending( a => a.CheckedInNow ) .ThenByDescending( a => a.LastCheckin ) .ThenBy( a => a.Name ) .ToList(); pnlNavHeading.Attributes["onClick"] = upnlContent.GetPostBackEventReference( CurrentNavPath ); lNavHeading.Text = "Back"; rptNavItems.Visible = false; rptPeople.Visible = true; rptPeople.DataSource = results; rptPeople.DataBind(); } RegisterStartupScript(); }
protected void gReleventPeople_RowSelected( object sender, RowEventArgs e ) { var attendance = new AttendanceService( rockContext ).Get( SelectedAttendanceGuid ); var selectedPlegePersonAlias = new PersonAliasService( rockContext ).Get( ( Guid ) e.RowKeyValue ); var workflowType = new WorkflowTypeService( rockContext ).Get( GetAttributeValue( "WorkflowType" ).AsGuid() ); if ( attendance != null && selectedPlegePersonAlias != null ) LaunchWorkflow( rockContext, attendance, selectedPlegePersonAlias, workflowType ); }
/// <summary> /// Handles the ItemCommand event of the rptPeople control. /// </summary> /// <param name="source">The source of the event.</param> /// <param name="e">The <see cref="RepeaterCommandEventArgs"/> instance containing the event data.</param> protected void rptPeople_ItemCommand( object source, RepeaterCommandEventArgs e ) { if ( e.CommandName == "Delete" ) { int personId = e.CommandArgument.ToString().AsInteger(); if ( string.IsNullOrWhiteSpace( CurrentNavPath ) || !CurrentNavPath.StartsWith( _configuredMode ) ) { CurrentNavPath = _configuredMode; } var pathParts = CurrentNavPath.Split( new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries ); int partIndex = pathParts.Length - 1; if ( partIndex >= 0 ) { string itemKey = pathParts[partIndex]; if ( itemKey.Length > 0 ) { string itemType = itemKey.Left( 1 ); int? itemId = itemKey.Length > 1 ? itemKey.Substring( 1 ).AsIntegerOrNull() : null; if ( itemType == "L" && itemId.HasValue ) { var dayStart = RockDateTime.Today; var now = RockDateTime.Now; using ( var rockContext = new RockContext() ) { var activeSchedules = new List<int>(); foreach ( var schedule in new ScheduleService( rockContext ) .Queryable().AsNoTracking() .Where( s => s.CheckInStartOffsetMinutes.HasValue ) ) { if ( schedule.IsScheduleOrCheckInActive ) { activeSchedules.Add( schedule.Id ); } } var attendanceService = new AttendanceService( rockContext ); foreach ( var attendance in attendanceService .Queryable() .Where( a => a.StartDateTime > dayStart && a.StartDateTime < now && a.LocationId.HasValue && a.LocationId.Value == itemId.Value && a.PersonAlias != null && a.PersonAlias.PersonId == personId && a.DidAttend.HasValue && a.DidAttend.Value && a.ScheduleId.HasValue && activeSchedules.Contains( a.ScheduleId.Value ) ) ) { attendanceService.Delete( attendance ); } rockContext.SaveChanges(); } int? campusId = CurrentCampusId.AsIntegerOrNull(); if ( campusId.HasValue ) { NavData = GetNavigationData( CampusCache.Read( campusId.Value ) ); } BuildNavigationControls(); } } } } }
/// <summary> /// Handles the Delete event of the gOccurrences control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param> protected void gOccurrences_Delete( object sender, RowEventArgs e ) { if ( _group != null ) { var occurrenceDate = (DateTime)e.RowKeyValues["Date"]; DateTime startDate = occurrenceDate.Date; DateTime endDate = occurrenceDate.Date.AddDays( 1 ); using ( var rockContext = new RockContext() ) { var attendanceService = new AttendanceService( rockContext ); var qry = attendanceService.Queryable() .Where( a => a.GroupId == _group.Id && a.StartDateTime >= startDate && a.StartDateTime < endDate ); int? scheduleId = e.RowKeyValues["ScheduleId"] as int?; if ( scheduleId.HasValue ) { qry = qry.Where( a => a.ScheduleId.HasValue && a.ScheduleId.Value == scheduleId.Value ); } else { qry = qry.Where( a => !a.ScheduleId.HasValue ); } int? locationId = e.RowKeyValues["LocationId"] as int?; if ( locationId.HasValue ) { qry = qry.Where( a => a.LocationId.HasValue && a.LocationId.Value == locationId.Value ); } else { qry = qry.Where( a => !a.LocationId.HasValue ); } foreach ( var attendance in qry ) { attendanceService.Delete( attendance ); } rockContext.SaveChanges(); if ( locationId.HasValue ) { Rock.CheckIn.KioskLocationAttendance.Flush( locationId.Value ); } } } BindGrid(); }
private void BuildNavigationControls() { if ( NavData != null ) { if ( string.IsNullOrWhiteSpace( CurrentNavPath ) || !CurrentNavPath.StartsWith( _configuredMode ) ) { CurrentNavPath = _configuredMode; } var pathParts = CurrentNavPath.Split( new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries ); int numParts = pathParts.Length; NavigationItem item = NavData.GetItem( pathParts[numParts-1] ); while (item == null && numParts > 1) { numParts--; item = NavData.GetItem( pathParts[numParts-1] ); } CurrentNavPath = pathParts.Take( numParts ).ToList().AsDelimited( "|" ); string itemKey = pathParts[numParts - 1]; string itemType = itemKey.Left( 1 ); int? itemId = itemKey.Length > 1 ? itemKey.Substring( 1 ).AsIntegerOrNull() : null; SetUserPreference( "CurrentNavPath", CurrentNavPath ); var navItems = new List<NavigationItem>(); switch ( itemType ) { case "L": // Location { // Add child locations NavData.Locations .Where( l => l.ParentId == itemId ) .ToList() .ForEach( l => navItems.Add( l ) ); break; } case "T": // Group Type { // Add child group types NavData.GroupTypes .Where( t => t.ParentId.Equals(itemId) ) .ToList().ForEach( t => navItems.Add( t ) ); // Add child groups var groupIds = NavData.GroupTypes .Where( t => t.Id == itemId ) .SelectMany( t => t.ChildGroupIds ) .Distinct() .ToList(); NavData.Groups .Where( g => groupIds.Contains( g.Id ) ) .ToList() .ForEach( g => navItems.Add( g ) ); break; } case "G": // Group { // Add child groups var groupIds = NavData.Groups .Where( g => g.Id == itemId ) .SelectMany( g => g.ChildGroupIds ) .Distinct() .ToList(); NavData.Groups .Where( g => groupIds.Contains( g.Id ) ) .ToList() .ForEach( g => navItems.Add( g ) ); // Add child locations var locations = NavData.Groups .Where( g => g.Id == itemId ) .SelectMany( g => g.ChildLocationIds ) .Distinct() .ToList(); NavData.Locations .Where( l => locations.Contains( l.Id ) ) .ToList() .ForEach( l => navItems.Add( l ) ); break; } } // Get chart data Dictionary<DateTime, List<int>> chartCounts = null; if (item != null) { chartCounts = item.RecentPersonIds; } else { chartCounts = new Dictionary<DateTime, List<int>>(); foreach(var navItem in navItems) { foreach ( var kv in navItem.RecentPersonIds ) { if ( !chartCounts.ContainsKey( kv.Key ) ) { chartCounts.Add( kv.Key, new List<int>() ); } chartCounts[kv.Key] = chartCounts[kv.Key].Union( kv.Value ).ToList(); } } } var chartData = new List<string>(); TimeSpan baseSpan = new TimeSpan( new DateTime(1970, 1, 1).Ticks ); foreach ( var kv in chartCounts.OrderBy( c => c.Key ) ) { DateTime offsetTime = kv.Key.Subtract( baseSpan ); long ticks = (long)( offsetTime.Ticks / 10000 ); chartData.Add( string.Format( "[{0}, {1}]", ticks, kv.Value.Count() ) ); } hfChartData.Value = string.Format( "[ [ {0} ] ]", chartData.AsDelimited( ", " ) ); pnlChart.Attributes["onClick"] = upnlContent.GetPostBackEventReference("R"); pnlNavHeading.Visible = item != null; if ( item != null ) { if ( numParts > 0 ) { pnlNavHeading.Attributes["onClick"] = upnlContent.GetPostBackEventReference( pathParts.ToList().Take( numParts - 1 ).ToList().AsDelimited( "|" ) ); } lNavHeading.Text = item.Name; var locationItem = item as NavigationLocation; if (locationItem != null && locationItem.HasGroups) { tglHeadingRoom.Visible = true; tglHeadingRoom.Checked = locationItem.IsActive; tglHeadingRoom.Attributes["data-key"] = locationItem.Id.ToString(); var rockContext = new RockContext(); var activeSchedules = new List<int>(); foreach ( var schedule in new ScheduleService( rockContext ) .Queryable().AsNoTracking() .Where( s => s.CheckInStartOffsetMinutes.HasValue ) ) { if ( schedule.IsScheduleOrCheckInActive ) { activeSchedules.Add( schedule.Id ); } } var dayStart = RockDateTime.Today; var now = RockDateTime.Now; var attendees = new AttendanceService( rockContext ) .Queryable( "Group,PersonAlias.Person,Schedule" ) .AsNoTracking() .Where( a => a.StartDateTime > dayStart && a.StartDateTime < now && a.LocationId.HasValue && a.LocationId == locationItem.Id && a.DidAttend.HasValue && a.DidAttend.Value && a.ScheduleId.HasValue && activeSchedules.Contains( a.ScheduleId.Value ) ) .ToList(); var people = new List<PersonResult>(); foreach ( var personId in attendees .OrderBy( a => a.PersonAlias.Person.NickName ) .ThenBy( a => a.PersonAlias.Person.LastName ) .Select( a => a.PersonAlias.PersonId ) .Distinct() ) { var matchingAttendees = attendees .Where( a => a.PersonAlias.PersonId == personId ) .ToList(); people.Add( new PersonResult( matchingAttendees ) ); } rptPeople.Visible = true; rptPeople.DataSource = people; rptPeople.DataBind(); } else { tglHeadingRoom.Visible = false; rptPeople.Visible = false; } } else { rptPeople.Visible = false; } rptNavItems.Visible = navItems.Any(); rptNavItems.DataSource = navItems .OrderBy( i => i.TypeKey ) .ThenBy( i => i.Order ) .ThenBy( i => i.Name ); rptNavItems.DataBind(); RegisterStartupScript(); } }
/// <summary> /// Binds the filter. /// </summary> private void BindFilter() { drpDates.DelimitedValues = rFilter.GetUserPreference( "Date Range" ); using ( var rockContext = new RockContext() ) { if ( _person != null ) { ppPerson.Visible = false; if ( _group == null ) { ddlAttendanceGroup.Visible = true; ddlAttendanceGroup.Items.Clear(); ddlAttendanceGroup.Items.Add( new ListItem() ); // only list groups that this person has attended before var groupIdsAttended = new AttendanceService( rockContext ) .Queryable().AsNoTracking() .Where( a => a.PersonAlias != null && a.PersonAlias.PersonId == _person.Id ) .Select( a => a.GroupId ) .Distinct() .ToList(); foreach ( var group in new GroupService( rockContext ) .Queryable().AsNoTracking() .Where( g => groupIdsAttended.Contains( g.Id ) ) .OrderBy( g => g.Name ) .Select( g => new { g.Name, g.Id } ).ToList() ) { ddlAttendanceGroup.Items.Add( new ListItem( group.Name, group.Id.ToString() ) ); } ddlAttendanceGroup.SetValue( rFilter.GetUserPreference( "Group" ).AsIntegerOrNull() ); } else { ddlAttendanceGroup.Visible = false; } } else { ppPerson.Visible = true; int? personId = rFilter.GetUserPreference( "Person" ).AsIntegerOrNull(); if ( personId.HasValue ) { var person = new PersonService( rockContext ).Get( personId.Value ); ppPerson.SetValue( person ); } ddlAttendanceGroup.Visible = false; } } spSchedule.SetValue( rFilter.GetUserPreference( "Schedule" ).AsIntegerOrNull() ); string filterValue = rFilter.GetUserPreference( "Attended" ); var filterAttendance = GetAttributeValue( "FilterAttendanceByDefault" ).AsBoolean(); if ( string.IsNullOrEmpty( filterValue ) && filterAttendance ) { filterValue = "1"; rFilter.SaveUserPreference( "Attended", filterValue ); } ddlDidAttend.SetValue( filterValue ); }
private NavigationData GetNavigationData( CampusCache campus ) { using ( var rockContext = new RockContext() ) { var validLocationids = new List<int>(); if ( campus.LocationId.HasValue ) { // Get all the child locations validLocationids.Add( campus.LocationId.Value ); new LocationService( rockContext ) .GetAllDescendents( campus.LocationId.Value ) .Select( l => l.Id ) .ToList() .ForEach( l => validLocationids.Add( l ) ); } var groupTypeTemplateGuid = PageParameter( "Area" ).AsGuidOrNull(); if ( !groupTypeTemplateGuid.HasValue ) { groupTypeTemplateGuid = this.GetAttributeValue( "GroupTypeTemplate" ).AsGuidOrNull(); } if ( !groupTypeTemplateGuid.HasValue ) { // Check to see if a specific group was specified Guid? guid = Rock.SystemGuid.DefinedValue.GROUPTYPE_PURPOSE_CHECKIN_TEMPLATE.AsGuid(); int? groupId = PageParameter( "Group" ).AsIntegerOrNull(); if ( groupId.HasValue && guid.HasValue ) { var group = new GroupService( rockContext ).Get( groupId.Value ); if ( group != null && group.GroupType != null ) { var groupType = GetParentPurposeGroupType( group.GroupType, guid.Value ); if ( groupType != null ) { groupTypeTemplateGuid = groupType.Guid; } } } } if ( groupTypeTemplateGuid.HasValue ) { pnlContent.Visible = true; NavData = new NavigationData(); var chartTimes = GetChartTimes(); // Get the group types var parentGroupType = GroupTypeCache.Read( groupTypeTemplateGuid.Value ); if ( parentGroupType != null ) { foreach ( var childGroupType in parentGroupType.ChildGroupTypes ) { AddGroupType( childGroupType, chartTimes ); } } // Get the groups var groupTypeIds = NavData.GroupTypes.Select( t => t.Id ).ToList(); var groups = new GroupService( rockContext ) .Queryable( "GroupLocations" ).AsNoTracking() .Where( g => groupTypeIds.Contains( g.GroupTypeId ) && g.IsActive ) .ToList(); var groupIds = groups.Select( g => g.Id ).ToList(); foreach( var group in groups ) { var childGroupIds = groups .Where( g => g.ParentGroupId.HasValue && g.ParentGroupId.Value == group.Id ) .Select( g => g.Id ) .ToList(); var childLocationIds = group.GroupLocations .Where( l => validLocationids.Contains( l.LocationId ) ) .Select( l => l.LocationId ) .ToList(); if ( childLocationIds.Any() || childGroupIds.Any() ) { var navGroup = new NavigationGroup( group, chartTimes ); navGroup.ChildLocationIds = childLocationIds; navGroup.ChildGroupIds = childGroupIds; NavData.Groups.Add( navGroup ); if ( !group.ParentGroupId.HasValue || groupIds.Contains( group.ParentGroupId.Value ) ) { NavData.GroupTypes.Where( t => t.Id == group.GroupTypeId ).ToList() .ForEach( t => t.ChildGroupIds.Add( group.Id ) ); } } } // Remove any groups without child locations var emptyGroupIds = NavData.Groups .Where( g => !g.ChildGroupIds.Any() && !g.ChildLocationIds.Any() ) .Select( g => g.Id ) .ToList(); while ( emptyGroupIds.Any() ) { NavData.Groups = NavData.Groups.Where( g => !emptyGroupIds.Contains( g.Id ) ).ToList(); NavData.Groups.ForEach( g => g.ChildGroupIds = g.ChildGroupIds.Where( c => !emptyGroupIds.Contains( c ) ).ToList() ); emptyGroupIds = NavData.Groups .Where( g => !g.ChildGroupIds.Any() && !g.ChildLocationIds.Any() ) .Select( g => g.Id ) .ToList(); } // Remove any grouptype without groups var emptyGroupTypeIds = NavData.GroupTypes .Where( t => !t.ChildGroupIds.Any() && !t.ChildGroupTypeIds.Any() ) .Select( t => t.Id ) .ToList(); while ( emptyGroupTypeIds.Any() ) { NavData.GroupTypes = NavData.GroupTypes.Where( t => !emptyGroupTypeIds.Contains( t.Id ) ).ToList(); NavData.GroupTypes.ForEach( t => t.ChildGroupTypeIds = t.ChildGroupTypeIds.Where( c => !emptyGroupTypeIds.Contains( c ) ).ToList() ); emptyGroupTypeIds = NavData.GroupTypes .Where( t => !t.ChildGroupIds.Any() && !t.ChildGroupTypeIds.Any() ) .Select( t => t.Id ) .ToList(); } // If not group types left, redirect to area select page if ( NavData.GroupTypes.Count == 0 ) { NavigateToLinkedPage( "AreaSelectPage" ); } // Get the locations var locationIds = NavData.Groups.SelectMany( g => g.ChildLocationIds ).Distinct().ToList(); foreach ( var location in new LocationService( rockContext ) .Queryable( "ParentLocation" ).AsNoTracking() .Where( l => locationIds.Contains( l.Id ) ) ) { var navLocation = AddLocation( location, chartTimes ); navLocation.HasGroups = true; } // Get the attendance counts var dayStart = RockDateTime.Today; var now = RockDateTime.Now; groupIds = NavData.Groups.Select( g => g.Id ).ToList(); var attendances = new AttendanceService( rockContext ).Queryable() .Where( a => a.ScheduleId.HasValue && a.GroupId.HasValue && a.LocationId.HasValue && a.StartDateTime > dayStart && a.StartDateTime < now && a.DidAttend.HasValue && a.DidAttend.Value && groupIds.Contains( a.GroupId.Value ) && locationIds.Contains( a.LocationId.Value ) ) .ToList(); var schedules = new ScheduleService( rockContext ).Queryable() .Where( s => s.CheckInStartOffsetMinutes.HasValue ) .ToList(); foreach ( DateTime chartTime in chartTimes ) { // Get the active schedules var activeSchedules = new List<int>(); foreach ( var schedule in schedules ) { if ( schedule.WasScheduleOrCheckInActive( chartTime ) ) { activeSchedules.Add( schedule.Id ); } } bool current = chartTime.Equals( chartTimes.Max() ); foreach ( var groupLocSched in attendances .Where( a => a.StartDateTime < chartTime && a.PersonAlias != null && activeSchedules.Contains( a.ScheduleId.Value ) ) .GroupBy( a => new { ScheduleId = a.ScheduleId.Value, GroupId = a.GroupId.Value, LocationId = a.LocationId.Value } ) .Select( g => new { ScheduleId = g.Key.ScheduleId, GroupId = g.Key.GroupId, LocationId = g.Key.LocationId, PersonIds = g.Select( a => a.PersonAlias.PersonId ).Distinct().ToList() } ) ) { AddGroupCount( chartTime, groupLocSched.GroupId, groupLocSched.PersonIds, current ); AddLocationCount( chartTime, groupLocSched.LocationId, groupLocSched.PersonIds, current ); } } return NavData; } else { if ( string.IsNullOrWhiteSpace( PageParameter( "Area" ) ) ) { // If could not determine area and did not come from are select, redirect to area select page NavigateToLinkedPage( "AreaSelectPage" ); } nbWarning.Text = "Please select a valid Check-in type in the block settings."; nbWarning.Visible = true; pnlContent.Visible = false; } } return null; }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="action">The workflow action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> public override bool Execute( RockContext rockContext, Model.WorkflowAction action, Object entity, out List<string> errorMessages ) { var checkInState = GetCheckInState( entity, out errorMessages ); if ( checkInState != null && checkInState.CheckInType.TypeOfCheckin == TypeOfCheckin.Family ) { bool configPrevents = checkInState.CheckInType.PreventDuplicateCheckin; var family = checkInState.CheckIn.CurrentFamily; if ( family != null ) { var remove = GetAttributeValue( action, "Remove" ).AsBoolean(); var personIds = family.People.Select( p => p.Person.Id ).ToList(); var today = RockDateTime.Today; var tomorrow = RockDateTime.Today.AddDays( 1 ); var existingAttendance = new AttendanceService( rockContext ) .Queryable().AsNoTracking() .Where( a => a.StartDateTime.CompareTo( today ) >= 0 && a.StartDateTime.CompareTo( tomorrow ) < 0 && a.DidAttend.HasValue && a.DidAttend.Value && a.PersonAlias != null && personIds.Contains( a.PersonAlias.PersonId ) && a.ScheduleId.HasValue ) .Select( a => new { PersonId = a.PersonAlias.PersonId, ScheduleId = a.ScheduleId.Value } ) .ToList(); if ( existingAttendance.Any() ) { foreach ( var person in family.People.ToList() ) { var attendedScheduleIds = existingAttendance.Where( a => a.PersonId == person.Person.Id ).Select( a => a.ScheduleId ).ToList(); if ( attendedScheduleIds.Any() ) { foreach ( var groupType in person.GroupTypes.ToList() ) { if ( configPrevents || groupType.GroupType.GetAttributeValue( "PreventDuplicateCheckin" ).AsBoolean() ) { attendedScheduleIds.ForEach( s => groupType.AvailableForSchedule.Remove( s ) ); if ( !groupType.AvailableForSchedule.Any() ) { person.GroupTypes.Remove( groupType ); } else { foreach ( var group in groupType.Groups.ToList() ) { attendedScheduleIds.ForEach( s => group.AvailableForSchedule.Remove( s ) ); if ( !group.AvailableForSchedule.Any() ) { groupType.Groups.Remove( group ); } else { foreach ( var location in group.Locations.ToList() ) { attendedScheduleIds.ForEach( s => location.AvailableForSchedule.Remove( s ) ); if ( !location.AvailableForSchedule.Any() ) { group.Locations.Remove( location ); } } if ( group.Locations.Count == 0 ) { groupType.Groups.Remove( group ); } } } if ( groupType.Groups.Count == 0 ) { person.GroupTypes.Remove( groupType ); } } } } if ( person.GroupTypes.Count == 0 ) { family.People.Remove( person ); } } } } } return true; } return false; }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="action">The action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public override bool Execute( RockContext rockContext, WorkflowAction action, Object entity, out List<string> errorMessages ) { errorMessages = new List<string>(); Guid? groupGuid = null; Person person = null; DateTime attendanceDateTime = DateTime.Now; bool addToGroup = true; // get the group attribute Guid groupAttributeGuid = GetAttributeValue(action, "Group").AsGuid(); if ( !groupAttributeGuid.IsEmpty() ) { groupGuid = action.GetWorklowAttributeValue(groupAttributeGuid).AsGuidOrNull(); if ( !groupGuid.HasValue ) { errorMessages.Add("The group could not be found!"); } } // get person alias guid Guid personAliasGuid = Guid.Empty; string personAttribute = GetAttributeValue( action, "Person" ); Guid guid = personAttribute.AsGuid(); if (!guid.IsEmpty()) { var attribute = AttributeCache.Read( guid, rockContext ); if ( attribute != null ) { string value = action.GetWorklowAttributeValue(guid); personAliasGuid = value.AsGuid(); } if ( personAliasGuid != Guid.Empty ) { person = new PersonAliasService(rockContext).Queryable().AsNoTracking() .Where(p => p.Guid.Equals(personAliasGuid)) .Select(p => p.Person) .FirstOrDefault(); } else { errorMessages.Add("The person could not be found in the attribute!"); } } // get attendance date Guid dateTimeAttributeGuid = GetAttributeValue(action, "AttendanceDatetime").AsGuid(); if ( !dateTimeAttributeGuid.IsEmpty() ) { string attributeDatetime = action.GetWorklowAttributeValue(dateTimeAttributeGuid); if ( !string.IsNullOrWhiteSpace(attributeDatetime) ) { if ( !DateTime.TryParse(attributeDatetime, out attendanceDateTime) ) { errorMessages.Add(string.Format("Could not parse the date provided {0}.", attributeDatetime)); } } } // get add to group addToGroup = GetAttributeValue(action, "AddToGroup").AsBoolean(); // get location Guid locationGuid = Guid.Empty; Guid locationAttributeGuid = GetAttributeValue(action, "Location").AsGuid(); if ( !locationAttributeGuid.IsEmpty() ) { var locationAttribute = AttributeCache.Read(locationAttributeGuid, rockContext); if ( locationAttribute != null ) { locationGuid = action.GetWorklowAttributeValue(locationAttributeGuid).AsGuid(); } } //// get Schedule Guid scheduleGuid = Guid.Empty; Guid scheduleAttributeGuid = GetAttributeValue( action, "Schedule" ).AsGuid(); if ( !scheduleAttributeGuid.IsEmpty() ) { var scheduleAttribute = AttributeCache.Read( scheduleAttributeGuid, rockContext ); if ( scheduleAttribute != null ) { scheduleGuid = action.GetWorklowAttributeValue( scheduleAttributeGuid ).AsGuid(); } } // set attribute if ( groupGuid.HasValue && person != null && attendanceDateTime != DateTime.MinValue ) { var group = new GroupService(rockContext).Queryable("GroupType.DefaultGroupRole") .Where(g => g.Guid == groupGuid) .FirstOrDefault(); if ( group != null ) { GroupMemberService groupMemberService = new GroupMemberService(rockContext); // get group member var groupMember = groupMemberService.Queryable() .Where(m => m.Group.Guid == groupGuid && m.PersonId == person.Id) .FirstOrDefault(); if ( groupMember == null ) { if ( addToGroup ) { if ( group != null ) { groupMember = new GroupMember(); groupMember.GroupId = group.Id; groupMember.PersonId = person.Id; groupMember.GroupMemberStatus = GroupMemberStatus.Active; groupMember.GroupRole = group.GroupType.DefaultGroupRole; groupMemberService.Add(groupMember); rockContext.SaveChanges(); } } else { action.AddLogEntry(string.Format("{0} was not a member of the group {1} and the action was not configured to add them.", person.FullName, group.Name)); } } AttendanceService attendanceService = new AttendanceService(rockContext); Attendance attendance = new Attendance(); attendance.GroupId = group.Id; attendance.PersonAliasId = person.PrimaryAliasId; attendance.StartDateTime = attendanceDateTime; attendance.CampusId = group.CampusId; attendance.DidAttend = true; if ( locationGuid != Guid.Empty ) { var location = new LocationService(rockContext).Queryable().AsNoTracking() .Where(l => l.Guid == locationGuid) .FirstOrDefault(); if ( location != null ) { attendance.LocationId = location.Id; } } attendanceService.Add(attendance); rockContext.SaveChanges(); if ( attendance.LocationId.HasValue ) { Rock.CheckIn.KioskLocationAttendance.Flush( attendance.LocationId.Value ); } } else { errorMessages.Add(string.Format("Could not find group matching the guid '{0}'.", groupGuid)); } } errorMessages.ForEach( m => action.AddLogEntry( m, true ) ); return true; }
/// <summary> /// Binds the attendees grid. /// </summary> private void BindAttendeesGrid() { var dateRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues( drpSlidingDateRange.DelimitedValues ); if ( dateRange.End == null || dateRange.End > RockDateTime.Now ) { dateRange.End = RockDateTime.Now; } var rockContext = new RockContext(); // make a qryPersonAlias so that the generated SQL will be a "WHERE .. IN ()" instead of an OUTER JOIN (which is incredibly slow for this) var qryPersonAlias = new PersonAliasService( rockContext ).Queryable(); var qryAttendance = new AttendanceService( rockContext ).Queryable(); qryAttendance = qryAttendance.Where( a => a.DidAttend.HasValue && a.DidAttend.Value ); var groupType = this.GetSelectedTemplateGroupType(); var qryAllVisits = qryAttendance; if ( groupType != null ) { var childGroupTypeIds = new GroupTypeService( rockContext ).GetChildGroupTypes( groupType.Id ).Select( a => a.Id ); qryAllVisits = qryAttendance.Where( a => childGroupTypeIds.Any( b => b == a.Group.GroupTypeId ) ); } else { return; } var groupIdList = new List<int>(); string groupIds = GetSelectedGroupIds().AsDelimited( "," ); if ( !string.IsNullOrWhiteSpace( groupIds ) ) { groupIdList = groupIds.Split( ',' ).AsIntegerList(); qryAttendance = qryAttendance.Where( a => a.GroupId.HasValue && groupIdList.Contains( a.GroupId.Value ) ); } //// If campuses were included, filter attendances by those that have selected campuses //// if 'null' is one of the campuses, treat that as a 'CampusId is Null' var includeNullCampus = clbCampuses.SelectedValues.Any( a => a.Equals( "null", StringComparison.OrdinalIgnoreCase ) ); var campusIdList = clbCampuses.SelectedValues.AsIntegerList(); // remove 0 from the list, just in case it is there campusIdList.Remove( 0 ); if ( campusIdList.Any() ) { if ( includeNullCampus ) { // show records that have a campusId in the campusIdsList + records that have a null campusId qryAttendance = qryAttendance.Where( a => ( a.CampusId.HasValue && campusIdList.Contains( a.CampusId.Value ) ) || !a.CampusId.HasValue ); } else { // only show records that have a campusId in the campusIdList qryAttendance = qryAttendance.Where( a => a.CampusId.HasValue && campusIdList.Contains( a.CampusId.Value ) ); } } else if ( includeNullCampus ) { // 'null' was the only campusId in the campusIds parameter, so only show records that have a null CampusId qryAttendance = qryAttendance.Where( a => !a.CampusId.HasValue ); } // have the "Missed" query be the same as the qry before the Main date range is applied since it'll have a different date range var qryMissed = qryAttendance; if ( dateRange.Start.HasValue ) { qryAttendance = qryAttendance.Where( a => a.StartDateTime >= dateRange.Start.Value ); } if ( dateRange.End.HasValue ) { qryAttendance = qryAttendance.Where( a => a.StartDateTime < dateRange.End.Value ); } // we want to get the first 2 visits at a minimum so we can show the date in the grid int nthVisitsTake = 2; int? byNthVisit = null; if ( radByVisit.Checked ) { // If we are filtering by nth visit, we might want to get up to first 5 byNthVisit = ddlNthVisit.SelectedValue.AsIntegerOrNull(); if ( byNthVisit.HasValue && byNthVisit > 2 ) { nthVisitsTake = byNthVisit.Value; } } ChartGroupBy groupBy = hfGroupBy.Value.ConvertToEnumOrNull<ChartGroupBy>() ?? ChartGroupBy.Week; IQueryable<PersonWithSummary> qryByPersonWithSummary = null; if ( byNthVisit.HasValue && byNthVisit.Value == 0 ) { // Show members of the selected groups that did not attend at all during selected date range // Get all the person ids that did attend var attendeePersonIds = qryAttendance.Select( a => a.PersonAlias.PersonId ); // Get all the active members of the selected groups who have no attendance within selected date range and campus qryByPersonWithSummary = new GroupMemberService( rockContext ) .Queryable().AsNoTracking() .Where( m => groupIdList.Contains( m.GroupId ) && !attendeePersonIds.Contains( m.PersonId ) && m.GroupMemberStatus == GroupMemberStatus.Active ) .Select( m => new PersonWithSummary { PersonId = m.PersonId, FirstVisits = new DateTime[] { }.AsQueryable(), LastVisit = new AttendancePersonAlias(), AttendanceSummary = new DateTime[] { }.AsQueryable() } ); } else { var qryAttendanceWithSummaryDateTime = qryAttendance.GetAttendanceWithSummaryDateTime( groupBy ); var qryGroup = new GroupService( rockContext ).Queryable(); var qryJoinPerson = qryAttendance.Join( qryPersonAlias, k1 => k1.PersonAliasId, k2 => k2.Id, ( a, pa ) => new { CampusId = a.CampusId, GroupId = a.GroupId, ScheduleId = a.ScheduleId, StartDateTime = a.StartDateTime, PersonAliasId = pa.Id, PersonAliasPersonId = pa.PersonId } ); var qryJoinFinal = qryJoinPerson.Join( qryGroup, k1 => k1.GroupId, k2 => k2.Id, ( a, g ) => new AttendancePersonAlias { CampusId = a.CampusId, GroupId = a.GroupId, GroupName = g.Name, ScheduleId = a.ScheduleId, StartDateTime = a.StartDateTime, PersonAliasId = a.PersonAliasId, PersonAliasPersonId = a.PersonAliasPersonId } ); var qryByPerson = qryJoinFinal.GroupBy( a => a.PersonAliasPersonId ).Select( a => new { PersonId = a.Key, Attendances = a } ); int? attendedMinCount = null; int? attendedMissedCount = null; DateRange attendedMissedDateRange = new DateRange(); if ( radByPattern.Checked ) { attendedMinCount = tbPatternXTimes.Text.AsIntegerOrNull(); if ( cbPatternAndMissed.Checked ) { attendedMissedCount = tbPatternMissedXTimes.Text.AsIntegerOrNull(); attendedMissedDateRange = new DateRange( drpPatternDateRange.LowerValue, drpPatternDateRange.UpperValue ); if ( !attendedMissedDateRange.Start.HasValue || !attendedMissedDateRange.End.HasValue ) { nbMissedDateRangeRequired.Visible = true; return; } } } nbMissedDateRangeRequired.Visible = false; // get either the first 2 visits or the first 5 visits (using a const take of 2 or 5 vs a variable to help the SQL optimizer) qryByPersonWithSummary = qryByPerson.Select( a => new PersonWithSummary { PersonId = a.PersonId, FirstVisits = qryAllVisits.Where( b => qryPersonAlias.Where( pa => pa.PersonId == a.PersonId ).Any( pa => pa.Id == b.PersonAliasId ) ).Select( s => s.StartDateTime ).OrderBy( x => x ).Take( 2 ), LastVisit = a.Attendances.OrderByDescending( x => x.StartDateTime ).FirstOrDefault(), AttendanceSummary = qryAttendanceWithSummaryDateTime.Where( x => qryPersonAlias.Where( pa => pa.PersonId == a.PersonId ).Any( pa => pa.Id == x.Attendance.PersonAliasId ) ).GroupBy( g => g.SummaryDateTime ).Select( s => s.Key ) } ); if ( nthVisitsTake > 2 ) { qryByPersonWithSummary = qryByPerson.Select( a => new PersonWithSummary { PersonId = a.PersonId, FirstVisits = qryAllVisits.Where( b => qryPersonAlias.Where( pa => pa.PersonId == a.PersonId ).Any( pa => pa.Id == b.PersonAliasId ) ).Select( s => s.StartDateTime ).OrderBy( x => x ).Take( 5 ), LastVisit = a.Attendances.OrderByDescending( x => x.StartDateTime ).FirstOrDefault(), AttendanceSummary = qryAttendanceWithSummaryDateTime.Where( x => qryPersonAlias.Where( pa => pa.PersonId == a.PersonId ).Any( pa => pa.Id == x.Attendance.PersonAliasId ) ).GroupBy( g => g.SummaryDateTime ).Select( s => s.Key ) } ); } if ( byNthVisit.HasValue ) { // only return attendees where their nth visit is within the selected daterange int skipCount = byNthVisit.Value - 1; qryByPersonWithSummary = qryByPersonWithSummary.Where( a => a.FirstVisits.OrderBy( x => x ).Skip( skipCount ).Take( 1 ).Any( d => d >= dateRange.Start && d < dateRange.End ) ); } if ( attendedMinCount.HasValue ) { qryByPersonWithSummary = qryByPersonWithSummary.Where( a => a.AttendanceSummary.Count() >= attendedMinCount ); } if ( attendedMissedCount.HasValue ) { if ( attendedMissedDateRange.Start.HasValue && attendedMissedDateRange.End.HasValue ) { var attendedMissedPossible = GetPossibleAttendancesForDateRange( attendedMissedDateRange, groupBy ); int attendedMissedPossibleCount = attendedMissedPossible.Count(); qryMissed = qryMissed.Where( a => a.StartDateTime >= attendedMissedDateRange.Start.Value && a.StartDateTime < attendedMissedDateRange.End.Value ); var qryMissedAttendanceByPersonAndSummary = qryMissed.GetAttendanceWithSummaryDateTime( groupBy ) .GroupBy( g1 => new { g1.SummaryDateTime, g1.Attendance.PersonAlias.PersonId } ) .GroupBy( a => a.Key.PersonId ) .Select( a => new { PersonId = a.Key, AttendanceCount = a.Count() } ); var qryMissedByPerson = qryMissedAttendanceByPersonAndSummary .Where( x => ( attendedMissedPossibleCount - x.AttendanceCount ) >= attendedMissedCount ); // filter to only people that missed at least X weeks/months/years between specified missed date range qryByPersonWithSummary = qryByPersonWithSummary.Where( a => qryMissedByPerson.Any( b => b.PersonId == a.PersonId ) ); } } } var personService = new PersonService( rockContext ); // Filter by dataview var dataViewId = dvpDataView.SelectedValueAsInt(); if ( dataViewId.HasValue ) { var dataView = new DataViewService( _rockContext ).Get( dataViewId.Value ); if ( dataView != null ) { var errorMessages = new List<string>(); ParameterExpression paramExpression = personService.ParameterExpression; Expression whereExpression = dataView.GetExpression( personService, paramExpression, out errorMessages ); SortProperty sort = null; var dataViewPersonIdQry = personService .Queryable().AsNoTracking() .Where( paramExpression, whereExpression, sort ) .Select( p => p.Id ); qryByPersonWithSummary = qryByPersonWithSummary.Where( a => dataViewPersonIdQry.Contains( a.PersonId ) ); } } // declare the qryResult that we'll use in case they didn't choose IncludeParents or IncludeChildren (and the Anonymous Type will also work if we do include parents or children) var qryPerson = personService.Queryable(); var qryResult = qryByPersonWithSummary.Join( qryPerson, a => a.PersonId, p => p.Id, ( a, p ) => new { a.PersonId, ParentId = (int?)null, ChildId = (int?)null, Person = p, Parent = (Person)null, Child = (Person)null, a.FirstVisits, a.LastVisit, p.PhoneNumbers, a.AttendanceSummary } ); var includeParents = hfViewBy.Value.ConvertToEnumOrNull<ViewBy>().GetValueOrDefault( ViewBy.Attendees ) == ViewBy.ParentsOfAttendees; var includeChildren = hfViewBy.Value.ConvertToEnumOrNull<ViewBy>().GetValueOrDefault( ViewBy.Attendees ) == ViewBy.ChildrenOfAttendees; // if Including Parents, join with qryChildWithParent instead of qryPerson if ( includeParents ) { var qryChildWithParent = new PersonService( rockContext ).GetChildWithParent(); qryResult = qryByPersonWithSummary.Join( qryChildWithParent, a => a.PersonId, p => p.Child.Id, ( a, p ) => new { a.PersonId, ParentId = (int?)p.Parent.Id, ChildId = (int?)null, Person = p.Child, Parent = p.Parent, Child = (Person)null, a.FirstVisits, a.LastVisit, p.Parent.PhoneNumbers, a.AttendanceSummary } ); } if ( includeChildren ) { var qryParentWithChildren = new PersonService( rockContext ).GetParentWithChild(); qryResult = qryByPersonWithSummary.Join( qryParentWithChildren, a => a.PersonId, p => p.Parent.Id, ( a, p ) => new { a.PersonId, ParentId = (int?)null, ChildId = (int?)p.Child.Id, Person = p.Parent, Parent = (Person)null, Child = p.Child, a.FirstVisits, a.LastVisit, p.Child.PhoneNumbers, a.AttendanceSummary } ); } var parentField = gAttendeesAttendance.Columns.OfType<PersonField>().FirstOrDefault( a => a.HeaderText == "Parent" ); if ( parentField != null ) { parentField.Visible = includeParents; } var parentEmailField = gAttendeesAttendance.Columns.OfType<RockBoundField>().FirstOrDefault( a => a.HeaderText == "Parent Email" ); if ( parentEmailField != null ) { parentEmailField.ExcelExportBehavior = includeParents ? ExcelExportBehavior.AlwaysInclude : ExcelExportBehavior.NeverInclude; } var childField = gAttendeesAttendance.Columns.OfType<PersonField>().FirstOrDefault( a => a.HeaderText == "Child" ); if ( childField != null ) { childField.Visible = includeChildren; } var childEmailField = gAttendeesAttendance.Columns.OfType<RockBoundField>().FirstOrDefault( a => a.HeaderText == "Child Email" ); if ( childEmailField != null ) { childEmailField.ExcelExportBehavior = includeChildren ? ExcelExportBehavior.AlwaysInclude : ExcelExportBehavior.NeverInclude; } SortProperty sortProperty = gAttendeesAttendance.SortProperty; if ( sortProperty != null ) { if ( sortProperty.Property == "AttendanceSummary.Count" ) { if ( sortProperty.Direction == SortDirection.Descending ) { qryResult = qryResult.OrderByDescending( a => a.AttendanceSummary.Count() ); } else { qryResult = qryResult.OrderBy( a => a.AttendanceSummary.Count() ); } } else if ( sortProperty.Property == "FirstVisit.StartDateTime" ) { if ( sortProperty.Direction == SortDirection.Descending ) { qryResult = qryResult.OrderByDescending( a => a.FirstVisits.Min() ); } else { qryResult = qryResult.OrderBy( a => a.FirstVisits.Min() ); } } else { qryResult = qryResult.Sort( sortProperty ); } } else { qryResult = qryResult.OrderBy( a => a.Person.LastName ).ThenBy( a => a.Person.NickName ); } var attendancePercentField = gAttendeesAttendance.Columns.OfType<RockTemplateField>().First( a => a.HeaderText.EndsWith( "Attendance %" ) ); attendancePercentField.HeaderText = string.Format( "{0}ly Attendance %", groupBy.ConvertToString() ); // Calculate all the possible attendance summary dates UpdatePossibleAttendances( dateRange, groupBy ); // pre-load the schedule names since FriendlyScheduleText requires building the ICal object, etc _scheduleNameLookup = new ScheduleService( rockContext ).Queryable() .ToList() .ToDictionary( k => k.Id, v => v.FriendlyScheduleText ); if ( includeParents ) { gAttendeesAttendance.PersonIdField = "ParentId"; gAttendeesAttendance.DataKeyNames = new string[] { "ParentId", "PersonId" }; } else if ( includeChildren ) { gAttendeesAttendance.PersonIdField = "ChildId"; gAttendeesAttendance.DataKeyNames = new string[] { "ChildId", "PersonId" }; } else { gAttendeesAttendance.PersonIdField = "PersonId"; gAttendeesAttendance.DataKeyNames = new string[] { "PersonId" }; } // Create the dynamic attendance grid columns as needed CreateDynamicAttendanceGridColumns(); try { nbAttendeesError.Visible = false; // increase the timeout from 30 to 90. The Query can be slow if SQL hasn't calculated the Query Plan for the query yet. // Sometimes, most of the time consumption is figuring out the Query Plan, but after it figures it out, it caches it so that the next time it'll be much faster rockContext.Database.CommandTimeout = 90; gAttendeesAttendance.SetLinqDataSource( qryResult.AsNoTracking() ); gAttendeesAttendance.DataBind(); } catch ( Exception exception ) { LogAndShowException( exception ); } }
/// <summary> /// Gets the expression. /// </summary> /// <param name="context">The context.</param> /// <param name="entityIdProperty">The entity identifier property.</param> /// <param name="selection">The selection.</param> /// <returns></returns> public override Expression GetExpression( RockContext context, MemberExpression entityIdProperty, string selection ) { Guid groupTypeGuid = selection.AsGuid(); if ( groupTypeGuid != Guid.Empty ) { AttendanceService attendanceService = new AttendanceService( context ); var groupAttendanceQry = attendanceService.Queryable().Where( a => a.Group.GroupType.Guid == groupTypeGuid); var qry = new PersonService( context ).Queryable() .Select( p => groupAttendanceQry.Where( xx => xx.PersonAlias.PersonId == p.Id && xx.DidAttend == true ).Max( xx => xx.StartDateTime )); Expression selectExpression = SelectExpressionExtractor.Extract( qry, entityIdProperty, "p" ); return selectExpression; } return null; }
private void ShowDetail(Guid personGuid) { using ( var rockContext = new RockContext() ) { var personService = new PersonService( new RockContext() ); var person = personService.Get( personGuid ); if ( person != null ) { lName.Text = person.FullName; string photoTag = Rock.Model.Person.GetPhotoImageTag( person, 120, 120 ); if ( person.PhotoId.HasValue ) { lPhoto.Text = string.Format( "<a href='{0}'>{1}</a>", person.PhotoUrl, photoTag ); } else { lPhoto.Text = photoTag; } lEmail.Visible = !string.IsNullOrWhiteSpace( person.Email ); lEmail.Text = person.GetEmailTag( ResolveRockUrl( "/" ), "btn btn-default", "<i class='fa fa-envelope'></i>" ); var childGuid = Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_CHILD.AsGuid(); var isFamilyChild = new Dictionary<int, bool>(); var allFamilyMembers = person.GetFamilyMembers( true ).ToList(); allFamilyMembers.Where( m => m.PersonId == person.Id ).ToList().ForEach( m => isFamilyChild.Add( m.GroupId, m.GroupRole.Guid.Equals( childGuid ) ) ); string urlRoot = Request.Url.ToString().ReplaceCaseInsensitive( personGuid.ToString(), "" ); var familyMembers = allFamilyMembers.Where( m => m.PersonId != person.Id ) .OrderBy( m => m.GroupId ) .ThenBy( m => m.Person.BirthDate ) .Select( m => new { Url = urlRoot + m.Person.Guid.ToString(), FullName = m.Person.FullName, Gender = m.Person.Gender, FamilyRole = m.GroupRole, Note = isFamilyChild[m.GroupId] ? ( m.GroupRole.Guid.Equals( childGuid ) ? " (Sibling)" : "(Parent)" ) : ( m.GroupRole.Guid.Equals( childGuid ) ? " (Child)" : "" ) } ) .ToList(); rcwFamily.Visible = familyMembers.Any(); rptrFamily.DataSource = familyMembers; rptrFamily.DataBind(); rptrPhones.DataSource = person.PhoneNumbers.Where( p => !p.IsUnlisted ).ToList(); rptrPhones.DataBind(); var schedules = new ScheduleService( rockContext ).Queryable() .Where( s => s.CheckInStartOffsetMinutes.HasValue ) .ToList(); var scheduleIds = schedules.Select( s => s.Id ).ToList(); var activeScheduleIds = new List<int>(); foreach ( var schedule in schedules ) { if ( schedule.IsScheduleOrCheckInActive ) { activeScheduleIds.Add( schedule.Id ); } } int? personAliasId = person.PrimaryAliasId; if ( !personAliasId.HasValue ) { personAliasId = new PersonAliasService( rockContext ).GetPrimaryAliasId( person.Id ); } var attendances = new AttendanceService( rockContext ) .Queryable( "Schedule,Group,Location" ) .Where( a => a.PersonAliasId.HasValue && a.PersonAliasId == personAliasId && a.ScheduleId.HasValue && a.GroupId.HasValue && a.LocationId.HasValue && a.DidAttend.HasValue && a.DidAttend.Value && scheduleIds.Contains( a.ScheduleId.Value ) ) .OrderByDescending( a => a.StartDateTime ) .Take( 20 ) .Select( a => new AttendanceInfo { Date = a.StartDateTime, GroupId = a.Group.Id, Group = a.Group.Name, LocationId = a.LocationId.Value, Location = a.Location.Name, Schedule = a.Schedule.Name, IsActive = a.StartDateTime > DateTime.Today && activeScheduleIds.Contains( a.ScheduleId.Value ) } ).ToList(); // Set active locations to be a link to the room in manager page var qryParam = new Dictionary<string, string>(); qryParam.Add( "Group", "" ); qryParam.Add( "Location", "" ); foreach ( var attendance in attendances.Where( a => a.IsActive ) ) { qryParam["Group"] = attendance.GroupId.ToString(); qryParam["Location"] = attendance.LocationId.ToString(); attendance.Location = string.Format( "<a href='{0}'>{1}</a>", LinkedPageUrl( "ManagerPage", qryParam ), attendance.Location ); } rcwCheckinHistory.Visible = attendances.Any(); gHistory.DataSource = attendances; gHistory.DataBind(); } } }
/// <summary> /// Binds the filter. /// </summary> private void BindFilter() { drpDates.DelimitedValues = rFilter.GetUserPreference( "Date Range" ); var attendanceService = new AttendanceService( new RockContext() ); var attendanceQuery = attendanceService.Queryable(); if ( _person != null ) { attendanceQuery = attendanceQuery.Where( a => a.PersonId == _person.Id ); ddlGroups.DataSource = attendanceQuery.Select( a => a.Group ).Distinct().OrderBy( a => a.Name ).ToList(); ddlGroups.DataBind(); ddlGroups.Items.Insert( 0, Rock.Constants.All.ListItem ); ddlGroups.Visible = attendanceQuery.Select( a => a.Group ).Distinct().ToList().Any(); ddlGroups.SetValue( rFilter.GetUserPreference( "Group" ) ); ddlPeople.Visible = false; } if ( _group != null ) { attendanceQuery = attendanceQuery.Where( a => a.GroupId == _group.Id ); var attendanceList = attendanceQuery.ToList(); ddlPeople.DataSource = attendanceList.OrderBy( a => a.Person.FullName ).Select( a => a.Person.FullName ).Distinct(); ddlPeople.DataBind(); ddlPeople.Items.Insert( 0, Rock.Constants.All.ListItem ); ddlPeople.Visible = attendanceList.Select( a => a.Person.FullName ).Distinct().Any(); ddlPeople.SetValue( rFilter.GetUserPreference( "Person" ) ); ddlGroups.Visible = false; } ddlSchedules.DataSource = attendanceQuery.OrderBy( a => a.Schedule.Name ).Select( a => a.Schedule.Name ).Distinct().ToList(); ddlSchedules.DataBind(); ddlSchedules.Items.Insert( 0, Rock.Constants.All.ListItem ); ddlSchedules.Visible = attendanceQuery.Select( a => a.Schedule.Name ).Distinct().ToList().Any(); ddlSchedules.SetValue( rFilter.GetUserPreference( "Schedule" ) ); }
/// <summary> /// Executes the specified context. /// </summary> /// <param name="context">The context.</param> public virtual void Execute( IJobExecutionContext context ) { JobDataMap dataMap = context.JobDetail.JobDataMap; var groupType = GroupTypeCache.Read( dataMap.GetString( "GroupType" ).AsGuid() ); int attendanceRemindersSent = 0; if ( groupType.TakesAttendance && groupType.SendAttendanceReminder ) { // Get the occurrence dates that apply var dates = new List<DateTime>(); dates.Add( RockDateTime.Today ); try { string[] reminderDays = dataMap.GetString( "SendReminders" ).Split( ',' ); foreach ( string reminderDay in reminderDays ) { if ( reminderDay.Trim() != string.Empty ) { var reminderDate = RockDateTime.Today.AddDays( 0 - Convert.ToInt32( reminderDay ) ); if ( !dates.Contains( reminderDate ) ) { dates.Add( reminderDate ); } } } } catch { } var rockContext = new RockContext(); var groupService = new GroupService( rockContext ); var groupMemberService = new GroupMemberService( rockContext ); var scheduleService = new ScheduleService( rockContext ); var attendanceService = new AttendanceService( rockContext ); var startDate = dates.Min(); var endDate = dates.Max().AddDays( 1 ); // Find all 'occurrences' for the groups that occur on the affected dates var occurrences = new Dictionary<int, List<DateTime>>(); foreach ( var group in groupService .Queryable( "Schedule" ).AsNoTracking() .Where( g => g.GroupTypeId == groupType.Id && g.IsActive && g.Schedule != null && g.Members.Any( m => m.GroupMemberStatus == GroupMemberStatus.Active && m.GroupRole.IsLeader && m.Person.Email != null && m.Person.Email != "" ) ) ) { // Add the group occurrences.Add( group.Id, new List<DateTime>() ); // Check for a iCal schedule if ( !string.IsNullOrWhiteSpace( group.Schedule.iCalendarContent ) ) { // If schedule has an iCal schedule, get occurrences between first and last dates foreach ( var occurrence in group.Schedule.GetOccurrences( startDate, endDate ) ) { var startTime = occurrence.Period.StartTime.Value; if ( dates.Contains( startTime.Date ) ) { occurrences[group.Id].Add( startTime ); } } } else { // if schedule does not have an iCal, then check for weekly schedule and calculate occurrences starting with first attendance or current week if ( group.Schedule.WeeklyDayOfWeek.HasValue ) { foreach ( var date in dates ) { if ( date.DayOfWeek == group.Schedule.WeeklyDayOfWeek.Value ) { var startTime = date; if ( group.Schedule.WeeklyTimeOfDay.HasValue ) { startTime = startTime.Add( group.Schedule.WeeklyTimeOfDay.Value ); } occurrences[group.Id].Add( startTime ); } } } } } // Remove any occurrences during group type exclusion date ranges foreach ( var exclusion in groupType.GroupScheduleExclusions ) { if ( exclusion.Start.HasValue && exclusion.End.HasValue ) { foreach ( var keyVal in occurrences ) { foreach ( var occurrenceDate in keyVal.Value.ToList() ) { if ( occurrenceDate >= exclusion.Start.Value && occurrenceDate < exclusion.End.Value.AddDays( 1 ) ) { keyVal.Value.Remove( occurrenceDate ); } } } } } // Remove any 'occurrenes' that already have attendance data entered foreach ( var occurrence in attendanceService .Queryable().AsNoTracking() .Where( a => a.StartDateTime >= startDate && a.StartDateTime < endDate && occurrences.Keys.Contains( a.GroupId.Value ) && a.ScheduleId.HasValue ) .Select( a => new { GroupId = a.GroupId.Value, a.StartDateTime } ) .Distinct() .ToList() ) { occurrences[occurrence.GroupId].RemoveAll( d => d.Date == occurrence.StartDateTime.Date ); } // Get the groups that have occurrences var groupIds = occurrences.Where( o => o.Value.Any() ).Select( o => o.Key ).ToList(); // Get the leaders of those groups var leaders = groupMemberService .Queryable( "Group,Person" ).AsNoTracking() .Where( m => groupIds.Contains( m.GroupId ) && m.GroupMemberStatus == GroupMemberStatus.Active && m.GroupRole.IsLeader && m.Person.Email != null && m.Person.Email != "" ) .ToList(); // Loop through the leaders foreach ( var leader in leaders ) { foreach ( var group in occurrences.Where( o => o.Key == leader.GroupId ) ) { var mergeObjects = Rock.Lava.LavaHelper.GetCommonMergeFields( null, leader.Person ); mergeObjects.Add( "Person", leader.Person ); mergeObjects.Add( "Group", leader.Group ); mergeObjects.Add( "Occurrence", group.Value.Max() ); var recipients = new List<RecipientData>(); recipients.Add( new RecipientData( leader.Person.Email, mergeObjects ) ); Email.Send( dataMap.GetString( "SystemEmail" ).AsGuid(), recipients ); attendanceRemindersSent++; } } } context.Result = string.Format( "{0} attendance reminders sent", attendanceRemindersSent ); }
public List <ScheduleOccurrence> GetGroupOccurrences(Group group, DateTime?fromDateTime, DateTime?toDateTime, List <int> locationIds, List <int> scheduleIds, bool loadSummaryData, int?campusId) { var occurrences = new List <ScheduleOccurrence>(); if (group != null) { var rockContext = (RockContext)this.Context; var attendanceService = new AttendanceService(rockContext); var scheduleService = new ScheduleService(rockContext); var locationService = new LocationService(rockContext); using (new Rock.Data.QueryHintScope(rockContext, QueryHintType.RECOMPILE)) { // Set up an 'occurrences' query for the group var qry = attendanceService .Queryable().AsNoTracking() .Where(a => a.GroupId == group.Id); // Filter by date range if (fromDateTime.HasValue) { var fromDate = fromDateTime.Value.Date; qry = qry.Where(a => DbFunctions.TruncateTime(a.StartDateTime) >= (fromDate)); } if (toDateTime.HasValue) { var toDate = toDateTime.Value.Date; qry = qry.Where(a => DbFunctions.TruncateTime(a.StartDateTime) < (toDate)); } // Location Filter if (locationIds.Any()) { qry = qry.Where(a => locationIds.Contains(a.LocationId ?? 0)); } // Schedule Filter if (scheduleIds.Any()) { qry = qry.Where(a => scheduleIds.Contains(a.ScheduleId ?? 0)); } // Get the unique combination of location/schedule/date for the selected group var occurrenceDates = qry .Select(a => new { a.LocationId, a.ScheduleId, Date = DbFunctions.TruncateTime(a.StartDateTime) }) .Distinct() .ToList(); // Get the locations for each unique location id var selectedlocationIds = occurrenceDates.Select(o => o.LocationId).Distinct().ToList(); var locations = locationService .Queryable().AsNoTracking() .Where(l => selectedlocationIds.Contains(l.Id)) .Select(l => new { l.Id, l.ParentLocationId, l.Name }) .ToList(); var locationNames = new Dictionary <int, string>(); locations.ForEach(l => locationNames.Add(l.Id, l.Name)); // Get the parent location path for each unique location var parentlocationPaths = new Dictionary <int, string>(); locations .Where(l => l.ParentLocationId.HasValue) .Select(l => l.ParentLocationId.Value) .Distinct() .ToList() .ForEach(l => parentlocationPaths.Add(l, locationService.GetPath(l))); var locationPaths = new Dictionary <int, string>(); locations .Where(l => l.ParentLocationId.HasValue) .ToList() .ForEach(l => locationPaths.Add(l.Id, parentlocationPaths[l.ParentLocationId.Value])); // Get the schedules for each unique schedule id var selectedScheduleIds = occurrenceDates.Select(o => o.ScheduleId).Distinct().ToList(); var schedules = scheduleService .Queryable().AsNoTracking() .Where(s => selectedScheduleIds.Contains(s.Id)) .ToList(); var scheduleNames = new Dictionary <int, string>(); var scheduleStartTimes = new Dictionary <int, TimeSpan>(); schedules .ForEach(s => { scheduleNames.Add(s.Id, s.Name); scheduleStartTimes.Add(s.Id, s.StartTimeOfDay); }); foreach (var occurrence in occurrenceDates.Where(o => o.Date.HasValue)) { occurrences.Add( new ScheduleOccurrence( occurrence.Date.Value, occurrence.ScheduleId.HasValue && scheduleStartTimes.ContainsKey(occurrence.ScheduleId.Value) ? scheduleStartTimes[occurrence.ScheduleId.Value] : new TimeSpan(), occurrence.ScheduleId, occurrence.ScheduleId.HasValue && scheduleNames.ContainsKey(occurrence.ScheduleId.Value) ? scheduleNames[occurrence.ScheduleId.Value] : string.Empty, occurrence.LocationId, occurrence.LocationId.HasValue && locationNames.ContainsKey(occurrence.LocationId.Value) ? locationNames[occurrence.LocationId.Value] : string.Empty, occurrence.LocationId.HasValue && locationPaths.ContainsKey(occurrence.LocationId.Value) ? locationPaths[occurrence.LocationId.Value] : string.Empty )); } } // Load the attendance data for each occurrence if (loadSummaryData && occurrences.Any()) { var minDate = occurrences.Min(o => o.Date); var maxDate = occurrences.Max(o => o.Date).AddDays(1); var attendanceQry = attendanceService .Queryable().AsNoTracking() .Where(a => a.GroupId.HasValue && a.GroupId == group.Id && a.StartDateTime >= minDate && a.StartDateTime < maxDate && a.PersonAlias != null && a.PersonAliasId.HasValue) .Select(a => new { a.LocationId, a.ScheduleId, a.StartDateTime, a.DidAttend, a.DidNotOccur, a.PersonAliasId, PersonId = a.PersonAlias.PersonId }); if (campusId.HasValue) { var familyGroupType = GroupTypeCache.Get(Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY.AsGuid()); var campusQry = new GroupMemberService(rockContext) .Queryable() .Where(g => g.Group != null && g.Group.GroupTypeId == familyGroupType.Id && g.Group.CampusId.HasValue && g.Group.CampusId.Value == campusId.Value ) .Select(m => m.PersonId); attendanceQry = attendanceQry .Where(s => campusQry.Contains(s.PersonId)); } var attendances = attendanceQry.ToList(); foreach (var summary in attendances .GroupBy(a => new { a.LocationId, a.ScheduleId, Date = a.StartDateTime.Date }) .Select(a => new { a.Key.LocationId, a.Key.ScheduleId, a.Key.Date, DidAttendCount = a .Where(t => t.DidAttend.HasValue && t.DidAttend.Value) .Select(t => t.PersonAliasId.Value) .Distinct() .Count(), DidNotOccurCount = a .Where(t => t.DidNotOccur.HasValue && t.DidNotOccur.Value) .Select(t => t.PersonAliasId.Value) .Distinct() .Count(), TotalCount = a .Select(t => t.PersonAliasId) .Distinct() .Count() })) { var occurrence = occurrences .Where(o => o.ScheduleId.Equals(summary.ScheduleId) && o.LocationId.Equals(summary.LocationId) && o.Date.Equals(summary.Date)) .FirstOrDefault(); if (occurrence != null) { occurrence.DidAttendCount = summary.DidAttendCount; occurrence.DidNotOccurCount = summary.DidNotOccurCount; occurrence.TotalCount = summary.TotalCount; } } } // Create any missing occurrences from the group's schedule (not location schedules) Schedule groupSchedule = null; if (group.ScheduleId.HasValue) { groupSchedule = group.Schedule; if (groupSchedule == null) { groupSchedule = new ScheduleService(rockContext).Get(group.ScheduleId.Value); } } if (groupSchedule != null) { var newOccurrences = new List <ScheduleOccurrence>(); var existingDates = occurrences .Where(o => o.ScheduleId.Equals(groupSchedule.Id)) .Select(o => o.Date) .Distinct() .ToList(); var startDate = fromDateTime.HasValue ? fromDateTime.Value : RockDateTime.Today.AddMonths(-2); var endDate = toDateTime.HasValue ? toDateTime.Value : RockDateTime.Today.AddDays(1); if (!string.IsNullOrWhiteSpace(groupSchedule.iCalendarContent)) { // If schedule has an iCal schedule, get all the past occurrences foreach (var occurrence in groupSchedule.GetOccurrences(startDate, endDate)) { var scheduleOccurrence = new ScheduleOccurrence( occurrence.Period.StartTime.Date, occurrence.Period.StartTime.TimeOfDay, groupSchedule.Id, groupSchedule.Name); if (!existingDates.Contains(scheduleOccurrence.Date)) { newOccurrences.Add(scheduleOccurrence); } } } else { // if schedule does not have an iCal, then check for weekly schedule and calculate occurrences starting with first attendance or current week if (groupSchedule.WeeklyDayOfWeek.HasValue) { // default to start with date 2 months earlier startDate = fromDateTime.HasValue ? fromDateTime.Value : RockDateTime.Today.AddMonths(-2); if (existingDates.Any(d => d < startDate)) { startDate = existingDates.Min(); } // Back up start time to the correct day of week while (startDate.DayOfWeek != groupSchedule.WeeklyDayOfWeek.Value) { startDate = startDate.AddDays(-1); } // Add the start time if (groupSchedule.WeeklyTimeOfDay.HasValue) { startDate = startDate.Add(groupSchedule.WeeklyTimeOfDay.Value); } // Create occurrences up to current time while (startDate < endDate) { if (!existingDates.Contains(startDate.Date)) { var scheduleOccurrence = new ScheduleOccurrence(startDate.Date, startDate.TimeOfDay, groupSchedule.Id, groupSchedule.Name); newOccurrences.Add(scheduleOccurrence); } startDate = startDate.AddDays(7); } } } if (newOccurrences.Any()) { // Filter Exclusions var groupType = GroupTypeCache.Get(group.GroupTypeId); foreach (var exclusion in groupType.GroupScheduleExclusions) { if (exclusion.Start.HasValue && exclusion.End.HasValue) { foreach (var occurrence in newOccurrences.ToList()) { if (occurrence.Date >= exclusion.Start.Value && occurrence.Date < exclusion.End.Value.AddDays(1)) { newOccurrences.Remove(occurrence); } } } } } foreach (var occurrence in newOccurrences) { occurrences.Add(occurrence); } } } return(occurrences); }