ullFlow: create new workflow

Introduction

In this tutorial we'll create an example workflow for a purchase request.

 

Prerequisites

  • Log in as admin

Create new workflow application

  • Main navigation -> Admin -> Workflow -> Manage applications
  • Create
  • Unique identifier: a unique string ("slug") for our new application
    • purchase_request
  • Label: Purchase request
  • Label of a document: Purchase request

Setup the fields

Each workflow application has a form which is made up of different fields like subject, text, email, etc.

  • Main navigation -> Admin -> Workflow -> Manage columns
  • Create
    • Application: Purchase request
    • Unique identifier: a unique string ("slug") for our new field
      • subject
    • Sequence: ordering of the fields. We recommend to use 1000, 2000, ...
      • 1000
    • Type: Link
      • This is only used for the subject
    • Enabled: yes
    • Show in list: no (subject is listed anyway)
    • Mandatory: yes
    • Is subject: yes
      • This is only used for the subject
    • Label: Subject
  • Repeat the create step with the following values:
    • Application: Purchase request
    • Unique Identifier: description
    • Sequence: 2000
    • Type: Textarea
    • Show in list: no
    • Mandatory: yes
    • Label: Description
  • Repeat the create step with the following values:
    • Application: Purchase request
    • Unique Identifier: reason
    • Sequence: 3000
    • Type: Textarea
    • Show in list: no
    • Mandatory: yes
    • Label: Reason
  • Repeat the create step with the following values:
    • Application: Purchase request
    • Unique Identifier: amount
    • Sequence: 4000
    • Type: Integer (TODO: creat float type)
    • Show in list: no
    • Mandatory: yes
    • Label: Amount

Setup workflow steps

The process of each workflow is defined by "steps". In most cases they are identical to roles.

  • Main navigation -> Admin -> Workflow -> Manage steps
  • Create
    • Application: Purchase request
    • Unique identifier: purchase_request_creator
      • It's a good idea to use the app's identifier so one don't get confused because every workflow as an "creator" for example
    • Is start-step: yes
      • This is only used for the first step
    • Label: Creator
  • Repeat the same for:
    • Application: Purchase request
    • Unique identifier: purchase_request_superior
    • Is start-step: no
    • Label: Superior
  • Repeat the same for:
    • Application: Purchase request
    • Unique identifier: purchase_request_ceo
    • Is start-step: no
    • Label: CEO
  • Repeat the same for:
    • Application: Purchase request
    • Unique identifier: purchase_request_purchaser
    • Is start-step: no
    • Label: Purchaser
  • Repeat the same for:
    • Application: Purchase request
    • Unique identifier: purchase_request_closed
    • Is start-step: no
    • Label: Closed

  

Setup the actions for the workflow steps

Let's define for each workflow step which actions should be available.

 

The process of each workflow is defined by "steps". In most cases they are identical to roles.

  • Main navigation -> Admin -> Workflow -> Manage actions for steps
  • Create
    • Step: Creator (Purchase Request)
    • Action: Sent
  • Repeat the same for:
    • Step: Superior (Purchase Request)
    • Action: Approved
  • Introduction

    In this tutorial we'll create an example workflow for a purchase request.

     

    Prerequisites

  • Log in as admin

Create new workflow application

  • Main navigation -> Admin -> Workflow -> Manage applications
  • Create
  • Unique identifier: a unique string ("slug") for our new application
    • purchase_request
  • Label: Purchase request
  • Label of a document: Purchase request

Setup the fields

Each workflow application has a form which is made up of different fields like subject, text, email, etc.

  • Main navigation -> Admin -> Workflow -> Manage columns
  • Create
    • Application: Purchase request
    • Unique identifier: a unique string ("slug") for our new field
      • my_subject
        (Don't use "subject", as it is also  a native UllFlowDoc property)
    • Sequence: ordering of the fields. We recommend to use 1000, 2000, ...
      • 1000
    • Type: Link
      • This is only used for the subject
    • Enabled: yes
    • Show in list: no (subject is listed anyway)
    • Mandatory: yes
    • Is subject: yes
      • This is only used for the subject
    • Label: Subject
  • Repeat the create step with the following values:
    • Application: Purchase request
    • Unique Identifier: description
    • Sequence: 2000
    • Type: Textarea
    • Show in list: no
    • Mandatory: yes
    • Label: Description
  • Repeat the create step with the following values:
    • Application: Purchase request
    • Unique Identifier: reason
    • Sequence: 3000
    • Type: Textarea
    • Show in list: no
    • Mandatory: yes
    • Label: Reason
  • Repeat the create step with the following values:
    • Application: Purchase request
    • Unique Identifier: amount
    • Sequence: 4000
    • Type: Integer (TODO: creat float type)
    • Show in list: no
    • Mandatory: yes
    • Label: Amount

Setup workflow steps

The process of each workflow is defined by "steps". In most cases they are identical to roles.

  • Main navigation -> Admin -> Workflow -> Manage steps
  • Create
    • Application: Purchase request
    • Unique identifier: purchase_request_creator
      • It's a good idea to use the app's identifier so one don't get confused because every workflow as an "creator" for example
    • Is start-step: yes
      • This is only used for the first step
    • Label: Creator
  • Repeat the same for:
    • Application: Purchase request
    • Unique identifier: purchase_request_superior
    • Is start-step: no
    • Label: Superior
  • Repeat the same for:
    • Application: Purchase request
    • Unique identifier: purchase_request_ceo
    • Is start-step: no
    • Label: CEO
  • Repeat the same for:
    • Application: Purchase request
    • Unique identifier: purchase_request_purchaser
    • Is start-step: no
    • Label: Purchaser
  • Repeat the same for:
    • Application: Purchase request
    • Unique identifier: purchase_request_closed
    • Is start-step: no
    • Label: Closed

  

Setup the actions for the workflow steps

Let's define for each workflow step which actions should be available.

 

The process of each workflow is defined by "steps". In most cases they are identical to roles.

  • Main navigation -> Admin -> Workflow -> Manage actions for steps
  • Create
    • Step: Creator (Purchase Request)
    • Action: Sent
  • Repeat the same for:
    • Step: Superior (Purchase Request)
    • Action: Approved
  • Repeat the same for:
    • Step: Superior (Purchase Request)
    • Action: Rejected
  • Repeat the same for:
    • Step: CEO (Purchase Request)
    • Action: Approved
  • Repeat the same for:
    • Step: CEO (Purchase Request)
    • Action: Rejected
  • Repeat the same for:
    • Step: Purchaser (Purchase Request)
    • Action: Closed 

Setup users

Since we don't have existing superior, CEO and purchaser users in our test environment yet, let's create them.

If you don't want to set a particular superior for a user, select "Master Admin". Use the first name as username.

  • Main navigation -> Admin -> Manage users
  • Create
    • Peter Purchasiator, the purchaser
    • Conny Ceomatic, the CEO
    • Bert Boss, the superior, with Conny Ceomatic as superior
    • Ullrich User, the user, with Bert Boss as superior

Setup groups

Since it is no good idea to hardcode users, we create Groups for our roles:

  • Main navigation -> Admin -> Manage groups
  • Create
    • Display name: CEO
  • Repeat the same for:
    • Display name: Purchaser

Setup group memberships

  • Main navigation -> Admin -> Manage group permissions
  • Put Conny Ceiomatic into the CEO group
  • Put Peter Purchasiator into the Purchaser group

Write rule script

A simple PHP rule script allows for great flexibility of the workflow. The rulescript defines per step and action what to do.

  • The scripts are located in apps/frontend/modules/ullFlow/lib/
  • Note: Look into the existing ullFlowRuleTroubleTicket.class.php for reference.
  • The naming convention is ullFlowRuleXXX.class.php where XXX stands for the camel case version of your app identifier.
    • In our example: ullFlowRulePurchaseRequest.php
  • The rule file is composed of a class named ullFlowRuleXXX and one method "getNext()". The initial version of the rule file should look like this:
    • <?php
      
      class ullFlowRulePurchaseRequest extends ullFlowRule
      {
        
        public function getNext()
        {
          $next = array();
      
          return $next;
        }
      }
  • The parent class ullFlowRule offers access to the workflow form's data and some methods to do something depending on the current step and action that was taken.
  • All the magic happens by returning the $next array. $next is a simple array which expects two keys:
    • 'step' - expects the next step to which the document should be assigend to - Takes a UllFlowStep object
    • 'entity' - expects the next user/group to which the document should be assigend to - Takes a UllFlowUser or UllFlowGroup object
       
    • Note: you don't have to set both keys. If no value is set, the current value is preserved.
  •  Now let's insert the handling for the first step "Creator":
    •   public function getNext()
        {
          $next = array();
      
          if ($this->isStep('purchase_request_creator')) 
          {
            $next['step']    = $this->findStep('purchase_request_superior');
            $next['entity']  = $this->findSuperior();
          }
         
          return $next;
        }
  •  But this doesn't handle the case when there is no superior for a user. So let's adapt it:
    •  
        public function getNext()
        {
          $next = array();
          if ($this->isStep('purchase_request_creator')) 
          {
            if ($superior = $this->findSuperior())
            {
              $next['step']    = $this->findStep('purchase_request_superior');
              $next['entity']  = $superior;
            }
            // if no superior skip the superior step
            else      
            {
              $next['step']    = $this->findStep('purchase_request_cio');
              $next['entity']  = $this->findGroup('CIO');
            }
          }
         
          return $next;
        }
  • Now let's add the rules for the remaining steps:
    •   public function getNext()
        {
          $next = array();
         
          if ($this->isStep('purchase_request_creator'))
          {
            if ($superior = $this->findSuperior())
            {
              $next['step']    = $this->findStep('purchase_request_superior');
              $next['entity']  = $superior;
            }
            else
            // skip the superior step
            {
              $next['step']    = $this->findStep('purchase_request_ceo');
              $next['entity']  = $this->findGroup('CEO');
            }
          }
          
          elseif ($this->isStep('purchase_request_superior'))
          {
            $next['step']    = $this->findStep('purchase_request_ceo');
            $next['entity']  = $this->findGroup('CEO');
          }
           
          elseif ($this->isStep('purchase_request_ceo'))
          {
            $next['step']    = $this->findStep('purchase_request_purchaser');
            $next['entity']  = $this->findGroup('Purchaser');
          } 
         
          return $next;
        }
  • While this is ok and valid, I don't think the CEO will be too pleased if he receives every single small purchase request for copy paper etc. So let's implement that he only receives purchase requests with an amount over 5000 currencies.
    Our complete rule file now looks like this:
    •  <?php
      
      class ullFlowRulePurchaseRequest extends ullFlowRule
      {
         
        public function getNext()
        {
          $next = array();
          
          if ($this->isStep('purchase_request_creator'))
          {
            if ($superior = $this->findSuperior())
            {
              $next['step']    = $this->findStep('purchase_request_superior');
              $next['entity']  = $superior;
            }
            // skip the superior step
            else      
            {
              $next = $this->getNextForCEO();
            }
          }
           
          elseif ($this->isStep('purchase_request_superior'))
          {
            if ($this->isAction('approve'))
            {
              $next = $this->getNextForCEO();
            }
          }
            
          elseif ($this->isStep('purchase_request_ceo'))
          {
            if ($this->isAction('approve'))
            {
              $next['step']    = $this->findStep('purchase_request_purchaser');
              $next['entity']  = $this->findGroup('Purchaser');
            }
          }  
          
          return $next;
        }
       
        /**
         * Return next parameters depending on the amount
         *
         * @return array
         */
        protected function getNextForCEO()
        {
          if ($this->doc->amount >= 5000)
          {
            $next['step']    = $this->findStep('purchase_request_ceo');
            $next['entity']  = $this->findGroup('CEO');
          }
          else
          // skip CEO
          {
            $next['step']    = $this->findStep('purchase_request_purchaser');
            $next['entity']  = $this->findGroup('Purchaser');
          }
          
          return $next;
        }
       
      }

Custom workflow application icons

If you want to install custom application icons, you can put them in "web/images/workflow_app_icons/".

 

They need to be available in 16x16, 24x24 and 32x32px. The first piece of the filename has to be the app slug.

 

Example: purchase_request_16x16.png