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.web;
35  
36  import java.time.LocalDate;
37  import java.time.LocalTime;
38  import java.time.ZoneId;
39  import java.util.ArrayList;
40  import java.util.List;
41  import java.util.Map;
42  import java.util.concurrent.locks.Lock;
43  import java.util.stream.Collectors;
44  
45  import javax.servlet.http.HttpServletRequest;
46  
47  import org.apache.commons.collections.CollectionUtils;
48  import org.apache.commons.lang3.StringUtils;
49  
50  import fr.paris.lutece.api.user.User;
51  import fr.paris.lutece.plugins.appointment.business.display.Display;
52  import fr.paris.lutece.plugins.appointment.business.planning.TimeSlot;
53  import fr.paris.lutece.plugins.appointment.business.planning.WeekDefinition;
54  import fr.paris.lutece.plugins.appointment.business.planning.WorkingDay;
55  import fr.paris.lutece.plugins.appointment.business.rule.ReservationRule;
56  import fr.paris.lutece.plugins.appointment.business.rule.ReservationRuleHome;
57  import fr.paris.lutece.plugins.appointment.business.slot.Slot;
58  import fr.paris.lutece.plugins.appointment.business.slot.SlotHome;
59  import fr.paris.lutece.plugins.appointment.service.AppointmentResourceIdService;
60  import fr.paris.lutece.plugins.appointment.service.AppointmentUtilities;
61  import fr.paris.lutece.plugins.appointment.service.DisplayService;
62  import fr.paris.lutece.plugins.appointment.service.FormService;
63  import fr.paris.lutece.plugins.appointment.service.ReservationRuleService;
64  import fr.paris.lutece.plugins.appointment.service.SlotSafeService;
65  import fr.paris.lutece.plugins.appointment.service.SlotService;
66  import fr.paris.lutece.plugins.appointment.service.TimeSlotService;
67  import fr.paris.lutece.plugins.appointment.service.WeekDefinitionService;
68  import fr.paris.lutece.plugins.appointment.service.WorkingDayService;
69  import fr.paris.lutece.plugins.appointment.web.dto.AppointmentFormDTO;
70  import fr.paris.lutece.portal.service.admin.AccessDeniedException;
71  import fr.paris.lutece.portal.service.i18n.I18nService;
72  import fr.paris.lutece.portal.service.rbac.RBACService;
73  import fr.paris.lutece.portal.util.mvc.admin.annotations.Controller;
74  import fr.paris.lutece.portal.util.mvc.commons.annotations.Action;
75  import fr.paris.lutece.portal.util.mvc.commons.annotations.View;
76  import fr.paris.lutece.util.date.DateUtil;
77  
78  /**
79   * JspBean to manage calendar slots
80   * 
81   * @author Laurent Payen
82   *
83   */
84  @Controller( controllerJsp = AppointmentAnnualCalendarJspBean.JSP_MANAGE_ANNUAL_CALENDAR, controllerPath = "jsp/admin/plugins/appointment/", right = AppointmentFormJspBean.RIGHT_MANAGEAPPOINTMENTFORM )
85  public class AppointmentAnnualCalendarJspBean extends AbstractAppointmentFormAndSlotJspBean
86  {
87      /**
88       * JSP of this JSP Bean
89       */
90      public static final String JSP_MANAGE_ANNUAL_CALENDAR = "ManageAnnualCalendar.jsp";
91  
92      /**
93       * Serial version UID
94       */
95      private static final long serialVersionUID = 2376721852596997810L;
96  
97      // Messages
98      private static final String MESSAGE_ANNUAL_CALENDAR_PAGE_TITLE = "appointment.annual.calendar.pageTitle";
99      private static final String MESSAGE_ERROR_REMOVE_WEEK = "appointment.message.error.removeWeek";
100     private static final String MESSAGE_ERROR_MODIFICATION = "appointment.message.error.errorModification";
101     private static final String MESSAGE_ERROR_REMOVE_WEEK_DATE_PASSED = "appointment.message.error.removeWeek.date.passed";
102     private static final String MESSAGE_ERROR_MODIFY_FORM_HAS_APPOINTMENTS_AFTER_DATE_OF_MODIFICATION = "appointment.message.error.refreshDays.modifyFormHasAppointments";
103     private static final String MESSAGE_INFO_VALIDATED_APPOINTMENTS_IMPACTED = "appointment.modifyCalendarSlots.messageValidatedAppointmentsImpacted";
104     private static final String MESSAGE_INFO_MULTI_SURBOOKING = "appointment.modifyCalendarMultiSlots.messageSurbooking";
105     private static final String INFO_PARAMETER_REMOVED = "appointment.info.advancedparameters.removed";
106     private static final String INFO_ADVANCED_PARAMETERS_UPDATED = "appointment.info.advancedparameters.updated";
107     private static final String VALIDATION_ATTRIBUTES_PREFIX = "appointment.model.entity.appointmentform.attribute.";
108 
109     // Parameters
110     private static final String PARAMETER_ID_FORM = "id_form";
111     private static final String PARAMETER_ID_WEEK_DEFINITION = "id_week_definition";
112     private static final String PARAMETER_DATE_OF_APPLY = "date_of_apply";
113     private static final String PARAMETER_DATE_END_OF_APPLY = "ending_date_of_apply";
114     private static final String PARAMETER_ID_RESERVATION_RULE = "id_reservation_rule";
115     private static final String PARAMETER_START_YEAR = "start_year";
116     // Mrker
117     private static final String MARK_LIST_RESERVATION_RULE = "listReservationRule";
118     private static final String MARK_LIST_WEEK_DEFINITION = "listWeekDefinition";
119     private static final String MARK_ID_FORM = "id_form";
120     private static final String MARK_LOCALE_TINY = "locale";
121     private static final String MARK_START_YEAR = "start_year";
122     private static final String MARK_SPECIFIC_SLOT_DATES = "specificSlotDates";
123 
124     // Views
125     private static final String VIEW_MANAGE_ANNUAL_CALENDAR = "manageAnnualCalendar";
126     // Actions
127     private static final String ACTION_UNASSIGN_WEEK = "doUnssignWeek";
128     private static final String ACTION_REMOVE_WEEK_FROM_CALENDAR = "doRemoveWeekFromCalendar";
129     private static final String ACTION_ASSIGN_WEEK = "doAssignWeek";
130 
131     // Templates
132     private static final String TEMPLATE_MANAGE_ANNUAL_CALENDAR = "admin/plugins/appointment/slots/manage_annual_calendar.html";
133 
134     // Session variable to store working values
135 
136     // Porperties
137 
138     // Infos
139 
140     /**
141      * Get the view of the typical week
142      * 
143      * @param request
144      *            the request
145      * @return the page
146      */
147     @View( value = VIEW_MANAGE_ANNUAL_CALENDAR )
148     public String getViewManageAnnualCalendar( HttpServletRequest request )
149     {
150         int nIdForm = Integer.parseInt( request.getParameter( PARAMETER_ID_FORM ) );
151         AppointmentFormDTO form = buildAppointmentFormLight( nIdForm );
152         String strStartYear = request.getParameter( PARAMETER_START_YEAR );
153         int nStartYear;
154         List<WeekDefinition> listWeek = WeekDefinitionService.findListWeekDefinition( nIdForm );
155         List<ReservationRule> listRule = ReservationRuleHome.findByIdForm( nIdForm );
156         if ( StringUtils.isNotEmpty( strStartYear ) && StringUtils.isNumeric( strStartYear ) )
157         {
158             nStartYear = Integer.parseInt( strStartYear );
159         }
160         else
161         {
162 
163             nStartYear = LocalDate.now( ).getYear( );
164         }
165         Map<String, Object> model = getModel( );
166         model.put( MARK_LIST_WEEK_DEFINITION, listWeek );
167         model.put( MARK_LIST_RESERVATION_RULE, listRule );
168         model.put( MARK_SPECIFIC_SLOT_DATES, SlotHome.findSpecificSlotDates( nIdForm ) );
169         model.put( MARK_ID_FORM, nIdForm );
170         model.put( MARK_START_YEAR, nStartYear );
171         model.put( MARK_LOCALE_TINY, getLocale( ) );
172         addElementsToModel( form, getUser( ), getLocale( ), model );
173 
174         return getPage( MESSAGE_ANNUAL_CALENDAR_PAGE_TITLE, TEMPLATE_MANAGE_ANNUAL_CALENDAR, model );
175 
176     }
177 
178     /**
179      * Assign a wek to the annual calendar
180      * 
181      * @param request
182      *            the request
183      * @return the page
184      * @throws AccessDeniedException
185      *             the AccessDeniedException
186      */
187     @Action( ACTION_ASSIGN_WEEK )
188     public String doAssignWeek( HttpServletRequest request ) throws AccessDeniedException
189     {
190         String strIdForm = request.getParameter( PARAMETER_ID_FORM );
191         int nIdForm = Integer.parseInt( strIdForm );
192         List<Slot> listSlotsImpacted = new ArrayList<>( );
193         List<WeekDefinition> listWeek = new ArrayList<>( );
194         AppointmentFormDTO form = buildAppointmentFormLight( nIdForm );
195 
196         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM,
197                 (User) getUser( ) ) )
198         {
199             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM );
200         }
201         WeekDefinitionment/business/planning/WeekDefinition.html#WeekDefinition">WeekDefinition newWeek = new WeekDefinition( );
202         populate( newWeek, request );
203 
204         if ( !validateBean( newWeek, VALIDATION_ATTRIBUTES_PREFIX ) || !checkConstraints( newWeek ) )
205         {
206             addError( MESSAGE_ERROR_MODIFICATION, getLocale( ) );
207             return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR, newWeek.getDateOfApply( ).getYear( ) );
208         }
209         listWeek.add( newWeek );
210         if ( AppointmentUtilities.weekIsOpenInFO( form, listWeek, getLocale( ) ) )
211         {
212 
213             addError( ERROR_MESSAGE_WEEK_IS_OPEN_FO, getLocale( ) );
214             return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR, newWeek.getDateOfApply( ).getYear( ) );
215 
216         }
217         ReservationRule reservationRule = ReservationRuleService.findReservationRuleById( newWeek.getIdReservationRule( ) );
218         listSlotsImpacted.addAll( SlotHome.findByIdFormAndDateRange( nIdForm, newWeek.getDateOfApply( ).atStartOfDay( ),
219                 newWeek.getEndingDateOfApply( ).atTime( LocalTime.MAX ) ) );
220         List<Slot> listSlotsImpactedWithAppointment = SlotService.findSlotWithAppointmentByDateRange( nIdForm, newWeek.getDateOfApply( ).atStartOfDay( ),
221                 newWeek.getEndingDateOfApply( ).atTime( LocalTime.MAX ) );
222 
223         if ( CollectionUtils.isNotEmpty( listSlotsImpacted ) )
224         {
225             // if there are appointments impacted
226             if ( CollectionUtils.isNotEmpty( listSlotsImpactedWithAppointment )
227                     && !AppointmentUtilities.checkNoAppointmentsImpacted( listSlotsImpactedWithAppointment, reservationRule.getIdReservationRule( ) ) )
228             {
229                 addError( MESSAGE_ERROR_MODIFY_FORM_HAS_APPOINTMENTS_AFTER_DATE_OF_MODIFICATION, getLocale( ) );
230                 return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR, newWeek.getDateOfApply( ).getYear( ) );
231             }
232             updateSlotImpacted( listSlotsImpacted, listSlotsImpactedWithAppointment, reservationRule );
233         }
234         WeekDefinitionService.assignWeekDefinition( nIdForm, newWeek );
235         addInfo( INFO_ADVANCED_PARAMETERS_UPDATED, getLocale( ) );
236 
237         return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR, newWeek.getDateOfApply( ).getYear( ) );
238 
239     }
240 
241     /**
242      * Unassign a week
243      * 
244      * @param request
245      *            the request
246      * @return the page
247      * @throws AccessDeniedException
248      */
249     @Action( ACTION_UNASSIGN_WEEK )
250     public String doUnassignWeek( HttpServletRequest request ) throws AccessDeniedException
251     {
252         String strIdForm = request.getParameter( PARAMETER_ID_FORM );
253         int nIdForm = Integer.parseInt( strIdForm );
254         AppointmentFormDTO form = buildAppointmentFormLight( nIdForm );
255         List<Slot> listSlotsImpacted = new ArrayList<>( );
256         List<WeekDefinition> listWeek = new ArrayList<>( );
257         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM,
258                 (User) getUser( ) ) )
259         {
260             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM );
261         }
262 
263         WeekDefinitionintment/business/planning/WeekDefinition.html#WeekDefinition">WeekDefinition week = new WeekDefinition( );
264         populate( week, request );
265         week.setIdReservationRule( 0 );
266 
267         if ( !checkConstraints( week ) )
268         {
269             addError( MESSAGE_ERROR_REMOVE_WEEK_DATE_PASSED, getLocale( ) );
270             return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR, week.getDateOfApply( ).getYear( ) );
271         }
272         listWeek.add( week );
273         if ( AppointmentUtilities.weekIsOpenInFO( form, listWeek, getLocale( ) ) )
274         {
275 
276             addError( ERROR_MESSAGE_WEEK_IS_OPEN_FO, getLocale( ) );
277             return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR, week.getDateOfApply( ).getYear( ) );
278         }
279         listSlotsImpacted.addAll(
280                 SlotHome.findByIdFormAndDateRange( nIdForm, week.getDateOfApply( ).atStartOfDay( ), week.getEndingDateOfApply( ).atTime( LocalTime.MAX ) ) );
281         List<Slot> listSlotsImpactedWithAppointment = SlotService.findSlotWithAppointmentByDateRange( nIdForm, week.getDateOfApply( ).atStartOfDay( ),
282                 week.getEndingDateOfApply( ).atTime( LocalTime.MAX ) );
283 
284         if ( CollectionUtils.isNotEmpty( listSlotsImpacted ) )
285         {
286             // if there are appointments impacted
287             if ( CollectionUtils.isNotEmpty( listSlotsImpactedWithAppointment ) )
288             {
289                 addError( MESSAGE_ERROR_MODIFY_FORM_HAS_APPOINTMENTS_AFTER_DATE_OF_MODIFICATION, getLocale( ) );
290                 return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR, week.getDateOfApply( ).getYear( ) );
291             }
292             SlotService.deleteListSlots( listSlotsImpacted );
293         }
294 
295         WeekDefinitionService.assignWeekDefinition( nIdForm, week );
296         addInfo( INFO_PARAMETER_REMOVED, getLocale( ) );
297 
298         return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR, week.getDateOfApply( ).getYear( ) );
299     }
300 
301     /**
302      * Unassign a week
303      * 
304      * @param request
305      *            the request
306      * @return the page
307      * @throws AccessDeniedException
308      */
309     @Action( ACTION_REMOVE_WEEK_FROM_CALENDAR )
310     public String doRemoveWeekFromCalendar( HttpServletRequest request ) throws AccessDeniedException
311     {
312         String strIdForm = request.getParameter( PARAMETER_ID_FORM );
313         String strIdWeekDefinition = request.getParameter( PARAMETER_ID_WEEK_DEFINITION );
314         int nIdForm = Integer.parseInt( strIdForm );
315         AppointmentFormDTO form = buildAppointmentFormLight( nIdForm );
316         List<WeekDefinition> listWeek = new ArrayList<>( );
317         List<Slot> listSlotsImpacted = new ArrayList<>( );
318 
319         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM,
320                 (User) getUser( ) ) )
321         {
322             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM );
323         }
324         WeekDefinition weekToDelete = WeekDefinitionService.findWeekDefinitionById( Integer.parseInt( strIdWeekDefinition ) );
325         ReservationRule rule = ReservationRuleHome.findByPrimaryKey( weekToDelete.getIdReservationRule( ) );
326         if ( rule.getIdForm( ) != nIdForm )
327         {
328 
329             addError( MESSAGE_ERROR_REMOVE_WEEK, getLocale( ) );
330             return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR,
331                     weekToDelete.getDateOfApply( ).getYear( ) );
332 
333         }
334         LocalDate dateNow = LocalDate.now( );
335         if ( weekToDelete.getDateOfApply( ).isBefore( dateNow ) )
336         {
337 
338             addError( MESSAGE_ERROR_REMOVE_WEEK_DATE_PASSED, getLocale( ) );
339             return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR,
340                     weekToDelete.getDateOfApply( ).getYear( ) );
341 
342         }
343         listWeek.add( weekToDelete );
344         if ( AppointmentUtilities.weekIsOpenInFO( form, listWeek, getLocale( ) ) )
345         {
346 
347             addError( ERROR_MESSAGE_WEEK_IS_OPEN_FO, getLocale( ) );
348             return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR,
349                     weekToDelete.getDateOfApply( ).getYear( ) );
350         }
351         List<Slot> listSlotsImpactedWithAppointment = SlotHome.findSlotWithAppointmentByDateRange( nIdForm, weekToDelete.getDateOfApply( ).atStartOfDay( ),
352                 weekToDelete.getEndingDateOfApply( ).atTime( LocalTime.MAX ) );
353 
354         if ( CollectionUtils.isNotEmpty( listSlotsImpactedWithAppointment ) )
355         {
356             addError( MESSAGE_INFO_VALIDATED_APPOINTMENTS_IMPACTED, getLocale( ) );
357             return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR,
358                     weekToDelete.getDateOfApply( ).getYear( ) );
359         }
360         listSlotsImpacted.addAll( SlotService.findSlotsByIdFormAndDateRange( nIdForm, weekToDelete.getDateOfApply( ).atStartOfDay( ),
361                 weekToDelete.getEndingDateOfApply( ).atTime( LocalTime.MAX ) ) );
362         SlotService.deleteListSlots( listSlotsImpacted );
363         WeekDefinitionService.removeWeekDefinition( weekToDelete );
364         addInfo( INFO_PARAMETER_REMOVED, getLocale( ) );
365 
366         return redirect( request, VIEW_MANAGE_ANNUAL_CALENDAR, PARAMETER_ID_FORM, nIdForm, PARAMETER_START_YEAR, weekToDelete.getDateOfApply( ).getYear( ) );
367 
368     }
369 
370     /**
371      * Update the slots with appointments impacted by a modification of a typical week or a modification of a timeSlot Delete the slots with no appointments
372      * 
373      * @param listSlotsImpacted
374      *            the slots impacted
375      * @param nMaxCapacity
376      *            the max capacity
377      */
378     private void updateSlotImpacted( List<Slot> listSlotsImpacted, List<Slot> listSlotsImpactedWithAppointments, ReservationRule reservationRule )
379     {
380         // Need to delete the slots that are impacted but with no appointments
381         List<Integer> listIdSlotsImpactedWithAppointments = listSlotsImpactedWithAppointments.stream( ).map( Slot::getIdSlot ).collect( Collectors.toList( ) );
382         List<Slot> listslotImpactedWithoutAppointments = listSlotsImpacted.stream( )
383                 .filter( p -> !listIdSlotsImpactedWithAppointments.contains( p.getIdSlot( ) ) ).collect( Collectors.toList( ) );
384         int nMaxCapacity = reservationRule.getMaxCapacityPerSlot( );
385         WorkingDay workingDay = null;
386         TimeSlot timeSlot = null;
387         StringBuilder sbAlert = new StringBuilder( );
388         boolean bOpeningHasChanged = false;
389         SlotService.deleteListSlots( listslotImpactedWithoutAppointments );
390 
391         for ( Slot slotImpacted : listSlotsImpactedWithAppointments )
392         {
393             workingDay = WorkingDayService.getWorkingDayOfDayOfWeek( reservationRule.getListWorkingDay( ),
394                     slotImpacted.getStartingDateTime( ).getDayOfWeek( ) );
395             timeSlot = TimeSlotService.getTimeSlotInListOfTimeSlotWithStartingTime( workingDay.getListTimeSlot( ), slotImpacted.getStartingTime( ) );
396             nMaxCapacity = timeSlot.getMaxCapacity( );
397             Lock lock = SlotSafeService.getLockOnSlot( slotImpacted.getIdSlot( ) );
398             lock.lock( );
399             try
400             {
401 
402                 slotImpacted = SlotHome.findByPrimaryKey( slotImpacted.getIdSlot( ) );
403                 int nOldBnMaxCapacity = slotImpacted.getMaxCapacity( );
404                 // If the max capacity has been modified
405                 if ( nMaxCapacity != nOldBnMaxCapacity )
406                 {
407                     // Need to update the remaining places
408                     // Need to add the diff between the old value and the new value
409                     // to the remaining places (if the new is higher)
410                     if ( nMaxCapacity > nOldBnMaxCapacity )
411                     {
412                         int nValueToAdd = nMaxCapacity - nOldBnMaxCapacity;
413                         slotImpacted.setNbPotentialRemainingPlaces( slotImpacted.getNbPotentialRemainingPlaces( ) + nValueToAdd );
414                         slotImpacted.setNbRemainingPlaces( slotImpacted.getNbRemainingPlaces( ) + nValueToAdd );
415                     }
416                     else
417                     {
418                         // the new value is lower than the previous capacity
419                         // !!!! If there are appointments on this slot and if the
420                         // slot is already full, the slot will be surbooked !!!!
421                         int nValueToSubstract = nOldBnMaxCapacity - nMaxCapacity;
422                         slotImpacted.setNbPotentialRemainingPlaces( slotImpacted.getNbPotentialRemainingPlaces( ) - nValueToSubstract );
423                         slotImpacted.setNbRemainingPlaces( slotImpacted.getNbRemainingPlaces( ) - nValueToSubstract );
424                     }
425                 }
426                 if ( slotImpacted.getIsOpen( ) && !timeSlot.getIsOpen( ) )
427                 {
428 
429                     bOpeningHasChanged = true;
430                 }
431                 slotImpacted.setIsOpen( timeSlot.getIsOpen( ) );
432                 slotImpacted.setIsSpecific( false );
433                 slotImpacted.setMaxCapacity( nMaxCapacity );
434 
435                 if ( slotImpacted.getMaxCapacity( ) < slotImpacted.getNbPlacesTaken( ) )
436                 {
437                     sbAlert.append( slotImpacted.getStartingDateTime( ) );
438                     sbAlert.append( "-" );
439                     sbAlert.append( slotImpacted.getEndingDateTime( ) );
440                     sbAlert.append( ", " );
441                 }
442 
443                 SlotSafeService.updateSlot( slotImpacted );
444             }
445             finally
446             {
447                 lock.unlock( );
448             }
449         }
450         if ( bOpeningHasChanged )
451         {
452             addWarning( MESSAGE_INFO_VALIDATED_APPOINTMENTS_IMPACTED, getLocale( ) );
453         }
454         if ( !StringUtils.isEmpty( sbAlert.toString( ) ) )
455         {
456             Object [ ] args = {
457                     sbAlert.toString( )
458             };
459             addWarning( I18nService.getLocalizedString( MESSAGE_INFO_MULTI_SURBOOKING, args, getLocale( ) ) );
460         }
461 
462     }
463 
464     /**
465      * Check Constraints
466      * 
467      * @param week
468      *            the week
469      * @return boolean
470      */
471     private boolean checkConstraints( WeekDefinition week )
472     {
473         LocalDate dateNow = LocalDate.now( );
474         if ( week.getDateOfApply( ).isAfter( week.getEndingDateOfApply( ) ) || dateNow.isAfter( week.getDateOfApply( ) ) )
475         {
476 
477             addError( MESSAGE_ERROR_MODIFICATION, getLocale( ) );
478             return false;
479         }
480 
481         return true;
482     }
483 
484     private void populate( WeekDefinition week, HttpServletRequest request )
485     {
486 
487         String dateOfApplay = request.getParameter( PARAMETER_DATE_OF_APPLY );
488         String dateEndOfApplay = request.getParameter( PARAMETER_DATE_END_OF_APPLY );
489         String idReservationRule = request.getParameter( PARAMETER_ID_RESERVATION_RULE );
490 
491         week.setDateOfApply( DateUtil.formatDate( dateOfApplay, getLocale( ) ).toInstant( ).atZone( ZoneId.systemDefault( ) ).toLocalDate( ) );
492         week.setEndingDateOfApply( DateUtil.formatDate( dateEndOfApplay, getLocale( ) ).toInstant( ).atZone( ZoneId.systemDefault( ) ).toLocalDate( ) );
493         week.setIdReservationRule( Integer.parseInt( idReservationRule ) );
494     }
495 
496     /**
497      * Build an appointmentForm light
498      * 
499      * @param nIdForm
500      *            the form Id
501      * @return the appointmentForm DTO
502      */
503     private AppointmentFormDTO buildAppointmentFormLight( int nIdForm )
504     {
505 
506         AppointmentFormDTO form = FormService.buildAppointmentFormLight( nIdForm );
507         Display display = DisplayService.findDisplayWithFormId( form.getIdForm( ) );
508         form.setNbWeeksToDisplay( display.getNbWeeksToDisplay( ) );
509         return form;
510     }
511 
512 }