qbo.Decision: Tasks (Import Forms)


Tasks (also called Import Forms) are custom screens intended to allow users to efficiently create a single task. Each task is based upon a template, which defines the layout of the screen and the data to be collected.

Creation of tasks requires basic knowledge of:

The QBO3 UI allows a power user to define the layout of a form (including an unlimited number of fields) by adding Questions.  Questions may be any type of HTML form element, and may map to any data point available in the database. If they do not map to a pre-existing data point in the database, the field will be tracked as part of an XML fragment in the ImportForm.XmlData column. This allows power users to create fields 'on the fly' if they wish.

Status-Based Routing

Sample State Transitions
A common use case is to submit a task for review and approval. Implied in such a use case is the possibility of rejection, or requiring a submitted to re-work the task to provide amplifying information. Thus, a single form may appear to multiple work lists, for multiple people, as it transitions between statuses.

Implementing this requirement in QBO is best done by:
  • Create a series of custom statuses for the task, representing the possible 'flow' of the task
    • e.g. Processor Review, Supervisor Review, Manager Review, Rejected, Accepted
  • Create a series of state transitions, representing what role is allowed to transition from one status to the next
    • Processor Review => Supervisor Review // submit for approval
    • Processor Review => Rejected // anyone can reject a task
    • Supervisor Review => Processor Review // supervisors can kick a task back to a processors
    • Supervisor Review => Manager Review // supervisors can submit a task for manager approval, but processors cannot
    • Supervisor Review => Rejected // anyone can reject a task
    • Manager Review => Accepted // only managers can accept
    • Manager Review => Rejected // anyone can reject a task
    • Manager Review => Supervisor Review // managers can kick a task back to supervisors
  • Adding a call to RenderStatusButtons template
    • This will render 'save' buttons labelled for each transition currently allowed, based on the current status and the user's role
When an Import Form record is updated, the ImportFormTransition trigger will:
  • Raise an error if the transition is not allowed (e.g. Process Review => Approved)
  • Complete any Smart Worklist Members bound to the task matching the old status
  • Insert a new Smart Worklist Member bound to the task matching the new status


When a task is created by a workflow, or via a GET request (e.g. ImportForm.ashx/Render?Template=My Task&Object=Organization&ObjectID=1), QBO will either create a new task or bind to an existing task based on the task template's repeatable setting: 
  • One per Parent (0): only one task based on the template may exist per parent
  • One active per Parent (1): only one active task based on the template may exist per parent
  • Many per Parent (2): any number of tasks based on the template may exist per parent
To demonstrate use cases for repeatability, we'll create three tasks all bound to 'Organization':
  • Company Profile (there should be only one such task, possibly reused over time)
  • Contract (there should be one active task, though once a old contract expires it may be replaced by a new contract)
  • Support Ticket (there may be many such tasks per organization)
The 'Company Profile' task template may be defined as 'one per parent', and any number of workflows may prompt a user to enter or review the Company Profile. Regardless of how many workflows include the 'Company Profile' task, only one copy of the task will be created per Organization. In this situation:
  • GET /Decision/ImportForm.ashx/Render?Template=Company Profile&Object=Organization&ObjectID=1
    will create and render a Company Profile task the first time it's called
  • GET /Decision/ImportForm.ashx/Render?Template=Company Profile&Object=Organization&ObjectID=1
    will render the existing Company Profile task all subsequent times it's called
A 'Support Ticket' task template may be defined as 'many per parent', and each time a support ticket task is added to an Organization, a new task is created. There may be multiple support tickets open simultaneously for a given organization, and each may be completed independently of any other support tickets. In this situation:
  • GET /Decision/ImportForm.ashx/Render?Template=Support Ticket&Object=Organization&ObjectID=1 
    will create and render a Support Ticket task every time it's called
The 'Contract' task template may be defined as 'one active per parent', meaning that there may only be one 'active' Contract task at a time. In this situation:
  • GET /Decision/ImportForm.ashx/Render?Template=Contract&Object=Organization&ObjectID=1 
    will create and render a Contract task the first time it's called
  • GET /Decision/ImportForm.ashx/Render?Template=Contract&Object=Organization&ObjectID=1 
    will render the existing Contract task until the existing Contract task is completed
  • POST /Decision/ImportForm.ashx/Save?Template=Contract&Object=Organization&ObjectID=1&ActualCompletion=1/1/2018 
    will complete the existing Contract task
  • GET /Decision/ImportForm.ashx/Render?Template=Contract&Object=Organization&ObjectID=1 
    will create and render a new Contract task, leaving the original completed task alone.
Note that there is a more complicated use case for 'one active per parent': creating a task that's part of a workflow, before the workflow is created. Let's assume that:
  • A 'Renew Contract' workflow is used by an Organization to handle new contract drafting, review, and approval
    • this workflow contains a 'Draft Contract' step that is handled by a third party law firm
  • The third party law firm case management system transmits 'Draft Contract' tasks when they, er, draft contracts for us
    • the firm does not know about our approval workflow; they just concentrate on creating a contract for us to review
    • the firm knows when to draft contracts; it's their job!
    • when they've drafted a contract, they just: 
      POST /Decision/ImportForm.ashx/Save?Template=Draft Contract&Object=Organization&ObjectID=1&ContractURL={Url}&ActualCompletion={Today}
The 'Draft Contract' task template can be defined as 'one active per parent'.  Then the following happens:
  • The law firm tells QBO they've finished the draft contract (with the POST above)
    • This inserts a new Draft Contract task, but there's no workflow step connected to this task
  • A data listener detects the 'orphaned' task (no workflow step), and launches a 'Renew Contract' workflow
    • the Renew Contract step, although marked complete by the third party law firm, should be 'detected and used' by the Renew Contract workflow
To handle this use case, 'active' tasks are task that:
  • have not yet been completed, OR
  • have been completed, but are not bound to an existing workflow
Tech note: the implementation of this behavior may be overridden in Design > Configuration > ImportForm > Statements > SelectByTemplate

PDF Forms

The qbo.Attachment.PDF plugins supports using form-enabled PDF documents as custom forms. This allows QBO 3 systems to plug-and-play existing PDF forms as custom forms. 

Steps required to use a data-enabled task:
  • Use Adobe Acrobat to create or edit a PDF adding form elements to it
    • if these form elements match QBO field names, the PDF will essentially edit those native QBO fields
    • if these form elements do not match QBO field names, the data will be saved to ImportForm.XmlData
  • Create an Import Form Template, based on the PDF form template
  • Set the Import Form Template Method to use the SummaryFlat method, or a statement based on SummaryFlat
  • Upload the PDF document you created in step 1 to the Import Form Template's Documents tab
Key methods include:
  • PDF.ashx/RenderEdit: this method renders form-related data as an XFDF file; Adobe Acrobat and Acrobat Reader will read XFDF files and render the corresponding form
  • PDF.ashx/LoanPDF: this method proxies loading PDFs from any IFileObject repository
  • PDF.ashx/Save: this method accepts XFDF posted data, translates the results into an IDictionary of parameters, and calls ImportForm.Save()
  • AbstractObject/SummaryFlat: this method returns a single data table, concatenating related records to the base data table returns
SummaryFlat Overview:

QBO data is stored in may tables. The AbstractObject/Summary() method returns a record, it's parents, siblings and children as multiple data tables, translated to XML. A rich DataSet or XML structure such is not usable by some third party software such as MS Word and Adobe Acrobat. For such products, AbstractObject/SummaryFlat will produce a single DataTable concatenating multiple DataTables together.

For example, assume we have the following structure:

  • Property
    • Loan
      • Borrowers
      • Valuation
        • ImportForm
        • Comparables
        • Messages
        • Attachments
        • Decisions

Assume that we wish to include Property, Loan, Borrower, Valuation, Comparable and ImportForm data in the PDF. We can 'shape' the data by including parameters matching the data structure relationships between the tables:


will create a single table structured as follows:

... all other ImportForm columns ...
... all ImportForm.XmlData elements ...

... all other Valuation columns ...

... all other Loan columns ...

... all other Property columns ...

... all other ValuationComparable columns for the first ValuationComparable record

... all other ValuationComparable columns for the second ValuationComparable record

... and so on, until we reach the 6th one (because we passed Valuation_Comparables=6)

... all other ValuationComparable columns for the sixth ValuationComparable record

This is a very 'wide' table, but generally speaking, Word and Acrobat can handle it.

Choosing what relationship to include requires some thought. Once you've 'shaped' the data by determining the parameters you want, you can create a reusable Statement that stores these parameters in a configuration entry. For example, assume a Valuations system might create an ImportForm statement called 'ValuationStandardOutput', with the BaseOperation set to 'SummaryFlat', and the parameters defined above.  Once done, multiple Import Form Templates, Attachment Templates, and such can reuse the 'ValuationStandardOutput' statement.

Extending the Task's Functionality

Creating questions allows a power user without any knowledge of HTML, CSS or Javascript to quickly and easily create powerful data-enabled forms. Forms use an XSLT to render the form in the browser. If the questions do not quite cover the functionality needed, one can edit the form's XSLT directly. Each form template may have a Select, List and Edit XSLT. In most cases, the Edit XSLT is the one being used.  QBO provides an in-browser XSLT Edit page to allow real-time modifications of the form layout.

By default, form XSLTs will import a library of standard QBO-specific XSLT templates, found in ImportForm.Library.xslt (and ImportForm.Library.Core.xslt).

Example: Embedding standard HTML

<div>Hello World!</div>
<iframe width="420" height="315" src="//www.youtube.com/embed/a7nbmjkImHQ" frameborder="0" allowfullscreen></iframe>

Example:  Embedding a new field (not mapped to a standard QBO table and column)

<input type="text" name="MyNewField" value="{$XmlData//MyNewField}"/>

  • $XmlData is a standard XSLT parameter which contains the XML fragment associated with the form. New fields specific to the form should be rendered in this manner.
  • In XSLT, curly braces in within HTML attributes tell XSLT to replace the XPath expression with the actual value from the XML being processed
Example: Embedding an existing field

<input type="text" name="Loan_UPBAmount" value="{{//LoanItem/UPBAmount}}"/>

  • We assume the form is designed for the Loan table, and wish to render the Loan.UPBAmount
  • We name the field Loan_UPBAmount so that, when the form is saved, QBO3 will save the value entered into the Loan.UPBAmount column
Example: Displaying a new field from another task

<xsl:value-of select="{//ImportFormItem[ImportForm='My Other Form']/XmlData//SomeOtherField}"/>

  • We assume the name of the other task you are accessing is 'My Other Task' (this is case sensitive!)
  • We assume the name of the field from the other form is 'SomeOtherField'

Subpages (2): Creating A Task Task API