Dynpro
Minuszeichen vor dem Wert im ALV anzeigen
Dieser Beitrag zeigt einen praxisnahen SAP-ABAP-Lösungsansatz, um negative Werte im ALV mit vorangestelltem Minuszeichen darzustellen – inklusive Konvertierungsroutine, Berücksichtigung benutzerspezifischer Dezimalformate und einsatzfähigem Beispiel für die ALV-Praxis.
Anforderung an den Test
- Negative Zahlen im ALV mit dem Minuszeichen vor dem Wert darstellen.
- Die benutzerindividuelle Dezimaldarstellung aus den SU01/SU3-Einstellungen dabei erhalten.
Fragestellung und Entscheidung zur Umsetzung
- Lässt sich das mit Standardmitteln im ALV lösen?
- Nein. Weder der Feldkatalog noch das ALV-Layout bieten eine Möglichkeit zur Beeinflussung der Vorzeichenposition.
- Ist eine eigene Entwicklung erforderlich?
- Ja. Die Lösung besteht in einer benutzerdefinierten Konvertierungsroutine, die als Funktionsgruppe mit zwei Funktionsbausteinen angelegt wird.
Umsetzungsschritte
Hinweis: Warnhinweise und Dialoge zur Paketzuweisung wurden in diesem Artikel bewusst ausgelassen. Alle Objekte wurden für die Demonstration im Paket $TMP angelegt.
Was zu beachten ist
Beim Implementieren einer Konvertierungsroutine für numerische Werte muss die benutzerindividuelle Dezimaltrennung aus den SU3-Einstellungen berücksichtigt werden. Eine feste EDIT MASK reicht hier nicht aus; stattdessen sollte die locale-abhängige Formatierung über die Built-in-Funktionen des ABAPs ermittelt werden, damit die Ausgabe für verschiedene Benutzereinstellungen korrekt bleibt.
Konvertierungsroutine anlegen
Eine Konvertierungsroutine wird über einen fünfstelligen Namen identifiziert und besteht aus einem Paar von Funktionsbausteinen mit festgelegter Namenskonvention:
- CONVERSION_EXIT_xxxxx_INPUT - für die Umwandlung von der externen in die interne Darstellung.
- CONVERSION_EXIT_xxxxx_OUTPUT - für die Umwandlung von der internen in die externe Darstellung.
Funktionsgruppe anlegen
Navigiere zum Topinclude der Funktionsgruppe und füge den folgenden Code ein:
Code: TOP-Include anzeigen (4 Zeilen)
FUNCTION-POOL zstkoes_sign_conversion.
DATA gv_decimal_sign TYPE char1.
DATA gv_separator TYPE char1.
Funktionsbaustein Intern → Anzeige (OUTPUT)
Code: INPUT EXIT anzeigen (30 Zeilen)
" Get the Decimal Format from the user settings (SU01/SU3)
" Dezimaldarstellung aus den Benutzereinstellungen holen (SU01/SU3)
IF gv_decimal_sign IS INITIAL.
CALL FUNCTION 'CLSE_SELECT_USR01'
EXPORTING
username = sy-uname
iv_delete_buffer = abap_true
IMPORTING
decimal_sign = gv_decimal_sign
separator = gv_separator.
ENDIF.
DATA(lv_input) = CONV string( input ).
REPLACE ALL OCCURRENCES OF gv_separator IN lv_input WITH ''.
REPLACE gv_decimal_sign IN lv_input WITH '.'.
CONDENSE lv_input NO-GAPS.
TRY.
output = lv_input.
CATCH cx_sy_conversion_no_number.
" Clear message fields of sy structure,
" so that 'Conversion error' will be raised
" Alle Message Felder der sy Struktur löschen,
" damit 'Fehler bei der Konvertierung.' geworfen wird
CLEAR sy-msgty.
CLEAR sy-msgno.
CLEAR sy-msgv1.
CLEAR sy-msgv2.
CLEAR sy-msgv3.
CLEAR sy-msgv4.
RAISE error_message.
ENDTRY.
Code: INPUT EXIT (alte Syntax) anzeigen (31 Zeilen)
DATA: lv_input TYPE string.
" Get the Decimal Format from the user settings (SU01/SU3)
" Dezimaldarstellung aus den Benutzereinstellungen holen (SU01/SU3)
IF gv_decimal_sign IS INITIAL.
CALL FUNCTION 'CLSE_SELECT_USR01'
EXPORTING
username = sy-uname
iv_delete_buffer = abap_true
IMPORTING
decimal_sign = gv_decimal_sign
separator = gv_separator.
ENDIF.
lv_input = input.
REPLACE ALL OCCURRENCES OF gv_separator IN lv_input WITH ''.
REPLACE gv_decimal_sign IN lv_input WITH '.'.
CONDENSE lv_input NO-GAPS.
TRY.
output = lv_input.
CATCH cx_sy_conversion_no_number.
" Clear message fields of sy structure,
" so that 'Conversion error' will be raised
" Alle Message Felder der sy Struktur löschen,
" damit 'Fehler bei der Konvertierung.' geworfen wird
CLEAR sy-msgty.
CLEAR sy-msgno.
CLEAR sy-msgv1.
CLEAR sy-msgv2.
CLEAR sy-msgv3.
CLEAR sy-msgv4.
RAISE error_message.
ENDTRY.
Funktionsbaustein Anzeige → Intern (INPUT)
Code: OUTPUT EXIT anzeigen (35 Zeilen)
" Get the Decimal Format from the user settings (SU01/SU3)
" Dezimaldarstellung aus den Benutzereinstellungen holen (SU01/SU3)
IF gv_decimal_sign IS INITIAL.
CALL FUNCTION 'CLSE_SELECT_USR01'
EXPORTING
username = sy-uname
iv_delete_buffer = abap_true
IMPORTING
decimal_sign = gv_decimal_sign
separator = gv_separator.
ENDIF.
DATA(lv_input) = CONV string( input ).
DATA(lv_negativ_number) = xsdbool( lv_input CS '-' ).
REPLACE ALL OCCURRENCES OF '-' IN lv_input WITH ''.
SPLIT lv_input AT '.' INTO DATA(lv_number) DATA(lv_decimals).
DO strlen( lv_number ) TIMES.
IF sy-index EQ 1.
DATA(lv_mask) = |_|.
CONTINUE.
ENDIF.
lv_mask = |_{ COND #( WHEN sy-index MOD 3 EQ 1
THEN gv_separator ) }{
lv_mask }|.
ENDDO.
DO strlen( lv_decimals ) TIMES.
IF sy-index EQ 1.
lv_mask = |{ lv_mask }{ gv_decimal_sign }_|.
CONTINUE.
ENDIF.
lv_mask = |{ lv_mask }_|.
ENDDO.
lv_mask = |{ COND #( WHEN lv_negativ_number EQ abap_true
THEN |-| ) }{
lv_mask }|.
WRITE input TO output USING EDIT MASK lv_mask.
Code: OUTPUT EXIT (alte Syntax) anzeigen (42 Zeilen)
DATA lv_input TYPE string.
DATA lv_negativ_number TYPE abap_bool.
DATA lv_number TYPE string.
DATA lv_decimals TYPE string.
DATA lv_mask TYPE string.
" Get the Decimal Format from the user settings (SU01/SU3)
" Dezimaldarstellung aus den Benutzereinstellungen holen (SU01/SU3)
IF gv_decimal_sign IS INITIAL.
CALL FUNCTION 'CLSE_SELECT_USR01'
EXPORTING
username = sy-uname
iv_delete_buffer = abap_true
IMPORTING
decimal_sign = gv_decimal_sign
separator = gv_separator.
ENDIF.
lv_input = input.
lv_negativ_number = boolc( lv_input CS '-' ).
REPLACE ALL OCCURRENCES OF '-' IN lv_input WITH ''.
SPLIT lv_input AT '.' INTO lv_number lv_decimals.
DO strlen( lv_number ) TIMES.
IF sy-index EQ 1.
lv_mask = '_'.
CONTINUE.
ENDIF.
IF sy-index MOD 3 EQ 1.
CONCATENATE gv_separator lv_mask INTO lv_mask.
ENDIF.
CONCATENATE '_' lv_mask INTO lv_mask.
ENDDO.
DO strlen( lv_decimals ) TIMES.
IF sy-index EQ 1.
CONCATENATE lv_mask gv_decimal_sign '_' INTO lv_mask.
CONTINUE.
ENDIF.
CONCATENATE lv_mask '_' INTO lv_mask.
ENDDO.
IF lv_negativ_number EQ abap_true.
CONCATENATE '-' lv_mask INTO lv_mask.
ENDIF.
WRITE input TO output USING EDIT MASK lv_mask.
Aktivierung
Abschließend werden die Funktionsgruppe und beide Funktionsbausteine aktiviert.
Implementierung der Konvertierungsroutine
Es gibt zwei Ansatzpunkte für die Verwendung der Routine:
Konvertierungsroutine einer Domäne zuweisen:
Eine neue Domäne anlegen oder eine vorhandene kopieren und die Konvertierungsroutine der Domäne zuordnen. Felder, die auf dieser Domäne basieren, nutzen die Routine automatisch — auch im ALV.
Konvertierungsroutine zur Laufzeit im ALV zuweisen:
Im Demo-Report ist gezeigt, wie sich die Routine dynamisch über den Feldkatalog auf einzelne Spalten des ALV zuweisen lässt.
Demo Report
Der folgende Demo-Report zeigt die Zuweisung der Konvertierungsroutine zu ALV-Spalten zur Laufzeit.
Code: Demo Report anzeigen (78 Zeilen)
REPORT zstkoes_alv_sort.
TYPES:
BEGIN OF ts_mard,
matnr TYPE matnr,
werks TYPE werks_d,
lgort TYPE lgort_d,
labst TYPE labst,
zlabst TYPE zlabst,
h_level TYPE h_level,
END OF ts_mard.
TYPES tt_mard TYPE STANDARD TABLE OF ts_mard
WITH EMPTY KEY.
START-OF-SELECTION.
DATA(gt_mard) = VALUE tt_mard( ( matnr = CONV numc4( 1 )
werks = '0001
lgort = '0001'
labst = '-9.999'
zlabst = '-9.999'
h_level = -99999999 )
( matnr = CONV numc4( 1 )
werks = '0001'
lgort = '0002'
labst = '-99.999'
zlabst = '-99.999'
h_level = -9999999 )
( matnr = CONV numc4( 1 )
werks = '0002'
lgort = '0001'
labst = '-999.999'
zlabst = '-999.999'
h_level = -999999 )
( matnr = CONV numc4( 1 )
werks = '0002'
lgort = '0002'
labst = '-9999.999'
zlabst = '-9999.999'
h_level = -99999 )
( matnr = CONV numc4( 2 )
werks = '0001'
lgort = '0001'
labst = '-99999.999'
zlabst = '-99999.999'
h_level = -9999 )
( matnr = CONV numc4( 2 )
werks = '0001'
lgort = '0002'
labst = '-999999.999'
zlabst = '-999999.999'
h_level = -999 )
( matnr = CONV numc4( 2 )
werks = '0002'
lgort = '0001'
labst = '-9999999.999'
zlabst = '-9999999.999'
h_level = -99 )
( matnr = CONV numc4( 2 )
werks = '0002'
lgort = '0002'
labst = '-99999999.999'
zlabst = '-99999999.999'
h_level = -9 ) ).
END-OF-SELECTION.
cl_salv_table=>factory(
IMPORTING
r_salv_table = DATA(lo_table)
CHANGING
t_table = gt_mard ).
lo_table->get_functions( )->set_all( ).
DATA(it_column_ref) = lo_table->get_columns( )->get( ).
LOOP AT it_column_ref ASSIGNING FIELD-SYMBOL(<st_column_ref>).
CASE <st_column_ref>-columnname.
WHEN 'H_LEVEL'.
<st_column_ref>-r_column->set_edit_mask( value = '==ZSIGN' ).
ENDCASE.
ENDLOOP.
lo_table->display( ).
Code: Demo Report (alte Syntax) anzeigen (93 Zeilen)
REPORT zstkoes_alv_sort.
TYPES:
BEGIN OF ts_mard,
matnr TYPE matnr,
werks TYPE werks_d,
lgort TYPE lgort_d,
labst TYPE labst,
zlabst TYPE zlabst,
h_level TYPE h_level,
END OF ts_mard,
TYPES tt_mard TYPE STANDARD TABLE OF ts_mard.
DATA gt_mard TYPE tt_mard.
DATA gt_column_ref TYPE salv_t_column_ref.
DATA go_salv TYPE REF TO cl_salv_table.
FIELD-SYMBOLS <gs_mard> TYPE ts_mard.
FIELD-SYMBOLS <gs_column_ref> TYPE salv_s_column_ref.
START-OF-SELECTION.
APPEND INITIAL LINE TO gt_mard ASSIGNING <gs_mard>.
<gs_mard>-matnr = '0001'.
<gs_mard>-werks = '0001'.
<gs_mard>-lgort = '0001'.
<gs_mard>-labst = '-9.999'.
<gs_mard>-zlabst = '-9.999'.
<gs_mard>-h_level = -99999999.
APPEND INITIAL LINE TO gt_mard ASSIGNING <gs_mard>.
<gs_mard>-matnr = '0001'.
<gs_mard>-werks = '0001'.
<gs_mard>-lgort = '0002'.
<gs_mard>-labst = '-99.999'.
<gs_mard>-zlabst = '-99.999'.
<gs_mard>-h_level = -9999999.
APPEND INITIAL LINE TO gt_mard ASSIGNING <gs_mard>.
<gs_mard>-matnr = '0001'.
<gs_mard>-werks = '0002'.
<gs_mard>-lgort = '0001'.
<gs_mard>-labst = '-999.999'.
<gs_mard>-zlabst = '-999.999'.
<gs_mard>-h_level = -999999.
APPEND INITIAL LINE TO gt_mard ASSIGNING <gs_mard>.
<gs_mard>-matnr = '0001'.
<gs_mard>-werks = '0002'.
<gs_mard>-lgort = '0002'.
<gs_mard>-labst = '-9999.999'.
<gs_mard>-zlabst = '-9999.999'.
<gs_mard>-h_level = -99999.
APPEND INITIAL LINE TO gt_mard ASSIGNING <gs_mard>.
<gs_mard>-matnr = '0002'.
<gs_mard>-werks = '0001'.
<gs_mard>-lgort = '0001'.
<gs_mard>-labst = '-99999.999'.
<gs_mard>-zlabst = '-99999.999'.
<gs_mard>-h_level = -9999.
APPEND INITIAL LINE TO gt_mard ASSIGNING <gs_mard>.
<gs_mard>-matnr = '0002'.
<gs_mard>-werks = '0001'.
<gs_mard>-lgort = '0002'.
<gs_mard>-labst = '-999999.999'.
<gs_mard>-zlabst = '-999999.999'.
<gs_mard>-h_level = -999.
APPEND INITIAL LINE TO gt_mard ASSIGNING <gs_mard>.
<gs_mard>-matnr = '0002'.
<gs_mard>-werks = '0002'.
<gs_mard>-lgort = '0001'.
<gs_mard>-labst = '-9999999.999'.
<gs_mard>-zlabst = '-9999999.999'.
<gs_mard>-h_level = -99.
APPEND INITIAL LINE TO gt_mard ASSIGNING <gs_mard>.
<gs_mard>-matnr = '0002'.
<gs_mard>-werks = '0002'.
<gs_mard>-lgort = '0002'.
<gs_mard>-labst = '-99999999.999'.
<gs_mard>-zlabst = '-99999999.999'.
<gs_mard>-h_level = -9.
END-OF-SELECTION.
cl_salv_table=>factory(
IMPORTING
r_salv_table = go_salv
CHANGING
t_table = gt_mard ).
go_salv->get_functions( )->set_all( ).
gt_column_ref = go_salv->get_columns( )->get( ).
LOOP AT gt_column_ref ASSIGNING <gs_column_ref>.
CASE <gs_column_ref>-columnname.
WHEN 'H_LEVEL'.
<gs_column_ref>-r_column->set_edit_mask( value = '==ZSIGN' ).
ENDCASE.
ENDLOOP.
go_salv->display( ).
Ergebnis
Die Ausgabe verdeutlicht den Unterschied zwischen den Spalten:
- Die vierte Spalte „Frei verwendbar" ohne Konvertierungsroutine zeigt das Minuszeichen in der ALV-Standarddarstellung hinter dem Wert.
- Die fünfte Spalte „Frei verwendbar" mit Konvertierungsroutine zeigt das Minuszeichen wie erwartet vor dem Wert — bei zugleich erhaltener Dezimaldarstellung.
- Die sechste Spalte „Baugruppenstufe" ist ein INTEGER-Feld und demonstriert, dass die Routine gleichermaßen auch für Ganzzahlen funktioniert.