Introduction
Hello Guys, I myself Vivek with 16+ years of rich experience in SAP and specialized in SAP Fiori/UI5 Development.
My major focus will be in the digital transformation projects.
Eligible Readers
SAPUI5 developers, Consultants, Solution Architects and basically anyone is working on Digital Transformation Projects.
When the readers need this blog?
One of the pain point lies in migrating the documents attached to the GOS(Generic Object Services). Most of the older implementations will definitely have utilized the GOS services and migrating them is a cumbersome process.
Once of the ways of migrating the GOS Documents is via downloading and uploading the same. We have tried moving them via IDOCs, but was not a success story in our case the source and target document number varies.
How GOS is linked to a Document?
Let us take a Finance document from transaction FB03 or Service entry sheet from ML81N, Document number is the key and the object type (eg: BKPF, BUS2091) are the important factors.
We can get the above information functionally and once we get the above information go to table SRGBTBREL
Please use the above selection and RELTYPE ‘ATTA’ means GOS Document. If the RELTYPE is URL, then it is an external link attached to the document.
INSTID A is the document number field. If it ML81N, service entry sheet number is the INSTID A id. If it is finance document fro, FB03 then it will be <Company code>+<Document No>+<Fiscal Year> and this changes accordingly.
Also please pay attention to the field INSTID B which is the field makes relation to the content of the actual Binary of the file stored in table SOC3.
Now let us see the coding we have made to download the GOS attachment and sequence to be used.
- Get the Binary Relation between the document number and the GOS attachment using the instid A, typeid A and Catid A. This will get the INSTID B for the attachment.
- Using the INSTID B, call the function module SO_OBJECT_READ
- After getting the lt_objcont from the read function module, use the function module SO_OBJECT_DOWNLOAD to download the file.
I am presenting the code below with which you can download all the Business object types.
We have also modified the code for uploading a mapping file with old document number in ECC and New document number in S4HANA.
Download does not complete our job, We have to upload the same in the new system. Let’s continue in Part 2.
FIELD-SYMBOLS: <gt_data> TYPE table,
<gs_data>.
DATA : gt_pod_xls TYPE TABLE OF zbc_gos_map_excl_st INITIAL SIZE 0.
DATA : gt_pod TYPE TABLE OF zbc_gos_map_excl_st INITIAL SIZE 0,
gs_pod TYPE eprof_delv_in.
DATA: lt_goslog TYPE TABLE OF zgos_log,
ls_goslog TYPE zgos_log.
TYPES: BEGIN OF ts_fin_att,
foltp TYPE so_fol_tp,
folyr TYPE so_fol_yr,
folno TYPE so_fol_no,
objtp TYPE so_obj_tp,
objyr TYPE so_obj_yr,
objno TYPE so_obj_no,
brelguid TYPE oblguid32,
roletype TYPE oblroltype,
END OF ts_fin_att.
DATA: it_final_cont TYPE STANDARD TABLE OF ts_fin_att,
is_final_cont TYPE ts_fin_att.
************************************************************************
* Class Definition
************************************************************************
CLASS lcl_po_attachments DEFINITION FINAL.
PUBLIC SECTION.
"Types Definition
TYPES: BEGIN OF ts_attachment,
foltp TYPE so_fol_tp,
folyr TYPE so_fol_yr,
folno TYPE so_fol_no,
objtp TYPE so_obj_tp,
objyr TYPE so_obj_yr,
objno TYPE so_obj_no,
brelguid TYPE oblguid32,
roletype TYPE oblroltype,
END OF ts_attachment,
BEGIN OF ts_key,
foltp TYPE so_fol_tp,
folyr TYPE so_fol_yr,
folno TYPE so_fol_no,
objtp TYPE so_obj_tp,
objyr TYPE so_obj_yr,
objno TYPE so_obj_no,
forwarder TYPE so_usr_nam,
END OF ts_key,
* BEGIN OF ts_po,
* ebeln TYPE ekko-ebeln,
* bukrs TYPE ekko-bukrs,
* ekgrp TYPE ekko-ekgrp,
* END OF ts_po,
BEGIN OF ts_po,
ebeln TYPE zbc_gos_map_excl_st-old_key,
bukrs TYPE zbc_gos_map_excl_st-new_key,
ekgrp TYPE zbc_gos_map_excl_st-objtype,
END OF ts_po,
BEGIN OF ts_output,
icon TYPE icon-id,
ebeln TYPE zbc_gos_map_excl_st-old_key,
bukrs TYPE zbc_gos_map_excl_st-new_key,
ekgrp TYPE zbc_gos_map_excl_st-objtype,
file(54) TYPE c,
END OF ts_output,
BEGIN OF ts_sood,
objtp TYPE sood-objtp,
objyr TYPE sood-objyr,
objno TYPE sood-objno,
objdes TYPE sood-objdes,
extct TYPE sood-extct,
file_ext TYPE sood-file_ext,
objlen TYPE sood-objlen,
END OF ts_sood,
tt_sood TYPE HASHED TABLE OF sood
WITH UNIQUE KEY primary_key
COMPONENTS objtp
objyr
objno,
tt_po TYPE TABLE OF ts_po,
tt_attachment TYPE STANDARD TABLE OF ts_attachment
WITH DEFAULT KEY,
tt_output TYPE STANDARD TABLE OF ts_output
WITH DEFAULT KEY.
"Constants
CONSTANTS: c_title TYPE string VALUE 'Select Folder Path to download the PO Attachments'.
"Declarations
DATA: ebeln TYPE ekko-ebeln,
lv_tot TYPE i,
lv_cur TYPE i,
it_ekko TYPE tt_po,
it_sood TYPE tt_sood,
it_out TYPE tt_output,
ls_ekko TYPE zbc_gos_map_excl_st,
it_atta TYPE tt_attachment.
*--- Local variables --------------------------------------------------*
DATA: lv_filename TYPE localfile,
lv_dref TYPE REF TO data.
"Methods
METHODS load.
METHODS check_folderpath
IMPORTING i_dirname TYPE string
RETURNING VALUE(invalid_path) TYPE char1.
METHODS get_sood
IMPORTING lt_attachments TYPE tt_attachment
RETURNING VALUE(lt_sood) TYPE tt_sood.
METHODS get_po_attachments
IMPORTING i_ekko TYPE ts_po
* i_ebeln TYPE zbc_gos_map_excl_st-old_key
* i_objid TYPE zbc_gos_map_excl_st-objtype
"ekko-ebeln
RETURNING VALUE(attachments) TYPE tt_attachment.
METHODS get_po
RETURNING VALUE(no_data) TYPE char1.
PRIVATE SECTION.
"Methods
METHODS download_attachments
IMPORTING i_sood TYPE sood "ts_sood
i_ekko TYPE ts_po.
* METHODS display.
METHODS set_desc
IMPORTING
field TYPE salv_s_ddic_reference-field
table TYPE salv_s_ddic_reference-table
length TYPE lvc_outlen
col TYPE REF TO cl_salv_column_list.
METHODS set_des
IMPORTING
short TYPE scrtext_s
medium TYPE scrtext_m
long TYPE scrtext_l
length TYPE lvc_outlen
col TYPE REF TO cl_salv_column_list.
ENDCLASS.
Selection Screen
************************************************************************
* Initialization
************************************************************************
INITIALIZATION.
DATA(ins_po_attachments) = NEW lcl_po_attachments( ).
************************************************************************
* Selection Screen
************************************************************************
SELECTION-SCREEN: BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-000.
SELECTION-SCREEN COMMENT 1(30) TEXT-003 FOR FIELD p_file.
PARAMETERS: p_file TYPE string LOWER CASE.
PARAMETERS: p_otype TYPE char24 DEFAULT 'BKPF'.
* SELECT-OPTIONS : s_ebeln FOR ins_po_attachments->ebeln.
PARAMETERS : p_path TYPE string LOWER CASE OBLIGATORY.
SELECTION-SCREEN: END OF BLOCK b1.
************************************************************************
* At Selection-screen on Value-request for P_PATH
************************************************************************
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_path.
CALL METHOD cl_gui_frontend_services=>directory_browse
EXPORTING
window_title = ins_po_attachments->c_title
CHANGING
selected_folder = p_path
EXCEPTIONS
cntl_error = 1
error_no_gui = 2
not_supported_by_gui = 3
OTHERS = 4.
IF sy-subrc <> 0.
RETURN.
ENDIF.
************************************************************************
* At Selection-screen on Value-request for P_FILE
************************************************************************
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
PERFORM f4_p_file CHANGING p_file.
START-OF-SELECTION.
ins_po_attachments->load( ).
************************************************************************
* Class Implementation
************************************************************************
CLASS lcl_po_attachments IMPLEMENTATION.
METHOD get_po.
CLEAR no_data.
* ls_ekko-old_key = '200075200019122013'.
* ls_ekko-new_key = '1000238392'.
* ls_ekko-objtype = 'BKPF'.
* APPEND ls_ekko TO it_ekko.
IF <gt_data> IS ASSIGNED.
UNASSIGN <gt_data>.
ENDIF.
IF <gs_data> IS ASSIGNED.
UNASSIGN <gs_data>.
ENDIF.
* Create internal table and structure for data
CREATE DATA lv_dref TYPE TABLE OF zbc_gos_map_excl_st.
ASSIGN lv_dref->* TO <gt_data>.
CREATE DATA lv_dref TYPE zbc_gos_map_excl_st.
ASSIGN lv_dref->* TO <gs_data>.
REFRESH : <gt_data>.
lv_filename = p_file.
BREAK-POINT.
IF NOT lv_filename IS INITIAL.
PERFORM get_excel_data_new USING lv_filename 'ZBC_GOS_MAP_EXCL_ST'.
IF NOT gt_pod IS INITIAL.
LOOP AT gt_pod INTO DATA(gs_pod).
ls_ekko-old_key = gs_pod-old_key.
ls_ekko-new_key = gs_pod-new_key.
ls_ekko-objtype = gs_pod-objtype.
APPEND ls_ekko TO it_ekko.
ENDLOOP.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD download_attachments.
DATA(l_pr) = ( lv_cur * 100 ) / lv_tot.
IF l_pr < 2.
l_pr = 2.
ENDIF.
CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
EXPORTING
percentage = l_pr
text = |{ l_pr
}% =>{ i_ekko-ebeln
}-{ i_sood-objdes
}.{ i_sood-file_ext }|.
DATA(ls_out) = VALUE ts_output( ).
DATA(l_sortf) = CONV char30( |{ i_sood-objtp
}{ i_sood-objyr
}{ i_sood-objno }| ).
DATA(lt_objcont) = VALUE soli_tab( ).
BREAK-POINT.
IMPORT objcont_tab TO lt_objcont[]
FROM DATABASE soc3(dt) ID l_sortf.
IF lt_objcont IS INITIAL.
READ TABLE it_final_cont INTO is_final_cont WITH KEY
objtp = i_sood-objtp
objyr = i_sood-objyr
objno = i_sood-objno.
IF sy-subrc = 0.
DATA: l_folderid TYPE soodk,
l_objectid TYPE soodk.
CONCATENATE is_final_cont-foltp is_final_cont-folyr is_final_cont-folno INTO l_folderid.
l_objectid = l_sortf.
DATA it_objcont TYPE STANDARD TABLE OF soli.
CALL FUNCTION 'SO_OBJECT_READ'
EXPORTING
* FILTER =
folder_id = l_folderid
* FORWARDER =
object_id = l_objectid
* OWNER =
* F_MAILER = ' '
* IMPORTING
* OBJECT_FL_DISPLAY =
* OBJECT_HD_DISPLAY =
* OBJECT_RC_DISPLAY =
TABLES
objcont = lt_objcont
* OBJHEAD =
* OBJPARA =
* OBJPARB =
EXCEPTIONS
active_user_not_exist = 1
communication_failure = 2
component_not_available = 3
folder_not_exist = 4
folder_no_authorization = 5
object_not_exist = 6
object_no_authorization = 7
operation_no_authorization = 8
owner_not_exist = 9
parameter_error = 10
substitute_not_active = 11
substitute_not_defined = 12
system_failure = 13
x_error = 14
OTHERS = 15.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
ENDIF.
ENDIF.
IF sy-subrc = 0.
CONCATENATE i_ekko-bukrs '_' p_otype INTO DATA(i_folder).
DATA(filename) = |{ p_path
}/{ i_folder
}/{ i_sood-objdes
}.{ i_sood-file_ext }|.
DATA(filesize) = CONV soxwd-doc_length( i_sood-objlen ).
DATA(lfilename) = VALUE string( ).
CALL FUNCTION 'SO_OBJECT_DOWNLOAD'
EXPORTING
bin_filesize = filesize
default_filename = filename
filetype = 'BIN'
path_and_file = filename
extct = i_sood-extct
no_dialog = abap_true
IMPORTING
act_filename = lfilename
TABLES
objcont = lt_objcont
EXCEPTIONS
file_write_error = 1
invalid_type = 2
x_error = 3
kpro_error = 4
OTHERS = 5.
IF sy-subrc <> 0.
ls_out-icon = icon_red_light.
***Create the Download Log*************************
ELSE.
ls_out-icon = icon_green_light.
CLEAR: ls_goslog.
ls_goslog-busobj = p_otype.
ls_goslog-cat = 'D'.
ls_goslog-ddate = sy-datum.
ls_goslog-dtime = sy-uzeit.
ls_goslog-filename = i_sood-objdes.
ls_goslog-filetype = i_sood-file_ext.
ls_goslog-objectid = i_ekko-ebeln.
ls_goslog-userid = sy-uname.
APPEND ls_goslog TO lt_goslog.
TRY.
MODIFY zgos_log FROM TABLE lt_goslog.
CATCH cx_sy_open_sql_db INTO DATA(cx_sy_ref_is_initial).
ENDTRY.
* INSERT zgos_log FROM TABLE lt_goslog.
COMMIT WORK.
CLEAR: ls_goslog.
ENDIF.
ELSE.
ls_out-icon = icon_red_light.
ENDIF.
ls_out-bukrs = i_ekko-bukrs.
ls_out-ebeln = i_ekko-ebeln.
ls_out-ekgrp = i_ekko-ekgrp.
ls_out-file = |{ i_sood-objdes
}.{ i_sood-file_ext }|.
APPEND ls_out TO it_out[].
CLEAR ls_out.
ENDMETHOD.
METHOD check_folderpath.
CLEAR invalid_path.
"Check the Folder path exists or not
CALL METHOD cl_gui_frontend_services=>directory_exist
EXPORTING
directory = i_dirname
RECEIVING
result = DATA(result)
EXCEPTIONS
cntl_error = 1
error_no_gui = 2
wrong_parameter = 3
OTHERS = 4.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
invalid_path = abap_true.
ENDIF.
ENDMETHOD.
METHOD get_po_attachments.
DATA(gs_lpor) = VALUE sibflporb( instid = i_ekko-ebeln
catid = 'BO'
typeid = p_otype ). "BKPF
DATA(lt_options) = VALUE obl_t_relt( sign = 'I'
option = 'EQ'
( low = 'ATTA' )
( low = 'NOTE' )
( low = 'URL' ) ).
DATA(ls_attachment) = VALUE ts_attachment( ).
DATA(ls_key) = VALUE ts_key( ).
*
TRY.
CALL METHOD cl_binary_relation=>read_links_of_binrels
EXPORTING
is_object = gs_lpor
it_relation_options = lt_options
ip_role = 'GOSAPPLOBJ'
ip_no_buffer = abap_false
IMPORTING
et_links = DATA(lt_links).
DELETE lt_links[] WHERE typeid_b <> 'MESSAGE'.
LOOP AT lt_links INTO DATA(ls_link).
ls_key = ls_link-instid_b.
MOVE-CORRESPONDING ls_key TO ls_attachment.
ls_attachment-roletype = ls_link-roletype_b.
IF ls_link-brelguid IS INITIAL.
ls_attachment-brelguid = ls_link-relguidold.
ELSE.
ls_attachment-brelguid = ls_link-brelguid.
ENDIF.
APPEND ls_attachment TO attachments[].
it_final_cont[] = attachments[].
CLEAR ls_attachment.
ENDLOOP.
CLEAR it_atta[].
it_atta[] = attachments[].
CATCH: cx_obl_parameter_error INTO DATA(cx_obl_parameter_error),
cx_obl_internal_error INTO DATA(cx_obl_internal_error),
cx_obl_model_error INTO DATA(cx_obl_model_error).
IF cx_obl_parameter_error IS BOUND.
MESSAGE cx_obl_parameter_error->get_text( ) TYPE 'S'
DISPLAY LIKE 'E'.
CLEAR cx_obl_parameter_error.
ENDIF.
IF cx_obl_internal_error IS BOUND.
MESSAGE cx_obl_internal_error->get_text( ) TYPE 'S'
DISPLAY LIKE 'E'.
CLEAR cx_obl_internal_error.
ENDIF.
IF cx_obl_model_error IS BOUND.
MESSAGE cx_obl_model_error->get_text( ) TYPE 'S'
DISPLAY LIKE 'E'.
CLEAR cx_obl_model_error.
ENDIF.
ENDTRY.
ENDMETHOD.
METHOD set_des.
col->set_short_text( short ).
col->set_medium_text( medium ).
col->set_long_text( long ).
col->set_output_length( length ).
ENDMETHOD.
METHOD set_desc.
DATA(value) = VALUE salv_s_ddic_reference(
field = field
table = table ).
col->set_ddic_reference( value ).
col->set_output_length( length ).
ENDMETHOD.
METHOD get_sood.
CLEAR it_sood[].
SELECT *
FROM sood
INTO TABLE lt_sood[]
FOR ALL ENTRIES IN lt_attachments[]
WHERE objtp = lt_attachments-objtp
AND objyr = lt_attachments-objyr
AND objno = lt_attachments-objno.
IF sy-subrc = 0.
it_sood[] = lt_sood[].
ENDIF.
ENDMETHOD.
METHOD load.
CLEAR it_out[].
IF check_folderpath( p_path ) = abap_true.
RETURN.
ENDIF.
IF get_po( ) = abap_true.
RETURN.
ENDIF.
lv_tot = lines( it_ekko[] ).
LOOP AT it_ekko[] INTO DATA(ls_ekko).
lv_cur = sy-tabix.
CHECK NOT get_po_attachments( ls_ekko ) IS INITIAL.
CHECK NOT get_sood( it_atta[] ) IS INITIAL.
LOOP AT it_atta[] INTO DATA(ls_atta).
READ TABLE it_sood[] INTO DATA(ls_sood)
WITH KEY primary_key
COMPONENTS objtp = ls_atta-objtp
objyr = ls_atta-objyr
objno = ls_atta-objno.
CHECK sy-subrc = 0.
download_attachments(
i_sood = ls_sood
i_ekko = ls_ekko ).
ENDLOOP.
ENDLOOP.
CLEAR: it_ekko[],
it_atta[],
it_sood[].
CLEAR it_out[].
ENDMETHOD.
ENDCLASS.
The document(s) will be downloaded in the folder with name of the target Object Key read from the mapping file uploaded.
Read Excel
FORM get_excel_data_new USING p_filename TYPE localfile
p_structure.
*--- Local internal tables --------------------------------------------*
DATA: lt_intern TYPE STANDARD TABLE OF alsmex_tabline,
lt_intern_add TYPE STANDARD TABLE OF alsmex_tabline,
lt_intern_del TYPE STANDARD TABLE OF alsmex_tabline,
lt_fields_check TYPE STANDARD TABLE OF dd03l,
lt_fields TYPE HASHED TABLE OF dd03l WITH UNIQUE KEY position,
lt_fields_t TYPE ex_tab_dd03l.
*--- Local structures -------------------------------------------------*
DATA: ls_intern TYPE alsmex_tabline,
ls_fields TYPE dd03l.
*--- Local variables --------------------------------------------------*
DATA: lv_err_hdr TYPE xflag,
lv_index TYPE sy-tabix,
lv_line(4) TYPE n.
*--- Local field-symbols ----------------------------------------------*
FIELD-SYMBOLS:
<lv_value>.
FIELD-SYMBOLS : <ls_pod> TYPE zbc_gos_map_excl_st,
<ls_pod_xls> TYPE zbc_gos_map_excl_st,
<ls_intern> TYPE alsmex_tabline,
<ls_field> TYPE any.
* PERFORM show_progress USING 20 text-p09.
CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
EXPORTING
filename = p_filename
i_begin_col = 1
i_begin_row = 1
i_end_col = 3
i_end_row = 65536
TABLES
intern = lt_intern
* TABLES
* intern =
EXCEPTIONS
inconsistent_parameters = 1
upload_ole = 2
OTHERS = 3.
IF sy-subrc = 0.
SORT lt_intern BY row col.
DELETE lt_intern WHERE row = 1.
LOOP AT lt_intern ASSIGNING <ls_intern>.
AT NEW row.
APPEND INITIAL LINE TO gt_pod_xls ASSIGNING <ls_pod_xls>.
ENDAT.
ASSIGN COMPONENT <ls_intern>-col OF STRUCTURE <ls_pod_xls> TO <ls_field>.
<ls_field> = <ls_intern>-value.
AT END OF row.
APPEND INITIAL LINE TO gt_pod ASSIGNING <ls_pod>.
MOVE-CORRESPONDING <ls_pod_xls> TO <ls_pod>.
* <ls_pod>-changd_by = sy-uname.
* <ls_pod>-chang_date = sy-datum.
* <ls_pod>-changd_at = sy-uzeit.
ENDAT.
<gt_data>[] = gt_pod[].
ENDLOOP.
ENDIF.
ENDFORM.
Routine for folder selection of downloadµ
*--- Local internal tables --------------------------------------------*
DATA: lt_dynp_values TYPE TABLE OF dynpread,
lt_fields TYPE dynpread_tabtype,
lt_files TYPE filetable.
*--- Local stuctures --------------------------------------------------*
DATA: ls_field LIKE LINE OF lt_fields.
*--- Local variables --------------------------------------------------*
DATA: lv_repid TYPE syrepid.
************************************************************************
* Programming *
************************************************************************
lv_repid = sy-repid.
CALL FUNCTION 'DYNP_VALUES_READ'
EXPORTING
dyname = lv_repid
dynumb = '1000'
request = 'A'
TABLES
dynpfields = lt_fields
EXCEPTIONS
invalid_abapworkarea = 01
invalid_dynprofield = 02
invalid_dynproname = 03
invalid_dynpronummer = 04
invalid_request = 05
no_fielddescription = 06
undefind_error = 07.
IF sy-subrc = 0.
READ TABLE lt_fields
INTO ls_field
WITH KEY fieldname = 'P_FILE'.
IF sy-subrc = 0.
p_upfile = ls_field-fieldvalue.
cl_gui_frontend_services=>file_open_dialog(
EXPORTING
default_filename = p_upfile
file_filter = zcl_excel_common=>c_xlsx_file_filter
CHANGING
file_table = lt_files
rc = sy-tabix
EXCEPTIONS
OTHERS = 1 ).
IF sy-subrc = 0.
READ TABLE lt_files
INDEX 1
INTO p_upfile.
IF sy-subrc <> 0.
CLEAR : p_upfile.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
ENDFORM.
Please the structure matching the upload template
Download does not complete our job, We have to upload the same in the new system. Let’s continue in Part 2.
Hope this blog is informative.