ConcourseSuite Support

Support
Corporate
PUBLIC PROFILE

Creating Workflows

The ConcourseSuite CRM framework includes a simple, component-based rules engine that can be used asynchronously for object events (events triggered by inserting, updating, or deleting objects) or for events that occur at a scheduled point in time.

A workflow process is comprised of Java components that act as Conditions or Actions. Conditional components usually inspect an object, then decide if the result is true or false. Action components perform an action based on the object, like sending an email.

The business process workflow is defined using XML, which can be imported into a system using the ConcourseSuite CRM Admin Module. The processes get cached when the application starts up and wait until triggered.

Example Workflow

The following process occurs every time a ticket is inserted or updated in ConcourseSuite CRM. The workflow is designed using Action Components and Condition Components. These components are included with ConcourseSuite CRM. Developers can completely modify this workflow, and others, by changing rules, properties and adding custom components to do just about anything.

Workflow - Ticket Example.png

Workflow XML

Each process is defined using XML. In the base CRM installation, a workflow_en_US.xml is provided, along with additional translated versions.

The workflow.xml file contains the following information:

  • Workflow Processes
  • The Objects and Actions which trigger a process
  • The Schedules which trigger a process

Defining a Workflow Process

A process has a unique name, a description, a startId which determines the first component in the process, a process type, and a module id which relates the process to a ConcourseSuite CRM module for viewing online.

The following process starts with component "2" which uses the QueryTicketJustClosed component to determine if the Ticket being inserted or updated has just been closed. This component will return a "true" or "false" and any components that respond to the condition will be triggered accordingly.

<processes>
  <process name="dhv.ticket.insert" description="Ticket change notification" startId="2" 
      type="OBJECT_EVENT" module="8">
    <components>
      <component id="2" class="org.aspcfs.modules.troubletickets.components.QueryTicketJustClosed"/>
      <component id="3" parent="2" if="false" 
        class="org.aspcfs.modules.troubletickets.components.QueryTicketJustAssigned"/>
      <component id="4" parent="2" if="true" 
          class="org.aspcfs.modules.components.SendEmailNotification">
        <parameters>
          <parameter name="notification.module" value="Tickets"/>
          <parameter name="notification.itemId" value="${this.id}"/>
          <parameter name="notification.itemModified" value="${this.modified}"/>
          <parameter name="notification.userToNotify" value="${previous.enteredBy}"/>
          <parameter name="notification.userGroupToNotify" value="${previous.userGroupId}"/>
          <parameter name="notification.subject">Ticket Closed: ${this.paddedTicketId}</parameter>
          <parameter name="notification.body"><![CDATA[<strong>The following ticket in ConcourseSuite CRM 
has been closed:</strong>
--- Ticket Details ---
<strong>Ticket #</strong> ${this.paddedTicketId}
Priority: ${ticketPriorityLookup.description}
Severity: ${ticketSeverityLookup.description}
Issue: ${this.problem}

Comment: ${this.comment}

Closed by: ${ticketModifiedByContact.nameFirstLast}

Solution: ${this.solution}
]]></parameter> </parameters> </component> <component id="5" parent="3" if="true" class="org.aspcfs.modules.components.SendEmailNotification"> <parameters> <parameter name="notification.module" value="Tickets"/> <parameter name="notification.itemId" value="${this.id}"/> <parameter name="notification.itemModified" value="${this.modified}"/> <parameter name="notification.userToNotify" value="${this.assignedTo}"/> <parameter name="notification.subject">Ticket Assigned: ${this.paddedTicketId}</parameter> <parameter name="notification.body"><![CDATA[<strong>The following ticket in ConcourseSuite CRM has been assigned to you:</strong>

--- Ticket Details ---

<strong>Ticket #</strong> ${this.paddedTicketId}
Priority: ${ticketPriorityLookup.description}
Severity: ${ticketSeverityLookup.description}
Issue: ${this.problem}

Assigned By: ${ticketModifiedByContact.nameFirstLast}
Comment: ${this.comment}
]]></parameter> </parameters> </component> <component id="7" parent="5" if="true" class="org.aspcfs.modules.components.SendEmailNotification"> <parameters> <parameter name="notification.module" value="Tickets"/> <parameter name="notification.itemId" value="${this.id}"/> <parameter name="notification.itemModified" value="${this.modified}"/> <parameter name="notification.userGroupToNotify" value="${this.userGroupId}"/> <parameter name="notification.skipUsers" value="${this.assignedTo}"/> <parameter name="notification.subject">Ticket Assigned: ${this.paddedTicketId}</parameter> <parameter name="notification.body"><![CDATA[<strong>The following ticket in ConcourseSuite CRM has been assigned to: ${ticketAssignedToContact.nameFirstLast}</strong>

--- Ticket Details ---

<strong>Ticket #</strong> ${this.paddedTicketId}
Priority: ${ticketPriorityLookup.description}
Severity: ${ticketSeverityLookup.description}
Issue: ${this.problem}

Assigned By: ${ticketModifiedByContact.nameFirstLast}
Comment: ${this.comment}
]]></parameter> </parameters> </component> <component id="6" parent="2" if="true" class="org.aspcfs.modules.troubletickets.components.SendTicketSurvey" enabled="false"/> </components> </process> </processes>

Triggering an Object Based Process

Most ConcourseSuite CRM Module Action Classes call processInsertHook(), processUpdateHook(), and processDeleteHook() when their objects are modified.

The following XML will enable ticket record triggers, when a ticket is inserted or updated in any module, including the HTTP-XML API... the same process is used for insert and update in this example.

<hooks>
  <hook class="org.aspcfs.modules.troubletickets.base.Ticket" module="8">
    <actions>
      <action type="update" process="dhv.ticket.insert" enabled="true"/>
      <action type="insert" process="dhv.ticket.insert" enabled="true"/>
    </actions>
  </hook>
</hooks>

Triggering a Schedule Based Process

Scheduled processes are great when integrating with other systems or for batch notification.

To schedule a process using standard CRON terminology, the following XML will trigger a process that emails a manager when tickets have not been assigned within 10 minutes.

<schedules>
  <schedule>
    <events>
      <event process="dhv.report.ticketList.overdue" 
        second="0" minute="*/10" hour="8-18" dayOfMonth="*" month="*" dayOfWeek="*" year="*" 
        extraInfo="" businessDays="true" enabled="true"/>
    </events>
  </schedule>
</schedules>

Workflow Components

ConcourseSuite CRM workflow components are Java objects intended to inspect data or act on data. As of Version 4.0, ConcourseSuite CRM ships with 42 "Query" workflow components and 5 "Action" components.

Most components extend the com.concursive.crm.workflow.ObjectHookComponent Class which provides easy access to database connections within a component, plus other useful methods. Components also implement the com.concursive.crm.workflow.ComponentInterface.

A Simple Component

The following component checks to see if a ticket was reassigned by the user... the result for components is always boolean.

public class QueryTicketJustAssigned extends ObjectHookComponent implements ComponentInterface {

  public String getDescription() {
    return "Was the ticket just assigned or reassigned?";
  }

  public boolean execute(ComponentContext context) {
    Ticket thisTicket = (Ticket) context.getThisObject();
    Ticket previousTicket = (Ticket) context.getPreviousObject();
    if (thisTicket != null) {
      if (previousTicket != null) {
        //Ticket was updated
        return ((thisTicket.getAssignedTo() != previousTicket.getAssignedTo())
            && thisTicket.getAssignedTo() > 0);
      } else {
        //Ticket was inserted
        return (thisTicket.getAssignedTo() > 0);
      }
    }
    return false;
  }

}

Registering a Component

ConcourseSuite CRM maintains a list of components in a library, which is read into memory when the web application starts.

Sign in to add your comment.