ACS Documentation : Workflow : Workflow Developer's Guide
It'll also provide your users with a unified user-interface to help them keep track the tasks they are supposed to perform. This user-interface also acts as the single place to go for information relating to the task, such as inputs and aids in performing the specific task, a log of all prior activity on the case including comments, and a visual overview over the case.
It also provides you with an interface for analyzing the performance of your workflow. You'll be able to spot bottlenecks, find overdue tasks, etc.
Finally, as the package evolves based on input from you and other users, the features above will grow stronger, and more will be added (see future plans).
From there on, there are four steps involved in taking advantage of the services of the workflow package in your application.
You can go a long way by starting with the Simple Process Wizard to define the basic steps of your process, then, if necessary, use the Advanced Process Builder, to add more advanced features. With this already-defined process as a starting point, it'll be relatively easy to translate it into DML. If you haven't already, this it the time to familiarize yourself with the conceptual model underlying the workflow package.
Then you simply translate the process into SQL (or more correctly, DDL and DML), like this (look at some of the samples to see how it's done):
case_id, referencing
wf_cases. Here's how that could look:
create table wf_expenses_cases (
case_id integer primary key
constraint wf_expenses_cases_case_fk
references wf_cases(case_id)
on delete cascade
);
declare
v_workflow_key varchar(40);
begin
v_workflow_key := workflow.workflow_create(
workflow_key => 'expenses_wf',
pretty_name => 'Expense Authorization',
pretty_plural => 'Expense authorizations',
description => 'Workflow for authorizing employee''s expenses on the company''s behalf',
table_name => 'wf_expenses_cases'
);
end;
/
show errors
The table_name argument is the name of the table you just
defined. The workflow_key also becomes the name of the
object type (primary key in acs_object_types). Don't
forget the on delete cascade if you want to be able to
delete cases.
insert into wf_places(place_key, workflow_key, place_name, sort_order)
values ('start', 'expenses_wf', 'Initial state', 1);
There are two special places: start and
end. There must be one of each, and they must be named
so. The sort_order column has no influence on the
execution on the workflow, it's only there so we can display the
places and transitions in some logical order, when we can do nothing
better.
insert into wf_transitions(transition_key, transition_name, workflow_key, sort_order, trigger_type)
values ('assign', 'Assign users to approval', 'expenses_wf', 1, 'user');
The trigger type can be user, automatic,
time or message. You can read about those in
the conceptual guide.
-- transition: assign
-- in
insert into wf_arcs(workflow_key, transition_key, place_key, direction)
values ('expenses_wf', 'assign', 'start', 'in');
-- out
insert into wf_arcs(workflow_key, transition_key, place_key, direction)
values ('expenses_wf', 'assign', 'assignments_done', 'out');
Keep in mind that every transition must have at least one arc going in
and one arc going out. All arcs go either from a place to a
transition, or from a transition to a place. You can't have an arc
from a place to a place or from a transition to a transition.
Outgoing arcs can have guards, which are predicates that determine whether the arc is 'really there' in a specific situation. Usually the guard will depend on the values of one or more workflow attributes (see conceptual guide). You'll learn how to add these in the next section, Adding Callbacks.
declare
v_attribute_id acs_attributes.attribute_id%TYPE;
begin
v_attribute_id := workflow.attribute_create(
workflow_key => 'expenses_wf',
attribute_name => 'supervisor_ok',
datatype => 'boolean',
wf_datatype => 'none',
pretty_name => 'Supervisor Approval',
default_value => 'f'
);
insert into wf_transition_attribute_map
(workflow_key, transition_key, attribute_id, sort_order)
values
('expenses_wf', 'supervisor_approval', v_attribute_id, 1);
end;
/
show errors;
First you define the attribute. The wf_datatype is a hack
that should go away soon. Currently it's only used for specifying that
an attribute holds values of type party (useful for
manual assignments). In that case, you set datatype to
number and wf_datatype to
party. We'll add more subtypes as needed, so please let use know what you need.
When you've defined the attribute, you usually also want to specify
when this attribute should be set. You do that by inserting a row into
wf_transition_attribute_map, saying that this attribute
should be part of the output for this transition (task). The
sort_order here is used to determine the order the
attributes are presented in on the form the user fills in when
finishing the task.
wf_callback package. To make it easier to adopt workflow,
we'll try to add predefined callbacks for all the common cases that we
can think of, so please let us know
what callback you're missing.
If you want to write your callbacks yourself, you must adhere to the
pre-specified procedure/function signature. These are listed in
Appendix A in this document, We'll but the authoritative reference for
these are the sql/wf-core-create.sql SQL file.
Generally, the callbacks take the arguments necessary to uniquely
identify the object (arc, transition, task) they're attached to, the
case_id, and a custom_arg, which makes it
possible to re-use the same callback for similar purposes.
To instruct the workflow engine to invoke your callbacks at the
specified points in time, set the relevant columns in
wf_context_transition_info. You set the
foo_callback column to the name of the PL/SQL or
Tcl procedure/function you want called, and
foo_custom_arg to the value you want passed in to
this procedure/function as the last, custom argument.
Note on the special built-in guard#: There's a special built-in guard,#. If, instead of a PL/SQL function name, you set theguard_callbackto the literal'#', that is taken to mean "true if no real guards on arcs going out of this transition were true". This is very useful for or-splits, where you use a PL/SQL function for the one guard, and the # symbol for the other. This way, if the real guard is true, that arc is traversed, otherwise the other arc is traversed.The semantics generalizes to more than two arcs and more than one #. First all the arcs with real guards are tried, and all the arcs where the guard evaluates to true are traversed. If no real guard evaluated to true, then all the arcs with a
#guard are traversed, otherwise none of them are traversed.
A few examples of callbacks:
insert into wf_arcs(
workflow_key, transition_key, place_key, direction,
fguard_callback
) values (
'expenses_wf', 'and_join', 'ready_to_buy', 'out', 'wf_expenses.guard_both_approved_p'
);
insert into wf_arcs(
workflow_key, transition_key, place_key, direction, guard_callback
) values (
'expenses_wf', 'and_join', 'end', 'out', '#'
);
Here we have two arcs, one with a real guard and the other with the
# guard, thus building an or-split. The function
implementing the guard
(wf_expenses.guard_both_approved_p) must be defined elsewhere.
insert into wf_context_transition_info (
context_key,
workflow_key,
transition_key,
assignment_callbackf,
hold_timeout_callback,
hold_timeout_custom_arg
) values (
'default',
'expenses_wf',
'supervisor_approval',
'wf_expenses.assign_supervisor_approval',
'wf_callback.time_sysdate_plus_x',
1/24
);
Here, for the assignment callback, we presumably have a PL/SQL function,
wf_expenses.assign_supervisor_approval, which returns the
user_id of the supervisor for a user. For the
hold-timeout callback, we're using one of the predefined callbacks,
wf_callback.time_sysdate_plus_x, which returns Oracle
sysdate plus the value given in
hold_timeout_custom_arg.
Static assignments of tasks to users or groups (e.g. assign the task 'Pay bill' to the billing department) will definitely vary from implementation to implementation. Other things, like the callback when a task is finished, may better belong to the workflow definition itself. We're hoping for some more real-world experience on this, so please share your experiences.
workflow_case.new when a new row is inserted into this table.
(More details later when I have done this myself.)
Most of the time, though, you want your users to be able to determine this at run-time. There will be a user-interface for this in the final release, but it is not done yet.
function name(
case_id in number,
workflow_key in varchar,
transition_key in varchar,
place_key in varchar,
direction in varchar,
custom_arg in varchar
) return char(1);
procedure name(
case_id in number,
transition_key in varchar,
custom_arg in varchar
);
procedure name(
task_id in number,
custom_arg in varchar
)
This procedure must insert rows into the
wf_task_assignments table.
function name(
case_id in number,
transition_key in varchar,
custom_arg in varchar
) return date;
function name(
case_id in number,
transition_key in varchar,
custom_arg in varchar
) return date;
function name(
case_id in number,
transition_key in varchar,
custom_arg in varchar
) return date;
name -task_info [wf_task_info $task_id]Look at
wf_task_info
documentation to see what information this variable will contain.
| Last Modified: 2001/01/21 00:36:46 |