DATA(service_manager) = NEW cl_hrpp_ws_service_manager( ).
SELECT * INTO TABLE @DATA(lt_t52el) FROM t52el WHERE molga = '01' AND symko <> @space AND endda >= @pn-begps. " Verknüpfung Lohnart zu symbolischen Konto
SELECT * INTO TABLE @DATA(lt_t52ek) FROM t52ek. " Symbolische Konten
SELECT * INTO TABLE @DATA(lt_t52ep) FROM t52ep. " Kontierungsarten
LOOP AT lt_t52el INTO DATA(ls_t52el). " Ermittle je Lohnart die symbolischen Konten (1:n)
TRY.
DATA(ls_t52ek) = lt_t52ek[ symko = ls_t52el-symko ]. " Ermittele Kontierungsart
DATA(ls_t52ep) = lt_t52ep[ koart = ls_t52ek-koart ]. " Ermittele Typ des symbolischen Kontos
DATA(process) = CONV ktosl( 'HR' && ls_t52ep-kttyp ).
CATCH cx_sy_itab_line_not_found.
CONTINUE.
ENDTRY.
service_manager->hrpp_fi_acct_det_hr( EXPORTING companycode = pernr-bukrs
process = process " Vorgangsschlüssel
symb_acct = ls_t52el-symko
eg_acct_det = CONV #( '1' ) " Überleitung FI/CO: Mitarbeitergruppierung Kontenfindung: alle Mitarbeiter
IMPORTING gl_account_debit = DATA(account_debit)
gl_account_credit = DATA(account_credit)
return_tab = DATA(return_tab) ).
IF line_exists( return_tab[ type = 'E' ] ).
CONTINUE.
ENDIF.
" Lese Sachkonto Text
service_manager->hrpp_gl_acc_getdetail( EXPORTING companycode = pernr-bukrs
glacct = account_debit
language = sy-langu
text_only = abap_true
IMPORTING account_detail = DATA(account_detail) ).
ENDLOOP.
Category: ABAP
ABAP
[ABAP] Enqueue and dequeue pernr
TRY.
DATA(messsage_handler) = NEW cl_hrpa_message_list( ).
cl_hrpa_masterdata_enq_deq=>enqueue_by_pernr( tclas = cl_hrpa_tclas=>tclas_employee
pernr = 1
message_handler = messsage_handler ).
cl_hrpa_masterdata_enq_deq=>dequeue_by_pernr( tclas = cl_hrpa_tclas=>tclas_employee
pernr = 1 ).
CATCH cx_hrpa_violated_assertion.
ENDTRY.
[Workflow] AC Rule
Recently, I had the task of assigning a workflow decision step to some users that were customized in a Z-Table. Normally I would have done this, by creating a container element “Actors”, a task that calls a method to return these Actors and use these Actors in the decision step. But this time I tried a custom AC Rule for the first time and I must say it was much easier than expected.
To begin, simply create a function module. The function module only needs two table parameters, AC_CONTAINER
and ACTOR_TAB
. They can be copied from RH_GET_ACTORS or GM_GET_RESP_FROM_INTERNAL. There you can also check, how to access the AC_CONTAINER
table, if you need any input values from the WF. In my case, I just had to read the Z-Table and return the result via ACTOR_TAB
.
SELECT * FROM ztable INTO TABLE @DATA(lt_table).
LOOP at lt_table INTO DATA(ls_table).
"you can also check if the provided user exists by using function module 'SUSR_USER_CHECK_EXISTENCE'
APPEND VALUE #( otype = 'US' objid = ls_table-userid ) TO actor_tab.
ENDLOOP.
IF lines( actor_tab) = 0.
RAISE nobody_found.
ENDIF.
Then simply go to tcode PFAC, create a rule, provide the function module and check the flag box at the end.

In the PFAC transaction, you can also simulate the rule resolution.

If everything works fine, add the new created rule to the decision step.

And done. Really straight forward.
[ABAP] Escape URL
DATA(path) = escape( val = 'https://url.com/path/with/a space/in/it'
format = cl_abap_format=>e_url ).
[ABAP] Get Filename and Mimetype from uploaded file
DATA data_tab TYPE solix_tab.
DATA filename TYPE string.
DATA path TYPE string DEFAULT 'C:\Users\path\to\my\file.pdf'.
cl_gui_frontend_services=>gui_upload( EXPORTING filename = path )
filetype = 'BIN'
CHANGING data_tab = data_tab ).
CALL FUNCTION 'SO_SPLIT_FILE_AND_PATH'
EXPORTING
full_name = path
IMPORTING
stripped_name = filename
EXCEPTIONS
x_error = 1
OTHERS = 2.
DATA(file_extension) = /iwwrk/cl_mgw_workflow_rt_util=>get_extention_from_file_name( filename ).
DATA(mimetype) = /iwwrk/cl_mgw_workflow_rt_util=>get_mime_type_from_extension( file_extension ).
Instead of SO_SPLIT_FILE_AND_PATH
you can also use PC_SPLIT_COMPLETE_FILENAME
.
[ABAP] Validate date
CALL FUNCTION 'DATE_CHECK_PLAUSIBILITY'
EXPORTING
date = '20250231' " invalid date
EXCEPTIONS
plausibility_check_failed = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
If you’re not interested in a specific error message, you can also use the following method to get the result as boolean.
DATA(date_is_valid) = cl_rs_time_service=>is_valid_date( '20250231' ).
[ABAP] Validate pernr
DATA ls_return TYPE bapireturn.
CALL FUNCTION 'BAPI_EMPLOYEE_CHECKEXISTENCE'
EXPORTING
number = 99999999
IMPORTING
return = ls_return.
IF ls_return-type = 'E'.
MESSAGE ls_return-message TYPE ls_return-type.
ENDIF.
On newer systems there is also class CL_HRPA_MAINTAIN_EMPLOYEE
with method PERSONNEL_NUMBER_EXISTS
.
Or class CL_HRPA_MAINTAIN_EMPLOYEE_UTIL
and method EXIST_EMPLOYEE
.
[ABAP] BASE CORRESPONDING
I recently had to rewrite a Report where I saw code that looked similar to this.
TYPES:
BEGIN OF ty_employee,
vorna TYPE vorna,
nachn TYPE nachn,
END OF ty_employee,
tt_employee TYPE TABLE OF ty_employee WITH DEFAULT KEY,
BEGIN OF ty_source,
col1 TYPE c LENGTH 2,
col2 TYPE c LENGTH 2,
col3 TYPE c LENGTH 2,
col4 TYPE c LENGTH 2,
END OF ty_source,
tt_source TYPE TABLE OF ty_source WITH DEFAULT KEY,
BEGIN OF ty_target,
col1 TYPE c LENGTH 2,
col2 TYPE c LENGTH 2,
col3 TYPE c LENGTH 2,
col4_vorna TYPE vorna,
col5_nachn TYPE nachn,
END OF ty_target,
tt_target TYPE TABLE OF ty_target WITH DEFAULT KEY.
* Test employees
DATA(employees) = VALUE tt_employee( ( vorna = 'Max' nachn = 'Mustermann' )
( vorna = 'Erika' nachn = 'Mustermann' ) ).
* In reallity, this table changed per employee
DATA(source_tab) = VALUE tt_source( ( col1 = 'a1' col2 = 'b1' col3 = 'c1' col4 = 'd1' )
( col1 = 'a2' col2 = 'b2' col3 = 'c2' col4 = 'd2' )
( col1 = 'a3' col2 = 'b3' col3 = 'c3' col4 = 'd3' ) ).
* Actual logic
DATA target_line TYPE ty_target.
DATA target_tab1 TYPE tt_target.
LOOP AT employees INTO DATA(employee).
LOOP AT source_tab INTO DATA(source_line).
CLEAR target_line.
target_line-col4_vorna = employee-vorna.
target_line-col5_nachn = employee-nachn.
MOVE-CORRESPONDING source_line TO target_line.
APPEND target_line TO target_tab1.
ENDLOOP.
ENDLOOP.
cl_demo_output=>write( employees ).
cl_demo_output=>write( source_tab ).
cl_demo_output=>write( target_tab1 ).
cl_demo_output=>display( ).
I spend some time thinking, how I could improve the actual logic by using some “new” ABAP syntax elements. I came up with the following result.
DATA target_tab2 TYPE tt_target.
LOOP AT employees INTO employee.
target_tab2 = VALUE #( BASE CORRESPONDING #( target_tab2 )
FOR line IN source_tab (
VALUE #( BASE CORRESPONDING #( line )
col4_vorna = employee-vorna
col5_nachn = employee-nachn ) ) ).
ENDLOOP.
But I must say, that in this case I prefer using nested LOOP’s like this
DATA target_tab3 TYPE tt_target.
LOOP AT employees INTO employee.
LOOP AT source_tab INTO source_line.
DATA(t_line) = CORRESPONDING ty_target( source_line ).
t_line-col4_vorna = employee-vorna.
t_line-col5_nachn = employee-nachn.
APPEND t_line TO target_tab3.
ENDLOOP.
ENDLOOP.
or this
DATA target_tab4 TYPE tt_target.
LOOP AT employees INTO employee.
LOOP AT source_tab INTO source_line.
APPEND VALUE #( BASE CORRESPONDING #( source_line )
col4_vorna = employee-vorna
col5_nachn = employee-nachn ) TO target_tab4.
ENDLOOP.
ENDLOOP.