This tutorial gives you an overview about the options available to set up notifications during the execution of workflows. It is written for ]po[ Developers.
Please note that notifications by email are not always the best option to notify a user about the assignment of a task or other incidences that require actions to be taken.
Too many email notifications can annoy users and as a consequence mail messages send automatically send out buy the system will be perceived as spam and as a consequence often ignored by users.
If users work frequently with the system, a email notification are usually obsolete since the "Workflow Home Inbox" always contains all tasks, the WF engine has assigned to user.
]po[ supports the following notification types
a) Default notification through "Workflow Home Inbox"
b) Default Notification about task assignment
c) Individual Notification about task assignment using OpenACS Notifications
d) Simple Notifications
Users receive notifications about workflow assignments through their "Workflow Inbox" on the home page:
The notification callback will get called whenever a user is assigned to this transition. The notification callback is passed the default subject line and body, the recipient party, and the default sending party. It may modify any of these elements before posting the message, or may choose to ignore the request and return without posting at all. If no notification callback is provided, the party assigned to the task will be notified automatically by the workflow engine.
Very likely this automatic notification will not work on your ]po[ installation. Please check if the user to be notified has a notification registered for the "acs-workflow package".
Users notification settings can be managed at http://[YOUR_SERVER]/notifications/admin/
In case no such entry is found, you can execute the following tcl code to create a notification service.
(Please set user_id accordingly!)
set user_id 1234 set type_id [notification::type::get_type_id -short_name "workflow_assignee"] set interval_id [notification::get_interval_id -name "instant"] set delivery_method_id [notification::get_delivery_method_id -name "email"] set wf_package_key [db_string get_data "select package_id from apm_packages where package_key = 'acs-workflow'" -default 0] notification::request::new \ -type_id $type_id \ -user_id $user_id \ -object_id $wf_package_key \ -interval_id $interval_id \ -delivery_method_id $delivery_method_id
For additional information on OpenACS notifications please see:
Have a look at ./intranet-helpdesk/sql/postgresql/intranet-helpdesk-notifications-create.sql to see how notifications are used
in ]project-open[:
-- /packages/intranet-helpdesk/sql/postgresql/intranet-helpdesk-notifications-create.sql ... create function inline_0() returns integer as ' declare impl_id integer; v_notif_type_id integer; begin -- the notification type impl impl_id := acs_sc_impl__new ( ''NotificationType'', ''ticket_notif_type'', ''jobs'' ); PERFORM acs_sc_impl_alias__new ( ''NotificationType'', ''ticket_notif_type'', ''GetURL'', ''im_ticket::notification::get_url'', ''TCL'' ); PERFORM acs_sc_impl_alias__new ( ''NotificationType'', ''ticket_notif_type'', ''ProcessReply'', ''im_ticket::notification::process_reply'', ''TCL'' ); PERFORM acs_sc_binding__new ( ''NotificationType'', ''ticket_notif_type'' ); v_notif_type_id:= notification_type__new ( NULL, impl_id, ''ticket_notif'', ''Ticket Changes'', ''Notifications of any change to a given ticket'', now(), NULL, NULL, NULL ); -- enable the various intervals and delivery methods insert into notification_types_intervals (type_id, interval_id) select v_notif_type_id, interval_id from notification_intervals where name in (''instant'',''hourly'',''daily''); insert into notification_types_del_methods (type_id, delivery_method_id) select v_notif_type_id, delivery_method_id from notification_delivery_methods where short_name in (''email''); return (0); end;' language 'plpgsql'; select inline_0(); drop function inline_0();
Objects such as tickets, projects, etc. can have notifications assigned to them. The assignment usually happens with the creation of the object.
The code below shows how a notification of type "ticket_notif" is assigned to a newly created ticket:
notification::new \ -type_id [notification::type::get_type_id -short_name ticket_notif] \ -object_id $ticket_id \ -response_id "" \ -notif_subject $ticket_name \ -notif_text $message
set type_id [notification::type::get_type_id -short_name "inquiry_notif"] set interval_id [notification::get_interval_id -name "instant"] set delivery_method_id [notification::get_delivery_method_id -name "email"] notification::request::new \ -type_id $type_id \ -user_id $user_id \ -object_id $project_id \ -interval_id $interval_id \ -delivery_method_id $delivery_method_id
-- Unassigned callback that assigns the transition to the supervisor of the absence owner. -- create or replace function im_timesheet_conf_object__assign_to_supervisor (integer,text) returns integer as ' declare p_task_id alias for $1; p_custom_arg alias for $2; v_case_id integer; v_conf_id integer; v_creation_user integer; v_creation_ip varchar; v_journal_id integer; v_transition_key varchar; v_transition_name varchar; v_owner_id integer; v_owner_name varchar; v_supervisor_id integer; v_supervisor_name varchar; v_str text; row RECORD; begin -- Get information about the transition and the "environment" select t.case_id, tr.transition_name, tr.transition_key, c.object_id, o.creation_user, o.creation_ip into v_case_id, v_transition_name, v_transition_key, v_conf_id, v_creation_user, v_creation_ip from wf_tasks t, wf_cases c, wf_transitions tr, acs_objects o where t.task_id = p_task_id and t.case_id = c.case_id and o.object_id = t.case_id and t.workflow_key = tr.workflow_key and t.transition_key = tr.transition_key; select v_creation_user, im_name_from_user_id(v_creation_user), e.supervisor_id, im_name_from_user_id(e.supervisor_id) into v_owner_id, v_owner_name, v_supervisor_id, v_supervisor_name from im_employees e where e.employee_id = v_creation_user; RAISE NOTICE ''im_timesheet_conf_object__assign_to_supervisor: task_id=%, conf_id=%, owner_id=%, superv=%'', p_task_id, v_conf_id, v_owner_id, v_supervisor_id; IF v_supervisor_id is not null THEN v_journal_id := journal_entry__new( null, v_case_id, v_transition_key || '' assign_to_supervisor '' || v_supervisor_name, v_transition_key || '' assign_to_supervisor '' || v_supervisor_name, now(), v_creation_user, v_creation_ip, ''Assigning to '' || v_supervisor_name || '', the supervisor of '' || v_owner_name || ''.'' ); PERFORM workflow_case__add_task_assignment(p_task_id, v_supervisor_id, ''f''); PERFORM workflow_case__notify_assignee (p_task_id, v_supervisor_id, null, null, ''wf_im_timesheet_conf_object_review_notif''); END IF; return 0; end;' language 'plpgsql';
For localized mail subjects, the system expects translation strings defined in the acs-workflow package for the workflow transition key and notification type:
... v_subject := 'Notification_Subject_' || v_transition_key || '_' || v_notification_type; v_subject := acs_lang_lookup_message(v_locale, 'acs-workflow', v_subject); ...
Users can manage their applications wide notifications at http:://[YOUR_SERVER]/notifications/manage
Using the OpenACS notifications can be in some cases an overhead. It is not always necessary, to give the user the possibility to subscribe/unsubscribe to a notifications or set the frequency of delivery.
To simply send an email to an user to inform him about an assignment, use im_workflow__notification_simple as follows:
(Custom Argument contains the id of the user to be notified.)
For customized output please set the localization strings in package acs_workflow accordingly:
The following placeholders are available:
e1) Absence Workflow
For the ]po[ Absence WF the following two procedures are suitable:
For customized output please set the localization strings in package intranet-timesheet2 accordingly:
Additional customizations:
v_request_id := acs_mail_nt__post_request ( v_party_from, -- party_from v_party_to, -- party_to 'f', -- expand_group v_subject, -- subject v_body, -- message 0, -- max_retries null, -- package_id 'text/html' -- mime type );
-- Get message from journal select msg into v_msg from journal_entries where object_id = v_acs_object_id and action_pretty = 'Approve finish'; IF v_msg IS NOT NULL THEN v_body := v_body || 'Note from Supervisor\n\n'; v_body := v_body || v_msg || '\n\n'; END IF;
e2) Timesheet Confirmation Workflow
The ]po[ Timesheet Confirmation WF provides:
For customized output please set the localization strings in package intranet-timesheet2-workflow accordingly:
CREATE OR REPLACE FUNCTION im_customer-portal_notify_customer(integer, character varying, character varying) RETURNS integer AS $BODY$ declare p_case_id alias for $1; p_transition_key alias for $2; p_custom_arg alias for $3; v_task_id integer; v_case_id integer; v_creation_ip varchar; v_creation_user integer; v_object_id integer; v_object_type varchar; v_journal_id integer; v_transition_key varchar; v_workflow_key varchar; v_group_id integer; v_group_name varchar; v_task_owner integer; v_object_name text; v_party_from parties.party_id%TYPE; v_party_to parties.party_id%TYPE; v_subject text; v_body text; v_request_id integer; v_locale text; v_count integer; begin RAISE NOTICE 'Notify_assignee_project_approval: enter'; -- Select out some frequently used variables of the environment select c.object_id, c.workflow_key, co.creation_user, task_id, c.case_id, co.object_type, co.creation_ip into v_object_id, v_workflow_key, v_creation_user, v_task_id, v_case_id, v_object_type, v_creation_ip from wf_tasks t, wf_cases c, acs_objects co where c.case_id = p_case_id and c.case_id = co.object_id and t.case_id = c.case_id and t.workflow_key = c.workflow_key and t.transition_key = p_transition_key; v_party_from := -1; -- Get locale of user select language_preference into v_locale from user_preferences where user_id = v_creation_user; -- ------------------------------------------------------------ -- Try with specific translation first v_subject := 'Notification_Subject_Notify_Customer_Quote_Created'; v_subject := acs_lang_lookup_message(v_locale, 'intranet-customer-portal', v_subject); -- Fallback to generic (no transition key) translation IF substring(v_subject from 1 for 7) = 'MISSING' THEN v_subject := 'A quote has been created'; END IF; -- Replace variables -- v_subject := replace(v_subject, '%object_name%', v_object_name); -- v_subject := replace(v_subject, '%transition_name%', v_transition_name); -- ------------------------------------------------------------ -- Try with specific translation first v_body := 'Notification_Body_Notify_Customer_QuoteCreated'; v_body := acs_lang_lookup_message(v_locale, 'intranet-customer-portal', v_body); -- Fallback to generic (no transition key) translation IF substring(v_body from 1 for 7) = 'MISSING' THEN v_body := 'Please check your RFQ box for a new quote'; END IF; -- Replace variables -- v_body := replace(v_body, '%object_name%', v_object_name); -- v_body := replace(v_body, '%transition_name%', v_transition_name); RAISE NOTICE 'Notify_assignee_project_approval: Subject=%, Body=%', v_subject, v_body; v_request_id := acs_mail_nt__post_request ( v_party_from, -- party_from v_creation_user, -- party_to 'f', -- expand_group v_subject, -- subject v_body, -- message 0 -- max_retries ); return 0; end;$BODY$ LANGUAGE 'plpgsql' VOLATILE; ALTER FUNCTION im_customer-portal_notify_customer(integer, character varying, character varying) OWNER TO postgres;Execute this stored procedure by setting your task actions accordingly:
Calle Aprestadora 19, 12o-2a
08902 Hospitalet de Llobregat (Barcelona)
Spain
Tel Europe: +34 609 953 751
Tel US: +1 415 200 2465
Mail: info@project-open.com