1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
59
60
61
62
63 public final class TimeSlotService
64 {
65
66
67
68
69 private TimeSlotService( )
70 {
71 }
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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
115
116
117
118
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
136
137
138
139
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
148
149
150
151
152
153
154
155
156
157
158
159
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
174
175
176
177
178
179 public static List<TimeSlot> findListTimeSlotByWorkingDay( int nIdWorkingDay )
180 {
181 return TimeSlotHome.findByIdWorkingDay( nIdWorkingDay );
182 }
183
184
185
186
187
188
189
190
191 public static TimeSlot findTimeSlotById( int nIdTimeSlot )
192 {
193 return TimeSlotHome.findByPrimaryKey( nIdTimeSlot );
194 }
195
196
197
198
199
200
201
202
203
204
205
206
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
241
242
243
244
245
246
247
248
249
250
251
252
253 private static void updateTimeSlotWithShift( TimeSlot timeSlot, WorkingDay workingDay, ReservationRule reservationRule, int nDuration,
254 LocalTime previousEndingTime )
255 {
256
257
258 List<TimeSlot> listOfAllTimeSlotsOfThisWorkingDay = findListTimeSlotByWorkingDay( workingDay.getIdWorkingDay( ) );
259
260 listOfAllTimeSlotsOfThisWorkingDay = listOfAllTimeSlotsOfThisWorkingDay.stream( )
261 .filter( timeSlotToKeep -> timeSlotToKeep.getStartingTime( ).isAfter( timeSlot.getStartingTime( ) ) ).collect( Collectors.toList( ) );
262
263
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
271
272
273
274
275
276
277
278
279
280
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
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
295
296
297
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
324
325
326 for ( TimeSlot timeSlotToShift : listTimeSlotToShift )
327 {
328
329 if ( bNewEndingTimeIsAfterThePreviousTime )
330 {
331
332
333 if ( timeSlotToShift.getStartingTime( ).plus( timeToAdd, ChronoUnit.MINUTES ).isBefore( endingTimeOfTheDay ) )
334 {
335 timeSlotToShift.setStartingTime( timeSlotToShift.getStartingTime( ).plus( timeToAdd, ChronoUnit.MINUTES ) );
336
337
338
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
352
353 deleteTimeSlot( timeSlotToShift );
354 }
355 }
356 else
357 {
358
359
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
369
370
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
380
381
382
383
384
385
386
387
388
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
395
396
397 List<TimeSlot> listAllTimeSlotsAfterThisTimeSlot = findListTimeSlotAfterThisTimeSlot( timeSlot );
398
399
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
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
418
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
430
431
432
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
442
443
444
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
453
454
455
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
470
471
472
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
487
488
489
490
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
500
501
502
503
504 public static void deleteListTimeSlot( List<TimeSlot> listTimeSlot )
505 {
506 for ( TimeSlot timeSlot : listTimeSlot )
507 {
508 deleteTimeSlot( timeSlot );
509 }
510 }
511
512
513
514
515
516
517
518 public static void deleteTimeSlot( TimeSlot timeSlot )
519 {
520 TimeSlotHome.delete( timeSlot.getIdTimeSlot( ) );
521 }
522
523
524
525
526
527
528
529
530
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
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
550
551
552
553
554
555
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
565
566
567
568
569
570
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 }