今天做了个Business events + Workflow 的例子,记录一下。
功能描述:
当表中新增一条INVOICE信息,自动触发Business events, 然后调用Workflow,发Notification 给审批者审批。
主要目的是测试Business events 的功能,学习一下。
测是测通了,但做完后,发觉并没有了解Business events的优势,因为这样的功能,完全可以在记录新增时直接调用Workflow来处理,感觉系统标准的Business events也无非是在某个操作完成后,触发一个Events,来完成后继的操作,就算有延迟处理(Defer)的功能,似乎我们也可通过database job 来实现,订阅(Subscriptions)功能也似乎可以写Package来实现不同的业务逻辑的分支处理。
如果有TX看到我的困惑,请不吝赐教!
下面是例子的详细步骤。
1. 建立客户化表c_apps.c_customer_invoices_all,当表中新增记录时,触发Business events
2. Events 一旦触发,做两个动作:往客户化表c_apps.c_customer_invoice_events 中插入该events的相关信息,然后启动客制化的Workflow 发一个Notification给审批人。
3.审批人收到Notification, 进行审批并给出审批意见
开发过程:
1. 建表
2. 定义Events
3. 开发Workflow并上传注册
4. 定义Event subscription
5. 新增数据并查看结果
建表:
1.业务数据表,用来存测试发票
create table c_apps.c_customer_invoices_all
(invoice_id number,
invoice_date date,
invoice_amount number,
submit_id number,
submit_date date,
approval_id number,
approval_date date,
approval_memo varchar2(100),
approval_status varchar2(1))
create sequence c_apps.c_customer_invoice_s
2. 业务事件表,用来存事件信息
create table c_apps.c_customer_invoice_events
(event_id number,
event_name varchar2(100),
event_key varchar2(100),
event_data varchar2(100),
event_date date,
invoice_id number,
submit_id number)
create sequence c_apps.c_customer_invoice_event_s
定义Business events
Path: System administrator/Administrator Workflow/Business Events
注意: Event name 需要符合一定的规范,可参考系统内置的Event name来定义
Owner Name/Tag 按实际的应用来输入application short name
定义Workflow
使用Workflow builder 开发一个新的Workflow item type
注意:Attributes 中的INVOICE_ID/SUBMIT_ID将来自于Event的Parameter list. 不用进行初始化赋值,因为Raise event的时候会由程序提供
ENAME/EKEY/EMSG用来存放Event的相关信息
3个Function 的功能如下:
GET_SUBMIT_INFO: 取得提交人的信息和审批人的信息并初始化各个Attributes
INVOICE_APPROVAL_ACTION: 审批分支的处理过程
INVOICE_REJECT_ACTION: 拒绝分支的处理过程
INVAPP_EVENT为Business event activity.
Main Process如下:
Event定义如下:
注意: 这里的Event action 一定要是receive,这表示这个activity是用来接收event data的,而不是用来触发一个Event.
注意,上面三个即是把Event 的信息传给之前定义的3个Attributes.
Lookup Types定义如下:
Message 定义如下:
Notification的定义如下:
注意Performer的定义,即为接收人
上传Workflow并注册至系统
注意,Phase 定义在100以下的为即时处理
注意: PL/SQL Rule Function 里为客制化的程序,用来完成Event 信息的保存和Event的初始化
Workflow Type 里既为上面开发的Workflow, Process 为里面唯一的Main_process
编写Package, 代码如下:
注: 假定审批者与提交者为同一个人
create or replace package body c_customer_invoice_pkg is
--用来生成测试数据及调用Events
procedure insert_data is
l_invoice_id number;
begin
select c_apps.c_customer_invoice_s.nextval into l_invoice_id from dual;
--Insert 数据
--3137为我的user id,此为测试方便,直接用。
insert into c_apps.c_customer_invoices_all
(invoice_id,
invoice_date,
invoice_amount,
submit_id,
submit_date,
approval_id,
approval_date,
approval_memo,
approval_status)
values
(l_invoice_id, sysdate, 1000, 3137, sysdate, null, null, null, null);
commit;
--调用过程启动Event
raise_event(l_invoice_id, 3137);
end insert_data;
--用来启动Event
PROCEDURE raise_event(pi_invoice_id in NUMBER, pi_submit_id in NUMBER) is
l_parameter_list wf_parameter_list_t := wf_parameter_list_t();
l_parameter_t wf_parameter_t := wf_parameter_t(null, null);
l_event_key NUMBER;
l_event_data varchar2(300);
l_message varchar2(10);
BEGIN
--用invoice id 做为event key
l_event_key := pi_invoice_id;
--定义event的参数
l_parameter_t.setName('INVOICE_ID');
l_parameter_t.setVALUE(pi_invoice_id);
l_parameter_list.extend;
l_parameter_list(1) := l_parameter_t;
l_parameter_t.setName('SUBMIT_ID');
l_parameter_t.setVALUE(pi_submit_id);
l_parameter_list.extend;
l_parameter_list(2) := l_parameter_t;
--启动
wf_event.raise(p_event_name => 'oracle.apps.c_apps.invoice.approval',
p_event_key => l_event_key,
--p_event_data => l_event_data,
p_parameters => l_parameter_list);
commit;
l_parameter_list.DELETE;
END raise_event;
--此过程设置在Subscription的rule function中,用来往表中写入Event信息
FUNCTION rule_function(p_subscription in RAW,
p_event in out NOCOPY WF_EVENT_T)
return varchar2 is
l_rule VARCHAR2(20);
l_parameter_list wf_parameter_list_t := wf_parameter_list_t();
l_parameter_t wf_parameter_t := wf_parameter_t(null, null);
i_parameter_name l_parameter_t.name%type;
i_parameter_value l_parameter_t.value%type;
i pls_integer;
l_invoice_id l_parameter_t.value%type;
l_submit_id l_parameter_t.value%type;
BEGIN
if p_event.geteventname() = 'oracle.apps.c_apps.invoice.approval' then
--获取Event的参数
l_parameter_list := p_event.getParameterList();
if l_parameter_list is not null then
i := l_parameter_list.FIRST;
--获取参数的值
while (i <= l_parameter_list.LAST) loop
i_parameter_name := null;
i_parameter_value := null;
i_parameter_name := l_parameter_list(i).getName();
i_parameter_value := l_parameter_list(i).getValue();
if i_parameter_name is not null then
if i_parameter_name = 'INVOICE_ID' then
l_invoice_id := i_parameter_value;
elsif i_parameter_name = 'SUBMIT_ID' then
l_submit_id := i_parameter_value;
end if;
end if;
i := l_parameter_list.NEXT(i);
end loop;
end if;
--写入Event表
insert into c_apps.c_customer_invoice_events
(event_id,
event_name,
event_key,
event_data,
event_date,
invoice_id,
submit_id)
values
(c_apps.c_customer_invoice_event_s.nextval,
p_event.getEventName,
p_event.getEventKey,
p_event.getEventData,
sysdate,
l_invoice_id,
l_submit_id);
--调用系统标准的Event rule
l_rule := wf_rule.default_rule(p_subscription, p_event);
end if;
return('SUCCESS');
EXCEPTION
WHEN OTHERS THEN
wf_core.context('c_customer_invoice_pkg',
'rule_function',
p_event.geteventname(),
p_subscription);
wf_event.seterrorinfo(p_event, 'ERROR');
RETURN 'ERROR';
END rule_function;
--用于Workflow,取得submit/approval的人员信息及发票信息
PROCEDURE get_submit_info(itemtype IN VARCHAR2,
itemkey IN VARCHAR2,
actid IN NUMBER,
funcmode IN VARCHAR2,
resultout OUT NOCOPY VARCHAR2) is
l_invoice_id NUMBER;
l_invoice_amount NUMBER;
l_invoice_date date;
l_orig_system wf_roles.orig_system%TYPE := 'PER';
l_submit_id NUMBER;
l_submit_name wf_roles.NAME%TYPE;
l_submit_display_name wf_roles.display_name%TYPE;
l_approval_id NUMBER;
l_approval_name wf_roles.NAME%TYPE;
l_approval_display_name wf_roles.display_name%TYPE;
begin
IF (funcmode <> wf_engine.eng_run) THEN
resultout := wf_engine.eng_null;
RETURN;
END IF;
l_invoice_id := wf_engine.getitemattrnumber(itemtype => itemtype,
itemkey => itemkey,
aname => 'INVOICE_ID');
l_submit_id := wf_engine.getitemattrnumber(itemtype => itemtype,
itemkey => itemkey,
aname => 'SUBMIT_ID');
wf_directory.GetRoleName(p_orig_system => l_orig_system,
p_orig_system_id => l_submit_id,
p_name => l_submit_name,
p_display_name => l_submit_display_name);
wf_engine.setitemattrtext(itemtype => itemtype,
itemkey => itemkey,
aname => 'SUBMIT_NAME',
avalue => l_submit_name);
wf_engine.setitemattrtext(itemtype => itemtype,
itemkey => itemkey,
aname => 'SUBMIT_DSP_NAME',
avalue => l_submit_display_name);
wf_directory.GetRoleName(p_orig_system => l_orig_system,
p_orig_system_id => l_submit_id,
p_name => l_approval_name,
p_display_name => l_approval_display_name);
wf_engine.setitemattrnumber(itemtype => itemtype,
itemkey => itemkey,
aname => 'APPROVAL_ID',
avalue => l_submit_id);
wf_engine.setitemattrtext(itemtype => itemtype,
itemkey => itemkey,
aname => 'APPROVAL_NAME',
avalue => l_approval_name);
wf_engine.setitemattrtext(itemtype => itemtype,
itemkey => itemkey,
aname => 'APPROVAL_DSP_NAME',
avalue => l_approval_display_name);
select invoice_amount, invoice_date
into l_invoice_amount, l_invoice_date
from c_apps.c_customer_invoices_all
where invoice_id = l_invoice_id;
wf_engine.setitemattrnumber(itemtype => itemtype,
itemkey => itemkey,
aname => 'INVOICE_AMOUNT',
avalue => l_invoice_amount);
wf_engine.SetItemAttrDate(itemtype => itemtype,
itemkey => itemkey,
aname => 'INVOICE_DATE',
avalue => l_invoice_date);
resultout := 'COMPLETE';
EXCEPTION
when others then
wf_core.context('C_CUSTOMER_INVOICE_PKG',
'get_submit_info',
itemtype,
itemkey,
TO_CHAR(actid),
funcmode,
SQLERRM);
raise;
end get_submit_info;
--用于Workflow的审批分支
PROCEDURE invoice_approval(itemtype IN VARCHAR2,
itemkey IN VARCHAR2,
actid IN NUMBER,
funcmode IN VARCHAR2,
resultout OUT NOCOPY VARCHAR2) is
l_invoice_id NUMBER;
l_approval_memo c_apps.c_customer_invoices_all.approval_memo%TYPE;
l_approval_id NUMBER;
begin
IF (funcmode <> wf_engine.eng_run) THEN
resultout := wf_engine.eng_null;
RETURN;
END IF;
l_invoice_id := wf_engine.getitemattrnumber(itemtype => itemtype,
itemkey => itemkey,
aname => 'INVOICE_ID');
l_approval_id := wf_engine.getitemattrnumber(itemtype => itemtype,
itemkey => itemkey,
aname => 'APPROVAL_ID');
l_approval_memo := wf_engine.getitemattrtext(itemtype => itemtype,
itemkey => itemkey,
aname => 'APPROVAL_MEMO');
UPDATE c_apps.c_customer_invoices_all
SET approval_id = l_approval_id,
approval_date = sysdate,
approval_memo = l_approval_memo,
approval_status = 'Y'
WHERE invoice_id = l_invoice_id;
resultout := 'COMPLETE';
EXCEPTION
when others then
wf_core.context('C_CUSTOMER_INVOICE_PKG',
'invoice_approval',
itemtype,
itemkey,
TO_CHAR(actid),
funcmode,
SQLERRM);
raise;
end invoice_approval;
--用于Workflow的拒绝分支
PROCEDURE invoice_reject(itemtype IN VARCHAR2,
itemkey IN VARCHAR2,
actid IN NUMBER,
funcmode IN VARCHAR2,
resultout OUT NOCOPY VARCHAR2) is
l_invoice_id NUMBER;
l_approval_memo c_apps.c_customer_invoices_all.approval_memo%TYPE;
l_approval_id NUMBER;
begin
IF (funcmode <> wf_engine.eng_run) THEN
resultout := wf_engine.eng_null;
RETURN;
END IF;
l_invoice_id := wf_engine.getitemattrnumber(itemtype => itemtype,
itemkey => itemkey,
aname => 'INVOICE_ID');
l_approval_id := wf_engine.getitemattrnumber(itemtype => itemtype,
itemkey => itemkey,
aname => 'APPROVAL_ID');
l_approval_memo := wf_engine.getitemattrtext(itemtype => itemtype,
itemkey => itemkey,
aname => 'APPROVAL_MEMO');
UPDATE c_apps.c_customer_invoices_all
SET approval_id = l_approval_id,
approval_date = sysdate,
approval_memo = l_approval_memo,
approval_status = 'N'
WHERE invoice_id = l_invoice_id;
resultout := 'COMPLETE';
EXCEPTION
when others then
wf_core.context('C_CUSTOMER_INVOICE_PKG',
'invoice_reject',
itemtype,
itemkey,
TO_CHAR(actid),
funcmode,
SQLERRM);
raise;
end invoice_reject;
end c_customer_invoice_pkg;
最后在PL/SQL中执行
BEGIN
c_customer_invoice_pkg.insert_data;
end;
查看Event表,记录生成,进入系统,发现Notification已经收到,可以正常审批!
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10359218/viewspace-716716/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/10359218/viewspace-716716/