Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Can RTTS help to make just a part of the needed output columns dynamic?

BaerbelWinkler
Active Contributor
0 Kudos
620

I need to change a program which currently - in addition to lots of other information - gets configuration data for a configured material via function module VC_I_GET_CONFIGURATION. I already searched for an answer and by reading through some of them guess that it will be "No" but thought I'd put it out there anyway before reporting back to the requester.

This is how the output structure is currently defined via the DDIC:

.. many other fields and then the 9 paired fields for the configuration data (characterstics and attributes):

The MKMn_WRT and MKMn fields are filled somewhat dynamically based on the output from the FM:

        CALL FUNCTION 'VC_I_GET_CONFIGURATION'
          EXPORTING
            instance            = ls_vbap-cuobj
          TABLES
            configuration_idoc  = lt_konf
          EXCEPTIONS
            instance_not_found  = 1
            internal_error      = 2
            no_class_allocation = 3
            instance_not_valid  = 4
            OTHERS              = 5.
        IF sy-subrc <> 0.
          CLEAR: ls_vbap-mkm1, "... mkm9
          lv_flg_fehler_zeile   =   gc_x.  "Zeile farblich markieren
        ELSE.
*         Get configuration characteristics and attribute into table
          LOOP  AT  pt_merkm_sel   INTO  ls_merkm_sel.
            lv_ind_sel       =  sy-tabix.
            READ   TABLE lt_konf   INTO  ls_konf              "<--- only the first fitting entry is retreived, 
             WITH  KEY atnam       =  ls_merkm_sel-name_char. "<--- but there can be more
            IF  sy-subrc     EQ 0.
              PERFORM uebertr_merkmal
               USING ls_vbap ls_konf lv_ind_sel.
              IF  lv_flag_les EQ   gc_x.
                PERFORM feld_ausgabe_wert_festlegen
                 USING ls_param ls_konf lv_ind_sel.
              ENDIF.
            ENDIF.
          ENDLOOP.
*         Text for header only needs to be determined once
          CLEAR  lv_flag_les.
        ENDIF.


FORM uebertr_merkmal
 USING
  ps_vbap         TYPE  ts_vbap_gek
  ps_konf         TYPE  ts_konf
  pv_ind_sel      TYPE  i
  .
*
  FIELD-SYMBOLS:
   <lv_merkm_feld> TYPE any.
  DATA:
    lv_feld         TYPE  char30.
  CONSTANTS:
    lc_feld_name  TYPE  char30  VALUE 'ps_vbap-mkm',
    lc_feld_name1 TYPE  char30  VALUE '_wrt'.
* Description of characterstic value
  lv_feld            =   lc_feld_name.
  lv_feld+11(1)      =   pv_ind_sel.
  ASSIGN  (lv_feld)  TO  <lv_merkm_feld>.
  <lv_merkm_feld>    =   ps_konf-atwtb.
* characterstic value
  lv_feld+12(4)      =   lc_feld_name1.
  ASSIGN  (lv_feld)  TO  <lv_merkm_feld>.
  <lv_merkm_feld>    =   ps_konf-atwrt.
*
ENDFORM.                    " UEBERTR_MERKMAL


FORM feld_ausgabe_wert_festlegen
 USING
  ps_param        TYPE  ts_param
  ps_konf         TYPE  ts_konf
  pv_ind_sel      TYPE  i
  .
*
  DATA:
    lv_ind      TYPE  i,
    lv_ind1     TYPE  i,
    lv_ind_c(1) TYPE  c.

* Get description for ATNAM
  TRY.                           
      CALL METHOD lo_variant->check_component_for_mat2 
        EXPORTING
          iv_atwrt = ps_konf-atwrt
          iv_atnam = ps_konf-atnam                     
        IMPORTING
          ev_matnr = lv_matnr.
    CATCH zcx_de1l0vc_variants .                          
  ENDTRY.                            
*     Prüfen auf Baugruppen
  IF lv_matnr IS NOT INITIAL.                              
    lv_ind_c     =  pv_ind_sel.
    CONCATENATE  ps_param-ausgabe_wert
                 lv_ind_c
           INTO  ps_param-ausgabe_wert.
  ENDIF.
*
ENDFORM.                    " FELD_AUSGABE_WERT_FESTLEGEN

For the ALV-output, the headings and column properties are filled "manually" for the nine pairs of possible characterstics:

      WHEN 'KUNNR'.
        ps_fieldcat-ddictxt      =  'M'.     "Für Langtext
        ps_fieldcat-seltext_l    =  'Auftraggeber'.
        ps_fieldcat-seltext_m    =  'Auftraggeber'.
        ps_fieldcat-seltext_s    =  'Auftr-Geb.'.
      WHEN 'MKM1_WRT'.
        lv_ind          =    ps_fieldcat-fieldname+3(1).
        lv_ind_c        =    ps_fieldcat-fieldname+3(1).
        IF   lv_ind_max GE   lv_ind
         AND lv_ind_c   CO   ps_param-ausgabe_wert.
          READ  TABLE  pt_merkm_sel  INTO  ls_merkm_sel INDEX lv_ind.
          ps_fieldcat-ddictxt      =  'L'.     "Für Langtext
          CONCATENATE ls_merkm_sel-descr
                      gc_wert
                 INTO ps_fieldcat-seltext_l
                      SEPARATED BY space.
          ps_fieldcat-seltext_m    =  ls_merkm_sel-descr(20).
          ps_fieldcat-seltext_s    =  ls_merkm_sel-descr(10).
        ELSE.
          ps_fieldcat-tech        = 'X'.
        ENDIF.
      WHEN 'MKM1'.
        lv_ind          =    ps_fieldcat-fieldname+3(1).
        IF   lv_ind_max GE   lv_ind.
          READ  TABLE  pt_merkm_sel  INTO  ls_merkm_sel INDEX lv_ind.
          ps_fieldcat-ddictxt      =  'L'.     "Für Langtext
          CONCATENATE ls_merkm_sel-descr
                      gc_bez
                 INTO ps_fieldcat-seltext_l
                      SEPARATED BY space.
          ps_fieldcat-seltext_m    =  ls_merkm_sel-descr(20).
          ps_fieldcat-seltext_s    =  ls_merkm_sel-descr(10).
        ELSE.
          ps_fieldcat-tech        = 'X'.
        ENDIF.

I think that we have two options:

The first is to "simply" tweak the existing logic and fill another "pair" of characterstic columns for other than just the first fitting entry in LT_KONF for ATNAM. This could however lead to not all characterstics initially requested to be shown because we could be "running out of columns".

The second might be to build the MKMn part of the structure dynamically with the help of RTTS based on the data actually found in the selection. To do this, I think that I'd first have to get individual entries into what is currently LT_VBAP, one for each characterstic found in LT_KONF with all the other fields showing the content they now have. Once that is done, the RTTS logic could somehow kick in to build as many columns as needed for the characterstic values found for all entries.

Is this second option technically possible and even feasible to entertain? Note that the selection for the program allows just one material number but many sales orders. And each line item can have a different setup of this configurable material.

Oh, and I'm not really sure if I'd able to fully wrap my head around what I guess will be quite some involved piece of dynamic coding required for option 2.

We are on NW 7.50 EHP8.

Thanks much for any input you might have!

Cheers

Bärbel

1 ACCEPTED SOLUTION

MateuszAdamus
Active Contributor
441

Hello 8b889d0e8e6f4ed39f6c58e35664518f

Yes, it is possible. You can create the whole structure/table dynamically, if you'd like that.

In the example shown below the structure is created based on a configuration. The names and field types are stored in the AT_STRUCTURE_FIELDS internal table.

  DATA:
    ld_structure TYPE REF TO data,
    ls_component  TYPE abap_componentdescr,
    ld_table TYPE REF TO data,
    lt_components TYPE abap_component_tab,
    lo_internal_structure_type TYPE REF TO CL_ABAP_STRUCTDESCR,
    lo_internal_table_type TYPE REF TO CL_ABAP_TABLEDESCR.

  FIELD-SYMBOLS:
    <lt_table> TYPE STANDARD TABLE.

  " append fields of the structure
  LOOP AT at_structure_fields REFERENCE INTO DATA(ld_structure_field).
    ls_component-name = ld_structure_field->field_name.
    ls_component-type ?= cl_abap_datadescr=>describe_by_name( ld_structure_field->field_data_type ).
    APPEND ls_component TO lt_components.
  ENDLOOP.

  lo_internal_structure_type = cl_abap_structdescr=>get( lt_components ).
  lo_internal_table_type ?= cl_abap_tabledescr=>create( lo_internal_structure_type ).
  CREATE DATA ld_table TYPE HANDLE lo_internal_table_type.

  ASSIGN ld_table->* TO <lt_table>.
  CREATE DATA ld_structure LIKE LINE OF <lt_table>.

And to make only some of the fields dynamic, you should read the structure definition first and then add the dynamic fields depending on your conditions.

Kind regards,
Mateusz

6 REPLIES 6

MateuszAdamus
Active Contributor
442

Hello 8b889d0e8e6f4ed39f6c58e35664518f

Yes, it is possible. You can create the whole structure/table dynamically, if you'd like that.

In the example shown below the structure is created based on a configuration. The names and field types are stored in the AT_STRUCTURE_FIELDS internal table.

  DATA:
    ld_structure TYPE REF TO data,
    ls_component  TYPE abap_componentdescr,
    ld_table TYPE REF TO data,
    lt_components TYPE abap_component_tab,
    lo_internal_structure_type TYPE REF TO CL_ABAP_STRUCTDESCR,
    lo_internal_table_type TYPE REF TO CL_ABAP_TABLEDESCR.

  FIELD-SYMBOLS:
    <lt_table> TYPE STANDARD TABLE.

  " append fields of the structure
  LOOP AT at_structure_fields REFERENCE INTO DATA(ld_structure_field).
    ls_component-name = ld_structure_field->field_name.
    ls_component-type ?= cl_abap_datadescr=>describe_by_name( ld_structure_field->field_data_type ).
    APPEND ls_component TO lt_components.
  ENDLOOP.

  lo_internal_structure_type = cl_abap_structdescr=>get( lt_components ).
  lo_internal_table_type ?= cl_abap_tabledescr=>create( lo_internal_structure_type ).
  CREATE DATA ld_table TYPE HANDLE lo_internal_table_type.

  ASSIGN ld_table->* TO <lt_table>.
  CREATE DATA ld_structure LIKE LINE OF <lt_table>.

And to make only some of the fields dynamic, you should read the structure definition first and then add the dynamic fields depending on your conditions.

Kind regards,
Mateusz

0 Kudos
441

Thanks, Mateusz!

If I understand correctly, then there is a means to easily add the majority of the fields based on the DDIC-structure - namely all which don‘t start with MKM in their fieldname - and do „something special“ for „MKM“-fields? There are about 45 other fields in the structure which will always be the same for each entry - it‘s just the MKM-fields where there can be a variable number of columns for.

Given that the processing logic in the existing code is already rather complex, I‘d very much prefer an option where I can leave that untouched and only tweak the logic for the MKM-fields where needed, ideally as the last thing done to avoid breaking anything which happened earlier in the logic.

Cheers

Bärbel

441

Hello

I'd remove the MKM fields from the DDIC structure and add them dynamically if needed.

You can read the fields of the DDIC structure using RTTI, too.

DATA: 
  ls_component  TYPE abap_componentdescr,
  lo_structure TYPE REF TO cl_abap_structdescr.

lo_structure ?= cl_abap_typedescr=>describe_by_name( 'ZSDXALV_MAT_AUSW_INPUT' ).
DATA(lt_components) = lo_structure->get_components( ).

And then add the MKM fields if necessary.

IF mkm_field_needed.
  ls_component-name = 'KMK1_WRT'.
  ls_component-type ?= cl_abap_datadescr=>describe_by_name( 'ATWRT' ).
  APPEND ls_component TO lt_components.
  ls_component-name = 'KMK1'.
  ls_component-type ?= cl_abap_datadescr=>describe_by_name( 'ATWTB' ).
  APPEND ls_component TO lt_components.
ENDIF.

The field names should, of course, be generated dynamically to have a counter or some other distinct part.

Kind regards,

Mateusz

0 Kudos
441

mateuszadamus

Thanks again, Mateusz!

The content for ls_component-name will be depended on how many different characterstics and attributes are included in the selected data and I'm still trying to decide where and when in the code I'd best do that. It's currently happening shortly before the ALV-output gets generated based on everyting in LT_OUT. The current location where just one VBAP line item is looked at may not be suitable as there's no way of knowing which other items may have more than one attribute - I think I'll have to collect that information first in a separate internal table somehow.

What else I'm still wondering is how (or even if?) I can "generate" the variable part in such a way, that it's basically an interim detour in the program which then feeds back into the existing logic to actually create the ALV-output via the old ALV function modules where I'd just have to replace the fixed DDIC-structure name with "something else" or if that is not compatible with the RTTI/S stuff:

FORM fuellen_feldkatalog
 USING
  pt_fieldcat     TYPE  tt_fieldcat
  ps_fieldcat     TYPE  ts_fieldcat
  pt_merkm_sel    TYPE  tt_merkm_sel
  ps_param        TYPE  ts_param
  .
*
  DATA:
    lv_ind_c(1)     TYPE  c,
    ls_merkm_sel    TYPE  ts_merkm_sel,
    lv_ind          TYPE  i,
    lv_ind_max      TYPE  i,
    lv_ind_fieldcat TYPE  i.
*
  DESCRIBE  TABLE pt_merkm_sel  LINES  lv_ind_max.
*
  CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
    EXPORTING
      i_program_name         = lv_repid
      i_structure_name       = 'ZSDXALV_MAT_AUSW_INPUT'
    CHANGING
      ct_fieldcat            = pt_fieldcat
    EXCEPTIONS
      inconsistent_interface = 1
      program_error          = 2
      OTHERS                 = 3.
  IF sy-subrc NE 0.
    EXIT.
  ENDIF.

  LOOP AT pt_fieldcat   INTO ps_fieldcat.
    lv_ind_fieldcat            =  sy-tabix.
    CASE ps_fieldcat-fieldname.
      WHEN 'VBELN'.
....

Oh, and an additional functionality, I'm not sure can be retained with an even just partially generated dynamic fieldcatalog, is the usage of layout variants which the users currently employ liberally to only have the columns they are interested in displayed. Would that have to be deleted if we go down the RTTS-route? Or would the need to retain it be a showstopper for using RTTS and the users would have to decide which is more important for them?

Thanks for bearing with me and my questions!

Cheers

Bärbel

441

Hello

I would probably go with SALV table factory. This should handle the dynamic internal table definition nicely.

However, if this is not an option, what I would do is to generate the field catalog from the DDIC static structure and then add information about the MKM fields manually, as I'm adding the fields to the structure. You can make a method with generic field catalog information for these fields and just pass the new field's name as a parameter.

I'm not sure about the variants. I would assume that if a field is not found, then ALV does not crash due to a variant definition, thus allowing user to create variants for the dynamic structures too. But this is something you'd have to test and check.

Kind regards,
Mateusz

BaerbelWinkler
Active Contributor
0 Kudos
441

To at least somewhat wrap this up, I accepted Mateusz' answer even though we discovered that it will not be feasible to implement what I had in mind - the existing program is (way too) complex for that. We may go for a much simpler solution to create a new program which just handles the specific issue the users have where we'll simply have on line item per identified classification value.

Cheers

Bärbel