TaskChooseNextState.java
/*
* Copyright (c) 2002-2025, 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.workflow.modules.ticketing.service.task;
import java.util.List;
import java.util.Locale;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import fr.paris.lutece.api.user.User;
import fr.paris.lutece.plugins.ticketing.business.ticket.Ticket;
import fr.paris.lutece.plugins.ticketing.service.TicketInitService;
import fr.paris.lutece.plugins.workflow.modules.ticketing.business.config.TaskChooseNextStateConfig;
import fr.paris.lutece.plugins.workflowcore.business.action.Action;
import fr.paris.lutece.plugins.workflowcore.business.action.ActionFilter;
import fr.paris.lutece.plugins.workflowcore.business.resource.IResourceHistoryFactory;
import fr.paris.lutece.plugins.workflowcore.business.resource.ResourceHistory;
import fr.paris.lutece.plugins.workflowcore.business.resource.ResourceWorkflow;
import fr.paris.lutece.plugins.workflowcore.business.state.State;
import fr.paris.lutece.plugins.workflowcore.exception.WorkflowRuntimeException;
import fr.paris.lutece.plugins.workflowcore.service.action.IActionService;
import fr.paris.lutece.plugins.workflowcore.service.config.ITaskConfigService;
import fr.paris.lutece.plugins.workflowcore.service.resource.IResourceWorkflowService;
import fr.paris.lutece.plugins.workflowcore.service.resource.ResourceWorkflowService;
import fr.paris.lutece.plugins.workflowcore.service.state.IStateService;
import fr.paris.lutece.plugins.workflowcore.service.task.ITask;
import fr.paris.lutece.plugins.workflowcore.service.task.ITaskService;
import fr.paris.lutece.plugins.workflowcore.service.workflow.IWorkflowService;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.spring.SpringContextService;
import fr.paris.lutece.portal.service.util.AppException;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.util.sql.TransactionManager;
public class TaskChooseNextState extends AbstractTicketingTask
{
private static final String MESSAGE_MARK_TITLE = "module.workflow.ticketing.task_choose_next_state.labelChooseNextState";
private static final String BEAN_CHOOSE_NEXT_STATE_CONFIG_SERVICE = "workflow-ticketing.taskChooseNextStateConfigService";
private static final String PROPERTY_CHANNEL_SCAN_NAME = "ticketing.channelScan.name";
private String _strchannelScanName = AppPropertiesService.getProperty( PROPERTY_CHANNEL_SCAN_NAME );
private static final String PROPERTY_AUTOMATIC_INIT_ACTION = "ticketing.taskAutomaticInitAction.id";
private String _nActionInitWorkflowId = AppPropertiesService.getProperty( PROPERTY_AUTOMATIC_INIT_ACTION );
private IResourceWorkflowService _resourceWorkflowService = SpringContextService.getBean( ResourceWorkflowService.BEAN_SERVICE );
private static TicketInitService _ticketInitService = SpringContextService.getBean( TicketInitService.BEAN_NAME );
@Inject
private IWorkflowService _serviceWorkflow;
@Inject
private ITaskService _taskService;
@Inject
protected IActionService _actionService;
@Inject
protected IStateService _stateService;
@Inject
private IResourceHistoryFactory _resourceHistoryFactory;
@Inject
@Named( BEAN_CHOOSE_NEXT_STATE_CONFIG_SERVICE )
private ITaskConfigService _taskConfigService;
@Override
public String processTicketingTask( int nIdResourceHistory, HttpServletRequest request, Locale locale )
{
String strTaskInformation = StringUtils.EMPTY;
Ticket ticket = getTicket( nIdResourceHistory );
IWorkflowService workflowService = SpringContextService.getBean( "workflow.workflowService" );
Action action = _actionService.findByPrimaryKey( Integer.parseInt( _nActionInitWorkflowId ) );
List<ITask> listActionTasks = _taskService.getListTaskByIdAction( action.getId( ), Locale.getDefault( ) );
ITask task = listActionTasks.get( 0 );
State state = _stateService.getInitialState( 301 );
ResourceWorkflow resource = new ResourceWorkflow( );
resource.setIdResource( ticket.getId( ) );
resource.setResourceType( "ticket" );
resource.setWorkFlow( workflowService.findByPrimaryKey( state.getWorkflow( ).getId( ) ) );
resource.setState( state );
TaskChooseNextStateConfig config = _taskConfigService.findByPrimaryKey( this.getId( ) );
if ( task != null )
{
try
{
chooseNewState( resource.getIdResource( ), resource.getResourceType( ), task, config, 301, request, resource.getState( ).getId( ), ticket );
} catch ( Exception e )
{
AppLogService.error( "Unexpected Error", e );
}
}
return strTaskInformation;
}
@Override
public String getTitle( Locale locale )
{
return I18nService.getLocalizedString( MESSAGE_MARK_TITLE, locale );
}
@Override
public void doRemoveConfig( )
{
_taskConfigService.remove( getId( ) );
}
private void chooseNewState( int nIdResource, String strResourceType, ITask task, TaskChooseNextStateConfig config, int nIdWorkflow, HttpServletRequest request, int oldState, Ticket ticket )
{
int newState = -1;
if ( !ticket.getChannel( ).getLabel( ).equals( _strchannelScanName ) )
{
newState = config.getIdStateOK( );
} else
{
newState = config.getIdStateKO( );
}
if ( ( newState != -1 ) && ( newState != oldState ) )
{
doChangeState( task, nIdResource, strResourceType, nIdWorkflow, request, newState );
}
}
private void doChangeState( ITask task, int nIdResource, String strResourceType, int nIdWorkflow, HttpServletRequest request, int newState )
{
Locale locale = I18nService.getDefaultLocale( );
State state = _stateService.findByPrimaryKey( newState );
Action action = _actionService.findByPrimaryKey( task.getAction( ).getId( ) );
if ( ( state != null ) && ( action != null ) )
{
// Update Resource
ResourceWorkflow resourceWorkflow = _resourceWorkflowService.findByPrimaryKey( nIdResource, strResourceType, nIdWorkflow );
resourceWorkflow.setState( state );
_resourceWorkflowService.update( resourceWorkflow );
_ticketInitService.doProcessAutomaticReflexiveActions( nIdResource, strResourceType, state.getId( ), null, request, locale, null );
}
}
public void doProcessAction( int nIdResource, String strResourceType, int nIdAction, Integer nIdExternalParent, HttpServletRequest request, Locale locale, boolean bIsAutomatic,
String strUserAccessCode, User user )
{
Action action = _actionService.findByPrimaryKey( nIdAction );
if ( ( action == null ) )
{
return;
}
ResourceWorkflow resourceWorkflow = _resourceWorkflowService.findByPrimaryKey( nIdResource, strResourceType, action.getWorkflow( ).getId( ) );
if ( resourceWorkflow == null )
{
resourceWorkflow = _serviceWorkflow.getInitialResourceWorkflow( nIdResource, strResourceType, action.getWorkflow( ), nIdExternalParent );
if ( resourceWorkflow != null )
{
_resourceWorkflowService.create( resourceWorkflow );
}
}
// Create ResourceHistory
ResourceHistory resourceHistory = _resourceHistoryFactory.newResourceHistory( nIdResource, strResourceType, action, strUserAccessCode, bIsAutomatic, user );
_resourceHistoryService.create( resourceHistory );
List<ITask> listActionTasks = _taskService.getListTaskByIdAction( nIdAction, locale );
for ( ITask task : listActionTasks )
{
task.setAction( action );
try
{
task.processTask( resourceHistory.getId( ), request, locale, user );
} catch ( Exception e )
{
// Revert the creation of the resource history
_resourceHistoryService.remove( resourceHistory.getId( ) );
throw new WorkflowRuntimeException( "WorkflowService - Error when executing task ID " + task.getId( ), e );
}
}
// Reload the resource workflow in case a task had modified it
resourceWorkflow = _resourceWorkflowService.findByPrimaryKey( nIdResource, strResourceType, action.getWorkflow( ).getId( ) );
resourceWorkflow.setState( action.getStateAfter( ) );
resourceWorkflow.setExternalParentId( nIdExternalParent );
_resourceWorkflowService.update( resourceWorkflow );
}
/**
* Proceed automatic reflexive actions of state given in parameter. This method should be called anytime a service changed the state of a resource without
* proceeding a workflow action
*
* @param nIdResource
* the resource id
* @param strResourceType
* the resource type
* @param nIdState
* the state of the resource id
* @param nIdExternalParent
* the external parent id*
* @param locale
* locale
* @param user
* the user
*/
public void doProcessAutomaticReflexiveActions( int nIdResource, String strResourceType, int nIdState, Integer nIdExternalParent, Locale locale, User user )
{
try
{
TransactionManager.beginTransaction( null );
doProcessAutomaticReflexiveActionsNext( nIdResource, strResourceType, nIdState, nIdExternalParent, locale, user );
TransactionManager.commitTransaction( null );
}
catch( Exception e )
{
TransactionManager.rollBack( null );
throw new AppException( e.getMessage( ), e );
}
}
public void doProcessAutomaticReflexiveActionsNext( int nIdResource, String strResourceType, int nIdState, Integer nIdExternalParent, Locale locale, User user )
{
State state = _stateService.findByPrimaryKey( nIdState );
ActionFilter actionFilter = new ActionFilter( );
actionFilter.setIdWorkflow( state.getWorkflow( ).getId( ) );
actionFilter.setIdStateBefore( state.getId( ) );
actionFilter.setAutomaticReflexiveAction( true );
List<Action> listAction = _actionService.getListActionByFilter( actionFilter );
if ( CollectionUtils.isNotEmpty( listAction ) )
{
for ( Action action : listAction )
{
doProcessAction( nIdResource, strResourceType, action.getId( ), nIdExternalParent, null, locale, true, null, user );
}
}
}
}