Financial Management Blogs by SAP
Get financial management insights from blog posts by SAP experts. Find and share tips on how to increase efficiency, reduce risk, and optimize working capital.
cancel
Showing results for 
Search instead for 
Did you mean: 
D059835
Advisor
Advisor
This post will share my experiences with you and guide you through the steps to connect your SAP Cloud for Real Estate API published by the SAP API Business Hub for Cloud for Real Estate to your SAP Cloud for Real Estate standard content available in SAP BW/4HANA since SP09.

Overview Architecture (Source: own representation)


Prerequisites are:

Steps are:

  1. Get the certificate of your SAP BTP and import it to your SAP BW/4HANA system.

  2. Create and configure a OAuth2 profile described in this blog post. Be sure, you managed your authorization objects (PFCG) before-hand.

  3. Configure a OAuth2 profile described in this blog post.

  4. Establish a connection to your SAP Cloud for Real Estate API either

    1. by destination (SM59) or

    2. by URL directly in the ABAP coding.



  5. Parse your JSON by using the ABAP JSON deserializer also described in this blog post and map your JSON attributes to your ABAP target structures.

  6. Write the results to ADSO type of Direct Update to the entry layer of the SAP Cloud for Real Estate standard content.


 

The steps in detail:

  1. Export the certificate from your SAP BTP instance: Best way is by calling the SAP Cloud for Real Estate REST API in your browser. You will get an 4xx error but you can download the certificate then from your browser by right clicking on the key symbol, right away. Next step is import this certificate via transaction STRUST in your SAP BW/4HANA System in your Anonym folder.

  2. First create a OAuth 2.0 profile in transaction SE80 as shown below and manage your scopes. You will get them (scopes) by calling the API endpoint to get the who am I information: <api_base_uri>/core/api/v0/whoami


  3. Now, configure your OAuth 2.0 profile via the transaction /nOA2C_CONFIG: 

    • putting in your <uaa_url> and also manage your OAuth 2.0 credentials with client id and client secrets, after you created your service keys.

    • the <uaa_url> should look like this: https://your_org_unit.authentication.sap.hana.ondemand.com and you will get them from your BTP service instance.

    • the Authorization Endpoint ends with /oauth/authorize

    • the Token Endpoint ends with /oauth/token





Steps 4 to 6 you can find in the following coding example. Here you can find a simple quick and dirty ABAP report for getting all buildings and its time-depended attributes:
*&---------------------------------------------------------------------*
*& Report ZREC4RE
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
report zrec4re.

data: profile type oa2c_profile,
target type string,
method type string,
lo_http_client type ref to if_http_client,
lo_oa2c_client type ref to if_oauth2_client,
lv_status_code type i,
lv_json_data type string,
lt_fields type tihttpnvp,
lx_oa2c type ref to cx_oa2c,
lr_data type ref to data,
ls_startdate type char10,
ls_enddate type char10,
ls_building type /b1h/ac_cre1202, "Buildings - structure of active table of ADSO /IMO/C_CRE120
lt_buildings type table of /b1h/ac_cre1202, "Buildings - active table of ADSO /IMO/C_CRE120
ls_statustimeline type /b1h/ac_cre2102, "StatusTimeline - structure of active table of ADSO /IMO/C_CRE210
lt_statustimeline type table of /b1h/ac_cre2102, "StatusTimeline - active table of ADSO /IMO/C_CRE210
ls_ownershipstatustimeline type /b1h/ac_cre2202, "OwnershipStatusTimeline - structure of active table of ADSO /IMO/C_CRE220
lt_ownershipstatustimeline type table of /b1h/ac_cre2202, "OwnershipStatusTimeline - active table of ADSO /IMO/C_CRE220
ls_usagetypetimeline type /b1h/ac_cre2402, "UsageTypeTimeline - structure of active table of ADSO /IMO/C_CRE240
lt_usagetypetimeline type table of /b1h/ac_cre2402. "UsageTypeTimeline - active table of ADSO /IMO/C_CRE240

field-symbols:
<ls_field> like line of lt_fields,
<data> type data,
<inner_data> type data,
<results> type any,
<inner_results> type any,
<structure> type any,
<inner_structure> type any,
<table> type any table,
<inner_table> type any table,
<field> type any,
<field_value> type data.

start-of-selection.

profile = 'ZREC4RE4'.
target = 'https://your_tenant.cfapps.sap.hana.ondemand.com/core/api/v0/buildings'.
method = 'GET'.

**********************************************************************
* Step 4: Create HTTP client by URL
**********************************************************************
call method cl_http_client=>create_by_url
exporting
url = target
ssl_id = 'ANONYM'
importing
client = lo_http_client
exceptions
argument_not_found = 1
plugin_not_active = 2
internal_error = 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.

lo_http_client->propertytype_logon_popup = 0.

call method lo_http_client->request->set_method
exporting
method = method.

**********************************************************************
* Set OAuth 2.0 Token
**********************************************************************
try.

call method cl_oauth2_client=>create
exporting
i_profile = profile
receiving
ro_oauth2_client = lo_oa2c_client.

catch cx_oa2c into lx_oa2c.
write: `Error calling CREATE.`.
write: / lx_oa2c->get_text( ).
return.
endtry.

try.

call method lo_oa2c_client->set_token
exporting
io_http_client = lo_http_client.

catch cx_oa2c into lx_oa2c.
try.

"CALL METHOD lo_oa2c_client->execute_refresh_flow.
call method lo_oa2c_client->execute_cc_flow.
catch cx_oa2c into lx_oa2c.
write: `Error calling EXECUTE_REFRESH_FLOW.`.
write: / lx_oa2c->get_text( ).
return.
endtry.
try.
call method lo_oa2c_client->set_token
exporting
io_http_client = lo_http_client.
catch cx_oa2c into lx_oa2c.
write: `Error calling SET_TOKEN.`.
write: / lx_oa2c->get_text( ).
return.
endtry.
endtry.

**********************************************************************
* Send / Receive Request
**********************************************************************
call method lo_http_client->send
exceptions
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
http_invalid_timeout = 4
others = 5.
if sy-subrc <> 0.
message id sy-msgid type sy-msgty number sy-msgno
with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
endif.

call method lo_http_client->receive
exceptions
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 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.

**********************************************************************
* Display result
**********************************************************************
call method lo_http_client->response->get_status
importing
code = lv_status_code.

if lv_status_code = 200.
call method lo_http_client->response->get_cdata
receiving
data = lv_json_data.

call method /ui2/cl_json=>deserialize
exporting
json = lv_json_data
pretty_name = /ui2/cl_json=>pretty_mode-user
assoc_arrays = abap_true
changing
data = lr_data.

else.
call method lo_http_client->response->get_header_fields
changing
fields = lt_fields.

loop at lt_fields assigning <ls_field>.
write: / <ls_field>-name, 25 <ls_field>-value.
endloop.
endif.

**********************************************************************
* Step 5: parse JSON result to target structure by using /ui2/cl_data_access
**********************************************************************
if lr_data is bound.

assign lr_data->* to <data>.
assign component `content` of structure <data> to <results>.
assign <results>->* to <table>.

loop at <table> assigning <structure>.

assign <structure>->* to <data>.

/ui2/cl_data_access=>create( iv_data = <data> iv_component = `irn`)->value( importing ev_data = ls_building-irn ).
/ui2/cl_data_access=>create( iv_data = <data> iv_component = `type`)->value( importing ev_data = ls_building-type ).
/ui2/cl_data_access=>create( iv_data = <data> iv_component = `siteIrn`)->value( importing ev_data = ls_building-siteirn ).
/ui2/cl_data_access=>create( iv_data = <data> iv_component = `constructionYear`)->value( importing ev_data = ls_building-constructionyear ).
/ui2/cl_data_access=>create( iv_data = <data> iv_component = `shortName`)->value( importing ev_data = ls_building-shortname ).
/ui2/cl_data_access=>create( iv_data = <data> iv_component = `longName`)->value( importing ev_data = ls_building-longname ).
/ui2/cl_data_access=>create( iv_data = <data> iv_component = `longitude`)->value( importing ev_data = ls_building-longitude ).
/ui2/cl_data_access=>create( iv_data = <data> iv_component = `latitude`)->value( importing ev_data = ls_building-latitude ).

assign component `statusTimeline` of structure <data> to <inner_results>.
assign <inner_results>->* to <inner_table>.

loop at <inner_table> assigning <inner_structure>.

assign <inner_structure>->* to <inner_data>.

/ui2/cl_data_access=>create( iv_data = <data> iv_component = `irn`)->value( importing ev_data = ls_statustimeline-irn ).
/ui2/cl_data_access=>create( iv_data = <inner_data> iv_component = `name`)->value( importing ev_data = ls_statustimeline-name ).
/ui2/cl_data_access=>create( iv_data = <inner_data> iv_component = `startDate`)->value( importing ev_data = ls_startdate ).
ls_statustimeline-startdate = |{ ls_startdate+0(4) }{ ls_startdate+5(2) }{ ls_startdate+8(2) }|.
/ui2/cl_data_access=>create( iv_data = <inner_data> iv_component = `endDate`)->value( importing ev_data = ls_enddate ).
ls_statustimeline-enddate = |{ ls_enddate+0(4) }{ ls_enddate+5(2) }{ ls_enddate+8(2) }|.

append ls_statustimeline to lt_statustimeline.
clear ls_statustimeline.
endloop.

assign component `ownershipStatusTimeline` of structure <data> to <inner_results>.
assign <inner_results>->* to <inner_table>.

loop at <inner_table> assigning <inner_structure>.

assign <inner_structure>->* to <inner_data>.

/ui2/cl_data_access=>create( iv_data = <data> iv_component = `irn`)->value( importing ev_data = ls_ownershipstatustimeline-irn ).
/ui2/cl_data_access=>create( iv_data = <inner_data> iv_component = `name`)->value( importing ev_data = ls_ownershipstatustimeline-name ).
/ui2/cl_data_access=>create( iv_data = <inner_data> iv_component = `startDate`)->value( importing ev_data = ls_ownershipstatustimeline-startdate ).
ls_ownershipstatustimeline-startdate = |{ ls_startdate+0(4) }{ ls_startdate+5(2) }{ ls_startdate+8(2) }|.
/ui2/cl_data_access=>create( iv_data = <inner_data> iv_component = `endDate`)->value( importing ev_data = ls_ownershipstatustimeline-enddate ).
ls_ownershipstatustimeline-enddate = |{ ls_enddate+0(4) }{ ls_enddate+5(2) }{ ls_enddate+8(2) }|.

append ls_ownershipstatustimeline to lt_ownershipstatustimeline.
clear ls_ownershipstatustimeline.
endloop.

assign component `usageTypeTimeline` of structure <data> to <inner_results>.
assign <inner_results>->* to <inner_table>.

loop at <inner_table> assigning <inner_structure>.

assign <inner_structure>->* to <inner_data>.

/ui2/cl_data_access=>create( iv_data = <data> iv_component = `irn`)->value( importing ev_data = ls_usagetypetimeline-irn ).
/ui2/cl_data_access=>create( iv_data = <inner_data> iv_component = `name`)->value( importing ev_data = ls_usagetypetimeline-name ).
/ui2/cl_data_access=>create( iv_data = <inner_data> iv_component = `startDate`)->value( importing ev_data = ls_usagetypetimeline-startdate ).
ls_usagetypetimeline-startdate = |{ ls_startdate+0(4) }{ ls_startdate+5(2) }{ ls_startdate+8(2) }|.
/ui2/cl_data_access=>create( iv_data = <inner_data> iv_component = `endDate`)->value( importing ev_data = ls_usagetypetimeline-enddate ).
ls_usagetypetimeline-enddate = |{ ls_enddate+0(4) }{ ls_enddate+5(2) }{ ls_enddate+8(2) }|.

append ls_usagetypetimeline to lt_usagetypetimeline.
clear ls_usagetypetimeline.
endloop.

append ls_building to lt_buildings.
clear ls_building.
endloop.

***********************************************************************
* "Step 6a: Write result to ADSO /IMO/C_CRE120
***********************************************************************
call function 'RSDSO_DU_WRITE_API'
exporting
i_adsonm = '/IMO/C_CRE120'
it_data = lt_buildings
i_insert_only = abap_false.

***********************************************************************
* "Step 6b: Write result to ADSO /IMO/C_CRE210
***********************************************************************
call function 'RSDSO_DU_WRITE_API'
exporting
i_adsonm = '/IMO/C_CRE210'
it_data = lt_statustimeline
i_insert_only = abap_false.

***********************************************************************
* "Step 6c: Write result to ADSO /IMO/C_CRE220
***********************************************************************
call function 'RSDSO_DU_WRITE_API'
exporting
i_adsonm = '/IMO/C_CRE220'
it_data = lt_ownershipstatustimeline
i_insert_only = abap_false.

***********************************************************************
* "Step 6d: Write result to ADSO /IMO/C_CRE240
***********************************************************************
call function 'RSDSO_DU_WRITE_API'
exporting
i_adsonm = '/IMO/C_CRE240'
it_data = lt_usagetypetimeline
i_insert_only = abap_false.


endif.

**********************************************************************
* Close HTTP client
**********************************************************************
call method lo_http_client->close
exceptions
http_invalid_state = 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.
**********************************************************************

 

Lessons learned:

In summary it was a easy walkover. The only thing was that at some point was not able to get a connection anymore. So I looked into the transaction logs via SMICM and found out that the certificate was expired. Just renew it and all works.

Additionally, I also want to mentioned if you have already SAP Cloud Platform Integration or SAP Data Intelligence in place then you also can connect the REST API to SAP BW/4HANA by those tools.

 
1 Comment