首页 > 代码库 > Oracle EBS Form个性化开发
Oracle EBS Form个性化开发
Form个性化开发内容不是很多,在国内的项目上客户化界面上基本用不上,相关开发文档有的讲解的很详细,有的讲解太过简练,希望通过这个文档可以给我们这些刚开始做个性化的新手快速完成需求,不要再这方面花费过多的时间,我们都做过Form开发,可以把Form个性化的开发都用类比Form开发去理解就很快能上手。
Form启动时,所有与当前Function相关的个性化规则都会被加载到内存,当Form触发特定的Event时候,系统会搜索相应的个性化规则并进行匹配,得到匹配的规则,再按照规则序号从小到大一次执行对应的个性化效果。执行完毕后,将该Event会传到Form,执行Form原先定义的处理代码。所以这里注意的是,Form个性化的规则是加在在Form原先定义的程序之前的,如果针对同一个事件,个性化和Form原先定义的程序都处理了,那么个性化的效果就会被Form原先定义的程序所覆盖,看不到个性化效果,这一点需要注意。
1. 基于Form界面的个性化开发
对标准界面简单的个性化开发可以直接在开发界面上进行一些修改,无需修改标准的CUSTOM.pll文件,避免对标准界面产生较大的影响。如果当前看不到帮助菜单的诊断功能的话,在界面上做个性化开发之前需要修改两个配置文件的值,分别是:
公用程序:诊断 是
隐藏诊断菜单项 否
1.1个性化界面介绍
注意事项:
1. 界面上顶部的有当前的表单名和功能名,如果是基于CUSTOM.pll文件的个性化,通常检测的都是当前的Form名称而不是功能 。
2. 调试模式:关闭,显示调试信息,逐步。
关闭:不使用调试模式,即当Action的类型为Message,Message的Message Type 为“调试“ 的时候,在打开Form界面的时候并不显示“调试”类型的消息。
显示调试信息:允许显示活动(Action)为Message,Message Type为“调试”的消息
逐步:设置为这个模式可以很方便的查看设置的个性化在哪一步起作用了,设置完成个性化之后,每次打开应用界面满足个性化条件的时候都会显示满足那个个性化规则。
3. 对一个界面所加的个性化序号在1到100直接,个性化的执行顺序按照需要的大小的顺序,序号可以是小数。
4. 执行该个性化的条件中的触发器时间,对于Form界面上只能用到五个触发器,并不像在Form Builder 开发工具中使用到很多的触发器,因为个性化效果是在Form代码之前加载的,这五个触发器分别是
WHEN-NEW-FORM-INSTANCE、WHEN-NEW-BLOCK-INSTANCE、WHEN-NEW-RECORD-INSTANCE、
WHEN-NEW-ITEM-INSTANCE、WHEN-VALIDATE-RECORD。
还有其它的SPECIALLn(总共45个,最终的结果是在菜单栏的下拉列表中添加一个菜单项,SPECIAL1至15是在Tools菜单下,16至30是在Reports菜单下,31至45在Actions菜单下,需要注意的是,一般Actions菜单不显示,因为它下面没有菜单项目,没有显示的意义,只有在这个菜单下创建了菜单项才会有显示出这个菜单),MENUn(15个)触发器。
有时候我们在个性化的开发中往往不能选准触发器,触发的时间过早会导致界面上相关字段的取值不能取到,触发的时机过迟会导致达不到效果。我们可以把界面设置成显示自定义状态,然后在界面上试着操作,找到我们对应的触发时机,需要打开个性化代码中的“显示自定义选项”的单选框。使用完成后需要关闭。
还需要注意的是,基于Form界面的五个WHEN触发器,不一定在所有的界面中都有,比如说个性化希望加在一些标准界面的查询界面,希望在点击查询按钮的时候对输入的数据经行校验,因为个性化不能加载在按钮上,所以我们想把数据的校验加载在when-validate-record上,但是查询界面并没有存储记录,更新记录,验证记录的要求,也不存在这个触发器。
5. 处理模式,也属于一个个性化执行条件,主要是指定个性化是否需要在查询状态下使用,或者仅在查询状态下使用。
6. 层,行业,地点,职责,用户,表示限制个性化的产生效果的范围,但是这里的效果并不像配置文件中的用户层设置覆盖职责层,职责层覆盖地点层,层级之间是相互覆盖和重写的的关系。而是或的关系,一条个性化规则只要符合其中一条层级限制,这个个性化规则就会产生作用。
7. 界面下端的两个按钮。“插入‘获取’表达式”,“插入项目值”是两个不错的按钮,通过这个按钮可以快速和准确的取得界面上对象的值。
插入‘获取’表达式按钮
${item.view_line_info_stub.ok_button.prompt_text}
ITEM:对象类型 ,有块(Block),窗口Windows
view_line_info_stub.ok_button 目标对象(数据块.数据项)
value:Property Name属性名称。 value 为值, Prompt_text为提示文本,还有高度,宽度,位置
这种方法可以替换在Form中使用的内置方法GET_ITEM_PROPERTY,GET_BLOCK_PROPERTY等
常见的类型:
窗口: ${window.} 块:${block.} 标签页: ${tab.} 画布: ${canvas.} 单选按钮: ${radio.}
视图: ${view.} 全局变量:${global.} 参数: ${parameter.} 值列表:${lov.} 局部变量: ${var.}
配置文件:${ps.} 消息:${ms.}
插入项目值按钮只获取item对象的值,得到的表达式是常见的
:数据库.数据项形式。例如 :OPERATING_UNITS.OPERATING_UNIT
1. 验证按钮:判断条件框中的条件是否成立。
2. 现在申请按钮:使设置的个性化规则立即生效,不用在重新打开和关闭Form界面,查看个性化规则是否起作用。
第二个界面主要是定义符合条件下执行的动作,总共有四种活动类型,每种类型下又有几种子类型,下面我们给出每一种类型的使用方法。
1.2 案列实现
1.2.1 活动类型是“特性”
这个活动类型,类似于我们在Form开发中按F4键打开对象的属性版,设置对象的属性。这些对象包括数据块,数据项,画布,窗口等,这个动作属性也可以用来定义全局变量,局部变量,参数等。
这里的局部变量:与全局变量的使用类似,但是只能在当前form使用,最大长度是4000 bytes,全局变量只有255 bytes,不能在Form的相互调用中使用。
选择这个动作类型的时候,会出现一个按文本选择的按钮,通过Form界面上的提示文本快速选择对象,这个按钮很有用,可以帮我们准确的找到对应的对象。
比如说我如果要修改一个ITEM的LOV的记录组,因为LOV,记录组的命名和字段不是一一对应的,我们仅仅通过帮助里面的诊断查看项不能准确的找到对应的 LOV名称,通过这个查询框,我们可以清楚地看到,那个对象对应那种类型的属性,从而获得属性名称。
案例1:修改定义并发程序的标准界面窗口的标题名:连接当前OU名称
触发器事件 | WHEN-NEW-FORM-INSTANCE |
类型 | 特性 |
对象类型 | 窗口 |
目标对象 | CONC_PROG |
特性名称 | Title |
值 | =‘并发程序‘||(select t.name from hr_operating_units t where t.organization_id =${ps.org_id.value}) |
赋值语句:${ps.org_id.value} 取的是当前配置文件中的默认业务实体的值,通过“插入‘获取’表达式按钮”获得
这里需要注意的是给对象的属性赋值的时候 “=”号的使用
不以“=”开头的值,在加载个性化的时候直接赋值给对象的属性
以“=”开头的值,可以在个性化加载的时候动态的执行内部的查询语句,替换绑定变量,全局变量等。常见的有
SQL 运算子:||,TO_CHAR,DECODE,和NVL
绑定变量值:(:Block.Field),:System,:Globle,:Parameter
Select 语句,但必须遵循以下条件:
需以? =SELECT?开头。
查询值结果必须为字符型的,且长度不超过2000个字节。
所查询的栏位的别名需给“A”(11.9以后的版本没有此限制)。
语句段的查询结果集不超过一行,若超过一行,只有第一行被使用。
案例2:打开接收事务处理界面,根据选择的库存组织设置界面上的业务实体字段的默认值为该库存组织对应的业务实体
根据平时Form开发的过程中使用到选择库存组织的案例可以知道,选择的库存组织ID是存储在Form的parameter参数里面的,下面的查询语句,可以使用这个参数作为绑定变量,动态的获取业务实体的值。
触发器事件 | WHEN-NEW-FORM-INSTANCE 设置两个Property类型的活动 | |
序号 | 10 | 11 |
类型 | Property | Property |
对象类型 | item | item |
目标对象 | FIND.OPERATING_UNIT | FIND.ORG_ID |
特性名称 | Value | Value |
值 | = SELECT hr.name FROM hr_operating_units hr, ORG_ORGANIZATION_DEFINITIONS ood WHERE hr.organization_id = ood.OPERATING_UNIT And ood.ORGANIZATION_ID = nvl(:PARAMETER.org_id,121) | = SELECT to_char(hr.organization_id) FROM hr_operating_units hr, ORG_ORGANIZATION_DEFINITIONS ood WHERE hr.organization_id = ood.OPERATING_UNIT and ood.ORGANIZATION_ID = nvl(:PARAMETER.org_id,121) |
在这里由于SQL语句只能返回字符串,这里需要把数字转换成字符串,原本是错误的做法,好在Oracle会自动转换数据类型。Item的初始化值(INITIAL_VALUE)只能在 WHEN-NEW-RECORD-INSTANCE触发器下设置
-INSTANCE 事件下进行改变设置
这里需要注意的是:如果Value的来源是通过select获取时,且是由多部分组合而成,其中的“select语句”这部分需要用()括起来
案例3:更改标准的定义并发请求界面的可执行名称不可更改
触发器事件 | WHEN-NEW-FORM-INSTANCE | ||
类型 | 特性 | 对象类型 | Item |
目标对象 | CONC_PROG.EXECUTABLE_NAME | 特性名称 | UPDATE_ALLOWED |
值 | False |
更改标准的可执行界面执行查询的时候只能查询出“客户化应用”的可执行结果
触发器事件 | WHEN-NEW-BLOCK-INSTANCE |
触发器对象 | FND_EXECUTABLES(也可以不填,其他的块没有这个触发器) |
执行模式 | 两者兼有(直接Ctrl+F11查询也要满足) |
类型 | Property |
目标对象 | FND_EXECUTABLES |
特性名称 | DEFAULT_WHERE |
值 | executable_id > 4and APPLICATION_NAME =‘Custom Application‘(红色部分为新增) |
这里需要注意的是:(1)触发器的选择 打开界面和按F11,或者直接按Ctrl+F11快捷键 进入查询状态都会触发 when-new-record-instance 触发器,因此这里也可以使用这个触发器。
(2)以前的教程里面介绍刚进入界面的时候通过“获取值”按钮来获取以前的default_where的值,再在其后加入我们需要限定的值,但是这个方法看不到上下文关联的字段。比如这里的通过该按钮只获取到executable_id> 4 而得不到与应用产品相关的字段。
直接加上:andexists(select1fromFND_EXECUTABLES_FORM_V t where t.APPLICATION_NAME=‘CustomApplication‘)
是不会对以前的where子句加上限制效果的,我们可以在不加个性化之前通过诊断-项目-块-last_query找到这个块的最后一次的查询语句。在此基础上增加我们的限制
1.2.2 活动类型是“菜单”
案例4:在Tools菜单下新增一个菜单项:“打开可执行”
触发器事件 | WHEN-NEW-FORM-INSTANCE(Special 的申明只能在when-new-form-instance 事件下进行) |
类型 | Menu |
菜单项 | SPECIAL15 |
菜单标签 | 打开可执行 |
编译菜单前的行 | 若勾选,在标签上方会出现一条直线以做区隔所用。一般special1,special16,special31 在菜单的最顶部不需要分割。 |
图标名称 | 图标名称可以使用我们自己的图片 路径放在 $COMMON_TOP/java/oracle/apps/media/ |
已在块中启用 | 指定菜单项在哪个Block 标签被激活。 |
需要注意的是这里除了可以选的45个SPECIAL菜单项,还可以选到15个MENU菜单项,这十五个菜单项是Form中原先已经有的,那么所创建的个性化规则将改写Form原有的菜单入口功能。
1.2.3 活动类型是“消息”
案例5:点击上一步我们创建的菜单项,如果可执行名称为空则提示错误消息
触发器事件 | SPECIAL15(上一步中我们自定义的菜单项,这个个性化的触发事件时我们点击这个菜单项的时候出发) |
条件 | ${item.conc_prog.executable_name.value} is null |
类型 | Message |
消息类型 | Error |
消息文本 | 请输入可执行文件名称 |
共有‘显示(Show)‘, ‘提示(Hint)‘, 警告(Warn), ‘错误(Error)‘, 和调试(Debug)。注意的是,若消息类型挑选了,Warn或 ‘Error‘, 当您按下按钮 Cancel 时,系统会执行RAISE_FORM_TRIGGER_FAILURE 这个Trigger ,将终止进一步的程序处理语句的执行。
1.2.4 活动类型是“内置”
案例6:内置类型是:“启动功能”,接上面的案例,如果可执行名称不为空,点击菜单项存储可执行名称并打开可执行界面
触发器事件 | SPECIAL15 | ||
序号 | 10 | 序号 | 11 |
类型 | Property | 类型 | Buildin |
对象类型 | 全局变量 | 内置类型 | 启动功能 |
目标对象 | G_EXEC_NAME | 功能代码 | FND_FNDCPMPE |
特性名称 | Value | 函数名 | 可执行并发程序 |
值 | =${item.conc_prog.executable_name.value} | 参数 |
|
案例7:内置类型是:“DO_KEY”,接上面的案例,打开可执行界面,如果上一步设置的全局变量名称不为空,则进入查询状态(相当于按F11),处于查询状态的时候再全局变量的值赋予“可执行的简称”,并执行查询(相当于按Ctrl+F11)
第一步打开可执行界面的时候,设置全局变量的初始值:INITIAL VALUE =NULL
触发器事件 | WHEN-NEW-FORM-INSTANCE |
类型 | 特性 |
对象类型 | 全局变量 |
目标对象 | G_EXEC_NAME |
特性名称 | INITIAL VALUE(全局变量有两个属性,Value和INITIAL VALUE,VALUE是直接赋值,而INITIAL VALUE为如果该变量为null或未被创建,会被赋初值,如果有值的话,则不会覆盖) |
值 | =Null(这个个性化的目的是为了直接打开该FORM时,不是通过点击我们个性化的菜单按钮打开这个界面,后面定义的用到此全局变量的个性化规则有效,因为如果直接打开这个界面,后面我们会去判断这个全局变量的值是否为空来执行查询,如果这个全局变量都不存在的话,个性化规则就出错了,打开这个界面就会报错) |
第二步判断全局变量的值是否为空,不为空则进入查询状态
触发器事件 | WHEN-NEW-FORM-INSTANCE |
条件 | :global.G_EXEC_NAME is not NULL |
类型 | 内置 |
内置类型 | DO_KEY |
变元 | ENTER_QUERY |
第三步在查询模式下,用全局变量的值作为查询条件,执行查询
触发器事件 | WHEN-NEW-RECORD-INSTANCE(上一步我们进入了查询界面,进入这个模式后就会执行新建记录触发器) | ||||
触发器对象 | FND_EXECUTABLES(新建记录所在的块名称) | ||||
序号 | 10 | 序号 | 11 | 序号 | 12 |
类型 | Property | 类型 | Property | 类型 | 内置 |
对象类型 | Item | 对象类型 | 全局变量 | 内置类型 | DO_KEY |
目标对象 | FND_EXECUTABLES.EXECUTABLE_NAME | 目标对象 | G_EXEC_NAME | 变元 | EXECUTE_QUERY |
特性名称 | VALUE | 特性名称 | VALUE |
| |
值 | = ${global.g_exec_name.value} | 值 | =NULL(使用完这个全局变量之后,把值置为空,为下一次使用) |
案例8:内置类型是:“raise_form_trigger_failure”,当保存并发程序的定义的时候,如果没有输入并发程序的说明,则提示错误信息,并阻止程序的经行
触发器事件 | WHEN-VALIDATE-RECORD | |||
触发器对象 | CONC_PROG | |||
条件 | ${item.conc_prog.description.value} is NULL | |||
序号 | 10 | 序号 | 11 | |
类型 | Message | 类型 | 内置 | |
消息类型 | Show | 内置类型 | RAISE_FORM_TRIGGER_FAILURE | |
消息文本 | 必须输入可执行的说明字段 |
| ||
案例9:内置类型是:“Create Record Group fromQuery”,标准销售订单界面中,限制销售订单类型LOV值列表的选择范围
触发器事件 | WHEN-NEW-ITEM-INSTANCE | |||||||||||
触发器对象 | ORDER.ORDER_TYPE | |||||||||||
层 | Responsibility | Value | HET INTER ORG(限制个性化加载在某个职责下) | |||||||||
序号 | 10 | 序号 | 11 | |||||||||
类型 | Builtin | 类型 | Property | |||||||||
Builtin Type | Create Record Group from Query | 对象类型 | LOV | Target Object | ORDER_TYPE | |||||||
Argument | select distinct OT.order_type_id, OT.name, OT.description from oe_order_types_v OT, oe_workflow_assignments OW, fnd_lookup_values_vl flv where trunc(sysdate) between trunc(OT.start_date_active) and nvl(trunc(OT.end_date_active), trunc(sysdate)) and trunc(sysdate) between trunc(OW.start_date_active) and nvl(trunc(OW.end_date_active), trunc(sysdate)) and OT.order_type_id = OW.order_type_id and process_name IS NOT NULL and line_type_id IS NULL and nvl(wf_item_type, ‘OEOH‘) = ‘OEOH‘ AND flv.enabled_flag = ‘Y‘ AND SYSDATE BETWEEN flv.start_date_active AND nvl(flv.end_date_active, SYSDATE) and flv.lookup_type = ‘XXOM_INTER_ORG_ORDER_TYPE‘ and upper(ot.name) = flv.LOOKUP_CODE and flv.TAG = NVL(:ORDER.OPERATING_UNIT, ‘HET_OU‘) order by name | |||||||||||
Group Name | XXOM_ORDER_TYPE | Property Name | GROUP_NAME | Value | XXOM_ORDER_TYPE | |||||||
在这里我们修改了标准销售订单界面上订单类型字段的LOV取值,一般的做法就是重新创建一个记录组,然后用这个记录组替换LOV以前的记录组。 我们需要注意的是新的记录组的返回字段的顺序和名称都应该和以前的记录组的一样,因为我们只改变了记录组,并没有重新设定LOV返回项,如果不能保持一致,会导致界面上有的记录不能从LOV选择中得到值,所以通常的做法就是先获取原来的LOV查询语句,再修改原来查询语句的 From子句和 where子句,不修改select子句。在PL/SQL Developer 中得到的LOV查询语句其中where子句中会有很多绑定变量,我们需要根据业务逻辑来确定绑定变量的值,做到尽量小的改动以前的LOV的记录组。
还有需要注意的是个性化开发中,我们不能对按钮添加个性化规则,如果有此类的需求一般都转换成加载在when-validate-record触发器上,如果校验的字段有LOV也可以通过限制LOV的取值来做到这一点。
案例9:内置类型是:“Forms_DDL”,客户化职责下的快速编码界面中, 当更新或者修改快速编码时,把快速编码的说明更新到快速编码类型的说明上。
触发器事件 | WHEN-VALIDATE-RECORD |
触发器对象 | FND_LOOKUP_VALUES |
类型 | Buildin |
内置类型 | Forms_DDL |
变元 | =‘Declare Begin update fnd_lookup_types_tl set description=‘‘‘||:FND_LOOKUP_VALUES.DESCRIPTION||‘‘‘ where lookup_type=‘‘‘||:FND_LOOKUP_TYPES.LOOKUP_TYPE||‘‘‘; Commit; End;‘ |
需要注意的是:Forms_DDL 的变元是字符串,如果字符串中有绑定变量需要用三个单引号和字符串连接符连接起来。 如果update,inset 语句内有手工输入的字符串,则需要使用双引号引用起来,数字类型的值不需要引号。
例如:=‘Declare
Begin Insert into student(stu_id,stu_name) values(1001,’’Smith’’);
Commit;
End;‘
Forms_DDL 执行的数据库定义语言,执行完成之后都需要显示的Commit
这里总结一下PL/SQL语言中的单引号和双引号的用法
单引号有两个作用:第一个作用就是字符串用单引号括起来,第二个作用是连续的单引号,第二个开始被看作转义字符。
输出一个单引号: select‘‘‘‘resultfrom dual –输出一个单引号
第一和第四两个单引号作为字符串的首尾单引号,第二单引号作为转义字符所起的作用的声明第三个单引号作为普通字符输出。
所以上面的insert 语句对于字符类型的字段,用了两个单引号括起来,一头一尾两个作为字符串标识,第二和第四个单引号转义第三和第五个单引号
最终执行的insert语句是:insert into student(stu_id,stu_name)values(1001,’smith’);
如果遇到字符串连接符:|| 又会出现另外一种情况
字符串连接符会分割两个字符串,也就是||符号左右两边的单引号没有任何关系
select‘‘‘||&l_var||‘‘‘resultfrom dual –输入2 输出 ‘||2||‘
左边第二个单引号转义第三个单引号得到一个单引号作为普通字符,从第一个单引号开始的字符串并没有结束,所以这里的字符串连接符并没有起到分割单引号的作用,而是被看成是普通的字符,但是内部的动态变量还是被解析了。
因此SQL会动态的解析字符串内部的绑定变量,如果我们的insert语句插入的number类型的值,直接写在字符串内就可以了,例如:’insert intostudent(stu_id,stu_name) values(:header.header_id,’smith’);’
select‘‘‘‘||&l_var||‘‘‘‘resultfrom dual –输入2 输出 ‘2‘
左边和右边四个单引号分别得到一个普通的单引号字符(仅包含一个单引号字符的字符串),连接中间的动态变量,得到的输出结果是一个被一对单引号括起来的字符串。
这样就符合上面的Update语句了,更新description字段赋给的值应该是由一对单引号括起来的里面的值
双引号的用法比较简单:
1. SQL语句中以中文作为别名时候需要用双引号括起来
select‘‘‘‘ "你好"from dual–输出一个单引号,列名是:你好
2.字符串中出现双引号只被当作普通字符来看
select‘hh24"小时""mi""分"""ss"秒"‘ resultsfrom dual; -- hh24"小时""mi""分"""ss"秒"
3. 当出现在to_char的格式字符串中时,双引号有特殊的作用, 就是将非法的格式符包装起来,避免出现ORA-01821: date format not recognized错误。也就是说,去掉双引号和其包含的字符后,剩下的应该是一个合法的格式串。
select to_char(sysdate,‘hh24"小时"mi"分"ss"秒"‘) results from dual;
-- 21小时39分37秒
案例10:内置类型是:“启动URL”,在定义并发程序界面的活动菜单下添加一个菜单项“打开CSDN博客”
规则1 | 创建打开CSDN博客菜单项 | 规则2 | 打开CSDN博客 |
触发器事件 | WHEN-NEW-FORM-INSTANCE | 触发器事件 | SPECIAL45 |
活动类型 | 菜单 | 活动类型 | Buildin |
菜单项 | SPECIAL45 | 内置类型 | 启动URL |
|
| 变元 | http://blog.csdn.net |
案例11:内置类型是:“启动 SRS 表单”,在定义并发请求界面的Actions下面加一个菜单项,提交我们客户化的采购入库单的并发请求。
第一步在定义并发请求的个性化下定义一个菜单项,点击该该菜单项提交我们执行的请求“CRC_B28_PO_采购入库单”
触发器事件 | WHEN-NEW-FORM-INSTANCE | |||||
类型 | 菜单 | 菜单项 | SPECIAL44 | 菜单标签 | 打印采购接收单据 | |
触发器事件 | SPECIAL44 | ||
序号 | 10 | 序号 | 11 |
类型 | Property | 类型 | Buildin |
对象类型 | 全局变量 | 内置类型 | 启动SRS表单 |
目标对象 | G_ALL_PARAMETER | 程序名 | CRC_B28_PO_采购入库单(客户化程序) |
特性名称 | Value(这里我们通过全局变量为提交请求界面的请求参数自动赋值,请求所需要参数之间用‘:‘冒号隔开,如果连续几个参数是空的话可以写在一起,例如‘:::::‘表示连续4个参数为空的,参数的顺序和个数必须与定义并发程序的时候一致) | ||
值 | SELECT ‘B28_BZCL0_常州包装‘ || ‘:::‘ || (select rsh.receipt_num from rcv_shipment_headers rsh, org_organization_definitions ood where ood.organization_id = rsh.ship_to_org_id and ood.operating_unit = 101 and rownum =1)||‘:‘|| ‘28010000623‘ || ‘:::::‘|| to_date(sysdate-365, ‘dd-mm-yyyy‘) ||‘:‘|| to_date(sysdate, ‘dd-mm-yyyy‘) FROM dual |
第二步在提交并发程序界面设置个性化,如果当前提交的请求是“CRC_B28_PO_采购入库单”且全局变量不为空,则给请求的参数自动赋值
触发器事件 | WHEN-NEW-ITEM-INSTANCE | ||
触发器对象 | WORK_ORDER.PARAMETERS | ||
条件 | ${item.work_order.concurrent_program_name.value} =‘CUX28PORCVRP1‘ and -- 这里是并发程序的简称 ${global.G_ALL_PARAMETER.value} is not null | ||
类型 | 特性 | 项目 | WORK_ORDER.PARAMETERS |
特性名称 | Value | ||
值 | =select nvl(${global.g_all_parameter.value}, ${item.work_order.parameters.value}) from dual |
案例12:内置类型是:“执行过程”,在定义并发请求界面的Actions下面加一个菜单项,提交报表的请求。
执行过程指的是执行数据库中一个包的procedure,function等,而不是Form的内置程序 set_item_property()等,在包中能实现的代码这里都能实现,只需要调用就可以了,调用数据库中的过程时可以使用当前界面的字段作为参数。这里不再重复。
2. 基于CUSTOM.PLL文件的个性化开发
一般的需求在Form界面上做个性化都能完成,如果在界面上不能完成,就考虑在CUSTOM.PLL文件中实现。凡是能在界面上实现的个性化效果都能够在CUSTOM.PLL文件中实现,反之不成立。界面上有很多的对象属性和内置程序都有,需要用到界面上没有的属性和内置程序就要在CUSTOM.PLL文件中实现。
2.1 通用开发步骤
(1) 将custom.pll另外复制一份,起名为xx模块名.pll。把xx模块名.pll加载到custom.pll下(用form builder打开custom.pll,在Attached Libraries里面加上xx模块名.pll)
(2) 在xx模块名.pll文件中新建一个接口包和包体:xx模块名_personalize,里面定义一个存储过程
procedure event(eventvarchar2); 接收传递过来的触发器事件
(3) 然后在custom.pll的event 里面调用每个模块名下的接口过程:
xx模块名_personalize.event(event_name);这样,我们的客户化代码都可以放在xx模块名.pll这个library 里面,降低了风险。
(4) 每次更改完xx模块名.pll文件之后,都要删除CUSTOM.PLL文件附加库中的这个xx模块名.pll这个附加库文件,再把最新的xx模块名.pll文件附加到CUSTOM.PLL文件的附加库里面。同时上传和编译CUSTOM.PLL文件和 xx模块名.pll文件这两个文件,而不是只需要编译CUSTOM.PLL文件。
(5) 编译的路径在:$AU_TOP/resource下
编译代码:
frmcmp_batchModule=$AU_TOP/resource/XXAP.pll Userid=apps/apps Module_Type=LIBRARYoutput_file=$AU_TOP/resource/XXAP.plx
frmcmp_batchModule=$AU_TOP/resource/CUSTOM.pll Userid=apps/apps Module_Type=LIBRARYoutput_file=$AU_TOP/resource/CUSTOM.plx
编译完成之后要重新登录EBS系统才能够看到效果。
(6) custom.pll文件中有两个function,一个procedure和四个常量如下:
function zoom_available return BOOLEAN;
function style(event_name varchar2) return integer;
procedure event(event_namevarchar2);
before constant integer := 1;
after constant integer := 2;
override constant integer := 3;
standard constant integer := 4;
第一个函数 zoom_available 很少使用,作用是可根据Form和块名称,激活EBS界面上菜单栏中的
“查看”菜单下的 “缩放(Zoom)”菜单项是否可用
例如当光标定位到采购订单头块上时候,激活Zoom菜单项,成功返回true,失败返回false
function zoom_availablereturnbooleanis form_name varchar2(30):= name_in(‘system.current_form‘); block_name varchar2(30):= name_in(‘system.cursor_block‘); begin if((form_name=‘POXPOEPO‘and block_name=‘PO_HEADERS‘)or (form_name=‘POXPOERL‘and block_name=‘PO_RELEASES‘))then returntrue; else returnfalse; endif; returnfalse; end zoom_available; |
第二个函数style 指定下面的存储过程event中的触发器事件码执行的方式,是先执行,后执行,还是覆盖。可选的有: custom.before、 custom.after、 custom.override、 custom.standard(默认值)
标准参考代码
function style(event_namevarchar2)returnintegeris begin if event_namein(‘SPECIAL10‘,‘SPECIAL11‘,‘SPECIAL12‘)then return custom.override; else return custom.standard; endif; end style; |
第三个存储过程Event才是我们最经常使用的,我们在这里捕获接收Form表单上触发事件,对触发的事件进行处理。我们在这个存储过程中,把每个触发器事件传递到新的PLL文件中做处理。如下图所示
这里我们能够捕获到的触发器事件中有:
ZOOM,WHEN-NEW-FORM-INSTANCE, WHEN-NEW-BLOCK-INSTANCE,WHEN-NEW-RECORDINSTANCE,WHEN-NEW-ITEM-INSTANCE,WHEN-VALIDATE-RECORD,自定义的菜单special1~special45
2.2案例实现
2.2.1 给标准的发运事务处理界面的查询块上的订单起始编号字段的LOV加上验证
由于这个字段的这个属性在界面上的个性化中并不能选到,而且DO_KEY中没有内置过程set_item_property,所以我们可以通过在库文件中动态的实现。
代码如下:
procedure event(eventvarchar2)is
form_name varchar2(30):= name_in(‘system.current_form‘); --当前Form名称 block_name varchar2(30):= name_in(‘system.cursor_block‘); --当前块名称 item_name varchar2(30):= name_in(‘system.CURRENT_ITEM‘); --当前项名称 -- 获取值只能用name_in() begin if fnd_global.resp_id=51281 --限定个性话在那个职责下才有效果 and form_name=‘WSHFSTRX‘ and block_name=‘QM_DLVB‘ and event_name=‘WHEN-NEW-ITEM-INSTANCE‘ --限定触发的时机 and item_name=‘DLVB_SOURCE_HEADER_NUMBER_LO‘ then app_item_property.set_property(‘QM_DLVB.DLVB_SOURCE_HEADER_NUMBER_LO‘, validate_from_list, property_true); -- 动态设置item的属性,LOV验证有效 endif; end event; |
2.2.2 自动填写AP发票头上的弹性域字段
在上面一个个性化中我们限制了个性化仅在一个职责下面有效,如果我们的个性化要新增职责或者是用户等,我们都要修改代码,修改后还要重新登录系统,不利于后期的维护。通常我们的做法是把职责和用户都维护在一个快码里面,这样的话后期做改动就比较方便了。我们这个个性化程序取值逻辑上有点繁琐,这里只把实现过程用到的一些方法做一些介绍。
PROCEDURE set_supplier_branch_number(p_event IN VARCHAR2) IS form_name VARCHAR2(30) := name_in(‘system.current_form‘); block_name VARCHAR2(30) := name_in(‘system.cursor_block‘); item_name varchar2(30) := name_in(‘system.current_item‘); l_supplier_branch_number VARCHAR2(100); l_approval_status VARCHAR2(100); BEGIN --AP header Invoices IF form_name = ‘APXINWKB‘ AND -- block_name = ‘INV_SUM_FOLDER‘ AND -- p_event = ‘WHEN-VALIDATE-RECORD‘ AND -- xxpo_personalization_util_pkg.ap_branch_enable_resp(fnd_global.resp_appl_id, fnd_global.resp_id) THEN -- 检测当前的职责是否在我们维护的快码之内,调用外部过程做处理,避免代码冗余 l_supplier_branch_number := name_in(‘INV_SUM_FOLDER.ATTRIBUTE13‘);
IF name_in(‘INV_SUM_FOLDER.INVOICE_ID‘) IS NOT NULL THEN -- 如果发票号存在,检测发票状态是否已经审批,调用的是标准的程序包接口 l_approval_status:= ap_invoices_pkg.get_approval_status( name_in(‘INV_SUM_FOLDER.INVOICE_ID‘), name_in(‘INV_SUM_FOLDER.INVOICE_AMOUNT‘), name_in(‘INV_SUM_FOLDER.PAYMENT_STATUS_FLAG‘), name_in(‘INV_SUM_FOLDER.INVOICE_TYPE_LOOKUP_CODE‘)); ELSE l_approval_status := ‘NEW‘; END IF;
IF name_in(‘INV_SUM_FOLDER.ORG_ID‘) = 84 AND -- l_supplier_branch_number IS NULL AND -- name_in(‘INV_SUM_FOLDER.QUICK_PO_HEADER_ID ‘) IS NOT NULL AND -- name_in(‘INV_SUM_FOLDER.POSTING_FLAG‘) NOT IN (‘Y‘) AND -- l_approval_status NOT IN (‘CANCELLED‘) THEN l_supplier_branch_number := xxpo_personalization_util_pkg.get_ap_branch_number( name_in(‘INV_SUM_FOLDER.QUICK_PO_HEADER_ID‘), NULL, name_in(‘INV_SUM_FOLDER.VENDOR_ID‘)); copy(l_supplier_branch_number, ‘INV_SUM_FOLDER.ATTRIBUTE13‘); -- 给目标弹性域段赋值,赋值只能用copy END IF; END IF; END set_supplier_branch_number;
验证当前职责是否满足条件的验证函数 function ap_branch_enable_resp(p_resp_appl_idinnumber, p_resp_id innumber)returnbooleanis l_return boolean; l_count number; begin l_count :=0; selectcount(1) into l_count from xxap_lookups xl, fnd_responsibility_vl frv where1=1 and xl.lookup_type=‘XXAP_BRANCH_PRSNLZ_RESP_ENABLE‘ --客户化快码 and xl.enabled_flag=‘Y‘ and trunc(sysdate)between nvl(xl.start_date_active, trunc(sysdate))and nvl(xl.end_date_active, trunc(sysdate)) and upper(frv.responsibility_name)= upper(xl.meaning) and frv.application_id= nvl(p_resp_appl_id, fnd_global.resp_appl_id) and frv.responsibility_id= nvl(p_resp_id, fnd_global.resp_id); if l_count>0then l_return:=true; else l_return:=false; endif; return l_return; exception whenothersthen returnfalse; end ap_branch_enable_resp; |
2.2.3 添加菜单项并为菜单项添加处理逻辑
在采购订单界面的Actions菜单下添加一个菜单项
procedure event(eventvarchar2)is
form_name varchar2(30):= name_in(‘system.current_form‘); block_name varchar2(30):= name_in(‘system.cursor_block‘); item_name varchar2(30):= name_in(‘system.CURRENT_ITEM‘); begin if form_name=‘POXPOEPO‘and block_name=‘PO_HEADERS‘and event =‘WHEN-NEW-FORM-INSTANCE‘then --添加菜单项 app_special2.instantiate(‘SPECIAL45‘, ‘Print Purchase Order &Again‘, ‘‘, true, ‘LINE‘); app_special2.enable(‘SPECIAL15‘,PROPERTY_ON); --设置菜单项可用 endif; -- 为菜单事件添加逻辑 if(event_name=‘SPECIAL45‘)then if(form_name=‘POXPOEPO‘and block_name=‘PO_HEADERS‘)then /* Add your Print Order logic here */ raise form_trigger_failure; endif; endif; -- 带复选框的菜单 if(event_name=‘WHEN-NEW-FORM-INSTANCE‘)then
--带复选框菜单 app_special2.instantiate(‘SPECIAL4_CHECKBOX‘, ‘TEST_CHECKBOX‘, ‘‘, true, ‘LINE‘); --设置复选框勾选 app_special2.set_checkbox(‘SPECIAL4_CHECKBOX‘,‘TRUE‘); --获取复选框状态 if app_special.get_checkbox(‘SPECIAL4_CHECKBOX‘)=‘TRUE‘then fnd_message.debug(‘Special 4 is True!‘); else fnd_message.debug(‘Special 4 is False!‘); endif; endif;
end event; |
|
app_special2.instantiate()过程的参数说明
第一个参数option_name:
将SPECIAL1传送到SPECIAL45,以指示您想放置功能的特殊菜单上的插槽。SPECIAL1位于三个特殊菜单中的第一个的顶部,SPECIAL15位于第一个特殊菜单的底部。 SPECIAL16位于三个特殊菜单中第二个的顶部,SPECIAL30位于第二个特殊菜单的底部。 SPECIAL31位于三个特殊菜单的第三个的顶部,SPECIAL45位于第三个特殊菜单的底部。当实例化任何菜单条目时,将启用相应特殊菜单的顶级菜单。
复选框仅在第一个特殊菜单上可用(Tools菜单)。复选框条目提供包含复选框的菜单条目。将SPECIAL1_CHECKBOX传递到SPECIAL15_CHECKBOX(而不是相应的SPECIALn条目),以指示要放置功能的特殊菜单上的插槽。如果使用复选框条目,还必须使用APP_SPECIAL.SET_CHECKBOX例程来为相应的菜单条目设置复选框的初始值。
传递SPECIAL,SPECIAL_B或SPECIAL_C以显式控制三个顶级特殊菜单之一。 SPECIAL位于三个特殊菜单中的第一个的顶部,SPECIAL_B位于第二个特殊菜单的顶部,SPECIAL_C位于第三个特殊菜单的顶部。这通常用于显式地启用或禁用顶级条目。
第二个参数:hint
您的菜单项标签。传递翻译后的字符串(如果要翻译表单,应在消息字典中定义消息,先检索消息,然后将检索到的消息字符串传递给APP_SPECIAL)。在字符串中包含一个“&”,以定义哪个字符成为该项的快捷键(这与Oracle Forms Form Builder中的行为相同,例如,‘&Book Orders‘,这时候字符“B”就是快捷键)。 您可以更改SPECIAL_B(报告)或SPECIAL_C(操作)的标签,但不能更改SPECIAL菜单(工具)的标签。此外,您不能为SPECIAL_B或SPECIAL_C指定访问密钥。
第三个参数icon(图标)
如果要在功能的工具栏上包含图标按钮,请指定图标的名称。
第四个参数:initially_enabled
一个布尔值,用于设置菜单项的初始状态。如果您不想在应用程序启动时启用该项目,请传递FALSE。 默认值为TRUE。
第五个参数:separator
通过“LINE”在菜单条目上方显示菜单分隔符行。对于SPECIAL1(_CHECKBOX),SPECIAL16或SPECIAL31,将忽略LINE参数。 默认是没有行。
Oracle EBS Form个性化开发