/// <summary> /// Binds the grid. /// </summary> private void BindGrid() { if (HasFilterErrors()) { return; } var checkinAreaFilter = CheckinManagerHelper.GetCheckinAreaFilter(this); CampusCache campus = GetCampusFromContext(); var selectedScheduleIds = lbSchedules.SelectedValues.AsIntegerList(); if (selectedScheduleIds.Any()) { btnShowFilter.AddCssClass("criteria-exists bg-warning"); } else { btnShowFilter.RemoveCssClass("criteria-exists bg-warning"); } CheckinManagerHelper.SaveRoomListFilterToCookie(selectedScheduleIds.ToArray()); var rockContext = new RockContext(); var groupService = new GroupService(rockContext); var groupTypeService = new GroupTypeService(rockContext); IEnumerable <CheckinAreaPath> checkinAreaPaths; if (checkinAreaFilter != null) { checkinAreaPaths = groupTypeService.GetCheckinAreaDescendantsPath(checkinAreaFilter.Id); } else { checkinAreaPaths = groupTypeService.GetAllCheckinAreaPaths(); } var selectedGroupTypeIds = checkinAreaPaths.Select(a => a.GroupTypeId).Distinct().ToArray(); var groupLocationService = new GroupLocationService(rockContext); var groupLocationsQuery = groupLocationService.Queryable() .Where(gl => selectedGroupTypeIds.Contains(gl.Group.GroupTypeId) && gl.Group.IsActive && (!gl.Group.IsArchived)); var parentLocationIdParameter = PageParameter(PageParameterKey.ParentLocationId).AsIntegerOrNull(); var locationIdParameter = PageParameter(PageParameterKey.LocationId).AsIntegerOrNull(); var locationGridField = gRoomList.ColumnsOfType <RockLiteralField>().FirstOrDefault(a => a.ID == "lRoomName"); if (locationGridField != null && !locationGridField.Visible) { locationGridField.Visible = true; } List <int> locationIds; if (locationIdParameter.HasValue) { // If LocationId is specified in the URL, list only items for the specified location. // Also, hide the Location Grid Column and set the PanelTitle as the location's name // This will take precedence over the selected campus+locations and/or <seealso cref="ParentLocationId"/> var locationService = new LocationService(rockContext); lPanelTitle.Text = locationService.GetSelect(locationIdParameter.Value, s => s.Name); locationIds = new List <int>(); locationIds.Add(locationIdParameter.Value); if (locationGridField != null) { // since a LocationId parameter was specified, the LocationGrid field doesn't need to be shown locationGridField.Visible = false; } } else if (parentLocationIdParameter.HasValue) { // If parentLocationId is specified, show the direct (first level) child locations of the specified ParentLocationId. // This will take precedence over the selected campus+locations. var locationService = new LocationService(rockContext); locationIds = locationService.Queryable() .Where(a => a.ParentLocationId.HasValue && a.ParentLocationId.Value == parentLocationIdParameter.Value) .Select(a => a.Id).ToList(); lPanelTitle.Text = string.Format("{0} Child Locations", locationService.GetSelect(parentLocationIdParameter.Value, s => s.Name)); } else { // Limit locations (rooms) to locations within the selected campus. locationIds = new LocationService(rockContext).GetAllDescendentIds(campus.LocationId.Value).ToList(); locationIds.Add(campus.LocationId.Value, true); lPanelTitle.Text = "Room List"; } groupLocationsQuery = groupLocationsQuery.Where(a => locationIds.Contains(a.LocationId)); if (selectedScheduleIds.Any()) { groupLocationsQuery = groupLocationsQuery.Where(a => a.Schedules.Any(s => s.IsActive && s.CheckInStartOffsetMinutes.HasValue && selectedScheduleIds.Contains(s.Id))); } else { groupLocationsQuery = groupLocationsQuery.Where(a => a.Schedules.Any(s => s.IsActive && s.CheckInStartOffsetMinutes.HasValue)); } var groupLocationList = groupLocationsQuery.Select(a => new GroupLocationInfo { LocationId = a.LocationId, LocationName = a.Location.Name, ParentGroupId = a.Group.ParentGroupId, ParentGroupName = a.Group.ParentGroup.Name, GroupId = a.Group.Id, GroupName = a.Group.Name, GroupTypeId = a.Group.GroupTypeId }).ToList(); var startDateTime = RockDateTime.Today; DateTime currentDateTime; if (campus != null) { currentDateTime = campus.CurrentDateTime; } else { currentDateTime = RockDateTime.Now; } // Get all Attendance records for the current day and location. var attendanceQuery = new AttendanceService(rockContext).Queryable().Where(a => a.StartDateTime >= startDateTime && a.DidAttend == true && a.StartDateTime <= currentDateTime && a.PersonAliasId.HasValue && a.Occurrence.GroupId.HasValue && a.Occurrence.LocationId.HasValue && a.Occurrence.ScheduleId.HasValue); // Limit attendances (rooms) to the groupLocations' LocationId and GroupIds that we'll be showing var groupLocationLocationIds = groupLocationList.Select(a => a.LocationId).Distinct().ToList(); var groupLocationGroupsIds = groupLocationList.Select(a => a.GroupId).Distinct().ToList(); attendanceQuery = attendanceQuery.Where(a => groupLocationLocationIds.Contains(a.Occurrence.LocationId.Value) && groupLocationGroupsIds.Contains(a.Occurrence.GroupId.Value)); attendanceQuery = attendanceQuery.Where(a => selectedGroupTypeIds.Contains(a.Occurrence.Group.GroupTypeId)); if (selectedScheduleIds.Any()) { attendanceQuery = attendanceQuery.Where(a => selectedScheduleIds.Contains(a.Occurrence.ScheduleId.Value)); } var rosterAttendeeAttendanceList = RosterAttendeeAttendance.Select(attendanceQuery).ToList(); var groupTypeIdsWithAllowCheckout = selectedGroupTypeIds .Select(a => GroupTypeCache.Get(a)) .Where(a => a != null) .Where(gt => gt.GetCheckInConfigurationAttributeValue(Rock.SystemKey.GroupTypeAttributeKey.CHECKIN_GROUPTYPE_ALLOW_CHECKOUT).AsBoolean()) .Select(a => a.Id) .Distinct().ToList(); var groupTypeIdsWithEnablePresence = selectedGroupTypeIds .Select(a => GroupTypeCache.Get(a)) .Where(a => a != null) .Where(gt => gt.GetCheckInConfigurationAttributeValue(Rock.SystemKey.GroupTypeAttributeKey.CHECKIN_GROUPTYPE_ENABLE_PRESENCE).AsBoolean()) .Select(a => a.Id) .Distinct(); var scheduleIds = rosterAttendeeAttendanceList.Select(a => a.ScheduleId.Value).Distinct().ToList(); var scheduleList = new ScheduleService(rockContext).GetByIds(scheduleIds).ToList(); var scheduleIdsWasScheduleOrCheckInActiveForCheckOut = new HashSet <int>(scheduleList.Where(a => a.WasScheduleOrCheckInActiveForCheckOut(currentDateTime)).Select(a => a.Id).ToList()); rosterAttendeeAttendanceList = rosterAttendeeAttendanceList.Where(a => { var allowCheckout = groupTypeIdsWithAllowCheckout.Contains(a.GroupTypeId); if (!allowCheckout) { /* * If AllowCheckout is false, remove all Attendees whose schedules are not currently active. Per the 'WasSchedule...ActiveForCheckOut()' * method below: "Check-out can happen while check-in is active or until the event ends (start time + duration)." This will help to keep * the list of 'Present' attendees cleaned up and accurate, based on the room schedules, since the volunteers have no way to manually mark * an Attendee as 'Checked-out'. * * If, on the other hand, AllowCheckout is true, it will be the volunteers' responsibility to click the [Check-out] button when an * Attendee leaves the room, in order to keep the list of 'Present' Attendees in order. This will also allow the volunteers to continue * 'Checking-out' Attendees in the case that the parents are running late in picking them up. */ return(scheduleIdsWasScheduleOrCheckInActiveForCheckOut.Contains(a.ScheduleId.Value)); } else { return(true); } }).ToList(); var attendancesByLocationId = rosterAttendeeAttendanceList .GroupBy(a => a.LocationId.Value).ToDictionary(k => k.Key, v => v.ToList()); _attendancesByLocationIdAndGroupId = attendancesByLocationId.ToDictionary( k => k.Key, v => v.Value.GroupBy(x => x.GroupId.Value).ToDictionary(x => x.Key, xx => xx.ToList())); _checkinAreaPathsLookupByGroupTypeId = checkinAreaPaths.ToDictionary(k => k.GroupTypeId, v => v); _showOnlyParentGroup = this.GetAttributeValue(AttributeKey.ShowOnlyParentGroup).AsBoolean(); var roomList = new List <RoomInfo>(); foreach (var groupLocation in groupLocationList) { AddToRoomList(roomList, groupLocation); } List <RoomInfo> sortedRoomList; if (_showOnlyParentGroup) { sortedRoomList = roomList.OrderBy(a => a.LocationName).ToList(); } else { sortedRoomList = new List <RoomInfo>(); sortedRoomList.AddRange(roomList.OfType <RoomInfoByGroup>().OrderBy(a => a.LocationName).ThenBy(a => a.GroupName).ToList()); } var checkedInCountField = gRoomList.ColumnsOfType <RockLiteralField>().FirstOrDefault(a => a.ID == "lCheckedInCount"); var presentCountField = gRoomList.ColumnsOfType <RockLiteralField>().FirstOrDefault(a => a.ID == "lPresentCount"); var checkedOutCountField = gRoomList.ColumnsOfType <RockLiteralField>().FirstOrDefault(a => a.ID == "lCheckedOutCount"); checkedOutCountField.Visible = groupTypeIdsWithAllowCheckout.Any(); // Always show Present Count regardless of the 'Enable Presence' setting. (A person gets automatically marked present if 'Enable Presence' is disabled.) presentCountField.Visible = true; if (groupTypeIdsWithEnablePresence.Any()) { // Presence is enabled, so records could be in the 'Checked-in' state // and Present column should be labeled 'Present'. checkedInCountField.Visible = true; presentCountField.HeaderText = "Present"; } else { // https://app.asana.com/0/0/1199637795718017/f // 'Enable Presence' is disabled, so a person automatically gets marked present. // So, no records will be in the 'Checked-In (but no present)' state. // Also, a user thinks of 'Present' as 'Checked-In' if they don't use the 'Enable Presence' feature checkedInCountField.Visible = false; presentCountField.HeaderText = "Checked-In"; } if (_showOnlyParentGroup) { gRoomList.DataKeyNames = new string[1] { "LocationId" }; } else { gRoomList.DataKeyNames = new string[2] { "LocationId", "GroupId" }; } gRoomList.DataSource = sortedRoomList; gRoomList.DataBind(); }
/// <summary> /// Gets the attendees. /// </summary> private IList <RosterAttendee> GetAttendees(RockContext rockContext) { var startDateTime = RockDateTime.Today; CampusCache campusCache = GetCampusFromContext(); DateTime currentDateTime; if (campusCache != null) { currentDateTime = campusCache.CurrentDateTime; } else { currentDateTime = RockDateTime.Now; } // Get all Attendance records for the current day and location var attendanceQuery = new AttendanceService(rockContext).Queryable().Where(a => a.StartDateTime >= startDateTime && a.DidAttend == true && a.StartDateTime <= currentDateTime && a.PersonAliasId.HasValue && a.Occurrence.GroupId.HasValue && a.Occurrence.ScheduleId.HasValue && a.Occurrence.LocationId.HasValue && a.Occurrence.ScheduleId.HasValue); if (campusCache != null) { // limit locations (rooms) to locations within the selected campus var campusLocationIds = new LocationService(rockContext).GetAllDescendentIds(campusCache.LocationId.Value).ToList(); attendanceQuery = attendanceQuery.Where(a => campusLocationIds.Contains(a.Occurrence.LocationId.Value)); } var selectedScheduleIds = lbSchedules.SelectedValues.AsIntegerList().Where(a => a > 0).ToList(); var selectedGroupIds = GetSelectedGroupIds(); if (selectedScheduleIds.Any()) { attendanceQuery = attendanceQuery.Where(a => selectedScheduleIds.Contains(a.Occurrence.ScheduleId.Value)); } if (selectedGroupIds.Any()) { if (cbIncludeChildGroups.Checked) { var groupService = new GroupService(rockContext); foreach (var groupId in selectedGroupIds.ToList()) { var childGroupIds = groupService.GetAllDescendentGroupIds(groupId, false); selectedGroupIds.AddRange(childGroupIds); } } attendanceQuery = attendanceQuery.Where(a => selectedGroupIds.Contains(a.Occurrence.GroupId.Value)); } else { var checkinAreaFilter = CheckinManagerHelper.GetCheckinAreaFilter(this); if (checkinAreaFilter != null) { // if there is a checkin area filter, limit to groups within the selected check-in area var checkinAreaGroupTypeIds = new GroupTypeService(rockContext).GetCheckinAreaDescendants(checkinAreaFilter.Id).Select(a => a.Id).ToList(); selectedGroupIds = new GroupService(rockContext).Queryable().Where(a => checkinAreaGroupTypeIds.Contains(a.GroupTypeId)).Select(a => a.Id).ToList(); attendanceQuery = attendanceQuery.Where(a => selectedGroupIds.Contains(a.Occurrence.GroupId.Value)); } } RosterStatusFilter rosterStatusFilter = this.GetAttributeValue(AttributeKey.FilterBy).ConvertToEnumOrNull <RosterStatusFilter>() ?? RosterStatusFilter.CheckedIn; attendanceQuery = CheckinManagerHelper.FilterByRosterStatusFilter(attendanceQuery, rosterStatusFilter); var attendanceList = RosterAttendeeAttendance.Select(attendanceQuery).ToList(); attendanceList = CheckinManagerHelper.FilterByActiveCheckins(currentDateTime, attendanceList); attendanceList = attendanceList.Where(a => a.Person != null).ToList(); if (tbSearch.Text.IsNotNullOrWhiteSpace()) { // search by name var searchValue = tbSearch.Text; // ignore the result of reversed (LastName, FirstName vs FirstName LastName bool reversed; var personIds = new PersonService(rockContext) .GetByFullName(searchValue, false, false, false, out reversed) .AsNoTracking() .Select(a => a.Id) .ToList(); attendanceList = attendanceList.Where(a => personIds.Contains(a.PersonId)).ToList(); } var attendees = RosterAttendee.GetFromAttendanceList(attendanceList); return(attendees); }
/// <summary> /// Gets the attendees. /// </summary> private IList <RosterAttendee> GetAttendees(RockContext rockContext) { var startDateTime = RockDateTime.Today; CampusCache campusCache = CampusCache.Get(CurrentCampusId); DateTime currentDateTime; if (campusCache != null) { currentDateTime = campusCache.CurrentDateTime; } else { currentDateTime = RockDateTime.Now; } // Get all Attendance records for the current day var attendanceQuery = new AttendanceService(rockContext) .Queryable() .Include(a => a.AttendanceCode) .Include(a => a.PersonAlias.Person) .Include(a => a.Occurrence.Schedule) .Include(a => a.Occurrence.Group) .Include(a => a.Occurrence.Location) .Where(a => a.StartDateTime >= startDateTime && a.DidAttend == true && a.StartDateTime <= currentDateTime && a.PersonAliasId.HasValue && a.Occurrence.GroupId.HasValue && a.Occurrence.ScheduleId.HasValue && a.Occurrence.LocationId.HasValue); attendanceQuery = attendanceQuery.Where(a => a.DidAttend == true); // Do the person search var personService = new PersonService(rockContext); List <int> personIds = null; // ignore the result of reversed (LastName, FirstName vs FirstName LastName bool reversed = false; string searchValue = tbSearch.Text.Trim(); if (searchValue.IsNullOrWhiteSpace()) { personIds = new List <int>(); } else { // If searching by code is enabled, first search by the code if (GetAttributeValue(AttributeKey.SearchByCode).AsBoolean()) { var dayStart = RockDateTime.Today; personIds = new AttendanceService(rockContext) .Queryable().Where(a => a.StartDateTime >= dayStart && a.StartDateTime <= currentDateTime && a.AttendanceCode.Code == searchValue) .Select(a => a.PersonAlias.PersonId) .Distinct().ToList(); } if (personIds == null || !personIds.Any()) { // If searching by code was disabled or nobody was found with code, search by name personIds = personService .GetByFullName(searchValue, false, false, false, out reversed) .AsNoTracking() .Select(a => a.Id) .ToList(); } } IList <RosterAttendee> attendees; if (personIds.Any()) { // Get *all* of today's transactions. // Not sure why we aren't filtering by PersonIds yet, but // it could be to make performance more consistent in case the PersonQuery is complex. var attendanceQueryList = RosterAttendeeAttendance.Select(attendanceQuery).ToList(); // join (in memory) matching person ids and attendances var peopleAttendances = personIds .GroupJoin( attendanceQueryList, pId => pId, a => a.PersonId, (p, a) => a) .SelectMany(a => a) .Distinct() .ToList(); attendees = RosterAttendee.GetFromAttendanceList(peopleAttendances); } else { // no matching persons, so return empty list attendees = new List <RosterAttendee>(); } return(attendees); }