WeekDefinitionService.java
/*
* Copyright (c) 2002-2022, City of Paris
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice
* and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* License 1.0
*/
package fr.paris.lutece.plugins.appointment.service;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import fr.paris.lutece.plugins.appointment.business.planning.WeekDefinition;
import fr.paris.lutece.plugins.appointment.business.planning.WeekDefinitionHome;
import fr.paris.lutece.plugins.appointment.business.planning.WorkingDay;
import fr.paris.lutece.plugins.appointment.business.rule.ReservationRule;
import fr.paris.lutece.plugins.appointment.service.listeners.WeekDefinitionManagerListener;
import fr.paris.lutece.portal.service.util.AppException;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.util.ReferenceList;
import fr.paris.lutece.util.sql.TransactionManager;
/**
* Service class of a week definition
*
* @author Laurent Payen
*
*/
public final class WeekDefinitionService
{
/**
* Private constructor - this class does not need to be instantiated
*/
private WeekDefinitionService( )
{
}
/**
* Create a week definition in database
*
* @param nIdReservationRule
* the nIdReservationRule
* @param dateOfApply
* the date of the week definition
* @return the week definition created
*/
public static WeekDefinition createWeekDefinition( int nIdReservationRule, LocalDate dateOfApply, LocalDate endingDateOfApply )
{
WeekDefinition weekDefinition = new WeekDefinition( );
fillInWeekDefinition( weekDefinition, nIdReservationRule, dateOfApply, endingDateOfApply );
WeekDefinitionHome.create( weekDefinition );
// WeekDefinitionManagerListener.notifyListenersWeekDefinitionAssigned( weekDefinition.getIdWeekDefinition( ) );
return weekDefinition;
}
/**
* Remove the weekdefinition (and by cascade the working days and the time slots)
*
* @param nIdWeekDefinition
* the id of the week definition to delete
*/
public static void removeWeekDefinition( WeekDefinition weekDefinition )
{
WeekDefinitionHome.delete( weekDefinition.getIdWeekDefinition( ) );
WeekDefinitionManagerListener.notifyListenersWeekDefinitionUnassigned( weekDefinition );
}
/**
* Save a week definition
*
* @param weekDefinition
* the week definition to save
* @return the week definition saved
*/
public static WeekDefinition saveWeekDefinition( WeekDefinition weekDefinition )
{
WeekDefinitionHome.create( weekDefinition );
WeekDefinitionManagerListener.notifyListenersWeekDefinitionAssigned( weekDefinition );
return weekDefinition;
}
/**
* Fill the week definition object with the given parameters
*
* @param weekDefinition
* the week definition to fill in
* @param nIdForm
* the form id
* @param dateOfApply
* the date of the week definition
*/
public static void fillInWeekDefinition( WeekDefinition weekDefinition, int nIdReservationRule, LocalDate dateOfApply, LocalDate endingDateOfApply )
{
weekDefinition.setDateOfApply( dateOfApply );
weekDefinition.setEndingDateOfApply( endingDateOfApply );
weekDefinition.setIdReservationRule( nIdReservationRule );
}
/**
* Fin all the week definition of a form
*
* @param nIdForm
* the form Id
* @return the list of all the week definition of the form
*/
public static List<WeekDefinition> findListWeekDefinition( int nIdForm )
{
return WeekDefinitionHome.findByIdForm( nIdForm );
}
/**
* Find a week definition of a form by date of apply
*
* @param nIdForm
* the id form
* @param startingDate
* the starting date
* @param endingDate
* the ending date
* @return the list of week definition
*/
public static List<WeekDefinition> findWeekDefinitionByDateOfApply( int nIdForm, LocalDate startingDate, LocalDate endingDate )
{
List<WeekDefinition> listWeekDefinition = WeekDefinitionService.findListWeekDefinition( nIdForm );
// Filter on the list of week definition on the starting date and the ending date of display
listWeekDefinition = listWeekDefinition.stream( )
.filter( w -> ( w.getEndingDateOfApply( ).isEqual( startingDate ) || w.getEndingDateOfApply( ).isAfter( startingDate ) )
&& ( w.getDateOfApply( ).isBefore( endingDate ) || w.getDateOfApply( ).isEqual( endingDate ) ) )
.collect( Collectors.toList( ) );
return listWeekDefinition;
}
/**
* Find a week definition of a form and a date of apply
*
* @param nIdForm
* the form Id
* @param dateOfApply
* the date of apply of the week definition
* @return the week definition with the closest date of apply
*/
public static WeekDefinition findWeekDefinitionByIdFormAndClosestToDateOfApply( int nIdForm, LocalDate dateOfApply )
{
// Get all the week definitions
List<WeekDefinition> listWeekDefinition = WeekDefinitionHome.findByIdForm( nIdForm );
List<LocalDate> listDate = new ArrayList<>( );
for ( WeekDefinition weekDefinition : listWeekDefinition )
{
listDate.add( weekDefinition.getDateOfApply( ) );
}
// Try to get the closest date in past of the date of apply
LocalDate closestDate = Utilities.getClosestDateInPast( listDate, dateOfApply );
WeekDefinition weekDefinition = null;
// If there is no closest date in past
if ( closestDate == null )
{
// if the list of week definitions is not null
if ( CollectionUtils.isNotEmpty( listWeekDefinition ) )
{
// Get the next week definition in the future
weekDefinition = listWeekDefinition.stream( ).min( ( w1, w2 ) -> w1.getDateOfApply( ).compareTo( w2.getDateOfApply( ) ) ).orElse( null );
}
}
else
{
// There is a closest date in past
if ( CollectionUtils.isNotEmpty( listWeekDefinition ) )
{
// Get the corresponding week definition
weekDefinition = listWeekDefinition.stream( ).filter( x -> closestDate.isEqual( x.getDateOfApply( ) ) ).findAny( ).orElse( null );
}
}
return weekDefinition;
}
/**
* Find the weekdefinition of a form on a specific date
*
* @param nIdForm
* the form Id
* @param dateOfApply
* the date of the weekdefinition
* @return the weekdefinition object
*/
public static WeekDefinition findWeekDefinitionByIdFormAndDateOfApply( int nIdForm, LocalDate dateOfApply )
{
return WeekDefinitionHome.findByIdFormAndDateOfApply( nIdForm, dateOfApply );
}
/**
* Return, if it exists, the next week definition after a given date
*
* @param nIdForm
* the form id
* @param previousDateOfApply
* the previous date of the previous week definition
* @return the next week definition if it exists, null otherwise
*/
public static WeekDefinition findNextWeekDefinition( int nIdForm, LocalDate previousDateOfApply )
{
WeekDefinition nextWeekDefinition = new WeekDefinition( );
List<WeekDefinition> listWeekDefinition = WeekDefinitionHome.findByIdForm( nIdForm );
if ( CollectionUtils.isNotEmpty( listWeekDefinition ) )
{
listWeekDefinition = listWeekDefinition.stream( ).filter( x -> x.getDateOfApply( ).isAfter( previousDateOfApply ) ).collect( Collectors.toList( ) );
if ( CollectionUtils.isNotEmpty( listWeekDefinition ) )
{
nextWeekDefinition = listWeekDefinition.stream( ).min( ( w1, w2 ) -> w1.getDateOfApply( ).compareTo( w2.getDateOfApply( ) ) ).orElse( null );
}
}
return nextWeekDefinition;
}
/**
* Find a week definition with its primary key
*
* @param nIdWeekDefinition
* the week definition id
* @return the week definition found
*/
public static WeekDefinition findWeekDefinitionLightById( int nIdWeekDefinition )
{
return WeekDefinitionHome.findByPrimaryKey( nIdWeekDefinition );
}
/**
* Find a week definition by its primary key and set its working days
*
* @param nIdWeekDefinition
* the week definition id
* @return the week definition and its working days
*/
public static WeekDefinition findWeekDefinitionById( int nIdWeekDefinition )
{
return WeekDefinitionHome.findByPrimaryKey( nIdWeekDefinition );
}
/**
* Build a reference list of all the week definitions of a form
*
* @param nIdForm
* the form Id
* @return a reference list of all the week definitions of a form (Id of the week definition / date of apply of the week definition
*/
public static ReferenceList findAllDateOfWeekDefinition( int nIdForm )
{
ReferenceList listDate = new ReferenceList( );
List<WeekDefinition> listWeekDefinition = WeekDefinitionHome.findByIdForm( nIdForm );
for ( WeekDefinition weekDefinition : listWeekDefinition )
{
listDate.addItem( weekDefinition.getIdWeekDefinition( ), weekDefinition.getDateOfApply( ).format( Utilities.getFormatter( ) ) );
}
return listDate;
}
/**
* Find all the week definition of a form
*
* @param nIdForm
* the form id
* @return a HashMap with the date of apply in key and the week definition in value
*/
public static HashMap<LocalDate, WeekDefinition> findAllWeekDefinition( int nIdForm )
{
HashMap<LocalDate, WeekDefinition> mapWeekDefinition = new HashMap<>( );
List<WeekDefinition> listWeekDefinition = WeekDefinitionHome.findByIdForm( nIdForm );
for ( WeekDefinition weekDefinition : listWeekDefinition )
{
mapWeekDefinition.put( weekDefinition.getDateOfApply( ), weekDefinition );
}
return mapWeekDefinition;
}
/**
* Return the min starting time of a list of week definitions
*
* @param listWeekDefinition
* the list of week definitions
* @return the mini starting time
*/
public static LocalTime getMinStartingTimeOfAListOfWeekDefinition( List<ReservationRule> listReservationRules )
{
LocalTime minStartingTime = null;
LocalTime startingTimeTemp;
for ( ReservationRule reservation : listReservationRules )
{
startingTimeTemp = getMinStartingTimeOfAWeekDefinition( reservation );
if ( minStartingTime == null || startingTimeTemp.isBefore( minStartingTime ) )
{
minStartingTime = startingTimeTemp;
}
}
return minStartingTime;
}
/**
* Return the min starting time of a week definition
*
* @param weekDefinition
* the week definition
* @return the min starting time of the week definition
*/
public static LocalTime getMinStartingTimeOfAWeekDefinition( ReservationRule reservationRule )
{
return WorkingDayService.getMinStartingTimeOfAListOfWorkingDay( reservationRule.getListWorkingDay( ) );
}
/**
* Return the max ending time of a list of week definitions
*
* @param listWeekDefinition
* the list of week definitions
* @return the max ending time of the list of week definitions
*/
public static LocalTime getMaxEndingTimeOfAListOfWeekDefinition( List<ReservationRule> listReservationRules )
{
LocalTime maxEndingTime = null;
LocalTime endingTimeTemp;
for ( ReservationRule reservationRule : listReservationRules )
{
endingTimeTemp = getMaxEndingTimeOfAWeekDefinition( reservationRule );
if ( maxEndingTime == null || endingTimeTemp.isAfter( maxEndingTime ) )
{
maxEndingTime = endingTimeTemp;
}
}
return maxEndingTime;
}
/**
* Get the max ending time of a week definition
*
* @param weekDefinition
* the week definition
* @return the max ending time of the week definition
*/
public static LocalTime getMaxEndingTimeOfAWeekDefinition( ReservationRule reservationRule )
{
return WorkingDayService.getMaxEndingTimeOfAListOfWorkingDay( reservationRule.getListWorkingDay( ) );
}
/**
* Get the min duration of a time slot of a list of week definition
*
* @param listWeekDefinition
* the list of the week definitions
* @return the min duration time slot
*/
public static int getMinDurationTimeSlotOfAListOfWeekDefinition( List<ReservationRule> listReservationRules )
{
int nMinDuration = 0;
int nDurationTemp;
for ( ReservationRule reservationRule : listReservationRules )
{
nDurationTemp = getMinDurationTimeSlotOfAWeekDefinition( reservationRule );
if ( nMinDuration == 0 || nMinDuration > nDurationTemp )
{
nMinDuration = nDurationTemp;
}
}
return nMinDuration;
}
/**
* Get the min duration of a time slot of a week definition
*
* @param weekDefinition
* the week definition
* @return the min duration time slot
*/
public static int getMinDurationTimeSlotOfAWeekDefinition( ReservationRule reservationRule )
{
return WorkingDayService.getMinDurationTimeSlotOfAListOfWorkingDay( reservationRule.getListWorkingDay( ) );
}
/**
* Get the working days integer enum values of a list of week definitions
*
* @param listWeekDefinition
* the list of week definitions
* @return a set of the working days (integer value in a week : 1-> Monday ...) // The fullCalendar library is zero-base (Sunday=0)
*/
public static Set<String> getSetDaysOfWeekOfAListOfWeekDefinitionForFullCalendar( List<ReservationRule> listReservationRules )
{
Set<String> setDayOfWeek = new HashSet<>( );
for ( ReservationRule reservationRule : listReservationRules )
{
setDayOfWeek.addAll( WorkingDayService.getSetDaysOfWeekOfAListOfWorkingDayForFullCalendar( reservationRule.getListWorkingDay( ) ) );
}
return setDayOfWeek;
}
/**
* Get the set of the open days of all the week definitons
*
* @param listWeekDefinition
* the list of week definitions
* @return the set of the open days
*/
public static Set<Integer> getOpenDaysOfWeek( List<ReservationRule> listReservationRules )
{
HashSet<Integer> setOpenDays = new HashSet<>( );
for ( ReservationRule reservation : listReservationRules )
{
for ( WorkingDay workingDay : reservation.getListWorkingDay( ) )
{
setOpenDays.add( workingDay.getDayOfWeek( ) );
}
}
return setOpenDays;
}
/**
* Get the week definitions of a form for reservation rule
*
* @param nIdReservationRule
* @return list of week definition
*/
public static List<WeekDefinition> findByReservationRule( int nIdReservationRule )
{
return WeekDefinitionHome.findByReservationRule( nIdReservationRule );
}
/**
* Assign a week to the calendar
*
* @param nIdForm
* the id from
* @param newWeek
* the week to assign
*/
public static void assignWeekDefinition( int nIdForm, WeekDefinition newWeek )
{
LocalDate startingDate = newWeek.getDateOfApply( );
LocalDate endingDate = newWeek.getEndingDateOfApply( );
List<WeekDefinition> listWeek = WeekDefinitionService.findListWeekDefinition( nIdForm );
List<WeekDefinition> listWeekToRemove = listWeek.stream( )
.filter( week -> ( week.getDateOfApply( ).isAfter( startingDate ) || week.getDateOfApply( ).isEqual( startingDate ) )
&& ( week.getEndingDateOfApply( ).isBefore( endingDate ) || week.getEndingDateOfApply( ).isEqual( endingDate ) ) )
.collect( Collectors.toList( ) );
listWeek.removeAll( listWeekToRemove );
listWeek = listWeek.stream( )
.filter( p -> ( ( p.getDateOfApply( ).isBefore( startingDate ) || p.getDateOfApply( ).isEqual( startingDate ) )
&& p.getEndingDateOfApply( ).isAfter( startingDate ) || p.getEndingDateOfApply( ).isEqual( startingDate ) )
|| ( p.getDateOfApply( ).isBefore( endingDate ) || p.getDateOfApply( ).isEqual( endingDate ) )
&& p.getEndingDateOfApply( ).isAfter( endingDate )
|| p.getEndingDateOfApply( ).isEqual( endingDate ) )
.collect( Collectors.toList( ) );
List<WeekDefinition> buildListWeekToEdit = new ArrayList<>( );
for ( WeekDefinition week : listWeek )
{
if ( week.getDateOfApply( ).isBefore( startingDate ) && week.getEndingDateOfApply( ).isAfter( endingDate ) )
{
WeekDefinition weekToAdd = new WeekDefinition( );
weekToAdd.setDateOfApply( endingDate.plusDays( 1 ) );
weekToAdd.setEndingDateOfApply( week.getEndingDateOfApply( ) );
weekToAdd.setIdReservationRule( week.getIdReservationRule( ) );
buildListWeekToEdit.add( weekToAdd );
week.setEndingDateOfApply( startingDate.minusDays( 1 ) );
}
else
if ( week.getDateOfApply( ).isEqual( startingDate )
|| ( week.getDateOfApply( ).isAfter( startingDate ) && week.getEndingDateOfApply( ).isAfter( endingDate ) ) )
{
week.setDateOfApply( endingDate.plusDays( 1 ) );
}
else
if ( week.getEndingDateOfApply( ).isEqual( endingDate )
|| ( week.getDateOfApply( ).isBefore( startingDate ) && week.getEndingDateOfApply( ).isBefore( endingDate ) ) )
{
week.setEndingDateOfApply( startingDate.minusDays( 1 ) );
}
buildListWeekToEdit.add( week );
}
if ( newWeek.getIdReservationRule( ) != 0 )
{
buildListWeekToEdit.add( newWeek );
}
assignWeekDefintion( listWeekToRemove, buildListWeekToEdit, nIdForm );
WeekDefinitionManagerListener.notifyListenersWeekDefinitionAssigned( newWeek );
}
private static void assignWeekDefintion( List<WeekDefinition> listWeekTodRemove, List<WeekDefinition> listWeekToEdit, int nIdForm )
{
TransactionManager.beginTransaction( AppointmentPlugin.getPlugin( ) );
try
{
for ( WeekDefinition week : listWeekTodRemove )
{
WeekDefinitionHome.delete( week.getIdWeekDefinition( ) );
}
for ( WeekDefinition week : listWeekToEdit )
{
if ( week.getIdWeekDefinition( ) != 0 )
{
WeekDefinitionHome.delete( week.getIdWeekDefinition( ) );
}
WeekDefinitionHome.create( week );
}
TransactionManager.commitTransaction( AppointmentPlugin.getPlugin( ) );
// WeekDefinitionManagerListener.notifyListenersListWeekDefinitionChanged( nIdForm, listWeekToEdit );
}
catch( Exception e )
{
TransactionManager.rollBack( AppointmentPlugin.getPlugin( ) );
AppLogService.error( "Error assign week " + e.getMessage( ), e );
throw new AppException( e.getMessage( ), e );
}
}
}