/// <summary>
 /// Toggles on or off one check-in GroupLocationSchedule (it will deselct others)
 /// </summary>
 /// <param name="chGroup">Checkin Group</param>
 /// <param name="chLocation">Checkin Location</param>
 /// <param name="chSchedule">Checkin Schedule</param>
 /// <param name="alreadySelected">Is the Group Location Schedule already selected</param>
 private void ToggleClass(CheckInGroup chGroup, CheckInLocation chLocation, CheckInSchedule chSchedule, bool alreadySelected)
 {
     foreach (var groupType in CurrentCheckInState.CheckIn.CurrentPerson.GroupTypes)
     {
         groupType.Selected = true;
         foreach (var group in groupType.Groups)
         {
             group.Selected = false;
             foreach (var location in group.Locations)
             {
                 location.Selected = false;
                 foreach (var schedule in location.Schedules)
                 {
                     schedule.Selected = false;
                 }
             }
         }
     }
     if (!alreadySelected)
     {
         chGroup.Selected    = true;
         chLocation.Selected = true;
         chSchedule.Selected = true;
         btnCheckin.Visible  = true;
     }
     SaveState();
     ShowPersonCheckin();
 }
Exemple #2
0
        /// <summary>
        /// Binds the schedules.
        /// </summary>
        /// <param name="person">The person.</param>
        protected void BindSchedules(List <CheckInGroupType> groupTypes)
        {
            int groupTypeId = ViewState["groupTypeId"].ToString().AsType <int>();
            int locationId  = ViewState["locationId"].ToString().AsType <int>();

            CheckInGroupType groupType = null;

            if (groupTypes.Any(gt => gt.GroupType.Id == groupTypeId))
            {
                groupType = groupTypes.Where(gt => gt.GroupType.Id == groupTypeId).FirstOrDefault();
            }
            else
            {
                groupType = groupTypes.FirstOrDefault();
            }

            CheckInLocation location  = null;
            var             locations = groupType.Groups.SelectMany(g => g.Locations).ToList();

            if (locationId > 0)
            {
                location = locations.Where(l => l.Location.Id == locationId).FirstOrDefault();
            }
            else
            {
                location = locations.FirstOrDefault();
            }

            rSchedule.DataSource = location.Schedules.ToList();
            rSchedule.DataBind();
            pnlSchedules.Update();
        }
Exemple #3
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, WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            if (checkInState != null)
            {
                var groupService = new GroupService(rockContext);

                foreach (var family in checkInState.CheckIn.Families.Where(f => f.Selected).ToList())
                {
                    foreach (var person in family.People)
                    {
                        var checkinGroupTypes = new List <CheckInGroupType>();

                        foreach (var id in checkInState.ConfiguredGroupTypes)
                        {
                            var cgt = new CheckInGroupType();
                            cgt.GroupType = GroupTypeCache.Get(id);
                            checkinGroupTypes.Add(cgt);
                            var groups = groupService.Queryable().Where(g => g.GroupTypeId == id);
                            List <CheckInGroup> checkinGroups = new List <CheckInGroup>();
                            foreach (var group in groups)
                            {
                                var cg = new CheckInGroup();
                                cg.Group = group;
                                group.LoadAttributes();
                                checkinGroups.Add(cg);
                                var groupLocations = group.GroupLocations;
                                List <CheckInLocation> checkinLocations = new List <CheckInLocation>();
                                foreach (var groupLocation in groupLocations)
                                {
                                    var cl = new CheckInLocation();
                                    cl.Location = groupLocation.Location;
                                    checkinLocations.Add(cl);
                                    var schedules = new List <CheckInSchedule>();
                                    foreach (var schedule in groupLocation.Schedules.ToList())
                                    {
                                        if (!schedule.WasCheckInActive(RockDateTime.Now))
                                        {
                                            continue;
                                        }
                                        var cs = new CheckInSchedule();
                                        cs.Schedule = schedule;
                                        schedules.Add(cs);
                                    }
                                    cl.Schedules = schedules;
                                }
                                cg.Locations = checkinLocations;
                            }
                            cgt.Groups = checkinGroups;
                        }
                        person.GroupTypes = checkinGroupTypes;
                    }
                }
                return(true);
            }
            errorMessages.Add($"Attempted to run {this.GetType().GetFriendlyTypeName()} in check-in, but the check-in state was null.");
            return(false);
        }
Exemple #4
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, WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            if (checkInState != null)
            {
                var groupService = new GroupService(rockContext);

                foreach (var family in checkInState.CheckIn.Families.Where(f => f.Selected).ToList())
                {
                    foreach (var person in family.People)
                    {
                        var checkinGroupTypes = new List <CheckInGroupType>();

                        foreach (var id in checkInState.ConfiguredGroupTypes)
                        {
                            var cgt = new CheckInGroupType();
                            cgt.GroupType = GroupTypeCache.Get(id);
                            checkinGroupTypes.Add(cgt);
                            var groups = groupService.Queryable().Where(g => g.GroupTypeId == id);
                            List <CheckInGroup> checkinGroups = new List <CheckInGroup>();
                            foreach (var group in groups.Where(g => g.IsActive))
                            {
                                var cg = new CheckInGroup();
                                cg.Group = group;
                                group.LoadAttributes();
                                checkinGroups.Add(cg);
                                var groupLocations = group.GroupLocations;
                                List <CheckInLocation> checkinLocations = new List <CheckInLocation>();
                                foreach (var groupLocation in groupLocations)
                                {
                                    var cl = new CheckInLocation();
                                    cl.Location = groupLocation.Location;
                                    cl.CampusId = cl.Location.CampusId;
                                    checkinLocations.Add(cl);
                                    var schedules = new List <CheckInSchedule>();
                                    foreach (var schedule in groupLocation.Schedules)
                                    {
                                        var cs = new CheckInSchedule();
                                        cs.Schedule = schedule;
                                        schedules.Add(cs);
                                    }
                                    cl.Schedules = schedules;
                                }
                                cg.Locations = checkinLocations;
                            }
                            cgt.Groups = checkinGroups;
                        }
                        person.GroupTypes = checkinGroupTypes;
                    }
                }
                return(true);
            }
            return(false);
        }
Exemple #5
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The workflow action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override bool Execute(RockContext rockContext, Model.WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            if (checkInState != null)
            {
                bool loadAll = GetAttributeValue(action, "LoadAll").AsBoolean();

                foreach (var family in checkInState.CheckIn.GetFamilies(true))
                {
                    foreach (var person in family.GetPeople(!loadAll))
                    {
                        foreach (var groupType in person.GetGroupTypes(!loadAll).ToList())
                        {
                            var kioskGroupType = checkInState.Kiosk.ActiveGroupTypes(checkInState.ConfiguredGroupTypes)
                                                 .Where(g => g.GroupType.Id == groupType.GroupType.Id)
                                                 .FirstOrDefault();

                            if (kioskGroupType != null)
                            {
                                foreach (var group in groupType.GetGroups(!loadAll))
                                {
                                    foreach (var kioskGroup in kioskGroupType.KioskGroups
                                             .Where(g => g.Group.Id == group.Group.Id && g.IsCheckInActive)
                                             .ToList())
                                    {
                                        foreach (var kioskLocation in kioskGroup.KioskLocations.Where(l => l.IsCheckInActive && l.IsActiveAndNotFull))
                                        {
                                            if (!group.Locations.Any(l => l.Location.Id == kioskLocation.Location.Id))
                                            {
                                                var checkInLocation = new CheckInLocation();
                                                checkInLocation.Location = kioskLocation.Location.Clone(false);
                                                checkInLocation.Location.CopyAttributesFrom(kioskLocation.Location);
                                                checkInLocation.CampusId = kioskLocation.CampusId;
                                                checkInLocation.Order    = kioskLocation.Order;
                                                group.Locations.Add(checkInLocation);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                return(true);
            }

            return(false);
        }
        /// <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)
            {
                bool loadAll = false;
                if (bool.TryParse(GetAttributeValue(action, "LoadAll"), out loadAll) && loadAll)
                {
                    loadAll = true;
                }

                foreach (var family in checkInState.CheckIn.Families.Where(f => f.Selected).ToList())
                {
                    foreach (var person in family.People.Where(p => p.Selected || loadAll).ToList())
                    {
                        foreach (var groupType in person.GroupTypes.Where(t => t.Selected || loadAll).ToList())
                        {
                            var kioskGroupType = checkInState.Kiosk.FilteredGroupTypes(checkInState.ConfiguredGroupTypes).Where(g => g.GroupType.Id == groupType.GroupType.Id).FirstOrDefault();
                            if (kioskGroupType != null)
                            {
                                foreach (var group in groupType.Groups.Where(g => g.Selected || loadAll).ToList())
                                {
                                    foreach (var kioskGroup in kioskGroupType.KioskGroups.Where(g => g.Group.Id == group.Group.Id).ToList())
                                    {
                                        foreach (var kioskLocation in kioskGroup.KioskLocations)
                                        {
                                            if (!group.Locations.Any(l => l.Location.Id == kioskLocation.Location.Id))
                                            {
                                                var checkInLocation = new CheckInLocation();
                                                checkInLocation.Location = kioskLocation.Location.Clone(false);
                                                checkInLocation.Location.CopyAttributesFrom(kioskLocation.Location);
                                                checkInLocation.CampuId = kioskLocation.CampusId;
                                                group.Locations.Add(checkInLocation);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                return(true);
            }

            return(false);
        }
Exemple #7
0
        /// <summary>
        /// Gets the attendance count for all of the schedules for a location. This will show on the schedule buttons.
        /// </summary>
        /// <param name="location"></param>
        protected void GetScheduleAttendance(CheckInLocation location)
        {
            if (location != null)
            {
                var rockContext       = new RockContext();
                var attendanceService = new AttendanceService(rockContext);
                var attendanceQuery   = attendanceService.GetByDateAndLocation(DateTime.Now, location.Location.Id);

                ScheduleAttendanceList.Clear();
                foreach (var schedule in location.Schedules)
                {
                    var attendance = new ScheduleAttendance();
                    attendance.ScheduleId      = schedule.Schedule.Id;
                    attendance.AttendanceCount = attendanceQuery.Where(l => l.ScheduleId == attendance.ScheduleId).Count();
                    ScheduleAttendanceList.Add(attendance);
                }
            }
        }
        /// <summary>
        /// Handles the Delete event of the gPersonList control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RowEventArgs" /> instance containing the event data.</param>
        protected void gPersonList_Delete(object sender, RowEventArgs e)
        {
            var dataKeyValues = gPersonList.DataKeys[e.RowIndex].Values;
            var personId      = Convert.ToInt32(dataKeyValues["PersonId"]);
            var locationId    = Convert.ToInt32(dataKeyValues["LocationId"]);
            var scheduleId    = Convert.ToInt32(dataKeyValues["ScheduleId"]);

            var selectedPerson = CurrentCheckInState.CheckIn.Families.Where(f => f.Selected).FirstOrDefault()
                                 .People.Where(p => p.Person.Id == personId).FirstOrDefault();
            var selectedGroups = selectedPerson.GroupTypes.Where(gt => gt.Selected)
                                 .SelectMany(gt => gt.Groups.Where(g => g.Selected));
            CheckInGroup selectedGroup = selectedGroups.Where(g => g.Selected &&
                                                              g.Locations.Any(l => l.Location.Id == locationId &&
                                                                              l.Schedules.Any(s => s.Schedule.Id == scheduleId))).FirstOrDefault();
            CheckInLocation selectedLocation = selectedGroup.Locations.Where(l => l.Selected &&
                                                                             l.Location.Id == locationId &&
                                                                             l.Schedules.Any(s => s.Schedule.Id == scheduleId)).FirstOrDefault();
            CheckInSchedule selectedSchedule = selectedLocation.Schedules.Where(s => s.Selected &&
                                                                                s.Schedule.Id == scheduleId).FirstOrDefault();

            selectedSchedule.Selected    = false;
            selectedSchedule.PreSelected = false;

            // clear checkin rows without anything selected
            if (!selectedLocation.Schedules.Any(s => s.Selected))
            {
                selectedLocation.Selected    = false;
                selectedLocation.PreSelected = false;
            }

            if (!selectedGroup.Locations.Any(l => l.Selected))
            {
                selectedGroup.Selected    = false;
                selectedGroup.PreSelected = false;
            }

            if (!selectedGroups.Any())
            {
                selectedPerson.Selected    = false;
                selectedPerson.PreSelected = false;
            }

            BindGrid();
        }
Exemple #9
0
        /// <summary>
        /// Binds the locations.
        /// </summary>
        /// <param name="person">The person.</param>
        protected void BindLocations(List <CheckInGroupType> groupTypes)
        {
            int groupTypeId = ViewState["groupTypeId"].ToString().AsType <int>();
            int locationId  = ViewState["locationId"].ToString().AsType <int>();

            CheckInGroupType groupType = null;

            if (groupTypes.Any(gt => gt.GroupType.Id == groupTypeId))
            {
                groupType = groupTypes.Where(gt => gt.GroupType.Id == groupTypeId).FirstOrDefault();
            }
            else
            {
                groupType = groupTypes.FirstOrDefault();
            }

            CheckInLocation location  = null;
            var             locations = groupType.Groups.SelectMany(g => g.Locations).ToList();

            if (locationId > 0)
            {
                location = locations.Where(l => l.Location.Id == locationId).FirstOrDefault();
                var selectedLocationPlaceInList = locations.IndexOf(location) + 1;
                var pageSize   = this.Pager.PageSize;
                var pageToGoTo = selectedLocationPlaceInList / pageSize;
                if (selectedLocationPlaceInList % pageSize != 0)
                {
                    pageToGoTo++;
                }

                this.Pager.SetPageProperties((pageToGoTo - 1) * this.Pager.PageSize, this.Pager.MaximumRows, false);
            }
            else
            {
                location = locations.FirstOrDefault();
            }

            Session["locations"]  = locations;
            lvLocation.DataSource = locations;
            lvLocation.DataBind();
            pnlLocations.Update();
        }
Exemple #10
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, WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            if (checkInState != null)
            {
                bool loadAll = GetAttributeValue(action, "LoadAll").AsBoolean();

                foreach (var family in checkInState.CheckIn.GetFamilies(true))
                {
                    foreach (var person in family.GetPeople(!loadAll))
                    {
                        foreach (var groupType in person.GetGroupTypes(!loadAll).ToList())
                        {
                            var kioskGroupType = checkInState.Kiosk.ActiveGroupTypes(checkInState.ConfiguredGroupTypes)
                                                 .Where(g => g.GroupType.Id == groupType.GroupType.Id)
                                                 .FirstOrDefault();

                            if (kioskGroupType != null)
                            {
                                foreach (var group in groupType.GetGroups(!loadAll))
                                {
                                    var closedGroupLocationIds = new AttendanceOccurrenceService(rockContext)
                                                                 .Queryable()
                                                                 .AsNoTracking()
                                                                 .Where(o =>
                                                                        o.GroupId == group.Group.Id &&
                                                                        o.OccurrenceDate == RockDateTime.Today)
                                                                 .WhereAttributeValue(rockContext, "rocks.kfs.OccurrenceClosed", "True")
                                                                 .Select(l => l.LocationId)
                                                                 .ToList();

                                    var loadBalance = group.Group.GetAttributeValue("rocks.kfs.LoadBalanceLocations").AsBoolean();
                                    if (loadBalance && loadAll)
                                    {
                                        group.Locations.Clear();
                                    }

                                    var locationAttendance = new Dictionary <CheckInLocation, int>();

                                    foreach (var kioskGroup in kioskGroupType.KioskGroups
                                             .Where(g => g.Group.Id == group.Group.Id && g.IsCheckInActive)
                                             .ToList())
                                    {
                                        foreach (var kioskLocation in kioskGroup.KioskLocations.Where(l => l.IsCheckInActive && l.IsActiveAndNotFull && !closedGroupLocationIds.Contains(l.Location.Id)))
                                        {
                                            if (!group.Locations.Any(l => l.Location.Id == kioskLocation.Location.Id))
                                            {
                                                var checkInLocation = new CheckInLocation();
                                                checkInLocation.Location = kioskLocation.Location.Clone(false);
                                                checkInLocation.Location.CopyAttributesFrom(kioskLocation.Location);
                                                checkInLocation.CampusId = kioskLocation.CampusId;
                                                checkInLocation.Order    = kioskLocation.Order;
                                                locationAttendance.Add(checkInLocation, KioskLocationAttendance.Get(checkInLocation.Location.Id).CurrentCount);
                                            }
                                        }
                                    }

                                    if (loadBalance)
                                    {
                                        var sortedLocationAttendance = locationAttendance.ToList();
                                        sortedLocationAttendance.Sort((x, y) => x.Key.Location.Name.CompareTo(y.Key.Location.Name));
                                        sortedLocationAttendance.Sort((x, y) => x.Value.CompareTo(y.Value));
                                        var order = 0;
                                        foreach (var checkInLocationPair in sortedLocationAttendance)
                                        {
                                            var checkInLocation = checkInLocationPair.Key;
                                            checkInLocation.Order = order;
                                            group.Locations.Add(checkInLocation);

                                            order++;
                                        }
                                    }
                                    else
                                    {
                                        group.Locations.AddRange(locationAttendance.Select(l => l.Key).ToList());
                                    }
                                }
                            }
                        }
                    }
                }

                return(true);
            }

            return(false);
        }
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            RockPage.AddScriptLink("~/Scripts/CheckinClient/checkin-core.js");

            if (CurrentWorkflow == null || CurrentCheckInState == null)
            {
                NavigateToHomePage();
            }
            else
            {
                if (!Page.IsPostBack)
                {
                    ClearSelection();

                    var personSchedules   = new List <CheckInSchedule>();
                    var distinctSchedules = new List <CheckInSchedule>();
                    if (CurrentCheckInType != null && CurrentCheckInType.TypeOfCheckin == TypeOfCheckin.Family)
                    {
                        CheckInFamily family = CurrentCheckInState.CheckIn.CurrentFamily;
                        if (family != null)
                        {
                            foreach (var schedule in family.GetPeople(true).SelectMany(p => p.PossibleSchedules).ToList())
                            {
                                personSchedules.Add(schedule);
                                if (!distinctSchedules.Any(s => s.Schedule.Id == schedule.Schedule.Id))
                                {
                                    distinctSchedules.Add(schedule);
                                }
                            }
                        }
                        else
                        {
                            GoBack();
                        }

                        lTitle.Text   = GetTitleText();
                        lbSelect.Text = "Next";
                        lbSelect.Attributes.Add("data-loading-text", "Loading...");
                    }
                    else
                    {
                        CheckInPerson   person   = CurrentCheckInState.CheckIn.Families.Where(f => f.Selected).SelectMany(f => f.People.Where(p => p.Selected)).FirstOrDefault();
                        CheckInGroup    group    = null;
                        CheckInLocation location = null;

                        if (person != null)
                        {
                            group = person.GroupTypes.Where(t => t.Selected).SelectMany(t => t.Groups.Where(g => g.Selected)).FirstOrDefault();

                            if (group != null)
                            {
                                location = group.Locations.Where(l => l.Selected).FirstOrDefault();
                            }
                        }

                        if (location == null)
                        {
                            GoBack();
                        }

                        lTitle.Text   = GetTitleText();
                        lbSelect.Text = "Check In";
                        lbSelect.Attributes.Add("data-loading-text", "Printing...");

                        personSchedules   = location.Schedules.Where(s => !s.ExcludedByFilter).ToList();
                        distinctSchedules = personSchedules;
                    }

                    lCaption.Text = GetAttributeValue(AttributeKey.Caption);

                    if (distinctSchedules.Count == 1)
                    {
                        personSchedules.ForEach(s => s.Selected = true);
                        ProcessSelection(maWarning);
                    }
                    else
                    {
                        string script = string.Format(@"
    <script>
        function GetTimeSelection() {{
            var ids = '';
            $('div.checkin-timelist button.active').each( function() {{
                ids += $(this).attr('schedule-id') + ',';
            }});
            if (ids == '') {{
                bootbox.alert('Please select at least one time');
                return false;
            }}
            else
            {{
                $('#{0}').button('loading')
                $('#{1}').val(ids);
                return true;
            }}
        }}
    </script>
", lbSelect.ClientID, hfTimes.ClientID);
                        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "SelectTime", script);

                        rSelection.DataSource = distinctSchedules
                                                .OrderBy(s => s.StartTime.Value.TimeOfDay)
                                                .ThenBy(s => s.Schedule.Name)
                                                .ToList();

                        rSelection.DataBind();
                    }
                }
            }
        }
Exemple #12
0
        /// <summary>
        /// Enforces the strict location threshold by removing attendances that would have ended up going into full location+schedules.
        /// Note: The is also checked earlier in the check-in process, so this catches ones that might have just gotten full in the last few seconds.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <param name="checkInState">State of the check in.</param>
        /// <param name="attendanceService">The attendance service.</param>
        /// <param name="currentOccurrences">The current occurrences.</param>
        /// <param name="person">The person.</param>
        /// <param name="group">The group.</param>
        /// <param name="location">The location.</param>
        /// <param name="schedule">The schedule.</param>
        /// <param name="startDateTime">The start date time.</param>
        private void EnforceStrictLocationThreshold(WorkflowAction action, CheckInState checkInState, AttendanceService attendanceService, List <OccurrenceRecord> currentOccurrences, CheckInPerson person, CheckInGroup group, CheckInLocation location, CheckInSchedule schedule, DateTime startDateTime)
        {
            var thresHold = location.Location.SoftRoomThreshold.Value;

            if (checkInState.ManagerLoggedIn && location.Location.FirmRoomThreshold.HasValue && location.Location.FirmRoomThreshold.Value > location.Location.SoftRoomThreshold.Value)
            {
                thresHold = location.Location.FirmRoomThreshold.Value;
            }

            var currentOccurrence = GetCurrentOccurrence(currentOccurrences, location, schedule, startDateTime.Date);

            // The totalAttended is the number of people still checked in (not people who have been checked-out)
            // not counting the current person who may already be checked in,
            // + the number of people we have checked in so far (but haven't been saved yet).
            var attendanceQry = attendanceService.GetByDateOnLocationAndSchedule(startDateTime.Date, location.Location.Id, schedule.Schedule.Id)
                                .AsNoTracking()
                                .Where(a => a.EndDateTime == null);

            // Only process if the current person is NOT already checked-in to this location and schedule
            if (!attendanceQry.Where(a => a.PersonAlias.PersonId == person.Person.Id).Any())
            {
                var totalAttended = attendanceQry.Count() + (currentOccurrence == null ? 0 : currentOccurrence.Count);

                // If over capacity, remove the schedule and add a warning message.
                if (totalAttended >= thresHold)
                {
                    // Remove the schedule since the location was full for this schedule.
                    location.Schedules.Remove(schedule);

                    var message = new CheckInMessage()
                    {
                        MessageType = MessageType.Warning
                    };

                    var mergeFields = Lava.LavaHelper.GetCommonMergeFields(null);
                    mergeFields.Add(MergeFieldKey.Person, person.Person);
                    mergeFields.Add(MergeFieldKey.Group, group.Group);
                    mergeFields.Add(MergeFieldKey.Location, location.Location);
                    mergeFields.Add(MergeFieldKey.Schedule, schedule.Schedule);
                    message.MessageText = GetAttributeValue(action, AttributeKey.NotCheckedInMessageFormat).ResolveMergeFields(mergeFields);

                    // Now add it to the check-in state message list for others to see.
                    checkInState.Messages.Add(message);
                    return;
                }
                else
                {
                    // Keep track of anyone who was checked in so far.
                    if (currentOccurrence == null)
                    {
                        currentOccurrence = new OccurrenceRecord()
                        {
                            Date       = startDateTime.Date,
                            LocationId = location.Location.Id,
                            ScheduleId = schedule.Schedule.Id
                        };

                        currentOccurrences.Add(currentOccurrence);
                    }

                    currentOccurrence.Count += 1;
                }
            }
        }
Exemple #13
0
 /// <summary>
 /// Gets the current occurrence from the given list for the matching location, schedule and startDateTime.
 /// </summary>
 /// <param name="currentOccurrences">The current occurrences.</param>
 /// <param name="location">The location.</param>
 /// <param name="schedule">The schedule.</param>
 /// <param name="startDateTime">The start date time.</param>
 /// <returns></returns>
 private OccurrenceRecord GetCurrentOccurrence(List <OccurrenceRecord> currentOccurrences, CheckInLocation location, CheckInSchedule schedule, DateTime startDateTime)
 {
     return(currentOccurrences
            .Where(a =>
                   a.Date == startDateTime.Date &&
                   a.LocationId == location.Location.Id &&
                   a.ScheduleId == schedule.Schedule.Id)
            .FirstOrDefault());
 }
Exemple #14
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))
                                    {
                                        int?bestScheduleId     = null;
                                        var availableSchedules = validGroups.SelectMany(g => g.Locations.SelectMany(l => l.Schedules)).DistinctBy(s => s.Schedule.Id).ToList();
                                        if (availableSchedules.Any())
                                        {
                                            bestScheduleId = availableSchedules.OrderBy(s => s.StartTime).Select(s => s.Schedule.Id).FirstOrDefault();
                                        }

                                        if (bestScheduleId != null)
                                        {
                                            validGroups = validGroups.Where(g => g.AvailableForSchedule.Contains((int)bestScheduleId));
                                        }

                                        var currentGroupAttendance = bestGroup.Locations.Select(l => Helpers.ReadAttendanceBySchedule(l.Location.Id, bestScheduleId)).Sum();
                                        var lowestGroup            = validGroups.Where(g => !g.ExcludedByFilter && !excludedLocations.Contains(g.Group.Name))
                                                                     .Select(g => new { Group = g, Attendance = g.Locations.Select(l => Helpers.ReadAttendanceBySchedule(l.Location.Id, bestScheduleId)).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;
                                if (numValidLocations == 1)
                                {
                                    bestLocation = validLocations.FirstOrDefault();
                                }
                                else
                                {
                                    var filteredLocations = validLocations.Where(l => !l.ExcludedByFilter && !excludedLocations.Contains(l.Location.Name));

                                    // room balance if they fit into multiple locations
                                    if (roomBalanceGroupTypeIds.Contains(bestGroup.Group.GroupTypeId))
                                    {
                                        int?bestScheduleId     = null;
                                        var availableSchedules = filteredLocations.SelectMany(l => l.Schedules).DistinctBy(s => s.Schedule.Id).ToList();
                                        if (availableSchedules.Any())
                                        {
                                            bestScheduleId = availableSchedules.OrderBy(s => s.StartTime).Select(s => s.Schedule.Id).FirstOrDefault();
                                        }

                                        if (bestScheduleId != null)
                                        {
                                            filteredLocations = filteredLocations.Where(l => l.AvailableForSchedule.Contains((int)bestScheduleId));
                                        }

                                        filteredLocations = filteredLocations.OrderBy(l => Helpers.ReadAttendanceBySchedule(l.Location.Id, bestScheduleId));
                                    }

                                    bestLocation = filteredLocations.FirstOrDefault();
                                }

                                if (bestLocation != null && bestLocation.Schedules.Any())
                                {
                                    // finished finding assignment, verify we can select everything
                                    var bestSchedule = bestLocation.Schedules.OrderBy(s => s.Schedule.StartTimeOfDay).FirstOrDefault();
                                    if (bestSchedule != null)
                                    {
                                        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);
        }
Exemple #15
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);
        }
        /// <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()).ToList();

            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();

                    // order by most recent attendance
                    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 assignmentsGiven = 0;
                        // get the most recent day, then create assignments starting with the earliest attendance record
                        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).OrderBy(a => a.Schedule.StartTimeOfDay))
                        {
                            bool currentlyCheckedIn = false;
                            var  serviceCutoff      = groupAttendance.StartDateTime;
                            if (serviceCutoff > RockDateTime.Now.Date && groupAttendance.Schedule != null)
                            {
                                // calculate the service window to determine if people are still checked in
                                var serviceTime  = groupAttendance.StartDateTime.Date + groupAttendance.Schedule.StartTimeOfDay;
                                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)
                            {
                                // assigning the right schedule depends on prior attendance & currently available schedules being sorted
                                var orderedSchedules = groupType.Groups.SelectMany(g => g.Locations.SelectMany(l => l.Schedules))
                                                       .DistinctBy(s => s.Schedule.Id).OrderBy(s => s.Schedule.StartTimeOfDay)
                                                       .Select(s => s.Schedule.Id).ToList();

                                int?currentScheduleId = null;
                                if (orderedSchedules.Count == 1)
                                {
                                    currentScheduleId = orderedSchedules.FirstOrDefault();
                                }
                                else if (currentlyCheckedIn)
                                {
                                    // always pick the schedule they're currently checked into
                                    currentScheduleId = orderedSchedules.Where(s => s == groupAttendance.ScheduleId).FirstOrDefault();
                                }
                                else
                                {
                                    // sort the earliest schedule for the current grouptype, then skip the number of assignments already given (multiple services)
                                    currentScheduleId = groupType.AvailableForSchedule
                                                        .OrderBy(d => orderedSchedules.IndexOf(d))
                                                        .Skip(assignmentsGiven).FirstOrDefault();
                                }

                                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 and only for the current service
                                    if (group != null && currentScheduleId != null && roomBalanceGroupTypeIds.Contains(group.Group.GroupTypeId) && !excludedLocations.Contains(group.Group.Name) && !useCheckinOverride)
                                    {
                                        // make sure balanced rooms are open for the current service
                                        var currentAttendance = group.Locations.Where(l => l.AvailableForSchedule.Contains((int)currentScheduleId))
                                                                .Select(l => Helpers.ReadAttendanceBySchedule(l.Location.Id, currentScheduleId)).Sum();

                                        var lowestAttendedGroup = groupType.Groups.Where(g => g.AvailableForSchedule.Contains((int)currentScheduleId))
                                                                  .Where(g => !g.ExcludedByFilter && !excludedLocations.Contains(g.Group.Name))
                                                                  .Select(g => new { Group = g, Attendance = g.Locations.Select(l => Helpers.ReadAttendanceBySchedule(l.Location.Id, currentScheduleId)).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 and only for the current service
                                        if (location != null && currentScheduleId != null && roomBalanceGroupTypeIds.Contains(group.Group.GroupTypeId) && !excludedLocations.Contains(location.Location.Name) && !useCheckinOverride)
                                        {
                                            var currentAttendance = Helpers.ReadAttendanceBySchedule(location.Location.Id, currentScheduleId);

                                            var lowestAttendedLocation = group.Locations.Where(l => l.AvailableForSchedule.Contains((int)currentScheduleId))
                                                                         .Where(l => !l.ExcludedByFilter && !excludedLocations.Contains(l.Location.Name))
                                                                         .Select(l => new { Location = l, Attendance = Helpers.ReadAttendanceBySchedule(l.Location.Id, currentScheduleId) })
                                                                         .OrderBy(l => l.Attendance)
                                                                         .FirstOrDefault();

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

                                    if (location != null)
                                    {
                                        // the current schedule could exist on multiple locations, so pick the one owned by this location
                                        // if the current schedule just closed, get the first available schedule at this location
                                        CheckInSchedule schedule = location.Schedules.OrderByDescending(s => s.Schedule.Id == currentScheduleId).FirstOrDefault();
                                        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 feature either removes the attendance or sets 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;
                                            previousAttender.Selected    = true;
                                            previousAttender.PreSelected = true;
                                            assignmentsGiven++;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(true);
        }
Exemple #17
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);
        }
Exemple #18
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);
        }
Exemple #19
0
        private CheckInStatus DehydrateStatus(CheckInStatus status)
        {
            var checkinstatus = new CheckInStatus
            {
                SearchType  = status.SearchType,
                SearchValue = status.SearchValue,
                Families    = new List <CheckInFamily>()
            };

            foreach (var family in status.Families)
            {
                var checkinFamily = new CheckInFamily()
                {
                    Selected      = family.Selected,
                    Caption       = family.Caption,
                    SubCaption    = family.SubCaption,
                    AttendanceIds = family.AttendanceIds,
                    FirstNames    = family.FirstNames,
                    Group         = new Group()
                    {
                        Id = family.Group.Id
                    },
                    People = new List <CheckInPerson>()
                };
                checkinstatus.Families.Add(checkinFamily);

                foreach (var person in family.People)
                {
                    var checkInPerson = new CheckInPerson
                    {
                        GroupTypes   = new List <CheckInGroupType>(),
                        FirstTime    = person.FirstTime,
                        FamilyMember = person.FamilyMember,
                        Person       = new Person {
                            Id = person.Person.Id
                        },
                        PreSelected      = person.PreSelected,
                        SecurityCode     = person.SecurityCode,
                        ExcludedByFilter = person.ExcludedByFilter,
                        Selected         = person.Selected
                    };
                    checkinFamily.People.Add(checkInPerson);

                    foreach (var grouptype in person.GroupTypes)
                    {
                        var checkinGroupType = new CheckInGroupType
                        {
                            GroupType        = grouptype.GroupType,
                            Selected         = grouptype.Selected,
                            PreSelected      = grouptype.PreSelected,
                            ExcludedByFilter = grouptype.ExcludedByFilter,
                            Groups           = new List <CheckInGroup>()
                        };
                        checkInPerson.GroupTypes.Add(checkinGroupType);

                        foreach (var group in grouptype.Groups)
                        {
                            var checkinGroup = new CheckInGroup
                            {
                                Group = new Group {
                                    Id = group.Group.Id
                                },
                                Selected         = group.Selected,
                                PreSelected      = group.PreSelected,
                                ExcludedByFilter = group.ExcludedByFilter,
                                Locations        = new List <CheckInLocation>()
                            };
                            checkinGroupType.Groups.Add(group);

                            foreach (var location in group.Locations)
                            {
                                var checkinLocation = new CheckInLocation
                                {
                                    Location = new Location {
                                        Id = location.Location.Id
                                    },
                                    Selected         = location.Selected,
                                    PreSelected      = location.PreSelected,
                                    ExcludedByFilter = location.ExcludedByFilter,
                                    CampusId         = location.CampusId,
                                    Schedules        = new List <CheckInSchedule>()
                                };
                                checkinGroup.Locations.Add(checkinLocation);

                                foreach (var schedule in location.Schedules)
                                {
                                    var checkinSchedule = new CheckInSchedule
                                    {
                                        Schedule = new Schedule {
                                            Id = schedule.Schedule.Id
                                        },
                                        Selected         = schedule.Selected,
                                        PreSelected      = schedule.PreSelected,
                                        ExcludedByFilter = schedule.ExcludedByFilter,
                                        CampusId         = schedule.CampusId,
                                        StartTime        = schedule.StartTime
                                    };
                                    checkinLocation.Schedules.Add(checkinSchedule);
                                }
                            }
                        }
                    }
                }
            }
            return(checkinstatus);
        }
Exemple #20
0
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            RockPage.AddScriptLink("~/Scripts/iscroll.js");
            RockPage.AddScriptLink("~/Scripts/CheckinClient/checkin-core.js");

            if (CurrentWorkflow == null || CurrentCheckInState == null)
            {
                NavigateToHomePage();
            }
            else
            {
                if (!Page.IsPostBack)
                {
                    ClearSelection();

                    CheckInPerson   person   = null;
                    CheckInGroup    group    = null;
                    CheckInLocation location = null;

                    person = CurrentCheckInState.CheckIn.Families.Where(f => f.Selected)
                             .SelectMany(f => f.People.Where(p => p.Selected))
                             .FirstOrDefault();

                    if (person != null)
                    {
                        group = person.GroupTypes.Where(t => t.Selected)
                                .SelectMany(t => t.Groups.Where(g => g.Selected))
                                .FirstOrDefault();

                        if (group != null)
                        {
                            location = group.Locations.Where(l => l.Selected)
                                       .FirstOrDefault();
                        }
                    }

                    if (location == null)
                    {
                        GoBack();
                    }

                    lTitle.Text    = person.ToString();
                    lSubTitle.Text = string.Format("{0} - {1}", group.ToString(), location.ToString());

                    var availSchedules = location.Schedules.Where(s => !s.ExcludedByFilter).ToList();
                    if (availSchedules.Count == 1)
                    {
                        availSchedules.FirstOrDefault().Selected = true;
                        ProcessSelection(maWarning);
                    }
                    else
                    {
                        string script = string.Format(@"
    <script>
        function GetTimeSelection() {{
            var ids = '';
            $('div.checkin-timelist button.active').each( function() {{
                ids += $(this).attr('schedule-id') + ',';
            }});
            if (ids == '') {{
                bootbox.alert('Please select at least one time');
                return false;
            }}
            else
            {{
                $('#{0}').button('loading')
                $('#{1}').val(ids);
                return true;
            }}
        }}
    </script>
", lbSelect.ClientID, hfTimes.ClientID);
                        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "SelectTime", script);

                        rSelection.DataSource = availSchedules
                                                .OrderBy(s => s.StartTime.Value.TimeOfDay)
                                                .ThenBy(s => s.Schedule.Name)
                                                .ToList();

                        rSelection.DataBind();
                    }
                }
            }
        }
Exemple #21
0
 private void SelectLocation(CheckInPerson person, CheckInGroupType gt, CheckInGroup g, CheckInLocation l)
 {
     l.Selected = !l.Selected;
     if (l.Selected)
     {
         person.Selected = true;
         gt.Selected     = true;
         g.Selected      = true;
         foreach (var s in l.Schedules)
         {
             s.Selected = true;
         }
     }
     else
     {
         foreach (var s in l.Schedules)
         {
             s.Selected = false;
         }
         if (!g.Locations.Where(_l => _l.Selected).Any())
         {
             g.Selected = false;
         }
         if (!gt.Groups.Where(_g => _g.Selected).Any())
         {
             gt.Selected = false;
         }
         if (!person.GroupTypes.Where(_gt => _gt.Selected).Any())
         {
             person.Selected = false;
         }
     }
     SaveState();
     BuildMemberCards();
 }