on 2024 Oct 23 8:11 PM
Hi guys,
I've been doing some research about calling Odata Services Locally in S/4HANA Cloud Public Edition, but have just faced some issue and was wondering if any of you could help me.
We need to Create TM Freight Orders using a job, but the only Behavior Definition related to Freight Orders I_FreightOrderTP is allowed only to read orders, but doesn't allow to create them:
One solution we found is to call API_FREIGHTORDER from CPI, but man, why adding this complexity if we've been allowed during decades to do this kind of things locally using BAPIs?
Based on that, I found the following great post:
How to attach documents to a Journal Entry within SAP S/4HANA Public Cloud from ABAP.
I was able to replicate the same steps, but using the API_FREIGHTORDER.
I created the following outbound service (plus all the Communication Arrangement stuff)
I then created the following class:
CLASS y43tmcl_create_frgtorders IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
TRY.
* Create Destination
DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Y43TMCS_FREIGHT_ORDER_CR' "Outbound Scenario
service_id = 'Y43TMOS_FREIGHT_ORDER_CR_REST' "Outbound Service
).
* Create the HTTP Client
DATA(lo_http_client) = cl_web_http_client_manager=>create_by_http_destination( i_destination = lo_destination ).
lo_http_client->accept_cookies( abap_true ).
* Create the HTTP Request
DATA(lo_request) = lo_http_client->get_http_request( ).
* -------------------------------------------
* GET Operation - X-CSRF-TOKEN and COOKIE
* -------------------------------------------
DATA(lt_header_fields0) = lo_request->get_header_fields( ).
* Get x-csrf-token
lo_request->set_header_fields( VALUE #( ( name = 'Content-Type' value = 'application/json' )
( name = 'Accept' value = '*/*' )
( name = 'Connection' value = 'keep-alive' )
( name = 'x-csrf-token' value = 'fetch' ) ) ).
* Perform the HTTP GET Request
DATA(lo_response) = lo_http_client->execute( if_web_http_client=>get ).
* Get the Response Header Fields and read the eTag
DATA(lt_header_fields) = lo_response->get_header_fields( ).
DATA: lv_Cookie TYPE string.
LOOP AT lt_header_fields INTO DATA(ls_header_fields).
CASE ls_header_fields-name.
WHEN 'x-csrf-token'.
DATA(lv_xcsrftoken) = ls_header_fields-value.
WHEN 'set-cookie'.
IF lv_Cookie IS INITIAL.
lv_Cookie = ls_header_fields-value.
ELSE.
lv_Cookie = lv_Cookie && ';' && ls_header_fields-value.
ENDIF.
ENDCASE.
ENDLOOP.
* -------------------------------------------
* POST Operation - CREATE FREIGHT ORDER
* -------------------------------------------
lo_request->set_header_fields( VALUE #( ( name = 'Content-Type' value = 'application/json' )
( name = 'Accept' value = '*/*' )
( name = 'x-csrf-token' value = lv_xcsrftoken )
( name = 'Cookie' value = lv_Cookie ) ) ).
* Set the Service Path pointing to Freight Order for which we want to get the eTag
lo_request->set_uri_path( i_uri_path = '/SAP__self.CreateFreightOrder' ).
* Set Body Contents to be modified
lo_request->set_text( EXPORTING i_text = '{"TransportationOrderType":"SFO2"}' ).
* Perform the HTTP POST Request
lo_response = lo_http_client->execute( if_web_http_client=>post ).
* Get the status of the call
DATA(ls_status) = lo_response->get_status( ).
* Write the results on the Console Log
out->write( 'Status' ).
out->write( ls_status ).
DATA(lv_response) = lo_response->get_text( ).
out->write( lv_response ).
CATCH cx_root INTO DATA(lo_root).
out->write( lo_root->get_text( ) ).
ENDTRY.
ENDMETHOD.
ENDCLASS.
Problems I found
When I perform the Post Operation (using following code)
lo_request->set_uri_path( i_uri_path = '/SAP__self.CreateFreightOrder' ).
lo_request->set_text( EXPORTING i_text = '{"TransportationOrderType":"SFO2"}' ).
lo_response = lo_http_client->execute( if_web_http_client=>post ).
The Service Responds with 403 Forbidden
Solution?
The only solution I have found so far is by modifying the code. When I'm going to call the Get Operation, to get the CSRF Token, I first set the URI Path using the path of the Action itself
lo_request->set_uri_path( i_uri_path = '/SAP__self.CreateFreightOrder' ).
I'm aware this is not correct in terms of Service development, we shouldn't perform a Get operation on an Action, but this is the only way in which SAP doesn't return a 403 Forbidden error and allows me to create the order.
The problem with above solution is that, such Get Operation on an action triggers a Gateway error in the system.
Such error doesn't stop my logic in any way. But since this program is aimed to create Freight Orders massively, I would be adding a ton of Gateway errors per day in the system.
Final thoughts
Some additional comments:
If you have any advice here, I would really appreciate it.
Request clarification before answering.
Hi Diego,
I think you are on the right track by setting the URI patch when fetching the csrf-token.
What I do no understand is that you say "we shouldn't perform a Get operation on an Action".
If you do it in Postman manually, how would you do it? I always first send a GET to the service so to fetch the csrf-token, the request goes here:
and right after that I can post and create a supplier invoice in this example:
Kind regards,
Johannes
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
24 | |
22 | |
8 | |
5 | |
5 | |
4 | |
4 | |
4 | |
3 | |
3 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.