Exemplo n.º 1
0
        ///<summary>Adds valid time slots to listAvailableTimeSlots if the time slot found does NOT already exist within the list.
        ///This is a helper method to better break up the complexity of GetAvailableWebSchedTimeSlots() so that it is easier to follow.
        ///Make sure that timePattern is always passed in utilizing 5 minute increments (no conversion will be applied to the pattern passed in).
        ///Optionally set defNumApptType if looking for time slots for New Pat Appt which will apply the DefNum to all time slots found.</summary>
        private static void AddTimeSlotsFromSchedule(List <TimeSlot> listAvailableTimeSlots, Schedule schedule, long operatoryNum
                                                     , TimeSpan timeSchedStart, TimeSpan timeSchedStop, List <Schedule> listBlockouts
                                                     , Dictionary <DateTime, List <ApptSearchProviderSchedule> > dictProvSchedules, List <Appointment> listApptsForOps, string timePattern
                                                     , long defNumApptType = 0)
        {
            //No need to check RemotingRole; no call to db and this is a private method.
            //Figure out how large of a time slot we need to find in order to consider this time slot "available".
            int      apptLengthMins = timePattern.Length * 5;
            int      timeIncrement  = PrefC.GetInt(PrefName.AppointmentTimeIncrement);
            DateTime dateSched      = schedule.SchedDate;
            //Start going through this operatories schedule according to the time increment, looking for a gap that can handle apptLengthMins.
            TimeSpan timeSlotStart = new TimeSpan(timeSchedStart.Ticks);

            //Start looking for collisions AFTER the start time.
            //Stop as soon as the slots stop time meets or passes the sched stop time.
            //Iterate through the schedule via the time increment preference.
            for (TimeSpan timeSlotStop = timeSchedStart.Add(new TimeSpan(0, timeIncrement, 0))
                 ; timeSlotStop <= timeSchedStop
                 ; timeSlotStop = timeSlotStop.Add(new TimeSpan(0, timeIncrement, 0)))
            {
                //Check to see if we've found an opening.
                TimeSpan timeSpanCur = timeSlotStop - timeSlotStart;
                //Check to see if there is an appointment or a blockout that collides with this blockout.
                bool isOverlapping = false;
                //First we'll look at blockouts because it should be quicker than looking at the appointments
                foreach (Schedule blockout in listBlockouts)
                {
                    if (dateSched.Date != blockout.SchedDate)
                    {
                        continue;                        //Blockout is not on the same day that we are looking at.
                    }
                    if (!blockout.Ops.Exists(x => x == operatoryNum))
                    {
                        continue;                        //Blockout is not present in this operatory.
                    }
                    //Same operatory and day, check if the times overlap.
                    //Create new TimeSpans in order to remove the date portion from the blockouts.
                    TimeSpan timeBlockoutStart = new TimeSpan(blockout.StartTime.Hours, blockout.StartTime.Minutes, 0);
                    TimeSpan timeBlockoutStop  = new TimeSpan(blockout.StopTime.Hours, blockout.StopTime.Minutes, 0);
                    if (IsTimeOverlapping(timeSlotStart, timeSlotStop, timeBlockoutStart, timeBlockoutStop))
                    {
                        isOverlapping = true;
                        break;
                    }
                }
                if (isOverlapping)                 //This check is here so that we don't waste time looping through appointments if we don't need to.
                //There was a collision, set the time slot start time to the stop time and continue from there.
                {
                    timeSlotStart = timeSlotStop;
                    continue;
                }
                //Next we'll look for overlapping appointments
                foreach (Appointment appointment in listApptsForOps)
                {
                    if (appointment.Op != operatoryNum)
                    {
                        continue;
                    }
                    if (dateSched.Date != appointment.AptDateTime.Date)
                    {
                        continue;                        //Appt is not on the same day that we are looking at.
                    }
                    //Same operatory and day, check if the times overlap.
                    TimeSpan timeApptStart = appointment.AptDateTime.TimeOfDay;
                    TimeSpan timeApptStop  = appointment.AptDateTime.AddMinutes(appointment.Pattern.Length * 5).TimeOfDay;
                    if (IsTimeOverlapping(timeSlotStart, timeSlotStop, timeApptStart, timeApptStop))
                    {
                        isOverlapping = true;
                        break;
                    }
                }
                if (isOverlapping)
                {
                    //There was a collision, set the time slot start time to the stop time and continue from there.
                    timeSlotStart = timeSlotStop;
                    continue;
                }
                if (timeSpanCur.TotalMinutes >= apptLengthMins)
                {
                    //We just found an opening.  Make sure we don't already have this time slot available.
                    DateTime dateTimeSlotStart = new DateTime(dateSched.Year, dateSched.Month, dateSched.Day, timeSlotStart.Hours, timeSlotStart.Minutes, 0);
                    DateTime dateTimeSlotStop  = new DateTime(dateSched.Year, dateSched.Month, dateSched.Day, timeSlotStop.Hours, timeSlotStop.Minutes, 0);
                    TimeSlot timeSlot          = new TimeSlot(dateTimeSlotStart, dateTimeSlotStop, operatoryNum, schedule.ProvNum, defNumApptType);
                    if (!listAvailableTimeSlots.Any(x => (x.DateTimeStart == dateTimeSlotStart && x.DateTimeStop == dateTimeSlotStop &&
                                                          x.ProvNum == schedule.ProvNum))) //We will return multiple time slots for the same time for different providers.
                    {
                        //This time slot is not already in our list of available time slots, check for double booking.
                        if (dictProvSchedules.ContainsKey(dateSched.Date))
                        {
                            long recallProvNum = schedule.ProvNum;
                            if (IsApptPatternDoubleBooked(dictProvSchedules[dateSched.Date], recallProvNum, timePattern, dateTimeSlotStart))
                            {
                                //There is a double booking conflict.  Do not add this time slot as a possibility.
                                //However, at this point we know that there are no appointment conflicts for the current time slot, only a double booking conflict.
                                //The appointment needs to scoot within the operatory to hopefully find the first available opening (unit test 86).
                                timeSlotStart = timeSlotStart.Add(new TimeSpan(0, timeIncrement, 0));
                                continue;
                            }
                        }
                        //There are no collisions with this provider's schedule, add it to our list of available time slots.
                        listAvailableTimeSlots.Add(timeSlot);
                    }
                    else
                    {
                        //We have found a time slot in another operatory that matches the necessary criteria.
                        //Check to see if this operatory should be considered before the previously found operatory.
                        TimeSlot  timeSlotCur  = listAvailableTimeSlots.First(x => (x.DateTimeStart == dateTimeSlotStart && x.DateTimeStop == dateTimeSlotStop));
                        Operatory operatoryIn  = Operatories.GetOperatory(operatoryNum);
                        Operatory operatoryCur = Operatories.GetOperatory(timeSlotCur.OperatoryNum);
                        if (operatoryIn.ItemOrder < operatoryCur.ItemOrder)
                        {
                            timeSlotCur.OperatoryNum = operatoryIn.OperatoryNum;
                        }
                    }
                    //Continue looking for more open slots starting at the end of this time slot.
                    //E.g. we just found 9:30 AM to 10:00 AM.  We need to continue from 10:00 AM.
                    timeSlotStart = timeSlotStop;
                    continue;
                }
            }
        }