RAP business object creation (managed, unmanaged, abstract), behavior definitions, determinations, validations, actions, draft handling, authorization control
RAP business object creation (managed, unmanaged, abstract), behavior definitions, determinations, validations, actions, draft handling, authorization control
Implement RESTful ABAP Programming Model (RAP) business objects with proper behavior definitions, draft handling, authorization, and best practices.
@EndUserText.label : 'Travel Booking'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table ztravelbook {
key client : abap.clnt not null;
key travel_uuid : sysuuid_x16 not null;
travel_id : abap.numc(10);
agency_id : abap.char(6);
customer_id : abap.char(8);
begin_date : abap.dats;
end_date : abap.dats;
booking_fee : abap.curr(17,2);
total_price : abap.curr(17,2);
currency_code : abap.cuky(5);
description : abap.char(255);
status : abap.char(1);
created_by : abap.uname;
created_at : timestampl;
last_changed_by : abap.uname;
last_changed_at : timestampl;
@AbapCatalog.foreignKey.keyType : #KEY
@AbapCatalog.foreignKey.screenCheck : true
foreign key [0..1,1] zagency
references zagency
on delete restrict
agency_id;
}
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Travel Booking Interface'
define root view entity ZI_TravelBooking
as select from ztravelbook
composition [0..*] of ZI_TravelBookingItem as _Items
association [0..1] to ZI_Agency as _Agency on $projection.AgencyID = _Agency.AgencyID
association [0..1] to ZI_Customer as _Customer on $projection.CustomerID = _Customer.CustomerID
{
key travel_uuid as TravelUUID,
travel_id as TravelID,
agency_id as AgencyID,
customer_id as CustomerID,
begin_date as BeginDate,
end_date as EndDate,
booking_fee as BookingFee,
total_price as TotalPrice,
currency_code as CurrencyCode,
description as Description,
status as Status,
created_by as CreatedBy,
created_at as CreatedAt,
last_changed_by as LastChangedBy,
last_changed_at as LastChangedAt,
/* Associations */
_Items,
_Agency,
_Customer,
/* Calculated fields */
@EndUserText.label: 'Duration in Days'
cast(end_date - begin_date as abap.int4) as DurationInDays
}
@EndUserText.label: 'Travel Booking Projection'
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
@Search.searchable: true
define view entity ZC_TravelBooking
as projection on ZI_TravelBooking
{
key TravelUUID,
TravelID,
AgencyID,
CustomerID,
BeginDate,
EndDate,
BookingFee,
TotalPrice,
CurrencyCode,
Description,
Status,
CreatedBy,
CreatedAt,
LastChangedBy,
LastChangedAt,
DurationInDays,
/* Associations */
_Items,
_Agency,
_Customer,
/* UI Annotations */
@UI: {
lineItem: [ { position: 10, importance: #HIGH },
{ type: #FOR_ACTION, dataAction: 'submit', label: 'Submit' } ],
identification: [ { position: 10, label: 'Travel ID' } ],
fieldGroup: [ { qualifier: 'General', position: 10 } ],
selectionField: [ { position: 10 } ]
}
TravelID,
@UI: {
lineItem: [ { position: 20 } ],
identification: [ { position: 20 } ],
fieldGroup: [ { qualifier: 'General', position: 20 } ]
}
Description,
@UI: {
lineItem: [ { position: 30 } ],
identification: [ { position: 30 } ],
fieldGroup: [ { qualifier: 'General', position: 30 } ]
}
Status,
@Consumption.valueHelpDefinition: [ { entity: { name: 'ZC_Agency', element: 'AgencyID' } } ]
AgencyID,
@Consumption.valueHelpDefinition: [ { entity: { name: 'ZC_Customer', element: 'CustomerID' } } ]
CustomerID
}
managed implementation in class zbp_i_travelbooking unique;
strict ( 2 );
with draft;
define behavior for ZI_TravelBooking alias TravelBooking
persistent table ztravelbook
draft table ztravelbook_d
lock master total etag LastChangedAt
authorization master ( instance )
{
// Field control
field ( readonly ) TravelUUID, CreatedBy, CreatedAt;
field ( mandatory ) AgencyID, CustomerID, BeginDate, EndDate;
field ( readonly : update ) TravelID;
// CRUD operations
create;
update;
delete;
// Draft actions
draft action Resume;
draft action Edit;
draft action Activate;
draft action Discard;
// Standard actions
action ( features : instance ) submit result [1] $self;
action ( features : instance ) cancel result [1] $self;
// Determinations
determination setTravelID on modify { create; }
determination calculateTotalPrice on modify { create; update; }
determination validateDates on modify { create; update; }
// Validations
validation validateBookingDates on save { create; update; }
validation validateCustomer on save { create; update; }
// Side effects
association _Items { create; update; delete; }
association _Agency { read; }
association _Customer { read; }
}
define behavior for ZI_TravelBookingItem alias TravelBookingItem
persistent table ztravelbookitem
draft table ztravelbookitem_d
lock dependent by _TravelBooking
authorization dependent by _TravelBooking
{
field ( readonly ) TravelUUID, ItemUUID;
field ( mandatory ) TravelID, Description, Price;
create;
update;
delete;
association _TravelBooking { create; }
}
CLASS lhc_travelbooking DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS setTravelID FOR DETERMINE ON MODIFY
IMPORTING keys FOR TravelBooking~setTravelID.
METHODS calculateTotalPrice FOR DETERMINE ON MODIFY
IMPORTING keys FOR TravelBooking~calculateTotalPrice.
METHODS validateDates FOR DETERMINE ON MODIFY
IMPORTING keys FOR TravelBooking~validateDates.
METHODS validateBookingDates FOR VALIDATE ON SAVE
IMPORTING keys FOR TravelBooking~validateBookingDates.
METHODS validateCustomer FOR VALIDATE ON SAVE
IMPORTING keys FOR TravelBooking~validateCustomer.
METHODS submit FOR MODIFY
IMPORTING keys FOR ACTION TravelBooking~submit
RESULT result.
METHODS cancel FOR MODIFY
IMPORTING keys FOR ACTION TravelBooking~cancel
RESULT result.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR TravelBooking
RESULT result.
ENDCLASS.
CLASS lhc_travelbooking IMPLEMENTATION.
METHOD setTravelID.
" Read travel bookings
READ ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking
FIELDS ( TravelID )
WITH CORRESPONDING #( keys )
RESULT DATA(travel_bookings).
" Get next number
DATA(number_range) = cl_numberrange_runtime=>number_get(
exporting
nr_range_nr = '01'
object = 'ZTRAVELBOOK'
quantity = lines( travel_bookings )
).
" Update travel bookings
LOOP AT travel_bookings ASSIGNING FIELD-SYMBOL(<booking>).
<booking>-TravelID = number_range-number.
number_range-number = number_range-number + 1.
ENDLOOP.
" Modify entities
MODIFY ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking
UPDATE FIELDS ( TravelID )
WITH CORRESPONDING #( travel_bookings ).
ENDMETHOD.
METHOD calculateTotalPrice.
" Read travel bookings with items
READ ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(travel_bookings).
READ ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking BY \_Items
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(items).
" Calculate total price
LOOP AT travel_bookings ASSIGNING FIELD-SYMBOL(<booking>).
DATA(total) = <booking>-BookingFee.
LOOP AT items INTO DATA(item) WHERE TravelUUID = <booking>-TravelUUID.
total = total + item-Price.
ENDLOOP.
<booking>-TotalPrice = total.
ENDLOOP.
" Update entities
MODIFY ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking
UPDATE FIELDS ( TotalPrice )
WITH CORRESPONDING #( travel_bookings ).
ENDMETHOD.
METHOD validateDates.
" Read travel bookings
READ ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking
FIELDS ( BeginDate EndDate Status )
WITH CORRESPONDING #( keys )
RESULT DATA(travel_bookings).
" Validate dates
LOOP AT travel_bookings ASSIGNING FIELD-SYMBOL(<booking>).
IF <booking>-EndDate < <booking>-BeginDate.
APPEND VALUE #( TravelUUID = <booking>-TravelUUID ) TO failed-travelbooking.
APPEND VALUE #( TravelUUID = <booking>-TravelUUID
%msg = new_message( id = 'ZTRAVELBOOK'
number = '001'
severity = if_abap_behv_message=>severity-error
v1 = |End date must be after begin date| )
%element-BeginDate = if_abap_behv=>mk-on
%element-EndDate = if_abap_behv=>mk-on ) TO reported-travelbooking.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD validateBookingDates.
" Similar validation logic
ENDMETHOD.
METHOD validateCustomer.
" Validate customer exists and is active
READ ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking
FIELDS ( CustomerID )
WITH CORRESPONDING #( keys )
RESULT DATA(travel_bookings).
" Check customer
SELECT SINGLE FROM zcustomer
FIELDS customer_id
WHERE customer_id = @<booking>-CustomerID
AND status = 'A'
INTO @DATA(customer_exists).
IF customer_exists IS INITIAL.
APPEND VALUE #( TravelUUID = <booking>-TravelUUID ) TO failed-travelbooking.
APPEND VALUE #( TravelUUID = <booking>-TravelUUID
%msg = new_message( id = 'ZTRAVELBOOK'
number = '002'
severity = if_abap_behv_message=>severity-error
v1 = |Customer not found or inactive| )
%element-CustomerID = if_abap_behv=>mk-on ) TO reported-travelbooking.
ENDIF.
ENDMETHOD.
METHOD submit.
" Read travel bookings
READ ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(travel_bookings).
" Update status
LOOP AT travel_bookings ASSIGNING FIELD-SYMBOL(<booking>).
<booking>-Status = 'S'. " Submitted
ENDLOOP.
" Modify entities
MODIFY ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking
UPDATE FIELDS ( Status )
WITH CORRESPONDING #( travel_bookings ).
" Return result
result = VALUE #( FOR booking IN travel_bookings
( TravelUUID = booking-TravelUUID
%param = booking ) ).
ENDMETHOD.
METHOD cancel.
" Similar to submit, set status to 'C' (Cancelled)
ENDMETHOD.
METHOD get_instance_authorizations.
" Implement instance-level authorization checks
READ ENTITIES OF ZI_TravelBooking IN LOCAL MODE
ENTITY TravelBooking
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(travel_bookings).
LOOP AT travel_bookings INTO DATA(booking).
" Check authorization
AUTHORITY-CHECK OBJECT 'ZTRAVELBOOK'
ID 'ACTVT' FIELD '02'
ID 'AGENCYID' FIELD booking-AgencyID.
IF sy-subrc = 0.
result = VALUE #( ( TravelUUID = booking-TravelUUID
%update = if_abap_behv=>auth-allowed
%delete = if_abap_behv=>auth-allowed
%action-submit = if_abap_behv=>auth-allowed ) ).
ELSE.
result = VALUE #( ( TravelUUID = booking-TravelUUID
%update = if_abap_behv=>auth-unauthorized
%delete = if_abap_behv=>auth-unauthorized
%action-submit = if_abap_behv=>auth-unauthorized ) ).
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
@EndUserText.label : 'Travel Booking Draft'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
define table ztravelbook_d {
key client : abap.clnt not null;
key travel_uuid : sysuuid_x16 not null;
%is_draft : abap.boolean;
travel_id : abap.numc(10);
agency_id : abap.char(6);
customer_id : abap.char(8);
begin_date : abap.dats;
end_date : abap.dats;
booking_fee : abap.curr(17,2);
total_price : abap.curr(17,2);
currency_code : abap.cuky(5);
description : abap.char(255);
status : abap.char(1);
created_by : abap.uname;
created_at : timestampl;
last_changed_by : abap.uname;
last_changed_at : timestampl;
%prep_action : abap.char(10);
%action : abap.char(10);
%control-travel_id : abap.int1;
%control-agency_id : abap.int1;
%control-customer_id : abap.int1;
%control-begin_date : abap.int1;
%control-end_date : abap.int1;
%control-booking_fee : abap.int1;
%control-total_price : abap.int1;
%control-currency_code : abap.int1;
%control-description : abap.int1;
%control-status : abap.int1;
}
@EndUserText.label: 'Travel Booking Service'
define service ZUI_TRAVELBOOKING_O4 {
expose ZC_TravelBooking as TravelBooking;
expose ZC_TravelBookingItem as TravelBookingItem;
}
fiori-development - Fiori Elements UI configurationcds-modeling - CDS view creationsecuring-sap-systems - Authorization and security patternssap-rap-patterns.json - RAP patterns and guidelinesThis skill should be used when strict adherence to the defined process is required.
npx skills add gitwalter/developing-rap-objects下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer