View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.appointment.modules.solr.service;
35  
36  import fr.paris.lutece.plugins.appointment.business.category.Category;
37  import fr.paris.lutece.plugins.appointment.business.category.CategoryHome;
38  import fr.paris.lutece.plugins.appointment.business.slot.Slot;
39  import fr.paris.lutece.plugins.appointment.service.FormService;
40  import fr.paris.lutece.plugins.appointment.web.dto.AppointmentFormDTO;
41  import fr.paris.lutece.plugins.search.solr.indexer.SolrIndexerService;
42  import fr.paris.lutece.plugins.search.solr.indexer.SolrItem;
43  import fr.paris.lutece.portal.service.image.ImageResourceManager;
44  import fr.paris.lutece.portal.web.l10n.LocaleService;
45  import fr.paris.lutece.util.url.UrlItem;
46  import org.apache.commons.lang3.StringUtils;
47  
48  import java.time.DayOfWeek;
49  import java.time.LocalDate;
50  import java.time.LocalDateTime;
51  import java.time.temporal.WeekFields;
52  import java.util.Arrays;
53  import java.util.List;
54  
55  /**
56   * Utils for the Appointment Form (Item, Url, Uid ...)
57   * 
58   * @author Laurent Payen
59   *
60   */
61  public final class FormUtil
62  {
63  
64      private static final String MIN_HOURS_BEFORE_APPOINTMENT = "min_hours_before_appointment";
65      private static final String FORM_ID_CATEGORY = "form_id_category";
66      private static final String APPOINTMENT_ACTIVE = "appointment_active";
67      private static final String URL_BASE = "url_base";
68      private static final String FORM_ID_TITLE = "form_id_title";
69      private static final String APPOINTMENT_MULTISLOTS = "appointment_multislots";
70      private static final String APPOINTMENT_MAX_CONSECUTIVES_SLOTS = "appointment_max_consecutives_slots";
71      private static final String APPOINTMENT_NB_FREE_PLACES = "appointment_nb_free_places";
72      private static final String APPOINTMENT_NB_PLACES = "appointment_nb_places";
73      private static final String VIEW_APPOINTMENT = "getViewAppointmentCalendar";
74  
75      private static final String FORM_ID_TITLE_SEPARATOR = "|";
76      private static final String DASH = "-";
77      private static final String SLASH = "/";
78  
79      public static final String PARAMETER_ID_FORM = "id_form";
80      private static final String IMAGE_RESOURCE_TYPE_ID = "appointmentForm_icon";
81      private static final String ICON_URL = "appointment_form_icon_url";
82  
83      /**
84       * Private constructor - this class does not need to be instantiated
85       */
86      private FormUtil( )
87      {
88      }
89  
90      /**
91       * Get the form Uid
92       * 
93       * @param nIdForm
94       *            the form id
95       * @return the form Uid
96       */
97      public static String getFormUid( int nIdForm )
98      {
99          return SolrIndexerService.getWebAppName( ) + Utilities.UNDERSCORE
100                 + Utilities.buildResourceUid( Integer.toString( nIdForm ), Utilities.RESOURCE_TYPE_APPOINTMENT );
101     }
102 
103     /**
104      * Get the form url
105      * 
106      * @param nIdForm
107      *            the form id
108      * @return the form url
109      */
110     public static String getFormUrl( int nIdForm )
111     {
112         UrlItem url = new UrlItem( SolrIndexerService.getBaseUrl( ) );
113         url.addParameter( Utilities.PARAMETER_XPAGE, Utilities.XPAGE_APPOINTMENT );
114         url.addParameter( Utilities.PARAMETER_VIEW, VIEW_APPOINTMENT );
115         url.addParameter( PARAMETER_ID_FORM, nIdForm );
116         return url.getUrl( );
117     }
118     /**
119      * Build and return the default form item for Solr
120      * 
121      * @param appointmentForm
122      *            the appointment form
123      * @return the form item
124      */
125     public static SolrItem getDefaultFormItem( AppointmentFormDTO appointmentForm )
126     {
127         SolrItem item = new SolrItem( );
128         item.setSummary( appointmentForm.getDescription( ) );
129         item.setTitle( appointmentForm.getTitle( ) );
130         item.setSite( SolrIndexerService.getWebAppName( ) );
131         item.setRole( appointmentForm.getRole( ) );
132         item.setXmlContent( StringUtils.EMPTY );
133         Category category = CategoryHome.findByPrimaryKey( appointmentForm.getIdCategory( ) );
134         if ( category != null )
135         {
136             item.setCategorie( Arrays.asList( category.getLabel( ) ) );
137             item.addDynamicField( FORM_ID_CATEGORY, (long) category.getIdCategory( ) );
138         }
139         StringBuilder stringBuilder = new StringBuilder( );
140         item.setContent( stringBuilder.toString( ) );
141         item.addDynamicField( MIN_HOURS_BEFORE_APPOINTMENT, (long) appointmentForm.getMinTimeBeforeAppointment( ) );
142         item.addDynamicFieldNotAnalysed( APPOINTMENT_ACTIVE, Boolean.toString( appointmentForm.getIsActive( ) ) );
143         item.addDynamicFieldNotAnalysed( URL_BASE, SolrIndexerService.getRootUrl( ) );
144         item.addDynamicFieldNotAnalysed( FORM_ID_TITLE, getFormUid( appointmentForm.getIdForm( ) ) + FORM_ID_TITLE_SEPARATOR + appointmentForm.getTitle( ) );
145         item.addDynamicFieldNotAnalysed( ICON_URL, SolrIndexerService.getRootUrl( ) + ImageResourceManager.getImageUrl( IMAGE_RESOURCE_TYPE_ID, appointmentForm.getIdForm() ));
146         return item;
147     }
148 
149     /**
150      * Build and return the Form Item for Solr
151      * 
152      * @param appointmentForm
153      *            the Appointment Form
154      * @param listSlots
155      *            the list of the slots of the form
156      * @return the Form Item
157      */
158     public static SolrItem getFormItem( AppointmentFormDTO appointmentForm, List<Slot> listSlots )
159     {
160         SolrItem item = getDefaultFormItem( appointmentForm );
161         item.setUrl( getFormUrl( appointmentForm.getIdForm( ) ) );
162         item.setUid( Utilities.buildResourceUid( Integer.toString( appointmentForm.getIdForm( ) ), Utilities.RESOURCE_TYPE_APPOINTMENT ) );
163         item.setDate( appointmentForm.getDateStartValidity( ) );
164         item.setType( Utilities.SHORT_NAME_APPOINTMENT );
165         int freePlaces = 0;
166         int places = 0;
167         for ( Slot slot : listSlots )
168         {
169             freePlaces += Math.max( 0, slot.getNbPotentialRemainingPlaces( ) );
170             places += slot.getMaxCapacity( );
171         }
172         if ( StringUtils.isNotEmpty( appointmentForm.getAddress( ) ) && appointmentForm.getLongitude( ) != null && appointmentForm.getLatitude( ) != null )
173         {
174             item.addDynamicFieldGeoloc( Utilities.SHORT_NAME_APPOINTMENT, appointmentForm.getAddress( ), appointmentForm.getLongitude( ),
175                     appointmentForm.getLatitude( ), Utilities.SHORT_NAME_APPOINTMENT + DASH + freePlaces + SLASH + places );
176         }
177         item.addDynamicField( APPOINTMENT_MULTISLOTS, Boolean.toString( appointmentForm.getIsMultislotAppointment( ) ) );
178         if( appointmentForm.getIsMultislotAppointment( ) ) {
179             item.addDynamicField(APPOINTMENT_MAX_CONSECUTIVES_SLOTS, Long.valueOf(appointmentForm.getNbConsecutiveSlots()));
180         }
181         else {
182             item.addDynamicField(APPOINTMENT_MAX_CONSECUTIVES_SLOTS,  1L);
183         }
184         item.addDynamicField( APPOINTMENT_NB_FREE_PLACES, Long.valueOf( freePlaces ) );
185         item.addDynamicField( APPOINTMENT_NB_PLACES, Long.valueOf( places ) );
186         // Date Hierarchy
187         if ( appointmentForm.getDateStartValidity( ) != null )
188         {
189             item.setHieDate( appointmentForm.getDateStartValidity( ).toLocalDate( ).format( Utilities.HIE_DATE_FORMATTER ) );
190         }
191         return item;
192     }
193 
194     /**
195      * check if the period between the startingDate and endingDate is displayed on the calendar FO
196      * 
197      * @param nIdForm
198      *            the form
199      * @param stratingDate
200      *            the starting period
201      * @param endingDate
202      *            the ending period
203      * @return true if the period between the startingDate and endingDate is displayed on the calendar FO
204      */
205     public static boolean isPeriodValidToIndex( int nIdForm, LocalDate stratingDate, LocalDate endingDate )
206     {
207 
208         AppointmentFormDTO form = FormService.buildAppointmentFormWithoutReservationRule( nIdForm );
209 
210         int nNbWeeksToDisplay = form.getNbWeeksToDisplay( );
211         LocalDate startingDateOfDisplay = LocalDateTime.now( ).plusHours( form.getMinTimeBeforeAppointment( ) ).toLocalDate( );
212         if ( form.getDateStartValidity( ) != null && startingDateOfDisplay.isBefore( form.getDateStartValidity( ).toLocalDate( ) ) )
213         {
214             startingDateOfDisplay = form.getDateStartValidity( ).toLocalDate( );
215         }
216         // Calculate the ending date of display with the nb weeks to display since today
217         // We calculate the number of weeks including the current week, so it and will end to the (n) next sunday
218         LocalDate endingDateOfDisplay = startingDateOfDisplay.with( WeekFields.of( LocaleService.getDefault( ) ).dayOfWeek( ), DayOfWeek.SUNDAY.getValue( ) )
219                 .plusWeeks( nNbWeeksToDisplay - 1L );
220         if ( form.getDateEndValidity( ) != null && endingDateOfDisplay.isAfter( form.getDateEndValidity( ).toLocalDate( ) ) )
221         {
222             endingDateOfDisplay = form.getDateEndValidity( ).toLocalDate( );
223         }
224 
225         return !( stratingDate.isAfter( endingDateOfDisplay ) || endingDate.isBefore( startingDateOfDisplay ) );
226 
227     }
228 
229 }