UPDATE 21/07/2012: because of some requests the program is now improved: it uploads Excel instead of processing hardcoded data, it converts texts from the input to the length that i suitable for PO03 transaction and also writes proficiencies for qualifications evaluated in the input.
I was asked to build a program that would upload HR-PD Job object (“C”) definitions from. I would like to share the experience as well as the example coding. I am not going to pretend the example coding will save an experienced developer more than twenty minutes, but in my experience it`s always better to start with something than from scratch, right?
Last time I blogged about development for HR-PD Qualifications and the coding made the blog more useful than just talking I hope. If interested, check the blog here: All you need to know about HR-PD Qualifications from the development perspective.
As I understood my task, it had multiple parts. Unfortunately only one fraction can be generalized and reused. That is the upload part when you have data in a suitable format and call the function modules to put them to the database.
Let me elaborate on the application parts first (you don`t need to stick to it, it`s just that the experience at the end helped me understand how I had better started):
- First one needs to read the data from the data source (whatever the source is, can be an Excel file, XML file, web service – depends on your task). In most cases this part will be easy with the help from CL_GUI_FRONTEND_SERVICES class.
- Once we have the data in the system, it`s time to translate them into a suitable upload format. My task was to use very VERY strange XML file as a data source. Then this part becomes really challenging. I have good news too - this is the most difficult part of the task in my opinion. Lesson learnt: split the “data transformation” part from the “data upload” part carefully. If you start creating or linking objects as you go through the input file, your coding becomes spaghetti very quickly (hint: I learnt the hard wayJ).
- Last step is to upload the data. We all have the “same” SAP system with same function modules so my example coding should cover a great deal of basic scenarios, I believe.
What`s not covered by the example coding but is typically needed
My coding does not create the qualifications. I assume you already have the qualifications in the system. But what if the task is to create job descriptions with qualifications that are specific to the jobs (well, the power of the qualifications is to have a qualification created once and assigned many… so you`d better do it only if there is a catalog of qualifications used by job descriptions, that you`re uploading, and you want to create the qualification before the first use, so you don`t create more than you need)? Then you might want to reuse some of the coding from the previous blog.
- When you create the qualifications together with the job descriptions, you may want to put the external qualification ID to the qualification “short” field. Then you don`t need a mapping table between the “old” IDs and the “new” ones.
- When you create qualifications with the jobs, you typically group them (qualification groups) and for those groups you use one scale. But the interpretation of proficiency for one qualification often differs from the interpretation for other qualifications. You can define qualification specific proficiency interpretations (text descriptions). Check the qualifications blog for more info.
I wanted to use some custom text sub-types (of infotype 1002) to accommodate various text descriptions of my jobs. So I needed to create the sub-types first. That you can do/ define sub-type in table T778U and then define the time constraint in view V_T777ZIT.
While building your own program for the task, you will create plenty of text jobs I believe. Then you might wonder how to get rid of the test data. Then you might find the SE38 program called RHRHDL00 handy (ok, I am a developer, so for normal mortals there is a transaction called RE_RHRHDL00).
Last but not least: you want to see your jobs. I assume you know how to display them, but if not, try transaction PO03. Hope that helps.
REPORT zjobs. TYPES: BEGIN OF tt_input, job TYPE objid, type TYPE char4, param TYPE text40, value TYPE string, END OF tt_input. DATA lt_input TYPE TABLE OF tt_input. DATA ls_input LIKE LINE OF lt_input. DATA ls_main LIKE LINE OF lt_input. TYPE-POOLS: truxs. DATA lt_filetable TYPE filetable. DATA ls_file LIKE LINE OF lt_filetable. DATA lt_raw_data TYPE truxs_t_text_data. DATA lv_file TYPE rlgrap-filename. DATA lv_rc TYPE i. DEFINE upload_file. clear: lt_filetable, lv_rc, lv_file. call method cl_gui_frontend_services=>file_open_dialog changing file_table = lt_filetable rc = lv_rc exceptions file_open_dialog_failed = 1 cntl_error = 2 error_no_gui = 3 not_supported_by_gui = 4 others = 5. if sy-subrc <> 0. message id sy-msgid type sy-msgty number sy-msgno with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. endif. read table lt_filetable into ls_file index 1. if sy-subrc ne 0. message 'Cancelled by the user' type 'S'. exit. endif. lv_file = ls_file-filename. call function 'TEXT_CONVERT_XLS_TO_SAP' exporting i_tab_raw_data = lt_raw_data i_filename = lv_file tables i_tab_converted_data = &1 exceptions conversion_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. END-OF-DEFINITION. upload_file lt_input. CONSTANTS: c_limit TYPE i VALUE 69. DATA lv_hlp TYPE string. DATA lv_c TYPE i. DATA lv_split TYPE i. DATA lv_test TYPE c. DEFINE split_text. lv_hlp = &1. condense lv_hlp. while lv_hlp is not initial. lv_c = strlen( lv_hlp ). *** find the reasonable part shorter than 79 (until last space in 79 length) if lv_c > c_limit. clear lv_split. lv_c = c_limit. *** look for the last space lv_test = lv_hlp+lv_c(1). condense lv_test. while lv_c > 1 and lv_test is not initial. lv_c = lv_c - 1. lv_test = lv_hlp+lv_c(1). condense lv_test. endwhile. lv_split = lv_c. ls_txt-tline = lv_hlp(lv_split). "put to the first instance of this line lv_hlp = lv_hlp+lv_split. condense lv_hlp. append ls_txt to lt_txt. else. *** take the rest ls_txt-tline = lv_hlp. append ls_txt to lt_txt. clear lv_hlp. exit. "the while endif. endwhile. END-OF-DEFINITION. ******************************************************** ******************************************************** ******************************************************** *** get list of jobs to create DATA lt_jobs LIKE lt_input. lt_jobs = lt_input. DELETE lt_jobs WHERE type <> 'MAIN'. SORT lt_jobs BY job. DELETE ADJACENT DUPLICATES FROM lt_jobs COMPARING job. DATA lt_texts LIKE lt_input. DATA lt_txt TYPE TABLE OF pt1002. "job subtype text lines DATA ls_txt LIKE LINE OF lt_txt. "job subtype text one line FIELD-SYMBOLS <fs_jobs> LIKE LINE OF lt_jobs. FIELD-SYMBOLS <fs_line> LIKE LINE OF lt_input. FIELD-SYMBOLS <fs_text> LIKE LINE OF lt_texts. DATA lv_objid TYPE hrp1000-objid. "job number DATA lv_stext TYPE hrp1000-stext. "job text DATA lv_short TYPE hrp1000-short. "job short text DATA lv_quali TYPE hrobjid. "qualification ID DATA lv_subty TYPE p1002-subty. "text subtype ID ******************************************************** *** for all jobs to create LOOP AT lt_jobs ASSIGNING <fs_jobs>. *** 1) i need to create the job object first *** get the "header" information for this job READ TABLE lt_input INTO ls_main WITH KEY job = <fs_jobs>-job type = 'MAIN'. lv_stext = ls_main-value. lv_short = ls_main-param. CALL FUNCTION 'RH_OBJECT_CREATE' EXPORTING plvar = '01' otype = 'C' stext = lv_stext short = lv_short begda = sy-datum endda = '99991231' IMPORTING objid = lv_objid EXCEPTIONS text_required = 1 invalid_otype = 2 invalid_date = 3 error_during_insert = 4 error_ext_number = 5 undefined = 6 OTHERS = 7. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. CONTINUE. ELSE. WRITE: / 'Job ', lv_objid, ' created'. ENDIF. *** 2) i need to processs the texts *** 2.1) get a list of subtypes I need to process CLEAR lt_texts. lt_texts = lt_input. DELETE lt_texts WHERE job <> <fs_jobs>-job. DELETE lt_texts WHERE type <> 'TEXT'. SORT lt_texts BY param. DELETE ADJACENT DUPLICATES FROM lt_texts COMPARING param. *** 2.2) for every subtype, get all lines LOOP AT lt_texts ASSIGNING <fs_text>. CLEAR lt_txt. LOOP AT lt_input ASSIGNING <fs_line> WHERE job = <fs_jobs>-job AND type = 'TEXT' AND param = <fs_text>-param. *** ls_txt-tline = <fs_line>-value. *** APPEND ls_txt TO lt_txt. split_text <fs_line>-value. ENDLOOP. *** 2.3) assign the description lv_subty = <fs_text>-param. CALL FUNCTION 'RH_OBJECT_DESCRIPTION_WRITE' EXPORTING langu = sy-langu plvar = '01' otype = 'C' objid = lv_objid begda = sy-datum endda = '99991231' subty = lv_subty TABLES ptxt1002 = lt_txt EXCEPTIONS object_not_found = 1 description_required = 2 no_authority = 3 error_during_insert = 4 invalid_date = 5 undefined = 6 OTHERS = 7. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ENDLOOP. *** 3) i need to process the qualifications LOOP AT lt_input ASSIGNING <fs_line> WHERE job = <fs_jobs>-job AND type = 'QUAL'. lv_quali = <fs_line>-value. "qualification ID CALL FUNCTION 'RH_RELATION_MAINTAIN' EXPORTING act_fcode = 'INSE' act_plvar = '01' act_otype = 'C' act_objid = lv_objid "the job I created in step one act_rsign = 'A' act_relat = '031' act_sclas = 'Q' act_sobid = lv_quali act_begda = sy-datum act_endda = '99991231' EXCEPTIONS maintainance_failed = 1. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ENDLOOP. *** now maintain the qualification profile INCLUDING proficiencies for the Job DATA lt_profilec TYPE TABLE OF hrpe_relaq. DATA ls_profile LIKE LINE OF lt_profilec. CLEAR lt_profilec. LOOP AT lt_input ASSIGNING <fs_line> WHERE job = <fs_jobs>-job AND type = 'QUAL'. CLEAR ls_profile. ls_profile-ttype = 'Q'. ls_profile-tbjid = <fs_line>-value. ls_profile-profcy = <fs_line>-param. ls_profile-sbegd = sy-datum. ls_profile-sendd = '99991231'. ls_profile-vbegd = sy-datum. ls_profile-vendd = '99991231'. ls_profile-istat = 1. IF ls_profile-profcy IS INITIAL. ls_profile-not_rated = 'X'. ENDIF. APPEND ls_profile TO lt_profilec. ENDLOOP. DATA objid TYPE p1001-sobid. objid = lv_objid. CALL FUNCTION 'RHPP_R_PROFILE_WRITE' EXPORTING plvar = '01' otype = 'C' objid = objid vtask = 'B' TABLES profile = lt_profilec EXCEPTIONS no_authority = 1 error_during_insert = 2 wrong_otype = 3 object_not_found = 4 object_required = 5 no_scale_defined = 6 scale_not_clear = 7 time_not_valid = 8 proficiency_not_valid = 9 wrong_date_format = 10 undefined = 11 OTHERS = 12. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. CALL FUNCTION 'RH_UPDATE_DATABASE' EXPORTING vtask = 'D' commit_flg = 'X' EXCEPTIONS corr_exit = 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. ENDLOOP.