Journey Manager (JM) The transaction engine for the platform. | System Manager / DevOps | All versions This feature is related to all versions.
You can configure steps of a collaboration job to expire depending on customer requirements, such as a Service Level AgreementA service-level agreement (SLA) is a commitment between a service provider and a client. Particular aspects of the service – quality, availability, responsibilities – are agreed between the service provider and the service user.. For example, you can implement a Review step to assign a task to a group, such as Reviewers group, so they have two days to action the task. Otherwise, it expires and will be routed to an Escalation step for a manager to review it.
The step expiry workflow is shown below.
You can implement step expiration using one of the following mechanisms:
expiryRule
attribute to specify the period of time, from its creation date, when the step will expire. You can also configure the Expiry Action, see Job Expiry Service, within a step. This allows for the clean-up code to be run. Steps that expire must define an Expiry Route; that is, a route with the Route Name Expiry. When the step expires, it is routed to the Next Step defined in the Expiry Route.
You can also download the application package with this example here.
This example uses the AVT-3547 Test Expiry form, which is a copy of Job Example 1 form, initiates a job controller. You can download the example below.
You can update an existing job controller by adding an Application Escalated step, so when the Application Review step expires, it will be routed to the Application Escalated step.
The AVT-3547 Test Expiry B job controller is a modified copy of the 1 Step Review job controller, where the version B introduces a new Group Task Step.
The Application Review step is modified to:
expiryServiceName
service.The Application Review and Application Escalated steps definition is shown below.
{
"name": "Application Review",
"type": "",
"expiryRule": "+1m",
"expiryServiceName": "Job Expiry - Expire Step Tasks",
"actions": [
{
"name": "Assign Review",
"type": "Job Task Assign",
"properties": [
{ "name": "Task Assign Groups", "value": "Job Reviewers" },
{ "name": "Task Form Code", "value": "$func.startFormCode()" },
{ "name": "Task Message", "value": "Please review the ${submission.formName} by ${formDataMap.firstName} ${formDataMap.lastName}." },
{ "name": "Task Review Previous Step", "value": "true" },
{ "name": "Task Subject", "value": "Review ${submission.formName} by by ${formDataMap.firstName} ${formDataMap.lastName}" },
{ "name": "Task Type", "value": "Review" }
]
},
{
"name": "Review Wait",
"type": "Job Task Wait"
}
],
"routes": [
{ "name": "Approve", "nextStep": "Application Delivery" },
{ "name": "Reject", "nextStep": "Application Rejected" },
{ "name": "Expiry", "nextStep": "Application Escalated", "display": "false" }
]
},
{
"name": "Application Escalated",
"type": "",
"actions": [
{
"name": "Assign Review",
"type": "Job Task Assign",
"properties": [
{ "name": "Task Assign Groups", "value": "Job Managers" },
{ "name": "Task Form Code", "value": "$func.startFormCode()" },
{ "name": "Task Message", "value": "The ${submission.formName} by ${formDataMap.firstName} ${formDataMap.lastName} has been escalated." },
{ "name": "Task Review Previous Step", "value": "true" },
{ "name": "Task Subject", "value": "Review Escalated ${submission.formName} by ${formDataMap.firstName} ${formDataMap.lastName}." },
{ "name": "Task Type", "value": "Review" }
]
},
{
"name": "Review Wait",
"type": "Job Task Wait"
}
]
This service cleans up an task that hasn't been submitted and returns the Expiry route name. If you are expiring a step that has tasks that have not been completed, then you will need to run a Job Expiry Action that cleans these up, as shown in the code below.
/* Groovy Job Expiry action service is a special type of job action service that is executed when a step expires.
It is used to clean up items such as tasks created by the step runs its actions.
Script parameters include:
actionContext : com.avoka.fc.core.service.job.ActionContext
actionStepProperties : com.avoka.fc.core.service.job.ActionStepProperties
serviceDefinition : com.avoka.fc.core.entity.ServiceDefinition
serviceParameters : Map<String, String>
job : com.avoka.fc.core.entity.Job
submission : com.avoka.fc.core.entity.Submission
formDataMap : Map<String, String>
Script return:
actionResult : com.avoka.fc.core.service.job.ActionResult
*/
import com.avoka.fc.core.dao.DaoFactory
import com.avoka.fc.core.entity.Job
import com.avoka.fc.core.entity.JobAction
import com.avoka.fc.core.entity.JobStep
import com.avoka.fc.core.entity.Submission
import com.avoka.fc.core.service.AbandonmentService
import com.avoka.fc.core.service.job.ActionResult
import com.avoka.fc.core.service.job.ActionResult.Status
import com.avoka.core.groovy.GroovyLogger as logger
final EXPIRY_ROUTE_NAME = "Expiry"
Date now = new Date()
JobAction expiryJobAction = actionContext.getJobAction()
JobStep step = expiryJobAction.jobStep
List<JobAction> jobActions = step.getOrderedJobActions();
jobActions.remove(expiryJobAction)
// the msg can't be longer than 2000 characters.
StringBuilder msg = new StringBuilder();
msg.append("The job step associated with this task has expired. ref Job: ")
.append(job.referenceNumber)
.append(" Step: ")
.append(step.name)
for (JobAction jobAction in jobActions) {
// Fix Job Actions that have not completed
if (jobAction.isStatusInProgress()
|| jobAction.isStatusAssigned()
|| jobAction.isStatusInvoked()
|| jobAction.isStatusPending()
|| jobAction.isStatusReady()) {
jobAction.setStatus(JobAction.STATUS_EXPIRED);
jobAction.setTimeFinished(now);
}
// Fix Tasks / Submissions in progress
Submission submission = jobAction.getSubmission()
if (submission != null) {
// Set For all Tasks in this step as the step has Expired we don't want to deliver the
submission.setDeliveryStatus(Submission.STATUS_NotRequired);
if (submission.isFormOpened()
|| submission.isFormAssigned()
|| submission.isFormSaved()
|| submission.isFormSubmitted()) {
submission.setFormStatus(Submission.STATUS_Abandoned)
submission.setAbandonmentType(AbandonmentService.ABANDONMENT_TYPE_SYSTEM)
submission.setAbandonmentTimestamp(now)
submission.setAbandonmentReason(msg.toString())
} else {
// For Tasks that were submitted
submission.setDeliveryTime(now);
submission.setAbandonmentReason(msg.toString())
}
if (submission.isDeliveryNotRequired()) {
if (submission.getPurgeTimeDataDelivered() == null) {
DaoFactory.submissionDao.setPurgeDatesForDeliveredAbandonedForms(submission);
}
}
}
}
ActionResult actionResult = new ActionResult(Status.COMPLETED)
actionResult.setRoute(EXPIRY_ROUTE_NAME)
return actionResult
This example uses the Core Transact API, but we recommend using the Fluent API instead whenever possible. A simple example is shown below:
import com.avoka.tm.job.*
import com.avoka.tm.util.*
import com.avoka.tm.vo.*
import groovy.transform.TypeChecked
import java.util.*
import javax.servlet.http.*
@TypeChecked
class FluentJobExpiryActionService {
/*
* Perform a job expiry action service invocation
*
* return: the job action result
*/
ActionResult invoke(SvcDef svcDef, Job job, JobAction jobAction, Map actionProperties, HttpServletRequest request, User user) {
// TODO: perform your logic
String xml = Jobs.getStartTxnXml(job)
Path path = new Path(xml)
String email = path.val('//Contact/Email')
return new ActionResultBuilder()
.setStatus('Completed')
.setMessage('Action completed for: ' + email)
.build()
}
}
Now, you can run the example and see how collaboration job's step expiry works.
This concludes the example.
You can also download the application package with this example here.
Next, learn about one step anonymous review collaboration jobs.