Side Effects in RAP Explained with Determination  Example
Share

[[{“value”:”

In the world of SAP RAP (RESTful Application Programming), Determinations and Side Effects play a crucial role in delivering responsive and intelligent user experiences. While determinations are used to implement logic that reacts to changes in data during specific RAP phases (such as on modify or on save), side effects ensure that related fields or entities stay consistent and updated on the UI without additional user actions. 

In his blog, I will demonstrate a practical scenario where determinations are used to dynamically calculate values based on user input, and side effects are configured to immediately reflect these changes on the UI. This not only improves the data integrity but also enhances usability in Fiori applications. By the end of this post, you will have a clearer understanding of how to leverage determinations and side effects together effectively within a RAP-based application. 

DETERMINATION : 

  • Actions modifies the existing BO instance where as Determination modifies the existing BO instances based on some  trigger condition  
  • We can see that Actions also triggers based on the conditions but cannot modify the BO instances , we can be able to throw the error messages. 

Pre requisites : 

During modification we change/modify  some fields / requirements  and we can compute the values of  particular fields 

Determination can be called during  Transactional phase/Save sequence where as validations always called during the save sequence 

Once a determination  has been triggered , it must run independently from other determinations 

During determination result must change if we execute detrmination several time under same condition  

 

Scenario : 

Here the determination calculateTotalPrice which is defined for all the three entities 

(Travel, booking and booking supplements) handles the  calculation of total  price of one travel. 

Based on the booking Fee total price must be calculated for the travel  

 

SIDE-EFFECTS: 

  • The SAP Fiori UI does not necessarily trigger a reload of all  related BO after every User input , as it simply does not know anything about data changes  on the tables 
  • Side effects are  used to reload data, permissions or messages based on data changes in UI scenarios with draft enabled BO’s  
  • Side effects reloads the screen but it does not reload entire screen  
  •  It changes some of the field values or will enable/ disable some of the fied values    Or status of the data in transactional buffer –> based on these same things should appear in the front end  
  • We need to define side effects in Behaviour definition  
  • Side effects will only reload the fields in front end  ,nothing will happen in backend  
  • The data which is available in the backend it will reload in the front end whihc is not currently displaying properly  

 

Side effects have two parts : 

  • Triggering condition : specifies when you should reload ( can be actions / validations) 
  • Target : which fields should get  reloaded ( value of a field / multiple fields / reload entire entity ) 

 

Important points: 

  • Determinations calculates the total  price and updates it into the transcational buffer 

But in the front end screen older values will be there . 

 

Requirement : 

  • Whenever I change the booking fee and booking supplement data and flight price 
  • The total  price should be updated not only in transactional buffer but also in the front end automatically  

And whenever we are updating booking fee the reload of total price should happen  

Based on the trigger condition –> it should reload the values / fields  

 

Here the source –> Booking fee 

Target –> totalprice 

 

Syntax: 

Side effects { filed MyField affects Target } 

                         { $self affects Targets ; } 

                 { action MyAction affects Tragets ;} 

     { determine action MyDetermineAction  

    Executed on sources  

Affects Tagets } . 

 

In the target we can specify : 

  • $self : The current RAP BO is reloaded  
  • Entity _MyAssoc  : the specified associated entity  _MyAssoc is reloaded when the side effect is triggered  
  • Message  : all the messages in the response parameter reported are reloaded when the side effects is triggered  
  • We can  also als provide multiple targets  

 

Side effects { field MyField affects Field1 , Field2 , action Action1 , 

                        Action Action 2 [..] } 

 

RESTRICTIONS : 

  • Static actions  defined using the addition static must  not be used as a side effect trigger , nor as a side effect target  
  • In case of the trigger entity property $sefl , the target cannot be a field of the current entity $self itself ,  

However fields  from the associated entity can be defined using path  expressions  

 

Side Effect In BDL: 

  • Side effects can be specified exactly once for each RAP BO entity in the entity  

Behaviour definition  

  • Multiple side effects can  be summarized with curly brackets , separated by a semicolon (; ) , if required. 
  • The syntax ‘use side effects’ is specified in the behaviour definition header and all  side effects from all  RAP BO entities of the underlying RAP BO are reused 

 

1. Create db table for travel  

@EndUserText.label : ‘travel table’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zpd_dt_travel {

key client : abap.clnt not null;
key travel_id : /dmo/travel_id not null;
agency_id : /dmo/agency_id;
customer_id : /dmo/customer_id;
begin_date : /dmo/begin_date;
end_date : /dmo/end_date;
@Semantics.amount.currencyCode : ‘zpd_dt_travel.currency_code’
booking_fee : /dmo/booking_fee;
@Semantics.amount.currencyCode : ‘zpd_dt_travel.currency_code’
total_price : /dmo/total_price;
currency_code : /dmo/currency_code;
description : /dmo/description;
overall_status : /dmo/overall_status;
created_by : abp_creation_user;
created_at : abp_creation_tstmpl;
last_changed_by : abp_locinst_lastchange_user;
last_changed_at : abp_locinst_lastchange_tstmpl;

}

2.Create db table for Booking

@EndUserText.label : ‘tbale for booking details’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zpd_dt_booking {

key client : abap.clnt not null;
@AbapCatalog.foreignKey.label : ‘Travel’
@AbapCatalog.foreignKey.screenCheck : false
key travel_id : /dmo/travel_id not null
with foreign key [0..*,1] zpd_dt_travel
where travel_id = zpd_dt_booking.travel_id;
key booking_id : /dmo/booking_id not null;
booking_date : /dmo/booking_date;
customer_id : /dmo/customer_id;
carrier_id : /dmo/carrier_id;
connection_id : /dmo/connection_id;
flight_date : /dmo/flight_date;
@Semantics.amount.currencyCode : ‘zpd_dt_booking.currency_code’
flight_price : /dmo/flight_price;
currency_code : /dmo/currency_code;
booking_status : /dmo/booking_status;
last_changed_at : abp_locinst_lastchange_tstmpl;

}

 3.Crete a db table for Booking suppliment

@EndUserText.label : ‘booking supplimnet’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zpd_dt_bsupplmnt {

key client : abap.clnt not null;
@AbapCatalog.foreignKey.label : ‘Travel’
@AbapCatalog.foreignKey.screenCheck : false
key travel_id : /dmo/travel_id not null
with foreign key [0..*,1] zpd_dt_travel
where travel_id = zpd_dt_bsupplmnt.travel_id;
@AbapCatalog.foreignKey.label : ‘Booking’
@AbapCatalog.foreignKey.screenCheck : false
key booking_id : /dmo/booking_id not null
with foreign key [0..*,1] zpd_dt_booking
where travel_id = zpd_dt_bsupplmnt.travel_id
and booking_id = zpd_dt_bsupplmnt.booking_id;
key booking_supplement_id : /dmo/booking_supplement_id not null;
supplement_id : /dmo/supplement_id;
@Semantics.amount.currencyCode : ‘zpd_dt_bsupplmnt.currency_code’
price : /dmo/supplement_price;
currency_code : /dmo/currency_code;
last_changed_at : abp_locinst_lastchange_tstmpl;

}

 4.Create a root view entity for travel

AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘root view for travel’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED

}

define root view entity zi_travel_detail as select from zpd_dt_travel
composition [0..*] of ZI_BOOKING_DETAIL as _booking
association [0..1] to /DMO/I_Agency as _agency on $projection.AgencyId = _agency.AgencyID
association [0..1] to /DMO/I_Customer as _customer on $projection.CustomerId = _customer.CustomerID
association [1..1] to I_Currency as _currency on $projection.CurrencyCode = _currency.Currency
association [1..1] to /DMO/I_Overall_Status_VH as _status on $projection.OverallStatus = _status.OverallStatus

{

key travel_id as TravelId,
agency_id as AgencyId,
customer_id as CustomerId,
begin_date as BeginDate,
end_date as EndDate,
@Semantics.amount.currencyCode: ‘CurrencyCode’
booking_fee as BookingFee,
@Semantics.amount.currencyCode: ‘CurrencyCode’
total_price as TotalPrice,
currency_code as CurrencyCode,
description as Description,
overall_status as OverallStatus,
@Semantics.user.createdBy: true
created_by as CreatedBy,
@Semantics.systemDateTime.createdAt: true
created_at as CreatedAt,
@Semantics.user.localInstanceLastChangedBy: true
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
last_changed_at as LastChangedAt,
_agency,
_customer,
_currency,
_status,
_booking

}

5.Create interface view  for booking 

@EndUserText.label: ‘root view for booking’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED

}

define view entity ZI_BOOKING_DETAIL as select from zpd_dt_booking association to parent zi_travel_detail as _travel
on $projection.TravelId = _travel.TravelId
composition [0..*] of zi_booking_supp as _bookingsuppl
association [1..1] to /DMO/I_Carrier as _carrier on $projection.CarrierId = _carrier.AirlineID
association [1..1] to /DMO/I_Customer as _customer on $projection.CustomerId = _customer.CustomerID
association [1..1] to /DMO/I_Connection as _connection on $projection.CarrierId = _connection.AirlineID
and $projection.ConnectionId = _connection.ConnectionID
association[1..1] to /DMO/I_Booking_Status_VH as _booking_status on $projection.BookingStatus = _booking_status.BookingStatus

{

key travel_id as TravelId,
key booking_id as BookingId,
booking_date as BookingDate,
customer_id as CustomerId,
carrier_id as CarrierId,
connection_id as ConnectionId,
flight_date as FlightDate,
@Semantics.amount.currencyCode: ‘CurrencyCode’
flight_price as FlightPrice,
currency_code as CurrencyCode,
booking_status as BookingStatus,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
last_changed_at as LastChangedAt,
_carrier,
_customer,
_connection,
_booking_status,
_travel,
_bookingsuppl
}

6.Create Interface view for Booking suppliment

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘root view for booking suppliment’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}

define view entity zi_booking_supp as select from zpd_dt_bsupplmnt
association to parent ZI_BOOKING_DETAIL as _booking on $projection.TravelId = _booking.TravelId
and $projection.BookingId = _booking.BookingId
association[1..1] to zi_travel_detail as _travel on $projection.TravelId = _travel.TravelId
association [1..1] to /DMO/I_Supplement as _suppliment on $projection.SupplementId = _suppliment.SupplementID
association[1..*] to /DMO/I_SupplementText as _supplimentText on $projection.SupplementId = _supplimentText.SupplementID

{

key travel_id as TravelId,
key booking_id as BookingId,
key booking_supplement_id as BookingSupplementId,
supplement_id as SupplementId,
@Semantics.amount.currencyCode: ‘CurrencyCode’
price as Price,
currency_code as CurrencyCode,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
last_changed_at as LastChangedAt,
_travel,
_supplimentText,
_suppliment,
_booking

}

7.Define projection for travel root entity 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘consumption view for travel’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define root view entity zc_travel_det provider contract transactional_query
as projection on zi_travel_detail

{

key TravelId,
@ObjectModel.text.element: [ ‘AgencyName’ ]
AgencyId,
_Agency.Name as AgencyName,
@ObjectModel.text.element: [ ‘CustomerName’ ]
CustomerId,
_Customer.LastName as CustomerName,
BeginDate,
EndDate,
@Semantics.amount.currencyCode: ‘CurrencyCode’
BookingFee,
@Semantics.amount.currencyCode: ‘CurrencyCode’
TotalPrice,
CurrencyCode,
Description,
@ObjectModel.text.element: [ ‘OverallStatusText’ ]
OverallStatus,
_Status._Text.Text as OverallStatusText : localized,
CreatedBy,
CreatedAt,
LastChangedBy,
LastChangedAt,
/* Associations */
_Agency,
_booking : redirected to composition child zc_booking_det,
_Currency,
_Customer,
_Status

}

 8.Define projection for booking  entity

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘consumption view for booking’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define view entity zc_booking_det
as projection on ZI_BOOKING_DETAIL
{

key TravelId,
key BookingId,
BookingDate,
@ObjectModel.text.element: [ ‘CustomerName’ ]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Customer’,
element: ‘CustomerID’

} }]

CustomerId,
_customer.LastName as CustomerName,
@ObjectModel.text.element: [ ‘CarrierName’ ]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Carrier’,
element: ‘AirlineId’

} }]

CarrierId,
_carrier.Name as CarrierName,
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘Connection Id’

}

}]
ConnectionId,
FlightDate,
@Semantics.amount.currencyCode: ‘CurrencyCode’
FlightPrice,
CurrencyCode,
@ObjectModel.text.element: [ ‘BookingStatusText’ ]
_booking_status._Text.Text as BookingStatusText : localized,
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Booking_Status_VH’,
element: ‘Booking_Status’

} }]
BookingStatus,
LastChangedAt,
/* Associations */
_bookingsuppl : redirected to composition child zc_booking_supp,
_booking_status,
_carrier,
_connection,
_customer,
_travel : redirected to parent zc_travel_det

}

9.Define projection for booking  suppliment  entity

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘consumption view for booking suppliment’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define view entity zc_booking_supp
as projection on zi_booking_supp

{

key TravelId,
key BookingId,
key BookingSupplementId,
@ObjectModel.text.element: [ ‘SupplemenDesc’ ]
SupplementId,
_SupplementText.Description as SupplemenDesc : localized,
@Semantics.amount.currencyCode: ‘CurrencyCode’
Price,
CurrencyCode,
LastChangedAt,
/* Associations */
_Travel : redirected to zc_travel_det,
_Booking : redirected to parent zc_booking_det,
_Supplement,
_SupplementText

}

10.provide metada extension for projected views

@Metadata.layer: #CORE

@Search.searchable: true
@UI.headerInfo: {
typeName: ‘Travel’,
typeNamePlural: ‘Travels’,

title: {
type: #STANDARD,
label: ‘Travel’,
value: ‘TravelId’

}

}
annotate view zc_travel_det
with

{

@UI.facet: [{
id: ‘Travel’,
purpose: #STANDARD,
position: 10 ,
label: ‘Travel’,
type: #IDENTIFICATION_REFERENCE

},

{

id: ‘Booking’,
purpose: #STANDARD,
position: 20 ,
label: ‘Booking’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_booking’

}

]

@UI.lineItem: [{ position: 10 }, { type:#FOR_ACTION, dataAction: ‘CopyTravel’, label: ‘Copy Travel’ }
,{ type:#FOR_ACTION, dataAction: ‘AcceptTravel’, label: ‘AcceptTravel’ }
,{ position: 30 },{ type:#FOR_ACTION, dataAction: ‘RejectTravel’, label: ‘RejectTravel’ }]
@UI.identification: [{ position: 10 }]
@Search.defaultSearchElement: true
TravelId;
@UI: { lineItem: [{ position: 40 }],
selectionField: [{ position: 40 }],
identification: [{ position: 40 }]

}

@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Agency’,
element: ‘AgencyID’

} }]

AgencyId;
// AgencyName;
@UI: { lineItem: [{ position: 50 }],
selectionField: [{ position: 50 }],
identification: [{ position: 50 }]
}
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Customer’,
element: ‘CustomerID’

} }]
CustomerId;
// CustomerName;
@UI.lineItem: [{ position: 60 }]
@UI.identification: [{ position: 60 }]
BeginDate;
@UI.lineItem: [{ position: 70 }]
@UI.identification: [{ position: 70 }]
EndDate;
@UI.identification: [{ position: 75 }]
BookingFee;
@UI.lineItem: [{ position: 80 }]
@UI.identification: [{ position: 80 }]
TotalPrice;
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘I_Currency’,
element: ‘Currency’
} }]

CurrencyCode;
@UI.identification: [{ position: 85 }]
Description;
@UI: { lineItem: [{ position: 90 }],
selectionField: [{ position: 60 }],
identification: [{ position: 90 }],
textArrangement: #TEXT_ONLY
}
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Overall_Status_VH’,
element: ‘OverallStatus’
} }]

OverallStatus;
// OverallStatusText;
// .hidden: true
// LastChangedAt;

}

11. metadata extension for booking entity

@Metadata.layer: #CORE

@Search.searchable: true
@UI.headerInfo: {
typeName: ‘Booking’,
typeNamePlural: ‘Bookings’,

title: {
type: #STANDARD,
label: ‘Booking’,
value: ‘BookingId’

}

}

annotate view zc_booking_det

with

{

@UI.facet: [{
id: ‘Booking’,
purpose: #STANDARD,
position: 10 ,
label: ‘Booking’,
type: #IDENTIFICATION_REFERENCE

},

{

id: ‘BookingSuppl’,
purpose: #STANDARD,
position: 20 ,
label: ‘Booking Suppliments’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_bookingsuppl’

}

]

// .defaultSearchElement: true
// TravelId;

@UI.lineItem: [{ position: 10 }]
@UI.identification: [{ position: 10 }]
@Search.defaultSearchElement: true
BookingId;
@UI.lineItem: [{ position: 20 }]
@UI.identification: [{ position: 20 }]

BookingDate;
@UI.lineItem: [{ position: 30 }]
@UI.identification: [{ position: 30 }]
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Customer’,
element: ‘CustomerID’

} }]

CustomerId;
@UI.lineItem: [{ position: 40 }]
@UI.identification: [{ position: 40 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Carrier’,
element: ‘AirlineID’

} }]

CarrierId;
@UI.lineItem: [{ position: 50 }]
@UI.identification: [{ position: 50 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘ConnectionId’

},

additionalBinding: [{ element: ‘ConnectionId’ ,
localElement: ‘ConnectionID’},
{ element: ‘AirlineID’ ,
localElement: ‘CarrierId’},
{ element: ‘CurrencyCode’ ,
localElement: ‘CurrencyCode’},
{ element: ‘Price’ ,
localElement: ‘FlightPrice’} ]

}]

ConnectionId;
@UI.lineItem: [{ position: 60 }]
@UI.identification: [{ position: 60 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘FlightDate’

},

additionalBinding: [{ element: ‘FlightDate’ ,
localElement: ‘FlightDate’},
{ element: ‘AirlineID’ ,
localElement: ‘CarrierId’},
{ element: ‘CurrencyCode’ ,

localElement: ‘CurrencyCode’},
{ element: ‘Price’ ,
localElement: ‘FlightPrice’} ]

}]

FlightDate;
@UI.lineItem: [{ position: 70 }]
@UI.identification: [{ position: 70 }]
FlightPrice;
// @Consumption.valueHelpDefinition: [{ entity: {
// name: ‘I_Currency’,
// element: ‘Currency’

// } }]

// CurrencyCode;
@UI.lineItem: [{ position: 80 }]
@UI.identification: [{ position: 80 }]
@UI.textArrangement: #TEXT_ONLY
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Booking_Status_VH’,
element: ‘BookingStatus’

} }]

BookingStatus;
// LastChangedAt;

}

12. Metadata extension for booking entity

@Metadata.layer: #CORE

@Search.searchable: true
@UI.headerInfo: {
typeName: ‘Booking’,
typeNamePlural: ‘Bookings’,
title: {
type: #STANDARD,
label: ‘Booking’,
value: ‘BookingId’

}

}
annotate view zc_booking_det
with

{

@UI.facet: [{
id: ‘Booking’,
purpose: #STANDARD,
position: 10 ,
label: ‘Booking’,
type: #IDENTIFICATION_REFERENCE

},

{

id: ‘BookingSuppl’,
purpose: #STANDARD,
position: 20 ,
label: ‘Booking Suppliments’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_bookingsuppl’

}

]
// .defaultSearchElement: true
// TravelId;

@UI.lineItem: [{ position: 10 }]
@UI.identification: [{ position: 10 }]
@Search.defaultSearchElement: true
BookingId;
@UI.lineItem: [{ position: 20 }]
@UI.identification: [{ position: 20 }]
BookingDate;
@UI.lineItem: [{ position: 30 }]
@UI.identification: [{ position: 30 }]
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Customer’,
element: ‘CustomerID’

} }]

CustomerId;
@UI.lineItem: [{ position: 40 }]
@UI.identification: [{ position: 40 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Carrier’,
element: ‘AirlineID’

} }]

CarrierId;
@UI.lineItem: [{ position: 50 }]
@UI.identification: [{ position: 50 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘ConnectionId’

},
additionalBinding: [{ element: ‘ConnectionId’ ,
localElement: ‘ConnectionID’},

{ element: ‘AirlineID’ ,
localElement: ‘CarrierId’},
{ element: ‘CurrencyCode’ ,
localElement: ‘CurrencyCode’},
{ element: ‘Price’ ,
localElement: ‘FlightPrice’} ]

}]
ConnectionId;
@UI.lineItem: [{ position: 60 }]
@UI.identification: [{ position: 60 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘FlightDate’

},

additionalBinding: [{ element: ‘FlightDate’ ,
localElement: ‘FlightDate’},
{ element: ‘AirlineID’ ,
localElement: ‘CarrierId’},
{ element: ‘CurrencyCode’ ,
localElement: ‘CurrencyCode’},
{ element: ‘Price’ ,
localElement: ‘FlightPrice’} ]

}]
FlightDate;
@UI.lineItem: [{ position: 70 }]
@UI.identification: [{ position: 70 }]

FlightPrice;
// @Consumption.valueHelpDefinition: [{ entity: {
// name: ‘I_Currency’,
// element: ‘Currency’
// } }]

// CurrencyCode;
@UI.lineItem: [{ position: 80 }]
@UI.identification: [{ position: 80 }]
@UI.textArrangement: #TEXT_ONLY
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Booking_Status_VH’,
element: ‘BookingStatus’

} }]
BookingStatus;
// LastChangedAt;

}

 13. Metadata extension for booking  suppliment entity

@Metadata.layer: #CORE 

@Search.searchable: true 
@UI.headerInfo: { 
typeName: 'BookingSuppl', 
typeNamePlural: 'BookingSuppls', 
title: { 
type: #STANDARD, 
label: 'Booking Suppliments', 
value: 'BookingSupplementId' 

} 
} 

annotate view zc_booking_supp 
with  
{ 
@UI.facet: [{ 
id: 'BookingSuppl', 
purpose: #STANDARD, 
position: 10 ,
label: 'Booking Suppliments', 
type: #IDENTIFICATION_REFERENCE 
} 
] 
// @Search.defaultSearchElement: true 
// TravelId; 
@Search.defaultSearchElement: true 
BookingId; 
@UI.lineItem: [{ position: 10 }] 
@UI.identification: [{ position: 10 }] 
BookingSupplementId; 
@UI.lineItem: [{ position: 20 }] 
@UI.identification: [{ position: 20 }] 
@Consumption.valueHelpDefinition: [{ entity: { 
name: '/DMO/I_SUPPLEMENT', 
element: 'SupplementID' 
}, 

additionalBinding: [{ element: 'SupplementID' , 
localElement: 'SupplementId'}, 
{ element: 'Price' , 
localElement: 'Price'}, 
{ element: 'CurrencyCode' , 
localElement: 'CurrencyCode'} 

] 

}] 
SupplementId; 
@UI.lineItem: [{ position: 30 }] 
@UI.identification: [{ position: 30 }] 

Price; 
// @Consumption.valueHelpDefinition: [{ entity: { 
// name: 'I_Currency', 
// element: 'Currency' 
// } }] 
// CurrencyCode; 
// @UI.hidden: true 
// LastChangedAt; 

} 

14. Create behaviour definition travel root entity 

managed;

strict ( 2 );
define behavior for zi_travel_detail //alias <alias_name>
implementation in class zcl_bp_travel_maa unique
persistent table zpd_dt_travel
lock master
authorization master ( global )
etag master LastChangedAt
early numbering

{

field ( readonly ) TravelId;
action AcceptTravel result [1] $self;
action RejectTravel result [1] $self;

factory action CopyTravel [1];
internal action RecalcTotalPrice;
determination CalcTotalPrice on modify { create; field BookingFee, CurrencyCode; }

// authorization ( global ),
create;
update;
delete;
// field ( readonly ) TravelId;
association _booking { create; }
mapping for zpd_dt_travel
{

TravelId = travel_id;
AgencyId = agency_id;
CustomerId = customer_id;
BeginDate = begin_date;
EndDate = end_date;
BookingFee = booking_fee;
TotalPrice = total_price;
CurrencyCode = currency_code;
Description = description;
OverallStatus = overall_status;
CreatedBy = created_by;
CreatedAt = created_at;
LastChangedBy = last_changed_by;
LastChangedAt = last_changed_at;

}
}
define behavior for ZI_BOOKING_DETAIL //alias <alias_name>
implementation in class zcl_bp_booking_ma unique
persistent table zpd_dt_booking
lock dependent by _Travel
//authorization dependent by _travel
authorization master ( global )
etag master LastChangedAt
early numbering
{
update;
delete;
field ( readonly ) TravelId, BookingId;

determination CalcTotalPrice on modify { create; field FlightPrice, CurrencyCode; }
association _travel;
association _bookingsuppl { create; }
mapping for zpd_dt_booking

{
TravelId = travel_id;
BookingId = booking_id;
BookingDate = booking_date;
CustomerId = customer_id;
CarrierId = carrier_id;
ConnectionId = connection_id;
FlightDate = flight_date;
FlightPrice = flight_price;

CurrencyCode = currency_code;
BookingStatus = booking_status;
LastChangedAt = last_changed_at;

}

}
define behavior for zi_booking_supp //alias <alias_name>
implementation in class zcl_bp_booking_ma unique
persistent table zpd_dt_bsupplmnt
lock dependent by _Travel
//authorization dependent by _Travel
authorization master ( global )
etag master LastChangedAt
early numbering

{
update;
delete;
field ( readonly ) TravelId, BookingId, BookingSupplementId;
determination CalcTotalPrice on modify { create; field Price, CurrencyCode; }
association _Travel;
association _Booking;
mapping for zpd_dt_bsupplmnt
{

SupplementId = supplement_id;
TravelId = travel_id;
BookingId = booking_id;
BookingSupplementId = booking_supplement_id;
Price = price;
CurrencyCode = currency_code;
LastChangedAt = last_changed_at;

}

}

15. Define behavior definition for projection root entity 

projection;

strict ( 2 );
define behavior for zc_travel_det //alias <alias_name>

{
use create;
use update;
use delete;

use action AcceptTravel;
use action RejectTravel;
use action CopyTravel;
use association _booking { create; }

}
define behavior for zc_booking_det //alias <alias_name>

{

use update;
use delete;
use association _travel;
use association _bookingsuppl { create; }

}

define behavior for zc_booking_supp //alias <alias_name>
{

use update;
use delete;

use association _Travel;
use association _Booking;

}

16. Create Service Definition

@EndUserText.label: ‘service def for travel’
define service Zsr_travel_det {

expose zc_travel_det;
expose zc_booking_det;
expose zc_booking_supp;
expose /DMO/I_Supplement_StdVH as Supplement;
expose /DMO/I_SupplementCategory_VH as SupplementCategory;
expose /DMO/I_Customer_StdVH as Passenger;
expose /DMO/I_Agency_StdVH as TravelAgency;
expose /DMO/I_Carrier_StdVH as Airline;
expose /DMO/I_Connection_StdVH as FlightConnection;
expose /DMO/I_Flight_StdVH as Flight;
expose /DMO/I_Airport_StdVH as Airport;
expose /DMO/I_Overall_Status_VH as OverallStatus;
expose /DMO/I_Booking_Status_VH as BookingStatus;
expose I_CurrencyStdVH as Currency;
expose I_CountryVH as Country;

}

17. Create service binding 

Pradeep555_0-1751354700486.png

18. Implement the class 

CLASS lhc_zi_travel_detail DEFINITION INHERITING FROM cl_abap_behavior_handler.

PRIVATE SECTION.

METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR zi_travel_detail RESULT result.
METHODS accepttravel FOR MODIFY
IMPORTING keys FOR ACTION zi_travel_detail~accepttravel RESULT result.
METHODS copytravel FOR MODIFY
IMPORTING keys FOR ACTION zi_travel_detail~copytravel.
METHODS recalctotalprice FOR MODIFY
IMPORTING keys FOR ACTION zi_travel_detail~recalctotalprice.
METHODS rejecttravel FOR MODIFY
IMPORTING keys FOR ACTION zi_travel_detail~rejecttravel RESULT result.
METHODS calctotalprice FOR DETERMINE ON MODIFY
IMPORTING keys FOR zi_travel_detail~calctotalprice.
METHODS earlynumbering_cba_booking FOR NUMBERING
IMPORTING entities FOR CREATE zi_travel_detail_booking.
METHODS earlynumbering_create FOR NUMBERING
IMPORTING entities FOR CREATE zi_travel_detail.

ENDCLASS.

CLASS lhc_zi_travel_detail IMPLEMENTATION.
METHOD get_global_authorizations.
ENDMETHOD.

METHOD earlynumbering_create.
DATA(lt_entities) = entities.
DELETE lt_entities WHERE TravelId IS NOT INITIAL .
TRY.
cl_numberrange_runtime=>number_get(

EXPORTING
nr_range_nr = ’01’
object = ‘/DMO/TRV_M’
quantity = CONV #( lines( lt_entities ) )
IMPORTING
number = DATA(lv_latest_num)
returncode = DATA(lv_code)
returned_quantity = DATA(lv_qty)

).
CATCH cx_nr_object_not_found.
CATCH cx_number_ranges INTO DATA(lo_error).

LOOP AT lt_entities INTO DATA(ls_entities).
APPEND VALUE #( %cid = ls_entities-%cid
%key = ls_entities-%key )
TO failed-zi_travel_detail.
APPEND VALUE #( %cid = ls_entities-%cid
%key = ls_entities-%key
%msg = lo_error )
TO reported-zi_travel_detail.
ENDLOOP.
EXIT.
ENDTRY..

ASSERT lv_qty = lines( lt_entities ).
DATA(lv_curr_num) = lv_latest_num – lv_qty.
LOOP AT lt_entities INTO ls_entities.
lv_curr_num = lv_curr_num + 1.
APPEND VALUE #( %cid = ls_entities-%cid
TravelId = lv_curr_num )
TO mapped-zi_travel_detail.
ENDLOOP.
ENDMETHOD.

METHOD earlynumbering_cba_Booking.

DATA : lv_max_booking TYPE /dmo/booking_id.
READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail BY _booking
FROM CORRESPONDING #( entities )
LINK DATA(lt_link_data).
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_group_entity>)
GROUP BY <ls_group_entity>-TravelId.

lv_max_booking = REDUCE #( INIT lv_max = CONV /dmo/booking_id( ‘0’ )
FOR ls_link IN lt_link_data USING KEY entity
WHERE ( source-TravelId = <ls_group_entity>-TravelId )
NEXT lv_max = COND /dmo/booking_id( WHEN lv_max < ls_link-target-BookingId
THEN ls_link-target-BookingId
ELSE lv_max ) ).

lv_max_booking = REDUCE #( INIT lv_max = lv_max_booking
FOR ls_entity IN entities USING KEY entity
WHERE ( TravelId = <ls_group_entity>-TravelId )
FOR ls_booking IN ls_entity-%target
NEXT lv_max = COND /dmo/booking_id( WHEN lv_max < ls_booking-BookingId
THEN ls_booking-BookingId
ELSE lv_max ) ).
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entities>)
USING KEY entity
WHERE TravelId = <ls_group_entity>-TravelId.

LOOP AT <ls_entities>-%target ASSIGNING FIELD-SYMBOL(<ls_booking>).
IF <ls_booking>-BookingId IS INITIAL.
lv_max_booking += 10.
APPEND CORRESPONDING #( <ls_booking> ) TO mapped-zi_booking_detail ASSIGNING FIELD-SYMBOL(<ls_new_map_book>).
<ls_new_map_book>-BookingId = lv_max_booking.

ENDIF.
ENDLOOP.
ENDLOOP.

ENDLOOP.
ENDMETHOD.

METHOD AcceptTravel.
MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail

UPDATE FIELDS ( OverallStatus )
WITH VALUE #( FOR ls_keys IN keys ( %tky = ls_keys-%tky
OverallStatus = ‘A’) ).
READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_result).
result = VALUE #( FOR ls_result IN lt_result ( %tky = ls_result-%tky
%param = ls_result ) ).

ENDMETHOD.
METHOD CopyTravel.
ENDMETHOD.

METHOD RecalcTotalPrice.

TYPES : BEGIN OF ty_total,
price TYPE /dmo/total_price,
curr TYPE /dmo/currency_code,
END OF ty_total.

DATA : lt_total TYPE TABLE OF ty_total,
lv_conv_price TYPE ty_total-price.

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
FIELDS ( BookingFee CurrencyCode )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
DELETE lt_travel WHERE CurrencyCode IS INITIAL.

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail BY _booking
FIELDS ( FlightPrice CurrencyCode )
WITH CORRESPONDING #( lt_travel )
RESULT DATA(lt_ba_booking) .

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_booking_detail BY _bookingsuppl
FIELDS ( Price CurrencyCode )
WITH CORRESPONDING #( lt_ba_booking )
RESULT DATA(lt_ba_bookingsupp) .
LOOP AT lt_travel ASSIGNING FIELD-SYMBOL(<ls_travel>).
lt_total = VALUE #( ( price = <ls_travel>-BookingFee curr = <ls_travel>-CurrencyCode ) ).

LOOP AT lt_ba_booking ASSIGNING FIELD-SYMBOL(<ls_booking>)
USING KEY entity
WHERE TravelId = <ls_travel>-TravelId
AND CurrencyCode IS NOT INITIAL.

APPEND VALUE #( price = <ls_booking>-FlightPrice curr = <ls_booking>-CurrencyCode )
TO lt_total.

LOOP AT lt_ba_bookingsupp ASSIGNING FIELD-SYMBOL(<ls_bookingsupp>)
USING KEY entity
WHERE TravelId = <ls_booking>-TravelId

AND BookingId = <ls_booking>-BookingId
AND CurrencyCode IS NOT INITIAL.
APPEND VALUE #( price = <ls_bookingsupp>-Price curr = <ls_bookingsupp>-CurrencyCode )

TO lt_total.
ENDLOOP.
ENDLOOP.

LOOP AT lt_total ASSIGNING FIELD-SYMBOL(<ls_total>).
IF <ls_total>-curr = <ls_travel>-CurrencyCode .
lv_conv_price = <ls_total>-price .
ELSE.

/dmo/cl_flight_amdp=>convert_currency(

EXPORTING
iv_amount = <ls_total>-price
iv_currency_code_source = <ls_total>-curr
iv_currency_code_target = <ls_travel>-CurrencyCode
iv_exchange_rate_date = cl_abap_context_info=>get_system_date( )
IMPORTING
ev_amount = lv_conv_price

).

ENDIF.
<ls_travel>-TotalPrice = <ls_travel>-TotalPrice + lv_conv_price.
ENDLOOP.

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
UPDATE FIELDS ( TotalPrice )
WITH CORRESPONDING #( lt_travel ).
ENDLOOP.

ENDMETHOD.
METHOD RejectTravel.

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE

ENTITY zi_travel_detail
UPDATE FIELDS ( OverallStatus )
WITH VALUE #( FOR ls_keys IN keys ( %tky = ls_keys-%tky
OverallStatus = ‘X’) )
REPORTED DATA(lt_travel).

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_result).
result = VALUE #( FOR ls_result IN lt_result ( %tky = ls_result-%tky
%param = ls_result ) ).
ENDMETHOD.

METHOD CalcTotalPrice.

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
EXECUTE RecalcTotalPrice
FROM CORRESPONDING #( keys ).
ENDMETHOD.

ENDCLASS.

18. Here we are calculating the total  price , whenever somebody changes the total  Price and currency manually this determination  should call on transactional phase(on modify) 

METHOD CalcTotalPrice.

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
EXECUTE RecalcTotalPrice
FROM CORRESPONDING #( keys ).

ENDMETHOD.

19.  will call RecacTotalPrice for each determination 

All the travel id which we modify  will trigger when we are calculating total price  

RecacTotalPrice–> will be called . We need to write the logic to modify Our BO instance based on travel ID And it will read and updae the price  

 Here the action will take care of the process – when we change the price  ( based on determination ) action will be called  

And as soon as price filed changes, determination happens  And we need to read the travel entity with fields booking fee and currency code  And we need to provide travel IDs which is present in keys  Result is taken in LT_TRAVEL 

Same thing we need to do it for boking and booking suppliment 

METHOD RecalcTotalPrice.

TYPES : BEGIN OF ty_total,
price TYPE /dmo/total_price,
curr TYPE /dmo/currency_code,
END OF ty_total.

DATA : lt_total TYPE TABLE OF ty_total,
lv_conv_price TYPE ty_total-price.

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
FIELDS ( BookingFee CurrencyCode )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).

DELETE lt_travel WHERE CurrencyCode IS INITIAL.
READ ENTITIES OF zi_travel_detail IN LOCAL MODE

ENTITY zi_travel_detail BY _booking
FIELDS ( FlightPrice CurrencyCode )
WITH CORRESPONDING #( lt_travel )
RESULT DATA(lt_ba_booking) .
READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_booking_detail BY _bookingsuppl
FIELDS ( Price CurrencyCode )
WITH CORRESPONDING #( lt_ba_booking )

RESULT DATA(lt_ba_bookingsupp) .

LOOP AT lt_travel ASSIGNING FIELD-SYMBOL(<ls_travel>).
lt_total = VALUE #( ( price = <ls_travel>-BookingFee curr = <ls_travel>-CurrencyCode ) ).

LOOP AT lt_ba_booking ASSIGNING FIELD-SYMBOL(<ls_booking>)
USING KEY entity
WHERE TravelId = <ls_travel>-TravelId
AND CurrencyCode IS NOT INITIAL.
APPEND VALUE #( price = <ls_booking>-FlightPrice curr = <ls_booking>-CurrencyCode )
TO lt_total.
LOOP AT lt_ba_bookingsupp ASSIGNING FIELD-SYMBOL(<ls_bookingsupp>)
USING KEY entity

WHERE TravelId = <ls_booking>-TravelId
AND BookingId = <ls_booking>-BookingId
AND CurrencyCode IS NOT INITIAL.

APPEND VALUE #( price = <ls_bookingsupp>-Price curr = <ls_bookingsupp>-CurrencyCode )
TO lt_total.

ENDLOOP.
ENDLOOP.

LOOP AT lt_total ASSIGNING FIELD-SYMBOL(<ls_total>).

IF <ls_total>-curr = <ls_travel>-CurrencyCode .
lv_conv_price = <ls_total>-price .
ELSE.

/dmo/cl_flight_amdp=>convert_currency(
EXPORTING
iv_amount = <ls_total>-price
iv_currency_code_source = <ls_total>-curr
iv_currency_code_target = <ls_travel>-CurrencyCode
iv_exchange_rate_date = cl_abap_context_info=>get_system_date( )
IMPORTING
ev_amount = lv_conv_price

).

ENDIF.

<ls_travel>-TotalPrice = <ls_travel>-TotalPrice + lv_conv_price.

ENDLOOP.

MODIFY ENTITIES OF zi_travel_detail in LOCAL MODE
ENTITY zi_travel_detail
UPDATE FIELDS ( TotalPrice )
WITH CORRESPONDING #( lt_travel ).
ENDLOOP.

ENDMETHOD.

20.  Class for booking  suppliment

CLASS lhc_zi_booking_supp DEFINITION INHERITING FROM cl_abap_behavior_handler.

PRIVATE SECTION.

METHODS CalcTotalPrice FOR DETERMINE ON MODIFY
IMPORTING keys FOR zi_booking_supp~CalcTotalPrice.
METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR zi_booking_supp RESULT result.
ENDCLASS.

CLASS lhc_zi_booking_supp IMPLEMENTATION.
METHOD CalcTotalPrice.

ENDMETHOD.
METHOD get_global_authorizations.
ENDMETHOD.

ENDCLASS.

CLASS lhc_zi_booking_detail DEFINITION INHERITING FROM cl_abap_behavior_handler.

PRIVATE SECTION.
METHODS earlynumbering_cba_Bookingsupp FOR NUMBERING

IMPORTING entities FOR CREATE zi_booking_detail_Bookingsuppl.
METHODS CalcTotalPrice FOR DETERMINE ON MODIFY
IMPORTING keys FOR zi_booking_detail~CalcTotalPrice.

METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR zi_booking_detail RESULT result.

ENDCLASS.

CLASS lhc_zi_booking_detail IMPLEMENTATION.

METHOD earlynumbering_cba_Bookingsupp.
DATA: max_booking_suppl_id TYPE /dmo/booking_supplement_id .
READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_booking_detail BY _Bookingsuppl
FROM CORRESPONDING #( entities )
LINK DATA(booking_supplements).

” Loop over all unique tky (TravelID + BookingID)
LOOP AT entities ASSIGNING FIELD-SYMBOL(<booking_group>) GROUP BY <booking_group>-%tky.

” Get highest bookingsupplement_id from bookings belonging to booking
max_booking_suppl_id = REDUCE #( INIT max = CONV /dmo/booking_supplement_id( ‘0’ )

FOR booksuppl IN booking_supplements USING KEY entity
WHERE ( source-TravelId = <booking_group>-TravelId
AND source-BookingId = <booking_group>-BookingId )
NEXT max = COND /dmo/booking_supplement_id( WHEN booksuppl-target-BookingSupplementId > max
THEN booksuppl-target-BookingSupplementId
ELSE max )

).
” Get highest assigned bookingsupplement_id from incoming entities

max_booking_suppl_id = REDUCE #( INIT max = max_booking_suppl_id
FOR entity IN entities USING KEY entity
WHERE ( TravelId = <booking_group>-TravelId
AND BookingId = <booking_group>-BookingId )
FOR target IN entity-%target
NEXT max = COND /dmo/booking_supplement_id( WHEN target-BookingSupplementId > max
THEN target-BookingSupplementId
ELSE max )

).
” Loop over all entries in entities with the same TravelID and BookingID
LOOP AT entities ASSIGNING FIELD-SYMBOL(<booking>) USING KEY entity WHERE TravelId = <booking_group>-TravelId
AND BookingId = <booking_group>-BookingId.

” Assign new booking_supplement-ids
LOOP AT <booking>-%target ASSIGNING FIELD-SYMBOL(<booksuppl_wo_numbers>).
APPEND CORRESPONDING #( <booksuppl_wo_numbers> ) TO mapped-zi_booking_supp ASSIGNING FIELD-SYMBOL(<mapped_booksuppl>).
IF <booksuppl_wo_numbers>-BookingSupplementId IS INITIAL.
max_booking_suppl_id += 1 .
<mapped_booksuppl>-BookingSupplementId = max_booking_suppl_id .
ENDIF.
ENDLOOP.
ENDLOOP.
ENDLOOP.
ENDMETHOD.

21. Based on the booking fee  we need to calculate the total price  , So we need to write the logic in calcTotal price method

METHOD CalcTotalPrice.

DATA : it_travel TYPE STANDARD TABLE OF zpd_dt_travel WITH UNIQUE HASHED KEY key COMPONENTS travel_id.
it_travel = CORRESPONDING #( keys DISCARDING DUPLICATES MAPPING travel_id = TravelId ).

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
EXECUTE RecalcTotalPrice
FROM CORRESPONDING #( it_travel ).

ENDMETHOD.

22. OUTPUT

Pradeep555_1-1751356413745.png

 

23. Edit–> changing booking fee from 140 USD to 240 USD

Pradeep555_3-1751356464751.png

 

Pradeep555_4-1751356486334.png

24.   Click on save << after saving , the total price is still the same —> not updated at the screen level 

Pradeep555_5-1751356553915.png

25.  When we refresh the page—the total price gets updated 

Pradeep555_6-1751356589520.png

 

26.  Now we need to use the side effects to make the data refreshed on save at screen level , So now it should not only be updated in the transactional buffer – it should  also be updated in the front end  

Pradeep555_7-1751356689309.png

27.  Change the booking fee 258 USD  and click on save 

Pradeep555_8-1751356741975.png

28. As soon as you click on save 

Pradeep555_9-1751356776648.png

 

Thanks and regards 

-PRADEEP ISHWAR DEVADIGA

 

“}]] 

 [[{“value”:”In the world of SAP RAP (RESTful Application Programming), Determinations and Side Effects play a crucial role in delivering responsive and intelligent user experiences. While determinations are used to implement logic that reacts to changes in data during specific RAP phases (such as on modify or on save), side effects ensure that related fields or entities stay consistent and updated on the UI without additional user actions. In his blog, I will demonstrate a practical scenario where determinations are used to dynamically calculate values based on user input, and side effects are configured to immediately reflect these changes on the UI. This not only improves the data integrity but also enhances usability in Fiori applications. By the end of this post, you will have a clearer understanding of how to leverage determinations and side effects together effectively within a RAP-based application. DETERMINATION : Actions modifies the existing BO instance where as Determination modifies the existing BO instances based on some  trigger condition  We can see that Actions also triggers based on the conditions but cannot modify the BO instances , we can be able to throw the error messages. Pre requisites : During modification we change/modify  some fields / requirements  and we can compute the values of  particular fields Determination can be called during  Transactional phase/Save sequence where as validations always called during the save sequence Once a determination  has been triggered , it must run independently from other determinations During determination result must change if we execute detrmination several time under same condition   Scenario : Here the determination calculateTotalPrice which is defined for all the three entities (Travel, booking and booking supplements) handles the  calculation of total  price of one travel. Based on the booking Fee total price must be calculated for the travel   SIDE-EFFECTS: The SAP Fiori UI does not necessarily trigger a reload of all  related BO after every User input , as it simply does not know anything about data changes  on the tables Side effects are  used to reload data, permissions or messages based on data changes in UI scenarios with draft enabled BO’s  Side effects reloads the screen but it does not reload entire screen   It changes some of the field values or will enable/ disable some of the fied values    Or status of the data in transactional buffer –> based on these same things should appear in the front end  We need to define side effects in Behaviour definition  Side effects will only reload the fields in front end  ,nothing will happen in backend  The data which is available in the backend it will reload in the front end whihc is not currently displaying properly   Side effects have two parts : Triggering condition : specifies when you should reload ( can be actions / validations) Target : which fields should get  reloaded ( value of a field / multiple fields / reload entire entity )  Important points: Determinations calculates the total  price and updates it into the transcational buffer But in the front end screen older values will be there .  Requirement : Whenever I change the booking fee and booking supplement data and flight price The total  price should be updated not only in transactional buffer but also in the front end automatically  And whenever we are updating booking fee the reload of total price should happen  Based on the trigger condition –> it should reload the values / fields   Here the source –> Booking fee Target –> totalprice  Syntax: Side effects { filed MyField affects Target }                          { $self affects Targets ; }                  { action MyAction affects Tragets ;}      { determine action MyDetermineAction      Executed on sources  Affects Tagets } .  In the target we can specify : $self : The current RAP BO is reloaded  Entity _MyAssoc  : the specified associated entity  _MyAssoc is reloaded when the side effect is triggered  Message  : all the messages in the response parameter reported are reloaded when the side effects is triggered  We can  also als provide multiple targets   Side effects { field MyField affects Field1 , Field2 , action Action1 ,                         Action Action 2 [..] }  RESTRICTIONS : Static actions  defined using the addition static must  not be used as a side effect trigger , nor as a side effect target  In case of the trigger entity property $sefl , the target cannot be a field of the current entity $self itself ,  However fields  from the associated entity can be defined using path  expressions   Side Effect In BDL: Side effects can be specified exactly once for each RAP BO entity in the entity  Behaviour definition  Multiple side effects can  be summarized with curly brackets , separated by a semicolon (; ) , if required. The syntax ‘use side effects’ is specified in the behaviour definition header and all  side effects from all  RAP BO entities of the underlying RAP BO are reused  1. Create db table for travel  @EndUserText.label : ‘travel table’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zpd_dt_travel {

key client : abap.clnt not null;
key travel_id : /dmo/travel_id not null;
agency_id : /dmo/agency_id;
customer_id : /dmo/customer_id;
begin_date : /dmo/begin_date;
end_date : /dmo/end_date;
@Semantics.amount.currencyCode : ‘zpd_dt_travel.currency_code’
booking_fee : /dmo/booking_fee;
@Semantics.amount.currencyCode : ‘zpd_dt_travel.currency_code’
total_price : /dmo/total_price;
currency_code : /dmo/currency_code;
description : /dmo/description;
overall_status : /dmo/overall_status;
created_by : abp_creation_user;
created_at : abp_creation_tstmpl;
last_changed_by : abp_locinst_lastchange_user;
last_changed_at : abp_locinst_lastchange_tstmpl;

} 2.Create db table for Booking@EndUserText.label : ‘tbale for booking details’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zpd_dt_booking {

key client : abap.clnt not null;
@AbapCatalog.foreignKey.label : ‘Travel’
@AbapCatalog.foreignKey.screenCheck : false
key travel_id : /dmo/travel_id not null
with foreign key [0..*,1] zpd_dt_travel
where travel_id = zpd_dt_booking.travel_id;
key booking_id : /dmo/booking_id not null;
booking_date : /dmo/booking_date;
customer_id : /dmo/customer_id;
carrier_id : /dmo/carrier_id;
connection_id : /dmo/connection_id;
flight_date : /dmo/flight_date;
@Semantics.amount.currencyCode : ‘zpd_dt_booking.currency_code’
flight_price : /dmo/flight_price;
currency_code : /dmo/currency_code;
booking_status : /dmo/booking_status;
last_changed_at : abp_locinst_lastchange_tstmpl;

}  3.Crete a db table for Booking suppliment@EndUserText.label : ‘booking supplimnet’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zpd_dt_bsupplmnt {

key client : abap.clnt not null;
@AbapCatalog.foreignKey.label : ‘Travel’
@AbapCatalog.foreignKey.screenCheck : false
key travel_id : /dmo/travel_id not null
with foreign key [0..*,1] zpd_dt_travel
where travel_id = zpd_dt_bsupplmnt.travel_id;
@AbapCatalog.foreignKey.label : ‘Booking’
@AbapCatalog.foreignKey.screenCheck : false
key booking_id : /dmo/booking_id not null
with foreign key [0..*,1] zpd_dt_booking
where travel_id = zpd_dt_bsupplmnt.travel_id
and booking_id = zpd_dt_bsupplmnt.booking_id;
key booking_supplement_id : /dmo/booking_supplement_id not null;
supplement_id : /dmo/supplement_id;
@Semantics.amount.currencyCode : ‘zpd_dt_bsupplmnt.currency_code’
price : /dmo/supplement_price;
currency_code : /dmo/currency_code;
last_changed_at : abp_locinst_lastchange_tstmpl;

}  4.Create a root view entity for travelAbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘root view for travel’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED

}

define root view entity zi_travel_detail as select from zpd_dt_travel
composition [0..*] of ZI_BOOKING_DETAIL as _booking
association [0..1] to /DMO/I_Agency as _agency on $projection.AgencyId = _agency.AgencyID
association [0..1] to /DMO/I_Customer as _customer on $projection.CustomerId = _customer.CustomerID
association [1..1] to I_Currency as _currency on $projection.CurrencyCode = _currency.Currency
association [1..1] to /DMO/I_Overall_Status_VH as _status on $projection.OverallStatus = _status.OverallStatus

{

key travel_id as TravelId,
agency_id as AgencyId,
customer_id as CustomerId,
begin_date as BeginDate,
end_date as EndDate,
@Semantics.amount.currencyCode: ‘CurrencyCode’
booking_fee as BookingFee,
@Semantics.amount.currencyCode: ‘CurrencyCode’
total_price as TotalPrice,
currency_code as CurrencyCode,
description as Description,
overall_status as OverallStatus,
@Semantics.user.createdBy: true
created_by as CreatedBy,
@Semantics.systemDateTime.createdAt: true
created_at as CreatedAt,
@Semantics.user.localInstanceLastChangedBy: true
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
last_changed_at as LastChangedAt,
_agency,
_customer,
_currency,
_status,
_booking

} 5.Create interface view  for booking @EndUserText.label: ‘root view for booking’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED

}

define view entity ZI_BOOKING_DETAIL as select from zpd_dt_booking association to parent zi_travel_detail as _travel
on $projection.TravelId = _travel.TravelId
composition [0..*] of zi_booking_supp as _bookingsuppl
association [1..1] to /DMO/I_Carrier as _carrier on $projection.CarrierId = _carrier.AirlineID
association [1..1] to /DMO/I_Customer as _customer on $projection.CustomerId = _customer.CustomerID
association [1..1] to /DMO/I_Connection as _connection on $projection.CarrierId = _connection.AirlineID
and $projection.ConnectionId = _connection.ConnectionID
association[1..1] to /DMO/I_Booking_Status_VH as _booking_status on $projection.BookingStatus = _booking_status.BookingStatus

{

key travel_id as TravelId,
key booking_id as BookingId,
booking_date as BookingDate,
customer_id as CustomerId,
carrier_id as CarrierId,
connection_id as ConnectionId,
flight_date as FlightDate,
@Semantics.amount.currencyCode: ‘CurrencyCode’
flight_price as FlightPrice,
currency_code as CurrencyCode,
booking_status as BookingStatus,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
last_changed_at as LastChangedAt,
_carrier,
_customer,
_connection,
_booking_status,
_travel,
_bookingsuppl
} 6.Create Interface view for Booking suppliment@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘root view for booking suppliment’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}

define view entity zi_booking_supp as select from zpd_dt_bsupplmnt
association to parent ZI_BOOKING_DETAIL as _booking on $projection.TravelId = _booking.TravelId
and $projection.BookingId = _booking.BookingId
association[1..1] to zi_travel_detail as _travel on $projection.TravelId = _travel.TravelId
association [1..1] to /DMO/I_Supplement as _suppliment on $projection.SupplementId = _suppliment.SupplementID
association[1..*] to /DMO/I_SupplementText as _supplimentText on $projection.SupplementId = _supplimentText.SupplementID

{

key travel_id as TravelId,
key booking_id as BookingId,
key booking_supplement_id as BookingSupplementId,
supplement_id as SupplementId,
@Semantics.amount.currencyCode: ‘CurrencyCode’
price as Price,
currency_code as CurrencyCode,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
last_changed_at as LastChangedAt,
_travel,
_supplimentText,
_suppliment,
_booking

} 7.Define projection for travel root entity @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘consumption view for travel’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define root view entity zc_travel_det provider contract transactional_query
as projection on zi_travel_detail

{

key TravelId,
@ObjectModel.text.element: [ ‘AgencyName’ ]
AgencyId,
_Agency.Name as AgencyName,
@ObjectModel.text.element: [ ‘CustomerName’ ]
CustomerId,
_Customer.LastName as CustomerName,
BeginDate,
EndDate,
@Semantics.amount.currencyCode: ‘CurrencyCode’
BookingFee,
@Semantics.amount.currencyCode: ‘CurrencyCode’
TotalPrice,
CurrencyCode,
Description,
@ObjectModel.text.element: [ ‘OverallStatusText’ ]
OverallStatus,
_Status._Text.Text as OverallStatusText : localized,
CreatedBy,
CreatedAt,
LastChangedBy,
LastChangedAt,
/* Associations */
_Agency,
_booking : redirected to composition child zc_booking_det,
_Currency,
_Customer,
_Status

}  8.Define projection for booking  entity@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘consumption view for booking’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define view entity zc_booking_det
as projection on ZI_BOOKING_DETAIL
{

key TravelId,
key BookingId,
BookingDate,
@ObjectModel.text.element: [ ‘CustomerName’ ]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Customer’,
element: ‘CustomerID’

} }]

CustomerId,
_customer.LastName as CustomerName,
@ObjectModel.text.element: [ ‘CarrierName’ ]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Carrier’,
element: ‘AirlineId’

} }]

CarrierId,
_carrier.Name as CarrierName,
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘Connection Id’

}

}]
ConnectionId,
FlightDate,
@Semantics.amount.currencyCode: ‘CurrencyCode’
FlightPrice,
CurrencyCode,
@ObjectModel.text.element: [ ‘BookingStatusText’ ]
_booking_status._Text.Text as BookingStatusText : localized,
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Booking_Status_VH’,
element: ‘Booking_Status’

} }]
BookingStatus,
LastChangedAt,
/* Associations */
_bookingsuppl : redirected to composition child zc_booking_supp,
_booking_status,
_carrier,
_connection,
_customer,
_travel : redirected to parent zc_travel_det

} 9.Define projection for booking  suppliment  entity@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘consumption view for booking suppliment’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define view entity zc_booking_supp
as projection on zi_booking_supp

{

key TravelId,
key BookingId,
key BookingSupplementId,
@ObjectModel.text.element: [ ‘SupplemenDesc’ ]
SupplementId,
_SupplementText.Description as SupplemenDesc : localized,
@Semantics.amount.currencyCode: ‘CurrencyCode’
Price,
CurrencyCode,
LastChangedAt,
/* Associations */
_Travel : redirected to zc_travel_det,
_Booking : redirected to parent zc_booking_det,
_Supplement,
_SupplementText

} 10.provide metada extension for projected views@Metadata.layer: #CORE

@Search.searchable: true
@UI.headerInfo: {
typeName: ‘Travel’,
typeNamePlural: ‘Travels’,

title: {
type: #STANDARD,
label: ‘Travel’,
value: ‘TravelId’

}

}
annotate view zc_travel_det
with

{

@UI.facet: [{
id: ‘Travel’,
purpose: #STANDARD,
position: 10 ,
label: ‘Travel’,
type: #IDENTIFICATION_REFERENCE

},

{

id: ‘Booking’,
purpose: #STANDARD,
position: 20 ,
label: ‘Booking’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_booking’

}

]

@UI.lineItem: [{ position: 10 }, { type:#FOR_ACTION, dataAction: ‘CopyTravel’, label: ‘Copy Travel’ }
,{ type:#FOR_ACTION, dataAction: ‘AcceptTravel’, label: ‘AcceptTravel’ }
,{ position: 30 },{ type:#FOR_ACTION, dataAction: ‘RejectTravel’, label: ‘RejectTravel’ }]
@UI.identification: [{ position: 10 }]
@Search.defaultSearchElement: true
TravelId;
@UI: { lineItem: [{ position: 40 }],
selectionField: [{ position: 40 }],
identification: [{ position: 40 }]

}

@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Agency’,
element: ‘AgencyID’

} }]

AgencyId;
// AgencyName;
@UI: { lineItem: [{ position: 50 }],
selectionField: [{ position: 50 }],
identification: [{ position: 50 }]
}
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Customer’,
element: ‘CustomerID’

} }]
CustomerId;
// CustomerName;
@UI.lineItem: [{ position: 60 }]
@UI.identification: [{ position: 60 }]
BeginDate;
@UI.lineItem: [{ position: 70 }]
@UI.identification: [{ position: 70 }]
EndDate;
@UI.identification: [{ position: 75 }]
BookingFee;
@UI.lineItem: [{ position: 80 }]
@UI.identification: [{ position: 80 }]
TotalPrice;
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘I_Currency’,
element: ‘Currency’
} }]

CurrencyCode;
@UI.identification: [{ position: 85 }]
Description;
@UI: { lineItem: [{ position: 90 }],
selectionField: [{ position: 60 }],
identification: [{ position: 90 }],
textArrangement: #TEXT_ONLY
}
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Overall_Status_VH’,
element: ‘OverallStatus’
} }]

OverallStatus;
// OverallStatusText;
// .hidden: true
// LastChangedAt;

} 11. metadata extension for booking entity@Metadata.layer: #CORE

@Search.searchable: true
@UI.headerInfo: {
typeName: ‘Booking’,
typeNamePlural: ‘Bookings’,

title: {
type: #STANDARD,
label: ‘Booking’,
value: ‘BookingId’

}

}

annotate view zc_booking_det

with

{

@UI.facet: [{
id: ‘Booking’,
purpose: #STANDARD,
position: 10 ,
label: ‘Booking’,
type: #IDENTIFICATION_REFERENCE

},

{

id: ‘BookingSuppl’,
purpose: #STANDARD,
position: 20 ,
label: ‘Booking Suppliments’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_bookingsuppl’

}

]

// .defaultSearchElement: true
// TravelId;

@UI.lineItem: [{ position: 10 }]
@UI.identification: [{ position: 10 }]
@Search.defaultSearchElement: true
BookingId;
@UI.lineItem: [{ position: 20 }]
@UI.identification: [{ position: 20 }]

BookingDate;
@UI.lineItem: [{ position: 30 }]
@UI.identification: [{ position: 30 }]
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Customer’,
element: ‘CustomerID’

} }]

CustomerId;
@UI.lineItem: [{ position: 40 }]
@UI.identification: [{ position: 40 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Carrier’,
element: ‘AirlineID’

} }]

CarrierId;
@UI.lineItem: [{ position: 50 }]
@UI.identification: [{ position: 50 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘ConnectionId’

},

additionalBinding: [{ element: ‘ConnectionId’ ,
localElement: ‘ConnectionID’},
{ element: ‘AirlineID’ ,
localElement: ‘CarrierId’},
{ element: ‘CurrencyCode’ ,
localElement: ‘CurrencyCode’},
{ element: ‘Price’ ,
localElement: ‘FlightPrice’} ]

}]

ConnectionId;
@UI.lineItem: [{ position: 60 }]
@UI.identification: [{ position: 60 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘FlightDate’

},

additionalBinding: [{ element: ‘FlightDate’ ,
localElement: ‘FlightDate’},
{ element: ‘AirlineID’ ,
localElement: ‘CarrierId’},
{ element: ‘CurrencyCode’ ,

localElement: ‘CurrencyCode’},
{ element: ‘Price’ ,
localElement: ‘FlightPrice’} ]

}]

FlightDate;
@UI.lineItem: [{ position: 70 }]
@UI.identification: [{ position: 70 }]
FlightPrice;
// @Consumption.valueHelpDefinition: [{ entity: {
// name: ‘I_Currency’,
// element: ‘Currency’

// } }]

// CurrencyCode;
@UI.lineItem: [{ position: 80 }]
@UI.identification: [{ position: 80 }]
@UI.textArrangement: #TEXT_ONLY
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Booking_Status_VH’,
element: ‘BookingStatus’

} }]

BookingStatus;
// LastChangedAt;

} 12. Metadata extension for booking entity@Metadata.layer: #CORE

@Search.searchable: true
@UI.headerInfo: {
typeName: ‘Booking’,
typeNamePlural: ‘Bookings’,
title: {
type: #STANDARD,
label: ‘Booking’,
value: ‘BookingId’

}

}
annotate view zc_booking_det
with

{

@UI.facet: [{
id: ‘Booking’,
purpose: #STANDARD,
position: 10 ,
label: ‘Booking’,
type: #IDENTIFICATION_REFERENCE

},

{

id: ‘BookingSuppl’,
purpose: #STANDARD,
position: 20 ,
label: ‘Booking Suppliments’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_bookingsuppl’

}

]
// .defaultSearchElement: true
// TravelId;

@UI.lineItem: [{ position: 10 }]
@UI.identification: [{ position: 10 }]
@Search.defaultSearchElement: true
BookingId;
@UI.lineItem: [{ position: 20 }]
@UI.identification: [{ position: 20 }]
BookingDate;
@UI.lineItem: [{ position: 30 }]
@UI.identification: [{ position: 30 }]
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Customer’,
element: ‘CustomerID’

} }]

CustomerId;
@UI.lineItem: [{ position: 40 }]
@UI.identification: [{ position: 40 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Carrier’,
element: ‘AirlineID’

} }]

CarrierId;
@UI.lineItem: [{ position: 50 }]
@UI.identification: [{ position: 50 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘ConnectionId’

},
additionalBinding: [{ element: ‘ConnectionId’ ,
localElement: ‘ConnectionID’},

{ element: ‘AirlineID’ ,
localElement: ‘CarrierId’},
{ element: ‘CurrencyCode’ ,
localElement: ‘CurrencyCode’},
{ element: ‘Price’ ,
localElement: ‘FlightPrice’} ]

}]
ConnectionId;
@UI.lineItem: [{ position: 60 }]
@UI.identification: [{ position: 60 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Flight’,
element: ‘FlightDate’

},

additionalBinding: [{ element: ‘FlightDate’ ,
localElement: ‘FlightDate’},
{ element: ‘AirlineID’ ,
localElement: ‘CarrierId’},
{ element: ‘CurrencyCode’ ,
localElement: ‘CurrencyCode’},
{ element: ‘Price’ ,
localElement: ‘FlightPrice’} ]

}]
FlightDate;
@UI.lineItem: [{ position: 70 }]
@UI.identification: [{ position: 70 }]

FlightPrice;
// @Consumption.valueHelpDefinition: [{ entity: {
// name: ‘I_Currency’,
// element: ‘Currency’
// } }]

// CurrencyCode;
@UI.lineItem: [{ position: 80 }]
@UI.identification: [{ position: 80 }]
@UI.textArrangement: #TEXT_ONLY
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_Booking_Status_VH’,
element: ‘BookingStatus’

} }]
BookingStatus;
// LastChangedAt;

}  13. Metadata extension for booking  suppliment entity@Metadata.layer: #CORE

@Search.searchable: true
@UI.headerInfo: {
typeName: ‘BookingSuppl’,
typeNamePlural: ‘BookingSuppls’,
title: {
type: #STANDARD,
label: ‘Booking Suppliments’,
value: ‘BookingSupplementId’

}
}

annotate view zc_booking_supp
with
{
@UI.facet: [{
id: ‘BookingSuppl’,
purpose: #STANDARD,
position: 10 ,
label: ‘Booking Suppliments’,
type: #IDENTIFICATION_REFERENCE
}
]
// @Search.defaultSearchElement: true
// TravelId;
@Search.defaultSearchElement: true
BookingId;
@UI.lineItem: [{ position: 10 }]
@UI.identification: [{ position: 10 }]
BookingSupplementId;
@UI.lineItem: [{ position: 20 }]
@UI.identification: [{ position: 20 }]
@Consumption.valueHelpDefinition: [{ entity: {
name: ‘/DMO/I_SUPPLEMENT’,
element: ‘SupplementID’
},

additionalBinding: [{ element: ‘SupplementID’ ,
localElement: ‘SupplementId’},
{ element: ‘Price’ ,
localElement: ‘Price’},
{ element: ‘CurrencyCode’ ,
localElement: ‘CurrencyCode’}

]

}]
SupplementId;
@UI.lineItem: [{ position: 30 }]
@UI.identification: [{ position: 30 }]

Price;
// @Consumption.valueHelpDefinition: [{ entity: {
// name: ‘I_Currency’,
// element: ‘Currency’
// } }]
// CurrencyCode;
// @UI.hidden: true
// LastChangedAt;

} 14. Create behaviour definition travel root entity managed;

strict ( 2 );
define behavior for zi_travel_detail //alias <alias_name>
implementation in class zcl_bp_travel_maa unique
persistent table zpd_dt_travel
lock master
authorization master ( global )
etag master LastChangedAt
early numbering

{

field ( readonly ) TravelId;
action AcceptTravel result [1] $self;
action RejectTravel result [1] $self;

factory action CopyTravel [1];
internal action RecalcTotalPrice;
determination CalcTotalPrice on modify { create; field BookingFee, CurrencyCode; }

// authorization ( global ),
create;
update;
delete;
// field ( readonly ) TravelId;
association _booking { create; }
mapping for zpd_dt_travel
{

TravelId = travel_id;
AgencyId = agency_id;
CustomerId = customer_id;
BeginDate = begin_date;
EndDate = end_date;
BookingFee = booking_fee;
TotalPrice = total_price;
CurrencyCode = currency_code;
Description = description;
OverallStatus = overall_status;
CreatedBy = created_by;
CreatedAt = created_at;
LastChangedBy = last_changed_by;
LastChangedAt = last_changed_at;

}
}
define behavior for ZI_BOOKING_DETAIL //alias <alias_name>
implementation in class zcl_bp_booking_ma unique
persistent table zpd_dt_booking
lock dependent by _Travel
//authorization dependent by _travel
authorization master ( global )
etag master LastChangedAt
early numbering
{
update;
delete;
field ( readonly ) TravelId, BookingId;

determination CalcTotalPrice on modify { create; field FlightPrice, CurrencyCode; }
association _travel;
association _bookingsuppl { create; }
mapping for zpd_dt_booking

{
TravelId = travel_id;
BookingId = booking_id;
BookingDate = booking_date;
CustomerId = customer_id;
CarrierId = carrier_id;
ConnectionId = connection_id;
FlightDate = flight_date;
FlightPrice = flight_price;

CurrencyCode = currency_code;
BookingStatus = booking_status;
LastChangedAt = last_changed_at;

}

}
define behavior for zi_booking_supp //alias <alias_name>
implementation in class zcl_bp_booking_ma unique
persistent table zpd_dt_bsupplmnt
lock dependent by _Travel
//authorization dependent by _Travel
authorization master ( global )
etag master LastChangedAt
early numbering

{
update;
delete;
field ( readonly ) TravelId, BookingId, BookingSupplementId;
determination CalcTotalPrice on modify { create; field Price, CurrencyCode; }
association _Travel;
association _Booking;
mapping for zpd_dt_bsupplmnt
{

SupplementId = supplement_id;
TravelId = travel_id;
BookingId = booking_id;
BookingSupplementId = booking_supplement_id;
Price = price;
CurrencyCode = currency_code;
LastChangedAt = last_changed_at;

}

} 15. Define behavior definition for projection root entity projection;

strict ( 2 );
define behavior for zc_travel_det //alias <alias_name>

{
use create;
use update;
use delete;

use action AcceptTravel;
use action RejectTravel;
use action CopyTravel;
use association _booking { create; }

}
define behavior for zc_booking_det //alias <alias_name>

{

use update;
use delete;
use association _travel;
use association _bookingsuppl { create; }

}

define behavior for zc_booking_supp //alias <alias_name>
{

use update;
use delete;

use association _Travel;
use association _Booking;

} 16. Create Service Definition@EndUserText.label: ‘service def for travel’
define service Zsr_travel_det {

expose zc_travel_det;
expose zc_booking_det;
expose zc_booking_supp;
expose /DMO/I_Supplement_StdVH as Supplement;
expose /DMO/I_SupplementCategory_VH as SupplementCategory;
expose /DMO/I_Customer_StdVH as Passenger;
expose /DMO/I_Agency_StdVH as TravelAgency;
expose /DMO/I_Carrier_StdVH as Airline;
expose /DMO/I_Connection_StdVH as FlightConnection;
expose /DMO/I_Flight_StdVH as Flight;
expose /DMO/I_Airport_StdVH as Airport;
expose /DMO/I_Overall_Status_VH as OverallStatus;
expose /DMO/I_Booking_Status_VH as BookingStatus;
expose I_CurrencyStdVH as Currency;
expose I_CountryVH as Country;

} 17. Create service binding 18. Implement the class CLASS lhc_zi_travel_detail DEFINITION INHERITING FROM cl_abap_behavior_handler.

PRIVATE SECTION.

METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR zi_travel_detail RESULT result.
METHODS accepttravel FOR MODIFY
IMPORTING keys FOR ACTION zi_travel_detail~accepttravel RESULT result.
METHODS copytravel FOR MODIFY
IMPORTING keys FOR ACTION zi_travel_detail~copytravel.
METHODS recalctotalprice FOR MODIFY
IMPORTING keys FOR ACTION zi_travel_detail~recalctotalprice.
METHODS rejecttravel FOR MODIFY
IMPORTING keys FOR ACTION zi_travel_detail~rejecttravel RESULT result.
METHODS calctotalprice FOR DETERMINE ON MODIFY
IMPORTING keys FOR zi_travel_detail~calctotalprice.
METHODS earlynumbering_cba_booking FOR NUMBERING
IMPORTING entities FOR CREATE zi_travel_detail_booking.
METHODS earlynumbering_create FOR NUMBERING
IMPORTING entities FOR CREATE zi_travel_detail.

ENDCLASS.

CLASS lhc_zi_travel_detail IMPLEMENTATION.
METHOD get_global_authorizations.
ENDMETHOD.

METHOD earlynumbering_create.
DATA(lt_entities) = entities.
DELETE lt_entities WHERE TravelId IS NOT INITIAL .
TRY.
cl_numberrange_runtime=>number_get(

EXPORTING
nr_range_nr = ’01’
object = ‘/DMO/TRV_M’
quantity = CONV #( lines( lt_entities ) )
IMPORTING
number = DATA(lv_latest_num)
returncode = DATA(lv_code)
returned_quantity = DATA(lv_qty)

).
CATCH cx_nr_object_not_found.
CATCH cx_number_ranges INTO DATA(lo_error).

LOOP AT lt_entities INTO DATA(ls_entities).
APPEND VALUE #( %cid = ls_entities-%cid
%key = ls_entities-%key )
TO failed-zi_travel_detail.
APPEND VALUE #( %cid = ls_entities-%cid
%key = ls_entities-%key
%msg = lo_error )
TO reported-zi_travel_detail.
ENDLOOP.
EXIT.
ENDTRY..

ASSERT lv_qty = lines( lt_entities ).
DATA(lv_curr_num) = lv_latest_num – lv_qty.
LOOP AT lt_entities INTO ls_entities.
lv_curr_num = lv_curr_num + 1.
APPEND VALUE #( %cid = ls_entities-%cid
TravelId = lv_curr_num )
TO mapped-zi_travel_detail.
ENDLOOP.
ENDMETHOD.

METHOD earlynumbering_cba_Booking.

DATA : lv_max_booking TYPE /dmo/booking_id.
READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail BY _booking
FROM CORRESPONDING #( entities )
LINK DATA(lt_link_data).
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_group_entity>)
GROUP BY <ls_group_entity>-TravelId.

lv_max_booking = REDUCE #( INIT lv_max = CONV /dmo/booking_id( ‘0’ )
FOR ls_link IN lt_link_data USING KEY entity
WHERE ( source-TravelId = <ls_group_entity>-TravelId )
NEXT lv_max = COND /dmo/booking_id( WHEN lv_max < ls_link-target-BookingId
THEN ls_link-target-BookingId
ELSE lv_max ) ).

lv_max_booking = REDUCE #( INIT lv_max = lv_max_booking
FOR ls_entity IN entities USING KEY entity
WHERE ( TravelId = <ls_group_entity>-TravelId )
FOR ls_booking IN ls_entity-%target
NEXT lv_max = COND /dmo/booking_id( WHEN lv_max < ls_booking-BookingId
THEN ls_booking-BookingId
ELSE lv_max ) ).
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entities>)
USING KEY entity
WHERE TravelId = <ls_group_entity>-TravelId.

LOOP AT <ls_entities>-%target ASSIGNING FIELD-SYMBOL(<ls_booking>).
IF <ls_booking>-BookingId IS INITIAL.
lv_max_booking += 10.
APPEND CORRESPONDING #( <ls_booking> ) TO mapped-zi_booking_detail ASSIGNING FIELD-SYMBOL(<ls_new_map_book>).
<ls_new_map_book>-BookingId = lv_max_booking.

ENDIF.
ENDLOOP.
ENDLOOP.

ENDLOOP.
ENDMETHOD.

METHOD AcceptTravel.
MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail

UPDATE FIELDS ( OverallStatus )
WITH VALUE #( FOR ls_keys IN keys ( %tky = ls_keys-%tky
OverallStatus = ‘A’) ).
READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_result).
result = VALUE #( FOR ls_result IN lt_result ( %tky = ls_result-%tky
%param = ls_result ) ).

ENDMETHOD.
METHOD CopyTravel.
ENDMETHOD.

METHOD RecalcTotalPrice.

TYPES : BEGIN OF ty_total,
price TYPE /dmo/total_price,
curr TYPE /dmo/currency_code,
END OF ty_total.

DATA : lt_total TYPE TABLE OF ty_total,
lv_conv_price TYPE ty_total-price.

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
FIELDS ( BookingFee CurrencyCode )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
DELETE lt_travel WHERE CurrencyCode IS INITIAL.

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail BY _booking
FIELDS ( FlightPrice CurrencyCode )
WITH CORRESPONDING #( lt_travel )
RESULT DATA(lt_ba_booking) .

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_booking_detail BY _bookingsuppl
FIELDS ( Price CurrencyCode )
WITH CORRESPONDING #( lt_ba_booking )
RESULT DATA(lt_ba_bookingsupp) .
LOOP AT lt_travel ASSIGNING FIELD-SYMBOL(<ls_travel>).
lt_total = VALUE #( ( price = <ls_travel>-BookingFee curr = <ls_travel>-CurrencyCode ) ).

LOOP AT lt_ba_booking ASSIGNING FIELD-SYMBOL(<ls_booking>)
USING KEY entity
WHERE TravelId = <ls_travel>-TravelId
AND CurrencyCode IS NOT INITIAL.

APPEND VALUE #( price = <ls_booking>-FlightPrice curr = <ls_booking>-CurrencyCode )
TO lt_total.

LOOP AT lt_ba_bookingsupp ASSIGNING FIELD-SYMBOL(<ls_bookingsupp>)
USING KEY entity
WHERE TravelId = <ls_booking>-TravelId

AND BookingId = <ls_booking>-BookingId
AND CurrencyCode IS NOT INITIAL.
APPEND VALUE #( price = <ls_bookingsupp>-Price curr = <ls_bookingsupp>-CurrencyCode )

TO lt_total.
ENDLOOP.
ENDLOOP.

LOOP AT lt_total ASSIGNING FIELD-SYMBOL(<ls_total>).
IF <ls_total>-curr = <ls_travel>-CurrencyCode .
lv_conv_price = <ls_total>-price .
ELSE.

/dmo/cl_flight_amdp=>convert_currency(

EXPORTING
iv_amount = <ls_total>-price
iv_currency_code_source = <ls_total>-curr
iv_currency_code_target = <ls_travel>-CurrencyCode
iv_exchange_rate_date = cl_abap_context_info=>get_system_date( )
IMPORTING
ev_amount = lv_conv_price

).

ENDIF.
<ls_travel>-TotalPrice = <ls_travel>-TotalPrice + lv_conv_price.
ENDLOOP.

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
UPDATE FIELDS ( TotalPrice )
WITH CORRESPONDING #( lt_travel ).
ENDLOOP.

ENDMETHOD.
METHOD RejectTravel.

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE

ENTITY zi_travel_detail
UPDATE FIELDS ( OverallStatus )
WITH VALUE #( FOR ls_keys IN keys ( %tky = ls_keys-%tky
OverallStatus = ‘X’) )
REPORTED DATA(lt_travel).

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_result).
result = VALUE #( FOR ls_result IN lt_result ( %tky = ls_result-%tky
%param = ls_result ) ).
ENDMETHOD.

METHOD CalcTotalPrice.

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
EXECUTE RecalcTotalPrice
FROM CORRESPONDING #( keys ).
ENDMETHOD.

ENDCLASS. 18. Here we are calculating the total  price , whenever somebody changes the total  Price and currency manually this determination  should call on transactional phase(on modify) METHOD CalcTotalPrice.

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
EXECUTE RecalcTotalPrice
FROM CORRESPONDING #( keys ).

ENDMETHOD. 19.  will call RecacTotalPrice for each determination All the travel id which we modify  will trigger when we are calculating total price  RecacTotalPrice–> will be called . We need to write the logic to modify Our BO instance based on travel ID And it will read and updae the price   Here the action will take care of the process – when we change the price  ( based on determination ) action will be called  And as soon as price filed changes, determination happens  And we need to read the travel entity with fields booking fee and currency code  And we need to provide travel IDs which is present in keys  Result is taken in LT_TRAVEL Same thing we need to do it for boking and booking suppliment METHOD RecalcTotalPrice.

TYPES : BEGIN OF ty_total,
price TYPE /dmo/total_price,
curr TYPE /dmo/currency_code,
END OF ty_total.

DATA : lt_total TYPE TABLE OF ty_total,
lv_conv_price TYPE ty_total-price.

READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
FIELDS ( BookingFee CurrencyCode )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).

DELETE lt_travel WHERE CurrencyCode IS INITIAL.
READ ENTITIES OF zi_travel_detail IN LOCAL MODE

ENTITY zi_travel_detail BY _booking
FIELDS ( FlightPrice CurrencyCode )
WITH CORRESPONDING #( lt_travel )
RESULT DATA(lt_ba_booking) .
READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_booking_detail BY _bookingsuppl
FIELDS ( Price CurrencyCode )
WITH CORRESPONDING #( lt_ba_booking )

RESULT DATA(lt_ba_bookingsupp) .

LOOP AT lt_travel ASSIGNING FIELD-SYMBOL(<ls_travel>).
lt_total = VALUE #( ( price = <ls_travel>-BookingFee curr = <ls_travel>-CurrencyCode ) ).

LOOP AT lt_ba_booking ASSIGNING FIELD-SYMBOL(<ls_booking>)
USING KEY entity
WHERE TravelId = <ls_travel>-TravelId
AND CurrencyCode IS NOT INITIAL.
APPEND VALUE #( price = <ls_booking>-FlightPrice curr = <ls_booking>-CurrencyCode )
TO lt_total.
LOOP AT lt_ba_bookingsupp ASSIGNING FIELD-SYMBOL(<ls_bookingsupp>)
USING KEY entity

WHERE TravelId = <ls_booking>-TravelId
AND BookingId = <ls_booking>-BookingId
AND CurrencyCode IS NOT INITIAL.

APPEND VALUE #( price = <ls_bookingsupp>-Price curr = <ls_bookingsupp>-CurrencyCode )
TO lt_total.

ENDLOOP.
ENDLOOP.

LOOP AT lt_total ASSIGNING FIELD-SYMBOL(<ls_total>).

IF <ls_total>-curr = <ls_travel>-CurrencyCode .
lv_conv_price = <ls_total>-price .
ELSE.

/dmo/cl_flight_amdp=>convert_currency(
EXPORTING
iv_amount = <ls_total>-price
iv_currency_code_source = <ls_total>-curr
iv_currency_code_target = <ls_travel>-CurrencyCode
iv_exchange_rate_date = cl_abap_context_info=>get_system_date( )
IMPORTING
ev_amount = lv_conv_price

).

ENDIF.

<ls_travel>-TotalPrice = <ls_travel>-TotalPrice + lv_conv_price.

ENDLOOP.

MODIFY ENTITIES OF zi_travel_detail in LOCAL MODE
ENTITY zi_travel_detail
UPDATE FIELDS ( TotalPrice )
WITH CORRESPONDING #( lt_travel ).
ENDLOOP.

ENDMETHOD. 20.  Class for booking  supplimentCLASS lhc_zi_booking_supp DEFINITION INHERITING FROM cl_abap_behavior_handler.

PRIVATE SECTION.

METHODS CalcTotalPrice FOR DETERMINE ON MODIFY
IMPORTING keys FOR zi_booking_supp~CalcTotalPrice.
METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR zi_booking_supp RESULT result.
ENDCLASS.

CLASS lhc_zi_booking_supp IMPLEMENTATION.
METHOD CalcTotalPrice.

ENDMETHOD.
METHOD get_global_authorizations.
ENDMETHOD.

ENDCLASS.

CLASS lhc_zi_booking_detail DEFINITION INHERITING FROM cl_abap_behavior_handler.

PRIVATE SECTION.
METHODS earlynumbering_cba_Bookingsupp FOR NUMBERING

IMPORTING entities FOR CREATE zi_booking_detail_Bookingsuppl.
METHODS CalcTotalPrice FOR DETERMINE ON MODIFY
IMPORTING keys FOR zi_booking_detail~CalcTotalPrice.

METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR zi_booking_detail RESULT result.

ENDCLASS.

CLASS lhc_zi_booking_detail IMPLEMENTATION.

METHOD earlynumbering_cba_Bookingsupp.
DATA: max_booking_suppl_id TYPE /dmo/booking_supplement_id .
READ ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_booking_detail BY _Bookingsuppl
FROM CORRESPONDING #( entities )
LINK DATA(booking_supplements).

” Loop over all unique tky (TravelID + BookingID)
LOOP AT entities ASSIGNING FIELD-SYMBOL(<booking_group>) GROUP BY <booking_group>-%tky.

” Get highest bookingsupplement_id from bookings belonging to booking
max_booking_suppl_id = REDUCE #( INIT max = CONV /dmo/booking_supplement_id( ‘0’ )

FOR booksuppl IN booking_supplements USING KEY entity
WHERE ( source-TravelId = <booking_group>-TravelId
AND source-BookingId = <booking_group>-BookingId )
NEXT max = COND /dmo/booking_supplement_id( WHEN booksuppl-target-BookingSupplementId > max
THEN booksuppl-target-BookingSupplementId
ELSE max )

).
” Get highest assigned bookingsupplement_id from incoming entities

max_booking_suppl_id = REDUCE #( INIT max = max_booking_suppl_id
FOR entity IN entities USING KEY entity
WHERE ( TravelId = <booking_group>-TravelId
AND BookingId = <booking_group>-BookingId )
FOR target IN entity-%target
NEXT max = COND /dmo/booking_supplement_id( WHEN target-BookingSupplementId > max
THEN target-BookingSupplementId
ELSE max )

).
” Loop over all entries in entities with the same TravelID and BookingID
LOOP AT entities ASSIGNING FIELD-SYMBOL(<booking>) USING KEY entity WHERE TravelId = <booking_group>-TravelId
AND BookingId = <booking_group>-BookingId.

” Assign new booking_supplement-ids
LOOP AT <booking>-%target ASSIGNING FIELD-SYMBOL(<booksuppl_wo_numbers>).
APPEND CORRESPONDING #( <booksuppl_wo_numbers> ) TO mapped-zi_booking_supp ASSIGNING FIELD-SYMBOL(<mapped_booksuppl>).
IF <booksuppl_wo_numbers>-BookingSupplementId IS INITIAL.
max_booking_suppl_id += 1 .
<mapped_booksuppl>-BookingSupplementId = max_booking_suppl_id .
ENDIF.
ENDLOOP.
ENDLOOP.
ENDLOOP.
ENDMETHOD. 21. Based on the booking fee  we need to calculate the total price  , So we need to write the logic in calcTotal price methodMETHOD CalcTotalPrice.

DATA : it_travel TYPE STANDARD TABLE OF zpd_dt_travel WITH UNIQUE HASHED KEY key COMPONENTS travel_id.
it_travel = CORRESPONDING #( keys DISCARDING DUPLICATES MAPPING travel_id = TravelId ).

MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE
ENTITY zi_travel_detail
EXECUTE RecalcTotalPrice
FROM CORRESPONDING #( it_travel ).

ENDMETHOD. 22. OUTPUT 23. Edit–> changing booking fee from 140 USD to 240 USD 24.   Click on save << after saving , the total price is still the same —> not updated at the screen level 25.  When we refresh the page—the total price gets updated  26.  Now we need to use the side effects to make the data refreshed on save at screen level , So now it should not only be updated in the transactional buffer – it should  also be updated in the front end  27.  Change the booking fee 258 USD  and click on save 28. As soon as you click on save  Thanks and regards -PRADEEP ISHWAR DEVADIGA “}]] Read More Application Development and Automation Blog Posts articles 

By ali