Currency & Unit Conversion in ABAP erfordert besondere Beachtung von Dezimalstellen, Wechselkursen und Umrechnungsfaktoren. Die korrekte Handhabung ist entscheidend für Finanz- und Logistikanwendungen.
Grundkonzept
| Thema | Beschreibung |
|---|---|
| Währung | Dezimalstellen abhängig von Währung (EUR: 2, JPY: 0) |
| Wechselkurs | Kurse aus Tabelle TCURR |
| Mengeneinheit | Umrechnungsfaktoren in T006 |
| Intern vs. Extern | Unterschiedliche Darstellung |
Beispiele
1. Währungsbetrag konvertieren
DATA: lv_amount_eur TYPE bapicurr-bapicurr VALUE '1000.00', lv_amount_usd TYPE bapicurr-bapicurr, lv_rate TYPE bapi1093_0.
" EUR nach USD umrechnenCALL FUNCTION 'BAPI_CURRENCY_CONV_TO_EXTERNAL' EXPORTING currency = 'EUR' amount_internal = lv_amount_eur IMPORTING amount_external = lv_amount_eur.
CALL FUNCTION 'BAPI_EXCHANGERATE_GETDETAIL' EXPORTING rate_type = 'M' " Kurstyp from_curr = 'EUR' to_currncy = 'USD' date = sy-datum IMPORTING exch_rate = lv_rate EXCEPTIONS not_found = 1 OTHERS = 2.
IF sy-subrc = 0. lv_amount_usd = lv_amount_eur * lv_rate-exch_rate. WRITE: / '1000 EUR =', lv_amount_usd, 'USD'.ENDIF.2. Währungskonvertierung mit CONVERT_TO_LOCAL_CURRENCY
DATA: lv_source_amount TYPE dmbtr VALUE '1000.00', lv_target_amount TYPE dmbtr.
CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY' EXPORTING date = sy-datum foreign_amount = lv_source_amount foreign_currency = 'USD' local_currency = 'EUR' type_of_rate = 'M' IMPORTING local_amount = lv_target_amount EXCEPTIONS no_rate_found = 1 overflow = 2 no_factors_found = 3 no_spread_found = 4 derived_2_times = 5 OTHERS = 6.
IF sy-subrc = 0. WRITE: / '1000 USD =', lv_target_amount, 'EUR'.ELSE. WRITE: / 'Wechselkurs nicht gefunden'.ENDIF.3. Dezimalstellen nach Währung
DATA: lv_amount_eur TYPE netwr VALUE '123.45', lv_amount_jpy TYPE netwr VALUE '12345', lv_decimals TYPE i.
" Dezimalstellen einer Währung ermittelnSELECT SINGLE currdec FROM tcurx WHERE currkey = 'EUR' INTO @lv_decimals.
IF sy-subrc <> 0. lv_decimals = 2. " StandardENDIF.
WRITE: / 'EUR hat', lv_decimals, 'Dezimalstellen'.
" Für JPY (0 Dezimalstellen)SELECT SINGLE currdec FROM tcurx WHERE currkey = 'JPY' INTO @lv_decimals.
" lv_decimals = 0
" Betrag entsprechend Währung formatierenCLASS zcl_currency DEFINITION. PUBLIC SECTION. CLASS-METHODS: format_amount IMPORTING iv_amount TYPE any iv_currency TYPE waers RETURNING VALUE(rv_formatted) TYPE string.ENDCLASS.
CLASS zcl_currency IMPLEMENTATION. METHOD format_amount. DATA: lv_decimals TYPE i.
SELECT SINGLE currdec FROM tcurx WHERE currkey = @iv_currency INTO @lv_decimals.
IF sy-subrc <> 0. lv_decimals = 2. ENDIF.
rv_formatted = |{ iv_amount DECIMALS = lv_decimals }|. ENDMETHOD.ENDCLASS.4. Interne/Externe Währungsdarstellung
DATA: lv_internal TYPE bapicurr-bapicurr, lv_external TYPE bapicurr-bapicurr.
" Intern (DB) -> Extern (Anzeige)" Für Währungen mit weniger als 2 Dezimalstellenlv_internal = '12345'. " JPY in DB (ohne Dezimalen)
CALL FUNCTION 'BAPI_CURRENCY_CONV_TO_EXTERNAL' EXPORTING currency = 'JPY' amount_internal = lv_internal IMPORTING amount_external = lv_external.
" lv_external = '12345.00' für Anzeige
" Extern -> Intern (für Speicherung)lv_external = '12345.00'.
CALL FUNCTION 'BAPI_CURRENCY_CONV_TO_INTERNAL' EXPORTING currency = 'JPY' amount_external = lv_external max_number_of_digits = 15 IMPORTING amount_internal = lv_internal.
" lv_internal = '12345' für DB5. Mengeneinheiten konvertieren
DATA: lv_quantity_kg TYPE menge VALUE '1000', lv_quantity_to TYPE menge.
" kg nach t (Tonnen) umrechnenCALL FUNCTION 'UNIT_CONVERSION_SIMPLE' EXPORTING input = lv_quantity_kg unit_in = 'KG' unit_out = 'TO' IMPORTING output = lv_quantity_to EXCEPTIONS conversion_not_found = 1 division_by_zero = 2 input_invalid = 3 output_invalid = 4 overflow = 5 type_invalid = 6 units_missing = 7 unit_in_not_found = 8 unit_out_not_found = 9 OTHERS = 10.
IF sy-subrc = 0. WRITE: / '1000 KG =', lv_quantity_to, 'TO'. " 1 TOENDIF.6. Materialspezifische Mengenumrechnung
DATA: lv_quantity_st TYPE menge VALUE '100', " 100 Stück lv_quantity_kg TYPE menge.
" Umrechnung mit MaterialstammCALL FUNCTION 'MD_CONVERT_MATERIAL_UNIT' EXPORTING i_matnr = '000000000012345678' i_in_me = 'ST' " Von Stück i_out_me = 'KG' " Nach Kilogramm i_menge = lv_quantity_st IMPORTING e_menge = lv_quantity_kg EXCEPTIONS error_in_application = 1 error = 2 OTHERS = 3.
IF sy-subrc = 0. WRITE: / '100 ST =', lv_quantity_kg, 'KG'.ENDIF.7. Currency Helper Klasse
CLASS zcl_currency_helper DEFINITION. PUBLIC SECTION. TYPES: BEGIN OF ty_conversion_result, amount TYPE dmbtr, currency TYPE waers, rate TYPE ukurs, END OF ty_conversion_result.
CLASS-METHODS: convert IMPORTING iv_amount TYPE dmbtr iv_from_currency TYPE waers iv_to_currency TYPE waers iv_date TYPE sy-datum DEFAULT sy-datum iv_rate_type TYPE kurst DEFAULT 'M' RETURNING VALUE(rs_result) TYPE ty_conversion_result RAISING zcx_currency_error.
CLASS-METHODS: get_decimals IMPORTING iv_currency TYPE waers RETURNING VALUE(rv_decimals) TYPE i.
CLASS-METHODS: round_amount IMPORTING iv_amount TYPE dmbtr iv_currency TYPE waers RETURNING VALUE(rv_amount) TYPE dmbtr.
CLASS-METHODS: to_internal IMPORTING iv_amount TYPE dmbtr iv_currency TYPE waers RETURNING VALUE(rv_amount) TYPE dmbtr.
CLASS-METHODS: to_external IMPORTING iv_amount TYPE dmbtr iv_currency TYPE waers RETURNING VALUE(rv_amount) TYPE dmbtr.ENDCLASS.
CLASS zcl_currency_helper IMPLEMENTATION. METHOD convert. IF iv_from_currency = iv_to_currency. rs_result-amount = iv_amount. rs_result-currency = iv_to_currency. rs_result-rate = 1. RETURN. ENDIF.
CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY' EXPORTING date = iv_date foreign_amount = iv_amount foreign_currency = iv_from_currency local_currency = iv_to_currency type_of_rate = iv_rate_type IMPORTING local_amount = rs_result-amount exchange_rate = rs_result-rate EXCEPTIONS no_rate_found = 1 OTHERS = 2.
IF sy-subrc <> 0. RAISE EXCEPTION TYPE zcx_currency_error EXPORTING textid = zcx_currency_error=>rate_not_found from_currency = iv_from_currency to_currency = iv_to_currency. ENDIF.
rs_result-currency = iv_to_currency. ENDMETHOD.
METHOD get_decimals. SELECT SINGLE currdec FROM tcurx WHERE currkey = @iv_currency INTO @rv_decimals.
IF sy-subrc <> 0. rv_decimals = 2. " Standard ENDIF. ENDMETHOD.
METHOD round_amount. DATA(lv_decimals) = get_decimals( iv_currency ).
rv_amount = round( val = iv_amount dec = lv_decimals mode = cl_abap_math=>round_half_up ). ENDMETHOD.
METHOD to_internal. CALL FUNCTION 'BAPI_CURRENCY_CONV_TO_INTERNAL' EXPORTING currency = iv_currency amount_external = iv_amount max_number_of_digits = 23 IMPORTING amount_internal = rv_amount. ENDMETHOD.
METHOD to_external. CALL FUNCTION 'BAPI_CURRENCY_CONV_TO_EXTERNAL' EXPORTING currency = iv_currency amount_internal = iv_amount IMPORTING amount_external = rv_amount. ENDMETHOD.ENDCLASS.
" VerwendungTRY. DATA(ls_result) = zcl_currency_helper=>convert( iv_amount = '1000.00' iv_from_currency = 'USD' iv_to_currency = 'EUR' ).
WRITE: / '1000 USD =', ls_result-amount, 'EUR'. WRITE: / 'Kurs:', ls_result-rate.
CATCH zcx_currency_error INTO DATA(lx_error). WRITE: / lx_error->get_text( ).ENDTRY.8. Unit Helper Klasse
CLASS zcl_unit_helper DEFINITION. PUBLIC SECTION. CLASS-METHODS: convert IMPORTING iv_quantity TYPE menge iv_from_unit TYPE meins iv_to_unit TYPE meins iv_matnr TYPE matnr OPTIONAL RETURNING VALUE(rv_quantity) TYPE menge RAISING zcx_unit_error.
CLASS-METHODS: get_base_unit IMPORTING iv_matnr TYPE matnr RETURNING VALUE(rv_unit) TYPE meins.
CLASS-METHODS: get_conversion_factor IMPORTING iv_from_unit TYPE meins iv_to_unit TYPE meins RETURNING VALUE(rv_factor) TYPE f.ENDCLASS.
CLASS zcl_unit_helper IMPLEMENTATION. METHOD convert. IF iv_from_unit = iv_to_unit. rv_quantity = iv_quantity. RETURN. ENDIF.
" Materialspezifisch wenn Material angegeben IF iv_matnr IS NOT INITIAL. CALL FUNCTION 'MD_CONVERT_MATERIAL_UNIT' EXPORTING i_matnr = iv_matnr i_in_me = iv_from_unit i_out_me = iv_to_unit i_menge = iv_quantity IMPORTING e_menge = rv_quantity EXCEPTIONS error_in_application = 1 OTHERS = 2.
IF sy-subrc = 0. RETURN. ENDIF. ENDIF.
" Allgemeine Umrechnung CALL FUNCTION 'UNIT_CONVERSION_SIMPLE' EXPORTING input = iv_quantity unit_in = iv_from_unit unit_out = iv_to_unit IMPORTING output = rv_quantity EXCEPTIONS OTHERS = 1.
IF sy-subrc <> 0. RAISE EXCEPTION TYPE zcx_unit_error EXPORTING textid = zcx_unit_error=>conversion_failed from_unit = iv_from_unit to_unit = iv_to_unit. ENDIF. ENDMETHOD.
METHOD get_base_unit. SELECT SINGLE meins FROM mara WHERE matnr = @iv_matnr INTO @rv_unit. ENDMETHOD.
METHOD get_conversion_factor. DATA: lv_output TYPE menge.
CALL FUNCTION 'UNIT_CONVERSION_SIMPLE' EXPORTING input = CONV menge( 1 ) unit_in = iv_from_unit unit_out = iv_to_unit IMPORTING output = lv_output EXCEPTIONS OTHERS = 1.
IF sy-subrc = 0. rv_factor = lv_output. ELSE. rv_factor = 1. ENDIF. ENDMETHOD.ENDCLASS.9. Preisumrechnung
" Preis pro Mengeneinheit umrechnenDATA: lv_price TYPE netpr VALUE '10.00', " 10 EUR pro 100 ST lv_per_unit TYPE i VALUE 100, " Pro 100 lv_quantity TYPE menge VALUE '250', lv_total TYPE netwr.
" Gesamtpreis berechnenlv_total = lv_price * lv_quantity / lv_per_unit." 10.00 * 250 / 100 = 25.00 EUR
" Mit EinheitenumrechnungDATA: lv_price_kg TYPE netpr VALUE '2.50', " 2.50 EUR pro KG lv_qty_to TYPE menge VALUE '500', " 500 KG bestellt lv_total_to TYPE netwr.
" Erst in Tonnen umrechnenDATA(lv_qty_converted) = zcl_unit_helper=>convert( iv_quantity = lv_qty_to iv_from_unit = 'KG' iv_to_unit = 'TO').
" Preis für 1 TO berechnenDATA(lv_price_to) = lv_price_kg * 1000. " 2500 EUR pro TOlv_total_to = lv_price_to * lv_qty_converted.10. Wechselkurs pflegen
" Wechselkurse lesen (TCURR)SELECT * FROM tcurr WHERE kurst = 'M' " Kurstyp AND fcurr = 'USD' " Ausgangswährung AND tcurr = 'EUR' " Zielwährung AND gdatu <= @sy-datum " Gültig ab ORDER BY gdatu DESCENDING INTO TABLE @DATA(lt_rates) UP TO 1 ROWS.
IF lt_rates IS NOT INITIAL. DATA(ls_rate) = lt_rates[ 1 ]. WRITE: / 'Kurs:', ls_rate-ukurs. WRITE: / 'Gültig ab:', ls_rate-gdatu.ENDIF.
" Kurs per BAPI ändern (Customizing)DATA: lt_return TYPE TABLE OF bapiret2.
CALL FUNCTION 'BAPI_EXCHRATE_CREATEMULTIPLE' TABLES exchrate_list = lt_rates_new return = lt_return.
IF NOT line_exists( lt_return[ type = 'E' ] ). CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.ENDIF.11. Kaufmännische Rundung
DATA: lv_amount TYPE p DECIMALS 4 VALUE '123.4567', lv_rounded TYPE p DECIMALS 2.
" Mathematische Rundunglv_rounded = round( val = lv_amount dec = 2 )." 123.46
" Kaufmännische Rundung (halbe auf)lv_rounded = round( val = lv_amount dec = 2 mode = cl_abap_math=>round_half_up).
" Abrundenlv_rounded = floor( lv_amount * 100 ) / 100." 123.45
" Aufrundenlv_rounded = ceil( lv_amount * 100 ) / 100." 123.46
" Mit WährungDATA(lv_currency_amount) = zcl_currency_helper=>round_amount( iv_amount = lv_amount iv_currency = 'EUR').12. Beträge in SQL
" Währungsumrechnung in CDS View@AbapCatalog.viewEnhancementCategory: [#NONE]define view entity ZI_SalesAmount as select from vbak{ key vbeln, netwr, waerk,
// Betrag mit Dezimalkorrektur @Semantics.amount.currencyCode: 'waerk' netwr as Amount,
// In Hauswährung (vereinfacht) @Semantics.amount.currencyCode: 'EUR' cast(netwr as abap.curr(15,2)) as AmountEUR}
" In Open SQLSELECT vbeln, netwr, waerk, CURR_TO_DECFLOAT_AMOUNT( netwr, waerk ) AS amount_decimal FROM vbak INTO TABLE @DATA(lt_sales).13. ISO-Codes
" SAP-interne Codes vs. ISO-CodesDATA: lv_sap_currency TYPE waers VALUE 'EUR', lv_iso_currency TYPE isocd.
" SAP -> ISOSELECT SINGLE isocd FROM tcurc WHERE waession = @lv_sap_currency INTO @lv_iso_currency.
" ISO -> SAPSELECT SINGLE waers FROM tcurc WHERE isocd = 'EUR' INTO @lv_sap_currency.
" MengeneinheitenDATA: lv_sap_unit TYPE meins VALUE 'KG', lv_iso_unit TYPE isocd_unit.
SELECT SINGLE isocode FROM t006 WHERE msehi = @lv_sap_unit INTO @lv_iso_unit.Wichtige Tabellen
| Tabelle | Inhalt |
|---|---|
| TCURR | Wechselkurse |
| TCURC | Währungen |
| TCURX | Dezimalstellen |
| T006 | Mengeneinheiten |
| T006A | Einheitentexte |
| MARM | Materialmengeneinheiten |
Wichtige Hinweise / Best Practice
- Dezimalstellen immer währungsabhängig behandeln.
- BAPI_CURRENCY_CONV für SAP-konforme Konvertierung.
- Interne Darstellung für DB, externe für Anzeige.
- Rundung nach kaufmännischen Regeln.
- Kurstyp ‘M’ für Standard-Umrechnung.
- Materialspezifisch für genaue Mengenumrechnung.
- ISO-Codes für externe Schnittstellen.
- Semantics in CDS für korrekte Darstellung.
- Fehlerbehandlung bei nicht gefundenen Kursen.
- Kombinieren Sie mit BAPI Development für APIs.