2021 Apr 14 9:14 AM
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
2021 Apr 14 9:30 AM
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
2021 Apr 14 9:30 AM
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
2021 Apr 14 9:28 PM
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
2021 Apr 15 8:24 AM
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,
Mateusz2021 Apr 15 10:23 AM
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
2021 Apr 15 10:33 AM
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,2021 Jun 11 9:59 AM
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