首页 > 开发, 默认 > Oracle Retail RMS 客户化开发文档

Oracle Retail RMS 客户化开发文档

概述

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

商云方经理的blog地址:http://blog.retailsolution.cn/

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界面风格

clip_image004

<图1-1> rms登录界面

clip_image006

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

clip_image008

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

clip_image010

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

clip_image012

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

clip_image014

<图1-6> 在运行报表前,需要再登录一次

clip_image016

<图1-7> 报表参数输入

clip_image018

<图1-8> 报表运行结果

Form获取

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

clip_image020

<图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的默认模式即可。

clip_image022

<图2-1>

clip_image024

<图2-2> 在<图2-1>所示界面点击“搜索”后,显示Form的另一个Canvases。

fm_XXX.fmb

这是实现业务逻辑的主要form。该form由fm_XXX_find.fmb调用open_form打开,open_form会使用一些参数,比如打开新form的状态是view,edit或者是new;或者是业务自己规定的一些变量。

clip_image026

<图2-3>

Me_XXX.mmb[可选]

fm_XXX.fmb所对应的主菜单。一般情况下,新开发的form不需要新建菜单,直接使用系统默认的菜单。除非业务功能特别多,需要菜单来实现。

clip_image028

<图2-4>

XXX.pls[可选]

fm_XXX.fmb处理业务逻辑所调用的package。如果业务逻辑比较复杂,建议建立一个这样的package,来实现业务逻辑,这样可以简化form的复杂度。

基于RMS form开发简单例子

先看一个简单例子,来演示一下RMS form的开发过程。

gmlsupreconfind.fmb

建立gmlsupreconfind.fmb。实现

界面

clip_image030

<图3-1>

clip_image032

<图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的时候会讲到)

clip_image034

<图3-3>

4. 新建一个data block,名称为B_ACTION,非数据库block。

5. 在B_ACTION下建立如下界面(红线圈内)所示的非数据库Item,都是push button类型的。

clip_image036

<图3-4>

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

clip_image038

<图3-5>

clip_image040

<图3-6>

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

clip_image042

<图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下一样。当然,可能还有主从结构的。

clip_image044

<图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。

clip_image046

创建一个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 :P ara1= '学生' then

    if F_SHOW_LOV(LOV_STUDENT') then

        Do_Key('Next_Item');

    end if;

elsif :P 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

<图4-1> 参数一

clip_image050

<图4-2> 布局一

clip_image052

<图4-3> 参数二

clip_image054

<图4-4>布局二

该类型的报表开发逻辑是:根据需要,用Reports builder建立两个不同的布局,根据参数显示不同的布局。

上面的这个例子在开发的时候,建立了两个循环框。分别在两个循环框里写如下代码如下:

function R_2FormatTrigger return boolean is

begin

    if :P _layout='1' then

        return (false);

    else

        return (true);

    end if;

end;

function R_1FormatTrigger return boolean is

begin

    if :P _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) := '&amp;USER_NAME' ;

 

  l_roles     VARCHAR2(400) := '&amp;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) := '&amp;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系统中设置用户属性,位置:启动->控制->设置->用户属性->新建

选择语言

clip_image056

注:如果没有创建用户,Step4中会提示用户无效。如果没有创建同义词,则用新建的用户进系统的时候会提示对表操作没有权限。

5. 设置用户组,位置:启动->控制->系统->地点/产品安全性->用户/组链接->编辑。(设置之前必须保证组已经建立并赋予一定的权限,这里不详细讲述)。添加一行新的。

clip_image058

到这里为止,用户已经成功创建,只要组已经设置并赋权,用户便可以使用。

可以看出,其实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,没有做这一个动作,仍然可以运行。

Closed Issues

---------------------------------------------------------------------------------------------------------

未命名

作者 黄鸿

组别 广州技术一组

2006年正式参加工作,热衷ERP事业,曾在liteonit(广州)实施SFC系统和EBS的二次开发和流程优化工作。2008年6月进入Hand,先后在温州天正协同制造项目,上海购宝零售项目做技术支持工作。对EBS制造、分销方面有开发经验,熟悉的开发工具有form/report/pl sql/discover/xml report 这篇文章是在上海购宝项目期间,做客户化开发过程中所写下的。

要学习的还有很多,同志仍需努力

 

 

关于作者:

昵称:jeff.huang
档案信息:
联系方式:你可以通过hong.huang@hand-china.com联系作者
点击查看jeff.huang发表过的所有文章...
本文永久链接: http://blog.retailsolution.cn/archives/2043

 

 

对本文的评价:

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...

 

 

分类: 开发, 默认 标签:
  1. cat
    2011年8月25日10:57 | #1

    关于RMS的用户安全性,上文已经把如何创建一个新用户讲完了;那么如何控制用户的的功能安全性和数据安全性呢? 请参考:merch-131-impg.pdf 在章节:RMS Users and Security 有详细描述;大概的意思:功能安全性通过插表的方式,数据安全性通过界面设置。

  2. xiaodongli
    2012年12月13日16:57 | #2

    可否再更新一下这个开发文档,或者 你那里有更新的版本么?或者有标准的开发官方文档吗,有的话发我邮箱一份,谢谢!

  1. 本文目前尚无任何 trackbacks 和 pingbacks.
您必须在 登录 后才能发布评论.