壹佰网|ERP100 - 企业信息化知识门户

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 3342|回复: 4

Oracle Retail RMS 客户化开发

  [复制链接]
发表于 2013/1/8 09:14:42 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。如果您注册时有任何问题请联系客服QQ: 83569622  。

您需要 登录 才可以下载或查看,没有帐号?注册

x
概述本文是在学习了retail rms下开发form的一点点心得。主要涉及内容是Form和Reports的开发。本文是在商云方经理的retail blog上取得原始资料,吸取了项目组很多同事的经验,非常感谢他们。本文档所描述的内容,可能只是Retail客户化开发的冰山一角,形如管中窥豹,希望后面有机会开发rms 的同事能从这篇文档里获得一些帮助,并对rms客户化开发文档进一步完善。

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的情况。很可惜,也没有类似EBS的弹性域,因为其数据库表结构没有弹性域字段,我认为这是Retail需要改进的一个地方。
注:有的地方叫法为Retek,实际上也是指的retail。
开发背景与基础读者基础要求1. 有EBS的使用经验,尤其是Form的使用经验
2. 熟悉PL/SQL
3. 熟悉Telnet和FTP工具,熟悉Windows常规操作
4. 理解或开发过数据库应用系统
5. 有Form(EBS Form)开发经验则更佳
准备工作用户1. OS用户:包括超级用户root,用于上传编译开发的form
2. 数据库开发用户,比如本项目中rms12dev,用于数据库的操作,比如使用pl/sql developer开发package等
3. Rms开发管理用户,比如本项目的rms12dev,用于在rms系统中调试
注: 关于Rms用户,将在“新增RMS”用户讲到
工具1. telnet工具 :如SecureCRT登录服务器,编译form和pll;连接服务器,SecureFX下载必要文件、上传开发的Form
2. Form builder: 安装developer10gr2(安装好后包括Form builder/Reports builder/Sql*pls/Jdeveloper)
3. 配置Form编辑环境:
客户端:
在D盘建立 retail_resource 目录
从服务器下载 /d01/app/retail/rms/app/rms/forms 目录
从服务器下载 /d01/app/retail/rms/app/toolsets 目录
Regedit
hkey_local_machine/software/oracle/KEY_DevSuiteHome1
编辑item : forms_path
添加
D:\Retail_Resource\forms\src;D:\Retail_Resource\toolset\src;D:\Retail_Resource\toolset\bin;
D:\Retail_Resource\forms\bin
服务器端配置
建立一个环境变量文件:rmsformsvr.env (创建在/home/oracle/),其内容如下:(环境不同,有些变量名称、路径不同)
ORACLE_HOME=/d01/app/oracleas/OraHome_1
export ORACLE_HOME
DISPLAY=syfr12:1.0
INSTALL_DIR=/d01/app/retail/rms/app
export INSTALL_DIR  
PATH=$ORACLE_HOME/bin:$ORACLE_HOME/opmn/bin:$ORACLE_HOME/dcm/bin:$INSTALL_DIR/
forms10gr2_scripts:$PATH
CLASSPATH=$ORACLE_HOME/jlib/importer:$ORACLE_HOME/jlib/debugger.jar:$ORACLE_HOME/
jlib/utj.jar:$ORACLE_HOME/jlib/ewt3.jar:$ORACLE_HOME/jlib/share.jar:$ORACLE_HOME/
jlib/dfc.jar:$ORACLE_HOME/jlib/help4.jar:$ORACLE_HOME/jlib/oracle_ice.jar:$ORACLE_HOME/
jlib/jewt4.jar
FORMS_BUILDER_CLASSPATH=$CLASSPATH
FORMS_PATH=$INSTALL_DIR/toolset/bin:$INSTALL_DIR/rms/forms/bin:$ORACLE_HOME/forms
REPORTS_PATH=$INSTALL_DIR/rms/reports/bin:$ORACLE_HOME/forms
TK_UNKNOWN==$ORACLE_HOME/guicommon/tk/admin
UP=rms12dev/rms12dev@RETL
LD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME/jdk/jre/lib/sparc:$ORACLE_HOME/jdk/jre/lib
/sparc/native_threads
export DISPLAY PATH CLASSPATH FORMS_BUILDER_CLASSPATH FORMS_PATH REPORTS_PATH TK_UNKNOWN UP LD_LIBRARY_PATH
注:本小节资料由商云方提供 http://blog.retailsolution.cn/blog/index.php/rms-form-compile
感性认识下面用几张图片来感性认识下rms form界面风格

<图1-1> rms登录界面

<图1-2> 用rms12dev登录后的主界面(rms12dev为开发管理员)

<图1-3> 查询界面以及LOV,查询界面类似ebs中点击“手电筒”后的查询窗口,区别是这里是一个单独的Form。

<图1-4> 主要业务逻辑处理界面,布局比较灵活。

<图1-5> 打印报表,点击“打印”后会显示<图1-6>所示画面。

<图1-6> 在运行报表前,需要再登录一次
clip-image016-thumb1.jpg
<图1-7> 报表参数输入

<图1-8> 报表运行结果
Form获取如果要修改一个Form,怎么知道它的名称呢?从界面上可以看到form的名字。比如下图中的recutadj,然后在/d01/app/retail/rms/app/rms/forms/src目录下(不同项目此目录可能目录不同)找到recutadj.fmb,下载之。

<图1-9> 通过界面查看Form名称
基于rms form开发过程按Retail的习惯,开发一个新的form,一般需要开发下面4个文件,但不是所有的都是必须的。
fm_XXX_find.fmb[可选]查找form,在打开“真正”的业务处理form fm_XXX.fmb之前,需要打开这个查找form,该form的作用是选择本次操作的类型查询出数据,一般操作类型有三种,“查看”,“编辑”,“新建”。如果是“新建”,则直接打开form_XXX来新建业务;如果是“查看”,则通过该form查到到业务记录,调用fm_XXX查看业务细节,fm_XXX的项都是不可编辑的;如果是“编辑”,则调用fm_XXX查看业务细节,并可对业务细节数据进行编辑。 当在RMS主界面上双击rms菜单项时,一般是打开该form,再由该Form调用fm_XXX。
使用fm_XXX_find,是因为Retail form中没有EBS的 F11,Ctl+F11等快捷键,也没有EBS中“查找”窗体。我们也可以不使用这个form,只要在打开form fm_XXX.fmb的时候能够确定本次操作是查看,编辑或者新建就好了。比如,同一个form我们需要不同权限的人来打开,有的权限是查看,有的是编辑,有的是新建。这时候,我们只要在菜单上给每个权限挂不同的菜单项,并对每个菜单项设置打开form的默认模式即可。

<图2-1>

<图2-2> 在<图2-1>所示界面点击“搜索”后,显示Form的另一个Canvases。
fm_XXX.fmb这是实现业务逻辑的主要form。该form由fm_XXX_find.fmb调用open_form打开,open_form会使用一些参数,比如打开新form的状态是view,edit或者是new;或者是业务自己规定的一些变量。

<图2-3>
Me_XXX.mmb[可选]fm_XXX.fmb所对应的主菜单。一般情况下,新开发的form不需要新建菜单,直接使用系统默认的菜单。除非业务功能特别多,需要菜单来实现。

<图2-4>
XXX.pls[可选]fm_XXX.fmb处理业务逻辑所调用的package。如果业务逻辑比较复杂,建议建立一个这样的package,来实现业务逻辑,这样可以简化form的复杂度。
基于RMS form开发简单例子先看一个简单例子,来演示一下RMS form的开发过程。
gmlsupreconfind.fmb建立gmlsupreconfind.fmb。实现
界面
<图3-1>

<图3-2>
实现过程1. 打开fm_temp1,将Module(FM_TEMPL)改为FM_GMLSUPRECONFIND,另存为gmlsupreconfind.fmb。
2. 新建一个data block,名称为B_MAIN,非数据库block。
3. 在B_MAIN下建立如下图界面(红线圈内)所示的非数据库Item,和ebs下步骤一样,就不多说了。这里只是演示建立block,其Canvas后面建立。(红线内的按钮先不管,后面将LOV的时候会讲到)

<图3-3>
4. 新建一个data block,名称为B_ACTION,非数据库block。
5. 在B_ACTION下建立如下界面(红线圈内)所示的非数据库Item,都是push button类型的。

<图3-4>
6. 新建一个data block,名称为B_SUPRECON,数据库block,基于表GML_INVC_STM_HEAD。其上的Item都不能insert、update、delete。因为这里只是将数据显示出来。将实现的效果如下:

<图3-5>

<图3-6>
7. 新建一个data block,名称为B_COL_HEAD,在B_COL_HEAD下建立如下界面(红线圈内)所示的非数据库Item,主要是按钮,一方面用来做上一步中建立的Item的标题,另一个用途主要是排序(点击某列上的按钮,则按该列排序,实际上是加上order by重新查询一次)。

<图3-7>
8. 建立Canvas: C_MAIN,type 为content。
9. 建立Canvas: C_SUPRECON,type为stacked。
10. 将B_MAIN上的Item放在C_MAIN上(见图3),将B_SUPPECON上的Item放在C_SUPPECON上(见图6),B_ACTION上的Item放C_MAIN上(见图4)。如
11. 建立W_MAIN,将C_MAIN和C_SUPPECON的window属性都设成W_MAIN,注意调整C_SUPPECON的位置和大小。需调整位置的大小和原因见下一步。
12. 建立:B_ACTION.PB_SEARCH(那个Search按钮)的WHEN-BUTTON-PRESSED事件:
BEGIN
    if not FORM_SUCCESS then
        raise FORM_TRIGGER_FAILURE;
    end if;
    show_View('C_SUPRECON');--C_SUPRECON
    P_MULTIVIEW.GO_MULTIVIEW_BLOCK('C_SUPRECON');--已有的form是这样写的,但我这样写的时候会报一大堆错。记住这里实现的就是显示C_SUPRECON,代码可以自己重写
    RWIDGET.TURN_OFF('B_main.LI_action');
    RWIDGET.TURN_ON('B_action.PB_back');
    RWIDGET.TURN_ON('B_action.PB_ok');
    RWIDGET.TURN_ON('B_action.PB_REFRESH');--retail标准的函数RWID.TRUN_OFF,RWID.TRUN_OFF,实现Item的enabled属性
EXCEPTION
    when FORM_TRIGGER_FAILURE then
      Raise;
    when OTHERS then
      emessage(SQLERRM);
      Raise FORM_TRIGGER_FAILURE;
    END;
13. 建立:B_ACTION.PB_OK(OK按钮)的WHEN-BUTTON-PRESSED事件:
该事件实现:在C_SUPPECON界面上,点击“OK”按钮,打开fm_SUPPECON。
DECLARE
    L_action VARCHAR2(10) := :B_main.LI_action;
BEGIN
    Issue_Savepoint('CALL_FORM');
    if L_action = 'NEW' then
        P_CALL_FORM('NEW');
    elsif L_action = 'VIEW' then
        P_CALL_FORM('VIEW');
    elsif L_action = 'EDIT' then
    P_CALL_FORM('EDIT');
    end if;
EXCEPTION
    when FORM_TRIGGER_FAILURE then
        Issue_Rollback('CALL_FORM');
        raise;
    when OTHERS then
        emessage(SQLERRM);
        raise FORM_TRIGGER_FAILURE;
END;
14. P_CALL_FORM
PROCEDURE P_CALL_FORM(p_action varchar2) IS
    L_action VARCHAR2(10) := :B_main.LI_action;
    PARAM_LIST PARAMLIST;
    PL_id VARCHAR2(9) := 'gml_supreconfind';
    L_exists VARCHAR2(1) := 'N';
    L_settlement_id GML_INVC_STM_HEAD.SETTLEMENT_ID%TYPE;
BEGIN
    -- destroy the parm list if still present
    P_DESTROY_PARAMETER_LIST(PL_id);
    PARAM_LIST := Create_Parameter_List(PL_id);
    -- add parameters
    add_parameter(PARAM_LIST,
                          'PM_MODE',
                          TEXT_PARAMETER,
                          L_action);
    add_parameter(PARAM_LIST,
                         'PM_settlement_id',
                         TEXT_PARAMETER,
                         L_settlement_id);
    -- call the program
     open_form('gmlsuprecom',
                    ACTIVATE,
                    SESSION,
                    PARAM_LIST);
EXCEPTION
    when FORM_TRIGGER_FAILURE then
        Raise;
END P_CALL_FORM;
fm_SUPPECON建立完毕。
15. 现在开始写fm_XXX.fmb,其开发过程和fm_XXX_find一样,也是从fm_temp1来。主要要建立三个习惯上的Block:
B_ACTION:和fm_XXX.fmb一样,用于放下面的一排按钮。
B_XXX:基于表的一个block。和ebs下一样。当然,可能还有主从结构的。

<图3-8>
16. B_APPLYS:类似EBS下的“Control”block,控制块。
其他的可以自由发挥,只要便于后面的人维护就好。这里,不再详细叙述。
17. me_XXX.mmb菜单我们在后面专门来叙述。
18. 如果form fm_XXX.fmb要用到package,需要在数据库中建立package。
到此,开发一个form的基本流程基本演示完毕,用户在使用的时候,会一次看到以下的画面。
<图3-1>
<图3-2>
<图3-8>
基于rms form开发常用技巧下面看一看retail开发的一些函数和技巧,这些多是retail标准的。
命名规则Form:Retail没有统一规则,一般以客户名简写加通俗易懂的字母/单词(比如:gmlgmlsuprecom.fmb,gml为客户名称简写)下面我们自己取名将以XXX替代。
Module:一般命名为FM_XXX(比如:FM_GMLCONSMRGN);
Block:一般命名为 B_XXX(比如:B_ACTION);
Cavans::一般命名为C_XXX(比如:C_CONSMRGN);
Window:一般命名为W_XXX(比如:W_CONSMRGN);
Item:一般是Text Item命名为TI_XXX,List Item命名为LI_XXX,Check Box命名为CB_XXX,按钮命名为PB_XXX…按此规律命名即可;只要大家一看都能明白就好。
多语言的实现Retail的多语言,和EBS不同。EBS是在不同的语言环境放置不同语言的form程序,retail则只有一个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(英文)。如果要设置两种语言,则要插入2笔数据。
这样,一个form可视项的多语言就设置成功了。
Retail这样设置多语言,感觉太麻烦,每一个项都这样设置一遍,一个form的工作量很大的。
Menu的多语言:和form差不多,它的表示menu_elements和menu_elements_langs。
注:form的多语言是指form上的提示信息,如Item标题,message,Lov标题等,不能像ebs的表fnd_lookup一样,表里的数据是多语言的。
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之前,需要向这个表里插入数据。当然,也可以在程序里面写死
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;
Lov设计Retail的Lov的展现一般不会像ebs中,ebs中,一般是鼠标落在某个text item的项上,弹出某个lov,retail是在这个项的后面有一个按钮,当点击这个按钮的时候,会弹出一个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 ara1= '学生' then
    if F_SHOW_LOV(LOV_STUDENT') then
        Do_Key('Next_Item');
    end if;
elsif ara1= '教师' then
    if F_SHOW_LOV(LOV_TEACHER') then
         Do_Key('Next_Item');
    end if;
end if;
F_SHOW_LOV函数定义在标准package 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;
Step6. 在按钮WHEN-BUTTON-PRESSED事件下写如下代码:
Go_Item ('B_main.TI_settlement_date'); -- B_main.TI_settlement_date是需要得到LOV值得Text Item
Do_Key ('List_Values');
菜单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中写事件 ,注意将form的menu Module属性设置为supplier
在 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
(编译方法参见下一节)
编译好后,将生成的.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';--菜单名
如果能查到一条数据,就说明菜单多语言设置已经成功了。
编译Form/Menu根据前面建立的环境变量,Form的编译语句如下:
假如要编译trv.fmb
oracle 用户登录
source rmsformsvr.env
cd $INSTALL_DIR/rms/forms/src
cp rtv.fmb rtv.fmb.bak
frmcmp.sh userid=$UP module=rtv module_type=form
cp $INSTALL_DIR/rms/forms/bin/rtv.fmx $INSTALL_DIR/rms/forms/bin/rtv.fmx.bak
cp -f $INSTALL_DIR/rms/forms/src/rtv.fmx $INSTALL_DIR/rms/forms/bin/
注:后面两句的意思是将原来的.fmx备份,再将编译后生成的文件放到bin目录下,这样才能运行。
编译menu,比如menu名称supplier.mmb,将上面的frmcmp.sh userid=$UP module=rtv module_type=form
换成frmcmp.sh userid=$UP module=supplier module_type=menu,即改变module=menu名,module_type=menu
注:本小节资料有商云方提供 http://blog.retailsolution.cn/blog/index.php/rms-form-compile
将客户化Form挂到rms上和Form上菜单项有关的sql语句一级菜单(folder)
SELECT * FROM NAV_FOLDER WHERE parent_folder IS NULL
二级菜单(folder)
SELECT * FROM NAV_FOLDER WHERE parent_folder ='ORDER_RELATED' --比如 订购
菜单项(Form)
SELECT * FROM NAV_ELEMENT where element='cux_jeffdemo' --Form名是 FM_cux_jeffdemo
SELECT * FROM NAV_ELEMENT_MODE WHERE folder='ORDER_RELATED' --Form 挂哪个Menu(folder)下
Menu和 Form对应关系(头上显示的菜单,不是菜单项)
SELECT * FROM FORM_MENU_LINK WHERE fm_name ='FM_'||upper('cux_jeffdemo') for update
Form和角色的关系即哪个角色可以看某个Form
SELECT * from NAV_ELEMENT_MODE_ROLE where element = 'cux_jeffdemo'
用户和角色的关系
SELECT * FROM USER_ROLE_PRIVS WHERE USERNAME = 'RMS12DEV'
所以,这里存在两种关系:
1. User->Role->Form(一个用户可以看见哪些Form)
       User
         |
      Role1 - Role2
               |
Form1-Form2-...FormN
2. Folder->Form (一个Form挂在哪个地方)
     Folder
        |
Folder-Folder...
      |
      .
      .
      .
    Folder-Folder...
        |
Form1-Form2...
实例挂Form下面以一个实例说明:
将form FM_cux_jeffdemo2 挂在rms系统的“订购”-->“固定交易” 菜单下
Step 1.建立菜单
向 table NAV_FOLDER 中加入一行(“订购”和“固定交易”两个菜单都有,所以不用建立)
Step 2.
向 table NAV_ELEMENT 中加入一行
ELEMENT ELEMENT_TYPE COMPONENT
cux_jeffdemo2 F RMS
--ELEMENT Form 名
--ELEMENT_TYPE 类型 F表示Form
--COMPONENT 挂在RMS下
Step 3.
向 table FORM_MENU_LINK 中加入一行
FM_NAME MENU_FILENAME
FM_CUX_JEFFDEMO2 cux_jeffdemo2
--FM_NAME 'FM_' + Form名
--MENU_FILENAME Form名
Step 4.
向 table NAV_ELEMENT_MODE 中加入一行
ELEMENT NAV_MODE FOLDER ELEMENT_MODE_NAME
cux_jeffdemo2 --DEFAULT-- FIX_DEAL 客户化Form Demo
--ELEMENT Form名
--NAV_MODE 打开Form的状态 查看(VIEW)-编辑(EDIT)-默认(--DEFAULT--)
--FOLDER Form放哪一个菜单(folder)下
--ELEMENT_MODE_NAME 菜单上显示的 prompt
Step 5.
向 table NAV_ELEMENT_MODE _ROLE中加入一行
ELEMENT NAV_MODE FOLDER ROLE
cux_jeffdemo2 --DEFAULT-- FIX_DEAL DEVELOPER
--ELEMENT Form名
--NAV_MODE 打开Form状态,需与上一步一致,否则建立不了(与上一步的table设置了外键)
--FOLDER 同上一步
--Role 该Form分给哪个Role
可以查看表 USER_ROLE_PRIVS 知道用户和Role的对应关系
至此,就可以在rms的菜单项中,看到我们增加的这个菜单了(“客户化Form Demo”)。
Retail Report开发简要说明Retail报表采用Reports builder开发。和6i下开发EBS报表基本没有区别。使用过6i的话,很快就能开发报表。需要提到的一点就是,根据不同输入参数,报表显示不同格式。
例如下面的报表,输入不同的参数,输出不容的布局。
clip-image048-thumb1.jpg
<图4-1> 参数一

<图4-2> 布局一
clip-image052-thumb1.jpg
<图4-3> 参数二

<图4-4>布局二
该类型的报表开发逻辑是:根据需要,用Reports builder建立两个不同的布局,根据参数显示不同的布局。
上面的这个例子在开发的时候,建立了两个循环框。分别在两个循环框里写如下代码如下:
function R_2FormatTrigger return boolean is
begin
    if _layout='1' then
        return (false);
    else
        return (true);
    end if;
end;
function R_1FormatTrigger return boolean is
begin
    if _layout='1' then
        return (TRUE);
    else
        return (false);
    end if;
end;
仅需这样,就可以实现上面的效果。以前6i里面直接这样写是不行的,还的在布局里建立一个过程。
将客户化Report挂到rms上Rms下,报表管理做得比较粗劣,下面用一个实例来了解Rms挂报表的方法。Rms报表的运行结果是一个浏览器打开的pdf格式的文件,很遗憾,不能像ebs中的并发请求那样,将结果保存在服务器上,只能保存到本地。
一个例子生成格式文件.rep文件利用写好的报表CUX_GouBaoRep_Demo.rdf生成CUX_GouBaoRep_Demo.rep
(6i开发rdf报表公司资料库有很多资料介绍,10 report builder建立rdf文件和6i差不多,这里不详细介绍了)
1. 将本地编译通过的CUX_GouBaoRep_Demo.rdf文件,上传到 /d01/app/retail/rms/app/rms/reports/src
2. 运行下面的命令
cd /home/oracle
su oracle
source rmsformsvr.env
cd /d01/app/retail/rms/app/rms/reports/src
rwconverter.sh source=CUX_GouBaoRep_Demo.rdf userid=$UP dest=CUX_GouBaoRep_Demo.rep stype=RDFFILE dtype=REPFILE batch=yes
上面的命令会在 /d01/app/retail/rms/app/rms/reports/src 目录下生成 CUX_GouBaoRep_Demo.rep,再将 CUX_GouBaoRep_Demo.rep 剪贴到
/d01/app/retail/rms/app/rms/reports/bin下
注意:生成的.rep文件名如果含有字母,则字母必须是全小写,否则在运行的时候会报找不到报表
在rms中设置报表可用在后台表RTK_REPORTS添加如下记录
MODULE REPORT_NAME REPORT_DESC PARAMETER_IND PRINTFRM_IND PRINT_MODE SELECT_IND
CUX_GouBaoRep_Demo CUX_GouBaoRep_Demo CUX_GouBaoRep_Description_Demo Y Y A
table RTK_REPORTS 字段说明:
1. MODULE 应该类似于EBS中的模组,但这里随便输入都可以
2. REPORT_NAME 报表名,这个须是报表文件名,比如CUX_GouBaoRep_Demo
3. REPORT_DESC 报表描述,随便取一个用户容易看懂的
4. PARAMETER_IND 只能选择'Y'/'N',目前还不知道作用,从意义上来看应该和参数有关,但我测试输入'Y'或'N'好像没有什么区别
5. PRINTFRM_IND 只能选择'Y'/'N',在form上可以打印的时候是否可以选择到该报表,选择'Y',可在rms form中选择到,否则选不到
6. PRINT_MODE 只能选择'A'/'S',同PARAMETER_IND,目前也不确定
7. SELECT_IND 不确定,目前系统里都为空
可以看到客户化的报表已经可以运行了。
效果图见:<图1-5>-<图1-8>
新增rms用户RMS系统用户的用户为DB用户,创建非常繁琐,而且需要后台处理,这里总结步骤如下:
1. 在数据库后台创建DB用户。
2. 对创建的用户授予角色权限、系统权限。
/*==================================================
  Copyright (C) HAND Enterprise Solutions Co.,Ltd.
             AllRights Reserved
  ==================================================*/
/*==================================================
  Program Name:
      CREATE RMS USER
  Description:
      This program create Oracle rms db user and grant all privileges .
  History:
      1.00  2008-11-10  Kenneth.shao    Creation
      2.00  2008-11-10  Kenneth.shao    Modified
修改角色授权,增加选择角色功能,可以支持授权多个角色,用“,”号分割
如:developer,select_catalog_role
  Version:
      2.00
  ==================================================*/
DECLARE
  l_user_name VARCHAR2(30) := '&USER_NAME' ;
  l_roles     VARCHAR2(400) := '&ROLE' ;
  l_crt_user varchar2(300) := 'create user '|| l_user_name ||'
  identified by "' || l_user_name || '"
  default tablespace RETEK_DATA
  temporary tablespace TEMP
  profile DEFAULT
  quota unlimited on lob_data
  quota unlimited on retek_data
  quota unlimited on retek_index';
  l_grant VARCHAR2(4000) ;
BEGIN
  --Create user
  EXECUTE IMMEDIATE l_crt_user ;

  --Grant directory
  l_grant := 'grant read on directory SYS.OUTPUT_WORKING to '||l_user_name;
  EXECUTE IMMEDIATE l_grant ;
  l_grant := 'grant read on directory SYS.UTL_FILE_DIR to '||l_user_name||'              with grant option';
  EXECUTE IMMEDIATE l_grant ;

  --Grant role privileges
  l_grant := 'grant ' || l_roles || ' to '||l_user_name ;
  EXECUTE IMMEDIATE l_grant ;

  --Grant system privileges
  l_grant := 'grant alter session
    , analyze any
    , create any context
    , create any procedure
    , create any synonym
    , create any table
    , create any type
    , create database link
    , create library
    , create materialized view
    , create procedure
    , create public database link
    , create public synonym
    , create sequence
    , create session
    , create synonym
    , create table
    , create trigger
    , create view
    , debug connect session
    , delete any table
    , drop any procedure
    , drop any synonym
    , drop any table
    , execute any procedure
    , execute any type
    , insert any table
    , query rewrite
    , select any sequence
    , select any table
    , update any table to '||l_user_name ;
  EXECUTE IMMEDIATE l_grant ;
END ;
3. 为新建DB用户创建RMS12DEV(现行环境下的用户)下对象的同义词
/*==================================================
  Copyright (C) HAND Enterprise Solutions Co.,Ltd.
             AllRights Reserved
  ==================================================*/
/*==================================================
  Program Name:
      CREATE RMS SYNONYM
  Description:
      This program create all synonym for rms12dev to rms new user .
  History:
      1.00  2008-11-10  Kenneth.shao    Creation
  Version:
      1.00
  ==================================================*/
DECLARE
  l_user VARCHAR2(30) := '&USER_NAME';
BEGIN
  FOR syn_r IN (SELECT DISTINCT 'create or replace synonym '|| l_user || '.' ||              object_name ||  ' for rms12dev.' || object_name   syn
                  FROM dba_objects
                 WHERE owner = 'RMS12DEV'
                   AND object_name NOT LIKE 'BIN$%'
                   AND object_type IN ('SEQUENCE'
                                      ,'PROCEDURE'
                                      ,'PACKAGE'
                                      ,'LOB'
                                      ,'LIBRARY'
                                      ,'MATERIALIZED VIEW'
                                      ,'TABLE'
                                      ,'VIEW'
                                      ,'FUNCTION'
                                      ,'TYPE')
                ) LOOP
    BEGIN
    EXECUTE IMMEDIATE syn_r.syn ;
    EXCEPTION
      WHEN OTHERS THEN
        dbms_output.put_line(syn_r.syn||'-----'||SQLERRM) ;
    END ;
  END LOOP;              
END ;
4. 在RMS系统中设置用户属性,位置:启动->控制->设置->用户属性->新建
选择语言

注:如果没有创建用户,Step4中会提示用户无效。如果没有创建同义词,则用新建的用户进系统的时候会提示对表操作没有权限。
5. 设置用户组,位置:启动->控制->系统->地点/产品安全性->用户/组链接->编辑。(设置之前必须保证组已经建立并赋予一定的权限,这里不详细讲述)。添加一行新的。

到这里为止,用户已经成功创建,只要组已经设置并赋权,用户便可以使用。
可以看出,其实RMS用户是在DB层建立的用户。
注:本小节资料有邵志国提供 http://blog.retailsolution.cn/blog/index.php/retail-rms-user-create
报表服务器的一个特殊设置在oracleias 10g中,已经没有report server,被整合到OC4J里,所以,要启动10AS的“Report Server”,只有启动OC4J就可以了。
通过下面命令:
opmnctl status
得到如下输出:
Processes in Instance: formreportsvr.syfr12
-------------------+--------------------+---------+---------
ias-component | process-type | pid | status
-------------------+--------------------+---------+---------
DSA | DSA | N/A | Down
LogLoader | logloaderd | 11895 | Alive
HTTP_Server | HTTP_Server | 5298 | Alive
dcm-daemon | dcm-daemon | N/A | Down
WebCache | WebCache | 5305 | Alive
WebCache | WebCacheAdmin | 5294 | Alive
OC4J | home | 13643 | Alive
OC4J | OC4J_BI_Forms | 13644 | Alive
可以看到OC4J已经起来了,但在运行报表的时候如下错误:
“http 404”的错误,或者找不到网页的错误
Case
Report Server的配置问题。
Solution
1. 修改rms.env(/d01/app/oracleas/OraHome_1/forms/server/目录下),在后面追加一下内容
具体请参考(Detail请参考 /d01/app/retail/rms/12.0.1下rms-1201-ig.pdf 【Configure Oracle Application Server 10 for RMS Reports】)
/*****************************************************
ORACLE_RMS_REPORTS_HOST=http://syfr12:7778/
ORACLE_RMS_REPORTS_SERVER=rep_syfr12_oracleas1+envid=rms12arep
ORACLE_RMS_RWSERVER=reports/rwservlet
*****************************************************/
注:ORACLE_RMS_REPORTS_HOST=http://<server>:<Listen port>
ORACLE_RMS_REPORTS_SERVER is the value of the reports configuration file without the .conf plus a standard envid ("envid" must be used) and the name of the header inside the configuration file that defines the variable REPORTS_PATH.
2. 修改rep_syfr12_oracleas1.conf(/d01/app/oracleas/OraHome_1/reports/conf目录下)
在标签</server>前添加以下内容(Detail请参考metalink 559039.1)
/*******************************************************
<environment id="rms12arep">
<envVariable name="REPORTS_PATH"
value="/appl/acc/ah01/rt12/rms/reports/bin:/appl/acc/ise/oras/aoasgm02/reports/reports/
templates:/appl/acc/ise/oras/aoasgm02/reports/reports/samples/demo:/appl/acc/ise/oras/
aoasgm02/reports/integ:/appl/acc/ise/oras/aoasgm02/reports/printers"/>
<envVariable name="NLS_LANG" value="AMERICAN_AMERICA.UTF8"/>
</environment>
*******************************************************/
Open Issues从Retail标准Form来看,新增一个Form,需在SCREEN_SQL中增加一个函数,在Form的初始化过程P_INITIALIZE中会调用SCREEN_SQ.GET_SCREENTEXT,进而调用的新增的函数。一直没弄明白该函数的作用,我自己新建的一个Form,没有做这一个动作,仍然可以运行。
 楼主| 发表于 2013/1/8 09:16:30 | 显示全部楼层
自己占个沙发,上面有商云方经理的博客。这个做为retail开发参考文档还是相当 不错的。 有发现更好的文档的可以拿 来分享交流!
发表于 2013/1/10 15:23:47 | 显示全部楼层
这篇文章是目前仅有的retail开发类文档,仅涉及到forms还没讲shell和proc。呵呵
发表于 2013/9/1 12:54:05 | 显示全部楼层
这个挂载form和report 是有个标准的界面处理的,在 控制>系统>树管理 界面 可以新增文件夹和挂载FORM,Report等东西
发表于 2013/9/9 13:19:02 | 显示全部楼层
ghgg 发表于 2013/9/1 12:54
这个挂载form和report 是有个标准的界面处理的,在 控制>系统>树管理 界面 可以新增文件夹和挂载FORM,Repo ...

{:soso_e146:}不早说,拉黑。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|小黑屋|手机版|壹佰网 ERP100 ( 京ICP备19053597号-2 )

Copyright © 2005-2012 北京海之大网络技术有限责任公司 服务器托管由互联互通
手机:13911575376
网站技术点击发送消息给对方83569622   广告&合作 点击发送消息给对方27675401   点击发送消息给对方634043306   咨询及人才点击发送消息给对方138011526

GMT+8, 2025/11/28 22:23 , Processed in 0.018378 second(s), 17 queries , File On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表