View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.appointment.service;
35  
36  import java.time.DayOfWeek;
37  import java.time.LocalDate;
38  import java.time.LocalDateTime;
39  import java.time.LocalTime;
40  import java.time.temporal.ChronoUnit;
41  import java.util.ArrayList;
42  import java.util.Collections;
43  import java.util.List;
44  import java.util.stream.Collectors;
45  
46  import org.apache.commons.collections.CollectionUtils;
47  
48  import fr.paris.lutece.plugins.appointment.business.planning.TimeSlot;
49  import fr.paris.lutece.plugins.appointment.business.planning.TimeSlotHome;
50  import fr.paris.lutece.plugins.appointment.business.planning.WeekDefinition;
51  import fr.paris.lutece.plugins.appointment.business.planning.WeekDefinitionHome;
52  import fr.paris.lutece.plugins.appointment.business.planning.WorkingDay;
53  import fr.paris.lutece.plugins.appointment.business.rule.ReservationRule;
54  import fr.paris.lutece.plugins.appointment.business.rule.ReservationRuleHome;
55  import fr.paris.lutece.plugins.appointment.service.listeners.WeekDefinitionManagerListener;
56  
57  /**
58   * Service class for the time slot
59   * 
60   * @author Laurent Payen
61   *
62   */
63  public final class TimeSlotService
64  {
65  
66      /**
67       * Private constructor - this class does not need to be instantiated
68       */
69      private TimeSlotService( )
70      {
71      }
72  
73      /**
74       * Build a list of timeSlot Object from a starting time to an endingTime
75       * 
76       * @param nIdWorkingDay
77       *            the workingDay Id
78       * @param startingTime
79       *            the starting time
80       * @param endingTime
81       *            the ending time
82       * @param nDuration
83       *            the duration of the slot
84       * @param nMaxCapacity
85       *            the maximum capacity of the slot
86       * @return the list of TimeSlot built
87       */
88      public static List<TimeSlot> generateListTimeSlot( int nIdWorkingDay, LocalTime startingTime, LocalTime endingTime, int nDuration, int nMaxCapacity,
89              boolean forceTimeSlotCreationWithMinTime )
90      {
91          List<TimeSlot> listTimeSlot = new ArrayList<>( );
92          LocalDateTime tempStartingDateTime = LocalDate.now( ).atTime( startingTime );
93          LocalDateTime tempEndingDateTime = LocalDate.now( ).atTime( startingTime.plusMinutes( nDuration ) );
94          LocalDateTime endingDateTime = LocalDate.now( ).atTime( endingTime );
95          while ( !tempEndingDateTime.isAfter( endingDateTime ) )
96          {
97              listTimeSlot.add( generateTimeSlot( nIdWorkingDay, tempStartingDateTime.toLocalTime( ), tempEndingDateTime.toLocalTime( ),
98                      Boolean.TRUE.booleanValue( ), nMaxCapacity ) );
99              tempStartingDateTime = tempEndingDateTime;
100             tempEndingDateTime = tempEndingDateTime.plusMinutes( nDuration );
101         }
102         if ( forceTimeSlotCreationWithMinTime )
103         {
104             tempStartingDateTime = tempEndingDateTime.minusMinutes( nDuration );
105             if ( tempStartingDateTime.isBefore( endingDateTime ) )
106             {
107                 listTimeSlot.add( generateTimeSlot( nIdWorkingDay, tempStartingDateTime.toLocalTime( ), endingTime, Boolean.FALSE, nMaxCapacity ) );
108             }
109         }
110         return listTimeSlot;
111     }
112 
113     /**
114      * Save a time slot
115      * 
116      * @param timeSlot
117      *            the time slot to save
118      * @return the time slot saved
119      */
120     public static TimeSlot../../../../fr/paris/lutece/plugins/appointment/business/planning/TimeSlot.html#TimeSlot">TimeSlot saveTimeSlot( TimeSlot timeSlot )
121     {
122         TimeSlot timeSlotSaved = null;
123         if ( timeSlot.getIdTimeSlot( ) == 0 )
124         {
125             timeSlotSaved = TimeSlotService.createTimeSlot( timeSlot );
126         }
127         else
128         {
129             timeSlotSaved = TimeSlotService.updateTimeSlot( timeSlot );
130         }
131         return timeSlotSaved;
132     }
133 
134     /**
135      * Create a time slot in db
136      * 
137      * @param timeSlot
138      *            the time slot to create
139      * @return the time slot created
140      */
141     public static TimeSlot/../../../fr/paris/lutece/plugins/appointment/business/planning/TimeSlot.html#TimeSlot">TimeSlot createTimeSlot( TimeSlot timeSlot )
142     {
143         return TimeSlotHome.create( timeSlot );
144     }
145 
146     /**
147      * Build a timeSlot with all its values
148      * 
149      * @param nIdWorkingDay
150      *            the workingDay Id
151      * @param startingTime
152      *            the starting time
153      * @param endingTime
154      *            the ending time
155      * @param isOpen
156      *            true if the slot is open
157      * @param nMaxCapacity
158      *            the maximum capacity of the slot
159      * @return the timeSLot built
160      */
161     public static TimeSlot generateTimeSlot( int nIdWorkingDay, LocalTime startingTime, LocalTime endingTime, boolean isOpen, int nMaxCapacity )
162     {
163         TimeSlotpointment/business/planning/TimeSlot.html#TimeSlot">TimeSlot timeSlot = new TimeSlot( );
164         timeSlot.setIdWorkingDay( nIdWorkingDay );
165         timeSlot.setIsOpen( isOpen );
166         timeSlot.setStartingTime( startingTime );
167         timeSlot.setEndingTime( endingTime );
168         timeSlot.setMaxCapacity( nMaxCapacity );
169         return timeSlot;
170     }
171 
172     /**
173      * Find the time slots of a working day
174      * 
175      * @param nIdWorkingDay
176      *            the working day Id
177      * @return the list of the timeSlot of this workingDay
178      */
179     public static List<TimeSlot> findListTimeSlotByWorkingDay( int nIdWorkingDay )
180     {
181         return TimeSlotHome.findByIdWorkingDay( nIdWorkingDay );
182     }
183 
184     /**
185      * Find a timeSlot with its primary key
186      * 
187      * @param nIdTimeSlot
188      *            the timeSlot Id
189      * @return the timeSlot found
190      */
191     public static TimeSlot findTimeSlotById( int nIdTimeSlot )
192     {
193         return TimeSlotHome.findByPrimaryKey( nIdTimeSlot );
194     }
195 
196     /**
197      * Update a timeSLot in database
198      * 
199      * @param timeSlot
200      *            the timeSlot to update
201      * @param bEndingTimeHasChanged
202      *            if the ending time has changed, need to regenerate and update all the next time slots
203      * @param previousEndingTime
204      *            the previous ending time of the current time slot
205      * @param bShifSlot
206      *            true if the user has decided to shift the next slots
207      */
208     public static void updateTimeSlot( TimeSlot timeSlot, boolean bEndingTimeHasChanged, LocalTime previousEndingTime, boolean bShifSlot )
209     {
210         WorkingDay workingDay = WorkingDayService.findWorkingDayById( timeSlot.getIdWorkingDay( ) );
211         ReservationRule reservationRule = ReservationRuleHome.findByPrimaryKey( workingDay.getIdReservationRule( ) );
212         List<WeekDefinition> listWeek = WeekDefinitionHome.findByReservationRule( reservationRule.getIdReservationRule( ) );
213 
214         int nDuration = reservationRule.getDurationAppointments( );
215         if ( bEndingTimeHasChanged )
216         {
217             if ( !bShifSlot )
218             {
219                 updateTimeSlotWithoutShift( timeSlot, workingDay, reservationRule, nDuration );
220             }
221             else
222             {
223                 updateTimeSlotWithShift( timeSlot, workingDay, reservationRule, nDuration, previousEndingTime );
224             }
225 
226         }
227         else
228         {
229             saveTimeSlot( timeSlot );
230         }
231 
232         if ( CollectionUtils.isNotEmpty( listWeek ) )
233         {
234 
235             WeekDefinitionManagerListener.notifyListenersListWeekDefinitionChanged( reservationRule.getIdForm( ), listWeek );
236         }
237     }
238 
239     /**
240      * Update a time slot with shifting the next
241      * 
242      * @param timeSlot
243      *            the time slot modified
244      * @param workingDay
245      *            the working day
246      * @param reservationRule
247      *            the reservation rule
248      * @param nDuration
249      *            the duration of a time slot
250      * @param previousEndingTime
251      *            the previous ending time
252      */
253     private static void updateTimeSlotWithShift( TimeSlot timeSlot, WorkingDay workingDay, ReservationRule reservationRule, int nDuration,
254             LocalTime previousEndingTime )
255     {
256         // We want to shift all the next time slots
257         // Get all the time slots of the day
258         List<TimeSlot> listOfAllTimeSlotsOfThisWorkingDay = findListTimeSlotByWorkingDay( workingDay.getIdWorkingDay( ) );
259         // Remove the current time slot and all the time slots before it
260         listOfAllTimeSlotsOfThisWorkingDay = listOfAllTimeSlotsOfThisWorkingDay.stream( )
261                 .filter( timeSlotToKeep -> timeSlotToKeep.getStartingTime( ).isAfter( timeSlot.getStartingTime( ) ) ).collect( Collectors.toList( ) );
262         // Need to delete all the time slots until the new end of this
263         // time slot
264         List<TimeSlot> listTimeSlotToDelete = listOfAllTimeSlotsOfThisWorkingDay.stream( )
265                 .filter( timeSlotToDelete -> timeSlotToDelete.getStartingTime( ).isAfter( timeSlot.getStartingTime( ) )
266                         && !timeSlotToDelete.getEndingTime( ).isAfter( timeSlot.getEndingTime( ) ) )
267                 .collect( Collectors.toList( ) );
268         deleteListTimeSlot( listTimeSlotToDelete );
269         listOfAllTimeSlotsOfThisWorkingDay.removeAll( listTimeSlotToDelete );
270         // Need to order the list of time slot to shift according to the
271         // shift
272         // if the new ending time is before the previous ending time,
273         // the list has to be ordered in chronological order ascending
274         // and the first time slot to shift is the closest to the
275         // current
276         // time slot
277         // (because we have an integrity constraint for the time slot,
278         // it
279         // can't have the same starting or ending time as another time
280         // slot
281         List<TimeSlot> listTimeSlotToShift = new ArrayList<>( );
282         listTimeSlotToShift.addAll( listOfAllTimeSlotsOfThisWorkingDay );
283         listTimeSlotToShift = listTimeSlotToShift.stream( )
284                 .sorted( ( timeSlot1, timeSlot2 ) -> timeSlot1.getStartingTime( ).compareTo( timeSlot2.getStartingTime( ) ) ).collect( Collectors.toList( ) );
285         boolean bNewEndingTimeIsAfterThePreviousTime = false;
286         // Need to know the ending time of the day
287         LocalTime endingTimeOfTheDay = WorkingDayService.getMaxEndingTimeOfAWorkingDay( workingDay );
288 
289         long timeToAdd = 0;
290         long timeToSubstract = 0;
291         if ( previousEndingTime.isBefore( timeSlot.getEndingTime( ) ) )
292         {
293             bNewEndingTimeIsAfterThePreviousTime = true;
294             // Need to find the next available time slot, to know how to
295             // add to the starting time of the next time slot to match
296             // with
297             // the new end of the current time slot
298             if ( CollectionUtils.isNotEmpty( listTimeSlotToShift ) )
299             {
300                 TimeSlot nextTimeSlot = listTimeSlotToShift.stream( ).min( ( t1, t2 ) -> t1.getStartingTime( ).compareTo( t2.getStartingTime( ) ) )
301                         .orElse( listTimeSlotToShift.get( 0 ) );
302                 if ( timeSlot.getEndingTime( ).isAfter( nextTimeSlot.getStartingTime( ) ) )
303                 {
304                     timeToAdd = nextTimeSlot.getStartingTime( ).until( timeSlot.getEndingTime( ), ChronoUnit.MINUTES );
305                 }
306                 else
307                 {
308                     timeToAdd = timeSlot.getEndingTime( ).until( nextTimeSlot.getStartingTime( ), ChronoUnit.MINUTES );
309                 }
310                 Collections.reverse( listTimeSlotToShift );
311             }
312             else
313             {
314                 timeToAdd = previousEndingTime.until( timeSlot.getEndingTime( ), ChronoUnit.MINUTES );
315             }
316 
317         }
318         else
319         {
320             timeToSubstract = timeSlot.getEndingTime( ).until( previousEndingTime, ChronoUnit.MINUTES );
321         }
322         updateTimeSlot( timeSlot );
323         // Need to set the new starting and ending time of all the time
324         // slots
325         // to shift and update them
326         for ( TimeSlot timeSlotToShift : listTimeSlotToShift )
327         {
328             // If the new ending time is after the previous time
329             if ( bNewEndingTimeIsAfterThePreviousTime )
330             {
331                 // If the starting time + the time to add is before the
332                 // ending time of the day
333                 if ( timeSlotToShift.getStartingTime( ).plus( timeToAdd, ChronoUnit.MINUTES ).isBefore( endingTimeOfTheDay ) )
334                 {
335                     timeSlotToShift.setStartingTime( timeSlotToShift.getStartingTime( ).plus( timeToAdd, ChronoUnit.MINUTES ) );
336                     // if the ending time is after the ending time of
337                     // the day, we set the new ending time to the ending
338                     // time of the day
339                     if ( timeSlotToShift.getEndingTime( ).plus( timeToAdd, ChronoUnit.MINUTES ).isAfter( endingTimeOfTheDay ) )
340                     {
341                         timeSlotToShift.setEndingTime( endingTimeOfTheDay );
342                     }
343                     else
344                     {
345                         timeSlotToShift.setEndingTime( timeSlotToShift.getEndingTime( ).plus( timeToAdd, ChronoUnit.MINUTES ) );
346                     }
347                     updateTimeSlot( timeSlotToShift );
348                 }
349                 else
350                 {
351                     // Delete this slot (the slot can not be after the
352                     // ending time of the day)
353                     deleteTimeSlot( timeSlotToShift );
354                 }
355             }
356             else
357             {
358                 // The new ending time is before the previous ending
359                 // time
360                 timeSlotToShift.setStartingTime( timeSlotToShift.getStartingTime( ).minus( timeToSubstract, ChronoUnit.MINUTES ) );
361                 timeSlotToShift.setEndingTime( timeSlotToShift.getEndingTime( ).minus( timeToSubstract, ChronoUnit.MINUTES ) );
362                 updateTimeSlot( timeSlotToShift );
363             }
364         }
365 
366         if ( !bNewEndingTimeIsAfterThePreviousTime )
367         {
368             // If the slots have been shift earlier,
369             // there is no slot(s) between the last slot created
370             // and the ending time of the day, need to create it(them)
371             List<TimeSlot> listTimeSlotToAdd = generateListTimeSlot( timeSlot.getIdWorkingDay( ), endingTimeOfTheDay.minusMinutes( timeToSubstract ),
372                     endingTimeOfTheDay, nDuration, reservationRule.getMaxCapacityPerSlot( ), Boolean.TRUE );
373             createListTimeSlot( listTimeSlotToAdd );
374         }
375 
376     }
377 
378     /**
379      * Update a time slot without shifting the next time slots
380      * 
381      * @param timeSlot
382      *            the time slot modified
383      * @param workingDay
384      *            the working day
385      * @param reservationRule
386      *            the reservation rule
387      * @param nDuration
388      *            the duration of a time slot
389      */
390     private static void updateTimeSlotWithoutShift( TimeSlot timeSlot, WorkingDay workingDay, ReservationRule reservationRule, int nDuration )
391     {
392         List<TimeSlot> listTimeSlotToCreate = new ArrayList<>( );
393         LocalTime maxEndingTime = WorkingDayService.getMaxEndingTimeOfAWorkingDay( workingDay );
394         // Find all the time slot after the starting time of the new
395         // time
396         // slot
397         List<TimeSlot> listAllTimeSlotsAfterThisTimeSlot = findListTimeSlotAfterThisTimeSlot( timeSlot );
398         // Need to delete all the time slots impacted (the ones with the
399         // starting time before the ending time of the new time slot)
400         List<TimeSlot> listAllTimeSlotsToUpdate = listAllTimeSlotsAfterThisTimeSlot.stream( )
401                 .filter( x -> x.getStartingTime( ).isBefore( timeSlot.getEndingTime( ) ) ).collect( Collectors.toList( ) );
402         for ( TimeSlot tSlot : listAllTimeSlotsToUpdate )
403         {
404             listAllTimeSlotsAfterThisTimeSlot.remove( tSlot );
405             // If the new ending time is after the previous time
406             if ( tSlot.getEndingTime( ).isAfter( timeSlot.getEndingTime( ) ) )
407             {
408                 tSlot.setStartingTime( timeSlot.getEndingTime( ) );
409                 updateTimeSlot( tSlot );
410                 listAllTimeSlotsAfterThisTimeSlot.add( tSlot );
411             }
412             else
413             {
414                 deleteTimeSlot( tSlot );
415             }
416         }
417         // Need to find the next time slot (the one with the closest
418         // starting time of the ending time of the new time slot)
419         TimeSlot nextTimeSlot = null;
420         if ( CollectionUtils.isNotEmpty( listAllTimeSlotsAfterThisTimeSlot ) )
421         {
422             nextTimeSlot = listAllTimeSlotsAfterThisTimeSlot.stream( ).min( ( t1, t2 ) -> t1.getStartingTime( ).compareTo( t2.getStartingTime( ) ) )
423                     .orElse( null );
424         }
425         if ( nextTimeSlot != null )
426         {
427             maxEndingTime = nextTimeSlot.getStartingTime( );
428         }
429         // and to regenerate time slots between this two ones, with the
430         // good
431         // rules
432         // for the slot capacity
433         listTimeSlotToCreate.addAll( generateListTimeSlot( timeSlot.getIdWorkingDay( ), timeSlot.getEndingTime( ), maxEndingTime, nDuration,
434                 reservationRule.getMaxCapacityPerSlot( ), Boolean.TRUE ) );
435         TimeSlotHome.update( timeSlot );
436         createListTimeSlot( listTimeSlotToCreate );
437 
438     }
439 
440     /**
441      * Update a time slot
442      * 
443      * @param timeSlot
444      *            the time slot to update
445      */
446     public static TimeSlot/../../../fr/paris/lutece/plugins/appointment/business/planning/TimeSlot.html#TimeSlot">TimeSlot updateTimeSlot( TimeSlot timeSlot )
447     {
448         return TimeSlotHome.update( timeSlot );
449     }
450 
451     /**
452      * Create in database the slots given
453      * 
454      * @param listSlotToCreate
455      *            the list of slots to create in database
456      */
457     public static void createListTimeSlot( List<TimeSlot> listTimeSlotToCreate )
458     {
459         if ( CollectionUtils.isNotEmpty( listTimeSlotToCreate ) )
460         {
461             for ( TimeSlot timeSlotTemp : listTimeSlotToCreate )
462             {
463                 TimeSlotHome.create( timeSlotTemp );
464             }
465         }
466     }
467 
468     /**
469      * Create in database the slots given
470      * 
471      * @param listSlotToCreate
472      *            the list of slots to create in database
473      */
474     public static void updateListTimeSlot( List<TimeSlot> listTimeSlotToCUpdate )
475     {
476         if ( CollectionUtils.isNotEmpty( listTimeSlotToCUpdate ) )
477         {
478             for ( TimeSlot timeSlotTemp : listTimeSlotToCUpdate )
479             {
480                 TimeSlotHome.update( timeSlotTemp );
481             }
482         }
483     }
484 
485     /**
486      * Find the next time slots of a given time slot
487      * 
488      * @param timeSlot
489      *            the time slot
490      * @return a list of the next time slots
491      */
492     public static List<TimeSlot> findListTimeSlotAfterThisTimeSlot( TimeSlot timeSlot )
493     {
494         return TimeSlotService.findListTimeSlotByWorkingDay( timeSlot.getIdWorkingDay( ) ).stream( )
495                 .filter( x -> x.getStartingTime( ).isAfter( timeSlot.getStartingTime( ) ) ).collect( Collectors.toList( ) );
496     }
497 
498     /**
499      * Delete in database time slots
500      * 
501      * @param listTimeSlot
502      *            the list of time slots to delete
503      */
504     public static void deleteListTimeSlot( List<TimeSlot> listTimeSlot )
505     {
506         for ( TimeSlot timeSlot : listTimeSlot )
507         {
508             deleteTimeSlot( timeSlot );
509         }
510     }
511 
512     /**
513      * Delete in database time slot
514      * 
515      * @param timeSlot
516      *            the time slot to delete
517      */
518     public static void deleteTimeSlot( TimeSlot timeSlot )
519     {
520         TimeSlotHome.delete( timeSlot.getIdTimeSlot( ) );
521     }
522 
523     /**
524      * Get the time slots of a list of working days
525      * 
526      * @param listWorkingDay
527      *            the list of the working days
528      * @param dateInWeek
529      *            the date in the week
530      * @return the list of the time slots
531      */
532     public static List<TimeSlot> getListTimeSlotOfAListOfWorkingDay( List<WorkingDay> listWorkingDay, LocalDate dateInWeek )
533     {
534         List<TimeSlot> listTimeSlot = new ArrayList<>( );
535         for ( WorkingDay workingDay : listWorkingDay )
536         {
537             for ( TimeSlot timeSlot : workingDay.getListTimeSlot( ) )
538             {
539                 // Need to add the current date to the hour
540                 timeSlot.setStartingDateTime( dateInWeek.with( DayOfWeek.of( workingDay.getDayOfWeek( ) ) ).atTime( timeSlot.getStartingTime( ) ) );
541                 timeSlot.setEndingDateTime( dateInWeek.with( DayOfWeek.of( workingDay.getDayOfWeek( ) ) ).atTime( timeSlot.getEndingTime( ) ) );
542                 listTimeSlot.add( timeSlot );
543             }
544         }
545         return listTimeSlot;
546     }
547 
548     /**
549      * Return an ordered and filtered list of time slots after a given time
550      * 
551      * @param listTimeSlot
552      *            the list of time slot to sort and filter
553      * @param time
554      *            the time
555      * @return the list ordered and filtered
556      */
557     public static List<TimeSlot> getNextTimeSlotsInAListOfTimeSlotAfterALocalTime( List<TimeSlot> listTimeSlot, LocalTime time )
558     {
559         return listTimeSlot.stream( ).filter( x -> x.getStartingTime( ).isAfter( time ) || x.getStartingTime( ).equals( time ) )
560                 .collect( Collectors.toList( ) );
561     }
562 
563     /**
564      * Returns the time slot in a list of time slot with the given starting time
565      * 
566      * @param listTimeSlot
567      *            the list of time slots
568      * @param timeToSearch
569      *            the starting time to search
570      * @return the time slot found
571      */
572     public static TimeSlot getTimeSlotInListOfTimeSlotWithStartingTime( List<TimeSlot> listTimeSlot, LocalTime timeToSearch )
573     {
574         return listTimeSlot.stream( ).filter( x -> timeToSearch.equals( x.getStartingTime( ) ) ).findFirst( ).orElse( null );
575     }
576 }