Exemplo n.º 1
0
        public async Task CanGetMissingTimeEntries()
        {
            var now      = new DateTime(2001, 1, 1);
            int userId   = 1;
            int patrolId = 1;

            var scheduledShift = new ScheduledShift()
            {
                StartsAt        = now - new TimeSpan(1, 0, 0),
                EndsAt          = now + new TimeSpan(1, 0, 0),
                DurationSeconds = (int)(new TimeSpan(2, 0, 0)).TotalSeconds,
                PatrolId        = patrolId,
            };
            await _shiftRepository.InsertScheduledShift(scheduledShift);

            var scheduledShiftAssignment = new ScheduledShiftAssignment()
            {
                AssignedUserId   = userId,
                ScheduledShiftId = scheduledShift.Id,
                Status           = ShiftStatus.Assigned
            };
            await _shiftRepository.InsertScheduledShiftAssignment(scheduledShiftAssignment);


            var entries = await _timeEntryRepository.GetMissingTimeEntries(patrolId, now);


            Assert.AreEqual(1, entries.Count());
        }
        public void CanAddShift()
        {
            var newShift = new ScheduledShift { StartHour = 12, StartMinute = 30, EndHour = 4, EndMinute = 30, RepeatsOnSaturday = true };
            var response = Post("/scheduled-shifts", newShift);

            var allShifts = Query(db => db.Connection.GetList<ScheduledShift>().ToList());
            Assert.Equal(3, allShifts.Count());

            var newestShift = allShifts.Where(s => s.StartHour == 12 && s.StartMinute == 30 && s.EndHour == 4 && s.EndMinute == 30 && s.RepeatsOnSaturday).First();
            Assert.Equal(response.Headers["Location"], String.Format("//scheduled-shifts/{0}", newestShift.Id));
        }
Exemplo n.º 3
0
        public async Task RemoveWorkItemsFromShiftOccurence(ScheduledShift shift)
        {
            var now       = _clock.UtcNow.UtcDateTime;
            var workItems = await _workItemRepository.GetWorkItems(now, 0, scheduledShiftId : shift.Id);

            foreach (var wi in workItems)
            {
                foreach (var asn in wi.Assignments)
                {
                    await _workItemRepository.DeleteWorkItemAssignment(asn);
                }
                await _workItemRepository.DeleteWorkItem(wi);
            }
        }
Exemplo n.º 4
0
        public async Task SendShiftAdded(List <User> assigned, Models.Patrol patrol, ScheduledShift shift)
        {
            var localStart = shift.StartsAt.UtcToPatrolLocal(patrol);
            var localEnd   = shift.EndsAt.UtcToPatrolLocal(patrol);

            var msg = new SendGridMessage()
            {
                Subject          = $"Shift created on {localStart.ToShortDateString()}",
                PlainTextContent = $"You have a new shift on {localStart.ToShortDateString()}, {localStart.ToShortTimeString()} - {localEnd.ToShortTimeString()}.",
                HtmlContent      = $"You have a new shift on {localStart.ToShortDateString()}, {localStart.ToShortTimeString()} - {localEnd.ToShortTimeString()}.",
            };

            this.AddOnBehalfOf(msg, patrol);

            var response = await Send(msg, patrol, assigned.ToArray());
        }
Exemplo n.º 5
0
        public async Task SendShiftRemoved(User assigned, Models.Patrol patrol, ScheduledShift shift)
        {
            var localStart = shift.StartsAt.UtcToPatrolLocal(patrol);
            var localEnd   = shift.EndsAt.UtcToPatrolLocal(patrol);

            var msg = new SendGridMessage()
            {
                Subject          = $"Shift on {localStart.ToShortDateString()} removed.",
                PlainTextContent = $"Your shift on {localStart.ToShortDateString()} has been removed.",
                HtmlContent      = $"Your shift on {localStart.ToShortDateString()} has been removed.",
            };

            this.AddOnBehalfOf(msg, patrol);

            var response = await Send(msg, patrol, assigned);
        }
Exemplo n.º 6
0
        public async Task AddWorkItemsToNewShiftOccurence(ScheduledShift shift)
        {
            var now             = _clock.UtcNow.UtcDateTime;
            var scheduledShifts = await _shiftRepository.GetScheduledShiftAssignments(shift.PatrolId, scheduledShiftId : shift.Id);

            var recurringWorkItems = await _workItemRepository.GetRecurringWorkItemsForShifts(new List <int>(shift.Id));

            var workItems = await _workItemRepository.GetWorkItemsForShifts(new List <int>(shift.Id));

            var workItemAssignments = await _workItemRepository.GetWorkItemAssignmentsForShifts(new List <int>() { shift.Id });

            var shiftRecurringWorkItems = await _workItemRepository.GetShiftRecurringWorkItemsForShifts(new List <int>(shift.Id));

            var patrol = await _patrolRepository.GetPatrol(shift.PatrolId);

            var shiftAssignments = await _shiftRepository.GetScheduledShiftAssignments(shift.PatrolId, scheduledShiftId : shift.Id);

            var shiftStartLocal = shift.StartsAt.UtcToPatrolLocal(patrol);

            var missings = recurringWorkItems.Where(x => !workItems.Any(y => y.RecurringWorkItemId == x.Id)).ToList();

            foreach (var missing in missings)
            {
                var shiftRecurrences = shiftRecurringWorkItems.Where(x => x.RecurringWorkItemId == missing.Id);

                foreach (var recurrence in shiftRecurrences)
                {
                    var workItem = new WorkItem()
                    {
                        AdminGroupId      = missing.AdminGroupId,
                        CreatedAt         = now,
                        CreatedByUserId   = missing.CreatedByUserId,
                        CompletionMode    = missing.CompletionMode,
                        DescriptionMarkup = missing.DescriptionMarkup,
                        Location          = missing.Location,
                        Name                = missing.Name,
                        PatrolId            = missing.PatrolId,
                        RecurringWorkItemId = missing.Id,
                        ScheduledShiftId    = shift.Id,
                        ScheduledAt         = new DateTime(shiftStartLocal.Year, shiftStartLocal.Month, shiftStartLocal.Day, recurrence.ScheduledAtHour, recurrence.ScheduledAtMinute, 0).UtcFromPatrolLocal(patrol)
                    };
                    await _workItemRepository.InsertWorkItem(workItem);
                }
            }

            await RecalculateSingleShiftWorkItemAssignments(shift.Id, shiftAssignments.ToList(), workItems.ToList(), workItemAssignments.ToList(), recurringWorkItems.ToList(), shiftRecurringWorkItems.ToList());
        }
Exemplo n.º 7
0
        public async Task CanUpdateTimeEntryScheduledShiftAssignment()
        {
            var now      = new DateTime(2001, 1, 1);
            int userId   = 1;
            int patrolId = 1;

            var entry = new TimeEntry()
            {
                ClockIn  = now,
                PatrolId = patrolId,
                UserId   = userId
            };
            await _timeEntryRepository.InsertTimeEntry(entry);

            var scheduledShift = new ScheduledShift()
            {
                StartsAt        = now,
                EndsAt          = now + new TimeSpan(1, 0, 0),
                DurationSeconds = (int)(new TimeSpan(1, 0, 0)).TotalSeconds,
                PatrolId        = patrolId,
            };
            await _shiftRepository.InsertScheduledShift(scheduledShift);

            var scheduledShiftAssignment = new ScheduledShiftAssignment()
            {
                AssignedUserId   = userId,
                ScheduledShiftId = scheduledShift.Id,
                Status           = ShiftStatus.Assigned
            };
            await _shiftRepository.InsertScheduledShiftAssignment(scheduledShiftAssignment);

            var timeEntryScheduledShiftAssignment = new TimeEntryScheduledShiftAssignment()
            {
                ScheduledShiftAssignmentId = scheduledShiftAssignment.Id,
                TimeEntryId = entry.Id
            };
            await _timeEntryRepository.InsertTimeEntryScheduledShiftAssignment(timeEntryScheduledShiftAssignment);

            timeEntryScheduledShiftAssignment.DurationSeconds = 1000;
            await _timeEntryRepository.UpdateTimeEntryScheduledShiftAssignment(timeEntryScheduledShiftAssignment);

            var after = await _timeEntryRepository.GetTimeEntryScheduledShiftAssignment(timeEntryScheduledShiftAssignment.Id);


            Assert.AreEqual(1000, after.DurationSeconds);
        }
        public async Task CanDeleteScheduledShift()
        {
            var before = new ScheduledShift()
            {
                StartsAt = new DateTime(2001, 1, 1, 8, 0, 0),
                EndsAt   = new DateTime(2001, 1, 1, 14, 0, 0),
                GroupId  = null,
                PatrolId = 1,
                ShiftId  = null
            };

            await _shiftRepository.InsertScheduledShift(before);

            await _shiftRepository.DeleteScheduledShift(before);

            var after = await _shiftRepository.GetScheduledShift(before.Id);

            Assert.IsNull(after);
        }
        public async Task CanInsertScheduledShift()
        {
            var before = new ScheduledShift()
            {
                StartsAt = new DateTime(2001, 1, 1, 8, 0, 0),
                EndsAt   = new DateTime(2001, 1, 1, 14, 0, 0),
                GroupId  = null,
                PatrolId = 1,
                ShiftId  = null
            };

            await _shiftRepository.InsertScheduledShift(before);

            var after = await _shiftRepository.GetScheduledShift(before.Id);

            Assert.AreEqual(before.StartsAt, after.StartsAt);
            Assert.AreEqual(before.EndsAt, after.EndsAt);
            Assert.AreEqual(before.GroupId, after.GroupId);
            Assert.AreEqual(before.PatrolId, after.PatrolId);
            Assert.AreEqual(before.ShiftId, after.ShiftId);
        }
Exemplo n.º 10
0
        public async Task SendTrainerShiftRemoved(User trainerUser, List <User> traineeUsers, Models.Patrol patrol, ScheduledShift shift)
        {
            var localStart = shift.StartsAt.UtcToPatrolLocal(patrol);
            var localEnd   = shift.EndsAt.UtcToPatrolLocal(patrol);

            var msg = new SendGridMessage()
            {
                Subject          = $"Trainer Shift Removed {localStart.ToShortDateString()}",
                PlainTextContent = $"{trainerUser.GetFullName()}'s shift in which you wanted to train with them on {localStart.ToShortDateString()} {localStart.ToShortTimeString()} - {localEnd.ToShortTimeString()} has been removed.\n  Please reschedule your training.",
                HtmlContent      = $"{trainerUser.GetFullName()}'s shift in which you wanted to train with them on {localStart.ToShortDateString()} {localStart.ToShortTimeString()} - {localEnd.ToShortTimeString()} has been removed.<br/>  Please reschedule your training.",
            };

            this.AddOnBehalfOf(msg, patrol);

            var response = await Send(msg, patrol, traineeUsers.ToArray());
        }
Exemplo n.º 11
0
        public async Task <ScheduledShift> ScheduleShift(ScheduledShiftUpdateDto dto)
        {
            var patrol = await _patrolRepository.GetPatrol(dto.PatrolId);

            Group        group        = null;
            IList <User> groupMembers = null;

            if (dto.GroupId.HasValue)
            {
                group = await _groupRepository.GetGroup(dto.GroupId.Value);

                groupMembers = (await _groupRepository.GetUsersInGroup(dto.GroupId.Value)).ToList();
            }

            Shift shift = null;

            if (dto.StartsAt.HasValue && dto.EndsAt.HasValue && !dto.ShiftId.HasValue)
            {
                var localizedStart = dto.StartsAt.Value.UtcToPatrolLocal(patrol);
                var localizedEnd   = dto.EndsAt.Value.UtcToPatrolLocal(patrol);
                var shifts         = await _shiftRepository.GetShifts(dto.PatrolId, localizedStart.Hour, localizedStart.Minute, localizedEnd.Hour, localizedEnd.Minute);

                if (shifts.Any())
                {
                    shift       = shifts.First();
                    dto.ShiftId = shift.Id;
                }
            }
            else if (dto.ShiftId.HasValue && dto.Day.HasValue)
            {
                shift = await _shiftRepository.GetShift(dto.ShiftId.Value);

                if (!dto.StartsAt.HasValue)
                {
                    var start = new DateTime(dto.Day.Value.Year, dto.Day.Value.Month, dto.Day.Value.Day, shift.StartHour, shift.StartMinute, 0, 0, DateTimeKind.Unspecified);
                    dto.StartsAt = start.UtcFromPatrolLocal(patrol);
                }
                if (!dto.EndsAt.HasValue)
                {
                    var end = new DateTime(dto.Day.Value.Year, dto.Day.Value.Month, dto.Day.Value.Day, shift.EndHour, shift.EndMinute, 0, 0, DateTimeKind.Unspecified);
                    dto.EndsAt = end.UtcFromPatrolLocal(patrol);
                }
            }
            else
            {
                throw new InvalidOperationException("Scheduled shift must provide either start+end or day+shift");
            }

            //by this point we should have filled in the dto as best we can and can now persist

            ScheduledShift scheduledShift = null;
            List <ScheduledShiftAssignment> assignments    = null;
            List <ScheduledShiftAssignment> newAssignments = new List <ScheduledShiftAssignment>();

            if (dto.Id != default(int))
            {
                scheduledShift = await _shiftRepository.GetScheduledShift(dto.Id);

                scheduledShift.StartsAt        = dto.StartsAt.Value;
                scheduledShift.EndsAt          = dto.EndsAt.Value;
                scheduledShift.GroupId         = group != null ? (int?)group.Id : null;
                scheduledShift.ShiftId         = shift != null ? (int?)shift.Id : null;
                scheduledShift.DurationSeconds = (int)(scheduledShift.EndsAt - scheduledShift.StartsAt).TotalSeconds;
                await _shiftRepository.UpdateScheduledShift(scheduledShift);

                assignments = (await _shiftRepository.GetScheduledShiftAssignmentsForScheduledShift(dto.Id)).ToList();
            }
            else
            {
                //make sure there's not an existing shift with the same start/end
                var existing = await _shiftRepository.GetScheduledShifts(dto.PatrolId, dto.StartsAt.Value, dto.EndsAt.Value);

                if (existing.Any())
                {
                    scheduledShift = existing.First();
                    dto.Id         = scheduledShift.Id;

                    bool updated = false;
                    if (!scheduledShift.GroupId.HasValue && group != null)
                    {
                        scheduledShift.GroupId = group.Id;
                        updated = true;
                    }
                    if (!scheduledShift.ShiftId.HasValue && shift != null)
                    {
                        scheduledShift.ShiftId = shift.Id;
                        updated = true;
                    }
                    if (updated)
                    {
                        scheduledShift.DurationSeconds = (int)(scheduledShift.EndsAt - scheduledShift.StartsAt).TotalSeconds;
                        await _shiftRepository.UpdateScheduledShift(scheduledShift);
                    }

                    assignments = (await _shiftRepository.GetScheduledShiftAssignmentsForScheduledShift(dto.Id)).ToList();
                }
                else
                {
                    scheduledShift = new ScheduledShift()
                    {
                        PatrolId = dto.PatrolId,
                        GroupId  = group != null ? (int?)group.Id : null,
                        ShiftId  = shift != null ? (int?)shift.Id : null,
                        StartsAt = dto.StartsAt.Value,
                        EndsAt   = dto.EndsAt.Value
                    };
                    scheduledShift.DurationSeconds = (int)(scheduledShift.EndsAt - scheduledShift.StartsAt).TotalSeconds;
                    await _shiftRepository.InsertScheduledShift(scheduledShift);

                    assignments = new List <ScheduledShiftAssignment>();

                    //populate with work items if necassary
                    await _shiftWorkItemService.AddWorkItemsToNewShiftOccurence(scheduledShift);
                }
            }

            if (group != null)
            {
                foreach (var groupMember in groupMembers)
                {
                    var existing = assignments.FirstOrDefault(x => x.OriginalAssignedUserId == groupMember.Id || x.AssignedUserId == groupMember.Id || x.ClaimedByUserId == groupMember.Id);
                    if (existing == null)
                    {
                        var ssa = new ScheduledShiftAssignment()
                        {
                            Status                 = ShiftStatus.Assigned,
                            AssignedUserId         = groupMember.Id,
                            OriginalAssignedUserId = groupMember.Id,
                            ScheduledShiftId       = scheduledShift.Id
                        };
                        assignments.Add(ssa);
                        await _shiftRepository.InsertScheduledShiftAssignment(ssa);

                        newAssignments.Add(ssa);
                    }
                    else if (existing.Status == ShiftStatus.Claimed && existing.ClaimedByUserId == groupMember.Id)
                    {
                        existing.AssignedUserId = existing.ClaimedByUserId.Value;
                        existing.Status         = ShiftStatus.Assigned;
                        await _shiftRepository.UpdateScheduledShiftAssignment(existing);
                    }
                }
            }

            if (dto.AssignUserIds != null)
            {
                foreach (var id in dto.AssignUserIds)
                {
                    var existing = assignments.FirstOrDefault(x => x.OriginalAssignedUserId == id || x.AssignedUserId == id || x.ClaimedByUserId == id);
                    if (existing == null || !id.HasValue)
                    {
                        var ssa = new ScheduledShiftAssignment()
                        {
                            Status                 = id.HasValue ? ShiftStatus.Assigned : ShiftStatus.Released,
                            AssignedUserId         = id,
                            OriginalAssignedUserId = id,
                            ScheduledShiftId       = scheduledShift.Id
                        };
                        assignments.Add(ssa);
                        await _shiftRepository.InsertScheduledShiftAssignment(ssa);

                        newAssignments.Add(ssa);
                    }
                    else if (existing.Status == ShiftStatus.Claimed && existing.ClaimedByUserId == id)
                    {
                        existing.AssignedUserId = existing.ClaimedByUserId.Value;
                        existing.Status         = ShiftStatus.Assigned;
                        await _shiftRepository.UpdateScheduledShiftAssignment(existing);
                    }
                }
            }

            var assigneeUserIds = newAssignments.Where(x => x.AssignedUserId.HasValue).Select(x => x.AssignedUserId.Value).Distinct().ToList();

            if (assigneeUserIds.Count > 0)
            {
                var newAssignees = await _userRepository.GetUsers(assigneeUserIds);

                await _emailService.SendShiftAdded(newAssignees.ToList(), patrol, scheduledShift);
            }

            //todo: delete things that aren't there?  seems risky if we found the shift by time not id etc

            return(await _shiftRepository.GetScheduledShift(scheduledShift.Id));
        }
Exemplo n.º 12
0
 public Task DeleteScheduledShift(ScheduledShift shift)
 {
     return(_connection.DeleteAsync(shift));
 }
Exemplo n.º 13
0
        public async Task InsertScheduledShift(ScheduledShift shift)
        {
            var id = (int)await _connection.InsertAsync(shift);

            shift.Id = id;
        }
Exemplo n.º 14
0
 public Task UpdateScheduledShift(ScheduledShift shift)
 {
     return(_connection.UpdateAsync(shift));
 }
Exemplo n.º 15
0
        public async Task SendTraineeCancel(User trainerUser, User traineeUser, Models.Patrol patrol, ScheduledShift shift)
        {
            var localStart = shift.StartsAt.UtcToPatrolLocal(patrol);
            var localEnd   = shift.EndsAt.UtcToPatrolLocal(patrol);

            var msg = new SendGridMessage()
            {
                Subject          = $"{traineeUser.GetFullName()} Cancelled for {localStart.ToShortDateString()}",
                PlainTextContent = $"{traineeUser.GetFullName()} has cancelled their request to train with you during your shift on {localStart.ToShortDateString()} {localStart.ToShortTimeString()} - {localEnd.ToShortTimeString()}",
                HtmlContent      = $"{traineeUser.GetFullName()} has cancelled their request to train with you during your shift on {localStart.ToShortDateString()} {localStart.ToShortTimeString()} - {localEnd.ToShortTimeString()}",
            };

            this.AddOnBehalfOf(msg, patrol);

            var response = await Send(msg, patrol, trainerUser);
        }
Exemplo n.º 16
0
        public async Task SendShiftRejected(User assigned, Models.Patrol patrol, User claimed, User rejected, ScheduledShift shift)
        {
            var localStart = shift.StartsAt.UtcToPatrolLocal(patrol);
            var localEnd   = shift.EndsAt.UtcToPatrolLocal(patrol);

            if (assigned == null)
            {
                var msg = new SendGridMessage()
                {
                    Subject          = $"Shift claim on {localStart.ToShortDateString()} to {claimed.GetFullName()} Rejected",
                    PlainTextContent = $"Your shift claim on {localStart.ToShortDateString()} to {claimed.GetFullName()} has been rejected",
                    HtmlContent      = $"Your shift Claim on {localStart.ToShortDateString()} to {claimed.GetFullName()} has been rejected",
                };

                this.AddOnBehalfOf(msg, patrol);

                var response = await Send(msg, patrol, claimed);
            }
            else
            {
                var msg = new SendGridMessage()
                {
                    Subject          = $"Shift swap on {localStart.ToShortDateString()} from {assigned.GetFullName()} to {claimed.GetFullName()} Rejected",
                    PlainTextContent = $"The shift swap on {localStart.ToShortDateString()} from {assigned.GetFullName()} to {claimed.GetFullName()} has been rejected",
                    HtmlContent      = $"The shift swap on {localStart.ToShortDateString()} from {assigned.GetFullName()} to {claimed.GetFullName()} has been rejected",
                };

                this.AddOnBehalfOf(msg, patrol);

                var response = await Send(msg, patrol, assigned, claimed);
            }
        }
Exemplo n.º 17
0
        //scheduling
        public async Task SendShiftClaimed(User assigned, Models.Patrol patrol, User claimed, ScheduledShift shift)
        {
            var localStart = shift.StartsAt.UtcToPatrolLocal(patrol);
            var localEnd   = shift.EndsAt.UtcToPatrolLocal(patrol);

            var msg = new SendGridMessage()
            {
                Subject          = $"Shift on {localStart.ToShortDateString()} Claimed by {claimed.GetFullName()}",
                PlainTextContent = $"The shift you released on {localStart.ToShortDateString()} has been claimed by {claimed.GetFullName()}.\nIt is now pending approval.",
                HtmlContent      = $"The shift you released on {localStart.ToShortDateString()} has been claimed by {claimed.GetFullName()}.<br/>It is now pending approval.",
            };

            this.AddOnBehalfOf(msg, patrol);

            var response = await Send(msg, patrol, assigned);
        }