Example #1
0
        private void addLabel(CheckInLabel checkInLabel, CheckInState checkInState, CheckInGroupType groupType, CheckInGroup group, RockContext rockContext)
        {
            var PrinterIPs = new Dictionary <int, string>();

            if (checkInLabel.PrintTo == PrintTo.Default)
            {
                checkInLabel.PrintTo = groupType.GroupType.AttendancePrintTo;
            }
            else if (checkInLabel.PrintTo == PrintTo.Location && group.Locations.Any())
            {
                var deviceId = group.Locations.FirstOrDefault().Location.PrinterDeviceId;
                if (deviceId != null)
                {
                    checkInLabel.PrinterDeviceId = deviceId;
                }
            }
            else
            {
                var device = checkInState.Kiosk.Device;
                if (device != null)
                {
                    checkInLabel.PrinterDeviceId = device.PrinterDeviceId;
                }
            }


            if (checkInLabel.PrinterDeviceId.HasValue)
            {
                if (PrinterIPs.ContainsKey(checkInLabel.PrinterDeviceId.Value))
                {
                    checkInLabel.PrinterAddress = PrinterIPs[checkInLabel.PrinterDeviceId.Value];
                }
                else
                {
                    var printerDevice = new DeviceService(rockContext).Get(checkInLabel.PrinterDeviceId.Value);
                    if (printerDevice != null)
                    {
                        PrinterIPs.Add(printerDevice.Id, printerDevice.IPAddress);
                        checkInLabel.PrinterAddress = printerDevice.IPAddress;
                    }
                }
            }

            groupType.Labels.Insert(0, checkInLabel);
        }
Example #2
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();
        }
Example #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, Rock.Model.WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            if (checkInState != null)
            {
                //This is an optimization over standard Rock
                //Core Rock has this inside the loop. Reading all the iCals is slow.
                var activeKioskGroupTypes = new List <KioskGroupType>();

                foreach (var kioskGroupType in checkInState.Kiosk.ActiveGroupTypes(checkInState.ConfiguredGroupTypes))
                {
                    if (kioskGroupType.KioskGroups.SelectMany(g => g.KioskLocations).Any(l => l.IsCheckInActive && l.Location.IsActive))
                    {
                        activeKioskGroupTypes.Add(kioskGroupType);
                    }
                }

                foreach (var family in checkInState.CheckIn.GetFamilies(true))
                {
                    foreach (var person in family.People)
                    {
                        foreach (var kioskGroupType in activeKioskGroupTypes)
                        {
                            if (!person.GroupTypes.Any(g => g.GroupType.Id == kioskGroupType.GroupType.Id))
                            {
                                var checkinGroupType = new CheckInGroupType();
                                checkinGroupType.GroupType = kioskGroupType.GroupType;
                                person.GroupTypes.Add(checkinGroupType);
                            }
                        }
                    }
                }
                return(true);
            }
            errorMessages.Add($"Attempted to run {this.GetType().GetFriendlyTypeName()} in check-in, but the check-in state was null.");
            return(false);
        }
Example #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, 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);
        }
Example #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, WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            var checkInState = GetCheckInState(entity, out errorMessages);

            CheckInGroupType lastCheckinGroupType = null;

            List <string> labelCodes = new List <string>();
            List <int>    childGroupIds;

            var    volAttributeGuid = GetAttributeValue(action, "VolunteerGroupAttribute");
            string volAttributeKey  = "";

            if (!string.IsNullOrWhiteSpace(volAttributeGuid))
            {
                volAttributeKey = AttributeCache.Read(volAttributeGuid.AsGuid()).Key;
                childGroupIds   = checkInState.Kiosk.KioskGroupTypes
                                  .SelectMany(g => g.KioskGroups)
                                  .Where(g => !g.Group.GetAttributeValue(volAttributeKey).AsBoolean())
                                  .Select(g => g.Group.Id).ToList();
            }
            else
            {
                childGroupIds = new List <int>();
            }

            if (checkInState != null)
            {
                var attendanceService = new AttendanceService(rockContext);
                var globalAttributes  = Rock.Web.Cache.GlobalAttributesCache.Read(rockContext);
                var globalMergeValues = Rock.Lava.LavaHelper.GetCommonMergeFields(null);

                var groupMemberService = new GroupMemberService(rockContext);

                foreach (var family in checkInState.CheckIn.Families.Where(f => f.Selected))
                {
                    foreach (var person in family.People.Where(p => p.Selected))
                    {
                        if (person.GroupTypes.Where(gt => gt.Selected).SelectMany(gt => gt.Groups).Where(g => g.Selected && childGroupIds.Contains(g.Group.Id)).Any())
                        {
                            labelCodes.Add((person.SecurityCode) + "-" + LabelAge(person.Person));
                        }

                        if (string.IsNullOrEmpty(person.SecurityCode))
                        {
                            var lastAttendance = attendanceService.Queryable()
                                                 .Where(a => a.PersonAlias.PersonId == person.Person.Id && a.AttendanceCode != null)
                                                 .OrderByDescending(a => a.StartDateTime)
                                                 .FirstOrDefault();
                            if (lastAttendance != null)
                            {
                                person.SecurityCode = lastAttendance.AttendanceCode.Code;
                            }
                        }

                        var firstCheckinGroupType = person.GroupTypes.Where(g => g.Selected).FirstOrDefault();
                        if (firstCheckinGroupType != null)
                        {
                            List <Guid> labelGuids = new List <Guid>();

                            var mergeObjects = new Dictionary <string, object>();
                            foreach (var keyValue in globalMergeValues)
                            {
                                mergeObjects.Add(keyValue.Key, keyValue.Value);
                            }
                            mergeObjects.Add("Person", person);
                            mergeObjects.Add("GroupTypes", person.GroupTypes.Where(g => g.Selected).ToList());
                            List <Group>    mergeGroups    = new List <Group>();
                            List <Location> mergeLocations = new List <Location>();
                            List <Schedule> mergeSchedules = new List <Schedule>();

                            var sets = attendanceService
                                       .Queryable().AsNoTracking().Where(a =>
                                                                         a.PersonAlias.Person.Id == person.Person.Id &&
                                                                         a.StartDateTime >= Rock.RockDateTime.Today &&
                                                                         a.EndDateTime == null &&
                                                                         a.Group != null &&
                                                                         a.Schedule != null &&
                                                                         a.Location != null
                                                                         )
                                       .Select(a =>
                                               new
                            {
                                Group          = a.Group,
                                Location       = a.Location,
                                Schedule       = a.Schedule,
                                AttendanceGuid = a.Guid
                            }
                                               )
                                       .ToList()
                                       .OrderBy(a => a.Schedule.StartTimeOfDay);

                            //Load breakout group
                            var breakoutGroups = GetBreakoutGroups(person.Person, rockContext, action);

                            //Add in an empty object as a placeholder for our breakout group
                            mergeObjects.Add("BreakoutGroup", "");

                            //Add in GUID for QR code
                            if (sets.Any())
                            {
                                mergeObjects.Add("AttendanceGuid", sets.FirstOrDefault().AttendanceGuid.ToString());
                            }

                            foreach (var set in sets)
                            {
                                mergeGroups.Add(set.Group);
                                mergeLocations.Add(set.Location);
                                mergeSchedules.Add(set.Schedule);

                                //Add the breakout group mergefield
                                if (breakoutGroups.Any())
                                {
                                    var breakoutGroup = breakoutGroups.Where(g => g.ScheduleId == set.Schedule.Id).FirstOrDefault();
                                    if (breakoutGroup != null)
                                    {
                                        var breakoutGroupEntity = new GroupService(rockContext).Get(breakoutGroup.Id);
                                        if (breakoutGroupEntity != null)
                                        {
                                            breakoutGroupEntity.LoadAttributes();
                                            mergeObjects["BreakoutGroup"] = breakoutGroupEntity.GetAttributeValue("Letter");
                                        }
                                    }
                                }
                            }
                            mergeObjects.Add("Groups", mergeGroups);
                            mergeObjects.Add("Locations", mergeLocations);
                            mergeObjects.Add("Schedules", mergeSchedules);

                            foreach (var groupType in person.GroupTypes.Where(g => g.Selected))
                            {
                                lastCheckinGroupType = groupType;

                                groupType.Labels = new List <CheckInLabel>();

                                GetGroupTypeLabels(groupType.GroupType, firstCheckinGroupType.Labels, mergeObjects, labelGuids);

                                var PrinterIPs = new Dictionary <int, string>();

                                foreach (var label in groupType.Labels)
                                {
                                    label.PrintFrom = checkInState.Kiosk.Device.PrintFrom;
                                    label.PrintTo   = checkInState.Kiosk.Device.PrintToOverride;

                                    if (label.PrintTo == PrintTo.Default)
                                    {
                                        label.PrintTo = groupType.GroupType.AttendancePrintTo;
                                    }

                                    if (label.PrintTo == PrintTo.Kiosk)
                                    {
                                        var device = checkInState.Kiosk.Device;
                                        if (device != null)
                                        {
                                            label.PrinterDeviceId = device.PrinterDeviceId;
                                        }
                                    }
                                    else if (label.PrintTo == PrintTo.Location)
                                    {
                                        // Should only be one
                                        var group = groupType.Groups.Where(g => g.Selected).FirstOrDefault();
                                        if (group != null)
                                        {
                                            var location = group.Locations.Where(l => l.Selected).FirstOrDefault();
                                            if (location != null)
                                            {
                                                var device = location.Location.PrinterDevice;
                                                if (device != null)
                                                {
                                                    label.PrinterDeviceId = device.PrinterDeviceId;
                                                }
                                            }
                                        }
                                    }

                                    if (label.PrinterDeviceId.HasValue)
                                    {
                                        if (PrinterIPs.ContainsKey(label.PrinterDeviceId.Value))
                                        {
                                            label.PrinterAddress = PrinterIPs[label.PrinterDeviceId.Value];
                                        }
                                        else
                                        {
                                            var printerDevice = new DeviceService(rockContext).Get(label.PrinterDeviceId.Value);
                                            if (printerDevice != null)
                                            {
                                                PrinterIPs.Add(printerDevice.Id, printerDevice.IPAddress);
                                                label.PrinterAddress = printerDevice.IPAddress;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    //Add in custom labels for parents
                    //This is the aggregate part
                    List <CheckInLabel> customLabels = new List <CheckInLabel>();

                    List <string> mergeCodes = (( string )GetAttributeValue(action, "MergeText")).Split(',').ToList();
                    while (labelCodes.Count > 0)
                    {
                        var mergeDict = new Dictionary <string, string>();

                        foreach (var mergeCode in mergeCodes)
                        {
                            if (labelCodes.Count > 0)
                            {
                                mergeDict.Add(mergeCode, labelCodes[0]);
                                labelCodes.RemoveAt(0);
                            }
                            else
                            {
                                mergeDict.Add(mergeCode, "");
                            }
                        }

                        mergeDict.Add("Date", Rock.RockDateTime.Today.DayOfWeek.ToString().Substring(0, 3) + " " + Rock.RockDateTime.Today.ToMonthDayString());

                        var labelCache = KioskLabel.Read(new Guid(GetAttributeValue(action, "AggregatedLabel")));
                        if (labelCache != null)
                        {
                            var checkInLabel = new CheckInLabel(labelCache, new Dictionary <string, object>());
                            checkInLabel.FileGuid = new Guid(GetAttributeValue(action, "AggregatedLabel"));

                            foreach (var keyValue in mergeDict)
                            {
                                if (checkInLabel.MergeFields.ContainsKey(keyValue.Key))
                                {
                                    checkInLabel.MergeFields[keyValue.Key] = keyValue.Value;
                                }
                                else
                                {
                                    checkInLabel.MergeFields.Add(keyValue.Key, keyValue.Value);
                                }
                            }

                            checkInLabel.PrintFrom = checkInState.Kiosk.Device.PrintFrom;
                            checkInLabel.PrintTo   = checkInState.Kiosk.Device.PrintToOverride;

                            if (checkInLabel.PrintTo == PrintTo.Default)
                            {
                                checkInLabel.PrintTo = lastCheckinGroupType.GroupType.AttendancePrintTo;
                            }

                            if (checkInLabel.PrintTo == PrintTo.Kiosk)
                            {
                                var device = checkInState.Kiosk.Device;
                                if (device != null)
                                {
                                    checkInLabel.PrinterDeviceId = device.PrinterDeviceId;
                                }
                            }
                            else if (checkInLabel.PrintTo == PrintTo.Location)
                            {
                                // Should only be one
                                var group = lastCheckinGroupType.Groups.Where(g => g.Selected).FirstOrDefault();
                                if (group != null)
                                {
                                    var location = group.Locations.Where(l => l.Selected).FirstOrDefault();
                                    if (location != null)
                                    {
                                        var device = location.Location.PrinterDevice;
                                        if (device != null)
                                        {
                                            checkInLabel.PrinterDeviceId = device.PrinterDeviceId;
                                        }
                                    }
                                }
                            }
                            if (checkInLabel.PrinterDeviceId.HasValue)
                            {
                                var printerDevice = new DeviceService(rockContext).Get(checkInLabel.PrinterDeviceId.Value);
                                checkInLabel.PrinterAddress = printerDevice.IPAddress;
                            }
                            if (lastCheckinGroupType != null)
                            {
                                lastCheckinGroupType.Labels.Add(checkInLabel);
                            }
                        }
                    }
                }

                return(true);
            }

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

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

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