ABAP Tipp - Externe Währung nach Intern
Ein kleiner Tipp um Daten aus einer Excel oder CSV-Datei in das korrekte interne Währungsformat zu konvertieren. Eine einfach Konvertierung kann schnell zu Fehlern führen.
Inhaltsverzeichnis
Heute einmal ein kleiner Tipp um externe Zahlen, die zum Beispiel aus einer Excel Datei kommen, in das interne Währungsformat zu bringen. Hierbei gehen wir vor allem auf Zahlen ein, die als Währung dargestellt und gespeichert werden.
Hinweis: Die gezeigten Screenshots beziehen sich auf die Ausgabe des deutschen Zahlenformats für die formatierten Zahlen mit Währung.
Währungsformat
Das Problem ist hier das Währungsformat und wie SAP solche Zahlen im System ablegt. Dazu einmal ein einfaches Beispiel um das "Problem" genauer zu beleuchten.
DATA:
ld_internal_number TYPE bseg-wrbtr,
ld_output TYPE char20.
ld_internal_number = CONV #( '123456' ).
out->write( |Number: { ld_internal_number }| ).
WRITE ld_internal_number TO ld_output CURRENCY 'EUR'.
out->write( |EUR: { ld_output }| ).
WRITE ld_internal_number TO ld_output CURRENCY 'JPY'.
out->write( |JPY: { ld_output }| ).
Dabei erhalten wir das folgende Ergebnis:
Dabei musst du wissen, dass die Währung EUR mit zwei Nachkommastellen definiert ist und die Währung JPY keine Nachkommestellen besitzt. Unser externer Input von 123456 verhält sich deshalb im Zahlenfeld und als Ausgabe in EUR korrekt, da wir keine Verschiebung der Nachkommastellen haben. Bereiten wir die gleiche Zahl aber als JPY auf, dann ist diese Zahl um den Faktor 100 zu groß. Dies liegt an der internen Speicherung und der externen Aufbereitung.
Aufbereitung
Arbeiten wir mit Währungen benötigen wir daher die korrekte Formatierung und Aufbereitung der Zahlen. Dazu können wir den Funktionsbaustein RS_CONV_EX_2_IN verwenden. Mit entsprechenden Zusatzinformationen berücksicht er die Währung und befüllt das interne Zahlenfeld entsprechend korrekt. Dabei benötigt der Baustein das externe Format in der entsprechenden Sprache (siehe Hinweis).
Für unseren Beispielcode erzeugen wir eine Methode die den Baustein verschalt und verwenden Dabei ein Feld aus dem FI Beleg, um die Aufbereitung nach Währung zu machen. In diesem Fall müssen wir die Währung übergeben, damit der Funktionsbaustein weiß, wie er die Zahl aufbereiten soll.
METHOD convert_number_to_ext.
CALL FUNCTION 'RS_CONV_EX_2_IN'
EXPORTING
input_external = CONV char80( id_number )
table_field = VALUE tabfield( tabname = 'BSEG' fieldname = 'WRBTR' )
currency = id_currency
IMPORTING
output_internal = rd_result
EXCEPTIONS
input_not_numerical = 1
too_many_decimals = 2
more_than_one_sign = 3
ill_thousand_separator_dist = 4
too_many_digits = 5
sign_for_unsigned = 6
too_large = 7
too_small = 8
invalid_date_format = 9
invalid_date = 10
invalid_time_format = 11
invalid_time = 12
invalid_hex_digit = 13
unexpected_error = 14
invalid_fieldname = 15
field_and_descr_incompatible = 16
input_too_long = 17
no_decimals = 18
invalid_float = 19
conversion_exit_error = 20
OTHERS = 21.
IF sy-subrc <> 0.
rd_result = sy-subrc.
ENDIF.
ENDMETHOD.
Dazu verwenden wir wieder einige Beispiele und schauen uns die fertige Aufbereitung der Zahl an. Die Beispiele sehen wir folgt aus:
out->write( |EUR>123456.78: { convert_number_to_ext( id_currency = 'EUR' id_number = `123456.78` ) }| ).
out->write( |EUR>123456,78: { convert_number_to_ext( id_currency = 'EUR' id_number = `123456,78` ) }| ).
out->write( |EUR>123,456.78: { convert_number_to_ext( id_currency = 'EUR' id_number = `123,456.78` ) }| ).
out->write( |EUR>123.456,78: { convert_number_to_ext( id_currency = 'EUR' id_number = `123.456,78` ) }| ).
out->write( |JPY>123456: { convert_number_to_ext( id_currency = 'JPY' id_number = `123456` ) }| ).
out->write( |JPY>123,456: { convert_number_to_ext( id_currency = 'JPY' id_number = `123,456` ) }| ).
out->write( |JPY>123.456: { convert_number_to_ext( id_currency = 'JPY' id_number = `123.456` ) }| ).
Dabei verwenden wir einmal das deutsche und einmal das englische Eingabeformat für Zahlen, um zu sehen, ob die Logik mit verschiedenen Eingaben zurecht kommt. Die Ausgabe der Routine sind nun wie folgt aus:
Der Funktionsbaustein erwartet für unser Szenario die deutschen Formate mit Komma und Tausender Punkt. Alle Ausgaben mit einer einstelligen Zahl sind Fehler die der Funktionsbaustein erzeugt hat, weil das Eingabeformat nicht gepasst hat. Wie du sehen kannst ist die "echte" Zahl in JPY nach der Konvertierung viel kleiner im Feld, da Intern ohne Nachkommastellen gespeichert wird.
Beispiel
Dazu wie immer noch das gesamte Beispiel als ausführbare Klasse:
CLASS zcl_13bs_tst_convert_ext_num DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
METHODS:
convert_number_to_ext
IMPORTING
id_number TYPE string
id_currency TYPE waers
RETURNING VALUE(rd_result) TYPE bseg-wrbtr.
ENDCLASS.
CLASS zcl_13bs_tst_convert_ext_num IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
out->write( |EUR>123456.78: { convert_number_to_ext( id_currency = 'EUR' id_number = `123456.78` ) }| ).
out->write( |EUR>123456,78: { convert_number_to_ext( id_currency = 'EUR' id_number = `123456,78` ) }| ).
out->write( |EUR>123,456.78: { convert_number_to_ext( id_currency = 'EUR' id_number = `123,456.78` ) }| ).
out->write( |EUR>123.456,78: { convert_number_to_ext( id_currency = 'EUR' id_number = `123.456,78` ) }| ).
out->write( |JPY>123456: { convert_number_to_ext( id_currency = 'JPY' id_number = `123456` ) }| ).
out->write( |JPY>123,456: { convert_number_to_ext( id_currency = 'JPY' id_number = `123,456` ) }| ).
out->write( |JPY>123.456: { convert_number_to_ext( id_currency = 'JPY' id_number = `123.456` ) }| ).
ENDMETHOD.
METHOD convert_number_to_ext.
CALL FUNCTION 'RS_CONV_EX_2_IN'
EXPORTING
input_external = CONV char80( id_number )
table_field = VALUE tabfield( tabname = 'BSEG' fieldname = 'WRBTR' )
currency = id_currency
IMPORTING
output_internal = rd_result
EXCEPTIONS
input_not_numerical = 1
too_many_decimals = 2
more_than_one_sign = 3
ill_thousand_separator_dist = 4
too_many_digits = 5
sign_for_unsigned = 6
too_large = 7
too_small = 8
invalid_date_format = 9
invalid_date = 10
invalid_time_format = 11
invalid_time = 12
invalid_hex_digit = 13
unexpected_error = 14
invalid_fieldname = 15
field_and_descr_incompatible = 16
input_too_long = 17
no_decimals = 18
invalid_float = 19
conversion_exit_error = 20
OTHERS = 21.
IF sy-subrc <> 0.
rd_result = sy-subrc.
ENDIF.
ENDMETHOD.
ENDCLASS.
Fazit
Die Speicherung von Währungen in SAP ist sehr speziell und sollte beachtet werden, wenn mit internen und externen Zahlen gearbeitet wird, vor allem wenn dazu noch gerechnet wird. Mit unserem kleinen Tipp sollte die Konvertierung kein Problem mehr sein.