Retek From开发框架
概述:
Retail 为Form开发提供了一个模板 fm_temp1.fmb ,在/d01/app/retail/rms/app/rms/forms/src目录下,该文件基本上已经将retail form涉及到的底层代码写好(比如实现多语言的调用等),我们在开发一个新的form的时候,只要在该模板的基础上实现自己的业务逻辑就行了。
另外,还有一个模板fm_date.fmb,用来做和日期相关的操作,最常见的是做LOV。比如,和ebs一样,我们需要选择日期,弹出一个选则日期的LOV,就要用到这个文件。
Retail的form界面风格和EBS有点不同,给我的总体感觉是布局比较灵活,比较接近我们客户化的风格。它的一个block在界面上显示出来的字段一般比较少,现在还没有发现使用folder的情况。
1. 开发一个新的form,需要开发那些文件。
按Retail的习惯,开发一个新的form,一般需要开发下面三个文件。
1).fm_XXX_find.fmb[可选]
查找form,在打开“真正”的业务处理form fm_XXX.fmb之前,需要打开这个查找form,该form的作用是选择本次操作的类型,一般有三种类型,查看,编辑,新建。如果是“新建”,则直接打开form_XXX来新建业务;如果是“查看”,则通过该form查到到业务记录,调用fm_XXX查看业务细节,fm_XXX的项都是不可编辑的;如果是“编辑”,则调用fm_XXX查看业务细节,并对业务细节进行编辑。
使用fm_XXX_find,是因为Retail form中没有EBS的 F11,Ctl+F11等快捷键,也没有EBS中“查找”窗体。我们也可以不使用这个form,只要在打开form fm_XXX.fmb的时候能够确定本次操作是查看,编辑或者新建就好了。比如,同一个form我们需要不同权限的人来打开,有的权限是查看,有的是编辑,有的是新建。这时候,我们只要在菜单上给每个权限挂不同的菜单项,对没个菜单项设置打开form的默认操作即可。
2).fm_XXX.fmb
这是实现业务逻辑的主要form。改form由fm_XXX_find.fmb调用open_form打开,open_form会使用一些参数,比如打开新form的状态是view,edit或者是new。
3).me_XXX.mmb[可选]
每一个form都对应一个菜单,当然,如果改form上不需要额外的菜单,在设置form对应的菜单的时候,就将该form的菜单设置为公用菜单:rtkform(参考 客户化Form挂到RMS中步骤,Menu中的 Form名和实际的Form名对应关系)
2. 开发form的细节
1). 命名规则:
Block 一般命名为 B_XXX,
Cavans 一般命名为 C_XXX,
Window一般命名为 W_XXX这样的形式。
2). 多语言的实现:
Retail的多语言,和ebs不同。ebs是在不同的语言环境放置不同语言的form程序,retek则只有一个form程序,它将需要显示给用户看的项的label,存放在数据库的特定表里,如果一个项有多种语言,则一个项在表里就有多条记录,当form启动的时候,在Form级WHEN-NEW-FORM-INSTANCE 触发器中,通过P_FORM_STARTUP->P_INITIALIZE 将Form中的每个Item和Item对应Label项取出来(在fm_temp1中已经写好了),我们要做的是将这些项和它们对应的语言手工取出来,放入数据库的特定表中。
Form的多语言:
Form的语言是放在表form_elements_langs和form_elements中的。
其获取语言的sql如下:
select fe.block_name,
fe.item_name,
fe.sub_item_name,
fe.item_type,
nvl(fel.lang_label_prompt, fe.default_label_prompt) label_prompt,
nvl(fel.lang_access_key,fe.default_access_key) access_key ,fel.lang
from form_elements_langs fel,
form_elements fe
where fe.fm_name = ‘FM_ORDHEAD’/*I_form*/–by Form
and upper(fe.fm_name) = upper(fel.fm_name(+))
and upper(fe.block_name) = upper(fel.block_name(+))
and upper(fe.item_name) = upper(fel.item_name(+))
and upper(fe.sub_item_name) = upper(fel.sub_item_name(+))
and 8/*L_user_lang*/ = fel.lang(+)–by user Language
and fe.default_label_prompt is not NULL;
所以,我需要向表form_elements_langs和form_elements中插入每个需要显示项的信息。比如,在供应商维护form(SUPVWEDT)中有一个供应商代码(SUPPLIER)字段,查询这两个表
select * from form_elements where fm_name=’FM_SUPVWEDT’ and item_name=’SUPPLIER’
FM_NAME BLOCK_NAME ITEM_NAME ITEM_TYPE SUB_ITEM_NAME DEFAULT_LABEL_PROMPT DEFAULT_ACCESS_KEY BASE_IND
FM_SUPVWEDT B_SUPS SUPPLIER Text Item NONE Supplier Y
字段描述:
FM_NAME: FM_||Form文件的名字
BLOCK_NAME: 该项(SUPPLIER)所在的block名字,如没有,就写"NONE"
ITEM_NAME: 该项(SUPPLIER)名
ITEM_TYPE: 项的类型,这里是 Text Item,还有Push Button,Window,LOV等很多,这里一定要写正确项的类型。
SUB_ITEM_NAME: 子项,目前我写的还没用到
DEFAULT_LABEL_PROMPT: 如果表form_elements_langs中没有设置语言标签,则用这个。
DEFAULT_ACCESS_KEY : 快捷键
BASE_IND: 目前还没搞清是什么意思,表里设置的都是’Y’
上面这个表里,是设置form拥有元素,实现多语言,还需要在表form_elements_langs中插入数据。
这个表结构和form_elements差不多,只不过少了字段ITEM_TYPE,多了Lang字段,Lang字段就是语言的种类。目前取值有8(中文)和1(英文)。
这样,一个form可视项的多语言就设置成功了。
Retail这样设置多语言,感觉太麻烦,每一个项都这样设置一遍,一个form的工作量很大的。
Menu的多语言:
和form差不多,它的表示menu_elements和menu_elements_langs。
3).Form初始化:
Form的初始化,写在Form的WHEN-NEW-FORM-INSTANCE触发器中。调用的主要过程有:
P_FORM_STARTUP->P_INITIALIZE、P_BOILERPLATE,这几个procedure都是fm_temp1中写好的,我们不用改变。我们需要添加的是自己的逻辑。
A. 初始化List Item
初始化List Item,要调用P_POPULATE_LIST(p_item_name varchar2,p_para varchar2),这个过程(该过程原型在stand45中),比如:P_POPULATE_LIST(‘B_apply.LI_cons_rev_freq’, ‘GCRF’)中,’B_apply.LI_cons_rev_freq’指List Item的名(一定要加上block的名),’GCRF’是表code_detail里的code_type字段。基本原理是该过程先定义一个cursor:
select code,code_desc from code_detail where code_type=’GCRF’,然后把code和code_desc赋给List Item,所以,List Item的动态值都来源于code_detail,做一个新的List Item之前,需要向这边表里插入数据。
4).Show错误提示:
显示错误提示,使用函数emessage(p_msg varchar2)如:
emessage(‘This_is_a_err_msg’);
raise form_trigger_failure;
错误提示也是分多语言的。所有的提示信息都放在rtk_errors表中,表里有一个三个重要字段
rtk_key: 比如这里的’This_is a err_msg’
rtk_lang: 语言
rtk_text: 提示信息;
比如在这个表里存在下面两条记录,则根据不同语言环境提示rtk_text的内容:
rtk_key rtk_lang rtk_text
This_is_a_err_msg 1 This is a err msg
This_is_a_err_msg 8 这个是错误信息
如果表里没有对于的提示信息,则直接显示emessage(‘This_is_a_err_msg’)中的参数,即’This_is_a_err_msg’
注:该过程原型:
PROCEDURE EMESSAGE (I_key varchar2,
I_txt_1 varchar2 := null,
I_txt_2 varchar2 := null,
I_txt_3 varchar2 := null) IS
l_ret_val BOOLEAN;
BEGIN
L_ret_val := RMESSAGE.SHOW (‘ALT_ERROR’, I_key, I_txt_1, I_txt_2, I_txt_3);
END;
5).Lov:
Retek的Lov的展现一般不会像ebs中,ebs中,一般是鼠标落在某个text item的项上,弹出某个lov,retek是在这个项的后面有一个按钮,当点击这个按钮的时候,会弹出一个lov,选择lov中的东西,吧选择的东西赋值给该item。
创建一个Lov的过程:
Step1. 建立一个Lov,指定其返回给那些项。
Step2. 在该需要Lov的Text Item的后面加一个按钮项(按钮项的图标:日期按钮的图标名称 calendsm,一般Lov 按钮的图标名称 listval,备注按钮的图标名称 smaltalk)
Step3. 在按钮下写如下代码:
Go_Item(‘B_ordhead.supplier’);–先把光标移到Text Item上
Do_Key(‘List_Values’);–显示Lov
刚才忘写了,创建弹出日期的Lov过程:
step1. 打开我们自己写的form的同时,打开fm_date.fmb(这个文件是标准程式)。
step2. 将fm_date下Object Group下的OG_DATE,拖动到自己的Object Group下,回弹出提示,这时选择“复制”。
step3. 将calend45.pll添加进来。
step4. 添加显示日期的text Item的when-new-item-instance事件:
另外,有一种情况也需要注意:
当需要根据不同的情况,动态显示不同的LOV。比如一个Text Item项里,但参数Para1为’学生’时,调用’学生’Lov(LOV_STUDENT),当Para1为’教师’时候,显示’教师’LOV(LOV_TEACHER)。这种情况,需要在Text Item的KEY-LISTVAL触发器中添加如下代码:
if :Para1= ‘学生’ then
if F_SHOW_LOV(LOV_STUDENT’) then
Do_Key(‘Next_Item’);
end if;
elsif :Para1= ‘教师’ then
if F_SHOW_LOV(LOV_TEACHER’) then
Do_Key(‘Next_Item’);
end if;…………
end if;
F_SHOW_LOV函数定义在stand45中。
BEGIN
Validate(Item_Scope);
if not FORM_SUCCESS then
raise FORM_TRIGGER_FAILURE;
end if;
—
if (P_CALENDAR.LP_date_ok is not NULL) then
if (P_CALENDAR.LP_date_ok = ‘Y’) then
:B_MAIN.TI_SETTLEMENT_DATE := P_CALENDAR.LP_current_date;
P_CALENDAR.LP_date_ok := NULL;
Do_Key(‘Next_Item’);
else
P_CALENDAR.LP_date_ok := NULL;
end if;
end if;
EXCEPTION
when FORM_TRIGGER_FAILURE then
raise;
when OTHERS then
emessage(SQLERRM);
raise FORM_TRIGGER_FAILURE;
END;
step5. 添加显示日期的text Item的key-listval事件:
DECLARE
L_return_to VARCHAR(256) := ‘B_main.TI_settlement_date’;
L_min_date DATE := NULL;
L_max_date DATE := INTERNAL_VARIABLES.GP_vdate;
L_default_date DATE := INTERNAL_VARIABLES.GP_vdate;
BEGIN
Validate(Item_Scope);
if not FORM_SUCCESS then
raise FORM_TRIGGER_FAILURE;
end if;
—
P_CALENDAR.SHOW_CALENDAR(L_return_to => L_return_to,
L_default_date => L_default_date,
L_min_date => L_min_date,
L_max_date => L_max_date);
EXCEPTION
when FORM_TRIGGER_FAILURE then
raise;
when OTHERS then
emessage(SQLERRM);
raise FORM_TRIGGER_FAILURE;
END;
step4. 在触发按钮下写如下代码:
Go_Item (‘B_main.TI_settlement_date’);
Do_Key (‘List_Values’);
6).新增菜单
retail的菜单是通过菜单文件(.mmb)来实现的。其真正的事件是代码是在form中,菜单只调用form中的代码。下面以一个例子来说明:
这个例子演示的是增加 供应商维护–〉选项 菜单中,增加“联营保底”,其form文件是supvwedt.fmb,菜单文件是supplier.mmb.
step 1. 新建(修改)Menu
(我们以supplier.mmb来说明,这个文件已经存在,我们来修改它既可)
在菜单OPTIONS_MENU下新增一个项:
name : GML_CONS_MARGIN
lable : &Consignment Attributes–其实这里的不准,因为我们后面还会改变它的lable
Menu Item Type : Plain
step 2. 在该Menu下写事件
Execute_Trigger(‘T_cons_margin’);–T_cons_margin是在form中定义的
step 3. 在Form中写事件
在 supplier.mmb 中增加form级trigger
name : T_CONS_MARGIN
execution Hierarchy : Override
其他默认
事件代码:
declare
…………
begin
……….
Open_Form(‘gmlconsmrgn’, –你自己的事件就写到这里就行了。
ACTIVATE,
SESSION,
L_pl_id);
………..
exception ….
..
end;
step 4. 编译form和Menu
编译form的步骤以前写的有,编译Menu的脚本和form一样,只是将
frmcmp.sh userid=$UP module=supvwedt module_type=form /**** 编译form */
换成
frmcmp.sh userid=$UP module=supplier module_type=menu /**** 编译Menu */
编译好后,将生成的.fmx和.mmx放到bin目录下去
注意:如果没有编译菜单文件生成.mmx并放入bin目录下,则菜单虽然会挂上去,但点击所有的菜单都没有任何事件响应。
step 5. 支持多语言
首先,执行
select * from menu_elements where menu_filename=’supplier’ for update;
可以看,菜单选项就是放这个表里的。
字段含义:
menu_filename 菜单文件名
menu_name 菜单名
menu_item_name 菜单选项名–这里我们一般使用英文,随便取一个名字,假设我们取 GML_CONS_MARGIN
default_lable 默认提示标签–如果语言设置里没有找到对应语言的标签,就会用这个
base_ind 目前我也不知道是什么含义,把它设为’Y’
所以,在上面的表里增加一行menu_name 取OPTIONS_MENU(因为我们要挂在“选项”下),menu_item_name 取 GML_CONS_MARGIN,default_lable 取&GML_CONS_MARGIN
其次,在执行
select * from form_menu_link where menu_filename=’supplier’ for update
可以看到,这个表里存放的是menu和form的关系。因为这form和menu的关系已经存在,我们不去修改它。
再次,执行
select * from menu_elements_langs where menu_filename=’supplier’ for update
这个表就是存放多语言的关系了。它和menu_elements的字段含义差不多,只不过多了一个语言
我们增加一行,语言设置成中文(字段值为8)
最后运行下边的sql检查多语言是否设置成功
select me.menu_name,
me.menu_item_name,
nvl(mel.lang_label, me.default_label) label
from menu_elements_langs mel,
menu_elements me,
form_menu_link fml
where upper(fml.fm_name) = upper(‘fm_supvwedt’)—form名
and upper(fml.menu_filename) = upper(me.menu_filename)
and upper(me.menu_filename) = upper(mel.menu_filename(+))
and upper(me.menu_name) = upper(mel.menu_name(+))
and upper(me.menu_item_name) = upper(mel.menu_item_name(+))
and 8/*L_user_lang*/ = mel.lang(+)–语言
and mel.menu_item_name = ‘GML_CONS_MARGIN’–菜单选项
and mel.menu_name = ‘OPTIONS_MENU’;–菜单名
如果能查到一条数据,就说明多语言设置已经成功了。
注:未完成,有时间再继续…..
关于作者:
昵称:jeff.huang 档案信息: 联系方式:你可以通过hong.huang@hand-china.com联系作者 点击查看jeff.huang发表过的所有文章... 本文永久链接: http://blog.retailsolution.cn/archives/1882 |
对本文的评价:
正在百度中找retek的calend45就发现商老大这一篇文章,正好来系统的了解下retek框架。