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.modules.solr.service;
35
36 import fr.paris.lutece.plugins.appointment.business.slot.Slot;
37 import fr.paris.lutece.plugins.appointment.service.SlotService;
38 import fr.paris.lutece.plugins.appointment.service.WeekDefinitionService;
39 import fr.paris.lutece.plugins.appointment.web.dto.AppointmentFormDTO;
40 import fr.paris.lutece.plugins.search.solr.indexer.SolrIndexerService;
41 import fr.paris.lutece.plugins.search.solr.indexer.SolrItem;
42 import fr.paris.lutece.portal.web.l10n.LocaleService;
43 import fr.paris.lutece.util.url.UrlItem;
44 import org.apache.commons.collections.CollectionUtils;
45 import org.apache.commons.lang3.StringUtils;
46
47 import java.time.DayOfWeek;
48 import java.time.LocalDate;
49 import java.time.LocalDateTime;
50 import java.time.temporal.ChronoUnit;
51 import java.time.temporal.TemporalField;
52 import java.time.temporal.WeekFields;
53 import java.util.List;
54 import java.util.Objects;
55 import java.util.concurrent.atomic.AtomicInteger;
56 import java.util.stream.Collectors;
57
58
59
60
61
62
63
64 public final class SlotUtil
65 {
66
67 private static final String DAY_OPEN = "day_open";
68 private static final String ENABLED = "enabled";
69 private static final String SLOT_NB_FREE_PLACES = "slot_nb_free_places";
70 private static final String SLOT_NB_PLACES = "slot_nb_places";
71 private static final String DAY_OF_WEEK = "day_of_week";
72 private static final String MINUTE_OF_DAY = "minute_of_day";
73 private static final String NB_CONSECUTIVES_SLOTS = "nb_consecutives_slots";
74 private static final String APPOINTMENT_MULTISLOTS = "appointment_multislots";
75 private static final String MAX_CONSECUTIVES_SLOTS = "max_consecutives_slots";
76 private static final String UID_FORM = "uid_form";
77 private static final String URL_FORM = "url_form";
78 private static final String APPOINTMENT_SLOT = "appointmentslot";
79 private static final String VIEW_FORM = "getViewAppointmentForm";
80
81 private static final String PARAMETER_STARTING_DATETIME = "starting_date_time";
82 private static final String PARAMETER_ANCHOR = "anchor";
83 private static final String VALUE_ANCHOR = "step3";
84
85
86
87
88 private SlotUtil( )
89 {
90 }
91
92
93
94
95
96
97
98
99 public static String getSlotUid( Slot slot )
100 {
101 String strSlotDateFormatted = slot.getStartingDateTime( ).format( Utilities.SLOT_SOLR_ID_DATE_FORMATTER );
102 return "F" + slot.getIdForm( ) + "D" + strSlotDateFormatted;
103 }
104
105
106
107
108
109
110
111
112 public static String getSlotUrl( Slot slot )
113 {
114 UrlItem url = new UrlItem( SolrIndexerService.getBaseUrl( ) );
115 url.addParameter( Utilities.PARAMETER_XPAGE, Utilities.XPAGE_APPOINTMENT );
116 url.addParameter( Utilities.PARAMETER_VIEW, VIEW_FORM );
117 url.addParameter( FormUtil.PARAMETER_ID_FORM, slot.getIdForm( ) );
118 url.addParameter( PARAMETER_STARTING_DATETIME, slot.getStartingDateTime( ).toString( ) );
119 url.addParameter( PARAMETER_ANCHOR, VALUE_ANCHOR );
120 return url.getUrl( );
121 }
122
123
124
125
126
127
128
129
130
131
132 public static SolrItem getSlotItem( AppointmentFormDTO appointmentForm, Slot slot, List<Slot> allSlots )
133 {
134
135 SolrItem item = FormUtil.getDefaultFormItem( appointmentForm );
136 item.setUid( Utilities.buildResourceUid( getSlotUid( slot ), Utilities.RESOURCE_TYPE_SLOT ) );
137 item.addDynamicFieldNotAnalysed( UID_FORM, FormUtil.getFormUid( appointmentForm.getIdForm( ) ) );
138 item.setUrl( getSlotUrl( slot ) );
139 item.addDynamicFieldNotAnalysed( URL_FORM, FormUtil.getFormUrl( appointmentForm.getIdForm( ) ) );
140 item.setDate( slot.getStartingTimestampDate( ) );
141 item.setType( Utilities.SHORT_NAME_SLOT );
142 if ( StringUtils.isNotEmpty( appointmentForm.getAddress( ) ) && appointmentForm.getLongitude( ) != null && appointmentForm.getLatitude( ) != null )
143 {
144 item.addDynamicFieldGeoloc( APPOINTMENT_SLOT, appointmentForm.getAddress( ), appointmentForm.getLongitude( ), appointmentForm.getLatitude( ),
145 "appointmentslot-" + slot.getNbPotentialRemainingPlaces( ) + "/" + slot.getMaxCapacity( ) );
146 }
147 item.addDynamicFieldNotAnalysed( DAY_OPEN, String.valueOf( Boolean.TRUE ) );
148 item.addDynamicFieldNotAnalysed( ENABLED, String.valueOf( slot.getIsOpen( ) ) );
149 item.addDynamicField( SLOT_NB_FREE_PLACES, Long.valueOf( slot.getNbPotentialRemainingPlaces( ) ) );
150 item.addDynamicField( SLOT_NB_PLACES, Long.valueOf( slot.getMaxCapacity( ) ) );
151 item.addDynamicField( DAY_OF_WEEK, Long.valueOf( slot.getStartingDateTime( ).getDayOfWeek( ).getValue( ) ) );
152 item.addDynamicField( MINUTE_OF_DAY,
153 ChronoUnit.MINUTES.between( slot.getStartingDateTime( ).toLocalDate( ).atStartOfDay( ), slot.getStartingDateTime( ) ) );
154
155 long consecutiveSlots = calculateConsecutiveSlots(slot, allSlots);
156 item.addDynamicField( APPOINTMENT_MULTISLOTS, Boolean.toString( appointmentForm.getIsMultislotAppointment( ) ) );
157 if (appointmentForm.getIsMultislotAppointment()) {
158 item.addDynamicField(MAX_CONSECUTIVES_SLOTS, Long.valueOf(appointmentForm.getNbConsecutiveSlots()));
159 if (consecutiveSlots <= appointmentForm.getNbConsecutiveSlots()) {
160 item.addDynamicField(NB_CONSECUTIVES_SLOTS, consecutiveSlots);
161 }
162 else
163 {
164 item.addDynamicField(NB_CONSECUTIVES_SLOTS, (long) appointmentForm.getNbConsecutiveSlots());
165 }
166 } else {
167 item.addDynamicField(NB_CONSECUTIVES_SLOTS, 1L);
168 item.addDynamicField(MAX_CONSECUTIVES_SLOTS, 1L);
169 }
170
171
172 item.setHieDate( slot.getStartingDateTime( ).toLocalDate( ).format( Utilities.HIE_DATE_FORMATTER ) );
173 return item;
174 }
175
176
177
178
179
180
181
182
183 public static List<Slot> getAllSlots( AppointmentFormDTO appointmentForm )
184 {
185
186 int nNbWeeksToDisplay = appointmentForm.getNbWeeksToDisplay( );
187 LocalDate startingDateOfDisplay = LocalDate.now( );
188 if ( appointmentForm.getDateStartValidity( ) != null && startingDateOfDisplay.isBefore( appointmentForm.getDateStartValidity( ).toLocalDate( ) ) )
189 {
190 startingDateOfDisplay = appointmentForm.getDateStartValidity( ).toLocalDate( );
191 }
192
193
194
195
196 TemporalField fieldISO = WeekFields.of( LocaleService.getDefault( ) ).dayOfWeek( );
197 LocalDate dateOfSunday = startingDateOfDisplay.with( fieldISO, DayOfWeek.SUNDAY.getValue( ) );
198 LocalDate endingDateOfDisplay = dateOfSunday.plusWeeks( nNbWeeksToDisplay - 1L );
199 LocalDate endingValidityDate = null;
200 if ( appointmentForm.getDateEndValidity( ) != null )
201 {
202 endingValidityDate = appointmentForm.getDateEndValidity( ).toLocalDate( );
203 }
204 if ( endingValidityDate != null && endingDateOfDisplay.isAfter( endingValidityDate ) )
205 {
206 endingDateOfDisplay = endingValidityDate;
207 }
208 List<Slot> listSlots = SlotService.buildListSlot( appointmentForm.getIdForm( ),
209 WeekDefinitionService.findAllWeekDefinition( appointmentForm.getIdForm( ) ), startingDateOfDisplay, endingDateOfDisplay );
210
211
212 if ( CollectionUtils.isNotEmpty( listSlots ) && appointmentForm.getMinTimeBeforeAppointment( ) != 0 )
213 {
214 LocalDateTime dateTimeBeforeAppointment = LocalDateTime.now( ).plusHours( appointmentForm.getMinTimeBeforeAppointment( ) );
215 listSlots = listSlots.stream( ).filter( s -> s.getStartingDateTime( ).isAfter( dateTimeBeforeAppointment ) ).collect( Collectors.toList( ) );
216 }
217
218 return listSlots;
219 }
220
221 public static int calculateConsecutiveSlots( Slot slot, List<Slot> allSlots )
222 {
223 if ( slot.getNbPotentialRemainingPlaces( ) <= 0 )
224 {
225 return 0;
226 }
227 AtomicInteger consecutiveSlots = new AtomicInteger( 1 );
228 doCalculateConsecutiveSlots( slot, allSlots, consecutiveSlots );
229 return consecutiveSlots.get( );
230 }
231
232 private static void doCalculateConsecutiveSlots( Slot slot, List<Slot> allSlots, AtomicInteger consecutiveSlots )
233 {
234 for ( Slot nextSlot : allSlots )
235 {
236 if ( Objects.equals( slot.getEndingDateTime( ), nextSlot.getStartingDateTime( ) ) )
237 {
238 if ( nextSlot.getNbPotentialRemainingPlaces( ) > 0 && nextSlot.getIsOpen( ) )
239 {
240 consecutiveSlots.addAndGet( 1 );
241 doCalculateConsecutiveSlots( nextSlot, allSlots, consecutiveSlots );
242 }
243 else
244 {
245 break;
246 }
247 }
248 }
249 }
250 }