예제 #1
0
        /// <summary>
        /// Handles the ItemDataBound event of the rLocations control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Web.UI.WebControls.RepeaterItemEventArgs"/> instance containing the event data.</param>
        protected void rLocations_ItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
        {
            object locationDataItem = e.Item.DataItem;

            if (locationDataItem != null)
            {
                var lbOpen   = e.Item.FindControl("lbOpen") as LinkButton;
                var lbClose  = e.Item.FindControl("lbClose") as LinkButton;
                var isActive = (bool)locationDataItem.GetPropertyValue("IsActive");

                if (isActive)
                {
                    lbClose.RemoveCssClass("btn-danger");
                    lbClose.RemoveCssClass("active");
                    lbOpen.AddCssClass("btn-success");
                    lbOpen.AddCssClass("active");
                }
                else
                {
                    lbOpen.RemoveCssClass("btn-success");
                    lbOpen.RemoveCssClass("active");
                    lbClose.AddCssClass("btn-danger");
                    lbClose.AddCssClass("active");
                }

                var lLocationName = e.Item.FindControl("lLocationName") as Literal;
                lLocationName.Text = locationDataItem.GetPropertyValue("Name") as string;

                var lLocationCount = e.Item.FindControl("lLocationCount") as Literal;
                lLocationCount.Text = KioskLocationAttendance.Read((int)locationDataItem.GetPropertyValue("LocationId")).CurrentCount.ToString();
            }
        }
예제 #2
0
        /// <summary>
        /// Formats the count.
        /// </summary>
        /// <param name="locationId">The location id.</param>
        /// <returns></returns>
        protected string FormatCount(int locationId)
        {
            string currentCountFormat = GetAttributeValue("CurrentCountFormat");

            if (!string.IsNullOrWhiteSpace(currentCountFormat) && currentCountFormat.Contains("{0}"))
            {
                return(string.Format(" <span class='checkin-sub-title'>{0}</span>",
                                     string.Format(currentCountFormat, KioskLocationAttendance.Read(locationId).CurrentCount)));
            }

            return(string.Empty);
        }
        /// <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)
            {
                var family = checkInState.CheckIn.CurrentFamily;
                if (family != null)
                {
                    var remove = GetAttributeValue(action, "Remove").AsBoolean();

                    foreach (var person in family.People)
                    {
                        foreach (var groupType in person.GroupTypes)
                        {
                            foreach (var group in groupType.Groups)
                            {
                                foreach (var location in group.Locations.ToList())
                                {
                                    if (location.Location.SoftRoomThreshold.HasValue)
                                    {
                                        var locAttendance = KioskLocationAttendance.Read(location.Location.Id);
                                        if (locAttendance != null &&
                                            !locAttendance.DistinctPersonIds.Contains(person.Person.Id) &&
                                            location.Location.SoftRoomThreshold.Value <= locAttendance.CurrentCount)
                                        {
                                            if (remove)
                                            {
                                                group.Locations.Remove(location);
                                            }
                                            else
                                            {
                                                location.ExcludedByFilter = true;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                return(true);
            }

            return(false);
        }
예제 #4
0
        /// <summary>
        /// Refreshes the view.
        /// </summary>
        private void RefreshView()
        {
            hfRefreshTimerSeconds.Value = "10";
            ManagerLoggedIn             = false;
            pnlActive.Visible           = false;
            pnlManagerLogin.Visible     = false;
            pnlManager.Visible          = false;
            btnManager.Visible          = true;

            lblActiveWhen.Text = string.Empty;

            if (CurrentKioskId == null || CurrentLocationId == null)
            {
                NavigateToParentPage();
                return;
            }

            pnlActive.Visible = true;

            var currentPeople = KioskLocationAttendance.Read(CurrentLocationId.Value);

            var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(this.RockPage, this.CurrentPerson);

            // add link to detail page
            Dictionary <string, object> linkedPages = new Dictionary <string, object>();

            mergeFields.Add("PersonIds", currentPeople.DistinctPersonIds);
            mergeFields.Add("LocationCount", currentPeople.CurrentCount);
            mergeFields.Add("CurrentKioskId", CurrentKioskId);
            mergeFields.Add("CurrentLocationId", CurrentLocationId);

            lOutput.Text = GetAttributeValue("LavaTemplate").ResolveMergeFields(mergeFields);

            // show debug info
            if (GetAttributeValue("EnableDebug").AsBoolean() && IsUserAuthorized(Authorization.EDIT))
            {
                lDebug.Visible = true;
                lDebug.Text    = mergeFields.lavaDebugInfo();
            }
        }
        /// <summary>
        /// Reads the attendance cache by schedule.
        /// </summary>
        /// <param name="locationId">The location identifier.</param>
        /// <param name="scheduleId">The schedule identifier.</param>
        /// <returns></returns>
        public static int ReadAttendanceBySchedule(int locationId, int?scheduleId)
        {
            var attendanceCount = 0;
            var attendanceCache = KioskLocationAttendance.Read(locationId);

            if (attendanceCache != null)
            {
                if (scheduleId != null)
                {
                    foreach (var scheduleAttendance in attendanceCache.Groups.SelectMany(g => g.Schedules).Where(s => s.ScheduleId == (int)scheduleId))
                    {
                        attendanceCount += scheduleAttendance.CurrentCount;
                    }
                }
                else
                {
                    attendanceCount = attendanceCache.CurrentCount;
                }
            }

            return(attendanceCount);
        }
예제 #6
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute(RockContext rockContext, 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);
        }
예제 #7
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute(RockContext rockContext, Rock.Model.WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            if (checkInState == null)
            {
                return(false);
            }

            int selectFromDaysBack    = checkInState.CheckInType.AutoSelectDaysBack;
            var roomBalanceGroupTypes = GetAttributeValue(action, "RoomBalanceGrouptypes").SplitDelimitedValues().AsGuidList();
            int roomBalanceOverride   = GetAttributeValue(action, "BalancingOverride").AsIntegerOrNull() ?? 5;
            int maxAssignments        = GetAttributeValue(action, "MaxAssignments").AsIntegerOrNull() ?? 5;
            var excludedLocations     = GetAttributeValue(action, "ExcludedLocations").SplitDelimitedValues(whitespace: false)
                                        .Select(s => s.Trim());

            // get the admin-selected attribute key instead of using a hardcoded key
            var personSpecialNeedsKey  = string.Empty;
            var personSpecialNeedsGuid = GetAttributeValue(action, "PersonSpecialNeedsAttribute").AsGuid();

            if (personSpecialNeedsGuid != Guid.Empty)
            {
                personSpecialNeedsKey = AttributeCache.Read(personSpecialNeedsGuid, rockContext).Key;
            }

            // log a warning if the attribute is missing or invalid
            if (string.IsNullOrWhiteSpace(personSpecialNeedsKey))
            {
                action.AddLogEntry(string.Format("The Person Special Needs attribute is not selected or invalid for '{0}'.", action.ActionType.Name));
            }

            var family = checkInState.CheckIn.Families.FirstOrDefault(f => f.Selected);

            if (family != null)
            {
                var cutoffDate        = RockDateTime.Today.AddDays(selectFromDaysBack * -1);
                var attendanceService = new AttendanceService(rockContext);

                // only process people who have been here before
                foreach (var previousAttender in family.People.Where(p => p.Selected && !p.FirstTime))
                {
                    // get a list of this person's available grouptypes
                    var availableGroupTypeIds = previousAttender.GroupTypes.Select(gt => gt.GroupType.Id).ToList();

                    var lastDateAttendances = attendanceService.Queryable().Where(a =>
                                                                                  a.PersonAlias.PersonId == previousAttender.Person.Id &&
                                                                                  availableGroupTypeIds.Contains(a.Group.GroupTypeId) &&
                                                                                  a.StartDateTime >= cutoffDate && a.DidAttend == true)
                                              .OrderByDescending(a => a.StartDateTime).Take(maxAssignments)
                                              .ToList();

                    if (lastDateAttendances.Any())
                    {
                        var lastAttended   = lastDateAttendances.Max(a => a.StartDateTime).Date;
                        var numAttendances = lastDateAttendances.Count(a => a.StartDateTime >= lastAttended);
                        foreach (var groupAttendance in lastDateAttendances.Where(a => a.StartDateTime >= lastAttended))
                        {
                            bool currentlyCheckedIn = false;
                            var  serviceCutoff      = groupAttendance.StartDateTime;
                            if (serviceCutoff > RockDateTime.Now.Date)
                            {
                                // calculate the service window to determine if people are still checked in
                                var serviceTime  = groupAttendance.StartDateTime.Date + groupAttendance.Schedule.NextStartDateTime.Value.TimeOfDay;
                                var serviceStart = serviceTime.AddMinutes((groupAttendance.Schedule.CheckInStartOffsetMinutes ?? 0) * -1.0);
                                serviceCutoff      = serviceTime.AddMinutes((groupAttendance.Schedule.CheckInEndOffsetMinutes ?? 0));
                                currentlyCheckedIn = RockDateTime.Now > serviceStart && RockDateTime.Now < serviceCutoff;
                            }

                            // override exists in case they are currently checked in or have special needs
                            bool useCheckinOverride = currentlyCheckedIn || previousAttender.Person.GetAttributeValue(personSpecialNeedsKey).AsBoolean();

                            // get a list of room balanced grouptype ID's since CheckInGroup model is a shallow clone
                            var roomBalanceGroupTypeIds = previousAttender.GroupTypes.Where(gt => roomBalanceGroupTypes.Contains(gt.GroupType.Guid))
                                                          .Select(gt => gt.GroupType.Id).ToList();

                            // 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 || useCheckinOverride));
                            if (groupType != null)
                            {
                                CheckInGroup group = null;
                                if (groupType.Groups.Count == 1)
                                {
                                    // Only a single group is open
                                    group = groupType.Groups.FirstOrDefault(g => !g.ExcludedByFilter || useCheckinOverride);
                                }
                                else
                                {
                                    // Pick the group they last attended, as long as it's open or what they're currently checked into
                                    group = groupType.Groups.FirstOrDefault(g => g.Group.Id == groupAttendance.GroupId && (!g.ExcludedByFilter || useCheckinOverride));

                                    // room balance only on new check-ins
                                    if (group != null && roomBalanceGroupTypeIds.Contains(group.Group.GroupTypeId) && !useCheckinOverride)
                                    {
                                        //TODO: use KioskLocationAttendance and group.AvailableForSchedule to room balance by service time attendance, not the entire day
                                        var currentAttendance   = group.Locations.Select(l => KioskLocationAttendance.Read(l.Location.Id).CurrentCount).Sum();
                                        var lowestAttendedGroup = groupType.Groups.Where(g => !g.ExcludedByFilter && !excludedLocations.Contains(g.Group.Name))
                                                                  .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 - roomBalanceOverride + 1))
                                        {
                                            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 || useCheckinOverride);
                                    }
                                    else
                                    {
                                        // Pick the location they last attended, as long as it's open or what they're currently checked into
                                        location = group.Locations.FirstOrDefault(l => l.Location.Id == groupAttendance.LocationId && (!l.ExcludedByFilter || useCheckinOverride));

                                        // room balance only on new check-ins
                                        if (location != null && roomBalanceGroupTypeIds.Contains(group.Group.GroupTypeId) && !useCheckinOverride)
                                        {
                                            //TODO: use KioskLocationAttendance and location.AvailableForSchedule to room balance by service time attendance, not the entire day
                                            var currentAttendance      = KioskLocationAttendance.Read(location.Location.Id).CurrentCount;
                                            var lowestAttendedLocation = group.Locations.Where(l => !l.ExcludedByFilter && !excludedLocations.Contains(l.Location.Name))
                                                                         .Select(l => new { Location = l, Attendance = KioskLocationAttendance.Read(l.Location.Id).CurrentCount })
                                                                         .OrderBy(l => l.Attendance)
                                                                         .FirstOrDefault();

                                            if (lowestAttendedLocation != null && lowestAttendedLocation.Attendance < (currentAttendance - roomBalanceOverride + 1))
                                            {
                                                location = lowestAttendedLocation.Location;
                                            }
                                        }
                                    }

                                    if (location != null)
                                    {
                                        CheckInSchedule schedule = null;
                                        if (location.Schedules.Count == 1)
                                        {
                                            schedule = location.Schedules.FirstOrDefault(s => !s.ExcludedByFilter || useCheckinOverride);
                                        }
                                        else
                                        {
                                            // if assigning to multiple services or currently checked in (not SN, otherwise they would get the wrong auto-schedule)
                                            if (numAttendances > 1 || currentlyCheckedIn)
                                            {
                                                // pick what they last attended last
                                                schedule = location.Schedules.FirstOrDefault(s => s.Schedule.Id == groupAttendance.ScheduleId && (!s.ExcludedByFilter || useCheckinOverride));
                                            }

                                            // otherwise pick the earliest available schedule
                                            schedule = schedule ?? location.Schedules.OrderBy(s => s.Schedule.StartTimeOfDay).FirstOrDefault(s => !s.ExcludedByFilter);
                                        }

                                        if (schedule != null)
                                        {
                                            // it's impossible to currently be checked in unless these match exactly
                                            if (group.Group.Id == groupAttendance.GroupId && location.Location.Id == groupAttendance.LocationId && schedule.Schedule.Id == groupAttendance.ScheduleId)
                                            {
                                                // Checkout would've removed the attendance or set the EndDateTime
                                                var endOfCheckinWindow = groupAttendance.EndDateTime ?? serviceCutoff;
                                                schedule.LastCheckIn         = endOfCheckinWindow;
                                                location.LastCheckIn         = endOfCheckinWindow;
                                                group.LastCheckIn            = endOfCheckinWindow;
                                                groupType.LastCheckIn        = endOfCheckinWindow;
                                                previousAttender.LastCheckIn = endOfCheckinWindow;
                                            }

                                            // finished finding assignment, verify everything is selected
                                            schedule.Selected            = true;
                                            schedule.PreSelected         = true;
                                            location.Selected            = true;
                                            location.PreSelected         = true;
                                            group.Selected               = true;
                                            group.PreSelected            = true;
                                            groupType.Selected           = true;
                                            groupType.PreSelected        = true;
                                            groupType.Selected           = true;
                                            groupType.PreSelected        = true;
                                            previousAttender.Selected    = true;
                                            previousAttender.PreSelected = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(true);
        }
예제 #8
0
        /// <summary>
        /// Handles the Click event of the btnManager 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 btnManager_Click(object sender, EventArgs e)
        {
            ManagerLoggedIn         = false;
            pnlNotActive.Visible    = false;
            pnlNotActiveYet.Visible = false;
            pnlClosed.Visible       = false;
            pnlActive.Visible       = false;
            pnlManager.Visible      = false;

            tbPIN.Text = string.Empty;

            // Get room counts
            List <int> locations = new List <int>();

            foreach (var groupType in CurrentCheckInState.Kiosk.FilteredGroupTypes(CurrentCheckInState.ConfiguredGroupTypes))
            {
                var lUl = new HtmlGenericControl("ul");
                lUl.AddCssClass("kioskmanager-count-locations");
                phCounts.Controls.Add(lUl);

                foreach (var location in groupType.KioskGroups.SelectMany(g => g.KioskLocations).OrderBy(l => l.Location.Name).Distinct())
                {
                    if (!locations.Contains(location.Location.Id))
                    {
                        locations.Add(location.Location.Id);
                        var locationAttendance = KioskLocationAttendance.Read(location.Location.Id);

                        if (locationAttendance != null)
                        {
                            var lLi = new HtmlGenericControl("li");
                            lUl.Controls.Add(lLi);
                            lLi.InnerHtml = string.Format("<strong>{0}</strong>: {1}", locationAttendance.LocationName, locationAttendance.CurrentCount);

                            var gUl = new HtmlGenericControl("ul");
                            gUl.AddCssClass("kioskmanager-count-groups");
                            lLi.Controls.Add(gUl);

                            foreach (var groupAttendance in locationAttendance.Groups)
                            {
                                var gLi = new HtmlGenericControl("li");
                                gUl.Controls.Add(gLi);
                                gLi.InnerHtml = string.Format("<strong>{0}</strong>: {1}", groupAttendance.GroupName, groupAttendance.CurrentCount);

                                var sUl = new HtmlGenericControl("ul");
                                sUl.AddCssClass("kioskmanager-count-schedules");
                                gLi.Controls.Add(sUl);

                                foreach (var scheduleAttendance in groupAttendance.Schedules.Where(s => s.IsActive))
                                {
                                    var sLi = new HtmlGenericControl("li");
                                    sUl.Controls.Add(sLi);
                                    sLi.InnerHtml = string.Format("<strong>{0}</strong>: {1}", scheduleAttendance.ScheduleName, scheduleAttendance.CurrentCount);
                                }
                            }
                        }
                    }
                }
            }

            pnlManagerLogin.Visible = true;

            // set manager timer to 10 minutes
            hfRefreshTimerSeconds.Value = "600";
        }
예제 #9
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute(RockContext rockContext, Rock.Model.WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            if (checkInState == null)
            {
                return(false);
            }

            var  roomBalanceGroupTypes = GetAttributeValue(action, "RoomBalanceGrouptypes").SplitDelimitedValues().AsGuidList();
            bool useGroupMembership    = GetAttributeValue(action, "PrioritizeGroupMembership").AsBoolean();
            int  roomBalanceOverride   = GetAttributeValue(action, "BalancingOverride").AsIntegerOrNull() ?? 5;
            var  excludedLocations     = GetAttributeValue(action, "ExcludedLocations").SplitDelimitedValues(false)
                                         .Select(s => s.Trim());

            // get admin-selected attribute keys instead of using a hardcoded key
            var personSpecialNeedsKey  = string.Empty;
            var personSpecialNeedsGuid = GetAttributeValue(action, "PersonSpecialNeedsAttribute").AsGuid();

            if (personSpecialNeedsGuid != Guid.Empty)
            {
                personSpecialNeedsKey = AttributeCache.Read(personSpecialNeedsGuid, rockContext).Key;
            }

            var groupSpecialNeedsKey  = string.Empty;
            var groupSpecialNeedsGuid = GetAttributeValue(action, "GroupSpecialNeedsAttribute").AsGuid();

            if (personSpecialNeedsGuid != Guid.Empty)
            {
                groupSpecialNeedsKey = AttributeCache.Read(groupSpecialNeedsGuid, rockContext).Key;
            }

            var groupAgeRangeKey  = string.Empty;
            var groupAgeRangeGuid = GetAttributeValue(action, "GroupAgeRangeAttribute").AsGuid();

            if (personSpecialNeedsGuid != Guid.Empty)
            {
                groupAgeRangeKey = AttributeCache.Read(groupAgeRangeGuid, rockContext).Key;
            }

            var groupGradeRangeKey  = string.Empty;
            var groupGradeRangeGuid = GetAttributeValue(action, "GroupGradeRangeAttribute").AsGuid();

            if (personSpecialNeedsGuid != Guid.Empty)
            {
                groupGradeRangeKey = AttributeCache.Read(groupGradeRangeGuid, rockContext).Key;
            }

            // log a warning if any of the attributes are missing or invalid
            if (string.IsNullOrWhiteSpace(personSpecialNeedsKey))
            {
                action.AddLogEntry(string.Format("The Person Special Needs attribute is not selected or invalid for '{0}'.", action.ActionType.Name));
            }

            if (string.IsNullOrWhiteSpace(groupSpecialNeedsKey))
            {
                action.AddLogEntry(string.Format("The Group Special Needs attribute is not selected or invalid for '{0}'.", action.ActionType.Name));
            }

            if (string.IsNullOrWhiteSpace(groupAgeRangeKey))
            {
                action.AddLogEntry(string.Format("The Group Age Range attribute is not selected or invalid for '{0}'.", action.ActionType.Name));
            }

            if (string.IsNullOrWhiteSpace(groupGradeRangeKey))
            {
                action.AddLogEntry(string.Format("The Group Grade Range attribute is not selected or invalid for '{0}'.", action.ActionType.Name));
            }

            var family = checkInState.CheckIn.Families.FirstOrDefault(f => f.Selected);

            if (family != null)
            {
                // don't process people who already have assignments
                foreach (var person in family.People.Where(f => f.Selected && !f.GroupTypes.Any(gt => gt.Selected)))
                {
                    decimal baseVariance = 100;
                    char[]  delimiter    = { ',' };

                    // check if this person has special needs
                    var hasSpecialNeeds = person.Person.GetAttributeValue(personSpecialNeedsKey).AsBoolean();

                    // get a list of room balanced grouptype ID's since CheckInGroup model is a shallow clone
                    var roomBalanceGroupTypeIds = person.GroupTypes.Where(gt => roomBalanceGroupTypes.Contains(gt.GroupType.Guid))
                                                  .Select(gt => gt.GroupType.Id).ToList();

                    if (person.GroupTypes.Count > 0)
                    {
                        CheckInGroupType           bestGroupType = null;
                        IEnumerable <CheckInGroup> validGroups;
                        if (person.GroupTypes.Count == 1)
                        {
                            bestGroupType = person.GroupTypes.FirstOrDefault();
                            validGroups   = bestGroupType.Groups;
                        }
                        else
                        {
                            // Start with unfiltered groups since one criteria may not match exactly ( SN > Grade > Age )
                            validGroups = person.GroupTypes.SelectMany(gt => gt.Groups);
                        }

                        // check how many groups exist without getting the whole list
                        int numValidGroups = validGroups.Take(2).Count();
                        if (numValidGroups > 0)
                        {
                            CheckInGroup bestGroup = null;
                            IEnumerable <CheckInLocation> validLocations;
                            if (numValidGroups == 1)
                            {
                                bestGroup      = validGroups.FirstOrDefault();
                                validLocations = bestGroup.Locations;
                            }
                            else
                            {
                                // Select by group assignment first
                                if (useGroupMembership)
                                {
                                    var personAssignments = new GroupMemberService(rockContext).GetByPersonId(person.Person.Id)
                                                            .Select(gm => gm.Group.Id).ToList();
                                    if (personAssignments.Count > 0)
                                    {
                                        bestGroup = validGroups.FirstOrDefault(g => personAssignments.Contains(g.Group.Id));
                                    }
                                }

                                // Select group by best fit
                                if (bestGroup == null)
                                {
                                    // Check age and special needs
                                    CheckInGroup closestAgeGroup   = null;
                                    CheckInGroup closestNeedsGroup = null;

                                    var ageGroups = validGroups.Where(g => g.Group.AttributeValues.ContainsKey(groupAgeRangeKey) &&
                                                                      g.Group.AttributeValues[groupAgeRangeKey].Value != null &&
                                                                      g.Group.AttributeValues.ContainsKey(personSpecialNeedsKey) == hasSpecialNeeds
                                                                      )
                                                    .ToList()
                                                    .Select(g => new
                                    {
                                        Group    = g,
                                        AgeRange = g.Group.AttributeValues[groupAgeRangeKey].Value
                                                   .Split(delimiter, StringSplitOptions.None)
                                                   .Where(av => !string.IsNullOrEmpty(av))
                                                   .Select(av => av.AsType <decimal>())
                                    })
                                                    .ToList();

                                    if (ageGroups.Count > 0)
                                    {
                                        if (person.Person.Age != null)
                                        {
                                            baseVariance = 100;
                                            decimal personAge = (decimal)person.Person.AgePrecise;
                                            foreach (var ageGroup in ageGroups.Where(g => g.AgeRange.Any()))
                                            {
                                                var minAge      = ageGroup.AgeRange.First();
                                                var maxAge      = ageGroup.AgeRange.Last();
                                                var ageVariance = maxAge - minAge;
                                                if (maxAge >= personAge && minAge <= personAge && ageVariance < baseVariance)
                                                {
                                                    closestAgeGroup = ageGroup.Group;
                                                    baseVariance    = ageVariance;

                                                    if (hasSpecialNeeds)
                                                    {
                                                        closestNeedsGroup = closestAgeGroup;
                                                    }
                                                }
                                            }
                                        }
                                        else if (hasSpecialNeeds)
                                        {
                                            // person has special needs but not an age, assign to first special needs group
                                            closestNeedsGroup = ageGroups.FirstOrDefault().Group;
                                        }
                                    }

                                    // Check grade
                                    CheckInGroup closestGradeGroup = null;
                                    if (person.Person.GradeOffset != null)
                                    {
                                        var gradeValues = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.SCHOOL_GRADES)).DefinedValues;
                                        var gradeGroups = validGroups.Where(g => g.Group.AttributeValues.ContainsKey(groupGradeRangeKey) && g.Group.AttributeValues[groupGradeRangeKey].Value != null)
                                                          .ToList()
                                                          .Select(g => new
                                        {
                                            Group        = g,
                                            GradeOffsets = g.Group.AttributeValues[groupGradeRangeKey].Value
                                                           .Split(delimiter, StringSplitOptions.None)
                                                           .Where(av => !string.IsNullOrEmpty(av))
                                                           .Select(av => gradeValues.FirstOrDefault(v => v.Guid == new Guid(av)))
                                                           .Select(av => av.Value.AsDecimal())
                                        })
                                                          .ToList();

                                        // Only check groups that have valid grade offsets
                                        if (person.Person.GradeOffset != null && gradeGroups.Count > 0)
                                        {
                                            baseVariance = 100;
                                            decimal gradeOffset = (decimal)person.Person.GradeOffset.Value;
                                            foreach (var gradeGroup in gradeGroups.Where(g => g.GradeOffsets.Any()))
                                            {
                                                var minGradeOffset = gradeGroup.GradeOffsets.First();
                                                var maxGradeOffset = gradeGroup.GradeOffsets.Last();
                                                var gradeVariance  = minGradeOffset - maxGradeOffset;
                                                if (minGradeOffset >= gradeOffset && maxGradeOffset <= gradeOffset && gradeVariance < baseVariance)
                                                {
                                                    closestGradeGroup = gradeGroup.Group;
                                                    baseVariance      = gradeVariance;
                                                }
                                            }

                                            /* ======================================================== *
                                             *  optional scenario: find the next closest grade group
                                             * ========================================================= *
                                             *  if (grade > max)
                                             *      grade - max
                                             *  else if (grade < min)
                                             *      min - grade
                                             *  else 0;
                                             *
                                             * // add a tiny variance to offset larger groups:
                                             *  result += ((max - min)/100)
                                             * ========================================================= */
                                        }
                                    }

                                    // Assignment priority: Group Membership, then Ability, then Grade, then Age, then the first non-excluded group
                                    // NOTE: if group member is prioritized (and membership exists) this section is skipped entirely
                                    bestGroup = closestNeedsGroup ?? closestGradeGroup ?? closestAgeGroup ?? validGroups.FirstOrDefault(g => !g.ExcludedByFilter);

                                    // room balance if they fit into multiple groups
                                    if (bestGroup != null && roomBalanceGroupTypeIds.Contains(bestGroup.Group.GroupTypeId))
                                    {
                                        var currentGroupAttendance = bestGroup.Locations.Select(l => KioskLocationAttendance.Read(l.Location.Id).CurrentCount).Sum();
                                        var lowestGroup            = validGroups.Where(g => !g.ExcludedByFilter && !excludedLocations.Contains(g.Group.Name))
                                                                     .Select(g => new { Group = g, Attendance = g.Locations.Select(l => KioskLocationAttendance.Read(l.Location.Id).CurrentCount).Sum() })
                                                                     .OrderBy(g => g.Attendance)
                                                                     .FirstOrDefault();

                                        if (lowestGroup != null && lowestGroup.Attendance < (currentGroupAttendance - roomBalanceOverride))
                                        {
                                            bestGroup = lowestGroup.Group;
                                        }
                                    }
                                }

                                validLocations = bestGroup.Locations;
                            }

                            // check how many locations exist without getting the whole list
                            int numValidLocations = validLocations.Take(2).Count();
                            if (numValidLocations > 0)
                            {
                                CheckInLocation bestLocation = null;
                                IEnumerable <CheckInSchedule> validSchedules;
                                if (numValidLocations == 1)
                                {
                                    bestLocation   = validLocations.FirstOrDefault();
                                    validSchedules = bestLocation.Schedules;
                                }
                                else
                                {
                                    var filteredLocations = validLocations.Where(l => !l.ExcludedByFilter && !excludedLocations.Contains(l.Location.Name) && l.Schedules.Any(s => s.Schedule.IsCheckInActive));

                                    // room balance if they fit into multiple locations
                                    if (roomBalanceGroupTypeIds.Contains(bestGroup.Group.GroupTypeId))
                                    {
                                        filteredLocations = filteredLocations.OrderBy(l => KioskLocationAttendance.Read(l.Location.Id).CurrentCount);
                                    }

                                    bestLocation   = filteredLocations.FirstOrDefault();
                                    validSchedules = bestLocation.Schedules;
                                }

                                // check how many schedules exist without getting the whole list
                                int numValidSchedules = validSchedules.Take(2).Count();
                                if (numValidSchedules > 0)
                                {
                                    // finished finding assignment, verify everything is selected
                                    var bestSchedule = validSchedules.OrderBy(s => s.Schedule.StartTimeOfDay).FirstOrDefault();
                                    bestSchedule.Selected    = true;
                                    bestSchedule.PreSelected = true;

                                    if (bestLocation != null)
                                    {
                                        bestLocation.PreSelected = true;
                                        bestLocation.Selected    = true;

                                        if (bestGroup != null)
                                        {
                                            bestGroup.PreSelected = true;
                                            bestGroup.Selected    = true;

                                            bestGroupType = person.GroupTypes.FirstOrDefault(gt => gt.GroupType.Id == bestGroup.Group.GroupTypeId);
                                            if (bestGroupType != null)
                                            {
                                                bestGroupType.Selected    = true;
                                                bestGroupType.PreSelected = true;
                                                person.Selected           = true;
                                                person.PreSelected        = true;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(true);
        }
        /// <summary>
        /// Formats the count.
        /// </summary>
        /// <param name="locationId">The location id.</param>
        /// <returns></returns>
        protected string FormatCount(int locationId)
        {
            if (CurrentCheckInType != null && CurrentCheckInType.DisplayLocationCount)
            {
                return(string.Format(" <span class='checkin-sub-title'> Count: {0}</span>", KioskLocationAttendance.Read(locationId).CurrentCount));
            }

            return(string.Empty);
        }
예제 #11
0
        private void RefreshView()
        {
            pnlNotActive.Visible    = false;
            pnlNotActiveYet.Visible = false;
            pnlClosed.Visible       = false;
            pnlActive.Visible       = false;

            lblActiveWhen.Text = string.Empty;

            if (CurrentCheckInState == null || IsMobileAndExpiredDevice())
            {
                NavigateToPreviousPage();
                return;
            }

            if (CurrentCheckInState.Kiosk.FilteredGroupTypes(CurrentCheckInState.ConfiguredGroupTypes).Count == 0)
            {
                pnlNotActive.Visible = true;
            }
            else if (!CurrentCheckInState.Kiosk.HasLocations(CurrentCheckInState.ConfiguredGroupTypes))
            {
                DateTimeOffset activeAt = CurrentCheckInState.Kiosk.FilteredGroupTypes(CurrentCheckInState.ConfiguredGroupTypes).Select(g => g.NextActiveTime).Min();
                lblActiveWhen.Text      = activeAt.ToString();
                pnlNotActiveYet.Visible = true;
            }
            else if (!CurrentCheckInState.Kiosk.HasActiveLocations(CurrentCheckInState.ConfiguredGroupTypes))
            {
                pnlClosed.Visible = true;
            }
            else
            {
                pnlActive.Visible = true;
            }

            List <int> locations = new List <int>();

            foreach (var groupType in CurrentCheckInState.Kiosk.FilteredGroupTypes(CurrentCheckInState.ConfiguredGroupTypes))
            {
                foreach (var location in groupType.KioskGroups.SelectMany(g => g.KioskLocations).Distinct())
                {
                    if (!locations.Contains(location.Location.Id))
                    {
                        locations.Add(location.Location.Id);
                        var locationAttendance = KioskLocationAttendance.Read(location.Location.Id);

                        if (locationAttendance != null)
                        {
                            var lUl = new HtmlGenericControl("ul");
                            lUl.AddCssClass("checkin-count-locations");
                            phCounts.Controls.Add(lUl);

                            var lLi = new HtmlGenericControl("li");
                            lUl.Controls.Add(lLi);
                            lLi.InnerHtml = string.Format("{0}: <strong>{1}</strong>", locationAttendance.LocationName, locationAttendance.CurrentCount);

                            foreach (var groupAttendance in locationAttendance.Groups)
                            {
                                var gUl = new HtmlGenericControl("ul");
                                gUl.AddCssClass("checkin-count-groups");
                                lLi.Controls.Add(gUl);

                                var gLi = new HtmlGenericControl("li");
                                gUl.Controls.Add(gLi);
                                gLi.InnerHtml = string.Format("{0}: <strong>{1}</strong>", groupAttendance.GroupName, groupAttendance.CurrentCount);

                                foreach (var scheduleAttendance in groupAttendance.Schedules)
                                {
                                    var sUl = new HtmlGenericControl("ul");
                                    sUl.AddCssClass("checkin-count-schedules");
                                    gLi.Controls.Add(sUl);

                                    var sLi = new HtmlGenericControl("li");
                                    sUl.Controls.Add(sLi);
                                    sLi.InnerHtml = string.Format("{0}: <strong>{1}</strong>", scheduleAttendance.ScheduleName, scheduleAttendance.CurrentCount);
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #12
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute(RockContext rockContext, Rock.Model.WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            if (checkInState == null)
            {
                return(false);
            }

            bool roomBalance        = GetAttributeValue(action, "RoomBalance").AsBoolean();
            bool useGroupMembership = GetAttributeValue(action, "PrioritizeGroupMembership").AsBoolean();
            int  balanceOverride    = GetAttributeValue(action, "DifferentialOverride").AsIntegerOrNull() ?? 10;

            var family = checkInState.CheckIn.Families.FirstOrDefault(f => f.Selected);

            if (family != null)
            {
                // don't run for people who already have attendance assignments
                foreach (var person in family.People.Where(f => f.Selected && !f.GroupTypes.Any(gt => gt.Selected)))
                {
                    decimal baseVariance = 100;
                    char[]  delimiter    = { ',' };

                    // variable must be a string to compare to group attribute value
                    var specialNeedsValue = person.Person.GetAttributeValue("IsSpecialNeeds").ToStringSafe();
                    var isSpecialNeeds    = specialNeedsValue.AsBoolean();

                    if (person.GroupTypes.Count > 0)
                    {
                        CheckInGroupType           bestGroupType = null;
                        IEnumerable <CheckInGroup> validGroups;
                        if (person.GroupTypes.Count == 1)
                        {
                            bestGroupType = person.GroupTypes.FirstOrDefault();
                            validGroups   = bestGroupType.Groups;
                        }
                        else
                        {
                            // Start with unfiltered groups since one criteria may not match exactly ( SN > Grade > Age )
                            validGroups = person.GroupTypes.SelectMany(gt => gt.Groups);
                        }

                        // check how many groups exist without getting the whole list
                        int numValidGroups = validGroups.Take(2).Count();
                        if (numValidGroups > 0)
                        {
                            CheckInGroup bestGroup = null;
                            IEnumerable <CheckInLocation> validLocations;
                            if (numValidGroups == 1)
                            {
                                bestGroup      = validGroups.FirstOrDefault();
                                validLocations = bestGroup.Locations;
                            }
                            else
                            {
                                // Select by group assignment first
                                if (useGroupMembership)
                                {
                                    var personAssignments = new GroupMemberService(rockContext).GetByPersonId(person.Person.Id)
                                                            .Select(gm => gm.Group.Id).ToList();
                                    if (personAssignments.Count > 0)
                                    {
                                        bestGroup = validGroups.FirstOrDefault(g => personAssignments.Contains(g.Group.Id));
                                    }
                                }

                                // Select group by best fit
                                if (bestGroup == null)
                                {
                                    // Check age and special needs
                                    CheckInGroup closestAgeGroup   = null;
                                    CheckInGroup closestNeedsGroup = null;

                                    var ageGroups = validGroups.Where(g => g.Group.AttributeValues.ContainsKey("AgeRange") &&
                                                                      g.Group.AttributeValues["AgeRange"].Value != null &&
                                                                      g.Group.AttributeValues.ContainsKey("IsSpecialNeeds") == isSpecialNeeds
                                                                      )
                                                    .ToList()
                                                    .Select(g => new
                                    {
                                        Group    = g,
                                        AgeRange = g.Group.AttributeValues["AgeRange"].Value
                                                   .Split(delimiter, StringSplitOptions.None)
                                                   .Where(av => !string.IsNullOrEmpty(av))
                                                   .Select(av => av.AsType <decimal>())
                                    })
                                                    .ToList();

                                    if (ageGroups.Count > 0)
                                    {
                                        if (person.Person.Age != null)
                                        {
                                            baseVariance = 100;
                                            decimal personAge = (decimal)person.Person.AgePrecise;
                                            foreach (var ageGroup in ageGroups.Where(g => g.AgeRange.Any()))
                                            {
                                                var minAge      = ageGroup.AgeRange.First();
                                                var maxAge      = ageGroup.AgeRange.Last();
                                                var ageVariance = maxAge - minAge;
                                                if (maxAge >= personAge && minAge <= personAge && ageVariance < baseVariance)
                                                {
                                                    closestAgeGroup = ageGroup.Group;
                                                    baseVariance    = ageVariance;

                                                    if (isSpecialNeeds)
                                                    {
                                                        closestNeedsGroup = closestAgeGroup;
                                                    }
                                                }
                                            }
                                        }
                                        else if (isSpecialNeeds)
                                        {
                                            // special needs was checked but no age, assign to first special needs group
                                            closestNeedsGroup = ageGroups.FirstOrDefault().Group;
                                        }
                                    }

                                    // Check grade
                                    CheckInGroup closestGradeGroup = null;
                                    if (person.Person.GradeOffset != null)
                                    {
                                        var gradeValues = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.SCHOOL_GRADES)).DefinedValues;
                                        var gradeGroups = validGroups.Where(g => g.Group.AttributeValues.ContainsKey("GradeRange") && g.Group.AttributeValues["GradeRange"].Value != null)
                                                          .ToList()
                                                          .Select(g => new
                                        {
                                            Group        = g,
                                            GradeOffsets = g.Group.AttributeValues["GradeRange"].Value
                                                           .Split(delimiter, StringSplitOptions.None)
                                                           .Where(av => !string.IsNullOrEmpty(av))
                                                           .Select(av => gradeValues.FirstOrDefault(v => v.Guid == new Guid(av)))
                                                           .Select(av => av.Value.AsDecimal())
                                        })
                                                          .ToList();

                                        // Only check groups that have valid grade offsets
                                        if (person.Person.GradeOffset != null && gradeGroups.Count > 0)
                                        {
                                            baseVariance = 100;
                                            decimal gradeOffset = (decimal)person.Person.GradeOffset.Value;
                                            foreach (var gradeGroup in gradeGroups.Where(g => g.GradeOffsets.Any()))
                                            {
                                                var minGradeOffset = gradeGroup.GradeOffsets.First();
                                                var maxGradeOffset = gradeGroup.GradeOffsets.Last();
                                                var gradeVariance  = minGradeOffset - maxGradeOffset;
                                                if (minGradeOffset >= gradeOffset && maxGradeOffset <= gradeOffset && gradeVariance < baseVariance)
                                                {
                                                    closestGradeGroup = gradeGroup.Group;
                                                    baseVariance      = gradeVariance;
                                                }
                                            }

                                            /* ======================================================== *
                                             *  optional scenario: find the next closest grade group
                                             * ========================================================= *
                                             *  if (grade > max)
                                             *      grade - max
                                             *  else if (grade < min)
                                             *      min - grade
                                             *  else 0;
                                             *
                                             * // add a tiny variance to offset larger groups:
                                             *  result += ((max - min)/100)
                                             * ========================================================= */
                                        }
                                    }

                                    // assignment priority: Ability, then Grade, then Age, then 1st available
                                    bestGroup = closestNeedsGroup ?? closestGradeGroup ?? closestAgeGroup ?? validGroups.FirstOrDefault(g => !g.ExcludedByFilter);

                                    // room balance if they fit into multiple groups
                                    if (bestGroup != null && roomBalance)
                                    {
                                        var currentGroupAttendance = bestGroup.Locations.Select(l => KioskLocationAttendance.Read(l.Location.Id).CurrentCount).Sum();
                                        var lowestGroup            = validGroups.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 (lowestGroup != null && lowestGroup.Attendance < (currentGroupAttendance - balanceOverride))
                                        {
                                            bestGroup = lowestGroup.Group;
                                        }
                                    }
                                }

                                validLocations = bestGroup.Locations;
                            }

                            // check how many locations exist without getting the whole list
                            int numValidLocations = validLocations.Take(2).Count();
                            if (numValidLocations > 0)
                            {
                                CheckInLocation bestLocation = null;
                                IEnumerable <CheckInSchedule> validSchedules;
                                if (numValidLocations == 1)
                                {
                                    bestLocation   = validLocations.FirstOrDefault();
                                    validSchedules = bestLocation.Schedules;
                                }
                                else
                                {
                                    var orderedLocations = validLocations.Where(l => !l.ExcludedByFilter && l.Schedules.Any(s => s.Schedule.IsCheckInActive));

                                    if (roomBalance)
                                    {
                                        orderedLocations = orderedLocations.OrderBy(l => KioskLocationAttendance.Read(l.Location.Id).CurrentCount);
                                    }

                                    bestLocation   = orderedLocations.FirstOrDefault();
                                    validSchedules = bestLocation.Schedules;
                                }

                                // check how many schedules exist without getting the whole list
                                int numValidSchedules = validSchedules.Take(2).Count();
                                if (numValidSchedules > 0)
                                {
                                    var bestSchedule = validSchedules.FirstOrDefault();
                                    bestSchedule.Selected    = true;
                                    bestSchedule.PreSelected = true;

                                    if (bestLocation != null)
                                    {
                                        bestLocation.PreSelected = true;
                                        bestLocation.Selected    = true;

                                        if (bestGroup != null)
                                        {
                                            bestGroup.PreSelected = true;
                                            bestGroup.Selected    = true;

                                            bestGroupType = person.GroupTypes.FirstOrDefault(gt => gt.GroupType.Id == bestGroup.Group.GroupTypeId);
                                            if (bestGroupType != null)
                                            {
                                                bestGroupType.Selected    = true;
                                                bestGroupType.PreSelected = true;
                                                person.PreSelected        = true;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(true);
        }
예제 #13
0
        /// <summary>
        /// Handles the Click event of the btnManager 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 btnManager_Click(object sender, EventArgs e)
        {
            var rockContext = new RockContext();

            pnlActive.Visible  = false;
            pnlManager.Visible = false;
            ManagerLoggedIn    = false;
            tbPIN.Text         = string.Empty;

            // Get room counts
            List <int> locations = new List <int>();

            var lUl = new HtmlGenericControl("ul");

            lUl.AddCssClass("kioskmanager-count-locations");
            phCounts.Controls.Add(lUl);
            var device = new DeviceService(rockContext).Get(CurrentKioskId.Value);

            if (device != null)
            {
                var deviceLocations = new List <Location>();
                var locationService = new LocationService(rockContext);
                foreach (var location in device.Locations)
                {
                    deviceLocations.Add(location);
                    deviceLocations.AddRange(locationService.GetAllDescendents(location.Id));
                }

                deviceLocations = deviceLocations
                                  .Where(l => l.LocationTypeValue == null || l.LocationTypeValue.Guid == Rock.SystemGuid.DefinedValue.LOCATION_TYPE_ROOM.AsGuid())
                                  .Distinct()
                                  .ToList();

                foreach (var location in deviceLocations)
                {
                    if (!locations.Contains(location.Id))
                    {
                        locations.Add(location.Id);
                        var locationAttendance = KioskLocationAttendance.Read(location.Id);

                        if (locationAttendance != null)
                        {
                            var lLi = new HtmlGenericControl("li");
                            lUl.Controls.Add(lLi);
                            lLi.InnerHtml = string.Format("<strong>{0}</strong>: {1}", locationAttendance.LocationName, locationAttendance.CurrentCount);

                            var gUl = new HtmlGenericControl("ul");
                            gUl.AddCssClass("kioskmanager-count-groups");
                            lLi.Controls.Add(gUl);

                            // ARRAN: If we only want to show the count of people in the room, and not further split it into groups and schedules, we need to remove this.
                            // I've tested both with and without it, so removing it is ok.
                            foreach (var groupAttendance in locationAttendance.Groups)
                            {
                                var gLi = new HtmlGenericControl("li");
                                gUl.Controls.Add(gLi);
                                gLi.InnerHtml = string.Format("<strong>{0}</strong>: {1}", groupAttendance.GroupName, groupAttendance.CurrentCount);

                                var sUl = new HtmlGenericControl("ul");
                                sUl.AddCssClass("kioskmanager-count-schedules");
                                gLi.Controls.Add(sUl);

                                foreach (var scheduleAttendance in groupAttendance.Schedules.Where(s => s.IsActive))
                                {
                                    var sLi = new HtmlGenericControl("li");
                                    sUl.Controls.Add(sLi);
                                    sLi.InnerHtml = string.Format("<strong>{0}</strong>: {1}", scheduleAttendance.ScheduleName, scheduleAttendance.CurrentCount);
                                }
                            }
                            // Remove up to here
                        }
                    }
                }
            }

            pnlManagerLogin.Visible = true;

            // set manager timer to 10 minutes
            hfRefreshTimerSeconds.Value = "600";
        }