How To Add a Flow To Mifos

Introduction

This page describes adding a flow to mifos using the create user workflow example.

The navigation flow is the following:

A user clicks on define system user link in Admin part of mifos application.

  1. The first page is displayed containing all applicable offices for associating a user with. A user clicks on an office link and directed to step 2.
  2. Next, the user is presented with a form for entering all user information where they can enter details and click on preview button or cancel.
  3. Next, the user is shown a preview of all details previously entered whereby the user can re-edit the detail (back to step 2), submit the details or cancel.

If everything is successful, the user will be directed to a confirmation screen.

Create Flow XML File

  • create an xml file and place it within flows folder of WEB-INF in application module (or specific module if it exists)

See

application/src/main/webapp/WEB-INF/flows/user.xml

Start by Expressing View Navigation

Handy Hint

Begin by simply expressing the basic view navigation using view-state, transition, and end-state elements

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

	<view-state id="chooseOfficeStep" view="chooseUserOffice">
		<transition on="officeSelected" to="enterUserDetailsStep" />
		<transition on="cancel" to="cancel" />
	</view-state>

	<view-state id="enterUserDetailsStep" view="enterUserDetails">
		<transition on="preview" to="reviewUserDetailsStep" />
		<transition on="cancel" to="cancel" />
	</view-state>

	<view-state id="reviewUserDetailsStep" view="reviewUserDetails">
		<transition on="reedit" to="enterUserDetailsStep" />
		<transition on="submit" to="success" />
		<transition on="cancel" to="cancel" />
	</view-state>

	<end-state id="success" view="externalRedirect:contextRelative:/AdminAction.do?method=load" />
        <end-state id="cancel" view="externalRedirect:contextRelative:/AdminAction.do?method=load"/>
</flow>

Initial Starting State

The first state declared in the flow is the starting state of the flow.

Default Views

A view-state can have any id but you need to use the view attribute if a .ftl file of the same name as the view-state id does not exist.

Create View and Events for Transitioning To Other States in Flow

So far within the flow, we have declared our choose office, enter user details, and review user details steps of the create user flow. Each view-state also has some transitions which tell spring web flow to navigate to another view state based on a given event. To make the flow functional we need to add the freemarker .ftl files and support the firing of events based on user interaction.

Choose Offfice - transition when officeSelected event is raised
  • Create a file chooseUserOffice.ftl

This page will display a list of offices so we use html link to fire the appropriate event so flow transitions to next step.

<a href="${flowExecutionUrl}&_eventId=officeSelected&officeId=${branch.id}">${branch.name}</a>

which would result is something like

<a href="/mifos-webapp/user.ftl?execution=e2s1&_eventId=officeSelected&officeId=1">Mifos HO</a>

Spring Web Flow Info

flowExecutionUrl - important and tells web flow that you are still taking part in the specific flow/conversation

_eventId=officeSelected - _eventId is recognised by spring web flow for identifying events

officeId=1 - passing along further information in the request which can be retrieve using requestParameters

We also need to support the cancel event which transitions the user to an end-state.

Choose Offfice - transition to end-state when cancel event is raised

To implement this on chooseUserOffice.ftl we use the form based approach for raising an event.

     <form method="post" action="user.ftl?execution=${flowExecutionKey}">
           <input class="buttn2" type="submit" name="_eventId_cancel" value="Cancel" />
     </form>

Spring Web Flow Info

post, action - we post the data and set the action url to be the flow url with flowExecution info

_eventId_cancel- _eventId_ is recognised by spring web flow for identifying events and cancel is stripped off as the event.

enterUserDetailsStep and reviewUserDetailsStep

In enterUserDetailsStep we need to enable two events, preview and cancel.

     <form name="enterUserDetails" method="post" action="user.ftl?execution=${flowExecutionKey}">
            <input class="buttn" type="submit" id="preview" name="_eventId_preview" value="Preview" />
	    <input class="buttn2" type="submit" id="cancel" name="_eventId_cancel" value="Cancel" />
     </form>

In reviewUserDetailsStep we need to enable three events, reedit, submit and cancel

     <form method="post" action="user.ftl?execution=${flowExecutionKey}">
            <input class="buttn2" type="submit" name="_eventId_reedit" value="Edit personal information" />
             <input class="buttn" type="submit" name="_eventId_submit" value="Submit" />
	    <input class="buttn2" type="submit" id="cancel" name="_eventId_cancel" value="Cancel" />
     </form>

Testing navigation

entering user.ftl will now force execution to go through spring web flow.

At this point should be possible to navigate around all the different views.

Use action-state and evaluate to handle behaviour

Now we've expressed the navigation through the use of view-states, transitions and end-states, its now time to start making the flow useful. We can do this using action-state, on-entry and evaluate.

Displaying list of data in ChooseUserOffice view

For chooseOfficeStep we want to display a list of offices where the user can then click on to get to the next step in the flow. To do this we do the following:

<view-state id="chooseOfficeStep" view="chooseUserOffice">
        <on-entry>
            <evaluate expression="systemUserController.showBranchHierarchy()" result="flowScope.officeDetails" />
        </on-entry>
	<transition on="officeSelected" to="enterUserDetailsStep" />
	<transition on="cancel" to="cancel" />
</view-state>
@Controller
public class SystemUserController {

 public OfficeHierarchyFormBean showBranchHierarchy() {
      .
      .
 }
}
In freemarker page...

[#list officeDetails.nonBranches as item]
    <li><a href="${flowExecutionUrl}&_eventId=officeSelected&officeId=${item.id}">${item.name}</a></li>
[/#list]

We have added a state entry action on-entry and used the evaluate element to invoke a method on our controller which returns the office details we need and assigns this to a variable named officeDetails which is available at flowscope (available to entire flow until we leave it)

In our .ftl page we can now access officeDetails and the data within it to produce the list of office that a user can select from.

Handy Hint

The implementation of the controller is left out. If we were just doing UI development and not worrying about calling application services to retrieve the data, you could just return the OfficeHierarchyFormBean with canned or stubbed data and ensure all UI parts are working correctly first.

Displaying a form for entering user details and binding this info to a model

a

References

Official Spring Web Flow documentation (2.0.x)