ABAP Quick - External currency to internal
A little tip to convert data from an Excel or CSV file into the correct internal currency format. A simple conversion can quickly lead to errors.
Table of contents
Today a little tip to convert external numbers, for example from an Excel file, into the internal currency format. Here we mainly deal with numbers that are displayed and stored as currency.
Hint: The screenshots shown refer to the output of the german number format for the formatted numbers with currency.
Currency format
The problem here is the currency format and how SAP stores such numbers in the system. Here is a simple example to shed light on the "problem" in more detail.
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 }| ).
We get the following result:
You have to know that the EUR currency is defined with two decimal places and the JPY currency has no decimal places. Our external input of 123456 therefore behaves correctly in the number field and as an output in EUR, as we have no shift of the decimal places. If we prepare the same number as JPY, then this number is 100 times too large. This is due to the internal storage and the external processing.
Editing
If we work with currencies, we therefore need the correct formatting and preparation of the numbers. We can use the RS_CONV_EX_2_IN function block for this. With the corresponding additional information, he takes the currency into account and correctly fills the internal number field accordingly. The block requires the external format in the corresponding language (see hint).
For our example code, we create a method that wraps the module and use a field from the FI document to prepare the currency. In this case we have to transfer the currency so that the function block knows how to process the number.
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.
To do this, we will use a few examples again and look at the finished preparation of the number. The examples look like this:
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` ) }| ).
We use the German and the English input format for numbers to see whether the logic can cope with different inputs. The output of the routine are now as follows:
The function module expects the German formats with commas and thousand points for our scenario. All outputs with a single-digit number are errors that the function block generated because the input format did not match. As you can see, the "real" number in JPY is much smaller in the field after the conversion, because it is saved internally without any decimal places.
Example
In addition, like the entire example as an executable class:
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.
Conclusion
The storage of currencies in SAP is very special and should be taken into account when working with internal and external numbers, especially when calculating in addition. With our little tip, the conversion should no longer be a problem.