This how-to is work in progress.
Written mostly by inexperienced developer, needs review.
You've been warned.
What are interaction workflows
Normal workflows are used to implement effects of user interaction - validating of objects, ordering, planning and confirming of orders, etc.
By interaction workflows it is possible to define interactions on objects - in other words catching some methods invocations and defining actions, which shall happen on object. You can think of it as something similar to a "trigger" in relation database, a "hook", or a "side effect" of other actions. In other words, you can add some behaviour to an object without altering the object (class) itself.
For example, you may want to set a generated Title on new created objects like T0001, T0002, ... To gain such possibility, it's possible to use interaction workflow.
Examples of interaction workflow are in business templates - very interesting usage is in trade_model_line_interaction_workflow.
Example case of interaction workflow
We want to set titles on Purchase Order and Sale Order objects.
Go to Contents tab of workflow tool, create custom_title_setter_sale_order_interaction_workflow, choose interaction workflow.
Now go to Workflows tab of workflow tool and associate custom_title_seter_sale_order_interaction_workflow with Purchase Order Module and Sale Order Module portal types, then return to defining of interaction workflow.
Create scripts: PurchaseOrder_titleSetter and SaleOrder_titleSetter.
1 ## Script (Python) "PurchaseOrder_titleSetter"
2 ##bind container=container
3 ##bind context=context
4 ##bind namespace=
5 ##bind script=script
6 ##bind subpath=traverse_subpath
7 ##parameters=state_change
8 ##title=
9 ##
10 module = state_change['object']
11 # get the new created object
12 new_created_object = state_change['kwargs']['workflow_method_result']
13
14 # id group si used to define what will define your counter
15 id_group = ('title', new_created_object.getPortalType())
16 default = 1
17 title = module.portal_ids.generateNewLengthId(id_group=id_group, default=default)
18 new_created_object.setTitle('T%04d' % title)
So now we have to define interaction for our portal types. Go to Interactions tab, and create PurchaseOrder_titleSetInteraction. Edit it, and for set fields to:
Filter : Purchase Order Module
Trigger Method Id(s) : newContent
Script (after) : PurchaseOrder_titleSetter
Create interaction SaleOrder_titleSetInteraction and set fields properly. As exercise base definitions of above values.
Now create Purchase or Sale order and watch what happens. Titles looking like T0001, T0002, ... should be used
Most important part in interaction definition is Trigger Method Id(s). To catch all typical invocations. You can use method like newContent, but also edit and _edit you can also catch workflow transition like cancel, validate. And last, but not least, you can catch relating order with source/destination section we have to add _setDestinationValue, _setDestinationSectionValue, _setSourceValue, _setSourceSectionValue.
Reference documentation
Creating interaction workflows
To create interaction workflow navigate to workflow tool Contents tab add new workflow, type its Id and choose Type interaction_workflow.
Proposed Id grammar is someprefix[_portal_or_meta_type][_description_]interaction_workflow, eg:
- custom_packing_list_interaction_workflow
- custom_order_line_title_setter_interaction_workflow
Interaction workflows can be organised in various ways - per portal type (one interaction workflow for each portal type which needs it), or per function (aspect), or something else. For example, some developers find it convenient to create one security_update_interaction_workflow which is then used for every portal type which requires a security update upon certain actions.
Properties
Same as in normal workflows.
Interactions
List of possible interactions, which every can have additional constraints:
Filter - interaction will be invoked only on chosen portal types ((!) this list will be filled after association interaction workflows with portal types)
Trigger type :
Automatic - TODO
Initiated by WorkflowMethod - TODO
Trigger Method Id(s) - list of methods, which will trigger workflows. You can catch many things:
edit and _edit (though think twice, this would be triggered very often)
normal workflow actions (like stop, cancel, confirm)
low level methods (manage_afterClone)
category setters (_setResourceValue,_setDestinationValue)
property setters (use _set[PropertyName].* to catch all invocations of the setter)
Script (before), Script (after) and Activities (later) - list of script which will be invoked before action happens, after action happens and which will be invoked in activities.
Experiment with other scripts which are invoked by those actions. Guard - which guards applies to this interaction, same as in normal workflows
It is quite good idea to define methods (scripts) before defining interactions.
Variables
TODO
Scripts
Every script in you interaction workflows definition shall have argument called (by convention) state_change. To access changed object use:
1 changed_object = state_change['object']
Don't do state_change.object - it usually works but sometimes causes security problems
Scripts can be invoked:
before - ran immediately; if triggered by a setter uses the old value of a property
after - ran immediately; if triggered by a setter uses the new value of a property
later - executed a bit later, usually a few seconds but can be much longer
QUESTION: what to do if an interaction has to compare the old value to the new one? Is there a way to access them both at the same time (other then request lookup)?
List of usable Trigger methods
When editing using the standard ERP5 interface, edit method will be called. Then for each modified property, when you have for example a field "my_foo", the corresponding accessor _setFoo will be called. If _setFoo does not exists, setFoo will be called instead. If setFoo does not exist either, setProperty('foo', value) will be called. There is an exception for RelationFields. When a RelationField is modified, either the field defines a "Relation Update Method" that will be called, either the default _set${base_category}Value (or _set${base_category}ValueList when setting a multiple relation) accessor will be called, where ${base_category} is the capitalized name of the base category used for this accessor. Here is a summary of methods that can be used: this method will be triggered on when relation defined on resource category will be changed. trigger on while pasting copied or cut object. Also note that you can use _afterClone TypeBasedMethod.
You can't.
Such change will NOT be triggered by edit method Questions and Answers