Saturday, November 18, 2017

Transferring data between SAP systems - improved version

Sometimes you find the need to transfer the data from a table in one client to another client or another system. E.g. when you've built a Z table and you've copied production down to the test environment or you might want to keep a copy of the table's contents before you make some change in case you mess things up and want to restore back to the old copy.

The program below will copy the data down to a text or binary file and will then read that file to reload the table again. Obviously there are a few caveats;
  • Table structures between the two systems must be completely identical.
  • Default parameters for things like date formats need to be identical between the two systems.
The program has been left with a deliberate compile bug in it at the point where you should put some kind of appropriate authorization check in place to prevent people from uploading junk into your system.

This is an improvement of a previous program I wrote as this one will handle GUIDs and text in foreign languages as well provided you use the binary format.


It's possible to limit the data that gets downloaded by using the Data selection button after you've selected the table and field names. This will dynamically build a new selection screen where you can select values to limit your data selection. You can also automatically split the file at a predefined record count if you're going to be working with really huge files.

When you're uploading you can decide if you want to skip existing records with the same key fields or simply overwrite them.

*&---------------------------------------------------------------------*
*& Report ZZDATA_TRANSFER
*&---------------------------------------------------------------------*
*& Use this program to transfer data between systems.
*& If you have data like unicode text that might get scrambled then
*& use binary mode to transfer the data.
*& Mark Langenhoven 2014 - 2017
*&---------------------------------------------------------------------*
report zzdata_transfer.


*--- Data declarations ------------------------------------------------
tables: dd03l.
type-pools:rsds.


data: begin of finalrec,
        fieldname like dd03l-fieldname,
        desc      like dd04t-ddtext,
      end of finalrec.
data: it_final  like finalrec occurs 0 with header line,
      lt_dd03l  like dd03l occurs 0 with header line,
      ls_dd03l  like dd03l,
      ls_dd04t  like dd04t,
      it_return like ddshretval occurs 0 with header line.

data: gv_where type rsds_twhere.


*--- Selection screen -------------------------------------------------
"Up or down direction
selection-screen begin of block dir with frame title dir.
selection-screen begin of line.
parameters p_down radiobutton group grp1 default 'X' user-command dib.
selection-screen comment 3(30) pdown.
selection-screen end of line.

selection-screen begin of line.
parameters p_up radiobutton group grp1.
selection-screen comment 3(30) pup.
selection-screen end of line.
selection-screen end of block dir.

"ASCII or Binary file type
selection-screen begin of block typ with frame title typ.
selection-screen begin of line.
parameters p_asc radiobutton group grp2 default 'X' user-command asc.
selection-screen comment 3(15) pasc.
selection-screen end of line.

selection-screen begin of line.
parameters p_bin radiobutton group grp2.
selection-screen comment 3(15) pbin.
selection-screen end of line.
selection-screen end of block typ.


"File name
selection-screen begin of block fil with frame title fil.
selection-screen begin of line.
selection-screen comment 1(15) pfile.
parameters p_file like rlgrap-filename.
selection-screen end of line.

"Add a header line to the output
selection-screen begin of line.
parameters p_head as checkbox default 'X'.
selection-screen comment 3(20) phead.
selection-screen end of line.

"Split file at NNN number of records
selection-screen begin of line.
selection-screen comment 1(25) pbrk.
parameters p_brk type i default '50000'.
selection-screen end of line.

selection-screen end of block fil.

"Table and field names
selection-screen begin of block tab with frame title tab.
selection-screen begin of line.
selection-screen comment 1(18) ptab.
parameters p_tab like dd03l-tabname.
selection-screen end of line.

selection-screen begin of line.
selection-screen comment 1(15) pfield.
select-options: s_field for dd03l-fieldname no intervals.
selection-screen end of line.

selection-screen: pushbutton 1(18) p_btn user-command clk.

selection-screen end of block tab.

"Skip or overwrite uploaded data
selection-screen begin of block upd with frame title upd.
selection-screen begin of line.
parameters p_skip radiobutton group upg default 'X'.
selection-screen comment 3(28) pskip.
selection-screen end of line.

selection-screen begin of line.
parameters p_over radiobutton group upg.
selection-screen comment 3(28) pover.
selection-screen end of line.

selection-screen end of block upd.


initialization.
  pdown = 'Transfer data down to a file'.
  pup = 'Transfer data up from a file'.
  pasc = 'ASCII text file'.
  pbin = 'Binary file'.
  pfile = 'File name'.
  ptab = 'Table name'.
  pfield = 'Field selection'.
  p_btn = 'Data selection'.
  pskip = 'Skip existing records'.
  pover = 'Overwrite existing records'.
  pbrk = 'Break files into records'.
  phead = 'Header line'.

  dir = 'Direction'.
  typ = 'File type'.
  fil = 'File information'.
  tab = 'Table information'.
  upd = 'Update method'.



  "Grab any fieldnames the user wants to select by

at selection-screen on value-request for s_field-low.
  "Build a custom search help because the dropdown on dd03l is terrible
  refresh it_final.
  select tabname fieldname keyflag rollname from dd03l
    into corresponding fields of table lt_dd03l
  where tabname = p_tab
  order by position.

  "Ignore includes
  delete lt_dd03l where fieldname cs '.INCL'.

  loop at lt_dd03l.
    clear it_final.
    it_final-fieldname = lt_dd03l-fieldname.
    select single ddtext from dd04t into it_final-desc
    where rollname = lt_dd03l-rollname
    and   ddlanguage = sy-langu.
    append it_final.
  endloop.

  call function 'F4IF_INT_TABLE_VALUE_REQUEST'
    exporting
      retfield        = 'FIELDNAME'
      value_org       = 'S'
    tables
      value_tab       = it_final
      return_tab      = it_return
    exceptions
      parameter_error = 1
      no_values_found = 2
      others          = 3.
  if sy-subrc <> 0.
* Implement suitable error handling here
  endif.

  loop at it_return.
    s_field-low = it_return-fieldval.
    s_field-sign = 'I'.
    s_field-option = 'EQ'.
    append s_field.
  endloop.

  sort s_field.
  delete adjacent duplicates from s_field.



at selection-screen on value-request for p_file.
  "Pop up a file selector for the user to choose a file
  data: objfile type ref to cl_gui_frontend_services.
  data: lv_rc    type i,
        ls_files type line of filetable,
        lt_files type filetable.

  check sy-batch is initial.

  create object objfile.
  call method cl_gui_frontend_services=>file_open_dialog
    exporting
      window_title            = 'Select file'
      default_extension       = 'TXT'
    changing
      file_table              = lt_files
      rc                      = lv_rc
    exceptions
      file_open_dialog_failed = 1
      cntl_error              = 2
      error_no_gui            = 3
      not_supported_by_gui    = 4
      others                  = 5.
  check sy-subrc = 0.

  read table lt_files into ls_files index 1.
  check sy-subrc = 0.

  p_file = ls_files-filename.


at selection-screen.
  if sy-ucomm = 'CLK'.
    if s_field[] is initial.
      message s000(38) with 'Select fields first'.
      exit.
    endif.
    perform restrict_data.
  endif.

  "Check if everything is filled prior to running
  if sy-ucomm = 'ONLI'.

    if p_file is initial.
      message e000(38) with 'Supply the filename'.
      exit.
    endif.

    if p_tab is initial.
      message e000(38) with 'Supply the table name'.
      exit.
    endif.

    select single * from dd03l into ls_dd03l
       where tabname = p_tab.
    if sy-subrc <> 0.
      message e000(38) with 'Invalid table name' p_tab.
      exit.
    endif.

  endif.


at selection-screen output.
  if p_up = abap_true.
    "Show the upload parameters
    loop at screen.
      if screen-name cs 'OVER' or
         screen-name cs 'SKIP'.
        screen-invisible = 0.
        modify screen.
      endif.
      if screen-name cs 'BTN' or
         screen-name cs 'FIELD' or
         screen-name cs 'BRK'.
        screen-invisible = 1.
        screen-input = 0.
        modify screen.
      endif.
    endloop.
  else.
    "Hide the upload parameters
    loop at screen.
      if screen-name cs 'OVER' or
         screen-name cs 'SKIP'.
        screen-invisible = 1.
        modify screen.
      endif.
      if screen-name cs 'BTN' or
         screen-name cs 'FIELD' or
         screen-name cs 'BRK'.
        screen-invisible = 0.
        modify screen.
      endif.
    endloop.
  endif.

  "No header record allowed on binary files
  if p_bin = abap_true.
    loop at screen.
      if screen-name cs 'HEAD'.
        screen-active = 0.
        modify screen.
      endif.
    endloop.
  endif.

  "Needed because SAP messes around with our stuff after the fact
  sort s_field.
  delete adjacent duplicates from s_field.



*=== Main program =====================================================
start-of-selection.
  if p_down = abap_true.
    perform download.
  else.
    if p_tab(1) <> 'Z'.
      message e000(38) with 'Only Z tables are allowed'.
      exit.
    endif.
    Build your authorization check here.
    perform upload.
  endif.


*&---------------------------------------------------------------------*
*&      Form  RESTRICT_DATA
*&---------------------------------------------------------------------*
* Use the user's selection to restrict which data will be downloaded
*----------------------------------------------------------------------*
form restrict_data.
  data: lv_title  like sy-title,
        lv_expr   type rsds_texpr,
        lt_tables like rsdstabs occurs 0 with header line,
        lt_fields like rsdsfields occurs 0 with header line,
        lv_selid  like rsdynsel-selid,
        lv_actnum like sy-tfill.

  refresh: lt_tables, lt_fields.
  clear: gv_where.

  lt_tables-prim_tab = p_tab.
  append lt_tables.

  loop at s_field.
    lt_fields-tablename = p_tab.
    lt_fields-fieldname = s_field-low.
    append lt_fields.
  endloop.

  call function 'FREE_SELECTIONS_INIT'
    exporting
      kind                     = 'T'
      expressions              = lv_expr
    importing
      selection_id             = lv_selid
      number_of_active_fields  = lv_actnum
    tables
      tables_tab               = lt_tables
      fields_tab               = lt_fields
    exceptions
      fields_incomplete        = 1
      fields_no_join           = 2
      field_not_found          = 3
      no_tables                = 4
      table_not_found          = 5
      expression_not_supported = 6
      incorrect_expression     = 7
      illegal_kind             = 8
      area_not_found           = 9
      inconsistent_area        = 10
      kind_f_no_fields_left    = 11
      kind_f_no_fields         = 12
      too_many_fields          = 13
      dup_field                = 14
      field_no_type            = 15
      field_ill_type           = 16
      dup_event_field          = 17
      node_not_in_ldb          = 18
      area_no_field            = 19
      others                   = 20.
  if sy-subrc <> 0.
* Implement suitable error handling here
  endif.

  concatenate 'Restrict data selections for' p_tab into lv_title separated by space.

  call function 'FREE_SELECTIONS_DIALOG'
    exporting
      selection_id            = lv_selid
      title                   = lv_title
      tree_visible            = ' '
    importing
      where_clauses           = gv_where
      number_of_active_fields = lv_actnum
    tables
      fields_tab              = lt_fields
    exceptions
      internal_error          = 1
      no_action               = 2
      selid_not_found         = 3
      illegal_status          = 4
      others                  = 5.
  if sy-subrc <> 0.
    clear: gv_where.
  endif.

endform.


*&---------------------------------------------------------------------*
*&      Form  DOWNLOAD
*&---------------------------------------------------------------------*
* Download data to a file
*----------------------------------------------------------------------*
form download.

  data: lv_file  type string,
        lv_ftype type char10,
        lv_sep   type char01.

  data: ls_where    type rsds_where,
        lt_wheretab type rsds_where_tab,
        ls_wheretab type rsdswhere,
        lv_where    type string.

  data: begin of namerec,
          fieldname like dd03l-fieldname,
        end of namerec.

  data: lt_dyntab     type ref to data,
        lt_dyntab2    type ref to data,
        ls_dynwa      type ref to data,
        lt_cat        type table of lvc_s_fcat,
        lt_fields     like dd03l occurs 0 with header line,
        lt_fieldnames like namerec occurs 0 with header line,
        wa_fields     like dd03l,
        wa_cat        type lvc_s_fcat,
        lv_cnt        type i,
        lv_sel        type i,
        lv_tabix      type i,
        lv_filecnt(3) type n.

  field-symbols: <table> type table,
                 <load>  type table,
                 <wa>.


  select * from dd03l into table lt_fields
  where tabname = p_tab.

  sort lt_fields by position.
  delete lt_fields where fieldname cp '.INCLU*'.

  loop at lt_fields into wa_fields.
    lv_cnt = lv_cnt + 1.
    wa_cat-tabname = p_tab.
    wa_cat-fieldname = wa_fields-fieldname.
    wa_cat-col_pos = lv_cnt.
    wa_cat-inttype = wa_fields-inttype.
    wa_cat-datatype = wa_fields-datatype.
    wa_cat-intlen = wa_fields-intlen.
    wa_cat-seltext = wa_fields-fieldname.
    wa_cat-decimals = wa_fields-decimals.
    wa_cat-ref_field = wa_fields-fieldname.
    wa_cat-ref_table = p_tab.
    append wa_cat to lt_cat.
    clear wa_cat.
  endloop.
  call method cl_alv_table_create=>create_dynamic_table
    exporting
      it_fieldcatalog           = lt_cat
    importing
      ep_table                  = lt_dyntab
    exceptions
      generate_subpool_dir_full = 1
      others                    = 2.
  if sy-subrc <> 0.
    message e000(38) with 'Error creating dynamic table'.
    exit.
  endif.

  assign lt_dyntab->* to <table>.

  call method cl_alv_table_create=>create_dynamic_table
    exporting
      it_fieldcatalog           = lt_cat
    importing
      ep_table                  = lt_dyntab2
    exceptions
      generate_subpool_dir_full = 1
      others                    = 2.
  if sy-subrc <> 0.
    message e000(38) with 'Error creating dynamic table'.
    exit.
  endif.
  assign lt_dyntab2->* to <load>.

  "Create a work area for us to loop through
  create data ls_dynwa like line of <table>.
  assign ls_dynwa->* to <wa>.

  "Select the actual data to download
  if gv_where is not initial.
    read table gv_where into ls_where index 1.
    lt_wheretab = ls_where-where_tab.
    if lt_wheretab[] is not initial.
      clear lv_where.
      loop at lt_wheretab into ls_wheretab.
        concatenate lv_where ls_wheretab-line into lv_where separated by space.
      endloop.
      select * from (p_tab) into table <table>
      where (lv_where).
    endif.

  else.
    select * from (p_tab) into table <table>.
  endif.

  describe table <table>.
  if sy-tfill > 0.
    write: / 'Selected ', sy-tfill, 'records'.
  else.
    write: / 'No data selected'.
    exit.
  endif.

  lv_sel = sy-tfill.
  lv_filecnt = 1.


  loop at <table> into <wa>.
    lv_tabix = sy-tabix.
    append <wa> to <load>.
    check lv_tabix mod p_brk = 0 or lv_tabix = lv_sel.


    if lv_sel > p_brk and p_brk > 0.
      perform build_filename using lv_filecnt changing lv_file.
      lv_filecnt = lv_filecnt + 1.
    else.
      lv_file = p_file.
    endif.

    if p_asc = abap_true.
      lv_ftype = 'ASC'.
      lv_sep = 'X'.
    else.
      lv_ftype = 'BIN'.
      clear: lv_sep.
    endif.

    refresh lt_fieldnames.
    if p_head = abap_true and p_asc = abap_true.
      loop at lt_fields.
        lt_fieldnames = lt_fields-fieldname.
        append lt_fieldnames.
      endloop.
    endif.

    call function 'GUI_DOWNLOAD'
      exporting
        filename                = lv_file
        filetype                = lv_ftype
        write_field_separator   = lv_sep
      tables
        data_tab                = <load>
        fieldnames              = lt_fieldnames
      exceptions
        file_write_error        = 1
        no_batch                = 2
        gui_refuse_filetransfer = 3
        invalid_type            = 4
        no_authority            = 5
        unknown_error           = 6
        header_not_allowed      = 7
        separator_not_allowed   = 8
        filesize_not_allowed    = 9
        header_too_long         = 10
        dp_error_create         = 11
        dp_error_send           = 12
        dp_error_write          = 13
        unknown_dp_error        = 14
        access_denied           = 15
        dp_out_of_memory        = 16
        disk_full               = 17
        dp_timeout              = 18
        file_not_found          = 19
        dataprovider_exception  = 20
        control_flush_error     = 21
        others                  = 22.
    if sy-subrc <> 0.
      write: / 'Error creating file', sy-subrc.
    else.
      write: / 'Downloaded file:', lv_file.
    endif.

    refresh <load>.

  endloop.

endform.


*&---------------------------------------------------------------------*
*&      Form  UPLOAD
*&---------------------------------------------------------------------*
* Upload the data from a file
*----------------------------------------------------------------------*
form upload.

  data: lv_file  type string,
        lv_ftype type char10,
        lv_sep   type char01,
        lv_rc    type i.

  data: lt_dyntab type ref to data,
        ls_dynwa  type ref to data,
        ls_dynwa2 type ref to data,
        lt_cat    type table of lvc_s_fcat,
        lt_fields like dd03l occurs 0 with header line,
        wa_fields like dd03l,
        wa_cat    type lvc_s_fcat,
        lv_cnt    type i,
        lv_mandt,
        lv_where  type string,
        lv_tmp    type string.

  field-symbols: <table> type table,
                 <wa>,
                 <field>,
                 <skip>.


  lv_file = p_file.

  if p_asc = abap_true.
    lv_ftype = 'ASC'.
    lv_sep = 'X'.
  else.
    lv_ftype = 'BIN'.
    clear lv_sep.
  endif.


  select * from dd03l into table lt_fields
  where tabname = p_tab.

  sort lt_fields by position.
  delete lt_fields where fieldname cp '.INCLU*'.

  loop at lt_fields into wa_fields.
    lv_cnt = lv_cnt + 1.
    wa_cat-tabname = p_tab.
    wa_cat-fieldname = wa_fields-fieldname.
    wa_cat-col_pos = lv_cnt.
    wa_cat-inttype = wa_fields-inttype.
    wa_cat-datatype = wa_fields-datatype.
    wa_cat-intlen = wa_fields-intlen.
    wa_cat-seltext = wa_fields-fieldname.
    wa_cat-decimals = wa_fields-decimals.
    wa_cat-ref_field = wa_fields-fieldname.
    wa_cat-ref_table = p_tab.
    append wa_cat to lt_cat.
    clear wa_cat.
  endloop.
  call method cl_alv_table_create=>create_dynamic_table
    exporting
      it_fieldcatalog           = lt_cat
    importing
      ep_table                  = lt_dyntab
    exceptions
      generate_subpool_dir_full = 1
      others                    = 2.
  if sy-subrc <> 0.
    message e000(38) with 'Error creating dynamic table'.
    exit.
  endif.

  assign lt_dyntab->* to <table>.

  "Create a work area for us to loop through
  create data ls_dynwa like line of <table>.
  assign ls_dynwa->* to <wa>.
  create data ls_dynwa2 like line of <table>.
  assign ls_dynwa2->* to <skip>.

  if p_asc = abap_true and p_head = abap_true.
    perform remove_header changing lv_file.
  endif.

  call function 'GUI_UPLOAD'
    exporting
      filename                = lv_file
      filetype                = lv_ftype
      has_field_separator     = lv_sep
    tables
      data_tab                = <table>
    exceptions
      file_open_error         = 1
      file_read_error         = 2
      no_batch                = 3
      gui_refuse_filetransfer = 4
      invalid_type            = 5
      no_authority            = 6
      unknown_error           = 7
      bad_data_format         = 8
      header_not_allowed      = 9
      separator_not_allowed   = 10
      header_too_long         = 11
      unknown_dp_error        = 12
      access_denied           = 13
      dp_out_of_memory        = 14
      disk_full               = 15
      dp_timeout              = 16
      others                  = 17.
  if sy-subrc <> 0.
    write: / 'Upload file error', sy-subrc.
    exit.
  endif.

  "Delete the temporary file
  if p_asc = abap_true and p_head = abap_true.

    call method cl_gui_frontend_services=>file_delete
      exporting
        filename             = lv_file
      changing
        rc                   = lv_rc
      exceptions
        file_delete_failed   = 1
        cntl_error           = 2
        error_no_gui         = 3
        file_not_found       = 4
        access_denied        = 5
        unknown_error        = 6
        not_supported_by_gui = 7
        wrong_parameter      = 8
        others               = 9.
    if sy-subrc <> 0.
*     Implement suitable error handling here
    endif.

  endif.

  read table lt_fields with key fieldname = 'MANDT'.
  if sy-subrc = 0.
    lv_mandt = abap_true.
  else.
    lv_mandt = abap_false.
  endif.

  clear lv_cnt.

  loop at <table> into <wa>.
    "Map to the current client
    if lv_mandt = abap_true.
      assign component 'MANDT' of structure <wa> to <field>.
      <field> = sy-mandt.
    endif.

    "See if we want to skip existing records
    if p_skip = abap_true.
      "Build up a dynamic where clause to select with
      clear lv_where.
      loop at lt_fields where keyflag = abap_true.
        check lt_fields-fieldname <> 'MANDT'.
        assign component lt_fields-fieldname of structure <wa> to <field>.

        concatenate '''' <field> '''' into lv_tmp.
        concatenate lv_where 'AND' lt_fields-fieldname '=' lv_tmp into lv_where separated by space.

      endloop.

      "Remove the unneeded AND
      shift lv_where left by 4 places.

      select single * from (p_tab) into <skip>
      where (lv_where).
      if sy-subrc = 0.
        continue.
      endif.
    endif.

    modify (p_tab) from <wa>.
    lv_cnt = lv_cnt + 1.
  endloop.

  commit work.

  write: / 'Updated', lv_cnt , 'records'.

endform.


*&---------------------------------------------------------------------*
*&      Form  BUILD_FILENAME
*&---------------------------------------------------------------------*
* Build up a filename for the file split
*----------------------------------------------------------------------*
form build_filename  using    pv_cnt
                     changing pv_file.

  data: lv_1 type string,
        lv_2 type string.

  pv_file = p_file.
  split pv_file at '.' into lv_1 lv_2.

  concatenate lv_1 pv_cnt '.' lv_2 into pv_file.

endform.


*&---------------------------------------------------------------------*
*&      Form  REMOVE_HEADER
*&---------------------------------------------------------------------*
* Remove the header record from the file
*----------------------------------------------------------------------*
form remove_header  changing pv_file.

  data: lt_dummy type table of string,
        lt_path  type string occurs 0 with header line.

  call method cl_gui_frontend_services=>gui_upload
    exporting
      filename                = pv_file
    changing
      data_tab                = lt_dummy
    exceptions
      file_open_error         = 1
      file_read_error         = 2
      no_batch                = 3
      gui_refuse_filetransfer = 4
      invalid_type            = 5
      no_authority            = 6
      unknown_error           = 7
      bad_data_format         = 8
      header_not_allowed      = 9
      separator_not_allowed   = 10
      header_too_long         = 11
      unknown_dp_error        = 12
      access_denied           = 13
      dp_out_of_memory        = 14
      disk_full               = 15
      dp_timeout              = 16
      not_supported_by_gui    = 17
      error_no_gui            = 18
      others                  = 19.
  if sy-subrc <> 0.
* Implement suitable error handling here
  endif.

  check lt_dummy is not initial.

  delete lt_dummy index 1.

  split pv_file at '\' into table lt_path.
  describe table lt_path.
  delete lt_path index sy-tfill.

  clear pv_file.
  loop at lt_path.
    concatenate pv_file '\' lt_path into pv_file.
  endloop.
  shift pv_file left.
  concatenate pv_file '\tempheader.txt' into pv_file.

  call method cl_gui_frontend_services=>gui_download
    exporting
      filename                = pv_file
    changing
      data_tab                = lt_dummy
    exceptions
      file_write_error        = 1
      no_batch                = 2
      gui_refuse_filetransfer = 3
      invalid_type            = 4
      no_authority            = 5
      unknown_error           = 6
      header_not_allowed      = 7
      separator_not_allowed   = 8
      filesize_not_allowed    = 9
      header_too_long         = 10
      dp_error_create         = 11
      dp_error_send           = 12
      dp_error_write          = 13
      unknown_dp_error        = 14
      access_denied           = 15
      dp_out_of_memory        = 16
      disk_full               = 17
      dp_timeout              = 18
      file_not_found          = 19
      dataprovider_exception  = 20
      control_flush_error     = 21
      not_supported_by_gui    = 22
      error_no_gui            = 23
      others                  = 24.
  if sy-subrc <> 0.
*   Implement suitable error handling here
  endif.

endform.

Sunday, June 4, 2017

Adding a debit memo line to a repair order

Repair orders appear to look like normal sales orders in SAP and can be viewed and changed via VA03/VA02 as usual. However, when you want to change a line, then you need to click on the repair line and hit the repair button at the bottom of the screen.

If you want to change this line programatically, then you need to jump through a few more hoops as you cannot use the usual BAPIs to add or edit one of these lines. Below is the code to add a debit memo to the repair line;

  "Open the sales order for manipulation
  call function 'SD_SALES_DOCUMENT_READ'
    exporting
      document_number            = ls_vbak-vbeln
      status_buffer_refresh      = 'X'
      requisition_buffer_refresh = 'X'.


  "Update our line item
  refresh lt_itemkom.
  clear lt_itemkom.
  lt_itemkom-posnr = '900003'.
  lt_itemkom-updkz = 'I'.
  lt_itemkom-vkgru = '109'. "Debit memo
  lt_itemkom-menge = ls_vbap-kwmeng.
  lt_itemkom-matnr_g = ls_vbap-matnr.
  lt_itemkom-arktx_g = ls_vbap-arktx.
  append lt_itemkom.

  perform repairitems_generate(sapfv45p) tables lt_itemkom
                                                lt_serikom
                                         using  ls_vbap-uepos.

  "Save the order again
  call function 'SD_SALES_DOCUMENT_SAVE'
    exporting
      synchron                   = 'X'
      status_buffer_refresh      = 'X'
      requisition_buffer_refresh = 'X'.



  commit work and wait.

Wednesday, September 28, 2016

Creating a sales order with a One time customer

When using the BAPI_SALESORDER_CREATEFROMDAT2 bapi and you want to use a one time customer you need to link the ORDER_PARTNERS table with the PARTNERADDRESSES table.

This is done as follows;
ORDER_PARTNERS-ADDR_LINK = '1'.
PARTNERADDRESSES-ADDR_NO = '1'.

This will link the two tables and allow you to pass address and email information into the sales order for the one time customer.

Thursday, May 12, 2016

Creating a customer in HANA 1511

Creating a customer in HANA 1511 isn't as easy as it used to be. There's a new function, CVI_EI_INBOUND_MAIN, that is used to create all Business Partners. This has to be fed a lot of information before it will create a new customer. The code below will create a bare-bones customer with a single address.

*&---------------------------------------------------------------------*
*& Report ZZCUSTCREATE
*&---------------------------------------------------------------------*
*& Test program to create a customer
*&---------------------------------------------------------------------*
report zzcustcreate.


data: lt_data   type cvis_ei_extern_t,
      lt_return type bapiretm,
      ls_return type bapireti,
      ls_retmsg type line of bapiretct,
      lv_text   type string.

data: wa_data     like line of lt_data,
      wa_role     type bus_ei_bupa_roles,
      wa_relation type burs_ei_extern,
      wa_paadr    type bus_ei_bupa_address,
      wa_company  type cmds_ei_company.

data: lv_guid    type guid_32,
      lv_pguid   like but000-partner_guid,
      lv_partner like wa_data-partner-header-object_instance-bpartner.


start-of-selection.

  lv_partner = '0017100152'.

  select single partner_guid from but000 into lv_pguid
      where partner = lv_partner.
  if sy-subrc = 0.
    lv_guid = lv_pguid.
  else.
    call method cl_system_uuid=>if_system_uuid_static~create_uuid_c32
      receiving
        uuid = lv_guid.
  endif.


*  Create customer
  wa_data-partner-header-object_task = 'M'.
  wa_data-partner-header-object_instance-bpartner = lv_partner. "Because BP03 is externally numbered
  wa_data-partner-header-object_instance-bpartnerguid = lv_guid.



*--- Partner / Central data / common --------------------------------
  wa_data-partner-central_data-common-data-bp_control-category = '2'. "Organization
  wa_data-partner-central_data-common-data-bp_control-grouping = 'BP03'. "Grouping

  wa_data-partner-central_data-common-data-bp_centraldata-searchterm1 = 'MARKLANGENHOVEN'.

  wa_data-partner-central_data-common-data-bp_organization-name1 = 'Marks LLC'.

  wa_data-partner-central_data-common-data-bp_group-namegroup1 = 'MARKLLC'.

  wa_data-partner-central_data-common-datax-bp_centraldata-searchterm1 = abap_true.
  wa_data-partner-central_data-common-datax-bp_organization-name1 = abap_true.
  wa_data-partner-central_data-common-datax-bp_group-namegroup1 = abap_true.


*--- Partner / Central data / Address -------------------------------
  wa_paadr-task = 'M'.
  wa_paadr-data_key-operation = 'XXDFLT'.
  wa_paadr-data-postal-data-city = 'Beverly Hills'.
  wa_paadr-data-postal-data-postl_cod1 = '90210'.
  wa_paadr-data-postal-data-street = '1234 Main St'.
  wa_paadr-data-postal-data-country = 'US'.
  wa_paadr-data-postal-data-region = 'CA'.
  wa_paadr-data-postal-data-langu = 'E'.

  wa_paadr-data-postal-datax-city = abap_true.
  wa_paadr-data-postal-datax-postl_cod1 = abap_true.
  wa_paadr-data-postal-datax-street = abap_true.
  wa_paadr-data-postal-datax-country = abap_true.
  wa_paadr-data-postal-datax-region = abap_true.
  wa_paadr-data-postal-datax-langu = abap_true.

  wa_paadr-currently_valid = abap_true.
  append wa_paadr to wa_data-partner-central_data-address-addresses.


*--- Partner / Central data / role ----------------------------------
  wa_role-task = 'M'. "Modify
  wa_role-data_key = 'FLCU01'. "Role key - customer
  wa_role-data-rolecategory = 'FLCU01'.
  wa_role-data-valid_from = sy-datum.
  wa_role-data-valid_to = '99991231'.
  wa_role-currently_valid = abap_true.

  wa_role-datax-valid_from = abap_true.
  wa_role-datax-valid_to = abap_true.

  append wa_role to wa_data-partner-central_data-role-roles.
  wa_data-partner-central_data-role-current_state = abap_true.


*--- Partner relation / header ---------------------------------
  wa_relation-header-object_instance-partner1-identificationcategory = 'FLCU01'.
  append wa_relation to wa_data-partner_relation.
  wa_relation-header-object_task = 'I'.


*--- Customer / Company data ------------------------------------
  wa_company-task        = 'M'.    "Modify
  wa_company-data_key    = '1710'. " company code
  wa_company-data-zterm  = '0002'. " terms of payment

  wa_company-datax-zterm = 'X'.

  append wa_company to wa_data-customer-company_data-company.


*--- Customer / Header --------------------------------------------
  wa_data-customer-header-object_task = 'I'.
  wa_data-customer-header-object_instance = lv_partner.



*--- Customer / Central data -------------------------------------
  wa_data-customer-central_data-address-task = 'M'. "Modify
  wa_data-customer-central_data-address-postal-data-from_date = sy-datum.
  wa_data-customer-central_data-address-postal-data-to_date = '99991231'.
  wa_data-customer-central_data-address-postal-data-name = 'Mark Langenhoven'.

  wa_data-ensure_create-create_customer = abap_true.

  "Finally fill the main data structure
  append wa_data to lt_data.


  call function 'CVI_EI_INBOUND_MAIN'
    exporting
      i_data   = lt_data
    importing
      e_return = lt_return.

  call function 'BAPI_TRANSACTION_COMMIT'.

  loop at lt_return into ls_return.
    loop at ls_return-object_msg into ls_retmsg.
      message id ls_retmsg-id type 'S' number ls_retmsg-number into lv_text
                  with ls_retmsg-message_v1 ls_retmsg-message_v2 ls_retmsg-message_v3 ls_retmsg-message_v4.
      write: / ' ', ls_retmsg-type, ls_retmsg-id, ls_retmsg-number, / '>>', lv_text.
    endloop.
  endloop.

  write: / 'Done'.

Thursday, January 21, 2016

Finding the correct BADi for the job

To be able to easily find the exact right BADi you need you can follow the steps below;

  • Go to t-code SE24
  • Pull up class CL_EXITHANDLER
  • Double click the GET_INSTANCE method
  • Put a break point on the CASE's sy-subrc line. (Roundabout line 28)
  • Now run the t-code you want the BADi for and check the EXIT_NAME field for the name of the BADI


Monday, November 16, 2015

Finding related data in SAP tables

Sometimes you need to find a seemingly obscure connection for some data that you have. E.g. you have a delivery number and you would like to know all the tables that that exact delivery number appears in so that you can search those records to find the second piece of information you're after.

Maybe you're trying to find all the links between a batch and a delivery so one of the tables you'll see is CHVW which might be exactly what you're after in your program's selections.

This is where my ZZFINDER program comes in handy. I use it multiple times on each project that I am on. You fill out the selection screen with the data you're after (including any leading zeroes) and hit F8.


The program will then come back with a list of table and field names to show you where this piece of data was found in the system.

So, here's the code to do this;

report zzfinder
       no standard page heading line-size 132.
* Mark Langenhoven 2015/11/14

*--- Data declarations ----------------------------------------------
"Record searching
tablesdd03ldd02l.

"Table searching
databegin of datarec,
        tabname   like dd03l-tabname,
        tabtext   like dd02t-ddtext,
        fieldname like dd03l-fieldname,
        fieldtext like dd03t-ddtext,
        data(80),
      end of datarec.
databegin of fieldrec,
        tabname   like dd03l-tabname,
        fieldname like dd03l-fieldname,
        tabclass  like dd02l-tabclass,
      end of fieldrec.

datagt_tfields like fieldrec occurs with header line.
datagt_tdata   like datarec occurs with header line.


*--- Selection screen -----------------------------------------------
selection-screen begin of block a1 with frame.
selection-screen begin of line.
selection-screen comment 1(22pdata.
parametersp_data type adrnr_txt.
selection-screen end of line.
selection-screen end of block a1.

selection-screen begin of block a2 with frame.

"Manual field definition
selection-screen begin of block a2a with frame.
selection-screen begin of line.
selection-screen comment 1(22stype.
select-options s_type for dd03l-datatype.
selection-screen end of line.

selection-screen begin of line.
selection-screen comment 1(22sleng.
select-options s_leng for dd03l-leng.
selection-screen end of line.

selection-screen begin of line.
selection-screen comment 1(22sdec.
select-options s_dec for dd03l-decimals.
selection-screen end of line.

selection-screen begin of line.
selection-screen comment 1(22sdom.
select-options s_dom for dd03l-domname.
selection-screen end of line.

selection-screen begin of line.
selection-screen comment 1(22skey.
select-options s_key for dd03l-keyflag no intervals.
selection-screen end of line.

selection-screen end of block a2a.

selection-screen comment 1(38eor.

"Field definition by example
selection-screen begin of block a2b with frame.
selection-screen begin of line.
selection-screen comment 1(22ptabnam.
parameters p_tabnam like dd03l-tabname.
selection-screen end of line.

selection-screen begin of line.
selection-screen comment 1(22pfieldn.
parameters p_fieldn like dd03l-fieldname.
selection-screen end of line.

selection-screen end of block a2b.

selection-screen end of block a2.

"Matching strategy
selection-screen begin of block a3 with frame.
selection-screen begin of line.
selection-screen comment 1(15pexact.
parameters p_exact radiobutton group smde.


selection-screen comment 25(15paddbf.
parameters p_addbf radiobutton group smde.
selection-screen end of line.

selection-screen end of block a3.

"Search limits
selection-screen begin of block a4 with frame.
selection-screen comment 1(35slimit.
selection-screen begin of line.
selection-screen comment 1(22stable.
select-options s_table for dd03l-tabname.
selection-screen end of line.

selection-screen begin of line.
selection-screen comment 1(22sfield.
select-options s_field for dd03l-fieldname.
selection-screen end of line.

"Exclude tables starting with a slash
selection-screen begin of line.
parametersp_noslsh as checkbox default 'X'.
selection-screen comment 5(22snoslash.
selection-screen end of line.

selection-screen end of block a4.



initialization.
  pdata   'Data to find'.
  stype   'Data type'.
  sleng   'Data length'.
  sdec    'Num. of decimals'.
  sdom    'Domain name'.
  skey    'Key flag'.
  eor     'Fill in block above OR block below'.
  ptabnam 'Reference table'.
  pfieldn 'Reference field'.
  pexact  'Match exactly'.
  paddbf  'Match subtext'.
  slimit  'Search limits:'.
  stable  'Search tables'.
  sfield  'Search fields'.
  snoslash 'Exclude tables with /'.


at selection-screen.
  perform validate_inputs.

*=== Main program ===================================================
start-of-selection.
  "Search through all tables to find some data
  perform search_all_tables.


at line-selection.
  perform goto_table using sy-cucol sy-lisel.


*&---------------------------------------------------------------------*
*&      Form  search_all_tables
*&---------------------------------------------------------------------*
form search_all_tables.

  "Check for wild cards
  if p_data cs '*'.
    p_addbf abap_true.
    p_exact abap_false.
    "Strip off the * because the selects don't like them
    translate p_data using ' `'.
    translate p_data using '* '.
    condense p_data no-gaps.
    translate p_data using '` '.
    message s000(38with 'Subset matching selected for wildcards'.
  endif.

  perform find_fields tables gt_tfields.

  perform find_data tables gt_tfields
                             gt_tdata.

  perform disp_data tables gt_tdata.

endform.                    "search_all_tables



*&---------------------------------------------------------------------*
*&      Form  VALIDATE_INPUTS
*&---------------------------------------------------------------------*
* Make sure we have valid stuff entered
*----------------------------------------------------------------------*
form validate_inputs .
  if p_data is initial.
    message e000(38with 'Enter some data to search for'.
  endif.

  "See if the user hasn't defined the field in some way or another
  if s_type[] is initial and
     s_dom[] is initial and
     p_tabnam is initial and
     p_fieldn is initial.
    message e000(38with 'Enter field definitions'.
  endif.

  if p_tabnam is not initial and
     p_fieldn is initial.
    message e000(38with 'Enter a table and field name in the definition'.
  endif.
  if p_tabnam is initial and
     p_fieldn is not initial.
    message e000(38with 'Enter a table and field name in the definition'.
  endif.

endform.                    " VALIDATE_INPUTS


*&---------------------------------------------------------------------*
*&      Form  find_fields
*&---------------------------------------------------------------------*
* Find the fields which match our search criteria
*----------------------------------------------------------------------*
form find_fields  tables   pt_fields structure fieldrec.

  databegin of dd02lrec,
          tabname  like dd02l-tabname,
          tabclass like dd02l-tabclass,
        end of dd02lrec.

  datalt_dd02l   like dd02lrec occurs with header line,
        lt_dd02l2  like dd02lrec occurs with header line,
        lv_lines   type i,
        lv_msg(50type c,
        lt_fields  like fieldrec occurs with header line.


  "Use the alternate field definition if the user has requested it
  perform build_fields.

  "If we are not dealing with an exact match, then allow for larger data elements
  if p_addbf abap_true.
    loop at s_leng .
      if s_leng-option 'EQ'.
        s_leng-option 'GE'.
        modify s_leng.
      endif.
    endloop.
  endif.

  "Exclude tables starting with /
  if p_noslsh abap_true.
    read table s_table with key low '/*'.
    if sy-subrc <> 0.
      s_table-low '/*'.
      s_table-option 'CP'.
      s_table-sign 'E'.
      append s_table.
    endif.

  endif.

  call function 'SAPGUI_PROGRESS_INDICATOR'
    exporting
      text 'Getting fields...'.


  select tabname fieldname from dd03l
        into corresponding fields of table lt_fields
        package size 10 "Can run for a long time
        where tabname in s_table
        and   fieldname in s_field
        and   datatype in s_type
        and   leng in s_leng
        and   decimals  in s_dec
        and   domname in s_dom
        and   keyflag in s_key.

    append lines of lt_fields to pt_fields.
    describe table pt_fields.
    lv_msg |Getting fields..{ sy-tfill }|.

    call function 'SAPGUI_PROGRESS_INDICATOR'
      exporting
        text lv_msg.


  endselect.


  check pt_fields[] is not initial.

  "Reduce the select time on the next two selects
  refresh lt_fields.
  append lines of pt_fields to lt_fields.
  sort lt_fields by tabname.
  delete adjacent duplicates from lt_fields comparing tabname.

  call function 'SAPGUI_PROGRESS_INDICATOR'
    exporting
      text 'Checking tables...'.

  "Make sure we only grab tables and not structures
  select tabname tabclass from dd02l into table lt_dd02l
         for all entries in lt_fields
         where tabname lt_fields-tabname
         and tabclass 'INTTAB' or
               tabclass 'APPEND' or
               tabclass 'VIEW' ).

  "Only activated tables allowed
  select tabname tabclass from dd02l into table lt_dd02l2
         for all entries in lt_fields
         where tabname lt_fields-tabname
         and   as4local <> 'A'.
  if sy-subrc 0.
    append lines of lt_dd02l2 to lt_dd02l.
  endif.

  sort lt_dd02l by tabname.
  delete adjacent duplicates from lt_dd02l comparing tabname.


  loop at lt_dd02l.
    delete pt_fields where tabname lt_dd02l-tabname.

    check sy-tabix mod 100 0.
    describe table pt_fields.
    lv_msg |Reducing fields..{ sy-tfill }|.

    call function 'SAPGUI_PROGRESS_INDICATOR'
      exporting
        text lv_msg.

  endloop.


  select tabname tabclass from dd02l into table lt_dd02l
           for all entries in pt_fields
           where tabname pt_fields-tabname.
  sort lt_dd02l by tabname.

  loop at pt_fields.
    read table lt_dd02l with key tabname pt_fields-tabname
                                binary search.
    pt_fields-tabclass lt_dd02l-tabclass.
    modify pt_fields.
  endloop.


  describe table pt_fields lines lv_lines.
  write:'Number of matching fields found: 'lv_lines.

*  message 'Done' type 'S'.

  call function 'SAPGUI_PROGRESS_INDICATOR'
    exporting
      text 'Fields selected'.

endform.                    " find_fields



*&---------------------------------------------------------------------*
*&      Form  find_data
*&---------------------------------------------------------------------*
* Search through our list of fields to see if we can find a match on
* our data
*----------------------------------------------------------------------*
form find_data  tables   pt_fields structure fieldrec
                         pt_data structure datarec.

  databegin of tabrec,
          data(80),
        end of tabrec.
  datalt_tab       like tabrec occurs with header line,
        lv_lines     type i,
        lv_total     type i,
        lv_tables    type i,
        lv_count     type i,
        lv_perc      type i,
        lv_cond      type string,
        lv_tabix(10),
        lv_msg(80).

  datals_old        like datarec,
        lv_counter(3type n.


  check pt_fields[] is not initial.

  describe table pt_fields lines lv_tables.

  loop at pt_fields .
    refresh lt_tab.

    "Update the job log with a status message
    lv_count sy-tabix mod 100.
    if lv_count 0.
*      WRITE sy-tabix TO lv_tabix.
      lv_msg | Searching table { sy-tabix } of { lv_tables } |.
      if lv_tables 0.
        lv_perc 0.
      else.
        lv_perc sy-tabix * 100 / lv_tables.
      endif.

      call function 'SAPGUI_PROGRESS_INDICATOR'
        exporting
          percentage lv_perc
          text       lv_msg.
    endif.

    refresh lt_tab.
    if p_exact abap_true.
      concatenate '''' p_data '''' into lv_cond.
      concatenate pt_fields-fieldname '=' lv_cond into lv_cond separated by space.
      select single (pt_fields-fieldnamefrom (pt_fields-tabname)
          into tabrec
          where (lv_cond).
      append tabrec to lt_tab.

    else.
      if pt_fields-tabclass 'POOL' or
         pt_fields-tabclass 'CLUSTER'.
        "Cannot optimize with DISTINCT on pool or cluster tables
        select (pt_fields-fieldnamefrom (pt_fields-tabname)
            into table lt_tab.

      else.

        select distinct (pt_fields-fieldnamefrom (pt_fields-tabname)
            into table lt_tab.

      endif.
    endif.

    if sy-subrc 0.

      describe table lt_tab lines lv_lines.
      lv_total lv_total + lv_lines.

      if p_exact abap_true.
        "Match the values exactly
        read table lt_tab with key data p_data.

        if sy-subrc 0.

          move-corresponding pt_fields to pt_data.
          pt_data-data lt_tab-data.
          append pt_data.

        endif.
      else.
        "Match any string which contains our string
        loop at lt_tab .
          find p_data in lt_tab-data.
          if sy-subrc 0.

            move-corresponding pt_fields to pt_data.
            pt_data-data lt_tab-data.
            append pt_data.

          endif.

        endloop.
      endif.

    endif.
  endloop.


  "Clean up the output a little bit
  sort pt_data.
  delete adjacent duplicates from pt_data.

  loop at pt_data.
    if pt_data-tabtext is initial.
      select single ddtext from dd02t into pt_data-tabtext
             where tabname pt_data-tabname
             and   ddlanguage sy-langu.
      modify pt_data transporting tabtext where tabname pt_data-tabname.
    endif.

    if pt_data-fieldtext is initial.
      select single ddtext from dd03t into pt_data-fieldtext
        where tabname pt_data-tabname
        and   fieldname pt_data-fieldname
        and   ddlanguage sy-langu.
      if sy-subrc <> 0.
        select single ddtext from dd04t into pt_data-fieldtext
          where rollname pt_data-fieldname
          and   ddlanguage sy-langu.
      endif.

      modify pt_data transporting fieldtext where fieldname pt_data-fieldname.
    endif.
  endloop.

  write'Number of data items checked   : 'lv_total.
  write/.

endform.                    " find_data


*&---------------------------------------------------------------------*
*&      Form  disp_data
*&---------------------------------------------------------------------*
* Display the data we found
*----------------------------------------------------------------------*
form disp_data  tables   pt_data structure datarec.

  datalv_lines(5type n.
  datals_old         like datarec,
        lv_count       type i,
        lv_line(90),
        lv_tabcount(5type n.

  "First write down what we searched for - useful for running multiple
  "background jobs
  write'Searched for: '.
  write/ p_data.

  skip.

  lv_count 0.
  lv_tabcount 0.
  loop at pt_data .
    "If we've searched for an exact value then there's no need to
    "display it for every table
    if p_exact is initial.

      if pt_data-tabname ls_old-tabname and
         pt_data-fieldname ls_old-fieldname.
        lv_count lv_count + 1.
        if lv_count 1.
          write'|        Multiple values found         ' color col_group,
                   at 86 '|'.
        endif.
      else.
        "If we have a single value then write it out for us to see
        if lv_count and ls_old is not initial.
          write'|'ls_old-dataat 86 '|'.
        endif.
        lv_count 0.
      endif.

    endif.

    ls_old pt_data.
    if lv_count > 0.
      continue.
    endif.

    uline (86).
    write'|''(Data)' hotspot,
             pt_data-tabname color col_heading hotspot,
             pt_data-fieldname color col_heading hotspot,
             at 86 '|'.
    write'|''      ',
             pt_data-tabtext(30color col_normal,
             pt_data-fieldtext(30color col_normal,
             at 86 '|'.

    lv_tabcount lv_tabcount + 1.

  endloop.

  if lv_count and ls_old is not initial.
    write'|''   'ls_old-dataat 86 '|'.
  endif.
  uline (86).


  describe table pt_data lines lv_lines.

  skip.
  "Format the output a little bit
  concatenate '$Found$' lv_lines '$records$in$' lv_tabcount '$tables' into lv_line.
  translate lv_line using '0 '.
  condense lv_line no-gaps.
  translate lv_line using '$ '.
  write/ lv_line.

  write.

  write' Done. '.

endform.                    " disp_data


*&---------------------------------------------------------------------*
*&      Form  build_fields
*&---------------------------------------------------------------------*
*If the user specified a table and field name, then use that to build up
*the datatype and other field parameters,
*----------------------------------------------------------------------*
form build_fields .

  datals_dd03l like dd03l.

  check p_tabnam is not initial and
        p_fieldn is not initial.

  select single from dd03l into ls_dd03l
        where tabname p_tabnam
        and   fieldname p_fieldn.

  check sy-subrc 0.

  refreshs_types_lengs_decs_doms_key.

  s_type-low ls_dd03l-datatype.
  s_type-sign 'I'.
  s_type-option 'EQ'.
  append s_type.

  s_leng-low ls_dd03l-leng.
  s_leng-sign 'I'.
  s_leng-option 'EQ'.
  append s_leng.

  s_dec-low ls_dd03l-decimals.
  s_dec-sign 'I'.
  s_dec-option 'EQ'.
  append s_dec.

  s_dom-low ls_dd03l-domname.
  s_dom-sign 'I'.
  s_dom-option 'EQ'.
  append s_dom.

  if ls_dd03l-keyflag abap_true.
    s_key-low ls_dd03l-keyflag.
    s_key-sign 'I'.
    s_key-option 'EQ'.
    append s_key.
  endif.

endform.                    " build_fields


*&---------------------------------------------------------------------*
*&      Form  goto_table
*&---------------------------------------------------------------------*
* Jump to the selected table
*----------------------------------------------------------------------*
form goto_table  using pv_pos
                       pv_line.

  datatabname      like dd03l-tabname,
        fieldname    like dd03l-fieldname,
        ls_gref      like tbprogref,
        progname     like rsvar-report,
        lv_dummy(10),
        lv_line(10),
        lt_sscr      like rsscr occurs with header line,
        ls_dd03l     like dd03l,
        ls_dd04l     like dd04l.

  datalt_params type table of rsparams,
        ls_param  type rsparams.



  split pv_line at space into lv_line lv_dummy tabname fieldname.
  condensetabnamefieldname.

  set parameter id 'DTB' field tabname.
  if pv_pos > 9.
    "The user wants to see the table and add more
    "selections to it
    call transaction 'SE16' and skip first screen.
    exit.
  endif.


  "User has selected the (Data) hotspot
  "See if we can plug the field name in via a parameter ID as well
  "so that we can go direct to the data instead of the data
  "selection screen
  select single from dd03l into ls_dd03l
             where tabname tabname
             and fieldname fieldname.
  if sy-subrc 0.
    select single from dd04l into ls_dd04l
            where rollname ls_dd03l-rollname
            and   domname ls_dd03l-domname.
    if sy-subrc and ls_dd04l-memoryid is not initial.
      set parameter id ls_dd04l-memoryid field p_data.
    endif.
  endif.

  select single from tbprogref into ls_gref
          where tabname tabname.
  if sy-subrc <> 0.
    "If we can't seem to find a program, then just
    "call the screen and let it sort the nonsense out
    call transaction 'SE16' and skip first screen.
  else.
    "Try to call the program manually with our additional
    "selection parameters
    concatenate '/1BCDWB/DB'  tabname into progname.

    load report progname part 'SSCR' into lt_sscr.

    refresh lt_params.
    loop at lt_sscr.
      if lt_sscr-dbfield cs fieldname.
        "Add our field to this selection
        ls_param-selname lt_sscr-name.
        ls_param-kind lt_sscr-kind.
        ls_param-option 'EQ'.
        ls_param-sign 'I'.
        "Put in all the fields we found in our earlier search
        loop at gt_tdata where tabname tabname
                        and fieldname fieldname.
          ls_param-low gt_tdata-data.
          append ls_param to lt_params.
        endloop.
      endif.
    endloop.

    "Display the data from the table directly the way
    "SE16 would
    call function 'RS_TABLE_LIST_CREATE'
      exporting
        table_name         tabname
      tables
        seltab             lt_params
      exceptions
        table_is_structure 1
        table_not_exists   2
        db_not_exists      3
        no_permission      4
        no_change_allowed  5
        others             6.
    if sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
    endif.

  endif.


endform.                    " goto_table