在SAP
HCM实施项目中,在某些特殊的情况下,SAP提供的标准函数(Function)和操作(Operation)无法满足客户的特定需求,顾问可能需要增强开发客户自定义的函数和操作,虽然以我的项目经验来看,虽然这是极少发生的事例,但也不是不可能发生。
本文以工资计算函数和操作为例,介绍开发用户自定义函数和操作的步骤和注意事项。
一、定义步骤
步骤一:运行TCODE
PE04,输入自定义函数或者操作的名字,然后选择对象类别(工资计算用或者考勤核算用)和对象类型(函数或者操作),点击创建(Create)按钮后进入下一屏幕。
步骤二:选择对应的FORM子例程名字,建议使用系统默认生成的标准名字,也可以使用自定义的FORM子例程名字,然后选择使用该函数或者操作的国家分组,如果是考勤核算使用的函数或者操作,选择所有国家分组,然后选择参数格式、参数和参数值,最后保存并激活定义的函数或者操作;
步骤三:使用TCODE SE38 显示程序 HCNCALC0,
找到Include
程序PCBURZCN0,这个Include是SAP预留给客户写自己定义的函数和操作代码的地方,但也需要修改对象的Access
Key,Access Key可以通过SAP的客户支持平台申请;
步骤四:
在程序PCBURZCN0中的紧急修改模式下,定义Operation或者Function对应的FORM,FORM的名字为:如果是函数,在Function的名字前加前缀FU,如果是操作,在Operation的名字前加前缀OP。这时候可以先不写任何的实现代码,保存后激活程序PCBURZCN0。
步骤五:使用工具程序RPUCT700或者RPUCT300生成包含自定义函数和操作的 Turbo
Case过程选择Include程序PCBO1CN0和PCOIPCN0等,RPUCT700也是调用的RPUCT300,两个程序无本质区别,均可以使用;在输出日志里或者生成的PCOIPCN0可以看到自己的定义的函数或者操作包括在Turbo
Case中,才算生成成功。
步骤六:再次使用TCODE
PE04编辑自定义的Function或者Operation,点击源代码按钮,这时候系统自动跳转到 程序PCBURZCN0中
对应的子例程FORM,这时候就可以写FORM子例程的代码逻辑了。
二、注意事项: 
1)一般情况,尽量使用标准的函数和操作及参数组合以满足客户的需求,不到万不得已不建议自己开发客户自己定义的函数和操作。
2)在自己写的代码中尽量不要修改工资核算程序使用的标准内表如WPBP、APER等,也不要改变其中记录的顺序,除非自己有充分的把握。如果确实需要对标准内表做排序或者临时修改其内容,可以先存在一个局部内表中,在结束函数或者操作的代码的时候恢复系统标准的内表。
3)对IT表和VAR表可以增加新的记录,但一般不要删除表中已经存在的记录。
4)客户自定义的函数和操作的命名要遵从SAP预留给客户的命名空间,不要使用SAP标准函数和操作对象的命名范围。使用工具程序RDDKOR54可以查询SAP预留给客户自定义函数和操作对象的命名空间,输入表名为T52A0,可以的命名空间如下图所示。
5)
用于考勤核算的客户自定义的函数和操作的代码存放在哪个INCLUDE,尚不清楚,SAP有没有预留INCLUDE需要进一步确认。
三、例子代码
 
    需要定义一个OPERATION,用于读取和汇总员工2017年1-7月和工人2017年1-8月的奖金计提额(工资项1090),然后存放在VAR表的变量2018中备用。下面是一个计算和往
VAR中插入变量的程序例子,该变量可以在该操作被调用后使用 。
1) 在工资计算规则中调用自定义的OPERATION
-------------+---------+---------+---------+---------+---------+---------+
     
     D CMPER
JJ18   "YEAR 2018
<     
     
ERROR
=     
    D AMT?0
= *
= >     
    ADDWT * 
 ADDWT 4010_1090 
   AMT=& 2018SUBWT 4010NEXTR
A
= >     
A   AMT=L 4009SUBWT 4010SUBWT
4009
>     
    D AMT?0
> *
> >   
      ADDWT
*   ADDWT 4010AMT=L 4009SUBWT
4010SUBWT 4009
 
其中
_1090就是自定义的Operation,它完成读取员工2017年1到7月或者8月的工资项1090,累加后存放在变量表VAR中的变量2018的AMT字段,供后面的Operation
AMT使用. 
2)程序代码
*----------------------------------------------------------------------*
*   INCLUDE PCBURZCN0                                                  *
*   Customer functions and operations                                  *
*   Use this include to create customer                                *
*   specific functions and operations                                  *
*   Attention: Never change or transport this include in SAP systems   *
*----------------------------------------------------------------------*
*{   INSERT         DEVK905020                                        1
form op_1090.
  data: gt_rgdir type table of pc261,
        gs_rgdir type pc261,
      gt_rgdir_final type table of pc261,
      gv_relid type relid_pcl,
      gv_molga type molga,
      gv_type  type t52relid-typename,
      gv_id type i,
      ref_payresult type ref to data,
      gs_wpbp type pc205,
      gs_rt type pc207,
      gv_date_begin like sy-datum,
      gv_date_end like sy-datum,
      gv_yifa type i.
  data: l_1090 type pc207-betrg.
     field-symbols:  type any,
 
     
     
   
  type hrpay99_rt.
  refresh gt_rgdir.
  call function 'CU_READ_RGDIR'
    exporting
      persnr          = pernr-pernr
    tables
      in_rgdir        = gt_rgdir
    exceptions
      no_record_found = 1
      others          = 2.
  if sy-subrc = 0.
    clear: gv_relid,gv_molga.
    call function 'PYXX_GET_RELID_FROM_PERNR'
      exporting
        employee                    = pernr-pernr
      importing
        relid                       = gv_relid
        molga                       = gv_molga
      exceptions
        error_reading_infotype_0001 = 1
        error_reading_molga         = 2
        error_reading_relid         = 3
        others                      = 4.
    if sy-subrc = 0.
      select single typename
               from t52relid
               into gv_type
              where relid eq gv_relid
                and tabname = 'PCL2'.
      if sy-subrc ne 0.
        gv_relid = 'CN'.
        gv_type = 'PAYCN_RESULT'.
      endif.
      create data ref_payresult type (gv_type).
      assign ref_payresult->* to .
    endif.
  endif.
  delete gt_rgdir where srtza ne 'A'.
  refresh gt_rgdir_final.
  clear gs_rgdir.
  read table p0001 index 1.
  if p0001-abkrs = 'A1'.
“办公室员工
  gv_date_begin = '20170101'.
  gv_date_end = '20170731'.
  else. 
     
     
     
     
 “现场工人
  gv_date_begin = '20170101'.
  gv_date_end = '20170831'.
  endif.
  loop at gt_rgdir into gs_rgdir where payty = ''
                                 and fpbeg ge gv_date_begin
                                 and fpend le gv_date_end.
    append gs_rgdir to gt_rgdir_final.
    clear gs_rgdir.
  endloop.
  sort gt_rgdir_final by seqnr.
  clear gs_rgdir.
  loop at gt_rgdir_final into gs_rgdir.
    call function 'PYXX_READ_PAYROLL_RESULT'
      exporting
        clusterid                    = gv_relid
        employeenumber               = pernr-pernr
        sequencenumber               = gs_rgdir-seqnr
      changing
        payroll_result               = 
      exceptions
        illegal_isocode_or_clusterid = 1
        error_generating_import      = 2
        import_mismatch_error        = 3
        subpool_dir_full             = 4
        no_read_authority            = 5
        no_record_found              = 6
        versions_do_not_match        = 7
        error_reading_archive        = 8
        error_reading_relid          = 9
        others                       = 10.
    if sy-subrc eq 0.
      assign component 'INTER-RT' of structure  to .
 
 
  if gs_rgdir-abkrs = 'A1'.
      loop at  into gs_rt.
        case gs_rt-lgart.
          when '1090'.
            l_1090 = l_1090 + gs_rt-betrg.
            exit.
          when others.
            continue.
        endcase.
        clear gs_rt.
      endloop.
      elseif ( gs_rgdir-abkrs = 'A2' or gs_rgdir-abkrs = 'A3' ).
      loop at  into gs_rt.
        case gs_rt-lgart.
          when '1000'.
            l_1090 = l_1090 + gs_rt-betrg * 150 / 1200 .
            exit.
          when others.
            continue.
        endcase.
        clear gs_rt.
      endloop.
      endif.
    else.
    endif.
 endloop.
 var-lgart = '2018'.
 var-betrg = l_1090.
 var-amt_curr = 'CNY'.
 collect var
endform.