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.LocalDate;
37  import java.time.LocalTime;
38  import java.util.ArrayList;
39  import java.util.HashMap;
40  import java.util.HashSet;
41  import java.util.List;
42  import java.util.Set;
43  import java.util.stream.Collectors;
44  
45  import org.apache.commons.collections.CollectionUtils;
46  
47  import fr.paris.lutece.plugins.appointment.business.planning.WeekDefinition;
48  import fr.paris.lutece.plugins.appointment.business.planning.WeekDefinitionHome;
49  import fr.paris.lutece.plugins.appointment.business.planning.WorkingDay;
50  import fr.paris.lutece.plugins.appointment.business.rule.ReservationRule;
51  import fr.paris.lutece.plugins.appointment.service.listeners.WeekDefinitionManagerListener;
52  import fr.paris.lutece.portal.service.util.AppException;
53  import fr.paris.lutece.portal.service.util.AppLogService;
54  import fr.paris.lutece.util.ReferenceList;
55  import fr.paris.lutece.util.sql.TransactionManager;
56  
57  /**
58   * Service class of a week definition
59   * 
60   * @author Laurent Payen
61   *
62   */
63  public final class WeekDefinitionService
64  {
65  
66      /**
67       * Private constructor - this class does not need to be instantiated
68       */
69      private WeekDefinitionService( )
70      {
71      }
72  
73      /**
74       * Create a week definition in database
75       * 
76       * @param nIdReservationRule
77       *            the nIdReservationRule
78       * @param dateOfApply
79       *            the date of the week definition
80       * @return the week definition created
81       */
82      public static WeekDefinition createWeekDefinition( int nIdReservationRule, LocalDate dateOfApply, LocalDate endingDateOfApply )
83      {
84          WeekDefinitionsiness/planning/WeekDefinition.html#WeekDefinition">WeekDefinition weekDefinition = new WeekDefinition( );
85          fillInWeekDefinition( weekDefinition, nIdReservationRule, dateOfApply, endingDateOfApply );
86          WeekDefinitionHome.create( weekDefinition );
87          // WeekDefinitionManagerListener.notifyListenersWeekDefinitionAssigned( weekDefinition.getIdWeekDefinition( ) );
88          return weekDefinition;
89      }
90  
91      /**
92       * Remove the weekdefinition (and by cascade the working days and the time slots)
93       * 
94       * @param nIdWeekDefinition
95       *            the id of the week definition to delete
96       */
97      public static void removeWeekDefinition( WeekDefinition weekDefinition )
98      {
99          WeekDefinitionHome.delete( weekDefinition.getIdWeekDefinition( ) );
100         WeekDefinitionManagerListener.notifyListenersWeekDefinitionUnassigned( weekDefinition );
101     }
102 
103     /**
104      * Save a week definition
105      * 
106      * @param weekDefinition
107      *            the week definition to save
108      * @return the week definition saved
109      */
110     public static WeekDefinitionfr/paris/lutece/plugins/appointment/business/planning/WeekDefinition.html#WeekDefinition">WeekDefinition saveWeekDefinition( WeekDefinition weekDefinition )
111     {
112         WeekDefinitionHome.create( weekDefinition );
113         WeekDefinitionManagerListener.notifyListenersWeekDefinitionAssigned( weekDefinition );
114         return weekDefinition;
115     }
116 
117     /**
118      * Fill the week definition object with the given parameters
119      * 
120      * @param weekDefinition
121      *            the week definition to fill in
122      * @param nIdForm
123      *            the form id
124      * @param dateOfApply
125      *            the date of the week definition
126      */
127     public static void fillInWeekDefinition( WeekDefinition weekDefinition, int nIdReservationRule, LocalDate dateOfApply, LocalDate endingDateOfApply )
128     {
129         weekDefinition.setDateOfApply( dateOfApply );
130         weekDefinition.setEndingDateOfApply( endingDateOfApply );
131         weekDefinition.setIdReservationRule( nIdReservationRule );
132     }
133 
134     /**
135      * Fin all the week definition of a form
136      * 
137      * @param nIdForm
138      *            the form Id
139      * @return the list of all the week definition of the form
140      */
141     public static List<WeekDefinition> findListWeekDefinition( int nIdForm )
142     {
143         return WeekDefinitionHome.findByIdForm( nIdForm );
144 
145     }
146 
147     /**
148      * Find a week definition of a form by date of apply
149      * 
150      * @param nIdForm
151      *            the id form
152      * @param startingDate
153      *            the starting date
154      * @param endingDate
155      *            the ending date
156      * @return the list of week definition
157      */
158     public static List<WeekDefinition> findWeekDefinitionByDateOfApply( int nIdForm, LocalDate startingDate, LocalDate endingDate )
159     {
160         List<WeekDefinition> listWeekDefinition = WeekDefinitionService.findListWeekDefinition( nIdForm );
161         // Filter on the list of week definition on the starting date and the ending date of display
162         listWeekDefinition = listWeekDefinition.stream( )
163                 .filter( w -> ( w.getEndingDateOfApply( ).isEqual( startingDate ) || w.getEndingDateOfApply( ).isAfter( startingDate ) )
164                         && ( w.getDateOfApply( ).isBefore( endingDate ) || w.getDateOfApply( ).isEqual( endingDate ) ) )
165                 .collect( Collectors.toList( ) );
166 
167         return listWeekDefinition;
168     }
169 
170     /**
171      * Find a week definition of a form and a date of apply
172      * 
173      * @param nIdForm
174      *            the form Id
175      * @param dateOfApply
176      *            the date of apply of the week definition
177      * @return the week definition with the closest date of apply
178      */
179     public static WeekDefinition findWeekDefinitionByIdFormAndClosestToDateOfApply( int nIdForm, LocalDate dateOfApply )
180     {
181         // Get all the week definitions
182         List<WeekDefinition> listWeekDefinition = WeekDefinitionHome.findByIdForm( nIdForm );
183         List<LocalDate> listDate = new ArrayList<>( );
184         for ( WeekDefinition weekDefinition : listWeekDefinition )
185         {
186             listDate.add( weekDefinition.getDateOfApply( ) );
187         }
188         // Try to get the closest date in past of the date of apply
189         LocalDate closestDate = Utilities.getClosestDateInPast( listDate, dateOfApply );
190         WeekDefinition weekDefinition = null;
191         // If there is no closest date in past
192         if ( closestDate == null )
193         {
194             // if the list of week definitions is not null
195             if ( CollectionUtils.isNotEmpty( listWeekDefinition ) )
196             {
197                 // Get the next week definition in the future
198                 weekDefinition = listWeekDefinition.stream( ).min( ( w1, w2 ) -> w1.getDateOfApply( ).compareTo( w2.getDateOfApply( ) ) ).orElse( null );
199             }
200         }
201         else
202         {
203             // There is a closest date in past
204             if ( CollectionUtils.isNotEmpty( listWeekDefinition ) )
205             {
206                 // Get the corresponding week definition
207                 weekDefinition = listWeekDefinition.stream( ).filter( x -> closestDate.isEqual( x.getDateOfApply( ) ) ).findAny( ).orElse( null );
208             }
209         }
210 
211         return weekDefinition;
212     }
213 
214     /**
215      * Find the weekdefinition of a form on a specific date
216      * 
217      * @param nIdForm
218      *            the form Id
219      * @param dateOfApply
220      *            the date of the weekdefinition
221      * @return the weekdefinition object
222      */
223     public static WeekDefinition findWeekDefinitionByIdFormAndDateOfApply( int nIdForm, LocalDate dateOfApply )
224     {
225         return WeekDefinitionHome.findByIdFormAndDateOfApply( nIdForm, dateOfApply );
226     }
227 
228     /**
229      * Return, if it exists, the next week definition after a given date
230      * 
231      * @param nIdForm
232      *            the form id
233      * @param previousDateOfApply
234      *            the previous date of the previous week definition
235      * @return the next week definition if it exists, null otherwise
236      */
237     public static WeekDefinition findNextWeekDefinition( int nIdForm, LocalDate previousDateOfApply )
238     {
239         WeekDefinitionss/planning/WeekDefinition.html#WeekDefinition">WeekDefinition nextWeekDefinition = new WeekDefinition( );
240         List<WeekDefinition> listWeekDefinition = WeekDefinitionHome.findByIdForm( nIdForm );
241         if ( CollectionUtils.isNotEmpty( listWeekDefinition ) )
242         {
243             listWeekDefinition = listWeekDefinition.stream( ).filter( x -> x.getDateOfApply( ).isAfter( previousDateOfApply ) ).collect( Collectors.toList( ) );
244             if ( CollectionUtils.isNotEmpty( listWeekDefinition ) )
245             {
246                 nextWeekDefinition = listWeekDefinition.stream( ).min( ( w1, w2 ) -> w1.getDateOfApply( ).compareTo( w2.getDateOfApply( ) ) ).orElse( null );
247             }
248         }
249         return nextWeekDefinition;
250     }
251 
252     /**
253      * Find a week definition with its primary key
254      * 
255      * @param nIdWeekDefinition
256      *            the week definition id
257      * @return the week definition found
258      */
259     public static WeekDefinition findWeekDefinitionLightById( int nIdWeekDefinition )
260     {
261         return WeekDefinitionHome.findByPrimaryKey( nIdWeekDefinition );
262     }
263 
264     /**
265      * Find a week definition by its primary key and set its working days
266      * 
267      * @param nIdWeekDefinition
268      *            the week definition id
269      * @return the week definition and its working days
270      */
271     public static WeekDefinition findWeekDefinitionById( int nIdWeekDefinition )
272     {
273         return WeekDefinitionHome.findByPrimaryKey( nIdWeekDefinition );
274     }
275 
276     /**
277      * Build a reference list of all the week definitions of a form
278      * 
279      * @param nIdForm
280      *            the form Id
281      * @return a reference list of all the week definitions of a form (Id of the week definition / date of apply of the week definition
282      */
283     public static ReferenceList findAllDateOfWeekDefinition( int nIdForm )
284     {
285         ReferenceList listDate = new ReferenceList( );
286         List<WeekDefinition> listWeekDefinition = WeekDefinitionHome.findByIdForm( nIdForm );
287         for ( WeekDefinition weekDefinition : listWeekDefinition )
288         {
289             listDate.addItem( weekDefinition.getIdWeekDefinition( ), weekDefinition.getDateOfApply( ).format( Utilities.getFormatter( ) ) );
290         }
291         return listDate;
292     }
293 
294     /**
295      * Find all the week definition of a form
296      * 
297      * @param nIdForm
298      *            the form id
299      * @return a HashMap with the date of apply in key and the week definition in value
300      */
301     public static HashMap<LocalDate, WeekDefinition> findAllWeekDefinition( int nIdForm )
302     {
303         HashMap<LocalDate, WeekDefinition> mapWeekDefinition = new HashMap<>( );
304         List<WeekDefinition> listWeekDefinition = WeekDefinitionHome.findByIdForm( nIdForm );
305         for ( WeekDefinition weekDefinition : listWeekDefinition )
306         {
307             mapWeekDefinition.put( weekDefinition.getDateOfApply( ), weekDefinition );
308         }
309         return mapWeekDefinition;
310     }
311 
312     /**
313      * Return the min starting time of a list of week definitions
314      * 
315      * @param listWeekDefinition
316      *            the list of week definitions
317      * @return the mini starting time
318      */
319     public static LocalTime getMinStartingTimeOfAListOfWeekDefinition( List<ReservationRule> listReservationRules )
320     {
321         LocalTime minStartingTime = null;
322         LocalTime startingTimeTemp;
323         for ( ReservationRule reservation : listReservationRules )
324         {
325             startingTimeTemp = getMinStartingTimeOfAWeekDefinition( reservation );
326             if ( minStartingTime == null || startingTimeTemp.isBefore( minStartingTime ) )
327             {
328                 minStartingTime = startingTimeTemp;
329             }
330         }
331         return minStartingTime;
332     }
333 
334     /**
335      * Return the min starting time of a week definition
336      * 
337      * @param weekDefinition
338      *            the week definition
339      * @return the min starting time of the week definition
340      */
341     public static LocalTime getMinStartingTimeOfAWeekDefinition( ReservationRule reservationRule )
342     {
343         return WorkingDayService.getMinStartingTimeOfAListOfWorkingDay( reservationRule.getListWorkingDay( ) );
344     }
345 
346     /**
347      * Return the max ending time of a list of week definitions
348      * 
349      * @param listWeekDefinition
350      *            the list of week definitions
351      * @return the max ending time of the list of week definitions
352      */
353     public static LocalTime getMaxEndingTimeOfAListOfWeekDefinition( List<ReservationRule> listReservationRules )
354     {
355         LocalTime maxEndingTime = null;
356         LocalTime endingTimeTemp;
357         for ( ReservationRule reservationRule : listReservationRules )
358         {
359             endingTimeTemp = getMaxEndingTimeOfAWeekDefinition( reservationRule );
360             if ( maxEndingTime == null || endingTimeTemp.isAfter( maxEndingTime ) )
361             {
362                 maxEndingTime = endingTimeTemp;
363             }
364         }
365         return maxEndingTime;
366     }
367 
368     /**
369      * Get the max ending time of a week definition
370      * 
371      * @param weekDefinition
372      *            the week definition
373      * @return the max ending time of the week definition
374      */
375     public static LocalTime getMaxEndingTimeOfAWeekDefinition( ReservationRule reservationRule )
376     {
377         return WorkingDayService.getMaxEndingTimeOfAListOfWorkingDay( reservationRule.getListWorkingDay( ) );
378     }
379 
380     /**
381      * Get the min duration of a time slot of a list of week definition
382      * 
383      * @param listWeekDefinition
384      *            the list of the week definitions
385      * @return the min duration time slot
386      */
387     public static int getMinDurationTimeSlotOfAListOfWeekDefinition( List<ReservationRule> listReservationRules )
388     {
389         int nMinDuration = 0;
390         int nDurationTemp;
391         for ( ReservationRule reservationRule : listReservationRules )
392         {
393             nDurationTemp = getMinDurationTimeSlotOfAWeekDefinition( reservationRule );
394             if ( nMinDuration == 0 || nMinDuration > nDurationTemp )
395             {
396                 nMinDuration = nDurationTemp;
397             }
398         }
399         return nMinDuration;
400     }
401 
402     /**
403      * Get the min duration of a time slot of a week definition
404      * 
405      * @param weekDefinition
406      *            the week definition
407      * @return the min duration time slot
408      */
409     public static int getMinDurationTimeSlotOfAWeekDefinition( ReservationRule reservationRule )
410     {
411         return WorkingDayService.getMinDurationTimeSlotOfAListOfWorkingDay( reservationRule.getListWorkingDay( ) );
412     }
413 
414     /**
415      * Get the working days integer enum values of a list of week definitions
416      * 
417      * @param listWeekDefinition
418      *            the list of week definitions
419      * @return a set of the working days (integer value in a week : 1-> Monday ...) // The fullCalendar library is zero-base (Sunday=0)
420      */
421     public static Set<String> getSetDaysOfWeekOfAListOfWeekDefinitionForFullCalendar( List<ReservationRule> listReservationRules )
422     {
423         Set<String> setDayOfWeek = new HashSet<>( );
424         for ( ReservationRule reservationRule : listReservationRules )
425         {
426             setDayOfWeek.addAll( WorkingDayService.getSetDaysOfWeekOfAListOfWorkingDayForFullCalendar( reservationRule.getListWorkingDay( ) ) );
427         }
428         return setDayOfWeek;
429     }
430 
431     /**
432      * Get the set of the open days of all the week definitons
433      * 
434      * @param listWeekDefinition
435      *            the list of week definitions
436      * @return the set of the open days
437      */
438     public static Set<Integer> getOpenDaysOfWeek( List<ReservationRule> listReservationRules )
439     {
440         HashSet<Integer> setOpenDays = new HashSet<>( );
441         for ( ReservationRule reservation : listReservationRules )
442         {
443             for ( WorkingDay workingDay : reservation.getListWorkingDay( ) )
444             {
445                 setOpenDays.add( workingDay.getDayOfWeek( ) );
446             }
447         }
448         return setOpenDays;
449     }
450 
451     /**
452      * Get the week definitions of a form for reservation rule
453      * 
454      * @param nIdReservationRule
455      * @return list of week definition
456      */
457     public static List<WeekDefinition> findByReservationRule( int nIdReservationRule )
458     {
459         return WeekDefinitionHome.findByReservationRule( nIdReservationRule );
460     }
461 
462     /**
463      * Assign a week to the calendar
464      * 
465      * @param nIdForm
466      *            the id from
467      * @param newWeek
468      *            the week to assign
469      */
470     public static void assignWeekDefinition( int nIdForm, WeekDefinition newWeek )
471     {
472 
473         LocalDate startingDate = newWeek.getDateOfApply( );
474         LocalDate endingDate = newWeek.getEndingDateOfApply( );
475         List<WeekDefinition> listWeek = WeekDefinitionService.findListWeekDefinition( nIdForm );
476 
477         List<WeekDefinition> listWeekToRemove = listWeek.stream( )
478                 .filter( week -> ( week.getDateOfApply( ).isAfter( startingDate ) || week.getDateOfApply( ).isEqual( startingDate ) )
479                         && ( week.getEndingDateOfApply( ).isBefore( endingDate ) || week.getEndingDateOfApply( ).isEqual( endingDate ) ) )
480                 .collect( Collectors.toList( ) );
481 
482         listWeek.removeAll( listWeekToRemove );
483         listWeek = listWeek.stream( )
484                 .filter( p -> ( ( p.getDateOfApply( ).isBefore( startingDate ) || p.getDateOfApply( ).isEqual( startingDate ) )
485                         && p.getEndingDateOfApply( ).isAfter( startingDate ) || p.getEndingDateOfApply( ).isEqual( startingDate ) )
486                         || ( p.getDateOfApply( ).isBefore( endingDate ) || p.getDateOfApply( ).isEqual( endingDate ) )
487                                 && p.getEndingDateOfApply( ).isAfter( endingDate )
488                         || p.getEndingDateOfApply( ).isEqual( endingDate ) )
489                 .collect( Collectors.toList( ) );
490         List<WeekDefinition> buildListWeekToEdit = new ArrayList<>( );
491 
492         for ( WeekDefinition week : listWeek )
493         {
494 
495             if ( week.getDateOfApply( ).isBefore( startingDate ) && week.getEndingDateOfApply( ).isAfter( endingDate ) )
496             {
497 
498                 WeekDefinitionnt/business/planning/WeekDefinition.html#WeekDefinition">WeekDefinition weekToAdd = new WeekDefinition( );
499                 weekToAdd.setDateOfApply( endingDate.plusDays( 1 ) );
500                 weekToAdd.setEndingDateOfApply( week.getEndingDateOfApply( ) );
501                 weekToAdd.setIdReservationRule( week.getIdReservationRule( ) );
502                 buildListWeekToEdit.add( weekToAdd );
503                 week.setEndingDateOfApply( startingDate.minusDays( 1 ) );
504 
505             }
506             else
507                 if ( week.getDateOfApply( ).isEqual( startingDate )
508                         || ( week.getDateOfApply( ).isAfter( startingDate ) && week.getEndingDateOfApply( ).isAfter( endingDate ) ) )
509                 {
510 
511                     week.setDateOfApply( endingDate.plusDays( 1 ) );
512 
513                 }
514                 else
515                     if ( week.getEndingDateOfApply( ).isEqual( endingDate )
516                             || ( week.getDateOfApply( ).isBefore( startingDate ) && week.getEndingDateOfApply( ).isBefore( endingDate ) ) )
517                     {
518 
519                         week.setEndingDateOfApply( startingDate.minusDays( 1 ) );
520 
521                     }
522 
523             buildListWeekToEdit.add( week );
524 
525         }
526         if ( newWeek.getIdReservationRule( ) != 0 )
527         {
528 
529             buildListWeekToEdit.add( newWeek );
530         }
531 
532         assignWeekDefintion( listWeekToRemove, buildListWeekToEdit, nIdForm );
533         WeekDefinitionManagerListener.notifyListenersWeekDefinitionAssigned( newWeek );
534     }
535 
536     private static void assignWeekDefintion( List<WeekDefinition> listWeekTodRemove, List<WeekDefinition> listWeekToEdit, int nIdForm )
537     {
538         TransactionManager.beginTransaction( AppointmentPlugin.getPlugin( ) );
539         try
540         {
541             for ( WeekDefinition week : listWeekTodRemove )
542             {
543                 WeekDefinitionHome.delete( week.getIdWeekDefinition( ) );
544             }
545             for ( WeekDefinition week : listWeekToEdit )
546             {
547 
548                 if ( week.getIdWeekDefinition( ) != 0 )
549                 {
550 
551                     WeekDefinitionHome.delete( week.getIdWeekDefinition( ) );
552                 }
553 
554                 WeekDefinitionHome.create( week );
555             }
556             TransactionManager.commitTransaction( AppointmentPlugin.getPlugin( ) );
557             // WeekDefinitionManagerListener.notifyListenersListWeekDefinitionChanged( nIdForm, listWeekToEdit );
558         }
559         catch( Exception e )
560         {
561             TransactionManager.rollBack( AppointmentPlugin.getPlugin( ) );
562             AppLogService.error( "Error assign week " + e.getMessage( ), e );
563             throw new AppException( e.getMessage( ), e );
564 
565         }
566     }
567 
568 }