1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.appointment.web;
35
36 import java.io.IOException;
37 import java.sql.Date;
38 import java.time.LocalDate;
39 import java.time.LocalDateTime;
40 import java.time.LocalTime;
41 import java.util.ArrayList;
42 import java.util.HashMap;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.concurrent.locks.Lock;
46 import java.util.stream.Collectors;
47
48 import javax.servlet.http.HttpServletRequest;
49
50 import org.apache.commons.collections.CollectionUtils;
51 import org.apache.commons.lang3.StringUtils;
52
53 import com.fasterxml.jackson.core.type.TypeReference;
54 import com.fasterxml.jackson.databind.DeserializationFeature;
55 import com.fasterxml.jackson.databind.ObjectMapper;
56 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
57
58 import fr.paris.lutece.api.user.User;
59 import fr.paris.lutece.plugins.appointment.business.appointment.Appointment;
60 import fr.paris.lutece.plugins.appointment.business.display.Display;
61 import fr.paris.lutece.plugins.appointment.business.form.Form;
62 import fr.paris.lutece.plugins.appointment.business.planning.ClosingDay;
63 import fr.paris.lutece.plugins.appointment.business.planning.ClosingDayHome;
64 import fr.paris.lutece.plugins.appointment.business.planning.WeekDefinition;
65 import fr.paris.lutece.plugins.appointment.business.planning.WorkingDay;
66 import fr.paris.lutece.plugins.appointment.business.rule.ReservationRule;
67 import fr.paris.lutece.plugins.appointment.business.slot.Period;
68 import fr.paris.lutece.plugins.appointment.business.slot.Slot;
69 import fr.paris.lutece.plugins.appointment.log.LogUtilities;
70 import fr.paris.lutece.plugins.appointment.service.AppointmentResourceIdService;
71 import fr.paris.lutece.plugins.appointment.service.AppointmentService;
72 import fr.paris.lutece.plugins.appointment.service.AppointmentUtilities;
73 import fr.paris.lutece.plugins.appointment.service.ClosingDayService;
74 import fr.paris.lutece.plugins.appointment.service.CommentService;
75 import fr.paris.lutece.plugins.appointment.service.DisplayService;
76 import fr.paris.lutece.plugins.appointment.service.FormService;
77 import fr.paris.lutece.plugins.appointment.service.ReservationRuleService;
78 import fr.paris.lutece.plugins.appointment.service.SlotSafeService;
79 import fr.paris.lutece.plugins.appointment.service.SlotService;
80 import fr.paris.lutece.plugins.appointment.service.WeekDefinitionService;
81 import fr.paris.lutece.plugins.appointment.service.WorkingDayService;
82 import fr.paris.lutece.plugins.appointment.web.dto.AppointmentFormDTO;
83 import fr.paris.lutece.portal.service.admin.AccessDeniedException;
84 import fr.paris.lutece.portal.service.i18n.I18nService;
85 import fr.paris.lutece.portal.service.rbac.RBACService;
86 import fr.paris.lutece.portal.service.util.AppLogService;
87 import fr.paris.lutece.portal.service.util.AppPropertiesService;
88 import fr.paris.lutece.portal.util.mvc.admin.annotations.Controller;
89 import fr.paris.lutece.portal.util.mvc.commons.annotations.Action;
90 import fr.paris.lutece.portal.util.mvc.commons.annotations.View;
91
92
93
94
95
96
97
98 @Controller( controllerJsp = SpecificWeekJspBean.JSP_MANAGE_APPOINTMENT_SLOTS, controllerPath = "jsp/admin/plugins/appointment/", right = AppointmentFormJspBean.RIGHT_MANAGEAPPOINTMENTFORM )
99 public class SpecificWeekJspBean extends AbstractAppointmentFormAndSlotJspBean
100 {
101
102
103
104 public static final String JSP_MANAGE_APPOINTMENT_SLOTS = "ManageSpecificWeek.jsp";
105
106
107
108
109 private static final long serialVersionUID = 2376721852596997810L;
110
111
112 private static final String MESSAGE_SPECIFIC_WEEK_PAGE_TITLE = "appointment.specificWeek.pageTitle";
113 private static final String MESSAGE_MODIFY_SLOT_PAGE_TITLE = "appointment.modifyCalendarSlots.pageTitle";
114 private static final String MESSAGE_ERROR_TIME_END_BEFORE_TIME_START = "appointment.modifyCalendarSlots.errorTimeEndBeforeTimeStart";
115 private static final String MESSAGE_SLOT_CAN_NOT_END_AFTER_DAY_OR_FORM = "appointment.message.error.slotCanNotEndAfterDayOrForm";
116 private static final String MESSAGE_ERROR_APPOINTMENT_ON_SLOT = "appointment.message.error.appointmentOnSlot";
117 private static final String MESSAGE_INFO_SLOT_UPDATED = "appointment.modifyCalendarSlots.messageSlotUpdated";
118 private static final String MESSAGE_INFO_VALIDATED_APPOINTMENTS_IMPACTED = "appointment.modifyCalendarSlots.messageValidatedAppointmentsImpacted";
119 private static final String MESSAGE_INFO_SURBOOKING = "appointment.modifyCalendarSlots.messageSurbooking";
120 private static final String MESSAGE_INFO_MULTI_SURBOOKING = "appointment.modifyCalendarMultiSlots.messageSurbooking";
121
122 private static final String MESSAGE_INFO_OVERLOAD = "appointment.modifyCalendarSlots.messageOverload";
123 private static final String MESSAGE_ERROR_PARSING_JSON = "appointment.message.error.parsing.json";
124
125
126 private static final String PARAMETER_ENDING_DATE_TO_APPLY = "ending_date_apply";
127 private static final String PARAMETER_STARTING_DATE_TO_APPLY = "starting_date_apply";
128 private static final String PARAMETER_ENDING_DATE_OF_DISPLAY = "ending_date_of_display";
129 private static final String PARAMETER_DATE_OF_DISPLAY = "date_of_display";
130 private static final String PARAMETER_ID_FORM = "id_form";
131 private static final String PARAMETER_ID_SLOT = "id_slot";
132 private static final String PARAMETER_STARTING_DATE_TIME = "starting_date_time";
133 private static final String PARAMETER_ENDING_DATE_TIME = "ending_date_time";
134 private static final String PARAMETER_EVENTS_COMMENTS = "comment_events";
135 private static final String PARAMETER_DAY_OF_WEEK = "dow";
136 private static final String PARAMETER_EVENTS = "events";
137 private static final String PARAMETER_MIN_DURATION = "min_duration";
138 private static final String PARAMETER_MIN_TIME = "min_time";
139 private static final String PARAMETER_MAX_TIME = "max_time";
140 private static final String PARAMETER_IS_OPEN = "is_open";
141 private static final String PARAMETER_IS_SPECIFIC = "is_specific";
142 private static final String PARAMETER_ENDING_TIME = "ending_time";
143 private static final String PARAMETER_MAX_CAPACITY = "max_capacity";
144
145 private static final String PARAMETER_SHIFT_SLOT = "shift_slot";
146 private static final String PARAMETER_DATA = "slotsData";
147 private static final String PARAMETER_IDENTICAL = "identical";
148
149
150 private static final String MARK_SLOT = "slot";
151 private static final String MARK_LOCALE_TINY = "locale";
152
153 private static final String VIEW_MANAGE_SPECIFIC_WEEK = "manageSpecificWeek";
154 private static final String VIEW_MODIFY_SLOT = "viewModifySlot";
155
156
157 private static final String ACTION_DO_MODIFY_SLOT = "doModifySlot";
158 private static final String ACTION_DO_MODIFY_LIST_SLOT = "doModifyListSlot";
159
160
161 private static final String TEMPLATE_MANAGE_SPECIFIC_WEEK = "admin/plugins/appointment/slots/manage_specific_week.html";
162 private static final String TEMPLATE_MODIFY_SLOT = "admin/plugins/appointment/slots/modify_slot.html";
163
164
165 private static final String PROPERTY_NB_WEEKS_TO_DISPLAY_IN_BO = "appointment.nbWeeksToDisplayInBO";
166
167
168 private AppointmentFormDTO _appointmentForm;
169 private Slot _slot;
170
171
172
173
174
175
176
177
178
179 @View( defaultView = true, value = VIEW_MANAGE_SPECIFIC_WEEK )
180 public String getViewManageSpecificWeek( HttpServletRequest request ) throws AccessDeniedException
181 {
182 _slot = null;
183 String strIdForm = request.getParameter( PARAMETER_ID_FORM );
184 int nIdForm = Integer.parseInt( strIdForm );
185 if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM,
186 (User) getUser( ) ) )
187 {
188 throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM );
189 }
190 Form form = FormService.findFormLightByPrimaryKey( nIdForm );
191
192 Display display = DisplayService.findDisplayWithFormId( nIdForm );
193 int nNbWeeksToDisplay = AppPropertiesService.getPropertyInt( PROPERTY_NB_WEEKS_TO_DISPLAY_IN_BO, display.getNbWeeksToDisplay( ) );
194 if ( ( _appointmentForm == null ) || ( nIdForm != _appointmentForm.getIdForm( ) ) )
195 {
196 _appointmentForm = FormService.buildAppointmentForm( nIdForm, 0 );
197 }
198 LocalDate dateOfDisplay = LocalDate.now( );
199 if ( _appointmentForm.getDateStartValidity( ) != null && _appointmentForm.getDateStartValidity( ).toLocalDate( ).isAfter( dateOfDisplay ) )
200 {
201 dateOfDisplay = _appointmentForm.getDateStartValidity( ).toLocalDate( );
202 }
203 LocalDate endingDateOfDisplay = LocalDate.now( ).plusWeeks( nNbWeeksToDisplay );
204 LocalDate endingValidityDate = form.getEndingValidityDate( );
205 if ( endingValidityDate != null && endingDateOfDisplay.isAfter( endingValidityDate ) )
206 {
207 endingDateOfDisplay = endingValidityDate;
208 }
209
210 List<WeekDefinition> listWeekDefinition = WeekDefinitionService.findListWeekDefinition( nIdForm );
211 Map<WeekDefinition, ReservationRule> mapReservationRule = ReservationRuleService.findAllReservationRule( nIdForm, listWeekDefinition );
212 List<ReservationRule> listReservationRules = new ArrayList<>( mapReservationRule.values( ) );
213
214
215 LocalTime minStartingTime = WeekDefinitionService.getMinStartingTimeOfAListOfWeekDefinition( listReservationRules );
216
217 LocalTime maxEndingTime = WeekDefinitionService.getMaxEndingTimeOfAListOfWeekDefinition( listReservationRules );
218
219 List<String> listDayOfWeek = new ArrayList<>( WeekDefinitionService.getSetDaysOfWeekOfAListOfWeekDefinitionForFullCalendar( listReservationRules ) );
220
221 List<Slot> listSlot = SlotService.buildListSlot( nIdForm, mapReservationRule, dateOfDisplay, endingDateOfDisplay );
222 listSlot = listSlot.stream( ).filter( s -> s.getEndingDateTime( ).isAfter( LocalDateTime.now( ) ) ).collect( Collectors.toList( ) );
223 String strDateOfDisplay = request.getParameter( PARAMETER_DATE_OF_DISPLAY );
224 if ( StringUtils.isNotEmpty( strDateOfDisplay ) )
225 {
226 dateOfDisplay = LocalDate.parse( strDateOfDisplay );
227 }
228 addInfo( MESSAGE_INFO_OVERLOAD, getLocale( ) );
229 Map<String, Object> model = getModel( );
230 model.put( PARAMETER_DATE_OF_DISPLAY, dateOfDisplay );
231 model.put( PARAMETER_ENDING_DATE_OF_DISPLAY, endingDateOfDisplay );
232 model.put( PARAMETER_DAY_OF_WEEK, listDayOfWeek );
233 model.put( PARAMETER_EVENTS, listSlot );
234 model.put( PARAMETER_MIN_TIME, minStartingTime );
235 model.put( PARAMETER_MAX_TIME, maxEndingTime );
236 model.put( PARAMETER_MIN_DURATION, LocalTime.MIN.plusMinutes( AppointmentUtilities.THIRTY_MINUTES ) );
237 model.put( PARAMETER_ID_FORM, nIdForm );
238 model.put( PARAMETER_EVENTS_COMMENTS, CommentService
239 .buildCommentDTO( CommentService.finListComments( Date.valueOf( dateOfDisplay ), Date.valueOf( endingDateOfDisplay ), nIdForm ) ) );
240 addElementsToModel( _appointmentForm, getUser( ), getLocale( ), model );
241 model.put( MARK_LOCALE_TINY, getLocale( ) );
242 return getPage( MESSAGE_SPECIFIC_WEEK_PAGE_TITLE, TEMPLATE_MANAGE_SPECIFIC_WEEK, model );
243 }
244
245
246
247
248
249
250
251
252
253 @View( VIEW_MODIFY_SLOT )
254 public String getViewModifySlot( HttpServletRequest request ) throws AccessDeniedException
255 {
256 String strIdForm = request.getParameter( PARAMETER_ID_FORM );
257 int nIdForm = Integer.parseInt( strIdForm );
258 if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM,
259 (User) getUser( ) ) )
260 {
261 throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM );
262 }
263 if ( _slot == null )
264 {
265 int nIdSlot = Integer.parseInt( request.getParameter( PARAMETER_ID_SLOT ) );
266
267 if ( nIdSlot == 0 )
268 {
269
270 LocalDateTime startingDateTime = LocalDateTime.parse( request.getParameter( PARAMETER_STARTING_DATE_TIME ) );
271 LocalDateTime endingDateTime = LocalDateTime.parse( request.getParameter( PARAMETER_ENDING_DATE_TIME ) );
272 boolean bIsOpen = Boolean.parseBoolean( request.getParameter( PARAMETER_IS_OPEN ) );
273 boolean bIsSpecific = Boolean.parseBoolean( request.getParameter( PARAMETER_IS_SPECIFIC ) );
274 int nMaxCapacity = Integer.parseInt( request.getParameter( PARAMETER_MAX_CAPACITY ) );
275 _slot = SlotService.buildSlot( nIdForm, new Period( startingDateTime, endingDateTime ), nMaxCapacity, nMaxCapacity, nMaxCapacity, 0, bIsOpen,
276 bIsSpecific );
277 }
278 else
279 {
280 _slot = SlotService.findSlotById( nIdSlot );
281 }
282 }
283 Map<String, Object> model = getModel( );
284 model.put( PARAMETER_DATE_OF_DISPLAY, _slot.getDate( ) );
285 model.put( MARK_SLOT, _slot );
286 model.put( PARAMETER_ID_FORM, strIdForm );
287 return getPage( MESSAGE_MODIFY_SLOT_PAGE_TITLE, TEMPLATE_MODIFY_SLOT, model );
288 }
289
290
291
292
293
294
295
296
297
298 @Action( ACTION_DO_MODIFY_SLOT )
299 public String doModifySlot( HttpServletRequest request ) throws AccessDeniedException
300 {
301 boolean bOpeningHasChanged = false;
302 String strIdSlot = request.getParameter( PARAMETER_ID_SLOT );
303 LocalTime endingTime = LocalTime.parse( request.getParameter( PARAMETER_ENDING_TIME ) );
304 boolean bIsOpen = Boolean.parseBoolean( request.getParameter( PARAMETER_IS_OPEN ) );
305 int nMaxCapacity = Integer.parseInt( request.getParameter( PARAMETER_MAX_CAPACITY ) );
306 boolean bEndingTimeHasChanged = false;
307 String strIdForm = request.getParameter( PARAMETER_ID_FORM );
308 boolean bShiftSlot = Boolean.parseBoolean( request.getParameter( PARAMETER_SHIFT_SLOT ) );
309 if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM,
310 (User) getUser( ) ) )
311 {
312 throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM );
313 }
314 int nIdSlot = Integer.parseInt( strIdSlot );
315 Lock lock = SlotSafeService.getLockOnSlot( nIdSlot );
316 lock.lock( );
317 try
318 {
319 if ( nIdSlot != 0 )
320 {
321 _slot = SlotService.findSlotById( nIdSlot );
322 }
323
324 if ( bIsOpen != _slot.getIsOpen( ) )
325 {
326 _slot.setIsOpen( bIsOpen );
327 bOpeningHasChanged = true;
328 }
329
330
331
332 ClosingDay closingDay = ClosingDayService.findClosingDayByIdFormAndDateOfClosingDay( _slot.getIdForm( ), _slot.getDate( ) );
333 if ( closingDay != null )
334 {
335
336
337
338 ClosingDayService.removeClosingDay( closingDay );
339 }
340 if ( nMaxCapacity != _slot.getMaxCapacity( ) )
341 {
342 _slot.setMaxCapacity( nMaxCapacity );
343
344
345
346
347
348 _slot.setNbRemainingPlaces( nMaxCapacity );
349 _slot.setNbPotentialRemainingPlaces( nMaxCapacity );
350 }
351 LocalTime previousEndingTime = _slot.getEndingTime( );
352 if ( !endingTime.equals( previousEndingTime ) )
353 {
354 _slot.setEndingTime( endingTime );
355 _slot.setEndingDateTime( _slot.getDate( ).atTime( endingTime ) );
356 bEndingTimeHasChanged = true;
357 }
358 if ( ( bEndingTimeHasChanged && !checkNoAppointmentsOnThisSlotOrOnTheSlotsImpacted( _slot, bShiftSlot ) )
359 || ( bEndingTimeHasChanged && !checkEndingTimeOfSlot( endingTime, _slot ) ) )
360 {
361 return redirect( request, VIEW_MODIFY_SLOT, PARAMETER_ID_FORM, _slot.getIdForm( ) );
362 }
363 SlotSafeService.updateSlot( _slot, bEndingTimeHasChanged, previousEndingTime, bShiftSlot );
364
365 }
366 finally
367 {
368
369 lock.unlock( );
370 }
371 AppLogService.info( LogUtilities.buildLog( ACTION_DO_MODIFY_SLOT, strIdSlot, getUser( ) ) );
372 addInfo( MESSAGE_INFO_SLOT_UPDATED, getLocale( ) );
373 boolean appointmentsImpacted = !AppointmentUtilities.checkNoValidatedAppointmentsOnThisSlot( _slot );
374 if ( appointmentsImpacted && bOpeningHasChanged )
375 {
376 addInfo( MESSAGE_INFO_VALIDATED_APPOINTMENTS_IMPACTED, getLocale( ) );
377 }
378 if ( appointmentsImpacted && nMaxCapacity < _slot.getNbPlacesTaken( ) )
379 {
380 addInfo( MESSAGE_INFO_SURBOOKING, getLocale( ) );
381 }
382
383 Map<String, String> additionalParameters = new HashMap<>( );
384 additionalParameters.put( PARAMETER_ID_FORM, Integer.toString( _slot.getIdForm( ) ) );
385 additionalParameters.put( PARAMETER_DATE_OF_DISPLAY, _slot.getDate( ).toString( ) );
386 return redirect( request, VIEW_MANAGE_SPECIFIC_WEEK, additionalParameters );
387 }
388
389
390
391
392
393
394
395
396
397 @Action( ACTION_DO_MODIFY_LIST_SLOT )
398 public String doModifyListSlots( HttpServletRequest request ) throws AccessDeniedException
399 {
400 int nVarMaxCapacity = 0;
401 int nMaxCapacity = -1;
402 boolean bShiftSlot = false;
403 LocalTime endingTime = null;
404
405 String strIdForm = request.getParameter( PARAMETER_ID_FORM );
406 String strShiftSlot = request.getParameter( PARAMETER_SHIFT_SLOT );
407 String strEndingTime = request.getParameter( PARAMETER_ENDING_TIME );
408 String strDateOfDisplay = request.getParameter( PARAMETER_DATE_OF_DISPLAY );
409 String strApplyOnIdentical = request.getParameter( PARAMETER_IDENTICAL );
410
411 boolean bStateHasChanged = false;
412 boolean bIsOpen = false;
413 String strIsOpen = request.getParameter( PARAMETER_IS_OPEN );
414 if ( !RBACService.isAuthorized( AppointmentFormDTO.RESOURCE_TYPE, strIdForm, AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM,
415 (User) getUser( ) ) )
416 {
417 throw new AccessDeniedException( AppointmentResourceIdService.PERMISSION_MODIFY_ADVANCED_SETTING_FORM );
418 }
419 if ( strIsOpen == null || strIsOpen.equalsIgnoreCase( "true" ) || strIsOpen.equalsIgnoreCase( "false" ) )
420 {
421
422 bStateHasChanged = true;
423 bIsOpen = Boolean.parseBoolean( strIsOpen );
424 }
425
426 String strCap = request.getParameter( PARAMETER_CAPACITY_MOD );
427
428 if ( strCap.equals( VAR_CAP ) )
429 {
430
431 nVarMaxCapacity = Integer.parseInt( request.getParameter( PARAMETER_MAX_CAPACITY ) );
432
433 }
434 else
435 if ( strCap.equals( NEW_CAP ) )
436 {
437
438 nMaxCapacity = Integer.parseInt( request.getParameter( PARAMETER_MAX_CAPACITY ) );
439
440 }
441
442 if ( !StringUtils.isEmpty( strShiftSlot ) && !StringUtils.isEmpty( strEndingTime ) )
443 {
444
445 bShiftSlot = Boolean.parseBoolean( request.getParameter( PARAMETER_SHIFT_SLOT ) );
446 endingTime = LocalTime.parse( strEndingTime );
447 }
448
449 String strJson = request.getParameter( PARAMETER_DATA );
450 AppLogService.debug( "slot - Received strJson : " + strJson );
451 ObjectMapper mapper = new ObjectMapper( );
452 mapper.registerModule( new JavaTimeModule( ) );
453 mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
454
455 List<Slot> listSlot = new ArrayList<>( );
456 try
457 {
458
459 listSlot = mapper.readValue( strJson, new TypeReference<List<Slot>>( )
460 {
461 } );
462 for ( Slot slt : listSlot )
463 {
464
465 if ( slt.getIdSlot( ) != 0 )
466 {
467
468 Slot slot = SlotService.findSlotById( slt.getIdSlot( ) );
469 slt.setNbPlacestaken( slot.getNbPlacesTaken( ) );
470 slt.setNbRemainingPlaces( slot.getNbRemainingPlaces( ) );
471 slt.setNbPotentialRemainingPlaces( slot.getNbPotentialRemainingPlaces( ) );
472 }
473 else
474 {
475
476 slt.setNbRemainingPlaces( slt.getMaxCapacity( ) );
477 slt.setNbPotentialRemainingPlaces( slt.getMaxCapacity( ) );
478 }
479
480 }
481 if ( !StringUtils.isEmpty( strApplyOnIdentical ) && Boolean.parseBoolean( strApplyOnIdentical ) )
482 {
483
484 LocalDate startingDate = LocalDate.parse( request.getParameter( PARAMETER_STARTING_DATE_TO_APPLY ) );
485 LocalDate endingDate = LocalDate.parse( request.getParameter( PARAMETER_ENDING_DATE_TO_APPLY ) );
486
487 listSlot = buildListSlotsToUpdate( listSlot, Integer.parseInt( strIdForm ), startingDate, endingDate );
488 }
489
490 }
491 catch( IOException e )
492 {
493
494 AppLogService.error( MESSAGE_ERROR_PARSING_JSON + e.getMessage( ), e );
495 addError( MESSAGE_ERROR_PARSING_JSON, getLocale( ) );
496
497 }
498
499 if ( !AppointmentUtilities.checkListSlotIsBuildedCorrectly( Integer.parseInt( strIdForm ), listSlot ) )
500 {
501
502 addError( MESSAGE_ERROR_PARSING_JSON, getLocale( ) );
503
504 }
505 else
506 {
507
508 updateListSlots( listSlot, nVarMaxCapacity, nMaxCapacity, bIsOpen, bStateHasChanged, bShiftSlot, endingTime );
509 }
510 Map<String, String> additionalParameters = new HashMap<>( );
511 additionalParameters.put( PARAMETER_ID_FORM, strIdForm );
512 additionalParameters.put( PARAMETER_DATE_OF_DISPLAY, strDateOfDisplay );
513 return redirect( request, VIEW_MANAGE_SPECIFIC_WEEK, additionalParameters );
514 }
515
516
517
518
519
520
521
522
523
524
525 private boolean checkEndingTimeOfSlot( LocalTime endingTime, Slot slot )
526 {
527 boolean bReturn = true;
528 LocalDate dateOfSlot = slot.getDate( );
529 ReservationRule resrvationRule = ReservationRuleService.findReservationRuleByIdFormAndClosestToDateOfApply( slot.getIdForm( ), dateOfSlot );
530 WorkingDay workingDay = WorkingDayService.getWorkingDayOfDayOfWeek( resrvationRule.getListWorkingDay( ), dateOfSlot.getDayOfWeek( ) );
531 LocalTime maxEndingTime = null;
532 if ( workingDay == null )
533 {
534 maxEndingTime = WorkingDayService.getMaxEndingTimeOfAListOfWorkingDay( resrvationRule.getListWorkingDay( ) );
535 }
536 else
537 {
538 maxEndingTime = WorkingDayService.getMaxEndingTimeOfAWorkingDay( workingDay );
539 }
540 if ( endingTime.isAfter( maxEndingTime ) )
541 {
542 bReturn = false;
543 addError( MESSAGE_SLOT_CAN_NOT_END_AFTER_DAY_OR_FORM, getLocale( ) );
544 }
545 if ( endingTime.isBefore( slot.getStartingTime( ) ) || endingTime.equals( slot.getStartingTime( ) ) )
546 {
547 bReturn = false;
548 addError( MESSAGE_ERROR_TIME_END_BEFORE_TIME_START, getLocale( ) );
549 }
550 return bReturn;
551 }
552
553
554
555
556
557
558
559
560
561
562 private boolean checkNoAppointmentsOnThisSlotOrOnTheSlotsImpacted( Slot slot, boolean bShiftSLot )
563 {
564 boolean bReturn = true;
565 LocalDateTime endingDateTime = slot.getEndingDateTime( );
566
567
568 if ( bShiftSLot )
569 {
570 endingDateTime = slot.getDate( ).atTime( LocalTime.MAX );
571 }
572 List<Slot> listSlotImpacted = SlotService.findSlotsByIdFormAndDateRange( slot.getIdForm( ), slot.getStartingDateTime( ), endingDateTime );
573 List<Appointment> listAppointment = AppointmentService.findListAppointmentByListSlot( listSlotImpacted );
574 if ( CollectionUtils.isNotEmpty( listAppointment ) )
575 {
576 bReturn = false;
577 }
578 return bReturn;
579 }
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597 private void updateListSlots( List<Slot> listSlot, int nVarMaxCapacity, int nMaxCapacity, boolean bIsOpen, boolean bStateHasChanged, boolean bShiftSlot,
598 LocalTime endingTime )
599 {
600 int nNewMaxCapacity = 0;
601 boolean bOpeningHasChanged = false;
602 boolean appointmentsImpacted = false;
603 boolean bEndingTimeHasChanged = false;
604 boolean bNoApptImpacted = true;
605 LocalDate dateSlot = null;
606 StringBuilder sbAlert = new StringBuilder( );
607
608 for ( Slot slot : listSlot )
609 {
610 Lock lock = SlotSafeService.getLockOnSlot( slot.getIdSlot( ) );
611 lock.lock( );
612 try
613 {
614 if ( bStateHasChanged && bIsOpen != slot.getIsOpen( ) )
615 {
616 slot.setIsOpen( bIsOpen );
617 bOpeningHasChanged = true;
618 }
619 if ( dateSlot == null || !dateSlot.isEqual( slot.getDate( ) ) )
620 {
621 dateSlot = slot.getDate( );
622
623
624
625
626 ClosingDayHome.deleteByIdFormAndDateOfClosingDay( slot.getIdForm( ), dateSlot );
627 }
628 if ( nVarMaxCapacity != 0 || ( nMaxCapacity >= 0 && nMaxCapacity != slot.getMaxCapacity( ) ) )
629 {
630 nNewMaxCapacity = ( nVarMaxCapacity != 0 ) ? ( slot.getMaxCapacity( ) + nVarMaxCapacity ) : nMaxCapacity;
631 if ( nNewMaxCapacity < 0 )
632 {
633 nNewMaxCapacity = 0;
634 }
635 slot.setMaxCapacity( nNewMaxCapacity );
636
637
638
639
640
641 slot.setNbRemainingPlaces( nNewMaxCapacity );
642 slot.setNbPotentialRemainingPlaces( nNewMaxCapacity );
643 }
644 LocalTime previousEndingTime = slot.getEndingTime( );
645 if ( endingTime != null && !endingTime.equals( previousEndingTime ) )
646 {
647 bNoApptImpacted = checkNoAppointmentsOnThisSlotOrOnTheSlotsImpacted( slot, bShiftSlot );
648 slot.setEndingTime( endingTime );
649 slot.setEndingDateTime( slot.getDate( ).atTime( endingTime ) );
650 bEndingTimeHasChanged = true;
651 }
652 if ( ( bEndingTimeHasChanged && !bNoApptImpacted ) || ( bEndingTimeHasChanged && !checkEndingTimeOfSlot( endingTime, slot ) ) )
653 {
654 addWarning( MESSAGE_ERROR_APPOINTMENT_ON_SLOT, getLocale( ) );
655
656 }
657 else
658 {
659 SlotSafeService.updateSlot( slot, bEndingTimeHasChanged, previousEndingTime, bShiftSlot );
660 if ( !appointmentsImpacted && slot.getNbPlacesTaken( ) > 0 )
661 {
662 appointmentsImpacted = true;
663 }
664 AppLogService.info( LogUtilities.buildLog( ACTION_DO_MODIFY_SLOT, String.valueOf( slot.getIdSlot( ) ), getUser( ) ) );
665
666 if ( slot.getMaxCapacity( ) < slot.getNbPlacesTaken( ) )
667 {
668 sbAlert.append( slot.getStartingDateTime( ) );
669 sbAlert.append( "-" );
670 sbAlert.append( slot.getEndingDateTime( ) );
671 sbAlert.append( ", " );
672 }
673 }
674 }
675 finally
676 {
677 lock.unlock( );
678 }
679 }
680
681 if ( appointmentsImpacted && bOpeningHasChanged )
682 {
683 addError( MESSAGE_INFO_VALIDATED_APPOINTMENTS_IMPACTED, getLocale( ) );
684 }
685 else
686 if ( CollectionUtils.isNotEmpty( listSlot ) )
687 {
688 boolean bNoSlotImpacted = true;
689 for ( Slot slt : listSlot )
690 {
691 if ( !checkNoAppointmentsOnThisSlotOrOnTheSlotsImpacted( slt, bShiftSlot ) )
692 bNoSlotImpacted = false;
693 }
694 if ( bNoSlotImpacted )
695 addInfo( MESSAGE_INFO_SLOT_UPDATED, getLocale( ) );
696 }
697
698 if ( !StringUtils.isEmpty( sbAlert.toString( ) ) )
699 {
700 Object [ ] args = {
701 sbAlert.toString( )
702 };
703 addWarning( I18nService.getLocalizedString( MESSAGE_INFO_MULTI_SURBOOKING, args, getLocale( ) ) );
704 }
705 }
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720 private List<Slot> buildListSlotsToUpdate( List<Slot> listSlotSelected, int nIdForm, LocalDate startingDate, LocalDate endingDate )
721 {
722 List<Slot> listBuilded = new ArrayList<>( );
723 listBuilded.addAll( listSlotSelected );
724 HashMap<LocalDate, WeekDefinition> mapWeekDefinition = WeekDefinitionService.findAllWeekDefinition( nIdForm );
725 List<Slot> listSlots = SlotService.buildListSlot( nIdForm, mapWeekDefinition, startingDate, endingDate );
726 for ( Slot slot : listSlotSelected )
727 {
728 listBuilded
729 .addAll( listSlots.stream( )
730 .filter( slt -> slt.getStartingTime( ).equals( slot.getStartingTime( ) ) && slt.getEndingTime( ).equals( slot.getEndingTime( ) )
731 && slt.getDate( ).getDayOfWeek( ).getValue( ) == slot.getDate( ).getDayOfWeek( ).getValue( ) )
732 .collect( Collectors.toList( ) ) );
733 }
734 return listBuilded;
735 }
736 }