View Javadoc
1   /*
2    * Copyright (c) 2002-2018, Mairie de 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.sql.Date;
37  import java.text.ParseException;
38  import java.text.SimpleDateFormat;
39  import java.time.LocalDate;
40  import java.time.LocalDateTime;
41  import java.time.LocalTime;
42  import java.util.ArrayList;
43  import java.util.Arrays;
44  import java.util.Collections;
45  import java.util.HashMap;
46  import java.util.List;
47  import java.util.Locale;
48  import java.util.Map;
49  import java.util.concurrent.TimeUnit;
50  import java.util.stream.Collectors;
51  import java.util.stream.Stream;
52  
53  import javax.servlet.http.HttpServletRequest;
54  import javax.servlet.http.HttpServletResponse;
55  import javax.servlet.http.HttpSession;
56  
57  import fr.paris.lutece.plugins.appointment.business.AppointmentFillDTO;
58  import org.apache.commons.collections.CollectionUtils;
59  import org.apache.commons.lang.ArrayUtils;
60  import org.apache.commons.lang.StringUtils;
61  
62  import fr.paris.lutece.plugins.appointment.business.appointment.Appointment;
63  import fr.paris.lutece.plugins.appointment.business.display.Display;
64  import fr.paris.lutece.plugins.appointment.business.form.Form;
65  import fr.paris.lutece.plugins.appointment.business.message.FormMessage;
66  import fr.paris.lutece.plugins.appointment.business.planning.WeekDefinition;
67  import fr.paris.lutece.plugins.appointment.business.rule.ReservationRule;
68  import fr.paris.lutece.plugins.appointment.business.slot.Period;
69  import fr.paris.lutece.plugins.appointment.business.slot.Slot;
70  import fr.paris.lutece.plugins.appointment.log.LogUtilities;
71  import fr.paris.lutece.plugins.appointment.service.AppointmentResourceIdService;
72  import fr.paris.lutece.plugins.appointment.service.AppointmentResponseService;
73  import fr.paris.lutece.plugins.appointment.service.AppointmentService;
74  import fr.paris.lutece.plugins.appointment.service.AppointmentUtilities;
75  import fr.paris.lutece.plugins.appointment.service.DisplayService;
76  import fr.paris.lutece.plugins.appointment.service.EntryService;
77  import fr.paris.lutece.plugins.appointment.service.FormMessageService;
78  import fr.paris.lutece.plugins.appointment.service.FormService;
79  import fr.paris.lutece.plugins.appointment.service.ReservationRuleService;
80  import fr.paris.lutece.plugins.appointment.service.SlotService;
81  import fr.paris.lutece.plugins.appointment.service.Utilities;
82  import fr.paris.lutece.plugins.appointment.service.WeekDefinitionService;
83  import fr.paris.lutece.plugins.appointment.service.addon.AppointmentAddOnManager;
84  import fr.paris.lutece.plugins.appointment.service.listeners.AppointmentListenerManager;
85  import fr.paris.lutece.plugins.appointment.service.lock.SlotEditTask;
86  import fr.paris.lutece.plugins.appointment.service.lock.TimerForLockOnSlot;
87  import fr.paris.lutece.plugins.appointment.service.upload.AppointmentAsynchronousUploadHandler;
88  import fr.paris.lutece.plugins.appointment.web.dto.AppointmentDTO;
89  import fr.paris.lutece.plugins.appointment.web.dto.AppointmentFilterDTO;
90  import fr.paris.lutece.plugins.appointment.web.dto.AppointmentFormDTO;
91  import fr.paris.lutece.plugins.genericattributes.business.Entry;
92  import fr.paris.lutece.plugins.genericattributes.business.EntryHome;
93  import fr.paris.lutece.plugins.genericattributes.business.GenericAttributeError;
94  import fr.paris.lutece.plugins.genericattributes.business.Response;
95  import fr.paris.lutece.plugins.workflowcore.business.state.State;
96  import fr.paris.lutece.plugins.workflowcore.business.state.StateFilter;
97  import fr.paris.lutece.plugins.workflowcore.service.state.StateService;
98  import fr.paris.lutece.plugins.workflowcore.service.task.ITask;
99  import fr.paris.lutece.plugins.workflowcore.service.task.ITaskService;
100 import fr.paris.lutece.plugins.workflowcore.service.task.TaskService;
101 import fr.paris.lutece.portal.business.file.FileHome;
102 import fr.paris.lutece.portal.business.user.AdminUser;
103 import fr.paris.lutece.portal.service.admin.AccessDeniedException;
104 import fr.paris.lutece.portal.service.i18n.I18nService;
105 import fr.paris.lutece.portal.service.message.AdminMessage;
106 import fr.paris.lutece.portal.service.message.AdminMessageService;
107 import fr.paris.lutece.portal.service.message.SiteMessageException;
108 import fr.paris.lutece.portal.service.rbac.RBACService;
109 import fr.paris.lutece.portal.service.security.LuteceUser;
110 import fr.paris.lutece.portal.service.security.SecurityService;
111 import fr.paris.lutece.portal.service.spring.SpringContextService;
112 import fr.paris.lutece.portal.service.template.AppTemplateService;
113 import fr.paris.lutece.portal.service.util.AppLogService;
114 import fr.paris.lutece.portal.service.util.AppPathService;
115 import fr.paris.lutece.portal.service.util.AppPropertiesService;
116 import fr.paris.lutece.portal.service.workflow.WorkflowService;
117 import fr.paris.lutece.portal.util.mvc.admin.MVCAdminJspBean;
118 import fr.paris.lutece.portal.util.mvc.admin.annotations.Controller;
119 import fr.paris.lutece.portal.util.mvc.commons.annotations.Action;
120 import fr.paris.lutece.portal.util.mvc.commons.annotations.View;
121 import fr.paris.lutece.portal.util.mvc.utils.MVCUtils;
122 import fr.paris.lutece.portal.web.util.LocalizedPaginator;
123 import fr.paris.lutece.util.ReferenceList;
124 import fr.paris.lutece.util.html.HtmlTemplate;
125 import fr.paris.lutece.util.html.Paginator;
126 import fr.paris.lutece.util.url.UrlItem;
127 import org.apache.commons.lang3.math.NumberUtils;
128 
129 /**
130  * This class provides the user interface to manage Appointment features ( manage, create, modify, remove )
131  * 
132  * @author Laurent Payen
133  * 
134  */
135 @Controller( controllerJsp = "ManageAppointments.jsp", controllerPath = "jsp/admin/plugins/appointment/", right = AppointmentFormJspBean.RIGHT_MANAGEAPPOINTMENTFORM )
136 public class AppointmentJspBean extends MVCAdminJspBean
137 {
138     /**
139      * Serial version UID
140      */
141     private static final long serialVersionUID = 1978001810468444844L;
142     private static final String PARAMETER_PAGE_INDEX = "page_index";
143 
144     // //////////////////////////////////////////////////////////////////////////
145     // Constants
146 
147     // templates
148     private static final String TEMPLATE_MANAGE_APPOINTMENTS_CALENDAR = "/admin/plugins/appointment/appointment/manage_appointments_calendar.html";
149     private static final String TEMPLATE_CREATE_APPOINTMENT = "/admin/plugins/appointment/appointment/create_appointment.html";
150     private static final String TEMPLATE_MANAGE_APPOINTMENTS = "/admin/plugins/appointment/appointment/manage_appointments.html";
151     private static final String TEMPLATE_VIEW_APPOINTMENT = "/admin/plugins/appointment/appointment/view_appointment.html";
152     private static final String TEMPLATE_HTML_CODE_FORM_ADMIN = "admin/plugins/appointment/html_code_form.html";
153     private static final String TEMPLATE_APPOINTMENT_FORM_RECAP = "/admin/plugins/appointment/appointment/appointment_form_recap.html";
154     private static final String TEMPLATE_TASKS_FORM_WORKFLOW = "admin/plugins/appointment/appointment/tasks_form_workflow.html";
155 
156     // Properties for page titles
157     private static final String PROPERTY_PAGE_TITLE_MANAGE_APPOINTMENTS = "appointment.manageAppointments.pageTitle";
158     private static final String PROPERTY_PAGE_TITLE_MANAGE_APPOINTMENTS_CALENDAR = "appointment.manageAppointmentCalendar.pageTitle";
159     private static final String PROPERTY_PAGE_TITLE_CREATE_APPOINTMENT = "appointment.name.create";
160     private static final String PROPERTY_PAGE_TITLE_VIEW_APPOINTMENT = "appointment.viewAppointment.pageTitle";
161     private static final String PROPERTY_PAGE_TITLE_RECAP_APPOINTMENT = "appointment.appointmentApp.recap.title";
162     private static final String PROPERTY_PAGE_TITLE_TASKS_FORM_WORKFLOW = "appointment.taskFormWorkflow.pageTitle";
163 
164     private static final String UNRESERVED = "appointment.message.labelStatusUnreserved";
165     private static final String RESERVED = "appointment.message.labelStatusReserved";
166 
167     // Connected User
168     private static final String PROPERTY_USER_EMAIL = "user.business-info.online.email";
169     private static final String PROPERTY_USER_FIRST_NAME = "user.name.given";
170     private static final String PROPERTY_USER_LAST_NAME = "user.name.family";
171 
172     // Parameters
173     private static final String PARAMETER_IS_OPEN = "is_open";
174     private static final String PARAMETER_IS_SPECIFIC = "is_specific";
175     private static final String PARAMETER_MAX_CAPACITY = "max_capacity";
176     private static final String PARAMETER_STARTING_DATE_TIME = "starting_date_time";
177     private static final String PARAMETER_ENDING_DATE_TIME = "ending_date_time";
178     private static final String PARAMETER_STARTING_DATE_OF_DISPLAY = "starting_date_of_display";
179     private static final String PARAMETER_STR_STARTING_DATE_OF_DISPLAY = "str_starting_date_of_display";
180     private static final String PARAMETER_ENDING_DATE_OF_DISPLAY = "ending_date_of_display";
181     private static final String PARAMETER_STR_ENDING_DATE_OF_DISPLAY = "str_ending_date_of_display";
182     private static final String PARAMETER_DATE_OF_DISPLAY = "date_of_display";
183     private static final String PARAMETER_DAY_OF_WEEK = "dow";
184     private static final String PARAMETER_EVENTS = "events";
185     private static final String PARAMETER_MIN_DURATION = "min_duration";
186     private static final String PARAMETER_MIN_TIME = "min_time";
187     private static final String PARAMETER_MAX_TIME = "max_time";
188     private static final String PARAMETER_ID_APPOINTMENT = "id_appointment";
189     private static final String PARAMETER_ID_ACTION = "id_action";
190     private static final String PARAMETER_ID_FORM = "id_form";
191     private static final String PARAMETER_COME_FROM_CALENDAR = "comeFromCalendar";
192     private static final String PARAMETER_EMAIL = "email";
193     private static final String PARAMETER_EMAIL_CONFIRMATION = "emailConfirm";
194     private static final String PARAMETER_FIRST_NAME = "firstname";
195     private static final String PARAMETER_LAST_NAME = "lastname";
196     private static final String PARAMETER_ID_SLOT = "id_slot";
197     private static final String PARAMETER_BACK = "back";
198     private static final String PARAMETER_ORDER_BY = "orderBy";
199     private static final String PARAMETER_ORDER_ASC = "orderAsc";
200     private static final String PARAMETER_ID_APPOINTMENT_DELETE = "apmt";
201     private static final String PARAMETER_DELETE_AND_BACK = "eraseAll";
202     private static final String PARAMETER_SEARCH = "Search";
203     private static final String PARAMETER_RESET = "reset";
204     private static final String PARAMETER_NUMBER_OF_BOOKED_SEATS = "nbBookedSeats";
205     private static final String PARAMETER_STATUS_CANCELLED = "status_cancelled";
206     private static final String PARAMETER_MODIF_DATE = "modif_date";
207 
208     // Markers
209     private static final String MARK_TASKS_FORM = "tasks_form";
210     private static final String MARK_APPOINTMENT_LIST = "appointment_list";
211     private static final String MARK_APPOINTMENT = "appointment";
212     private static final String MARK_PAGINATOR = "paginator";
213     private static final String MARK_NB_ITEMS_PER_PAGE = "nb_items_per_page";
214     private static final String MARK_FORM_MESSAGES = "formMessages";
215     private static final String MARK_FORM_HTML = "form_html";
216     private static final String MARK_FORM = "form";
217     private static final String MARK_MODIFICATION_DATE_APPOINTMENT = "modifDateAppointment";
218     private static final String MARK_FORM_CALENDAR_ERRORS = "formCalendarErrors";
219     private static final String MARK_FORM_ERRORS = "form_errors";
220     private static final String MARK_LIST_ERRORS = "listAllErrors";
221     private static final String MARK_LOCALE = "locale";
222     private static final String MARK_PLACES = "nbplaces";
223     private static final String MARK_STR_ENTRY = "str_entry";
224     private static final String MARK_RIGHT_CREATE = "rightCreate";
225     private static final String MARK_RIGHT_MODIFY = "rightModify";
226     private static final String MARK_RIGHT_DELETE = "rightDelete";
227     private static final String MARK_RIGHT_VIEW = "rightView";
228     private static final String MARK_RIGHT_CHANGE_STATUS = "rightChangeStatus";
229     private static final String MARK_RIGHT_CHANGE_DATE = "rightChangeDate";
230     private static final String MARK_FILTER = "filter";
231     private static final String MARK_LIST_STATUS = "listStatus";
232     private static final String MARK_RESOURCE_HISTORY = "resource_history";
233     private static final String MARK_ADDON = "addon";
234     private static final String MARK_LIST_RESPONSE_RECAP_DTO = "listResponseRecapDTO";
235     private static final String MARK_LANGUAGE = "language";
236     private static final String MARK_ACTIVATE_WORKFLOW = "activateWorkflow";
237     private static final String MARK_HORAIRE_MAX_AM = "horaireMaxAM";
238     private static final String MARK_HORAIRE_MIN_PM = "horaireMinPM";
239     private static final String MARK_HORAIRE_ID_ENTRY= "horaireIdEntry";
240 
241     private static final String JSP_MANAGE_APPOINTMENTS = "jsp/admin/plugins/appointment/ManageAppointments.jsp";
242     private static final String ERROR_MESSAGE_SLOT_FULL = "appointment.message.error.slotFull";
243 
244     // Messages
245     private static final String MESSAGE_CONFIRM_REMOVE_APPOINTMENT = "appointment.message.confirmRemoveAppointment";
246     private static final String MESSAGE_CONFIRM_REMOVE_MASSAPPOINTMENT = "appointment.message.confirmRemoveMassAppointment";
247 
248     // Properties
249     private static final String PROPERTY_DEFAULT_LIST_APPOINTMENT_PER_PAGE = "appointment.listAppointments.itemsPerPage";
250     private static final String PROPERTY_NB_WEEKS_TO_DISPLAY_IN_BO = "appointment.nbWeeksToDisplayInBO";
251     private static final String PROPERTY_NB_MAX_APPOINTMENTS_TO_EXPORT = "appointment.nbMaxAppointmentsToExport";
252     private static final String PROPERTY_AMPLITUDE = "appointment.amplitude";
253     private static final String PROPERTY_AMPLITUDE_ANIMATIONS = "appointment.amplitude.animations";
254     private static final String PROPERTY_HORAIRE_MAX_AM = "appointment.horaireLimiteMaxAM";
255     private static final String PROPERTY_HORAIRE_MIN_PM = "appointment.horaireLimiteMinPM";
256 
257     // Views
258     private static final String VIEW_MANAGE_APPOINTMENTS = "manageAppointments";
259     private static final String VIEW_CREATE_APPOINTMENT = "createAppointment";
260     private static final String VIEW_MODIFY_APPOINTMENT = "modifyAppointment";
261     private static final String VIEW_VIEW_APPOINTMENT = "viewAppointment";
262     private static final String VIEW_DISPLAY_RECAP_APPOINTMENT = "displayRecapAppointment";
263     private static final String VIEW_CALENDAR_MANAGE_APPOINTMENTS = "viewCalendarManageAppointment";
264     private static final String VIEW_WORKFLOW_ACTION_FORM = "viewWorkflowActionForm";
265     private static final String VIEW_CHANGE_DATE_APPOINTMENT = "viewChangeDateAppointment";
266 
267     // Actions
268     private static final String ACTION_DO_VALIDATE_FORM = "doValidateForm";
269     private static final String ACTION_REMOVE_APPOINTMENT = "removeAppointment";
270     private static final String ACTION_REMOVE_MASSAPPOINTMENT = "removeMassAppointment";
271     private static final String ACTION_CONFIRM_REMOVE_APPOINTMENT = "confirmRemoveAppointment";
272     private static final String ACTION_CONFIRM_REMOVE_MASS_APPOINTMENT = "confirmRemoveMassAppointment";
273     private static final String ACTION_DO_MAKE_APPOINTMENT = "doMakeAppointment";
274     private static final String ACTION_DO_PROCESS_WORKFLOW_ACTION = "doProcessWorkflowAction";
275     private static final String ACTION_DO_CHANGE_APPOINTMENT_STATUS = "doChangeAppointmentStatus";
276 
277     // Infos
278     private static final String INFO_APPOINTMENT_CREATED = "appointment.info.appointment.created";
279     private static final String INFO_APPOINTMENT_REMOVED = "appointment.info.appointment.removed";
280     private static final String INFO_APPOINTMENT_MASSREMOVED = "appointment.info.appointment.removed";
281 
282     // Error
283     private static final String ERROR_MESSAGE_FORM_NOT_ACTIVE = "appointment.validation.appointment.formNotActive";
284     private static final String ERROR_MESSAGE_NO_STARTING_VALIDITY_DATE = "appointment.validation.appointment.noStartingValidityDate";
285     private static final String ERROR_MESSAGE_FORM_NO_MORE_VALID = "appointment.validation.appointment.formNoMoreValid";
286     private static final String MESSAGE_UNVAILABLE_SLOT = "appointment.slot.unvailable";
287     private static final String ERROR_MESSAGE_NB_MAX_APPOINTMENTS_FOR_EXPORT = "appointment.manageAppointments.nbMaxAppointmentsForExport";
288     private static final String ERROR_MESSAGE_AMPLITUDE = "appointment.message.error.amplitude";
289     private static final String ERROR_MESSAGE_HORAIRE_BO = "appointment.message.error.horaireBO";
290 
291     // Session keys
292     private static final String SESSION_CURRENT_PAGE_INDEX = "appointment.session.currentPageIndex";
293     private static final String SESSION_ITEMS_PER_PAGE = "appointment.session.itemsPerPage";
294     private static final String SESSION_NOT_VALIDATED_APPOINTMENT = "appointment.appointmentFormService.notValidatedAppointment";
295     private static final String SESSION_VALIDATED_APPOINTMENT = "appointment.appointmentFormService.validatedAppointment";
296     private static final String SESSION_APPOINTMENT_FORM_ERRORS = "appointment.session.formErrors";
297     private static final String SESSION_ATTRIBUTE_APPOINTMENT_FORM = "appointment.session.appointmentForm";
298     private static final String SESSION_APPOINTMENT_FILTER = "appointment.session.filter";
299     private static final String SESSION_LIST_APPOINTMENTS = "appointment.session.listAppointments";
300 
301     // Constants
302     private static final String DEFAULT_CURRENT_PAGE = "1";
303     public static final String ACTIVATEWORKFLOW = AppPropertiesService.getProperty( "appointment.activate.workflow" );
304     public static final String PREVIOUS_FORM = "calendar";
305     private static final String LAST_NAME = "last_name";
306     private static final String FIRST_NAME = "first_name";
307     private static final String EMAIL = "email";
308     private static final String NB_BOOKED_SEATS = "nbBookedSeats";
309     private static final String DATE_APPOINTMENT = "date_appointment";
310     private static final String ADMIN = "admin";
311     private static final String STATUS = "status";
312     private static final int MAX_NB_APPOINTMENTS_TO_EXPORT = 8000;
313     private static final String LABEL_MONTAGE = "début du montage";
314     private static final String LABEL_DEMONTAGE = "démontage";
315     private static final String LABEL_TYPE_ANIMATION = "Type précis de l’animation";
316     // services
317     private final transient StateService _stateService = SpringContextService.getBean( StateService.BEAN_SERVICE );
318     private final transient ITaskService _taskService = SpringContextService.getBean( TaskService.BEAN_SERVICE );
319 
320     // Session variable to store working values
321     private int _nDefaultItemsPerPage;
322 
323     private int amplitude = Integer.valueOf(AppPropertiesService.getProperty( PROPERTY_AMPLITUDE ));
324     private String[] animations = StringUtils.split( AppPropertiesService.getProperty( PROPERTY_AMPLITUDE_ANIMATIONS ), "," );
325     private String horaireMaxAM = AppPropertiesService.getProperty( PROPERTY_HORAIRE_MAX_AM );
326     private String horaireMinPM = AppPropertiesService.getProperty( PROPERTY_HORAIRE_MIN_PM );
327 
328     /**
329      * Get the page to manage appointments. Appointments are displayed in a calendar.
330      * 
331      * @param request
332      *            The request
333      * @return The HTML code to display
334      * @throws AccessDeniedException
335      */
336     @View( value = VIEW_CALENDAR_MANAGE_APPOINTMENTS, defaultView = true )
337     public String getViewCalendarManageAppointments( HttpServletRequest request ) throws AccessDeniedException
338     {
339         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, "0", AppointmentResourceIdService.PERMISSION_VIEW_FORM, getUser( ) ) )
340         {
341             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_VIEW_FORM );
342         }
343         cleanSession( request.getSession( ) );
344         String strIdAppointment = request.getParameter( PARAMETER_ID_APPOINTMENT );
345         AppointmentDTO appointmentDTO = null;
346         if ( StringUtils.isNotEmpty( strIdAppointment ) )
347         {
348             // If we want to change the date of an appointment
349             int nIdAppointment = Integer.parseInt( strIdAppointment );
350             appointmentDTO = AppointmentService.buildAppointmentDTOFromIdAppointment( nIdAppointment );
351             AppointmentService.addAppointmentResponses( appointmentDTO );
352         }
353         int nIdForm = Integer.parseInt( request.getParameter( PARAMETER_ID_FORM ) );
354         Form form = FormService.findFormLightByPrimaryKey( nIdForm );
355         boolean bError = false;
356         if ( !form.getIsActive( ) )
357         {
358             addError( ERROR_MESSAGE_FORM_NOT_ACTIVE, getLocale( ) );
359             bError = true;
360         }
361         FormMessage formMessages = FormMessageService.findFormMessageByIdForm( nIdForm );
362         // Check if the date of display and the endDateOfDisplay are in the
363         // validity date range of the form
364         LocalDate startingValidityDate = form.getStartingValidityDate( );
365         if ( startingValidityDate == null )
366         {
367             addError( ERROR_MESSAGE_NO_STARTING_VALIDITY_DATE, getLocale( ) );
368             bError = true;
369         }
370         Display display = DisplayService.findDisplayWithFormId( nIdForm );
371         int nNbWeeksToDisplay = AppPropertiesService.getPropertyInt( PROPERTY_NB_WEEKS_TO_DISPLAY_IN_BO, display.getNbWeeksToDisplay( ) );
372         LocalDate startingDateOfDisplay = LocalDate.now( ).minusWeeks( nNbWeeksToDisplay );
373         LocalDate endingDateOfDisplay = LocalDate.now( ).plusWeeks( nNbWeeksToDisplay );
374         LocalDate endingValidityDate = form.getEndingValidityDate( );
375         if ( endingValidityDate != null )
376         {
377             if ( startingDateOfDisplay.isAfter( endingDateOfDisplay ) )
378             {
379                 addError( ERROR_MESSAGE_FORM_NO_MORE_VALID, getLocale( ) );
380                 bError = true;
381             }
382             if ( endingDateOfDisplay.isAfter( endingValidityDate ) )
383             {
384                 endingDateOfDisplay = endingValidityDate;
385             }
386         }
387         String strDateOfDisplay = request.getParameter( PARAMETER_DATE_OF_DISPLAY );
388         LocalDate dateOfDisplay = LocalDate.now( );
389         if ( StringUtils.isNotEmpty( strDateOfDisplay ) )
390         {
391             dateOfDisplay = LocalDate.parse( strDateOfDisplay );
392         }
393         List<Slot> listSlot = new ArrayList<>( );
394         HashMap<LocalDate, WeekDefinition> mapWeekDefinition = WeekDefinitionService.findAllWeekDefinition( nIdForm );
395         List<WeekDefinition> listWeekDefinition = new ArrayList<WeekDefinition>( mapWeekDefinition.values( ) );
396         LocalTime maxEndingTime = WeekDefinitionService.getMaxEndingTimeOfAListOfWeekDefinition( listWeekDefinition );
397         LocalTime minStartingTime = WeekDefinitionService.getMinStartingTimeOfAListOfWeekDefinition( listWeekDefinition );
398         List<String> listDayOfWeek = new ArrayList<>( WeekDefinitionService.getSetDaysOfWeekOfAListOfWeekDefinitionForFullCalendar( listWeekDefinition ) );
399         if ( !bError )
400         {
401             listSlot = SlotService.buildListSlot( nIdForm, mapWeekDefinition, startingDateOfDisplay, endingDateOfDisplay );
402             // Tag as passed the slots passed
403             List<Slot> listSlotsPassed = listSlot.stream( ).filter( s -> s.getEndingDateTime( ).isBefore( LocalDateTime.now( ) ) )
404                     .collect( Collectors.toList( ) );
405             for ( Slot slotPassed : listSlotsPassed )
406             {
407                 slotPassed.setIsPassed( Boolean.TRUE );
408             }
409         }
410         Map<String, Object> model = getModel( );
411         if ( bError )
412         {
413             model.put( MARK_FORM_CALENDAR_ERRORS, bError );
414         }
415         // If we change the date of an appointment
416         // filter the list of slot with only the ones that have enough places at
417         // the moment of the edition
418         if ( appointmentDTO != null )
419         {
420             int nbBookedSeats = appointmentDTO.getNbBookedSeats( );
421             listSlot = listSlot.stream( ).filter( s -> s.getNbPotentialRemainingPlaces( ) >= nbBookedSeats && s.getIsOpen( ) ).collect( Collectors.toList( ) );
422             request.getSession( ).setAttribute( SESSION_VALIDATED_APPOINTMENT, appointmentDTO );
423             model.put( MARK_MODIFICATION_DATE_APPOINTMENT, true );
424         }
425         else
426         {
427             model.put( MARK_MODIFICATION_DATE_APPOINTMENT, false );
428         }
429         model.put( MARK_FORM, FormService.buildAppointmentFormLight( nIdForm ) );
430         model.put( PARAMETER_ID_FORM, nIdForm );
431         model.put( MARK_FORM_MESSAGES, formMessages );
432         model.put( PARAMETER_STARTING_DATE_OF_DISPLAY, startingDateOfDisplay );
433         model.put( PARAMETER_STR_STARTING_DATE_OF_DISPLAY, startingDateOfDisplay.format( Utilities.getFormatter( ) ) );
434         model.put( PARAMETER_ENDING_DATE_OF_DISPLAY, endingDateOfDisplay );
435         model.put( PARAMETER_STR_ENDING_DATE_OF_DISPLAY, endingDateOfDisplay.format( Utilities.getFormatter( ) ) );
436         model.put( PARAMETER_DATE_OF_DISPLAY, dateOfDisplay );
437         model.put( PARAMETER_DAY_OF_WEEK, listDayOfWeek );
438         model.put( PARAMETER_EVENTS, listSlot );
439         model.put( PARAMETER_MIN_TIME, minStartingTime );
440         model.put( PARAMETER_MAX_TIME, maxEndingTime );
441         model.put( PARAMETER_MIN_DURATION, LocalTime.MIN.plusMinutes( AppointmentUtilities.THIRTY_MINUTES ) );
442         return getPage( PROPERTY_PAGE_TITLE_MANAGE_APPOINTMENTS_CALENDAR, TEMPLATE_MANAGE_APPOINTMENTS_CALENDAR, model );
443     }
444 
445     /**
446      * Get the page to manage appointments
447      * 
448      * @param request
449      *            The request
450      * @return The HTML code to display
451      * @throws AccessDeniedException
452      * @throws SiteMessageException
453      */
454     @SuppressWarnings( "unchecked" )
455     @View( value = VIEW_MANAGE_APPOINTMENTS )
456     public String getManageAppointments( HttpServletRequest request ) throws AccessDeniedException, SiteMessageException
457     {
458         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, "0", AppointmentResourceIdService.PERMISSION_VIEW_FORM, getUser( ) ) )
459         {
460             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_VIEW_FORM );
461         }
462         String strModifDateAppointment = request.getParameter( PARAMETER_MODIF_DATE );
463         if ( strModifDateAppointment != null && Boolean.parseBoolean( strModifDateAppointment ) )
464         {
465             return getViewChangeDateAppointment( request );
466         }
467         // Clean session
468         AppointmentAsynchronousUploadHandler.getHandler( ).removeSessionFiles( request.getSession( ).getId( ) );
469         request.getSession( ).removeAttribute( SESSION_NOT_VALIDATED_APPOINTMENT );
470         request.getSession( ).removeAttribute( SESSION_VALIDATED_APPOINTMENT );
471 
472         String strIdForm = request.getParameter( PARAMETER_ID_FORM );
473         int nIdForm = Integer.parseInt( strIdForm );
474         // If it is a new search
475         if ( request.getParameter( PARAMETER_RESET ) != null )
476         {
477             request.getSession( ).removeAttribute( SESSION_APPOINTMENT_FILTER );
478             request.getSession( ).removeAttribute( SESSION_LIST_APPOINTMENTS );
479         }
480         // Get the appointment filter in session
481         AppointmentFilterDTO filter = (AppointmentFilterDTO) request.getSession( ).getAttribute( SESSION_APPOINTMENT_FILTER );
482         if ( filter == null )
483         {
484             filter = new AppointmentFilterDTO( );
485             filter.setIdForm( nIdForm );
486             // if we come from the calendar, need to get the starting and ending
487             // time of the slot
488             String strStartingDateTime = request.getParameter( PARAMETER_STARTING_DATE_TIME );
489             String strEndingDateTime = request.getParameter( PARAMETER_ENDING_DATE_TIME );
490             if ( strStartingDateTime != null && strEndingDateTime != null )
491             {
492                 LocalDateTime startingDateTime = LocalDateTime.parse( strStartingDateTime );
493                 LocalDateTime endingDateTime = LocalDateTime.parse( strEndingDateTime );
494                 filter.setStartingDateOfSearch( Date.valueOf( startingDateTime.toLocalDate( ) ) );
495                 filter.setStartingTimeOfSearch( startingDateTime.toLocalTime( ).toString( ) );
496                 filter.setEndingDateOfSearch( Date.valueOf( endingDateTime.toLocalDate( ) ) );
497                 filter.setEndingTimeOfSearch( endingDateTime.toLocalTime( ).toString( ) );
498             }
499             request.getSession( ).setAttribute( SESSION_APPOINTMENT_FILTER, filter );
500         }
501         // Get the list in session
502         // If it is an order by or a navigation page, no need to search again
503         List<AppointmentDTO> listAppointmentsDTO = (List<AppointmentDTO>) request.getSession( ).getAttribute( SESSION_LIST_APPOINTMENTS );
504         if ( listAppointmentsDTO == null )
505         {
506             listAppointmentsDTO = AppointmentService.findListAppointmentsDTOByFilter( filter );
507         }
508         // If it is a new search
509         if ( request.getParameter( PARAMETER_SEARCH ) != null )
510         {
511             // Populate the filter
512             populate( filter, request );
513             listAppointmentsDTO = AppointmentService.findListAppointmentsDTOByFilter( filter );
514         }
515         // If it is an order by
516         String strOrderBy = request.getParameter( PARAMETER_ORDER_BY );
517         String strOrderAsc = request.getParameter( PARAMETER_ORDER_ASC );
518         listAppointmentsDTO = orderList( listAppointmentsDTO, strOrderBy, strOrderAsc );
519         request.getSession( ).setAttribute( SESSION_LIST_APPOINTMENTS, listAppointmentsDTO );
520         if ( StringUtils.isNotEmpty( request.getParameter( PARAMETER_DELETE_AND_BACK ) ) )
521         {
522             String [ ] tabIdAppointmentToDelete = request.getParameterValues( PARAMETER_ID_APPOINTMENT_DELETE );
523             if ( tabIdAppointmentToDelete != null )
524             {
525                 request.getSession( ).setAttribute( PARAMETER_ID_APPOINTMENT_DELETE, tabIdAppointmentToDelete );
526                 return getConfirmRemoveMassAppointment( request, nIdForm );
527             }
528         }
529         String strCurrentPageIndex = Paginator.getPageIndex( request, Paginator.PARAMETER_PAGE_INDEX,
530                 (String) request.getSession( ).getAttribute( SESSION_CURRENT_PAGE_INDEX ) );
531         if ( strCurrentPageIndex == null )
532         {
533             strCurrentPageIndex = DEFAULT_CURRENT_PAGE;
534         }
535         request.getSession( ).setAttribute( SESSION_CURRENT_PAGE_INDEX, strCurrentPageIndex );
536         int nItemsPerPage = Paginator.getItemsPerPage( request, Paginator.PARAMETER_ITEMS_PER_PAGE,
537                 getIntSessionAttribute( request.getSession( ), SESSION_ITEMS_PER_PAGE ), _nDefaultItemsPerPage );
538         request.getSession( ).setAttribute( SESSION_ITEMS_PER_PAGE, nItemsPerPage );
539         UrlItem url = new UrlItem( JSP_MANAGE_APPOINTMENTS );
540         url.addParameter( MVCUtils.PARAMETER_VIEW, VIEW_MANAGE_APPOINTMENTS );
541         url.addParameter( PARAMETER_ID_FORM, strIdForm );
542         String strUrl = url.getUrl( );
543         LocalizedPaginator<AppointmentDTO> paginator = new LocalizedPaginator<AppointmentDTO>( listAppointmentsDTO, nItemsPerPage, strUrl,
544                 PARAMETER_PAGE_INDEX, strCurrentPageIndex, getLocale( ) );
545         AppointmentFormDTO form = FormService.buildAppointmentFormLight( nIdForm );
546         Map<String, Object> model = getModel( );
547         model.put( MARK_FORM, form );
548         model.put( MARK_FORM_MESSAGES, FormMessageService.findFormMessageByIdForm( nIdForm ) );
549         model.put( MARK_NB_ITEMS_PER_PAGE, Integer.toString( nItemsPerPage ) );
550         model.put( MARK_PAGINATOR, paginator );
551         model.put( MARK_LANGUAGE, getLocale( ) );
552         model.put( MARK_ACTIVATE_WORKFLOW, ACTIVATEWORKFLOW );
553         if ( ( form.getIdWorkflow( ) > 0 ) && WorkflowService.getInstance( ).isAvailable( ) )
554         {
555             int nIdWorkflow = form.getIdWorkflow( );
556             StateFilter stateFilter = new StateFilter( );
557             stateFilter.setIdWorkflow( nIdWorkflow );
558             for ( AppointmentDTO appointment : paginator.getPageItems( ) )
559             {
560                 State stateAppointment = _stateService.findByResource( appointment.getIdAppointment( ), Appointment.APPOINTMENT_RESOURCE_TYPE, nIdWorkflow );
561                 if ( stateAppointment != null )
562                 {
563                     appointment.setState( stateAppointment );
564                 }
565                 appointment.setListWorkflowActions( WorkflowService.getInstance( ).getActions( appointment.getIdAppointment( ),
566                         Appointment.APPOINTMENT_RESOURCE_TYPE, form.getIdWorkflow( ), getUser( ) ) );
567             }
568         }
569         AdminUser user = getUser( );
570         model.put( MARK_APPOINTMENT_LIST, paginator.getPageItems( ) );
571         model.put( MARK_FILTER, filter );
572         model.put( MARK_LIST_STATUS, getListStatus( ) );
573         model.put( MARK_RIGHT_CREATE,
574                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_CREATE_APPOINTMENT, user ) );
575         model.put( MARK_RIGHT_MODIFY,
576                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_MODIFY_APPOINTMENT, user ) );
577         model.put( MARK_RIGHT_DELETE,
578                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_DELETE_APPOINTMENT, user ) );
579         model.put( MARK_RIGHT_VIEW,
580                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_VIEW_APPOINTMENT, user ) );
581         model.put( MARK_RIGHT_CHANGE_STATUS,
582                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_CHANGE_APPOINTMENT_STATUS, user ) );
583         model.put( MARK_RIGHT_CHANGE_DATE,
584                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_CHANGE_APPOINTMENT_DATE, user ) );
585         return getPage( PROPERTY_PAGE_TITLE_MANAGE_APPOINTMENTS, TEMPLATE_MANAGE_APPOINTMENTS, model );
586     }
587 
588     /**
589      * Manages the removal form of a appointment whose identifier is in the HTTP request
590      * 
591      * @param request
592      *            The HTTP request
593      * @return the HTML code to confirm
594      */
595     @Action( ACTION_CONFIRM_REMOVE_APPOINTMENT )
596     public String getConfirmRemoveAppointment( HttpServletRequest request )
597     {
598         UrlItem url = new UrlItem( getActionUrl( ACTION_REMOVE_APPOINTMENT ) );
599         url.addParameter( PARAMETER_ID_APPOINTMENT, request.getParameter( PARAMETER_ID_APPOINTMENT ) );
600         url.addParameter( PARAMETER_ID_FORM, request.getParameter( PARAMETER_ID_FORM ) );
601         String strMessageUrl = AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRM_REMOVE_APPOINTMENT, url.getUrl( ), AdminMessage.TYPE_CONFIRMATION );
602         return redirect( request, strMessageUrl );
603     }
604 
605     /**
606      * Handles the removal form of a appointment
607      * 
608      * @param request
609      *            The HTTP request
610      * @return the JSP URL to display the form to manage appointments
611      * @throws AccessDeniedException
612      *             If the user is not authorized to access this feature
613      */
614     @SuppressWarnings( {
615         "unchecked"
616     } )
617     @Action( ACTION_REMOVE_APPOINTMENT )
618     public String doRemoveAppointment( HttpServletRequest request ) throws AccessDeniedException
619     {
620         int nIdAppointment = Integer.parseInt( request.getParameter( PARAMETER_ID_APPOINTMENT ) );
621         Integer idForm = Integer.parseInt( request.getParameter( PARAMETER_ID_FORM ) );
622         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, Integer.toString( idForm ),
623                 AppointmentResourceIdService.PERMISSION_DELETE_APPOINTMENT, getUser( ) ) )
624         {
625             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_DELETE_APPOINTMENT );
626         }
627         AppointmentService.deleteAppointment( nIdAppointment );
628         AppLogService.info( LogUtilities.buildLog( ACTION_REMOVE_APPOINTMENT, Integer.toString( nIdAppointment ), getUser( ) ) );
629         addInfo( INFO_APPOINTMENT_REMOVED, getLocale( ) );
630         // Need to update the list of the appointments in session
631         List<AppointmentDTO> listAppointmentsDTO = (List<AppointmentDTO>) request.getSession( ).getAttribute( SESSION_LIST_APPOINTMENTS );
632         if ( listAppointmentsDTO != null )
633         {
634             listAppointmentsDTO = listAppointmentsDTO.stream( ).filter( a -> a.getIdAppointment( ) != nIdAppointment ).collect( Collectors.toList( ) );
635             request.getSession( ).setAttribute( SESSION_LIST_APPOINTMENTS, listAppointmentsDTO );
636         }
637         return redirect( request, VIEW_MANAGE_APPOINTMENTS, PARAMETER_ID_FORM, idForm );
638     }
639 
640     /**
641      * Manages the removal form of a appointment whose identifier is in the HTTP request
642      * 
643      * @param request
644      *            The HTTP request
645      * @return the HTML code to confirm
646      */
647     @Action( ACTION_CONFIRM_REMOVE_MASS_APPOINTMENT )
648     public String getConfirmRemoveMassAppointment( HttpServletRequest request, int nIdForm )
649     {
650         UrlItem url = new UrlItem( getActionUrl( ACTION_REMOVE_MASSAPPOINTMENT ) );
651         url.addParameter( PARAMETER_ID_FORM, nIdForm );
652         String strMessageUrl = AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRM_REMOVE_MASSAPPOINTMENT, url.getUrl( ),
653                 AdminMessage.TYPE_CONFIRMATION );
654         return redirect( request, strMessageUrl );
655     }
656 
657     /**
658      * Handles the removal form of a appointment
659      * 
660      * @param request
661      *            The HTTP request
662      * @return the JSP URL to display the form to manage appointments
663      * @throws AccessDeniedException
664      *             If the user is not authorized to access this feature
665      */
666     @SuppressWarnings( "unchecked" )
667     @Action( ACTION_REMOVE_MASSAPPOINTMENT )
668     public String doRemoveMassAppointment( HttpServletRequest request ) throws AccessDeniedException
669     {
670         String [ ] tabIdAppointmentToDelete = (String [ ]) request.getSession( ).getAttribute( PARAMETER_ID_APPOINTMENT_DELETE );
671         request.getSession( ).removeAttribute( PARAMETER_ID_APPOINTMENT_DELETE );
672         Integer idForm = Integer.parseInt( request.getParameter( PARAMETER_ID_FORM ) );
673         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, Integer.toString( idForm ),
674                 AppointmentResourceIdService.PERMISSION_DELETE_APPOINTMENT, getUser( ) ) )
675         {
676             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_DELETE_APPOINTMENT );
677         }
678         ArrayList<String> listStringIdAppointment = new ArrayList<>( );
679         if ( tabIdAppointmentToDelete != null )
680         {
681             for ( String strIdAppointment : tabIdAppointmentToDelete )
682             {
683                 AppointmentService.deleteAppointment( Integer.valueOf( strIdAppointment ) );
684                 AppLogService.info( LogUtilities.buildLog( ACTION_REMOVE_APPOINTMENT, strIdAppointment, getUser( ) ) );
685             }
686             addInfo( INFO_APPOINTMENT_MASSREMOVED, getLocale( ) );
687             listStringIdAppointment.addAll( Arrays.asList( tabIdAppointmentToDelete ) );
688         }
689         // Need to update the list of the appointments in session
690         List<AppointmentDTO> listAppointmentsDTO = (List<AppointmentDTO>) request.getSession( ).getAttribute( SESSION_LIST_APPOINTMENTS );
691         if ( listAppointmentsDTO != null )
692         {
693             listAppointmentsDTO = listAppointmentsDTO.stream( ).filter( a -> !listStringIdAppointment.contains( Integer.toString( a.getIdAppointment( ) ) ) )
694                     .collect( Collectors.toList( ) );
695             request.getSession( ).setAttribute( SESSION_LIST_APPOINTMENTS, listAppointmentsDTO );
696         }
697         return redirect( request, VIEW_MANAGE_APPOINTMENTS, PARAMETER_ID_FORM, idForm );
698     }
699 
700     /**
701      * View details of an appointment
702      * 
703      * @param request
704      *            The request
705      * @return The HTML content to display
706      * @throws AccessDeniedException
707      *             If the user is not authorized to access this feature
708      */
709     @View( VIEW_VIEW_APPOINTMENT )
710     public String getViewAppointment( HttpServletRequest request ) throws AccessDeniedException
711     {
712         String strIdAppointment = request.getParameter( PARAMETER_ID_APPOINTMENT );
713         String strIdForm = request.getParameter( PARAMETER_ID_FORM );
714         int nIdForm = Integer.parseInt( strIdForm );
715         Form form = FormService.findFormLightByPrimaryKey( nIdForm );
716         int nItemsPerPage = Paginator.getItemsPerPage( request, Paginator.PARAMETER_ITEMS_PER_PAGE,
717                 getIntSessionAttribute( request.getSession( ), SESSION_ITEMS_PER_PAGE ), _nDefaultItemsPerPage );
718         int nIdAppointment = Integer.parseInt( strIdAppointment );
719         AppointmentDTO appointmentDTO = AppointmentService.buildAppointmentDTOFromIdAppointment( nIdAppointment );
720         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_VIEW_APPOINTMENT, getUser( ) ) )
721         {
722             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_VIEW_APPOINTMENT );
723         }
724         Map<String, Object> model = getModel( );
725         model.put( MARK_APPOINTMENT, appointmentDTO );
726         model.put( MARK_FORM_MESSAGES, FormMessageService.findFormMessageByIdForm( nIdForm ) );
727         model.put( MARK_FORM, form );
728         model.put( MARK_NB_ITEMS_PER_PAGE, Integer.toString( nItemsPerPage ) );
729         if ( ( form.getIdWorkflow( ) > 0 ) && WorkflowService.getInstance( ).isAvailable( ) )
730         {
731             model.put(
732                     MARK_RESOURCE_HISTORY,
733                     WorkflowService.getInstance( ).getDisplayDocumentHistory( nIdAppointment, Appointment.APPOINTMENT_RESOURCE_TYPE, form.getIdWorkflow( ),
734                             request, getLocale( ) ) );
735         }
736         if ( ( form.getIdWorkflow( ) > 0 ) && WorkflowService.getInstance( ).isAvailable( ) )
737         {
738             int nIdWorkflow = form.getIdWorkflow( );
739             StateFilter stateFilter = new StateFilter( );
740             stateFilter.setIdWorkflow( nIdWorkflow );
741             State stateAppointment = _stateService.findByResource( appointmentDTO.getIdAppointment( ), Appointment.APPOINTMENT_RESOURCE_TYPE, nIdWorkflow );
742             if ( stateAppointment != null )
743             {
744                 appointmentDTO.setState( stateAppointment );
745             }
746             appointmentDTO.setListWorkflowActions( WorkflowService.getInstance( ).getActions( appointmentDTO.getIdAppointment( ),
747                     Appointment.APPOINTMENT_RESOURCE_TYPE, form.getIdWorkflow( ), getUser( ) ) );
748         }
749         Locale locale = getLocale( );
750         List<Response> listResponse = AppointmentResponseService.findListResponse( nIdAppointment );
751         for ( Response response : listResponse )
752         {
753             if ( response.getFile( ) != null )
754             {
755                 response.setFile( FileHome.findByPrimaryKey( response.getFile( ).getIdFile( ) ) );
756             }
757             if ( response.getEntry( ) != null )
758             {
759                 response.setEntry( EntryHome.findByPrimaryKey( response.getEntry( ).getIdEntry( ) ) );
760             }
761         }
762         appointmentDTO.setListResponse( listResponse );
763         model.put( MARK_LIST_RESPONSE_RECAP_DTO, AppointmentUtilities.buildListResponse( appointmentDTO, request, locale ) );
764         model.put( MARK_ADDON, AppointmentAddOnManager.getAppointmentAddOn( appointmentDTO.getIdAppointment( ), getLocale( ) ) );
765         AdminUser user = getUser( );
766         model.put( MARK_RIGHT_CREATE,
767                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_CREATE_APPOINTMENT, user ) );
768         model.put( MARK_RIGHT_MODIFY,
769                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_MODIFY_APPOINTMENT, user ) );
770         model.put( MARK_RIGHT_DELETE,
771                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_DELETE_APPOINTMENT, user ) );
772         model.put( MARK_RIGHT_VIEW,
773                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_VIEW_APPOINTMENT, user ) );
774         model.put( MARK_RIGHT_CHANGE_STATUS,
775                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_CHANGE_APPOINTMENT_STATUS, user ) );
776         model.put( MARK_RIGHT_CHANGE_DATE,
777                 RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_CHANGE_APPOINTMENT_DATE, user ) );
778         model.put( MARK_LANGUAGE, getLocale( ) );
779         model.put( MARK_ACTIVATE_WORKFLOW, ACTIVATEWORKFLOW );
780         return getPage( PROPERTY_PAGE_TITLE_VIEW_APPOINTMENT, TEMPLATE_VIEW_APPOINTMENT, model );
781     }
782 
783     /**
784      * Do download a file from an appointment response
785      * 
786      * @param request
787      *            The request
788      * @param response
789      *            The response
790      * @return nothing.
791      * @throws AccessDeniedException
792      *             If the user is not authorized to access this feature
793      */
794     @SuppressWarnings( "unchecked" )
795     public String getDownloadFileAppointment( HttpServletRequest request, HttpServletResponse response ) throws AccessDeniedException
796     {
797         String strIdForm = request.getParameter( PARAMETER_ID_FORM );
798         if ( StringUtils.isEmpty( strIdForm ) || !StringUtils.isNumeric( strIdForm ) )
799         {
800             return redirect( request, AppointmentFormJspBean.getURLManageAppointmentForms( request ) );
801         }
802         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_VIEW_APPOINTMENT, getUser( ) ) )
803         {
804             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_VIEW_APPOINTMENT );
805         }
806         Locale locale = getLocale( );
807         List<AppointmentDTO> listAppointmentsDTO = (List<AppointmentDTO>) request.getSession( ).getAttribute( SESSION_LIST_APPOINTMENTS );
808         if ( listAppointmentsDTO.size( ) > AppPropertiesService.getPropertyInt( PROPERTY_NB_MAX_APPOINTMENTS_TO_EXPORT, MAX_NB_APPOINTMENTS_TO_EXPORT ) )
809         {
810             addError( ERROR_MESSAGE_NB_MAX_APPOINTMENTS_FOR_EXPORT, locale );
811             UrlItem urlItem = new UrlItem( AppPathService.getBaseUrl( request ) + JSP_MANAGE_APPOINTMENTS );
812             urlItem.addParameter( MVCUtils.PARAMETER_VIEW, VIEW_MANAGE_APPOINTMENTS );
813             urlItem.addParameter( PARAMETER_ID_FORM, strIdForm );
814             return redirect( request, urlItem.getUrl( ) );
815         }
816         else
817         {
818             AppointmentUtilities.buildExcelFileWithAppointments( strIdForm, response, locale, listAppointmentsDTO, _stateService );
819         }
820         return null;
821     }
822 
823     /**
824      * Get the page to modify an appointment
825      * 
826      * @param request
827      *            The request
828      * @return The HTML content to display or the next URL to redirect to
829      * @throws AccessDeniedException
830      *             If the user is not authorized to access this feature
831      */
832     @View( VIEW_MODIFY_APPOINTMENT )
833     public String getModifyAppointment( HttpServletRequest request ) throws AccessDeniedException
834     {
835         HttpSession session = request.getSession( );
836         clearUploadFilesIfNeeded( session );
837         String strIdAppointment = request.getParameter( PARAMETER_ID_APPOINTMENT );
838         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdAppointment, AppointmentResourceIdService.PERMISSION_MODIFY_APPOINTMENT,
839                 getUser( ) ) )
840         {
841             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_MODIFY_APPOINTMENT );
842         }
843         int nIdAppointment = Integer.parseInt( strIdAppointment );
844         AppointmentDTO appointmentDTO = AppointmentService.buildAppointmentDTOFromIdAppointment( nIdAppointment );
845         appointmentDTO.setListResponse( AppointmentResponseService.findAndBuildListResponse( nIdAppointment, request ) );
846         appointmentDTO.setMapResponsesByIdEntry( AppointmentResponseService.buildMapFromListResponse( appointmentDTO.getListResponse( ) ) );
847         session.removeAttribute( SESSION_NOT_VALIDATED_APPOINTMENT );
848         Slot slot = appointmentDTO.getSlot( );
849         int nIdForm = slot.getIdForm( );
850         LocalDate dateOfSlot = slot.getDate( );
851         ReservationRule reservationRule = ReservationRuleService.findReservationRuleByIdFormAndClosestToDateOfApply( nIdForm, dateOfSlot );
852         WeekDefinition weekDefinition = WeekDefinitionService.findWeekDefinitionByIdFormAndClosestToDateOfApply( nIdForm, dateOfSlot );
853         AppointmentFormDTO form = FormService.buildAppointmentForm( nIdForm, reservationRule.getIdReservationRule( ), weekDefinition.getIdWeekDefinition( ) );
854         request.getSession( ).setAttribute( SESSION_ATTRIBUTE_APPOINTMENT_FORM, form );
855 
856         int nbAlreadyBookedSeats = appointmentDTO.getNbBookedSeats( );
857         int nbMaxPeoplePerAppointment = form.getMaxPeoplePerAppointment( );
858         if ( ( nbAlreadyBookedSeats < nbMaxPeoplePerAppointment ) && ( slot.getNbPotentialRemainingPlaces( ) > 0 ) )
859         {
860             SlotEditTask slotEditTask = new SlotEditTask( );
861             int nbPotentialPlacesToTake = form.getMaxPeoplePerAppointment( ) - nbAlreadyBookedSeats;
862             int nbPotentialRemainingPlaces = slot.getNbPotentialRemainingPlaces( );
863             appointmentDTO.setNbMaxPotentialBookedSeats( nbAlreadyBookedSeats + nbPotentialPlacesToTake );
864             slot.setNbPotentialRemainingPlaces( nbPotentialRemainingPlaces - nbPotentialPlacesToTake );
865             SlotService.updateSlot( slot );
866             slotEditTask.setNbPlacesTaken( nbPotentialPlacesToTake );
867             slotEditTask.setIdSlot( slot.getIdSlot( ) );
868             TimerForLockOnSlot timer = new TimerForLockOnSlot( );
869             long delay = TimeUnit.MINUTES.toMillis( AppPropertiesService
870                     .getPropertyInt( AppointmentUtilities.PROPERTY_DEFAULT_EXPIRED_TIME_EDIT_APPOINTMENT, 1 ) );
871             timer.schedule( slotEditTask, delay );
872             request.getSession( ).setAttribute( AppointmentUtilities.SESSION_TIMER_SLOT, timer );
873         }
874         else
875         {
876             appointmentDTO.setNbMaxPotentialBookedSeats( nbAlreadyBookedSeats );
877         }
878         session.setAttribute( SESSION_NOT_VALIDATED_APPOINTMENT, appointmentDTO );
879         return getViewCreateAppointment( request );
880     }
881 
882     /**
883      * Returns the form to create an appointment
884      * 
885      * @param request
886      *            The HTTP request
887      * @return the HTML code of the appointment form
888      * @throws AccessDeniedException
889      *             If the user is not authorized to access this feature
890      */
891     @SuppressWarnings( "unchecked" )
892     @View( VIEW_CREATE_APPOINTMENT )
893     public String getViewCreateAppointment( HttpServletRequest request ) throws AccessDeniedException
894     {
895         clearUploadFilesIfNeeded( request.getSession( ) );
896         String strIdForm = request.getParameter( PARAMETER_ID_FORM );
897         int nIdForm = Integer.parseInt( strIdForm );
898         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_CREATE_APPOINTMENT, getUser( ) ) )
899         {
900             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_CREATE_APPOINTMENT );
901         }
902         AppointmentFormDTO form = (AppointmentFormDTO) request.getSession( ).getAttribute( SESSION_ATTRIBUTE_APPOINTMENT_FORM );
903         // Get the not validated appointment in session if it exists
904         AppointmentDTO appointmentDTO = (AppointmentDTO) request.getSession( ).getAttribute( SESSION_NOT_VALIDATED_APPOINTMENT );
905         Locale locale = getLocale( );
906         if ( appointmentDTO == null )
907         {
908             appointmentDTO = (AppointmentDTO) request.getSession( ).getAttribute( SESSION_VALIDATED_APPOINTMENT );
909             if ( appointmentDTO != null )
910             {
911                 request.getSession( ).setAttribute( SESSION_NOT_VALIDATED_APPOINTMENT, appointmentDTO );
912                 request.getSession( ).removeAttribute( SESSION_VALIDATED_APPOINTMENT );
913             }
914             else
915             {
916                 Slot slot = null;
917                 int nIdSlot = Integer.parseInt( request.getParameter( PARAMETER_ID_SLOT ) );
918                 appointmentDTO = new AppointmentDTO( );
919                 if ( nIdSlot == 0 )
920                 {
921                     // Need to get all the informations to create the slot
922                     LocalDateTime startingDateTime = LocalDateTime.parse( request.getParameter( PARAMETER_STARTING_DATE_TIME ) );
923                     LocalDateTime endingDateTime = LocalDateTime.parse( request.getParameter( PARAMETER_ENDING_DATE_TIME ) );
924                     // Need to check if the slot has not been already created
925                     HashMap<LocalDateTime, Slot> slotInDbMap = SlotService.buildMapSlotsByIdFormAndDateRangeWithDateForKey( nIdForm, startingDateTime,
926                             endingDateTime );
927                     if ( !slotInDbMap.isEmpty( ) )
928                     {
929                         slot = slotInDbMap.get( startingDateTime );
930                     }
931                     else
932                     {
933                         boolean bIsOpen = Boolean.parseBoolean( request.getParameter( PARAMETER_IS_OPEN ) );
934                         boolean bIsSpecific = Boolean.parseBoolean( request.getParameter( PARAMETER_IS_SPECIFIC ) );
935                         int nMaxCapacity = Integer.parseInt( request.getParameter( PARAMETER_MAX_CAPACITY ) );
936                         slot = SlotService.buildSlot( nIdForm, new Period( startingDateTime, endingDateTime ), nMaxCapacity, nMaxCapacity, nMaxCapacity, 0,
937                                 bIsOpen, bIsSpecific );
938                         slot = SlotService.saveSlot( slot );
939                     }
940                 }
941                 else
942                 {
943                     slot = SlotService.findSlotById( nIdSlot );
944                 }
945                 // Need to check competitive access
946                 // May be the slot is already taken at the same time
947                 if ( slot.getNbPotentialRemainingPlaces( ) == 0 )
948                 {
949                     addInfo( ERROR_MESSAGE_SLOT_FULL, locale );
950                     return redirect( request, VIEW_CALENDAR_MANAGE_APPOINTMENTS, PARAMETER_ID_FORM, nIdForm );
951                 }
952                 appointmentDTO.setSlot( slot );
953                 appointmentDTO.setIdForm( nIdForm );
954                 LuteceUser user = SecurityService.getInstance( ).getRegisteredUser( request );
955                 if ( user != null )
956                 {
957                     Map<String, String> map = user.getUserInfos( );
958                     appointmentDTO.setEmail( map.get( PROPERTY_USER_EMAIL ) );
959                     appointmentDTO.setFirstName( map.get( PROPERTY_USER_FIRST_NAME ) );
960                     appointmentDTO.setLastName( map.get( PROPERTY_USER_LAST_NAME ) );
961                 }
962                 request.getSession( ).setAttribute( SESSION_NOT_VALIDATED_APPOINTMENT, appointmentDTO );
963                 ReservationRule reservationRule = ReservationRuleService.findReservationRuleByIdFormAndClosestToDateOfApply( nIdForm, slot.getDate( ) );
964                 WeekDefinition weekDefinition = WeekDefinitionService.findWeekDefinitionByIdFormAndClosestToDateOfApply( nIdForm, slot.getDate( ) );
965                 form = FormService.buildAppointmentForm( nIdForm, reservationRule.getIdReservationRule( ), weekDefinition.getIdWeekDefinition( ) );
966                 request.getSession( ).setAttribute( SESSION_ATTRIBUTE_APPOINTMENT_FORM, form );
967                 AppointmentUtilities.putTimerInSession( request, slot, appointmentDTO, form.getMaxPeoplePerAppointment( ) );
968 
969             }
970         }
971         Map<String, Object> model = getModel( );
972         List<GenericAttributeError> listErrors = (List<GenericAttributeError>) request.getSession( ).getAttribute( SESSION_APPOINTMENT_FORM_ERRORS );
973         List<Entry> listEntryFirstLevel = EntryService.getFilter( form.getIdForm( ), true );
974         StringBuffer strBuffer = new StringBuffer( );
975         for ( Entry entry : listEntryFirstLevel )
976         {
977             EntryService.getHtmlEntry( model, entry.getIdEntry( ), strBuffer, locale, false, request );
978             // generic error message for debut montage and fin demontage
979             if ( CollectionUtils.isNotEmpty( listErrors ) && ( StringUtils.contains( entry.getTitle( ), LABEL_MONTAGE ) || StringUtils.contains( entry.getTitle( ), LABEL_DEMONTAGE ) ) )
980             {
981                 for ( GenericAttributeError error : listErrors )
982                 {
983                     if ( !error.isMandatoryError( ) && entry.getTitle( ).equals( error.getTitleQuestion( ) ) )
984                     {
985                         strBuffer.append("<div class=\"alert alert-error alert-danger\"><p>" + error.getErrorMessage( ) + "</p></div>");
986                     }
987                 }
988             }
989             // specific error message depending selected slot
990             if ( StringUtils.contains( entry.getTitle( ), LABEL_DEMONTAGE ) && AppointmentUtilities.isSlotAM( appointmentDTO.getSlot( ) )  )
991             {
992                 // error message for slot AM
993                 model.put( MARK_HORAIRE_ID_ENTRY, entry.getIdEntry( ) );
994                 strBuffer.append( "<div id=\"errorHoraireAM\" style=\"display:none\" class=\"alert alert-error alert-danger\">" + I18nService.getLocalizedString( ERROR_MESSAGE_HORAIRE_BO, request.getLocale( ) ) + "</div>" );
995             } else if ( StringUtils.contains( entry.getTitle( ), LABEL_MONTAGE ) && !AppointmentUtilities.isSlotAM( appointmentDTO.getSlot( ) ) )
996             {
997                 // error message for slot PM
998                 model.put( MARK_HORAIRE_ID_ENTRY, entry.getIdEntry( ) );
999                 strBuffer.append( "<div id=\"errorHorairePM\" style=\"display:none\" class=\"alert alert-error alert-danger\">" + I18nService.getLocalizedString( ERROR_MESSAGE_HORAIRE_BO, request.getLocale( ) ) + "</div>" );
1000             }
1001         }
1002         model.put( MARK_HORAIRE_MAX_AM, horaireMaxAM );
1003         model.put( MARK_HORAIRE_MIN_PM, horaireMinPM );
1004         model.put( MARK_STR_ENTRY, strBuffer.toString( ) );
1005         model.put( MARK_FORM, form );
1006         model.put( MARK_APPOINTMENT, appointmentDTO );
1007         model.put( PARAMETER_DATE_OF_DISPLAY, appointmentDTO.getSlot( ).getDate( ) );
1008         model.put( MARK_PLACES, appointmentDTO.getNbMaxPotentialBookedSeats( ) );
1009         FormMessage formMessages = FormMessageService.findFormMessageByIdForm( nIdForm );
1010         model.put( MARK_FORM_MESSAGES, formMessages );
1011         model.put( MARK_LOCALE, locale );
1012         model.put( MARK_FORM_ERRORS, listErrors );
1013         model.put( MARK_LIST_ERRORS, AppointmentDTO.getAllErrors( locale ) );
1014         HtmlTemplate templateForm = AppTemplateService.getTemplate( TEMPLATE_HTML_CODE_FORM_ADMIN, getLocale( ), model );
1015         model.put( MARK_FORM_HTML, templateForm.getHtml( ) );
1016         if ( listErrors != null )
1017         {
1018             model.put( MARK_FORM_ERRORS, listErrors );
1019             request.getSession( ).removeAttribute( SESSION_APPOINTMENT_FORM_ERRORS );
1020         }
1021         return getPage( PROPERTY_PAGE_TITLE_CREATE_APPOINTMENT, TEMPLATE_CREATE_APPOINTMENT, model );
1022     }
1023 
1024     /**
1025      * Do validate data entered by a user to fill a form
1026      * 
1027      * @param request
1028      *            The request
1029      * @return The next URL to redirect to
1030      * @throws AccessDeniedException
1031      *             If the user is not authorized to access this feature
1032      * @throws SiteMessageExcamoreption
1033      */
1034     @Action( ACTION_DO_VALIDATE_FORM )
1035     public String doValidateForm( HttpServletRequest request ) throws AccessDeniedException, SiteMessageException
1036     {
1037         String strIdForm = request.getParameter( PARAMETER_ID_FORM );
1038         int nIdForm = Integer.parseInt( strIdForm );
1039         AppointmentFormDTO form = (AppointmentFormDTO) request.getSession( ).getAttribute( SESSION_ATTRIBUTE_APPOINTMENT_FORM );
1040         AppointmentDTO appointmentDTO = (AppointmentDTO) request.getSession( ).getAttribute( SESSION_NOT_VALIDATED_APPOINTMENT );
1041         String strEmail = request.getParameter( PARAMETER_EMAIL );
1042         List<GenericAttributeError> listFormErrors = new ArrayList<GenericAttributeError>( );
1043         Locale locale = request.getLocale( );
1044         AppointmentUtilities.checkDateOfTheAppointmentIsNotBeforeNow( appointmentDTO, locale, listFormErrors );
1045         AppointmentUtilities.checkEmail( strEmail, request.getParameter( PARAMETER_EMAIL_CONFIRMATION ), form, locale, listFormErrors );
1046         int nbBookedSeats = AppointmentUtilities.checkAndReturnNbBookedSeats( request.getParameter( PARAMETER_NUMBER_OF_BOOKED_SEATS ), form, appointmentDTO,
1047                 locale, listFormErrors );
1048         AppointmentUtilities.fillAppointmentDTO( appointmentDTO, nbBookedSeats, strEmail, request.getParameter( PARAMETER_FIRST_NAME ),
1049                 request.getParameter( PARAMETER_LAST_NAME ) );
1050         AppointmentUtilities.validateFormAndEntries( appointmentDTO, request, listFormErrors );
1051         AppointmentUtilities.fillInListResponseWithMapResponse( appointmentDTO );
1052 
1053         List<Response> responses = appointmentDTO.getListResponse( );
1054 
1055         Response responseMontage = null;
1056         Response responseDemontage = null;
1057         Response responseTypeAnimation = null;
1058         for ( Response response : responses )
1059         {
1060             Entry entry = response.getEntry( );
1061             if ( StringUtils.contains( entry.getTitle( ), LABEL_MONTAGE ) )
1062             {
1063                 responseMontage = response;
1064             }
1065             if ( StringUtils.contains( entry.getTitle( ), LABEL_DEMONTAGE ) )
1066             {
1067                 responseDemontage = response;
1068             }
1069             if ( StringUtils.contains( entry.getTitle( ), LABEL_TYPE_ANIMATION) )
1070             {
1071                 responseTypeAnimation = response;
1072             }
1073         }
1074 
1075         if ( responseMontage != null && responseDemontage != null )
1076         {
1077             SimpleDateFormat sdf = new SimpleDateFormat( "HHmm" );
1078 
1079             java.util.Date dateMontage = null;
1080             java.util.Date dateDemontage = null;
1081             try
1082             {
1083                 // montage
1084                 String heureMontage = responseMontage.getToStringValueResponse( ).replaceAll("(?i)h", "");
1085                 if ( heureMontage != null && heureMontage.length() == 3 )
1086                 {
1087                     heureMontage = "0" + heureMontage;
1088                 }
1089                 dateMontage = sdf.parse( heureMontage );
1090                 // demontage
1091                 String heureDemontage = responseDemontage.getToStringValueResponse( ).replaceAll("(?i)h", "");
1092                 if ( heureDemontage != null && heureDemontage.length() == 3 )
1093                 {
1094                     heureDemontage = "0" + heureDemontage;
1095                 }
1096                 dateDemontage = sdf.parse( heureDemontage );
1097             } catch ( ParseException e )
1098             {
1099                 AppLogService.error( "Parsing error", e );
1100             }
1101 
1102             if ( dateMontage != null && dateDemontage != null && responseTypeAnimation != null )
1103             {
1104                 String typeAnimation = responseTypeAnimation.getToStringValueResponse( );
1105                 // Validation de l'amplitude horaire
1106                 if ( ArrayUtils.contains( animations, typeAnimation ) && amplitude != NumberUtils.INTEGER_MINUS_ONE )
1107                 {
1108                     long minutes = TimeUnit.MILLISECONDS.toMinutes( dateDemontage.getTime( ) - dateMontage.getTime( ) );
1109                     if ( minutes > amplitude )
1110                     {
1111                         GenericAttributeError error = new GenericAttributeError( );
1112                         error.setTitleQuestion( responseDemontage.getEntry( ).getTitle( ) );
1113                         error.setErrorMessage( I18nService.getLocalizedString( ERROR_MESSAGE_AMPLITUDE, request.getLocale( ) ) );
1114                         error.setIsDisplayableError( Boolean.TRUE );
1115                         listFormErrors.add( error );
1116                     }
1117                 }
1118 
1119             }
1120         }
1121 
1122         if ( CollectionUtils.isNotEmpty( listFormErrors ) )
1123         {
1124             request.getSession( ).setAttribute( SESSION_APPOINTMENT_FORM_ERRORS, listFormErrors );
1125             return redirect( request, VIEW_CREATE_APPOINTMENT, PARAMETER_ID_FORM, nIdForm, PARAMETER_ID_SLOT, appointmentDTO.getSlot( ).getIdSlot( ) );
1126         }
1127         request.getSession( ).removeAttribute( SESSION_NOT_VALIDATED_APPOINTMENT );
1128         request.getSession( ).setAttribute( SESSION_VALIDATED_APPOINTMENT, appointmentDTO );
1129         return redirect( request, VIEW_DISPLAY_RECAP_APPOINTMENT, PARAMETER_ID_FORM, nIdForm );
1130     }
1131 
1132     /**
1133      * Return to the display recap view with the new date selected on the calendar
1134      * 
1135      * @param request
1136      *            the request
1137      * @return to the display recap view
1138      * @throws AccessDeniedException
1139      * @throws SiteMessageException
1140      */
1141     @View( VIEW_CHANGE_DATE_APPOINTMENT )
1142     public String getViewChangeDateAppointment( HttpServletRequest request ) throws AccessDeniedException, SiteMessageException
1143     {
1144         String strIdForm = request.getParameter( PARAMETER_ID_FORM );
1145         int nIdForm = Integer.parseInt( strIdForm );
1146         if ( !RBACService
1147                 .isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_CHANGE_APPOINTMENT_DATE, getUser( ) ) )
1148         {
1149             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_CHANGE_APPOINTMENT_DATE );
1150         }
1151         AppointmentDTO appointmentDTO = (AppointmentDTO) request.getSession( ).getAttribute( SESSION_VALIDATED_APPOINTMENT );
1152         int nIdSlot = Integer.parseInt( request.getParameter( PARAMETER_ID_SLOT ) );
1153         Slot slot = null;
1154         // If nIdSlot == 0, the slot has not been created yet
1155         if ( nIdSlot == 0 )
1156         {
1157             // Need to get all the informations to create the slot
1158             LocalDateTime startingDateTime = LocalDateTime.parse( request.getParameter( PARAMETER_STARTING_DATE_TIME ) );
1159             LocalDateTime endingDateTime = LocalDateTime.parse( request.getParameter( PARAMETER_ENDING_DATE_TIME ) );
1160             // Need to check if the slot has not been already created
1161             HashMap<LocalDateTime, Slot> slotInDbMap = SlotService.buildMapSlotsByIdFormAndDateRangeWithDateForKey( nIdForm, startingDateTime, endingDateTime );
1162             if ( !slotInDbMap.isEmpty( ) )
1163             {
1164                 slot = slotInDbMap.get( startingDateTime );
1165             }
1166             else
1167             {
1168                 boolean bIsOpen = Boolean.parseBoolean( request.getParameter( PARAMETER_IS_OPEN ) );
1169                 boolean bIsSpecific = Boolean.parseBoolean( request.getParameter( PARAMETER_IS_SPECIFIC ) );
1170                 int nMaxCapacity = Integer.parseInt( request.getParameter( PARAMETER_MAX_CAPACITY ) );
1171                 slot = SlotService.buildSlot( nIdForm, new Period( startingDateTime, endingDateTime ), nMaxCapacity, nMaxCapacity, nMaxCapacity, 0, bIsOpen,
1172                         bIsSpecific );
1173                 slot = SlotService.saveSlot( slot );
1174             }
1175         }
1176         else
1177         {
1178             slot = SlotService.findSlotById( nIdSlot );
1179         }
1180         appointmentDTO.setSlot( slot );
1181         appointmentDTO.setDateOfTheAppointment( slot.getStartingDateTime( ).toLocalDate( ).format( Utilities.getFormatter( ) ) );
1182         request.getSession( ).setAttribute( SESSION_VALIDATED_APPOINTMENT, appointmentDTO );
1183         LocalDate dateOfSlot = slot.getDate( );
1184         ReservationRule reservationRule = ReservationRuleService.findReservationRuleByIdFormAndClosestToDateOfApply( nIdForm, dateOfSlot );
1185         WeekDefinition weekDefinition = WeekDefinitionService.findWeekDefinitionByIdFormAndClosestToDateOfApply( nIdForm, dateOfSlot );
1186         AppointmentFormDTO form = FormService.buildAppointmentForm( nIdForm, reservationRule.getIdReservationRule( ), weekDefinition.getIdWeekDefinition( ) );
1187         request.getSession( ).setAttribute( SESSION_ATTRIBUTE_APPOINTMENT_FORM, form );
1188         AppointmentUtilities.putTimerInSession( request, slot, appointmentDTO, form.getMaxPeoplePerAppointment( ) );
1189         Map<String, String> additionalParameters = new HashMap<>( );
1190         additionalParameters.put( PARAMETER_ID_FORM, Integer.toString( form.getIdForm( ) ) );
1191         additionalParameters.put( PARAMETER_COME_FROM_CALENDAR, Boolean.TRUE.toString( ) );
1192         return redirect( request, VIEW_DISPLAY_RECAP_APPOINTMENT, additionalParameters );
1193     }
1194 
1195     /**
1196      * Display the recap before validating an appointment
1197      * 
1198      * @param request
1199      *            The request
1200      * @return The HTML content to display or the next URL to redirect to
1201      */
1202     @View( VIEW_DISPLAY_RECAP_APPOINTMENT )
1203     public String displayRecapAppointment( HttpServletRequest request )
1204     {
1205         AppointmentDTO appointmentDTO = (AppointmentDTO) request.getSession( ).getAttribute( SESSION_VALIDATED_APPOINTMENT );
1206         AppointmentFormDTO form = (AppointmentFormDTO) request.getSession( ).getAttribute( SESSION_ATTRIBUTE_APPOINTMENT_FORM );
1207 
1208         Map<String, Object> model = new HashMap<String, Object>( );
1209         String strComeFromCalendar = request.getParameter( PARAMETER_COME_FROM_CALENDAR );
1210         if ( StringUtils.isNotEmpty( strComeFromCalendar ) )
1211         {
1212             model.put( PARAMETER_COME_FROM_CALENDAR, strComeFromCalendar );
1213             model.put( PARAMETER_DATE_OF_DISPLAY, appointmentDTO.getSlot( ).getDate( ) );
1214         }
1215         model.put( MARK_FORM_MESSAGES, FormMessageService.findFormMessageByIdForm( appointmentDTO.getIdForm( ) ) );
1216         fillCommons( model );
1217         model.put( MARK_APPOINTMENT, appointmentDTO );
1218         Locale locale = getLocale( );
1219         model.put( MARK_ADDON, AppointmentAddOnManager.getAppointmentAddOn( appointmentDTO.getIdAppointment( ), getLocale( ) ) );
1220         model.put( MARK_LIST_RESPONSE_RECAP_DTO, AppointmentUtilities.buildListResponse( appointmentDTO, request, locale ) );
1221         model.put( MARK_FORM, form );
1222         return getPage( PROPERTY_PAGE_TITLE_RECAP_APPOINTMENT, TEMPLATE_APPOINTMENT_FORM_RECAP, model );
1223     }
1224 
1225     /**
1226      * Do save an appointment into the database if it is valid
1227      * 
1228      * @param request
1229      *            The request
1230      * @return The XPage to display
1231      * @throws AccessDeniedException
1232      *             If the user is not authorized to access this feature
1233      */
1234     @Action( ACTION_DO_MAKE_APPOINTMENT )
1235     public String doMakeAppointment( HttpServletRequest request ) throws AccessDeniedException
1236     {
1237         AppointmentDTO appointmentDTO = (AppointmentDTO) request.getSession( ).getAttribute( SESSION_VALIDATED_APPOINTMENT );
1238         if ( StringUtils.isNotEmpty( request.getParameter( PARAMETER_BACK ) ) )
1239         {
1240             return redirect( request, VIEW_CREATE_APPOINTMENT, PARAMETER_ID_FORM, appointmentDTO.getIdForm( ) );
1241         }
1242         AppointmentFormDTO form = (AppointmentFormDTO) request.getSession( ).getAttribute( SESSION_ATTRIBUTE_APPOINTMENT_FORM );
1243         if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, Integer.toString( form.getIdForm( ) ),
1244                 AppointmentResourceIdService.PERMISSION_CREATE_APPOINTMENT, getUser( ) ) )
1245         {
1246             throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_CREATE_APPOINTMENT );
1247         }
1248         Slot slot = null;
1249         // Reload the slot from the database
1250         // The slot could have been taken since the beginning of the entry of
1251         // the form
1252         if ( appointmentDTO.getSlot( ).getIdSlot( ) != 0 )
1253         {
1254             slot = SlotService.findSlotById( appointmentDTO.getSlot( ).getIdSlot( ) );
1255         }
1256         else
1257         {
1258             HashMap<LocalDateTime, Slot> mapSlot = SlotService.buildMapSlotsByIdFormAndDateRangeWithDateForKey( appointmentDTO.getIdForm( ), appointmentDTO
1259                     .getSlot( ).getStartingDateTime( ), appointmentDTO.getSlot( ).getEndingDateTime( ) );
1260             if ( !mapSlot.isEmpty( ) )
1261             {
1262                 slot = mapSlot.get( appointmentDTO.getSlot( ).getStartingDateTime( ) );
1263             }
1264             else
1265             {
1266                 slot = appointmentDTO.getSlot( );
1267             }
1268         }
1269         appointmentDTO.setSlot( slot );
1270         SlotService.addDateAndTimeToSlot( slot );
1271         // If it's a modification need to get the old number of booked seats
1272         // if the reservation is on the same slot, if not, the check has been
1273         // already done before
1274         if ( appointmentDTO.getIdAppointment( ) != 0 )
1275         {
1276             // If it's a modification of the date of the appointment
1277             if ( appointmentDTO.getSlot( ).getIdSlot( ) != appointmentDTO.getIdSlot( ) )
1278             {
1279                 List<String> listMessages = AppointmentListenerManager.notifyListenersAppointmentDateChanged( appointmentDTO.getIdAppointment( ),
1280                         appointmentDTO.getIdSlot( ), getLocale( ) );
1281                 for ( String strMessage : listMessages )
1282                 {
1283                     addInfo( strMessage );
1284                 }
1285             }
1286             Appointment oldAppointment = AppointmentService.findAppointmentById( appointmentDTO.getIdAppointment( ) );
1287             if ( oldAppointment.getIdSlot( ) == appointmentDTO.getSlot( ).getIdSlot( )
1288                     && appointmentDTO.getNbBookedSeats( ) > ( slot.getNbRemainingPlaces( ) + oldAppointment.getNbPlaces( ) ) )
1289             {
1290                 addError( ERROR_MESSAGE_SLOT_FULL, getLocale( ) );
1291                 return redirect( request, VIEW_CALENDAR_MANAGE_APPOINTMENTS, PARAMETER_ID_FORM, appointmentDTO.getIdForm( ) );
1292             }
1293         }
1294         else
1295             if ( appointmentDTO.getNbBookedSeats( ) > slot.getNbRemainingPlaces( ) )
1296             {
1297                 addError( ERROR_MESSAGE_SLOT_FULL, getLocale( ) );
1298                 return redirect( request, VIEW_CALENDAR_MANAGE_APPOINTMENTS, PARAMETER_ID_FORM, appointmentDTO.getIdForm( ) );
1299             }
1300         AppointmentUtilities.killTimer( request );
1301         int nIdAppointment = AppointmentService.saveAppointment( appointmentDTO );
1302         AppLogService.info( LogUtilities.buildLog( ACTION_DO_MAKE_APPOINTMENT, Integer.toString( nIdAppointment ), getUser( ) ) );
1303         request.getSession( ).removeAttribute( SESSION_VALIDATED_APPOINTMENT );
1304         addInfo( INFO_APPOINTMENT_CREATED, getLocale( ) );
1305         AppointmentAsynchronousUploadHandler.getHandler( ).removeSessionFiles( request.getSession( ).getId( ) );
1306         Map<String, String> additionalParameters = new HashMap<>( );
1307         additionalParameters.put( PARAMETER_ID_FORM, Integer.toString( form.getIdForm( ) ) );
1308         additionalParameters.put( PARAMETER_DATE_OF_DISPLAY, slot.getDate( ).toString( ) );
1309         return redirect( request, VIEW_CALENDAR_MANAGE_APPOINTMENTS, additionalParameters );
1310     }
1311 
1312     /**
1313      * Get an integer attribute from the session
1314      * 
1315      * @param session
1316      *            The session
1317      * @param strSessionKey
1318      *            The session key of the item
1319      * @return The value of the attribute, or 0 if the key is not associated with any value
1320      */
1321     private int getIntSessionAttribute( HttpSession session, String strSessionKey )
1322     {
1323         Integer nAttr = (Integer) session.getAttribute( strSessionKey );
1324         if ( nAttr != null )
1325         {
1326             return nAttr;
1327         }
1328         return 0;
1329     }
1330 
1331     /**
1332      * Default constructor
1333      */
1334     public AppointmentJspBean( )
1335     {
1336         _nDefaultItemsPerPage = AppPropertiesService.getPropertyInt( PROPERTY_DEFAULT_LIST_APPOINTMENT_PER_PAGE, 10 );
1337     }
1338 
1339     private void cleanSession( HttpSession session )
1340     {
1341         session.removeAttribute( SESSION_APPOINTMENT_FILTER );
1342         session.removeAttribute( SESSION_LIST_APPOINTMENTS );
1343         session.removeAttribute( SESSION_CURRENT_PAGE_INDEX );
1344         session.removeAttribute( SESSION_CURRENT_PAGE_INDEX );
1345         session.removeAttribute( SESSION_NOT_VALIDATED_APPOINTMENT );
1346         session.removeAttribute( SESSION_VALIDATED_APPOINTMENT );
1347         session.removeAttribute( SESSION_APPOINTMENT_FORM_ERRORS );
1348         AppointmentAsynchronousUploadHandler.getHandler( ).removeSessionFiles( session.getId( ) );
1349     }
1350 
1351     /**
1352      * Clear uploaded files if needed.
1353      * 
1354      * @param session
1355      *            The session of the current user
1356      */
1357     private void clearUploadFilesIfNeeded( HttpSession session )
1358     {
1359         // If we do not reload an appointment, we clear uploaded files.
1360         if ( session.getAttribute( SESSION_NOT_VALIDATED_APPOINTMENT ) == null && session.getAttribute( SESSION_VALIDATED_APPOINTMENT ) == null )
1361         {
1362             AppointmentAsynchronousUploadHandler.getHandler( ).removeSessionFiles( session.getId( ) );
1363         }
1364     }
1365 
1366     /**
1367      * Order the list of the appointment in the result tab with the order by and order asc given
1368      * 
1369      * @param listAppointmentsDTO
1370      *            the llist of appointments
1371      * @param strOrderBy
1372      *            the order by
1373      * @param strOrderAsc
1374      *            the order asc
1375      */
1376     private List<AppointmentDTO> orderList( List<AppointmentDTO> listAppointmentsDTO, String strOrderBy, String strOrderAsc )
1377     {
1378         List<AppointmentDTO> sortedList = new ArrayList<>( );
1379         if ( CollectionUtils.isNotEmpty( listAppointmentsDTO ) )
1380         {
1381             sortedList.addAll( listAppointmentsDTO );
1382         }
1383         if ( strOrderBy == null )
1384         {
1385             strOrderBy = DATE_APPOINTMENT;
1386         }
1387         boolean bAsc = Boolean.FALSE;
1388         if ( strOrderAsc != null )
1389         {
1390             bAsc = Boolean.parseBoolean( strOrderAsc );
1391         }
1392         Stream<AppointmentDTO> stream = null;
1393         switch( strOrderBy )
1394         {
1395             case LAST_NAME:
1396                 stream = sortedList.stream( ).sorted( ( a1, a2 ) -> a1.getLastName( ).compareTo( a2.getLastName( ) ) );
1397                 break;
1398             case FIRST_NAME:
1399                 stream = sortedList.stream( ).sorted( ( a1, a2 ) -> a1.getFirstName( ).compareTo( a2.getFirstName( ) ) );
1400                 break;
1401             case EMAIL:
1402                 stream = sortedList.stream( ).sorted( ( a1, a2 ) -> a1.getEmail( ).compareTo( a2.getEmail( ) ) );
1403                 break;
1404             case NB_BOOKED_SEATS:
1405                 stream = sortedList.stream( ).sorted( ( a1, a2 ) -> Integer.compare( a1.getNbBookedSeats( ), a2.getNbBookedSeats( ) ) );
1406                 break;
1407             case DATE_APPOINTMENT:
1408                 stream = sortedList.stream( ).sorted( ( a1, a2 ) -> a1.getStartingDateTime( ).compareTo( a2.getStartingDateTime( ) ) );
1409                 break;
1410             case ADMIN:
1411                 stream = sortedList.stream( ).sorted( ( a1, a2 ) -> a1.getAdminUser( ).compareTo( a2.getAdminUser( ) ) );
1412                 break;
1413             case STATUS:
1414                 stream = sortedList.stream( ).sorted( ( a1, a2 ) -> Boolean.compare( a1.getIsCancelled( ), a2.getIsCancelled( ) ) );
1415                 break;
1416             default:
1417                 stream = sortedList.stream( ).sorted( ( a1, a2 ) -> a1.getStartingDateTime( ).compareTo( a2.getStartingDateTime( ) ) );
1418         }
1419         sortedList = stream.collect( Collectors.toList( ) );
1420         if ( !bAsc )
1421         {
1422             Collections.reverse( sortedList );
1423         }
1424         return sortedList;
1425     }
1426 
1427     /**
1428      * Get the URL to display the form of a workflow action. If the action has no form, then the user is redirected to the page to execute the workflow action
1429      * 
1430      * @param request
1431      *            The request
1432      * @param strIdAppointment
1433      *            The id of the appointment
1434      * @param strIdAction
1435      *            The id of the workflow action
1436      * @return The URL
1437      */
1438     public static String getUrlExecuteWorkflowAction( HttpServletRequest request, String strIdAppointment, String strIdAction )
1439     {
1440         UrlItem url = new UrlItem( AppPathService.getBaseUrl( request ) + JSP_MANAGE_APPOINTMENTS );
1441         url.addParameter( MVCUtils.PARAMETER_VIEW, VIEW_WORKFLOW_ACTION_FORM );
1442         url.addParameter( PARAMETER_ID_APPOINTMENT, strIdAppointment );
1443         url.addParameter( PARAMETER_ID_ACTION, strIdAction );
1444 
1445         return url.getUrl( );
1446     }
1447 
1448     /**
1449      * Get the workflow action form before processing the action. If the action does not need to display any form, then redirect the user to the workflow action
1450      * processing page.
1451      * 
1452      * @param request
1453      *            The request
1454      * @return The HTML content to display, or the next URL to redirect the user to
1455      */
1456     @View( VIEW_WORKFLOW_ACTION_FORM )
1457     public String getWorkflowActionForm( HttpServletRequest request )
1458     {
1459         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
1460         String strIdAppointment = request.getParameter( PARAMETER_ID_APPOINTMENT );
1461         if ( StringUtils.isNotEmpty( strIdAction ) && StringUtils.isNumeric( strIdAction ) && StringUtils.isNotEmpty( strIdAppointment )
1462                 && StringUtils.isNumeric( strIdAppointment ) )
1463         {
1464             int nIdAction = Integer.parseInt( strIdAction );
1465             int nIdAppointment = Integer.parseInt( strIdAppointment );
1466             if ( WorkflowService.getInstance( ).isDisplayTasksForm( nIdAction, getLocale( ) ) )
1467             {
1468                 String strHtmlTasksForm = WorkflowService.getInstance( ).getDisplayTasksForm( nIdAppointment, Appointment.APPOINTMENT_RESOURCE_TYPE, nIdAction,
1469                         request, getLocale( ) );
1470                 Map<String, Object> model = new HashMap<String, Object>( );
1471                 model.put( MARK_TASKS_FORM, strHtmlTasksForm );
1472                 model.put( PARAMETER_ID_ACTION, nIdAction );
1473                 model.put( PARAMETER_ID_APPOINTMENT, nIdAppointment );
1474                 return getPage( PROPERTY_PAGE_TITLE_TASKS_FORM_WORKFLOW, TEMPLATE_TASKS_FORM_WORKFLOW, model );
1475             }
1476             return doProcessWorkflowAction( request );
1477         }
1478         return redirect( request, AppointmentFormJspBean.getURLManageAppointmentForms( request ) );
1479     }
1480 
1481     /**
1482      * Do process a workflow action over an appointment
1483      * 
1484      * @param request
1485      *            The request
1486      * @return The next URL to redirect to
1487      */
1488     @Action( ACTION_DO_PROCESS_WORKFLOW_ACTION )
1489     public String doProcessWorkflowAction( HttpServletRequest request )
1490     {
1491         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
1492         String strIdAppointment = request.getParameter( PARAMETER_ID_APPOINTMENT );
1493         if ( StringUtils.isNotEmpty( strIdAction ) && StringUtils.isNumeric( strIdAction ) && StringUtils.isNotEmpty( strIdAppointment )
1494                 && StringUtils.isNumeric( strIdAppointment ) )
1495         {
1496             int nIdAction = Integer.parseInt( strIdAction );
1497             int nIdAppointment = Integer.parseInt( strIdAppointment );
1498             Appointment appointment = AppointmentService.findAppointmentById( nIdAppointment );
1499             Slot slot = SlotService.findSlotById( appointment.getIdSlot( ) );
1500             if ( request.getParameter( PARAMETER_BACK ) == null )
1501             {
1502                 AppointmentFormDTO form = FormService.buildAppointmentFormLight( slot.getIdForm( ) );
1503                 try
1504                 {
1505                     if ( WorkflowService.getInstance( ).isDisplayTasksForm( nIdAction, getLocale( ) ) )
1506                     {
1507                         String strError = WorkflowService.getInstance( ).doSaveTasksForm( nIdAppointment, Appointment.APPOINTMENT_RESOURCE_TYPE, nIdAction,
1508                                 form.getIdForm( ), request, getLocale( ) );
1509                         if ( strError != null )
1510                         {
1511                             return redirect( request, strError );
1512                         }
1513                     }
1514                     else
1515                     {
1516                         List<ITask> listActionTasks = _taskService.getListTaskByIdAction( nIdAction, getLocale( ) );
1517                         for ( ITask task : listActionTasks )
1518                         {
1519                             if ( task.getTaskType( ).getKey( ).equals( "taskChangeAppointmentStatus" ) && ( slot.getNbRemainingPlaces( ) == 0 )
1520                                     && ( appointment.getIsCancelled( ) ) )
1521                             {
1522                                 return redirect( request, AdminMessageService.getMessageUrl( request, MESSAGE_UNVAILABLE_SLOT, AdminMessage.TYPE_STOP ) );
1523                             }
1524                         }
1525 
1526                         WorkflowService.getInstance( ).doProcessAction( nIdAppointment, Appointment.APPOINTMENT_RESOURCE_TYPE, nIdAction, form.getIdForm( ),
1527                                 request, getLocale( ), false );
1528                     }
1529                 }
1530                 catch( Exception e )
1531                 {
1532                     AppLogService.error( "Error Workflow", e );
1533                 }
1534                 Map<String, String> mapParams = new HashMap<String, String>( );
1535                 mapParams.put( PARAMETER_ID_FORM, Integer.toString( form.getIdForm( ) ) );
1536                 request.getSession( ).removeAttribute( SESSION_LIST_APPOINTMENTS );
1537                 return redirect( request, VIEW_MANAGE_APPOINTMENTS, mapParams );
1538             }
1539             return redirect( request, VIEW_MANAGE_APPOINTMENTS, PARAMETER_ID_FORM, slot.getIdForm( ) );
1540         }
1541         return redirect( request, AppointmentFormJspBean.getURLManageAppointmentForms( request ) );
1542     }
1543 
1544     /**
1545      * Do change the status of an appointment
1546      * 
1547      * @param request
1548      *            The request
1549      * @return The next URL to redirect to
1550      * @throws AccessDeniedException
1551      *             If the user is not authorized to access this feature
1552      */
1553     @Action( ACTION_DO_CHANGE_APPOINTMENT_STATUS )
1554     public String doChangeAppointmentStatus( HttpServletRequest request ) throws AccessDeniedException
1555     {
1556         String strIdAppointment = request.getParameter( PARAMETER_ID_APPOINTMENT );
1557         String strStatusCancelled = request.getParameter( PARAMETER_STATUS_CANCELLED );
1558         if ( StringUtils.isNotEmpty( strIdAppointment ) && StringUtils.isNumeric( strIdAppointment ) && StringUtils.isNotEmpty( strStatusCancelled ) )
1559         {
1560             int nIdAppointment = Integer.parseInt( strIdAppointment );
1561             boolean bStatusCancelled = Boolean.parseBoolean( strStatusCancelled );
1562             Appointment appointment = AppointmentService.findAppointmentById( nIdAppointment );
1563             Slot slot = SlotService.findSlotById( appointment.getIdSlot( ) );
1564             if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, Integer.toString( slot.getIdForm( ) ),
1565                     AppointmentResourceIdService.PERMISSION_CHANGE_APPOINTMENT_STATUS, getUser( ) ) )
1566             {
1567                 throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_CHANGE_APPOINTMENT_STATUS );
1568             }
1569             if ( ( slot.getNbRemainingPlaces( ) == 0 ) && appointment.getIsCancelled( ) && !bStatusCancelled )
1570             {
1571                 return redirect( request, AdminMessageService.getMessageUrl( request, MESSAGE_UNVAILABLE_SLOT, AdminMessage.TYPE_STOP ) );
1572             }
1573             if ( appointment.getIsCancelled( ) != bStatusCancelled )
1574             {
1575                 appointment.setIsCancelled( bStatusCancelled );
1576                 AppointmentService.updateAppointment( appointment );
1577                 AppLogService.info( LogUtilities.buildLog( ACTION_DO_CHANGE_APPOINTMENT_STATUS, strIdAppointment, getUser( ) ) );
1578             }
1579             return redirect( request, VIEW_MANAGE_APPOINTMENTS, PARAMETER_ID_FORM, slot.getIdForm( ) );
1580         }
1581         return redirect( request, AppointmentFormJspBean.getURLManageAppointmentForms( request ) );
1582     }
1583 
1584     /**
1585      * List of all the available status of an appointment
1586      * 
1587      * @return the list of the status
1588      */
1589     private ReferenceList getListStatus( )
1590     {
1591         ReferenceList refListStatus = new ReferenceList( );
1592         refListStatus.addItem( -1, StringUtils.EMPTY );
1593         refListStatus.addItem( 0, I18nService.getLocalizedString( RESERVED, getLocale( ) ) );
1594         refListStatus.addItem( 1, I18nService.getLocalizedString( UNRESERVED, getLocale( ) ) );
1595         return refListStatus;
1596     }
1597 
1598 }