【ERP】如何在多行数据块中实现仅能勾选唯一的主联系人

功能背景

本篇所描述的功能是基于Oracle E-Businees Suite 11i 版应收模块的客户标准界面下的联系方式输入功能。有过该界面操作经历的同学应该知道,上面的主联系人标记在任何情况下只能选择唯一的一个。在实际的客户化开发中,该功能有时也是格外的有用。因此本人从标准客户界面上抽取出该功能,并作了一些格外的功能限制。

  

功能实现

前提

我们在FORM中有一个显示多行的数据块CONTACT,数据源为一张联系人表,暂且取名为ZZ_CONTACTS吧。该表除了拥有标记主联系人的字段PRIMARY_FLAG外,还包含其他一些信息,但本例中不太重要,故略之。

数据块: CONTACT

数据表: ZZ_CONTACTS

CREATE TABLE ZZ_CONTACTS (
CONTACT_ID
NUMBER NOT NULL.
PRIMARY_FLAG
VARCHAR2(1),
-- 其他联系人信息
CONTACT_NAME VARCHAR2(30),
EMAIL
VARCHAR2(30)
-- ... ...
);

实现

1. 为数据块CONTACT的PRIMARY_FLAG项添加触发器WHEN-CHECKBOX-CHANGED, 代码如下:

--
--
当用户勾选了主联系人标记时,进行检查
--
IF :CONTACT.PRIMARY_FLAG = 'Y' THEN
-- 执行检查
CONTACT_UTL.VALIDATE_PRIMARY_FLAG;
END IF;

2. 在Form中创建程序包CONTACT_UTL来验证“界面显示部分”的主联系人的唯一性,代码如下:

程序包声明部分:

PACKAGE CONTACT_UTL IS
PROCEDURE validate_primary_flag;
END;

程序主体部分:

PACKAGE BODY CONTACT_UTL IS
PROCEDURE validate_primary_flag IS
v_cur_blk
varchar2(30) := name_in('system.cursor_block');
v_cur_rec
number := name_in('system.cursor_record');
v_primary_flag
varchar2(1);
b_validate_passed boolean :
= TRUE;
BEGIN
--
-- 备份当前主联系人标识
--
v_primary_flag := name_in(v_cur_blk || '.primary_flag');

-- 反选当前主标识,若之后的验证通过,再将其还原
IF v_primary_flag = 'Y' THEN
Copy(
'N', v_cur_blk || '.primary_flag');
END IF;

-- 若当前记录仍有必输项未填写,则跳过验证,转向该ITEM
IF app_record.get_status(v_cur_blk) IN ('INSERT', 'CHANGED')
THEN
IF NAME_IN(v_cur_blk || '.EMAIL') IS NULL THEN
GO_ITEM(v_cur_blk
|| '.EMAIL');
RETURN;
END IF;
-- 更多验证...
END IF;

--
-- 循环界面上的记录,如果之前已经有主联系人标记
-- 则打上验证失败标记
--
FIRST_RECORD;
LOOP

IF v_primary_flag = name_in(v_cur_blk || '.primary_flag') AND
v_cur_rec
!= :system.cursor_record
THEN
b_validate_passed :
= FALSE;
EXIT;
ELSE
IF :system.last_record = 'TRUE' THEN
EXIT;
ELSE
NEXT_RECORD;
END IF;
END IF;

END LOOP;

-- 回复原始光标位置
GO_RECORD(v_cur_rec);
GO_ITEM(v_cur_blk
|| '.primary_flag');

-- 如果验证失败,报错,否则,回复其选中时的值
IF NOT b_validate_passed THEN
fnd_message.debug(
'Validate failed!');
RAISE form_trigger_failure;
ELSE
Copy(
'Y', v_cur_blk || '.primary_flag');
END IF;
END;
END;

3. 最后,在向插入到数据库里之前,我们还要做一次数据库层面的验证,因为并不是所有的记录都显示在了form界面上,在这里,我采取的策略是以用户界面上最后验证通过的主联系人为主,其他的在数据表中并且未显示出来的主联系人记录则将其设为非主联系人。为此,我们要在数据块CONTACT的ON-INSERT触发器中添加如下代码:

-- CODE for ON-INSERT/ON-UPDATE trigger

-- 代码...
BEGIN
IF :CONTACT.PRIMARY_FLAG = 'Y' THEN
UPDATE ZZ_CONTACTS
SET PRIMARY_FLAG = 'N'
WHERE PRIMARY_FLAG = 'Y'
AND ( CONTACT_ID IS NULL OR CONTACT_ID != :CONTACT.CONTACT_ID )
;
END IF;
END;

-- INSERT/UPDATE实现代码...

  

已知问题

在主从块设计中,该解决方案不能应用到主块上,明细块可以,主块在loop 记录的时候会引发GET_RELATION_PROPERTY非法调用的错误。目前还有找到什么解决方法,欢迎交流!

  

示例代码仅供参考,请根据实际需要进行修改:)

Enjoy!



posted @ 2011-07-17 12:00  eliuhy  阅读(1701)  评论(1编辑  收藏  举报