前言
由于太了解自己的重度拖延症,那是不火烧眉毛(主要是担心毁容)就置之脑后了,所以我先对好友把牛吹下了,说我必将花费两周心血研究的HCM权限控制成果写成博客,所以立字为据,如我这般玉树临风、风流倜傥、才高八斗、信守诺言之人,那必定得言出必行。
导言
HCM权限控制有三部分配置,一个是角色配置,另一个是结构化授权配置,另外还有个授权主开关配置。
结构化授权配置是HCM的特殊产物,因为HCM有组织层级,即评估路径O-S-P,组织下有岗位,岗位下有人员,夫妻肺片里没有夫妻,蚂蚁上树里没有蚂蚁,日料店里没有日料。
正文
一、配置点
1、 角色配置
角色配置使用Tcode PFCG,常用权限对象如下:
权限对象 | 作用 | 示例 |
---|---|---|
PLOG | 校验人员计划的权限 | PLVAR: * OTYPE: C,O,P,S,T,US INFOTYP: 1000,1001 SUBTYP: * ISTAT: * PPFCODE: DISP,LISD |
P_ABAP | 简化指定程序的权限检查 | REPID: HCNCALC0 |
P_ORGIN | 校验人员信息类型的权限 | INFTY: 0000-9051 SUBTY :* AUTHC: M,R PERSA: 9005 PERSG: * PERSK: * VDSK1: * |
P_PCLX | 校验PCLx( x =1、 2、 3、4 ) 簇的权限 | RELID: * AUTHC:* |
P_PCR | 校验工资核算范围的权限 | ABRKS:MS ACTVT:* |
P_PERNR | 校验人员编号权限 | AUTHC:* PSIGN: * INFTY: * SUBTY:* |
2、 结构化授权配置
① 创建权限参数文件,使用Tcode OOSP,示例如下:
其中期间的选项释义如下:
选项 | 描述 | 期间 |
---|---|---|
(空) | 全部 | 19000101—99991231 |
D | 关键日期 | 系统当前日期 |
M | 当前月 | 系统当前日期所在月初—系统当前日期所在月末 |
Y | 当前年 | 系统当前日期所在年初—系统当前日期所在年末 |
P | 过期 | 19000101—系统当前日期 |
F | 未来 | 系统当前日期—99991231 |
② 创建权限参数文件,使用Tcode OOSB,示例如下:
3、 授权主开关配置
授权主开关配置使用Tcode OOAC,示例如下:
其中常用配置释义如下:
语义缩写 | 描述 | 作用 |
---|---|---|
ADAYS | HR:权限检查的时间容差 | 设置一个天数,默认是15,权限调整后这个天数内依然保留权限 |
ORGIN | HR: 主数据 | 是否检查权限对象P_ORGIN |
ORGPD | HR:结构权限检查 | 是否启用结构化授权检查 |
ORGXX | HR:主数据 - 扩展的检查 | 是否检查权限对象P_ORGXX |
PERNR | HR:主数据 - 个人号检查 | 是否检查权限对象P_PERNR |
二、问题点
1、结构化授权无法校验权限有效期间。
此项目有许多人事报表需求,选择屏幕输入期间和组织,即可查询该期间内的组织下所有人员。选择屏幕组织搜索帮助调用函数 HR_COMBINED_SELECTION 或 RH_TYPE_STRUC_HELP,查询调用函数 RH_STRUC_GET,评估路径使用 O-S-P,测试过程中遇到问题点列举如下:
① 问题描述:
直接下级组织调动,该组织还有下级组织,组织 50021443是根组织 10005200的直接下级组织,2021/04/01调入其他组织,其还有下级组织 50021444,但仅直接下级组织在权限视图里的有效期间更新了,再下级组织的有效期间未更新,如下图所示。
此时报表输入期间2021/04/01及之后的日期,组织搜索帮助由于下下级组织 50021444在选择屏幕期间内无法找到直接上级组织,所以认为该组织也是根组织,这样就会出现多个根组织并列的情况,如下图所示。
解决方法:
在函数 RH_TYPE_STRUC_INDEX 结束处增加隐式增强,判断根节点的上级组织权限是否被截止。
ENHANCEMENT 1 YENH_RH_TYPE_STRUC_INDEX. "active version
* 由于组织调整,结构化授权视图里只有调整组织有截止日期,下级组织截止日期依然是99991231,
* 这样导致下级组织会显示为单独一个根节点,所以增加一层权限校验,判断上级组织是否权限被截止
DATA: lt_view TYPE STANDARD TABLE OF hrview,
lv_tabix TYPE sy-tabix,
lv_auth TYPE char1.
IF sy-tcode = 'YXHR064' OR SY-CPROG = 'YXHRR064'.
IF root_object_index[] IS NOT INITIAL.
SELECT objid, sclas, sobid
FROM hrp1001
INTO TABLE @data(lt_uporg)
FOR ALL ENTRIES IN @root_object_index
WHERE plvar = @root_object_index-plvar
AND otype = @root_object_index-otype
AND objid = @root_object_index-objid
AND rsign = 'A'
AND relat = '002'
AND istat = '1'
AND begda LE @act_endda
AND endda GE @act_begda.
ENDIF.
PERFORM fill_view(saplrhac) USING act_plvar sy-uname.
IMPORT view = lt_view FROM MEMORY ID '$PD__VIEW__IN__MEM$'.
SORT lt_view BY plvar otype objid begda.
LOOP AT root_object_index.
CLEAR lv_auth.
LOOP AT lt_uporg INTO DATA(ls_uporg) WHERE objid = root_object_index-objid.
READ TABLE lt_view TRANSPORTING NO FIELDS
WITH KEY plvar = act_plvar
otype = ls_uporg-sclas
objid = '00000000' BINARY SEARCH.
IF sy-subrc = 0.
lv_auth = 'X'.
EXIT.
ELSE.
READ TABLE lt_view TRANSPORTING NO FIELDS
WITH KEY plvar = act_plvar
otype = ls_uporg-sclas
objid = ls_uporg-sobid BINARY SEARCH.
IF sy-subrc <> 0.
lv_auth = 'X'.
EXIT.
ELSE.
lv_tabix = sy-tabix.
LOOP AT lt_view INTO DATA(ls_view) FROM lv_tabix.
IF ls_view-plvar <> act_plvar
OR ls_view-otype <> ls_uporg-sclas
OR ls_view-objid <> ls_uporg-sobid.
EXIT.
ENDIF.
IF ls_view-begda <= act_endda AND ls_view-endda >= act_begda.
lv_auth = 'X'.
EXIT.
ENDIF.
ENDLOOP.
ENDIF.
ENDIF.
ENDLOOP.
IF sy-subrc = 0 AND lv_auth IS INITIAL.
DELETE TABLE root_object_index.
ENDIF.
ENDLOOP.
ENDIF.
ENDENHANCEMENT.
② 问题描述:
直接下级组织调动,组织 10005201是根组织 10005200的直接下级组织,2023/05/11调入其他组织,权限有效期间已更新,如下图所示。
但SAP标准校验结构化授权对象使用函数RH_STRU_AUTHORITY_CHECK,此函数仅检查权限视图是否包含检查对象,但并不校验期间。
所以当报表输入查询期间2023/05/11及之后的日期,组织输入10005201,依然有权限查看数据。
解决方法:
在函数 RH_STRUC_GET 的结束处增加隐式增强,增加一重校验,检查查询组织的权限期间。
ENHANCEMENT 1 YENH_RH_STRUC_GET. "active version
* 1. 标准组织权限检查不包含期间,即之前有权限的组织则一直有权限,
* 所以组织调动后还能查询该组织信息,因此校验结构化授权再加一重期间校验
* 2. 由于组织调整,结构化授权视图里只有调整组织有截止日期,下级组织截止日期依然是99991231,
* 这样导致下级组织依然有权限,所以增加一层权限校验,判断上级组织是否权限被截止
* 3. 由于根组织与上级组织上下级关系发生变化,互为上下级组织,上级组织截止日期不再是99991231,
* 此处查询会导致无数据,所以如果查询组织是根组织则不用校验
DATA: lt_view TYPE STANDARD TABLE OF hrview,
lt_struc TYPE STANDARD TABLE OF struc,
lv_objid TYPE t77pr-objid,
lv_tabix TYPE sy-tabix,
lv_auth TYPE char1.
IF authority_check = 'X' AND 'O-S-P' CS act_otype.
* 由于根组织与上级组织上下级关系发生变化,互为上下级组织,
* 此处查询会导致无数据,所以如果查询组织是根组织则不用校验
SELECT SINGLE t77pr~objid
INTO @lv_objid
FROM t77ua
INNER JOIN t77pr
ON t77ua~profl = t77pr~profl
WHERE t77ua~uname = @sy-uname
AND t77pr~plvar = @act_plvar
AND t77pr~otype = @act_otype
AND t77pr~objid = @act_objid.
IF sy-subrc <> 0.
PERFORM fill_view(saplrhac) USING act_plvar sy-uname.
IMPORT view = lt_view FROM MEMORY ID '$PD__VIEW__IN__MEM$'.
SORT lt_view BY plvar otype objid begda.
READ TABLE lt_view TRANSPORTING NO FIELDS
WITH KEY plvar = act_plvar
otype = act_otype
objid = '00000000' BINARY SEARCH.
IF sy-subrc <> 0.
* 检查查询组织是否权限被截止
READ TABLE lt_view TRANSPORTING NO FIELDS
WITH KEY plvar = act_plvar
otype = act_otype
objid = act_objid BINARY SEARCH.
IF sy-subrc = 0.
lv_tabix = sy-tabix.
LOOP AT lt_view INTO DATA(ls_view) FROM lv_tabix.
IF ls_view-plvar <> act_plvar
OR ls_view-otype <> act_otype
OR ls_view-objid <> act_objid.
EXIT.
ENDIF.
IF ls_view-begda <= act_endda AND ls_view-endda >= act_begda.
lv_auth = 'X'.
EXIT.
ENDIF.
ENDLOOP.
ENDIF.
IF lv_auth IS INITIAL.
REFRESH: result_tab, result_objec, result_struc.
MESSAGE e170(5w) WITH act_plvar act_otype
act_objid act_wegid
RAISING no_entry_found.
ENDIF.
* 检查上级组织是否权限被截止
IF act_wegid CS 'O-S-P' AND act_otype = 'O'.
CALL FUNCTION 'RH_STRUC_GET'
EXPORTING
act_otype = act_otype
act_objid = act_objid
act_wegid = 'O-O'
act_plvar = act_plvar
act_begda = act_begda
act_endda = act_endda
authority_check = ''
TABLES
result_struc = lt_struc
EXCEPTIONS
no_plvar_found = 1
no_entry_found = 2
OTHERS = 3.
IF sy-subrc = 0.
LOOP AT lt_struc INTO DATA(ls_struc) FROM 2.
* 检查是否有权限被截止的上级组织
READ TABLE lt_view INTO ls_view
WITH KEY plvar = act_plvar
otype = ls_struc-otype
objid = ls_struc-objid BINARY SEARCH.
IF sy-subrc = 0.
IF ls_view-begda > act_endda OR ls_view-endda < act_begda.
CLEAR lv_auth.
* 检查同级别期间是否有有权限的组织
LOOP AT lt_struc INTO DATA(ls_struc_level) WHERE level = ls_struc-level.
READ TABLE lt_view TRANSPORTING NO FIELDS
WITH KEY plvar = act_plvar
otype = ls_struc_level-otype
objid = ls_struc_level-objid BINARY SEARCH.
IF sy-subrc = 0.
lv_tabix = sy-tabix.
LOOP AT lt_view INTO ls_view FROM lv_tabix.
IF ls_view-plvar <> act_plvar
OR ls_view-otype <> ls_struc_level-otype
OR ls_view-objid <> ls_struc_level-objid.
EXIT.
ENDIF.
IF ls_view-begda <= act_endda AND ls_view-endda >= act_begda.
lv_auth = 'X'.
EXIT.
ENDIF.
ENDLOOP.
ENDIF.
IF lv_auth = 'X'.
EXIT.
ENDIF.
ENDLOOP.
IF lv_auth IS INITIAL.
REFRESH: result_tab, result_objec, result_struc.
MESSAGE e170(5w) WITH act_plvar act_otype
act_objid act_wegid
RAISING no_entry_found.
ENDIF.
ENDIF.
ENDIF.
ENDLOOP.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
ENDENHANCEMENT.
2、工资核算结果报表无法区分人事专员和薪酬专员权限。
问题描述:
譬如某家公司的人事专员和薪酬专员皆有该公司人事范围的权限,那使用逻辑数据库PNP 选择屏幕900 或者函数 PYXX_READ_PAYROLL_RESULT 读取工资核算结果皆可查看数据。
这是由于SAP标准查看工资核算结果Tcode PC_PAYRESULT校验了人员基本工资0008信息类型的权限,校验期间先用系统当前日期,如若系统当前日期没有权限则再校验工资核算结果最新历经结束日期的权限,如若都无权限则不可查看。而逻辑数据库PNP 和函数 PYXX_READ_PAYROLL_RESULT无该校验。
解决方法:
由于逻辑数据库PNP 查询工资核算结果底层也是调用的函数 PYXX_READ_PAYROLL_RESULT,所以在函数 PYXX_READ_PAYROLL_RESULT 结束处增加隐式增强,增加一重校验,检查人员基本工资0008信息类型的权限。
ENHANCEMENT 1 YENH_PYXX_READ_PAYROLL_RESULT. "active version
* 参照Tcode PC_PAYRESULT(程序CONSTRUCTOR (CL_HR_LSTCE_EMPLOYEE))增加人员0008信息类型检查
* check read-authority for infotype 0008
IF check_read_authority = 'X'.
CALL FUNCTION 'HR_CHECK_AUTHORITY_INFTY'
EXPORTING
tclas = 'A'
pernr = employeenumber
infty = '0008'
subty = ''
begda = sy-datum
endda = sy-datum
level = 'R'
EXCEPTIONS
no_authorization = 1.
IF sy-subrc <> 0.
ASSIGN COMPONENT 'INTER' OF STRUCTURE payroll_result
TO FIELD-SYMBOL(<ls_inter>).
IF sy-subrc = 0.
ASSIGN COMPONENT 'VERSC' OF STRUCTURE <ls_inter>
TO FIELD-SYMBOL(<lv_versc>).
IF sy-subrc = 0.
ASSIGN COMPONENT 'FPEND' OF STRUCTURE <lv_versc>
TO FIELD-SYMBOL(<lv_fpend>).
IF sy-subrc = 0.
DATA(lv_fpend) = conv datum( <lv_fpend> ).
* second chance: check with payroll_until
CALL FUNCTION 'HR_CHECK_AUTHORITY_INFTY'
EXPORTING
tclas = 'A'
pernr = employeenumber
infty = '0008'
subty = ''
begda = lv_fpend
endda = lv_fpend
level = 'R'
EXCEPTIONS
no_authorization = 1.
IF sy-subrc <> 0.
CLEAR payroll_result.
MESSAGE i018 WITH clusterid
RAISING no_read_authority.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
ENDENHANCEMENT.