cancel
Showing results for 
Search instead for 
Did you mean: 

Unable to load FX rates from Central Bank Brazil

hohoman
Active Participant
0 Kudos
471

Hello,

I have problems extending my own report to load FX rates from different Banks to load the rates from the Central Bank in Brazil.

The template of my own report was the SAP Standard report for loading fx rates from the European Central Bank but I mainly only copied the HTTP_GET_BINARY and HTTP_GET_TEXT methods. I successfully implemented the load of rates from the MNB (HU), SRB (SE), SNB (CH) but now when I deal with the Brazilian Central Bank I do not get the connection working.

Based on the option you choose on the selection screen the system is creating an instance of another class therefore all classes are using the same interface the "Main" part of the program is quite lean and the itelligence is moved to the classes.

In the main class the most important routines are defined and implemented and in the subclasses differs in the way what file will be imported and how does the file structure looks like and how it has to be converted to TCURR format a.s.o.


For the BCB i wanted to do it the same way as for swedish bank. For the SRB I had the problem that I did not get the querystring properly integrated while using the RfC so I extended the HTTP_GET... method to use also a given URL directly after I filled a query table.

METHOD fill_query_table.
DATA: lw_query TYPE ty_query,
l_value TYPE char10,
l_value_str TYPE string.

lw_query-name = 'c'.
lw_query-value = 'cAverage'.
APPEND lw_query TO t_query.

lw_query-name = 'f'.
lw_query-value = 'Day'.
APPEND lw_query TO t_query.

IF p_up2dte EQ space.
lw_query-name = 'from'.
WRITE p_datum TO l_value.
REPLACE ALL OCCURRENCES OF '.' IN l_value WITH '/'.
lw_query-value = l_value.
* lw_query-value = cl_http_utility=>escape_url( l_value_str ).
APPEND lw_query TO t_query.
ELSE.
DATA(lv_datum) = p_datum. lv_datum = '20170101'.
WRITE lv_datum TO l_value. lw_query-value = l_value.
APPEND lw_query TO t_query.
ENDIF.

lw_query-name = 'g130-SEKATSPMI'.
lw_query-value = 'on'.
APPEND lw_query TO t_query.

lw_query-name = 'g130-SEKBEFPMI'.
lw_query-value = 'on'.
APPEND lw_query TO t_query.

______

*Set Query fields
fill_query_table( ).
*Get File
http_get_binary( EXPORTING i_dest = p_dest1
i_url = 'https://www.riksbank.se:443/en-gb/statistics/search-interest--exchange-rates/'
i_query = t_query
IMPORTING e_data = gv_raw_data_binary
EXCEPTIONS OTHERS = 1 ).

In this method http_get_binary I am converting the querystring and then add it to the URI.

IF i_query IS SUPPLIED.
DATA(l_path) = l_client->create_abs_url( ).
l_uri = cl_http_utility=>fields_to_string( EXPORTING fields = i_query ).
CONCATENATE l_path '?' l_uri INTO l_uri.
cl_http_utility=>set_request_uri( request = l_client->request uri = l_uri ).
ENDIF.

Before and after this part is nearly the same as in the ECB report ... Header fields are filled, SEND, RECEIVE and GET_DATA call ... The complete Method is shown at the end of my question.

When I am doing this for Brazil the system always reports HTTP 500 Connection Close.

The standard URL to get one currency pair is ...

https://olinda.bcb.gov.br/olinda/servico/PTAX/versao/v1/odata/CotacaoMoedaDia(moeda=@moeda,dataCotacao=@dataCotacao)?@moeda='EUR'&@dataCotacao='09-15-2023'&$top=100&$format=text/csv

So those @ and $ are generating me a headache because I only use my standard procedure the URI looks like and fails:

https://olinda.bcb.gov.br:443/olinda/servico/PTAX/versao/v1/odata/CotacaoMoedaDia(moeda=@moeda,dataC...;

The querystring is converted and all @ were replaced by %40 all ' by %27 all $ by %24 and the / by %2 ... SEND OKAY ... RECEIVE NOT OKAY ... COPIED into Browser everything works fine

Then I thought okay you are only encoding the query string do it also manually with the main part of the url.

https://olinda.bcb.gov.br:443/olinda/servico/PTAX/versao/v1/odata/CotacaoMoedaDia(moeda=%40moeda,dat...

Same effect .. SEND OK RECEIVE NOT OK COPIED to Browser everything works fine

Next try keep the @ and the $ but even this did not worked either.

In my last try I replaced my normal I_QUERY conversion and tried to use the SET_FORM_FIELD method.

Loop at i_query ASSIGNING FIELD-SYMBOL(<query>).
if <query>-name ne '$format'.
l_client->request->SET_FORM_FIELD( NAME = <query>-name VALUE = cl_http_utility=>escape_url( <query>-value ) ).
else.
l_client->request->SET_FORM_FIELD( NAME = <query>-name VALUE = <query>-value ).
endif.
Endloop.

now the system behavior changed ... SEND OK ... RECEIVE OK but the content of the BODY was crap.

~response_line : HTTP/1.1 400 Bad Request
~server_protocol : HTTP/1.1
~status_code : 400
~status_reason : Bad Request
date : Wed, 20 Sep 2023 15:00:21 GMT
x-oneagent-js-injection : true
x-content-type-options : nosniff
x-xss-protection : 1; mode=block
pragma : no-cache
expires : 0
strict-transport-security : max-age=16070400; includeSubDomains
x-frame-options : DENY
odata-version : 4.0
set-cookie : JSESSIONID=0000MMDIsc4zKJ7GtonquGA1U6a:1dof85j5r; Path=/; HttpOnly
server-timing : dtSInfo;desc="1"
set-cookie : dtCookie=v_4_srv_4_sn_602B069D7E552F7F37243B9DFCBD9A6F_perc_100000_ol_0_mul_1_app-3Aea7c4b59f27d43eb_1; Path=/; Domain=.bcb.gov.br
connection : close
content-language : en-US
set-cookie : BIGipServer~was_p_as3~was_p~pool_was_443_p=1020268972.47873.0000; path=/; Httponly; Secure
vary : Accept-Encoding
content-length : 64
set-cookie : TS013694c2=012e4f88b3965accc4200e7a710ad4d2d36d46e9cafadfff9454be3a7ba20e4dba48158bbd5b0a0fb5b0176d6f2fb0a530e1e9287e; Path=/
set-cookie : TS01d9825e=012e4f88b3965accc4200e7a710ad4d2d36d46e9cafadfff9454be3a7ba20e4dba48158bbd5b0a0fb5b0176d6f2fb0a530e1e9287e; path=/; domain=.bcb.gov.br
~remote_addr :
~uri_scheme_expanded : NONE
/*{#  "codigo" : 400,#  "mensagem" : "The URI is malformed."#}*/

I am totally lost now ... does anybody has some hints for me how can get this solved ... or does anybody have a report to load the fx rates.

Thank you in advance already for trying to read and understand my crazy thoughts.

Regards

Holger

=========================================

COMPLETE METHOD FILL_QERY_TABLE

METHOD fill_query_table.
DATA: lw_query TYPE ty_query,
l_value TYPE char10,
l_value_str TYPE string.


* lw_query-name = '@moeda'.
lw_query-name = '@moeda'.
CONCATENATE '''' 'EUR' '''' into lw_query-value.
* lw_query-value = 'EUR'.
APPEND lw_query TO t_query.

lw_query-name = '@dataCotacao'.
WRITE p_datum TO l_value.
REPLACE ALL OCCURRENCES OF '.' IN l_value WITH '-'.
CONCATENATE '''' l_value+3(2) '-' l_value+0(2) '-' l_value+6(4) '''' into lw_query-value.
* lw_query-value = cl_http_utility=>escape_url( l_value_str ).
APPEND lw_query TO t_query.

lw_query-name = '$top'.
lw_query-value = '100'.
APPEND lw_query TO t_query.

lw_query-name = '$format'.
lw_query-value = 'text/csv'.
APPEND lw_query TO t_query.

ENDMETHOD.

COMPLETE METHOD HTTP_GET_BINARY

METHOD http_get_binary.
DATA: l_client TYPE REF TO if_http_client,
lt_hfields TYPE tihttpnvp,
l_hfield TYPE ihttpnvp,
l_content TYPE xstring,
l_mess TYPE string,
l_subrc TYPE sy-subrc,
l_line(72) TYPE c,
l_len TYPE i,
l_len2 TYPE i,
l_uri TYPE string,
ls_err TYPE t_err_line,
l_str TYPE string.


* create connection
IF i_url IS SUPPLIED.
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = i_url
proxy_host =
proxy_service =
ssl_id =
IMPORTING
client = l_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.

ELSE.
CALL METHOD cl_http_client=>create_by_destination
EXPORTING
destination = i_dest
IMPORTING
client = l_client
EXCEPTIONS
argument_not_found = 1
destination_not_found = 2
destination_no_authority = 3
plugin_not_active = 4
internal_error = 5.
ENDIF.
IF sy-subrc <> 0.
* error
l_str = sy-subrc.
CONCATENATE TEXT-e05 l_str INTO ls_err-text SEPARATED BY space.
APPEND ls_err TO gt_err.
RAISE connection_error.
ENDIF.

IF i_query IS SUPPLIED.
* if p_bcb ne 'X'.
DATA(l_path) = l_client->create_abs_url( ).
l_uri = cl_http_utility=>fields_to_string( EXPORTING fields = i_query ).

if p_bcb eq 'X'.
replace ALL OCCURRENCES OF '%40' in l_uri WITH '@'.
REPLACE all OCCURRENCES OF '%24' in l_uri with '$'.
REPLACE all OCCURRENCES OF '%2f' in l_uri with '/' RESPECTING CASE.
endif.

CONCATENATE l_path '?' l_uri INTO l_uri.
cl_http_utility=>set_request_uri( request = l_client->request uri = l_uri ).
* else.
* l_client->request->SET_METHOD( 'POST' ).
* Data(l_method) = l_client->request->get_method( ).
* l_uri = l_path.
* cl_http_utility=>set_request_uri( request = l_client->request uri = l_uri ).
* Loop at i_query ASSIGNING FIELD-SYMBOL(<query>).
* if <query>-name ne '$format'.
* l_client->request->SET_FORM_FIELD( NAME = <query>-name VALUE = cl_http_utility=>escape_url( <query>-value ) ).
* else.
* l_client->request->SET_FORM_FIELD( NAME = <query>-name VALUE = <query>-value ).
* endif.
* Endloop.
* endif.
ENDIF.

* set header fields
CLEAR l_hfield.
l_hfield-name = '~request_method'. "#EC NOTEXT
l_hfield-value = 'GET'. "#EC NOTEXT
APPEND l_hfield TO lt_hfields.

CLEAR l_hfield.
l_hfield-name = '~server_protocol'. "#EC NOTEXT
l_hfield-value = 'HTTP/1.1'. "#EC NOTEXT
APPEND l_hfield TO lt_hfields.

CLEAR l_hfield.
l_hfield-name = 'cache-control'. "#EC NOTEXT
l_hfield-value = 'no-cache'. "#EC NOTEXT
APPEND l_hfield TO lt_hfields.

* if i_query is SUPPLIED.
* l_client->request->SET_METHOD( ).
* Data(l_method) = l_client->request->get_method( ).
* Loop at i_query ASSIGNING FIELD-SYMBOL(<query>).
* l_client->request->SET_FORM_FIELD( NAME = <query>-name VALUE = <query>-value ).
* Endloop.
* endif.


CALL METHOD l_client->request->set_header_fields
EXPORTING
fields = lt_hfields.

* get uri - for ECB it is defined in RFC definition
DATA(l_uri_shadow) = l_client->create_abs_url( ).
* send
CALL METHOD l_client->send
EXPORTING
timeout = 0
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
http_invalid_timeout = 4.

IF sy-subrc <> 0.
* error
CALL METHOD l_client->get_last_error
IMPORTING
code = l_subrc
message = l_mess.

l_str = l_subrc.
CONCATENATE TEXT-e06 l_str INTO ls_err-text SEPARATED BY space.
APPEND ls_err TO gt_err.
CONCATENATE TEXT-e07 l_mess INTO ls_err-text SEPARATED BY space.
APPEND ls_err TO gt_err.
RAISE connection_error.
ENDIF.

* receive
CALL METHOD l_client->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
OTHERS = 4.

IF sy-subrc <> 0.
CALL METHOD l_client->get_last_error
IMPORTING
code = l_subrc
message = l_mess.

l_str = l_subrc.
CONCATENATE TEXT-e06 l_str INTO ls_err-text SEPARATED BY space.
APPEND ls_err TO gt_err.
CONCATENATE TEXT-e07 l_mess INTO ls_err-text SEPARATED BY space.
APPEND ls_err TO gt_err.
RAISE connection_error.
ENDIF.

* get content
l_content = l_client->response->get_data( ).

* check content
CLEAR: l_hfield, lt_hfields.
REFRESH lt_hfields.

l_hfield-name = '~status_code'.
CALL METHOD l_client->response->get_header_field
EXPORTING
name = l_hfield-name
RECEIVING
value = l_hfield-value.

* 200 = OK, 404 = Error
IF l_hfield-value <> '200'.
DATA(l_content_err) = l_client->response->get_cdata( ).

* error
CALL METHOD l_client->response->get_header_fields
CHANGING
fields = lt_hfields.

* detail output list
LOOP AT lt_hfields INTO l_hfield.
CONCATENATE l_hfield-name ':' l_hfield-value INTO ls_err-text
SEPARATED BY space.
APPEND ls_err TO gt_err.
ENDLOOP.

* DESCRIBE FIELD l_content_err LENGTH l_len IN byte MODE.
l_len = strlen( l_content_err ).
CLEAR ls_err.
APPEND ls_err TO gt_err.

* output XML content
WHILE l_len > 0.
if l_len >= 72.
l_line = l_content_err+l_len2(72).
else.
l_line = l_content_err+l_len2(l_len).
endif.
ls_err-text = l_line.
APPEND ls_err TO gt_err.
l_len = l_len - 72.
l_len2 = l_len2 + 72.
ENDWHILE.
LOOP AT gt_err INTO ls_err.
WRITE: / ls_err.
ENDLOOP.
RAISE connection_error.
ENDIF.

* close connection
CALL METHOD l_client->close ##SUBRC_OK
EXCEPTIONS
http_invalid_state = 1
OTHERS = 2.

e_data = l_content.
ENDMETHOD.

Accepted Solutions (0)

Answers (0)