Description:
A RAP BO entity which is not part of the BO composition tree for which it is defined. Defining a foreign entity in the behavior definition enables cross-BO message mapping between the two BOs.
Key Concepts:
RAP foreign entity is a component of the BC-ESI-RAP RESTful ABAP Programming Model. It is a representation of an external entity, such as a web service, that can be used in an ABAP program. The foreign entity is defined in the ABAP program and can be used to access data from the external source.
Tips & Tricks:
When defining a RAP foreign entity, it is important to ensure that all authentication information is correct. This will ensure that requests are sent securely and that responses are received correctly. Additionally, it is important to ensure that the URL of the external source is correct, as this will ensure that requests are sent to the correct location.
How to use it:
To use a RAP foreign entity, first define the entity in the ABAP program. This includes specifying the URL of the external source, as well as any authentication information that may be required. Once the entity is defined, it can be used to access data from the external source. This can be done using the RAP API, which provides methods for making requests and receiving responses from the external source.
Example :
"In our system, we have two distinct business entities: Inventory and Sales Order. Although they are separate, they are fundamentally linked. We manage this connection by using the product ID as the key identifier. This ensures that every time a sales order is created, the system automatically checks and deducts the correct quantity from the available stock in the inventory. This process maintains accurate, real-time stock levels, which is critical for our operations."
@EndUserText.label : 'inverty table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zscn_t_inventory {
key product_id : abap.char(10) not null;
stock_level : abap.int4;
product_name : abap.char(40);
create_at : timestampl;
last_chdate : timestampl;
} @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'INTERFACE VIEW INVERNTORY'
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZSCN_i_INVENTORY as select from zscn_t_inventory
{
key product_id as ProductId,
stock_level as StockLevel,
product_name as ProductName,
create_at as CreateAt,
last_chdate as LastChdate
} @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'INVENTORY CONSUMPATION VIEW'
@Metadata.ignorePropagatedAnnotations: true
@VDM.viewType: #TRANSACTIONAL
define root view entity ZSCN_C_INVENTORY
provider contract transactional_query
as projection on ZSCN_i_INVENTORY
{
@UI.facet: [{ type: #IDENTIFICATION_REFERENCE }]
@UI.lineItem: [{ position: 10 , label: 'Product Id' }]
@UI.identification:[{ position: 10 , label: 'Product Id' }]
key ProductId,
@UI.lineItem: [{ position: 20 , label: 'Stock Level' }]
@UI.identification:[{ position: 20 , label: 'Stock Level' }]
StockLevel,
@UI.lineItem: [{ position: 30 , label: 'Product Name' }]
@UI.identification:[{ position: 30 , label: 'Product Name' }]
ProductName,
@Semantics.systemDateTime.createdAt: true
CreateAt,
@Semantics.systemDateTime.lastChangedAt: true
LastChdate
} managed implementation in class zbp_scn_i_inventory unique;
strict ( 2 );
with draft;
define behavior for ZSCN_i_INVENTORY //alias <alias_name>
persistent table zscn_t_inventory
lock master
total etag LastChdate
draft table zscn_t_invent_d
authorization master ( instance )
late numbering
//etag master <field_name>
{
create ( authorization : global );
update;
delete;
field ( readonly ) ProductId;
validation vali_Stock on save { create; update; }
draft action Activate optimized ;
draft action Discard ;
draft action Edit ;
draft action Resume ;
draft determine action Prepare ;
mapping for zscn_t_inventory {
CreateAt = create_at ;
LastChdate = last_chdate ;
ProductId = product_id ;
ProductName = product_name ;
StockLevel = stock_level;
}
} In our system, a key validation for inventory is to prevent the stock level from ever going into a negative value.
METHOD vali_Stock.
LOOP AT keys INTO DATA(lv_key).
READ ENTITY IN LOCAL MODE ZSCN_i_INVENTORY
ALL FIELDS WITH VALUE #( ( %key = lv_key-%key ) )
RESULT DATA(lt_result).
CHECK lt_result IS NOT INITIAL.
LOOP AT lt_result INTO DATA(lv_result).
IF lv_result-StockLevel < 0 .
APPEND VALUE #( %tky = lv_result-%tky ) TO failed-zscn_i_inventory.
APPEND VALUE #( %tky = lv_result-%tky
%msg = new_message_with_text( severity =
if_abap_behv_message=>severity-error
text = 'Stock value should not be negative value ' && ' ' && lv_result-StockLevel )
%element-stocklevel = if_abap_behv=>mk-on ) TO reported-zscn_i_inventory .
ENDIF.
ENDLOOP.
ENDLOOP.
ENDMETHOD.Sales order Entity
@EndUserText.label : 'SALES ORDER'
@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zscn_dt_salesord {
key sales_order_id : abap.numc(10) not null;
product_id : abap.char(10) not null;
quantity : abap.numc(5);
customer_id : abap.char(10);
order_date : abap.dats;
@Semantics.amount.currencyCode : 'zscn_dt_salesord.currency'
total_amount : abap.curr(13,2);
currency : abap.cuky;
create_at : timestamp;
last_changed : timestamp;
} @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'SALESORD CONSUMPATION VIEW'
@Metadata.ignorePropagatedAnnotations: false
define root view entity ZSCN_C_SALESORD
provider contract transactional_query
as projection on ZSCN_I_SALESORD
{
@UI.facet: [{ type: #IDENTIFICATION_REFERENCE }]
@UI.lineItem: [{ position: 10 , label: 'Sales Order Id' }]
@UI.identification:[{ position: 10 , label: 'Sales Order Id' }]
key SalesOrderId,
@UI.lineItem: [{ position: 20 , label: 'Product Id' }]
@UI.identification:[{ position: 20 , label: 'Product Id' }]
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZSCN_C_INVENTORY', element: 'ProductId' } }]
ProductId,
@UI.lineItem: [{ position: 30 , label: 'Quantity' }]
@UI.identification:[{ position: 30 , label: 'Quantity' }]
Quantity,
@UI.lineItem: [{ position: 40 , label: 'Customer Id' }]
@UI.identification:[{ position: 40 , label: 'Customer Id' }]
CustomerId,
@UI.lineItem: [{ position: 50 , label: 'Order Date' }]
@UI.identification:[{ position: 50 , label: 'Order Date' }]
OrderDate,
@UI.lineItem: [{ position: 60 , label: 'Total Amount' }]
@UI.identification:[{ position: 60 , label: 'Total Amount' }]
TotalAmount,
Currency,
@Semantics.systemDateTime.createdAt: true
CreateAt,
@Semantics.systemDateTime.lastChangedAt: true
LastChanged
} managed implementation in class zbp_scn_i_salesord unique;
strict ( 2 );
with draft;
//foreign entity Zscn_i_inventory alias _inventory ;
define behavior for ZSCN_I_SALESORD //alias <alias_name>
persistent table zscn_dt_salesord
lock master
total etag LastChanged
draft table zscn_dt_salord_d
authorization master ( instance )
early numbering
//etag master <field_name>
{
create ( authorization : global );
update;
delete;
field ( readonly ) SalesOrderId;
validation valid_ProductId on save { create; update; }
determination stock_upadte on save { field Quantity; }
draft action Activate optimized ;
draft action Discard ;
draft action Edit ;
draft action Resume ;
draft determine action Prepare ;
mapping for zscn_dt_salesord
{
CreateAt = create_at;
Currency = currency;
CustomerId = customer_id;
LastChanged = last_changed;
OrderDate = order_date;
ProductId = product_id;
SalesOrderId = sales_order_id;
Quantity = quantity;
TotalAmount = total_amount;
}
} without the foreign entity Zscn_i_inventory syntax , behavior definition of the ZSCN_I_SALESORD it only holding the structure of ZSCN_I_SALESORD it doesn't hold the structure Zscn_i_inventory .
Due to the separate entity definitions, errors from an inventory stock update cannot be directly propagated to the sales order user interface. In Failed and Reported structure will be miss match.
To propagate this we use of foreign entity syntax .
uncomment the //foreign entity Zscn_i_inventory alias _inventory ; in Behavior definition of Zscn_i_salesord .
After adding the Foreign entity Zscn_i_inventory alies _inventory ;
We can see the change in the entity Zscn_i_salesord structure .
Using the Determination we are update the stock of the inventory table based on the Product id in Behavior definition implementation class .
A critical validation has been implemented: when a sales order is created, if the requested quantity is greater than the available stock level, an error is raised in the inventory business logic. This error is then propagated to the sales order entity, making it visible on the sales order screen.
METHOD stock_upadte.
LOOP AT keys INTO DATA(lv_key).
READ ENTITY IN LOCAL MODE zscn_i_salesord ALL FIELDS WITH
VALUE #( ( %key = lv_key-%key ) )
RESULT DATA(lt_result).
CHECK lt_result IS NOT INITIAL.
LOOP AT lt_result INTO DATA(lv_result).
READ ENTITY ZSCN_i_INVENTORY
ALL FIELDS WITH VALUE #( ( ProductId = lv_result-ProductId ) )
RESULT DATA(lt_result_inventory).
LOOP AT lt_result_inventory INTO DATA(lv_inventory).
DATA(lv_stock) = CONV i( lv_inventory-StockLevel - lv_result-Quantity ).
MODIFY ENTITY ZSCN_i_INVENTORY UPDATE FIELDS ( StockLevel )
WITH VALUE #( ( %key-ProductId = lv_inventory-%key-ProductId
StockLevel = lv_stock ) ) REPORTED DATA(ltreported).
if ltreported is not INITIAL.
DATA: lt_dummy LIKE reported-_inventory.
lt_dummy = CORRESPONDING #( ltreported-zscn_i_inventory ).
APPEND LINES OF lt_dummy TO reported-_inventory.
endif.
ENDLOOP.
ENDLOOP.
ENDLOOP.
ENDMETHOD. In above code I am using CORRESPONDING #( ltreported-zscn_i_inventory ). because of while using the EML syntax the report will be early but inside the Behavior definition it will be late structure.
In inventory entity this are the possible product we have in that i will chose Titan watch
When creating a sales order for a Titan watch, if the requested quantity of 50 exceeds the available stock of 40, the system will prevent the transaction and display an error.
The error which is from the inventory entity by using the foreign entity concept we are propagating the error message of inventory in sales order entity.
Related Information:
For more information on using RAP foreign entities, please refer to the SAP Help documentation on BC-ESI-RAP RESTful ABAP Programming Model. Additionally, there are many tutorials available online which provide step-by-step instructions on how to use RAP foreign entities in an ABAP program.
Thanks for
What is RAP foreign entity in SAP BC-ESI-RAP? Definition & Tips
https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbdl_foreign.htm