Technical Articles
ABAP Restful Application Programming Model with Legacy BAPI
Summary
The research I have done for three months has shown that there is not much content produced on this subject(RAP with BAPIs). Because of this reason I decided to prepare a BAPI-based development example using RAP model over a real scenario.
While preparing this article, I have benefited greatly from this tutorial of Julie Plummer, which is the best resource I could access about unmanaged rap scenario. Thanks Julie.
To summarize, the restful programming logic works with a focus on Core Data Services. This CDS-focused structure can be configured with standard functions (such as BAPIs) that we have used in the legacy logics(brownfield scenario).
I suggest you look at the references below to get a good understanding of how the new RAP model works . In addition check out this resource to understand Save Sequence Runtime in ABAP Restful Application Programming Model.
If you don’t know anything about the ABAP Restful Application Programming Model . This openSap course is good starting point.
What will you learn?
In this example I will create “Unmanaged Restful Application Programming Model Scenario” with Legacy Appropriation Requests BAPIs and structures.
You’ll learn
1- How to create custom cds entity and implement a query provider class include BAPI_APPREQUEST_GETDETAIL’
2- How to create behavior definition and implementation include BAPI_APPREQUEST_CREATE function.
3- How to create service definition and service binding.
Legacy Codes Summary
- GET Appropriation Request Data through Legacy BAPI : ‘BAPI_APPREQUEST_GETDETAIL’
- CREATE Appropriation Request through BAPI: ‘BAPI_APPREQUEST_CREATE’
RAP Codes Summary
Get Appropriation Requests
- Create a Custom CDS Entity: ZHVL_IC_APPROPREQ
- Implement a query provider class: ZCL_APPROP_VIA_RFC->interface>if_rap_query_provider
Create Appropriation Request
- Create Behavior Definition for ZHVL_IC_APPROPREQ Custom CDS Entity
- Create Control Structure Name: ZHVL_CS_APPROP
- In Behavior Definition->create mapping for ZHVL_IC_APPROPREQ using control structure ZHVL_CS_APPROP
- Create Behavior Implementation->unmanaged implementation in class ZBP_HVL_IC_APPROPREQ
Create ODATA Service
- Create Service Definition
- Create Service Binding
1- Create Custom CDS Entity
@EndUserText.label: 'Approp Request Custom Cds Entity'
@ObjectModel.query.implementedBy: 'ABAP:ZCL_APPROP_VIA_RFC'
@UI: {
headerInfo: {
typeName: 'Approp Request',
typeNamePlural: 'Approp Requests'
}
}
define root custom entity ZHVL_IC_APPROPREQ
{
@UI.facet : [
{
id : 'AppropRequest',
purpose : #STANDARD,
type : #IDENTIFICATION_REFERENCE,
label : 'Approp Request',
position: 10 }
]
@UI : {
lineItem : [{position: 10, importance: #HIGH}],
identification : [{position: 10}],
selectionField : [{position: 10}]
}
key externalnumber : abap.char( 24 );
//MASTER DATA
@UI : {
lineItem : [{position: 20, importance: #HIGH}],
identification : [{position: 20}],
selectionField : [{position: 20}]
}
REQ_TXT : ima_txt50;
@UI : {
lineItem : [{position: 30, importance: #HIGH}],
identification : [{position: 30}],
selectionField : [{position: 30}]
}
RSP_COST_CENTER : ima_vkostl;
@UI : {
lineItem : [{position: 40, importance: #HIGH}],
identification : [{position: 40}],
selectionField : [{position: 40}]
}
APPR_DATE : ima_gdatu;
@UI : {
lineItem : [{position: 50, importance: #HIGH}],
identification : [{position: 50}],
selectionField : [{position: 50}]
}
ORIG_APPR_YEAR : ima_gjahr;
@UI : {
lineItem : [{position: 60, importance: #HIGH}],
identification : [{position: 60}],
selectionField : [{position: 60}]
}
//Variant Data
DESCRIPTION : ima_txv50;
@UI : {
lineItem : [{position: 70, importance: #HIGH}],
identification : [{position: 70}],
selectionField : [{position: 70}]
}
COMPLETION_DATE : ima_fdatu;
START_UP_DATE : ima_idatu;
//PLAN TOTAL
OVERHEAD_COSTS : bapicurr_d;
// ORG_UNITS
REQ_COST_CENTER : ima_akostl;
PERCENTAGE : ima_aproz;
//PARTNER DATA
PARTNER_FUNCTION : abap.char( 2 );
PARTNER : i_parnr;
//PLAN_YEAR
FISCAL_YEAR : gjahr;
INV_PROG : im_prnam;
APPR_YEAR : im_gnjhr;
PROGRAM_POS : abap.char( 24 );
PERCENT_PROG_POS : im_prozu;
}
2- Implement a query provider class to get the data, using a BAPI (Business Application Programming Interface)
CLASS zcl_approp_via_rfc DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_rap_query_provider .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_approp_via_rfc IMPLEMENTATION.
METHOD if_rap_query_provider~select.
TYPES: BEGIN OF ty_approp,
externalnumber TYPE ima_posid,
req_txt TYPE ima_txt50,
rsp_cost_center TYPE ima_vkostl,
appr_date TYPE ima_gdatu,
orig_appr_year TYPE ima_gjahr,
description TYPE ima_txv50,
completion_date TYPE ima_fdatu,
start_up_date TYPE ima_idatu,
overhead_costs TYPE bapicurr_d,
req_cost_center TYPE ima_akostl,
percentage TYPE ima_aproz,
partner_function TYPE parvw,
partner TYPE i_parnr,
fiscal_year TYPE gjahr,
inv_prog TYPE im_prnam,
appr_year TYPE im_gnjhr,
program_pos TYPE im_posid,
percent_prog_pos TYPE im_prozu,
END OF ty_approp.
DATA: ls_approp_req TYPE ty_approp.
DATA: lt_approp_req TYPE STANDARD TABLE OF ty_approp.
DATA: ls_master_data TYPE bapiappreqmaster,
ls_controlling TYPE bapi_appreq_id-cntrl_area,
lt_org TYPE TABLE OF bapiappreqorgunit,
lt_partner TYPE TABLE OF bapiappreqpartnerout,
lt_pos TYPE TABLE OF bapiappreqexpprogassgn,
lt_variant TYPE TABLE OF bapiappreqvarntmulti,
lt_plantot TYPE TABLE OF bapiappreqplantotalmulti,
lt_planyear TYPE TABLE OF bapiappreqplanyearmulti,
lt_return TYPE TABLE OF bapiret2.
"Set RFC destination
TRY.
"data(lo_rfc_dest) = cl_rfc_destination_provider=>proxy_type_onpremise(
"i_name = ''
").
"DATA(lv_rfc_dest_name) = lo_rfc_dest->get_destination_name( ).
"Check if data is requested
IF io_request->is_data_requested( ).
* DATA lv_maxrows TYPE int4.
* DATA(lv_skip) = io_request->get_paging( )->get_offset( ).
* DATA(lv_top) = io_request->get_paging( )->get_page_size( ).
* lv_maxrows = lv_skip + lv_top.
io_request->get_paging( )->get_offset( ).
io_request->get_paging( )->get_page_size( ).
"Call BAPI
CALL FUNCTION 'BAPI_APPREQUEST_GETDETAIL'
EXPORTING
externalnumber = '2.018E11-016288'
* language =
* language_iso =
IMPORTING
master_data = ls_master_data
* user_fields =
"controlling_area = ls_controlling
TABLES
org_units = lt_org
* division =
* material_group =
* invest_reason =
* environmnt_invest =
* assets_equis =
* order =
* wbs_element =
partner = lt_partner
assignment_to_pos = lt_pos
* assignment_to_budg_categ =
variant = lt_variant
* variant_to_version =
* assigned_apprequests =
plan_total = lt_plantot
plan_year = lt_planyear
* plan_total_obj =
* plan_year_obj =
return = lt_return.
ENDIF.
ls_approp_req-externalnumber = '2.018E11-016288'.
ls_approp_req-req_txt = ls_master_data-req_txt.
ls_approp_req-rsp_cost_center = ls_master_data-rsp_cost_center.
ls_approp_req-appr_date = ls_master_data-appr_date.
ls_approp_req-orig_appr_year = ls_master_data-orig_appr_year.
READ TABLE lt_org INTO DATA(ls_org) INDEX 1.
ls_approp_req-req_cost_center = ls_org-req_cost_center.
ls_approp_req-percentage = ls_org-percentage.
READ TABLE lt_partner INTO DATA(ls_partner) INDEX 1.
ls_approp_req-partner_function = ls_partner-partner_function.
ls_approp_req-partner = ls_partner-partner.
READ TABLE lt_pos INTO DATA(ls_pos) INDEX 1.
ls_approp_req-inv_prog = ls_pos-inv_prog.
ls_approp_req-appr_year = ls_pos-appr_year.
ls_approp_req-percent_prog_pos = ls_pos-percent_prog_pos.
ls_approp_req-program_pos = ls_pos-program_pos.
READ TABLE lt_variant INTO DATA(ls_variant) INDEX 1.
ls_approp_req-req_cost_center = ls_variant-description.
ls_approp_req-start_up_date = ls_variant-start_up_date.
READ TABLE lt_plantot INTO DATA(ls_plantot) INDEX 1.
ls_approp_req-overhead_costs = ls_plantot-overhead_costs.
READ TABLE lt_planyear INTO DATA(ls_planyear) INDEX 1.
ls_approp_req-fiscal_year = ls_planyear-fiscal_year.
APPEND ls_approp_req TO lt_approp_req.
CLEAR ls_approp_req.
"Set total no. of records
io_response->set_total_number_of_records( lines( lt_approp_req ) ).
"Output data
io_response->set_data( lt_approp_req ).
CATCH cx_rfc_dest_provider_error INTO DATA(lx_dest).
ENDTRY.
ENDMETHOD.
ENDCLASS.
3- Create Behavior Definition for ZHVL_IC_APPROPREQ
unmanaged implementation in class zbp_hvl_ic_appropreq unique;
define behavior for ZHVL_IC_APPROPREQ alias approp
//late numbering
//lock master
//etag master <field_name>
{
create;
update;
delete;
mapping for ZHVL_IC_APPROPREQ control zhvl_cs_approp
{
externalnumber = externalnumber;
req_txt = req_txt;
rsp_cost_center = rsp_cost_center;
appr_date = appr_date;
orig_appr_year = orig_appr_year;
description = description;
completion_date = completion_date;
start_up_date = start_up_date;
overhead_costs = overhead_costs;
req_cost_center = req_cost_center;
percentage = percentage;
partner_function = partner_function;
partner = partner;
fiscal_year = fiscal_year;
inv_prog = inv_prog;
appr_year = appr_year;
program_pos = program_pos;
percent_prog_pos = percent_prog_pos;
}
}
3.1- Create control structure: zhvl_cs_approp
@EndUserText.label : 'Control Structure For Approp Req'
@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE
define structure zhvl_cs_approp {
externalnumber : xsdboolean;
req_txt : xsdboolean;
rsp_cost_center : xsdboolean;
appr_date : xsdboolean;
orig_appr_year : xsdboolean;
description : xsdboolean;
completion_date : xsdboolean;
start_up_date : xsdboolean;
overhead_costs : xsdboolean;
req_cost_center : xsdboolean;
percentage : xsdboolean;
partner_function : xsdboolean;
partner : xsdboolean;
fiscal_year : xsdboolean;
inv_prog : xsdboolean;
appr_year : xsdboolean;
program_pos : xsdboolean;
percent_prog_pos : xsdboolean;
}
4- Create a custom RFC function module and call legacy BAPI in this function module.**IMPORTANT
Important Note:
RAP framework does not allow Commit/Rollback statements, as the framework itself internally takes care for committing/roll backing entities. If you try calling BAPI directly in behavior implementation class methods. You’ll get a dump.Because of this reason,We will call this RFC enabled function with destination none in behavior implementation class.(this may not be the best method. But I couldn’t find a better way,If anyone can find a better way, I would appreciate it if they write in the comments section.)
FUNCTION zhvl_approp_req
IMPORTING
VALUE(legacy_entity_in) TYPE zhvl_ic_appropreq
EXPORTING
VALUE(gv_ext) TYPE bapi_appreq_id-appreq
VALUE(gv_appr) TYPE bapi_appreq_id-appreqvrnt.
DATA messages TYPE bapiret2.
DATA : ls_masterdata TYPE bapiappreqmaster.
DATA: lt_org TYPE TABLE OF bapiappreqorgunit,
lt_partner TYPE TABLE OF bapiappreqpartner,
lt_pos TYPE TABLE OF bapiappreqexpprogassgn,
lt_variant TYPE TABLE OF bapiappreqvarntmulti,
lt_plantot TYPE TABLE OF bapiappreqplantotalmulti,
lt_planyear TYPE TABLE OF bapiappreqplanyear,
lt_return TYPE TABLE OF bapiret2.
DATA: ls_org TYPE bapiappreqorgunit,
ls_partner TYPE bapiappreqpartner,
ls_pos TYPE bapiappreqexpprogassgn,
ls_variant TYPE bapiappreqvarnt,
ls_plantot TYPE bapiappreqplantotal,
ls_planyear TYPE bapiappreqplanyear,
ls_return TYPE bapiret2.
ls_masterdata-req_txt = legacy_entity_in-req_txt.
ls_masterdata-rsp_cost_center = legacy_entity_in-rsp_cost_center.
ls_masterdata-appr_date = legacy_entity_in-appr_date.
ls_masterdata-orig_appr_year = legacy_entity_in-orig_appr_year.
ls_variant-description = legacy_entity_in-description.
ls_variant-completion_date = legacy_entity_in-completion_date.
ls_variant-start_up_date = legacy_entity_in-start_up_date.
ls_plantot-overhead_costs = legacy_entity_in-overhead_costs.
ls_org-req_cost_center = legacy_entity_in-req_cost_center.
ls_org-percentage = legacy_entity_in-percentage.
APPEND ls_org TO lt_org.
* ls_partner-partner_function = legacy_entity_in-partner_function.
* ls_partner-partner = legacy_entity_in-partner.
* APPEND ls_partner TO lt_partner.
ls_partner-partner_function = 'I1'.
ls_partner-partner = 'user1'.
APPEND ls_partner TO lt_partner.
ls_partner-partner_function = 'I2'.
ls_partner-partner = 'user1'.
APPEND ls_partner TO lt_partner.
ls_partner-partner_function = 'I3'.
ls_partner-partner = 'user2'.
APPEND ls_partner TO lt_partner.
ls_partner-partner_function = 'I4'.
ls_partner-partner = 'user2'.
APPEND ls_partner TO lt_partner.
ls_partner-partner_function = 'I5'.
ls_partner-partner = 'user2'.
APPEND ls_partner TO lt_partner.
ls_partner-partner_function = 'I6'.
ls_partner-partner = 'user3'.
APPEND ls_partner TO lt_partner.
ls_planyear-fiscal_year = legacy_entity_in-fiscal_year.
ls_planyear-overhead_costs = legacy_entity_in-overhead_costs.
APPEND ls_planyear TO lt_planyear.
ls_pos-inv_prog = legacy_entity_in-inv_prog.
ls_pos-appr_year = legacy_entity_in-appr_year.
ls_pos-program_pos = legacy_entity_in-program_pos.
ls_pos-percent_prog_pos = legacy_entity_in-percent_prog_pos.
APPEND ls_pos TO lt_pos.
CALL FUNCTION 'BAPI_APPREQUEST_CREATE'
EXPORTING
apprequest_type = '10'
appropriationrequest_in = legacy_entity_in-externalnumber
appropriationrequestvariant_in = ''
controlling_area = 'A000'
master_data = ls_masterdata
"user_fields = ls_user
variant = ls_variant
plan_total = ls_plantot
test_run = ''
IMPORTING
externalnumber = gv_ext
appropriationrequestvariantout = gv_appr
TABLES
org_units = lt_org
"division = lt_division
"material_grp = lt_matgroup
"investment_reason = lt_investrea
"environmnt_invest = lt_environve
"orders = lt_order
"wbs_element = lt_wbselement
"variant_to_version = lt_variant
partner = lt_partner
assignment_to_pos = lt_pos
plan_year = lt_planyear
return = lt_return.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.
ENDFUNCTION.
5- Create Behavior Implementation: class ZBP_HVL_IC_APPROPREQ.
CLASS lhc_ZHVL_IC_APPROPREQ DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE approp.
METHODS delete FOR MODIFY
IMPORTING keys FOR DELETE approp.
METHODS update FOR MODIFY
IMPORTING entities FOR UPDATE approp.
METHODS read FOR READ
IMPORTING keys FOR READ approp RESULT result.
ENDCLASS.
CLASS lhc_ZHVL_IC_APPROPREQ IMPLEMENTATION.
METHOD create.
DATA legacy_entity_in TYPE zhvl_ic_appropreq.
DATA: gv_ext TYPE bapi_appreq_id-appreq,
gv_appr TYPE bapi_appreq_id-appreqvrnt.
LOOP AT entities ASSIGNING FIELD-SYMBOL(<entity>).
legacy_entity_in = CORRESPONDING #( <entity> MAPPING FROM ENTITY USING CONTROL ).
CALL FUNCTION 'ZHVL_APPROP_REQ' DESTINATION 'NONE'
EXPORTING
legacy_entity_in = legacy_entity_in
IMPORTING
gv_ext = gv_ext
gv_appr = gv_appr.
ENDLOOP.
ENDMETHOD.
METHOD delete.
ENDMETHOD.
METHOD update.
ENDMETHOD.
METHOD read.
ENDMETHOD.
ENDCLASS.
CLASS lsc_ZHVL_IC_APPROPREQ DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS check_before_save REDEFINITION.
METHODS finalize REDEFINITION.
METHODS save REDEFINITION.
ENDCLASS.
CLASS lsc_ZHVL_IC_APPROPREQ IMPLEMENTATION.
METHOD check_before_save.
ENDMETHOD.
METHOD finalize.
ENDMETHOD.
METHOD save.
ENDMETHOD.
ENDCLASS.
6- Create Service Definition
7- Create Service Binding and Publish ODATA Service
8- Preview your App
8 .1- GET Appropriation Request Data through Legacy BAPI : ‘BAPI_APPREQUEST_GETDETAIL’ using custom CDS entity.
8.2 CREATE Appropriation Request through BAPI: ‘BAPI_APPREQUEST_CREATE’ using behavior implementation class.
Important Note:
The codes in this example are purely for illustrative purposes. No performance testing has been done. No development has been made regarding the return parameters. May not be suitable for production system.
If you think there is a mistake in this method, please contribute in the comment section.
Please submit questions in the respective Q&A area in SAP Community.
References
1- OpenSap Course-Building Apps with Restful Application Programming Model
3- Using Custom Cds Entity For Data Modeling
Muito Bom...
As I understand it the handler class in the behavior definition is designed to update data in memory (the so called transactional buffer)
The saver class is designed to update the database. That would be why the framework does not like you doing a COMMIT WORK in the class designed to update memory only.
If you look at the SAP tutorials for the unmanaged scenario they have function modules which update internal tables in the methods of the handler class, and call a function module which does the database update from those internal tables in the saver class. That is just like a traditional DYNPRO really. The user changes things on the screen which updates structures and internal tables, and the the user presses SAVE and the program updates the database.
Cheersy Cheers
Paul
Hi Paul , thanks for your comment. I understand theory behind the rap framework but I can’t use this methodology with BAPI create scenario. Sap Tutorials have simple db update in save method, this example is not enough for BAPI usage.
According to my example How can we use best practice you said to creation scenario with only BAPI call.
Please describe us and share your knowledge with coding example? Thank you very much!🙏
Maybe Julie Plummer help us, I learned rap unmanaged scenario through her examples and try to modify for my requirements.
I saw many questions about BAPI usage in RAP Framework but these questions havent any answers yet in SAP community, I wrote this blog post because of this reason and I want to get ideas from experts like you and start a discussion.
Cheers🥃
I am in the midst of writing the fourth edition of my A2TF book and so have been playing around with the RAP a lot lately, both managed and unmanaged. The unmanaged will be heavily used due to the vast amount of existing code people will not want to throw away.
The RAP takes a really big mindset change in that instead of a series of related tables e.g. VBAK / VBAP / VBEP / VBKD etc. you instead have associated entities with (in this example) VBAK being the root entity which has associations to the other entities (order items, schedule lines, sales data).
The BOPF had a similar concept and that also had separate methods for updating the memory and updating the database.
Now let us say your example is something like which only has a header level i.e. only stored in one table. That's not very realistic but lets just say. Let us call this entity a "widget" and you had a BAPI_CREATE_WIDGET.
In the UI you have a list of widgets and you press the CREATE button and enter all the details and then press SAVE. The RAP mechanism would call the CREATE method then the SAVE method, one after the other.
So at first glance you would say to yourself - why should I fill an internal table or something in the CREATE method and then have the database update (e.g. call to a BAPI) in the SAVE method using that internal tale? Why bother splitting it up if the two methods are called directly after each other during SAVE?
In that example things appear to make no sense. However as I said in real life you usually have a complex hierarchy of entities. You will note in the RAP behavior class that even if there are multiple entities (hence multiple local behavior classes) there is only one saver class.
The customer phones up and says there requirements have changed. This means you open an existing order, add one item, change an existing item, and delete one existing item. Then the customer phones up just before you are going to press SAVE and says they have changed their mind again, keep everything the way it was so you press CANCEL instead of SAVE.
In that scenario you would not want the database to be updated as you add an item or delete an item as you have not pressed SAVE yet. Hence the logical unit of work (LUW) concept where either all related tables are updated together or none are.
So in the RAP as you perform a CUD operation on an item the CUD method in the behavior class for that item just updates the memory. Only when SAVE is pressed does the SAVE method in the saver class get called and the database is updated.
As I said it really isn't that different to a DYNPRO program. There if I only had a header I would fill a structure in memory as the user enters the detail and then call the BAPI upon save using the structure in memory. If later the data model changed and their were items I would store the items in an internal table that got changed during the transaction, and then change the SAVE method so that the call to the BAPI now had an item table passed in as well. Thus - if traditional programs have a clear separation between changing data in memory and changing data in the database why in the world should the RAP not be the same?
Cheersy Cheers
Paul
Thanks for your detailed explanation Paul.
Thanks Umut for highlighting the restrictions in RAP with respect to BAPI usage. I just worked through a similar example for PM Work orders with the same outcome as the one you have described. In short:
It looks also to me that the definition of an LUW for RAP where a memory image is built-up incrementally and then saved to DB like the flight demo scenario does not fit the classical LUW used in SAP legacy code where a memory image is created after validations and registered for the update process in one step - or even committed in the same step. Ultimately I ran the scenario in a separate LUW like you did, but that is a workaround around a framework, not the usage of one. But I also think that ultimately unmanaged RAP will support BAPIs by easing the restrictions on callable statements because most people will associate 'legacy code' with 'SAP legacy code'
thanks Stephan
As mentioned in the comments by Paul Hardy , we expect the unmanaged will be commonly used. I wonder what is the added value of going with the RAP Unmanaged approach in comparison to the alternative that we're used to - being implementing code based implementation DPC_EXT.
Edit: just to state, for Read we always have CDS as priority 1, but CUD was always code based.
Before going into detail, I'd like to refer to a blogpost of Andre Fischer that discusses quite a lot on OData service development options: https://blogs.sap.com/2017/12/12/odata-service-development-options/
From what I can conclude from the blogpost, reduced TCO for OData V4 enablement is the main driver to use RAP. But in comparison to code based implementation, this looks like additional overhead/complexity of the framework. I view it a bit as BOPF, I always opted for a clean code, code based implementation instead of BOPF to avoid complexity. Then again, I have no real life experience with BOPF nor RAP, can anyone share their throughts?
Are there any other added values for using RAP? What would the main drivers and added value be for OData V4? When upgrading, would there be any reason to upgrade your Code based and OData V2 to V4?
Hi, I only have 1909 onPrem for developing. There i have following problems:
will cause an error in my case: wrong input length, because there is a point and the mask in the bapi is catching this. '-016288' for example works for me.
The second problem is:
causes a 'call_function_not_remote' short dump. Who can help? I dont find a solution yet. I've copied the example 1 to 1 but the names of the objects.Is the example only for 2020 or should it run on 1909? Is the example only for Cloud? Who can help please? Whats wrong? I shall test, if we can call BAPIs in RAP on 1909 onPrem, so i need an explanation.
Hi Martin,
1- I tried this example on S4Hana Onpremise 2020. I think that “custom cds entity” feature work only 2020 onpremise.
2- you must create ZHVL_APPROP _REQ function with “Remote Function Module” feature in se37.
Hi, Umut. Thank you. It works. but now I have a problem with my own example. The Fiori preview cache does not work properly. When I do changes in the CDS-Annotations after creating the Service, the preview show these changes for the first time. But after this the preview does not recognize any other changes. I must create a new CDS with these changes and build a Service on thes CDS. Then it works for a while.Do you know the problem?
Hi Martin,
1- if you redefine the annotations again in Annotation Modeler in WebIDE, try clearing browser cache.
2- if your annotation coming from backend, your changes automatically display in your app.
Maybe you will try to go /IWFND/MAINT_SERVICE and go to Service Implementation and click on Cleanup Cache.
Hi, thank you for your response. but the problem is the Fiori preview in eclipse. I cleaned the browser cache and all the backend caches. But when i use the preview in eclipse, the changes will not dispaly automatically. I must create a new cds-entity with changes in eclipse, a new service definition and a new servie binding. Then the fiori preview in eclipse shows it correctly. I cleaned also the cache in /IWFND/MAINT_SERVICE without success. I also deleted eclipse and reinstalled without success. Here the objects:
Hi Umut,
Thank you for this blog. We are creating an app using the ABAP RAP Method. We are also using an ABAP Class for this (Unmanaged app)
We have two questions regarding your blog:
// Kind Regards,
Gene
Hi Gene,
You can check the answer given by Andre Fischer in the post below.
https://answers.sap.com/questions/12859717/abap-in-scp-custom-entity-cds-views.html
Hi Umut,
Thank you for your information.
I've created two CDS Views. These CDS Views are connected by using association [0..*].
But how can I get a list of items on my Object Page? I am still getting this output
// Kind regards,
Gene
Hi Gene, I understand the problem you are having. I don't think we can simply do this with using custom cds entity.
After writing this article, I decided that it is too early to use the RAP model for the complex unmanaged scenario includes custom cds entity, BAPIs, external services etc.
I am waiting a complex RAP unmanaged scenario example by Andre Fischer or Julie Plummer to describe limitation of RAP model with Complex Multi Dimensional Legacy Scenarios.
Until these examples arrive, I think the following method is the best for us.
Creating a draft enabled Sales Order Fiori App using the new ABAP Programming Model – Part 1: Overview
Note: You can try to do my example without using custom cds entity, just using behavior implementation. Because we have serious restrictions on the use of custom cds entities.
Again, I wrote this article to bring people into the discussion who can better answer these types of questions than I do. I hope they hear our voices.
Thanks.
Hi Umut,
Thanks for this very interesting blog post, and for the positive feedback.
Just one request: By linking to the Github repo, you limit the users to existing Github users.
We have purposely made these tutorials available in SAP Tutorial Navigator, so that anyone (well, anyone with a browser 😉 ) can access them. The link is here:
https://developers.sap.com/mission.abap-env-connect-onpremise.html
Could you please update your blog post accordingly?
Thanks again and best wishes,
Julie.
Hi, Julia
Thanks for your feedback. I updated link in my blogpost.
Thank you also for the nice tutorials you have prepared.
Thankyou for the tutorlal.
Shailaja Ainala.
Thank you Umut Yazici for your post!
Can't we call BAPI in Managed scenarios with unmanaged save?
Yes you can, this article does not contain strictly correct methods.
Brownfield (unmanaged) scenarios are recommended by SAP.(Managed scenarios with unmanaged save or Unmanaged)
https://help.sap.com/docs/BTP/923180ddb98240829d935862025004d6/bb7122a430f94f59b36081414ffd8a95.html
Hi everyone and thanks for the blog, Umut.
Please find also further blogs related to this topic here:
Calling a BAPI is (in general) not that easy in order to be SAP LUW compliant (e.g. no data inconsistencies) and user friendly. The two blogs provide some more background information 🙂
Hi and thanks for the blog. If i understand the comments correctly i should use a BAPI with internal update task in the save() method.