Custom program to Convert Amount from one currency to another currency
As most of the technical consultants know that how to convert the amount from one currency to another currency.
But in this blog I would like to give you a brief overview of calculating accurate Converted amount and Exchange rate values. I Hope It may useful for you while ABAP Coding.
Prerequisites
- Basic knowledge on ABAP.
Technical code explanation:
1. Initially the input file must contain four mandatory parameters
- Conversion Date
- From Currency
- From Amount
- To Currency (To what currency we would like to convert the input amount)
2. Output file structure
- Conversion Date
- From Currency
- From Amount
- To Currency
- To Amount
- Exchange Rate
3. Read data from the input excel file using FM: TEXT_CONVERT_XLS_TO_SAP.
4. Loop over all the input file records and pass the relevant input values to the standard SAP FM: CONVERT_TO_LOCAL_CURRENCY and consider only the below output parameters:
- Exchange rate
- Foreign factor
- Local factor
Note: Don’t consider the Converted amount (Local amount) directly from the FM: CONVERT_TO_LOCAL_CURRENCY. Instead there was a small logic to calculate the actual accurate CONVERTED AMOUNT by following the below logic:
*-Below is the logic to determine the Exact values of Conv. amt and Exc. Rate
IF lv_excrate IS NOT INITIAL.
IF lv_excrate GE 0.
lv_excrate_actual = lv_excrate / ( foreign / locfact ).
ELSE.
lv_excrate = lv_excrate * -1.
lv_excrate_actual = ( 1 / lv_excrate ) / ( foreign / locfact ).
ENDIF.
IF lv_excrate_actual NE 0.
converted_amt_actual = lr_ipfile->from_amt * lv_excrate_actual.
ENDIF.
ENDIF.
5. The above logic is used to calculate accurate Converted Amount and Exchange rate values even the exchange rate was maintained in either of the below blocks and even the input amount is Negative.
6. Technical coding part is as shown below, copy and paste the below logic in your systems and try to see the acurate results.
REPORT zrhramtconversion.
TYPE-POOLS: slis,truxs.
*-Structure declarations
TYPES: BEGIN OF ty_ipfile,
conv_date TYPE char8,
from_curr TYPE fcurr_curr,
from_amt TYPE dec11_4,
to_curr TYPE tcurr_curr,
to_amt TYPE maxbt,
exc_rate TYPE p DECIMALS 5,
message TYPE char255,
END OF ty_ipfile.
DATA:BEGIN OF lt_title OCCURS 2,
title(200),
END OF lt_title.
*-Declarations
DATA: lv_outfile TYPE string,
lv_msg TYPE string.
DATA: lt_ipfile TYPE TABLE OF ty_ipfile,
lv_date TYPE datum,
lt_outfile TYPE TABLE OF ty_ipfile.
DATA: lr_ipfile TYPE REF TO ty_ipfile.
DATA: converted_amt_actual TYPE p DECIMALS 3,
lv_amount TYPE p DECIMALS 3.
DATA: lv_excrate TYPE tkurs,
lv_excrate_actual TYPE ckrate,
foreign TYPE i,
locfact TYPE i,
excratex(8) TYPE p,
fixrate TYPE tcurr-ukurs,
derive TYPE tcurr-kurst.
*-Selection screen
SELECTION-SCREEN BEGIN OF BLOCK rad1
WITH FRAME TITLE title.
PARAMETERS: p_ipf LIKE rlgrap-filename OBLIGATORY, "Input File Path
p_outfl AS CHECKBOX USER-COMMAND c1, "Checkbox for output file
p_outf TYPE string MODIF ID id1. "Output File Path
SELECTION-SCREEN END OF BLOCK rad1.
INITIALIZATION.
title = text-001.
AT SELECTION-SCREEN OUTPUT.
LOOP AT SCREEN.
IF p_outfl <> 'X'.
CLEAR p_outf.
IF screen-group1 = 'ID1' .
screen-invisible = '1'.
screen-input = '0'.
screen-output = '0'.
ENDIF.
MODIFY SCREEN.
ENDIF.
ENDLOOP.
*-Input file F4 Functionality
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_ipf.
PERFORM fetch_file CHANGING p_ipf.
*-Directory browse for Output file
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_outf.
*-F4 help for getting directory in which output file should be downloaded
CALL METHOD cl_gui_frontend_services=>directory_browse
CHANGING
selected_folder = p_outf
EXCEPTIONS
cntl_error = 1
error_no_gui = 2
not_supported_by_gui = 3
OTHERS = 4.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
START-OF-SELECTION.
IF p_ipf IS NOT INITIAL.
*-Read data from XLS to Internal Table
PERFORM read_file TABLES lt_ipfile USING p_ipf.
ELSE.
MESSAGE text-002 TYPE 'E'.
ENDIF.
*-Loop Input file, Calculate the converted amounts and
* Fill the Output file
LOOP AT lt_ipfile REFERENCE INTO lr_ipfile.
CLEAR lv_date.
lv_date = lr_ipfile->conv_date.
CLEAR: sy-msgty,sy-msgid,sy-msgno,
sy-msgv1,sy-msgv2,sy-msgv3,sy-msgv4.
CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY'
EXPORTING
date = lv_date
foreign_amount = lr_ipfile->from_amt
foreign_currency = lr_ipfile->from_curr
local_currency = lr_ipfile->to_curr
rate = 0
type_of_rate = 'M'
read_tcurr = 'X'
IMPORTING
exchange_rate = lv_excrate
foreign_factor = foreign
local_amount = lv_amount
local_factor = locfact
exchange_ratex = excratex
fixed_rate = fixrate
derived_rate_type = derive
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.
lr_ipfile->message = text-011.
*-Below is the logic to determine the Exact values of Conv. amt and Exc. Rate
IF lv_excrate IS NOT INITIAL.
IF lv_excrate GE 0.
lv_excrate_actual = lv_excrate / ( foreign / locfact ).
ELSE.
lv_excrate = lv_excrate * -1.
lv_excrate_actual = ( 1 / lv_excrate ) / ( foreign / locfact ).
ENDIF.
IF lv_excrate_actual NE 0.
converted_amt_actual = lr_ipfile->from_amt * lv_excrate_actual.
ENDIF.
ENDIF.
lr_ipfile->to_amt = converted_amt_actual.
lr_ipfile->exc_rate = lv_excrate_actual.
ELSE.
IF lv_date IS INITIAL OR
lr_ipfile->from_amt IS INITIAL OR
lr_ipfile->from_curr IS INITIAL OR
lr_ipfile->to_curr IS INITIAL.
CONCATENATE text-012 text-013 INTO lr_ipfile->message
SEPARATED BY space.
ELSE.
*-Formatting the message to a required format
CALL FUNCTION 'FORMAT_MESSAGE'
EXPORTING
id = sy-msgid
lang = sy-langu
no = sy-msgno
v1 = sy-msgv1
v2 = sy-msgv2
v3 = sy-msgv3
v4 = sy-msgv4
IMPORTING
msg = lv_msg
EXCEPTIONS
not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
* MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
* WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
*-Filling Error message to the Output messages
IF lv_msg IS NOT INITIAL.
CONCATENATE text-012 lv_msg INTO lr_ipfile->message
SEPARATED BY space.
ENDIF.
ENDIF.
ENDIF.
CLEAR: lv_excrate_actual,converted_amt_actual,
lv_excrate,foreign,locfact,lv_msg.
ENDLOOP.
END-OF-SELECTION.
*-Assign updated input file to output file
lt_outfile[] = lt_ipfile[].
IF p_outf IS NOT INITIAL.
*-Output File path
CONCATENATE p_outf text-003 sy-datum sy-uzeit '.xls' INTO lv_outfile.
*-Fill Header for the Output file
PERFORM file_header .
*-Download the Output to Output File
PERFORM download.
ENDIF.
*-ALV Grid Output
PERFORM display.
*&---------------------------------------------------------------------*
*& Form FETCH_FILE
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* <--P_P_IPF text
*----------------------------------------------------------------------*
FORM fetch_file CHANGING p_p_ipf.
CALL FUNCTION 'F4_FILENAME'
IMPORTING
file_name = p_p_ipf.
ENDFORM. " FETCH_FILE
*&---------------------------------------------------------------------*
*& Form READ_FILE
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_LT_GRANT text
* -->P_P_IPF text
*----------------------------------------------------------------------*
FORM read_file TABLES p_lt_ipfile USING p_ipf.
DATA: ls_truxs TYPE truxs_t_text_data.
CALL FUNCTION 'TEXT_CONVERT_XLS_TO_SAP'
EXPORTING
i_line_header = 'X'
i_tab_raw_data = ls_truxs
i_filename = p_ipf
TABLES
i_tab_converted_data = p_lt_ipfile
EXCEPTIONS
conversion_failed = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM. " READ_FILE
*&---------------------------------------------------------------------*
*& Form FILE_HEADER
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM file_header.
lt_title-title = text-004.
APPEND lt_title.
lt_title-title = text-005.
APPEND lt_title.
lt_title-title = text-006.
APPEND lt_title.
lt_title-title = text-007.
APPEND lt_title.
lt_title-title = text-008.
APPEND lt_title.
lt_title-title = text-009.
APPEND lt_title.
lt_title-title = text-010.
APPEND lt_title.
ENDFORM. " FILE_HEADER
*&---------------------------------------------------------------------*
*& Form DOWNLOAD
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM download.
CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
filename = lv_outfile
filetype = 'DBF'
write_field_separator = 'X'
fieldnames = lt_title[]
CHANGING
data_tab = lt_outfile[]
EXCEPTIONS
file_write_error = 1
no_batch = 2
gui_refuse_filetransfer = 3
invalid_type = 4
no_authority = 5
unknown_error = 6
header_not_allowed = 7
separator_not_allowed = 8
filesize_not_allowed = 9
header_too_long = 10
dp_error_create = 11
dp_error_send = 12
dp_error_write = 13
unknown_dp_error = 14
access_denied = 15
dp_out_of_memory = 16
disk_full = 17
dp_timeout = 18
file_not_found = 19
dataprovider_exception = 20
control_flush_error = 21
not_supported_by_gui = 22
error_no_gui = 23
OTHERS = 24.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM. " DOWNLOAD
*&---------------------------------------------------------------------*
*& Form DISPLAY
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM display.
*-Declaration for ALV Grid
DATA : gr_table TYPE REF TO cl_salv_table.
DATA : gr_functions TYPE REF TO cl_salv_functions_list.
DATA : gr_columns TYPE REF TO cl_salv_columns_table,
gr_column TYPE REF TO cl_salv_column_table.
CLEAR : gr_table.
TRY.
CALL METHOD cl_salv_table=>factory
EXPORTING
list_display = if_salv_c_bool_sap=>false
IMPORTING
r_salv_table = gr_table
CHANGING
t_table = lt_outfile.
CATCH cx_salv_msg. "#EC NO_HANDLER
ENDTRY.
IF gr_table IS BOUND.
*-Get functions
gr_functions = gr_table->get_functions( ).
*-Enable Buttons in Tool Bar
gr_functions->set_all( if_salv_c_bool_sap=>true ).
*-Get the columns from table
gr_columns = gr_table->get_columns( ).
IF gr_columns IS BOUND.
gr_columns->set_optimize( if_salv_c_bool_sap=>true ).
CALL METHOD gr_columns->set_column_position
EXPORTING
columnname = 'CONV_DATE'
position = 1.
CALL METHOD gr_columns->set_column_position
EXPORTING
columnname = 'FROM_CURR'
position = 2.
CALL METHOD gr_columns->set_column_position
EXPORTING
columnname = 'FROM_AMT'
position = 3.
CALL METHOD gr_columns->set_column_position
EXPORTING
columnname = 'TO_CURR'
position = 4.
CALL METHOD gr_columns->set_column_position
EXPORTING
columnname = 'TO_AMT'
position = 5.
CALL METHOD gr_columns->set_column_position
EXPORTING
columnname = 'EXC_RATE'
position = 6.
CALL METHOD gr_columns->set_column_position
EXPORTING
columnname = 'MESSAGE'
position = 7.
TRY.
gr_column ?= gr_columns->get_column( 'CONV_DATE' ).
gr_column->set_short_text( 'Conv. Date' ).
gr_column->set_medium_text( 'Conv. Date' ).
gr_column->set_long_text( 'Conversion date' ).
CATCH cx_salv_not_found. "#EC NO_HANDLER
ENDTRY.
TRY.
gr_column ?= gr_columns->get_column( 'FROM_CURR' ).
gr_column->set_short_text( 'From Curr' ).
gr_column->set_medium_text( 'From Curr' ).
gr_column->set_long_text( 'From Currency' ).
CATCH cx_salv_not_found. "#EC NO_HANDLER
ENDTRY.
TRY.
gr_column ?= gr_columns->get_column( 'FROM_AMT' ).
gr_column->set_short_text( 'From Amt' ).
gr_column->set_medium_text( 'From Amt' ).
gr_column->set_long_text( 'From Amount' ).
CATCH cx_salv_not_found. "#EC NO_HANDLER
ENDTRY.
TRY.
gr_column ?= gr_columns->get_column( 'TO_CURR' ).
gr_column->set_short_text( 'To Curr' ).
gr_column->set_medium_text( 'To Curr' ).
gr_column->set_long_text( 'To Currency' ).
CATCH cx_salv_not_found. "#EC NO_HANDLER
ENDTRY.
TRY.
gr_column ?= gr_columns->get_column( 'TO_AMT' ).
gr_column->set_short_text( 'To Amt' ).
gr_column->set_medium_text( 'To Amt' ).
gr_column->set_long_text( 'To Amount' ).
CATCH cx_salv_not_found. "#EC NO_HANDLER
ENDTRY.
TRY.
gr_column ?= gr_columns->get_column( 'EXC_RATE' ).
gr_column->set_short_text( 'Exc. Rate' ).
gr_column->set_medium_text( 'Exc. Rate' ).
gr_column->set_long_text( 'Exchange Rate' ).
CATCH cx_salv_not_found. "#EC NO_HANDLER
ENDTRY.
TRY.
gr_column ?= gr_columns->get_column( 'MESSAGE' ).
gr_column->set_short_text( 'O/P Msg' ).
gr_column->set_medium_text( 'O/P Msg' ).
gr_column->set_long_text( 'Output Message' ).
CATCH cx_salv_not_found. "#EC NO_HANDLER
ENDTRY.
ENDIF.
CALL METHOD gr_table->display.
ENDIF.
ENDFORM. " DISPLAY
7. Selection texts:
8. Text Symbols:
9. Execution process:
Go to SE38 and execute the program “ZRHRAMTCONVERSION”.
10. Provide the Input file path as per required.
C:\Users\raghub\Desktop\Converstion Folder\Conv_Input_File.xls
11. Provide the Output file path as per required.
12. Click on Execute, to see the results
13. Output Results:
14. Output file downloaded like this:
15. Downloaded output file is as shown below: