View Javadoc
1   package fr.paris.lutece.plugins.aot.modules.declarationimmat.utils;
2   
3   import java.text.DecimalFormat;
4   import java.text.ParseException;
5   import java.text.SimpleDateFormat;
6   import java.time.LocalDate;
7   import java.time.Period;
8   import java.time.ZoneId;
9   import java.time.ZonedDateTime;
10  import java.time.temporal.ChronoUnit;
11  import java.util.Calendar;
12  import java.util.Date;
13  import java.util.List;
14  import java.util.Map;
15  import java.util.regex.Matcher;
16  import java.util.regex.Pattern;
17  
18  import org.apache.commons.lang3.StringUtils;
19  
20  import fr.paris.lutece.plugins.forms.business.FormQuestionResponse;
21  import fr.paris.lutece.plugins.genericattributes.business.Response;
22  import fr.paris.lutece.portal.service.util.AppLogService;
23  import fr.paris.lutece.portal.service.util.AppPropertiesService;
24  
25  /**
26   * DateUtils to find if a date is during the french holidays or a sunday.
27   *
28   */
29  public class CalculUtils
30  {
31  
32      private static Integer MIDDAY        = Integer.valueOf( AppPropertiesService.getProperty( "aot-declarationimmat.midday", "14" ) );
33      private static Integer MIDDAY_MINUTE = Integer.valueOf( AppPropertiesService.getProperty( "aot-declarationimmat.midday.minute", "30" ) );
34      private static Integer STARTDAY      = Integer.valueOf( AppPropertiesService.getProperty( "aot-declarationimmat.startday", "9" ) );
35      private static Integer ENDDAY        = Integer.valueOf( AppPropertiesService.getProperty( "aot-declarationimmat.endday", "20" ) );
36  
37      /**
38       * Private Constrctor.
39       */
40      private CalculUtils( )
41      {
42          super( );
43      }
44  
45      /**
46       * Calculate the number of days between two date.
47       * 
48       * @param date1
49       * @param date2
50       * @return
51       * @throws ParseException
52       */
53      public static Integer nbDaysBetweenTwoDate( String date1, String heure1, String date2, String heure2 ) throws ParseException
54      {
55  
56          Calendar calendar = Calendar.getInstance( );
57          calendar.setTime( org.apache.commons.lang3.time.DateUtils.parseDate( date1, "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" ) );
58          LocalDate first = LocalDate.of( calendar.get( Calendar.YEAR ), calendar.get( Calendar.MONTH ) + 1, calendar.get( Calendar.DAY_OF_MONTH ) );
59  
60          if ( StringUtils.isNotBlank( date2 ) )
61          {
62              calendar.setTime( org.apache.commons.lang3.time.DateUtils.parseDate( date2, "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" ) );
63          }
64          LocalDate second = LocalDate.of( calendar.get( Calendar.YEAR ), calendar.get( Calendar.MONTH ) + 1, calendar.get( Calendar.DAY_OF_MONTH ) );
65  
66          int nbDay = 0;
67          Period period = Period.between( first, second );
68          if ( StringUtils.isBlank( heure1 ) && StringUtils.isBlank( heure2 ) )
69          {
70  
71              nbDay = period.getDays( ) + 1;
72          }
73          else
74          {
75              nbDay = period.getDays( ) + 1 - nbHalfDaysBetweenTwoDate( date1, heure1, date2, heure2 );
76  
77          }
78          return nbDay;
79      }
80  
81      /**
82       * Calculate the number of business days between two date.
83       * 
84       * @param date1
85       * @param date2
86       * @return
87       * @throws ParseException
88       */
89      public static Integer nbBusinessDaysBetweenTwoDate( String date1, String heure1, String date2, String heure2 ) throws ParseException
90      {
91          Calendar calendar = Calendar.getInstance( );
92  
93          calendar.setTime( org.apache.commons.lang3.time.DateUtils.parseDate( date1, "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" ) );
94          ZonedDateTime first = ZonedDateTime.of( calendar.get( Calendar.YEAR ), calendar.get( Calendar.MONTH ) + 1, calendar.get( Calendar.DAY_OF_MONTH ), calendar.get( Calendar.HOUR_OF_DAY ),
95                  calendar.get( Calendar.MINUTE ), 0, 0, ZoneId.of( "Europe/Paris" ) );
96  
97          if ( StringUtils.isNotBlank( date2 ) )
98          {
99              calendar.setTime( org.apache.commons.lang3.time.DateUtils.parseDate( date2, "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" ) );
100         }
101         ZonedDateTime second = ZonedDateTime.of( calendar.get( Calendar.YEAR ), calendar.get( Calendar.MONTH ) + 1, calendar.get( Calendar.DAY_OF_MONTH ), calendar.get( Calendar.HOUR_OF_DAY ),
102                 calendar.get( Calendar.MINUTE ), 0, 0, ZoneId.of( "Europe/Paris" ) );
103 
104         int nbBusinessDay = 0;
105         while ( first.isBefore( second ) || first.truncatedTo( ChronoUnit.DAYS ).equals( second.truncatedTo( ChronoUnit.DAYS ) ) )
106         {
107             if ( !DateUtils.isDateDuringHolidayOrSunday( Date.from( first.toInstant( ) ) ) )
108             {
109                 nbBusinessDay++;
110             }
111             first = first.plusDays( 1 );
112         }
113 
114         return nbBusinessDay - nbHalfBusinessDaysBetweenTwoDate( date1, heure1, date2, heure2 );
115     }
116 
117     /**
118      * Calculate the number of half days between two date including hours, only half days are calculated, if a day is complete, it will not be added.
119      * 
120      * @param date1
121      * @param date2
122      * @param heure1
123      * @param heure2
124      * @return a number
125      * @throws ParseException
126      */
127     public static Integer nbHalfDaysBetweenTwoDate( String date1, String heure1, String date2, String heure2 ) throws ParseException
128     {
129         Calendar calendar = Calendar.getInstance( );
130 
131         calendar.setTime( org.apache.commons.lang3.time.DateUtils.parseDate( date1, "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" ) );
132         ZonedDateTime first = ZonedDateTime.of( calendar.get( Calendar.YEAR ), calendar.get( Calendar.MONTH ) + 1, calendar.get( Calendar.DAY_OF_MONTH ), calendar.get( Calendar.HOUR_OF_DAY ),
133                 calendar.get( Calendar.MINUTE ), 0, 0, ZoneId.of( "Europe/Paris" ) );
134 
135         if ( StringUtils.isNotBlank( date2 ) )
136         {
137             calendar.setTime( org.apache.commons.lang3.time.DateUtils.parseDate( date2, "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" ) );
138         }
139         ZonedDateTime second = ZonedDateTime.of( calendar.get( Calendar.YEAR ), calendar.get( Calendar.MONTH ) + 1, calendar.get( Calendar.DAY_OF_MONTH ), calendar.get( Calendar.HOUR_OF_DAY ),
140                 calendar.get( Calendar.MINUTE ), 0, 0, ZoneId.of( "Europe/Paris" ) );
141 
142         int nbBusinessDay = 0;
143 
144         boolean isMorning = getHours( heure2 ) < MIDDAY || ( getHours( heure2 ) == MIDDAY && getMinutes( heure2 ) <= MIDDAY_MINUTE );
145         boolean isAfterNoon = getHours( heure1 ) > MIDDAY || ( getHours( heure1 ) == MIDDAY && getMinutes( heure1 ) >= MIDDAY_MINUTE );
146 
147         if ( first.truncatedTo( ChronoUnit.DAYS ).equals( second.truncatedTo( ChronoUnit.DAYS ) ) )
148         {
149             // Same Day
150 
151             if ( ( getHours( heure2 ) >= 9 && isMorning ) || ( isAfterNoon && getHours( heure1 ) <= ENDDAY ) )
152             {
153                 nbBusinessDay++;
154             }
155 
156         }
157         else
158         {
159             // Test if first day is half day
160             if ( isAfterNoon && getHours( heure1 ) <= ENDDAY )
161             {
162 
163                 nbBusinessDay++;
164 
165             }
166             // Test if last day is half day
167             if ( getHours( heure2 ) >= STARTDAY && isMorning )
168             {
169 
170                 nbBusinessDay++;
171 
172             }
173 
174         }
175 
176         return nbBusinessDay;
177     }
178 
179     /**
180      * Calculate the number of half business days between two date including hours.
181      * 
182      * @param date1
183      * @param date2
184      * @param heure1
185      * @param heure2
186      * @return a number
187      * @throws ParseException
188      */
189     public static Integer nbHalfBusinessDaysBetweenTwoDate( String date1, String heure1, String date2, String heure2 ) throws ParseException
190     {
191         Calendar calendar = Calendar.getInstance( );
192 
193         calendar.setTime( org.apache.commons.lang3.time.DateUtils.parseDate( date1, "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" ) );
194         ZonedDateTime first = ZonedDateTime.of( calendar.get( Calendar.YEAR ), calendar.get( Calendar.MONTH ) + 1, calendar.get( Calendar.DAY_OF_MONTH ), calendar.get( Calendar.HOUR_OF_DAY ),
195                 calendar.get( Calendar.MINUTE ), 0, 0, ZoneId.of( "Europe/Paris" ) );
196 
197         if ( StringUtils.isNotBlank( date2 ) )
198         {
199             calendar.setTime( org.apache.commons.lang3.time.DateUtils.parseDate( date2, "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" ) );
200         }
201         ZonedDateTime second = ZonedDateTime.of( calendar.get( Calendar.YEAR ), calendar.get( Calendar.MONTH ) + 1, calendar.get( Calendar.DAY_OF_MONTH ), calendar.get( Calendar.HOUR_OF_DAY ),
202                 calendar.get( Calendar.MINUTE ), 0, 0, ZoneId.of( "Europe/Paris" ) );
203 
204         int nbBusinessDay = 0;
205 
206         boolean isMorning = getHours( heure2 ) < MIDDAY || ( getHours( heure2 ) == MIDDAY && getMinutes( heure2 ) <= MIDDAY_MINUTE );
207         boolean isAfterNoon = getHours( heure1 ) > MIDDAY || ( getHours( heure1 ) == MIDDAY && getMinutes( heure1 ) >= MIDDAY_MINUTE );
208 
209         if ( first.truncatedTo( ChronoUnit.DAYS ).equals( second.truncatedTo( ChronoUnit.DAYS ) ) )
210         {
211             // Same Day
212             if ( !DateUtils.isDateDuringHolidayOrSunday( Date.from( first.toInstant( ) ) ) && ( ( getHours( heure2 ) >= STARTDAY && isMorning ) || ( isAfterNoon && getHours( heure1 ) <= ENDDAY ) ) )
213             {
214                 nbBusinessDay++;
215             }
216 
217         }
218         else
219         {
220             // Test if first day is half day
221             if ( !DateUtils.isDateDuringHolidayOrSunday( Date.from( first.toInstant( ) ) ) && getHours( heure1 ) <= ENDDAY && isAfterNoon )
222             {
223 
224                 nbBusinessDay++;
225 
226             }
227             // Test if last day is half day
228             if ( !DateUtils.isDateDuringHolidayOrSunday( Date.from( second.toInstant( ) ) ) && getHours( heure2 ) >= STARTDAY && isMorning )
229             {
230 
231                 nbBusinessDay++;
232 
233             }
234 
235         }
236 
237         return nbBusinessDay;
238     }
239 
240     /**
241      * Sum all numeric value for each iteration of a signet.
242      * 
243      * @param signetToSum
244      *            the signet to sum
245      * @param questionsResponses
246      *            the list of question and response.
247      * @return a sum
248      */
249 
250     public static Double sumEachIteration( String signetToSum, List<FormQuestionResponse> questionsResponses )
251     {
252         Integer idSignetToSum = Integer.valueOf( signetToSum.replace( "signet", StringUtils.EMPTY ) );
253         Double sumResult = 0d;
254         for ( FormQuestionResponse formQuestionResponse : questionsResponses )
255         {
256             if ( idSignetToSum == formQuestionResponse.getQuestion( ).getId( ) )
257             {
258                 String value = formQuestionResponse.getEntryResponse( ) != null && !formQuestionResponse.getEntryResponse( ).isEmpty( )
259                         ? formQuestionResponse.getEntryResponse( ).get( 0 ).getResponseValue( )
260                         : "0";
261 
262                 if ( StringUtils.isNotBlank( value ) && Pattern.matches( "^[\\d.,]*$", value ) )
263                 {
264                     sumResult += Double.valueOf( value );
265                 }
266             }
267         }
268 
269         return sumResult;
270     }
271 
272     public static String obtainDate( String ordre, String pattern, String signetToUse, List<FormQuestionResponse> questionsResponses )
273     {
274         SimpleDateFormat sdf = new SimpleDateFormat( );
275         boolean isLong = Boolean.FALSE;
276         boolean isMax = Boolean.FALSE;
277         Date dateSaved = null;
278         if ( "LONG".equalsIgnoreCase( pattern ) )
279         {
280             isLong = Boolean.TRUE;
281         }
282         else
283         {
284             sdf.applyPattern( pattern );
285         }
286 
287         if ( "MAX".equalsIgnoreCase( ordre ) )
288         {
289             isMax = Boolean.TRUE;
290         }
291 
292         Integer idSignetToUse = Integer.valueOf( signetToUse.replace( "signet", StringUtils.EMPTY ) );
293 
294         for ( FormQuestionResponse formQuestionResponse : questionsResponses )
295         {
296             if ( idSignetToUse == formQuestionResponse.getQuestion( ).getId( ) )
297             {
298 
299                 for ( Response response : formQuestionResponse.getEntryResponse( ) )
300                 {
301 
302                     if ( StringUtils.isNotBlank( response.getResponseValue( ) ) )
303                     {
304                         Date dateToTest;
305                         try
306                         {
307                             dateToTest = org.apache.commons.lang3.time.DateUtils.parseDate( response.getResponseValue( ), "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" );
308                         }
309                         catch ( ParseException e )
310                         {
311                             dateToTest = null;
312                             AppLogService.error( "parseError : " + e.getMessage( ), e );
313                         }
314                         // test the date
315                         if ( dateSaved == null || ( isMax && dateSaved.before( dateToTest ) ) || ( !isMax && dateSaved.after( dateToTest ) ) )
316                         {
317                             dateSaved = dateToTest;
318                         }
319 
320                     }
321                 }
322             }
323         }
324         if ( dateSaved == null )
325         {
326             return StringUtils.EMPTY;
327         }
328         return isLong ? String.valueOf( dateSaved.getTime( ) ) : sdf.format( dateSaved );
329 
330     }
331 
332     /**
333      * Look in the formula to find what signet need to be put in the map for later use.
334      * 
335      * @param formula
336      *            the formula
337      * @param data
338      *            the map
339      */
340     public static void setSignetThatWillBeNedeedInTheFormula( String formula, String methodName, Map<String, Object> data )
341     {
342         String testFormula = formula.replaceAll( " ", StringUtils.EMPTY );
343         // if there is sommeLesIterations( take, what is next between ( and )
344         Pattern pattern = Pattern.compile( methodName + "\\((.+?)\\)" );
345         Matcher matcher = pattern.matcher( testFormula );
346         while ( matcher.find( ) )
347         {
348             String find = matcher.group( );
349             find = find.replaceAll( methodName + "\\(", StringUtils.EMPTY ).replaceAll( "\\)", StringUtils.EMPTY );
350             data.put( find.substring( find.indexOf( "signet" ), find.indexOf( ",listeQR" ) ), find.substring( find.indexOf( "signet" ), find.indexOf( ",listeQR" ) ) );
351 
352         }
353 
354     }
355 
356     /**
357      * Return only the hour from a String using a regex.
358      * 
359      * @param pHour
360      *            the string to test
361      * @return null, 0 or the hour
362      */
363     public static Integer getHours( String pHour )
364     {
365         Integer hour = null;
366         if ( StringUtils.isNotBlank( pHour ) )
367         {
368             hour = 0;
369 
370             Pattern pattern = Pattern.compile( "(?<!\\d{2}:)(\\d{2})(?=:|h)" );
371             Matcher matcher = pattern.matcher( pHour );
372 
373             while ( matcher.find( ) )
374             {
375                 String find = matcher.group( );
376 
377                 if ( StringUtils.isNotBlank( find ) && StringUtils.isNumeric( find.trim( ) ) )
378                 {
379                     hour = Integer.valueOf( find.trim( ) );
380                 }
381 
382             }
383         }
384         return hour;
385     }
386 
387     /**
388      * Return the minute from a String
389      * 
390      * @param pHour
391      *            the string to test
392      * @return null, 0 or the minutes
393      */
394     public static Integer getMinutes( String pHour )
395     {
396         Integer minutes = null;
397         if ( StringUtils.isNotBlank( pHour ) )
398         {
399             minutes = 0;
400             Pattern pattern;
401             if ( StringUtils.countMatches( pHour, ":" ) == 2 )
402             {
403                 pattern = Pattern.compile( "(?<=\\d{2}:)(\\d{2})(?=:\\d{2})" );
404             }
405             else
406             {
407                 pattern = Pattern.compile( "(?<=\\d{2}:|h)(\\d{2})(?!:\\d{2})" );
408             }
409 
410             Matcher matcher = pattern.matcher( pHour );
411 
412             while ( matcher.find( ) )
413             {
414                 String find = matcher.group( );
415 
416                 if ( StringUtils.isNotBlank( find ) && StringUtils.isNumeric( find.trim( ) ) )
417                 {
418                     minutes = Integer.valueOf( find.trim( ) );
419                 }
420 
421             }
422         }
423         return minutes;
424     }
425 
426     /**
427      * return a Double as a String like X.XX or X (if trailing 00)
428      * 
429      * @param result
430      *            the double
431      * @return the result formated
432      */
433     public static String getStringWithFormat( Double result )
434     {
435         // O2T 75276 supprimer les 00 si pas de d├ęcimale
436         if (result!=null)
437         {
438             String retour = new DecimalFormat( "#0.00" ).format( result ).replaceAll( ",", "." );
439             if ( retour.endsWith( ".00" ) )
440             {
441                 retour = retour.replaceAll( "\\.00", StringUtils.EMPTY ).trim( );
442             }
443             return retour;
444         }
445         return null;
446     }
447 
448 }