Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mindsquare-custom-solutions/rap_samples
Codebeispiele für die mindsquare Restful Application Programming Model Schulung
https://github.com/mindsquare-custom-solutions/rap_samples
abap rap restful-application-programming-model sap
Last synced: 2 months ago
JSON representation
Codebeispiele für die mindsquare Restful Application Programming Model Schulung
- Host: GitHub
- URL: https://github.com/mindsquare-custom-solutions/rap_samples
- Owner: mindsquare-Custom-Solutions
- Created: 2023-04-23T06:57:02.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-08-13T08:22:53.000Z (4 months ago)
- Last Synced: 2024-10-10T02:23:42.160Z (2 months ago)
- Topics: abap, rap, restful-application-programming-model, sap
- Language: ABAP CDS
- Homepage: https://mindsquare.de/schulungen/
- Size: 150 KB
- Stars: 2
- Watchers: 1
- Forks: 3
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Begleitmaterialien zur RAP Schulung
Codebeispiele für die [mindsquare Restful Application Programming Model Schulung](https://mindsquare.de/schulungen/)
## Datenmodell
TODO## Core Data Services im RAP
### Root View Entities
```cds
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'RAP Example: Root View'
define root view entity ZREX_I_Carrier
as select from ZMIND2E_I_Carrier
composition [0..*] of ZREX_I_Connection as _Connection
{
key AirlineId as CarrierId,
Name,
CurrencyCode,
CreatedBy,
CreatedAt,
LastChangedBy,
LastChangedAt,
LocalLastChangedAt,/* Associations */
_Connection
}
```### Kompositionen
```cds
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'RAP Example: Child View'
define view entity ZREX_I_Connection
as select from ZMIND2E_I_Connection
association to parent ZREX_I_Carrier as _Carrier on $projection.CarrierId = _Carrier.CarrierId
composition [0..*] of ZREX_I_Flight as _Flight
{
key AirlineId as CarrierId,
key ConnectionId,
DepartureAirport,
DestinationAirport,
DepartureTime,
ArrivalTime,
Distance,
DistanceUnit,
LocalLastChangedAt,/* Associations */
_Carrier,
_Flight
}
``````cds
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'RAP Example: Grant Child View'
define view entity ZREX_I_Flight
as select from ZMIND2E_I_Flight
association to parent ZREX_I_Connection as _Connection on $projection.CarrierId = _Connection.CarrierId
and $projection.ConnectionID = _Connection.ConnectionId
association [1] to ZREX_I_Carrier as _Carrier on $projection.CarrierId = _Carrier.CarrierId
{
key AirlineID as CarrierId,
key ConnectionID,
key FlightDate,
Price,
CurrencyCode,
PlaneType,
MaximumSeats,
OccupiedSeats,LocalLastChangedAt,
/* Associations */
_Carrier,
_Connection
}
```### Annotationen
```cds
define view entity ZMIND2E_I_Flight
as select from zmind2_flight
association [0..1] to I_Currency as _Currency on $projection.CurrencyCode = _Currency.Currency
{
key carrier_id as AirlineID,
key connection_id as ConnectionID,
key flight_date as FlightDate,@Semantics.amount.currencyCode: 'CurrencyCode'
price as Price,@ObjectModel.foreignKey.association: '_Currency'
currency_code as CurrencyCode,// Weitere Felder
// Assoziation für Fremdschlüsselbeziehung
_Currency
}
``````cds
@ObjectModel.representativeKey: 'Currency'
define view I_Currency
as select from tcurc
{
key waers as Currency
}
```#### Annotationen für administrative Felder
```cds
define view entity ZMIND2E_I_Carrier
as select from zmind2_carrier
{
key carrier_id as AirlineId,@Semantics.user.createdBy: true
local_created_by as CreatedBy,@Semantics.systemDateTime.createdAt: true
local_created_at as CreatedAt,@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt,@Semantics.user.lastChangedBy: true
local_last_changed_by as LastChangedBy,@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed_at as LocalLastChangedAt
}
```### Abstract CDS Entity
```cds
@EndUserText.label: 'Parameter for Action Book Travel'
define abstract entity ZMIND2RAP_A_BookTravel
{
@EndUserText.label: 'book flights, too?'
@EndUserText.quickInfo: 'Should all flights of the selected travels be booked as well?'
@Consumption.defaultValue: 'X'
bookFlights : abap_boolean;
}
```### Custom CDS Entity
```cds
@EndUserText.label: 'Custom entity for unmanaged travel query'
@ObjectModel.query.implementedBy:'ABAP:/dmo/cl_travel_uq'define custom entity /DMO/I_TRAVEL_UQ
{
key Travel_ID : abap.numc( 8 );
Agency_ID : abap.numc( 6 );
Customer_ID : abap.numc( 6 );
Begin_Date : abap.dats;
End_Date : abap.dats;
Booking_Fee : abap.dec( 17, 3 );
Total_Price : abap.dec( 17, 3 );
Currency_Code : abap.cuky;
Status : abap.char( 1 );
LastChangedAt : timestampl;
}
```Implementierung der Datensaelektion
```abap
CLASS /dmo/cl_travel_uq DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .PUBLIC SECTION.
INTERFACES if_rap_query_provider.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.CLASS /dmo/cl_travel_uq IMPLEMENTATION.
METHOD if_rap_query_provider~select.
TRY.
CASE io_request->get_entity_id( ).WHEN '/DMO/I_TRAVEL_UQ' .
**query implementation for travel entity**filter
DATA(lv_sql_filter) = io_request->get_filter( )->get_as_sql_string( ).
TRY.
DATA(lt_filter) = io_request->get_filter( )->get_as_ranges( ).
CATCH cx_rap_query_filter_no_range.
"handle exception
ENDTRY.
**parameters
DATA(lt_parameters) = io_request->get_parameters( ).
DATA(lv_next_year) = CONV /dmo/end_date( cl_abap_context_info=>get_system_date( ) + 365 ) .
DATA(lv_par_filter) = | BEGIN_DATE >= '{ cl_abap_dyn_prg=>escape_quotes( VALUE #( lt_parameters[ parameter_name = 'P_START_DATE' ]-value
DEFAULT cl_abap_context_info=>get_system_date( ) ) ) }'| &&
| AND | &&
| END_DATE <= '{ cl_abap_dyn_prg=>escape_quotes( VALUE #( lt_parameters[ parameter_name = 'P_END_DATE' ]-value
DEFAULT lv_next_year ) ) }'| .
IF lv_sql_filter IS INITIAL.
lv_sql_filter = lv_par_filter.
ELSE.
lv_sql_filter = |( { lv_sql_filter } AND { lv_par_filter } )| .
ENDIF.
**search
DATA(lv_search_string) = io_request->get_search_expression( ).
DATA(lv_search_sql) = |DESCRIPTION LIKE '%{ cl_abap_dyn_prg=>escape_quotes( lv_search_string ) }%'|.IF lv_sql_filter IS INITIAL.
lv_sql_filter = lv_search_sql.
ELSE.
lv_sql_filter = |( { lv_sql_filter } AND { lv_search_sql } )|.
ENDIF.
**request data
IF io_request->is_data_requested( ).
**paging
DATA(lv_offset) = io_request->get_paging( )->get_offset( ).
DATA(lv_page_size) = io_request->get_paging( )->get_page_size( ).
DATA(lv_max_rows) = COND #( WHEN lv_page_size = if_rap_query_paging=>page_size_unlimited
THEN 0 ELSE lv_page_size ).
**sorting
DATA(sort_elements) = io_request->get_sort_elements( ).
DATA(lt_sort_criteria) = VALUE string_table( FOR sort_element IN sort_elements
( sort_element-element_name && COND #( WHEN sort_element-descending = abap_true THEN ` descending`
ELSE ` ascending` ) ) ).
DATA(lv_sort_string) = COND #( WHEN lt_sort_criteria IS INITIAL THEN `primary key`
ELSE concat_lines_of( table = lt_sort_criteria sep = `, ` ) ).
**requested elements
DATA(lt_req_elements) = io_request->get_requested_elements( ).
**aggregate
DATA(lt_aggr_element) = io_request->get_aggregation( )->get_aggregated_elements( ).IF lt_aggr_element IS NOT INITIAL.
LOOP AT lt_aggr_element ASSIGNING FIELD-SYMBOL().
DELETE lt_req_elements WHERE table_line = -result_element.
DATA(lv_aggregation) = |{ -aggregation_method }( { -input_element } ) as { -result_element }|.
APPEND lv_aggregation TO lt_req_elements.
ENDLOOP.
ENDIF.
DATA(lv_req_elements) = concat_lines_of( table = lt_req_elements sep = `, ` ).
****grouping
DATA(lt_grouped_element) = io_request->get_aggregation( )->get_grouped_elements( ).
DATA(lv_grouping) = concat_lines_of( table = lt_grouped_element sep = `, ` ).**select data
DATA lt_travel_response TYPE STANDARD TABLE OF /dmo/i_travel_uq.
SELECT (lv_req_elements) FROM /dmo/travel
WHERE (lv_sql_filter)
GROUP BY (lv_grouping)
ORDER BY (lv_sort_string)
INTO CORRESPONDING FIELDS OF TABLE @lt_travel_response
OFFSET @lv_offset UP TO @lv_max_rows ROWS.
**fill response
io_response->set_data( lt_travel_response ).
ENDIF.
**request count
IF io_request->is_total_numb_of_rec_requested( ).
**select count
SELECT COUNT( * ) FROM /dmo/travel
WHERE (lv_sql_filter)
INTO @DATA(lv_travel_count).
**fill response
io_response->set_total_number_of_records( lv_travel_count ).
ENDIF.WHEN `/DMO/I_BOOKING_UQ`.
**query implementation for booking entity
ENDCASE.
CATCH cx_rap_query_provider.ENDTRY.
ENDMETHOD.
ENDCLASS.
```## Implementierungsarten
### Managed Scenario
```cds
managed;define behavior for ZREX_I_Carrier alias Carrier
persistent table zmind2_carrier
...
```#### Managed Sencario with additional save
Zusätzliche Speichersequenz für alle CDS Entitäten:
```cds
managed with additional save;define behavior for ZREX_I_Carrier alias Carrier
persistent table zmind2_carrier
...
```Zusätzliche Speichersequenz für eine CDS Entität:
```cds
managed;define behavior for ZREX_I_Carrier alias Carrier
persistent table zmind2_carrier
with additional save
...
```#### Managed Scenario with unmanaged save
Unmanaged Speichersequenz für alle CDS Entitäten:
```cds
managed with unmanaged save;define behavior for ZREX_I_Carrier alias Carrier
...
```Unmanmaged Speichersequenz für eine CDS Entität:
```cds
managed;define behavior for ZREX_I_Carrier alias Carrier
with unmanged save
...
```### Unmanaged Scenario
```cds
unmanaged;define behavior for ZREX_I_Carrier alias Carrier
...
```## Einführung RAP
### Behavior Definition
```cds
managed implementation in class zbp_rex_i_carrier unique;
strict ( 2 );
extensible;define behavior for ZREX_I_Carrier alias Carrier
persistent table zmind2_carrier
authorization master ( instance )
etag master LocalLastChangedAt
extensible
{
create;
update;
delete;association _Connection { create; }
}
```### Standardaktionen
#### Create, Update & Delete
```cds
define behavior for ZREX_I_Carrier alias Carrier
...
{
create;
update;
delete;
}
```#### Read per Assoziation
```cds
define behavior for ZREX_I_Carrier alias Carrier
...
{
...
// Lesen per Assoziation
association _Connection { }
}define behavior for ZREX_I_Connection alias Connection
...
{
...
// Lesen per Assoziation
association _Carrier { }
}
```#### Create per Assoziation
```cds
define behavior for ZREX_I_Carrier alias Carrier
...
{
...
// Lesen und Anlegen per Assoziation
association _Connection { create; }
}define behavior for ZREX_I_Connection alias Connection
...
{
...
// Lesen per Assoziation
association _Carrier { }
}
```### Feldmapping
```cds
define behavior for ZREX_I_Carrier alias Carrier
...
{
...
mapping for zmind2_carrier corresponding extensible
{
CarrierId = carrier_id;
Name = name;
CurrencyCode = currency_code;
CreatedBy = local_created_by;
CreatedAt = local_created_at;
LastChangedBy = local_last_changed_by;
LastChangedAt = last_changed_at;
LocalLastChangedAt = local_last_changed_at;
}
...
}
```#### Nutzung in ABAP
Zuweisung CDS Entität als Quelle:
```abap
data ls_po type bapimepoheader.
ls_po = corresponding #( po_entity mapping from entity ).
```Zuweisung CDS Entität als Ziel:
```abap
data ls_po type bapimepoheader.
data ls_po_entity type zi_rap_purchaseorder_m.
ls_po_entity = corresponding #( ls_po mapping to entity ).
```### Feature Control
#### Felder: Statische Feature Control
```cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
field ( numbering : managed ) SalesOrderUuid;
// Schlüssel auf nur lesend setzen
field ( readonly ) SalesOrderUuid;
field ( mandatory : create ) SalesOrderType;field( mandatory : create, readonly : update ) PersonId;
...
```#### Operationen: Statische Feature Control
```cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
internal create;
...
}
```#### Dynamische Feature Control
Global:
```cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
...
create ( features : global );
}
``````abap
CLASS lhc_handler DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_global_features FOR GLOBAL FEATURES
IMPORTING REQUEST requested_features
FOR entity RESULT result.
ENDCLASS.CLASS lhc_handler IMPLEMENTATION.
METHOD get_global_features.
result = VALUE #(
" Feature Control für Aktion
%features-%action-action_name = COND #( WHEN condition
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
%features-%update = COND #( WHEN condition
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )" Feature Control für eine create-Operation per Assoziation
%assoc-_Assoc = COND #( WHEN condition
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
).
ENDMETHOD.
ENDCLASS.
```Instanzbasiert:
```cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
...
create ( features : instance );
}
``````abap
CLASS lhc_handler DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_features FOR INSTANCE FEATURES
IMPORTING keys
FOR entity RESULT result.
ENDCLASS.CLASS lhc_handler IMPLEMENTATION.
METHOD get_features.
READ ENTITIES OF /dmo/i_travel_m IN LOCAL MODE
ENTITY travel
FIELDS ( travel_id overall_status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel_result).result = VALUE #( FOR ls_travel IN lt_travel_result
( %key = ls_travel-%key
%field-travel_id = if_abap_behv=>fc-f-read_only
%features-%action-rejectTravel = COND #( WHEN ls_travel-overall_status = 'X'
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
%features-%action-acceptTravel = COND #( WHEN ls_travel-overall_status = 'A'
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
%assoc-_Booking = COND #( WHEN ls_travel-overall_status = 'X'
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
) ).
ENDMETHOD.
ENDCLASS.
```### Projection View Entity
```cds
@EndUserText.label: 'RAP Example: Projection Root View'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: truedefine root view entity ZREX_C_Carrier
provider contract transactional_query
as projection on ZREX_I_Carrier
{
key CarrierId,
Name,
@ObjectModel.text.element: ['CurrencyName']
CurrencyCode,
@Semantics.text: true
_Currency._Text.CurrencyName : localized,
CreatedBy,
CreatedAt,
LastChangedBy,
LastChangedAt,
LocalLastChangedAt,/* Associations */
_Connection : redirected to composition child ZREX_C_Connection,
_Currency
}
``````cds
@EndUserText.label: 'RAP Example: Projection Child View'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
define view entity ZREX_C_Connection
as projection on ZREX_I_Connection
{
key CarrierId,
key ConnectionId,
DepartureAirport,
DestinationAirport,
DepartureTime,
ArrivalTime,
Distance,
DistanceUnit,
LocalLastChangedAt,/* Associations */
_Carrier : redirected to parent ZREX_C_Carrier,
_Flight : redirected to composition child ZREX_C_Flight,
_DepartureAirport,
_DestinationAirport
}
``````cds
@EndUserText.label: 'RAP Example: Projection Grant Child View'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
define view entity ZREX_C_Flight
as projection on ZREX_I_Flight
{
key CarrierId,
key ConnectionID,
key FlightDate,
Price,
CurrencyCode,
PlaneType,
MaximumSeats,
OccupiedSeats,
LocalLastChangedAt,/* Associations */
_Carrier : redirected to ZREX_C_Carrier,
_Connection : redirected to parent ZREX_C_Connection,
_Currency
}
```### Behavior Definition Projektion
```cds
projection;
strict ( 2 );define behavior for ZREX_C_Carrier alias Carrier
{
use create;
use update;
use delete;use association _Connection { create; }
}
```### Service Definition
>Leading Entity Annotation ab S/4HANA Platform 2023/ BTP abap Environment 2308
```cds
@EndUserText.label: 'Released Objects: CDS'
@ObjectModel.leadingEntity.name: 'ZC_RO_CDSViewTP'
define service ZUI_RO_CDSVIEW {
expose ZC_RO_CDSViewTP as CDSViewTP;
expose ZC_RO_CDSViewBusinessContextTP as BusinessContextTP;
expose ZC_RO_CDSViewCapabilityTP as CDSViewCapabilityTP;
expose ZC_RO_CDSViewFieldTP as FieldTP;
expose ZC_RO_CDSViewSuccessorTP as SuccessorTP;
expose ZI_RO_ReleaseState as ReleaseState;
expose ZI_RO_SupportedCapability as Capability;
expose ZI_RO_SupportedCapabilityText as CapabilityText;
}
```### Metadatenerweiterung
Zu erweiternde CDS View Entity:
```cds
@Metadata.allowExtensions: truedefine view entity ZREX_C_Carrier
as select from ZREX_I_Carrier
{
key CarrierId
...
}
```CDS View Entity Metadatenerweiterung
```cds
@Metadata.layer: #PARTNER@Search.searchable: true
annotate entity ZREX_C_Carrier with
{
@UI.lineItem: [{ position: 10 }]
CarrierId;...
}
```## EML
### Interner Zugriff
```abap
READ ENTITIES OF /dmo/i_travel_m IN LOCAL MODE
ENTITY travel
FIELDS ( travel_id
agency_id
customer_id
booking_fee
total_price
currency_code )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_read_result)
FAILED failed
REPORTED reported.
```### EML Read
```abap
READ ENTITIES OF /dmo/i_travel_m IN LOCAL MODE
ENTITY travel
FIELDS ( travel_id
agency_id
customer_id
booking_fee
total_price
currency_code )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_read_result)
FAILED failed
REPORTED reported.
```### EML Read per Assoziation
```abap
READ ENTITIES OF /DMO/I_Travel_D IN LOCAL MODE
ENTITY Travel BY \_Booking
FIELDS ( FlightPrice CurrencyCode )
WITH VALUE #( ( %tky = -%tky ) )
RESULT DATA(lt_booking).
```### EML Create
```abap
MODIFY ENTITIES OF /dmo/i_travel_m IN LOCAL MODE
ENTITY travel
CREATE FIELDS ( travel_id
agency_id
customer_id
begin_date
end_date
booking_fee
total_price
currency_code
description
overall_status )
WITH lt_create
MAPPED mapped
FAILED failed
REPORTED reported.
```### EML Deep Create
```abap
MODIFY ENTITIES OF /DMO/I_Travel_D
ENTITY Travel
CREATE
FIELDS ( CustomerID
AgencyID
BeginDate
EndDate
Description )
WITH create " Variable vom TYPE TABLE FOR CREATE /DMO/I_TRAVEL_D
CREATE BY \_Booking
FIELDS ( CustomerID
AirlineID
ConnectionID
FlightDate )
WITH VALUE #( (
%cid_ref = 'create_travel'
%target = VALUE #(
(
%cid = 'create_booking_1'
CustomerID = '1'
AirlineID = flight-AirlineID
ConnectionID = flight-ConnectionID
FlightDate = flight-FlightDate )
(
%cid = 'create_booking_2'
CustomerID = '1'
AirlineID = flight-AirlineID
ConnectionID = flight-ConnectionID
FlightDate = flight-FlightDate) ) ) )
MAPPED DATA(mapped)
REPORTED DATA(reported)
FAILED DATA(failed).
```### EML Update
```abap
MODIFY ENTITIES OF /DMO/I_Travel_D IN LOCAL MODE
ENTITY Travel
UPDATE
FIELDS ( OverallStatus )
WITH VALUE #( FOR key IN keys (
%tky = key-%tky
OverallStatus = travel_status-accepted ) )
REPORTED DATA(reported)
FAILED DATA(failed).
```### EML Delete
```abap
MODIFY ENTITIES OF /DMO/I_Travel_D IN LOCAL MODE
ENTITY Travel
DELETE FROM VALUE #( ( TravelUUID = lv_travel_id ) )
REPORTED DATA(reported)
FAILED DATA(failed).
```### EML Aktionen ausführen
```abap
DATA travel_action TYPE TABLE FOR ACTION IMPORT ZMIND2RAP_I_Travel~bookTravel.
travel_action = VALUE #( ( %is_draft = if_abap_behv=>mk-off
TravelId = '00000009'
%param = VALUE #( bookFlights = abap_true ) ) ).MODIFY ENTITIES OF ZMIND2RAP_I_Travel
ENTITY Travel
EXECUTE bookTravel
FROM CORRESPONDING #( travel_action )
RESULT DATA(action_result)
FAILED DATA(action_failed)
REPORTED DATA(action_reported).
```### EML Verschiedene Operationen in einer Modifiy Anweisung
### EML Commit & Rollback
```abap
COMMIT ENTITIES.ROLLBACK ENTITIES.
```## Behavior Pool
### BP für Verhaltensdefinition
```cds
managed implementation in class zbp_rex_i_carrier unique;
strict ( 2 );define behavior for ZREX_I_Carrier alias Carrier
...
```### BP für CDS Entität
```cds
managed;
strict ( 2 );define behavior for ZREX_I_Carrier alias Carrier
implementation in class zbp_rex_i_carrier unique
...define behavior for ZREX_I_Connection alias Connection
implementation in class zbp_rex_i_connection unique
...
```### BP für Implementierungsgruppen
TODO
### Phasen des Programmflusses
#### Methodendefinition
```abap
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
TYPES:
tt_travel_update TYPE TABLE
FOR UPDATE /dmo/i_travel_u.
METHODS:
create_travel FOR MODIFY
IMPORTING it_travel_create FOR CREATE travel,
update_travel FOR MODIFY
IMPORTING it_travel_update FOR UPDATE travel,
delete_travel FOR MODIFY
IMPORTING it_travel_delete FOR DELETE travel,
read_travel FOR READ
IMPORTING it_travel FOR READ travel
RESULT et_travel,
create_booking_ba FOR MODIFY
IMPORTING it_booking_create_ba
FOR CREATE travel\_booking,
read_booking_ba FOR READ
IMPORTING it_travel FOR READ travel\_Booking
FULL iv_full_requested
RESULT et_booking
LINK et_link_table,
lock FOR LOCK
IMPORTING it_travel_lock FOR LOCK travel,
set_travel_status FOR MODIFY
IMPORTING it_travel_set_status_booked
FOR ACTION travel~set_status_booked
RESULT et_travel_set_status_booked,
get_features FOR FEATURES
IMPORTING keys REQUEST requested_features
FOR travel
RESULT result.
ENDCLASS.
```### Messages
```abap
APPEND VALUE #( %tky = -%tky
%msg = new_message(
id = 'ZMC_REX_CARRIER'
number = '001'
severity = if_abap_behv_message=>severity-error )
%element-CarrierId = if_abap_behv=>mk-on
) TO reported-carrier.
```## Nummernvergabe
### Frühe, interne Nummernvergabe
```cds
define behavior for ZI_SalesOrder alias SalesOrder
early numbering
...
{
...
``````cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
field ( numbering : managed ) SalesOrderUuid;
...
}
```#### Nummernvergabe mit Nummernkreis
```abap
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handlerPRIVATE SECTION.
METHODS earlynumbering_create FOR NUMBERING
IMPORTING entities FOR CREATE travel.ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD earlynumbering_create.
DATA:
entity TYPE STRUCTURE FOR CREATE /DMO/I_Travel_M,
travel_id_max TYPE /dmo/travel_id." Ensure Travel ID is not set yet (idempotent)- must be checked when BO is draft-enabled
LOOP AT entities INTO entity WHERE travel_id IS NOT INITIAL.
APPEND CORRESPONDING #( entity ) TO mapped-travel.
ENDLOOP.DATA(entities_wo_travelid) = entities.
DELETE entities_wo_travelid WHERE travel_id IS NOT INITIAL." Get Numbers
TRY.
cl_numberrange_runtime=>number_get(
EXPORTING
nr_range_nr = '01'
object = '/DMO/TRV_M'
quantity = CONV #( lines( entities_wo_travelid ) )
IMPORTING
number = DATA(number_range_key)
returncode = DATA(number_range_return_code)
returned_quantity = DATA(number_range_returned_quantity)
).
CATCH cx_number_ranges INTO DATA(lx_number_ranges).
LOOP AT entities_wo_travelid INTO entity.
APPEND VALUE #( %cid = entity-%cid
%key = entity-%key
%msg = lx_number_ranges
) TO reported-travel.
APPEND VALUE #( %cid = entity-%cid
%key = entity-%key
) TO failed-travel.
ENDLOOP.
EXIT.
ENDTRY.CASE number_range_return_code.
WHEN '1'.
" 1 - the returned number is in a critical range (specified under “percentage warning” in the object definition)
LOOP AT entities_wo_travelid INTO entity.
APPEND VALUE #( %cid = entity-%cid
%key = entity-%key
%msg = NEW /dmo/cm_flight_messages(
textid = /dmo/cm_flight_messages=>number_range_depleted
severity = if_abap_behv_message=>severity-warning )
) TO reported-travel.
ENDLOOP.WHEN '2' OR '3'.
" 2 - the last number of the interval was returned
" 3 - if fewer numbers are available than requested, the return code is 3
LOOP AT entities_wo_travelid INTO entity.
APPEND VALUE #( %cid = entity-%cid
%key = entity-%key
%msg = NEW /dmo/cm_flight_messages(
textid = /dmo/cm_flight_messages=>not_sufficient_numbers
severity = if_abap_behv_message=>severity-warning )
) TO reported-travel.
APPEND VALUE #( %cid = entity-%cid
%key = entity-%key
%fail-cause = if_abap_behv=>cause-conflict
) TO failed-travel.
ENDLOOP.
EXIT.
ENDCASE." At this point ALL entities get a number!
ASSERT number_range_returned_quantity = lines( entities_wo_travelid ).travel_id_max = number_range_key - number_range_returned_quantity.
" Set Travel ID
LOOP AT entities_wo_travelid INTO entity.
travel_id_max += 1.
entity-travel_id = travel_id_max .APPEND VALUE #( %cid = entity-%cid
%key = entity-%key
) TO mapped-travel.
ENDLOOP.ENDMETHOD.
ENDCLASS.
```#### Nummernvergabe durch Hochzählen
```abap
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handlerPRIVATE SECTION.
METHODS earlynumbering_cba_booking FOR NUMBERING
IMPORTING entities FOR CREATE travel\_booking.ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD earlynumbering_cba_booking.
DATA: max_booking_id TYPE /dmo/booking_id.READ ENTITIES OF /DMO/I_Travel_M IN LOCAL MODE
ENTITY travel BY \_booking
FROM CORRESPONDING #( entities )
LINK DATA(bookings)." Loop over all unique TravelIDs
LOOP AT entities ASSIGNING FIELD-SYMBOL() GROUP BY -travel_id." Get highest booking_id from bookings belonging to travel
max_booking_id = REDUCE #( INIT max = CONV /dmo/booking_id( '0' )
FOR booking IN bookings USING KEY entity WHERE ( source-travel_id = -travel_id )
NEXT max = COND /dmo/booking_id( WHEN booking-target-booking_id > max
THEN booking-target-booking_id
ELSE max )
).
" Get highest assigned booking_id from incoming entities
max_booking_id = REDUCE #( INIT max = max_booking_id
FOR entity IN entities USING KEY entity WHERE ( travel_id = -travel_id )
FOR target IN entity-%target
NEXT max = COND /dmo/booking_id( WHEN target-booking_id > max
THEN target-booking_id
ELSE max )
)." Loop over all entries in entities with the same TravelID
LOOP AT entities ASSIGNING FIELD-SYMBOL() USING KEY entity WHERE travel_id = -travel_id." Assign new booking-ids if not already assigned
LOOP AT -%target ASSIGNING FIELD-SYMBOL().
APPEND CORRESPONDING #( ) TO mapped-booking ASSIGNING FIELD-SYMBOL().
IF -booking_id IS INITIAL.
max_booking_id += 10 .
-booking_id = max_booking_id .
ENDIF.
ENDLOOP.ENDLOOP.
ENDLOOP.
ENDMETHOD.ENDCLASS.
```### Späte Nummernvergabe
```cds
define behavior for ZI_SalesOrder alias SalesOrder
late numbering
...
{
// Schlüsselfeld auf »nur lesend« setzen
field ( readonly ) SalesOrderId;
...
}
```## Ermittlungen
### Ermittlungen definieren
```cds
define behavior for ZI_SalesOrderItem alias Item
...
{
...
determination calcTotalAmount on modify { delete; field ItemAmount }
}
```### Ermittlungen implementieren
```cds
define behavior for ZMIND2RAP_I_Booking alias Booking
...
{
...
determination setBookingDate on modify { create; }
}
``````abap
METHOD setBookingDate.
READ ENTITIES OF ZMIND2RAP_I_Travel IN LOCAL MODE
ENTITY Booking
FIELDS ( BookingDate )
WITH CORRESPONDING #( keys )
RESULT DATA(bookings).DELETE bookings WHERE BookingDate IS NOT INITIAL.
CHECK bookings IS NOT INITIAL.MODIFY ENTITIES OF ZMIND2RAP_I_Travel IN LOCAL MODE
ENTITY Booking
UPDATE FIELDS ( BookingDate )
WITH VALUE #( FOR booking IN bookings
( %tky = booking-%tky
BookingDate = cl_abap_context_info=>get_system_date( ) ) ).
ENDMETHOD.
```## Validierung
### Validierungen definieren
Operationen als Auslösebedingung:
```cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
...
validation validateOnChange on save { create; update; }
}
```Felder als Ausläsebedingung:
```cds
define behavior for ZI_SalesOrderItem alias Item
...
{
...
validation validateMaterial on save { field MaterialId; }
}
```Kombination aus Operation und Feld:
```cds
define behavior for ZI_SalesOrderItem alias Item
...
{
...
field ( mandatory ) MaterialId;
validation validateMaterial on save { create; field MaterialId; }
}
```### Validierungen implementieren
```abap
METHOD validate_agency.
" Read relevant travel instance data
READ ENTITIES OF /DMO/I_Travel_M IN LOCAL MODE
ENTITY travel
FIELDS ( agency_id )
WITH CORRESPONDING #( keys )
RESULT DATA(travels).DATA agencies TYPE SORTED TABLE OF /dmo/agency WITH UNIQUE KEY agency_id.
" Optimization of DB select: extract distinct non-initial agency IDs
agencies = CORRESPONDING #( travels DISCARDING DUPLICATES MAPPING agency_id = agency_id EXCEPT * ).
DELETE agencies WHERE agency_id IS INITIAL.
IF agencies IS NOT INITIAL." check if agency ID exist
SELECT FROM /dmo/agency FIELDS agency_id
FOR ALL ENTRIES IN @agencies
WHERE agency_id = @agencies-agency_id
INTO TABLE @DATA(agencies_db).
ENDIF." Raise msg for non existing and initial agency id
LOOP AT travels INTO DATA(travel).
IF travel-agency_id IS INITIAL
OR NOT line_exists( agencies_db[ agency_id = travel-agency_id ] ).APPEND VALUE #( %tky = travel-%tky ) TO failed-travel.
APPEND VALUE #( %tky = travel-%tky
%msg = NEW /dmo/cm_flight_messages(
textid = /dmo/cm_flight_messages=>agency_unkown
agency_id = travel-agency_id
severity = if_abap_behv_message=>severity-error )
%element-agency_id = if_abap_behv=>mk-on
) TO reported-travel.
ENDIF.
ENDLOOP.ENDMETHOD.
```### Vorprüfungen
```cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
create ( precheck );
...
}
``````abap
CLASS lhc_salesorder DEFINITION INHERITING FROM cl_abap_behavior_handler.
...
METHODS testCheck for PRECHECK
IMPORTING keys FOR ACTION SalesOrder~test.
ENDCLASS.CLASS lhc_salesorder IMPLEMENTATION.
...
METHOD testcheck.
READ ENTITIES OF ...
IF ...
...
ENDMETHOD.
ENDCLASS.
```## Aktionen
```cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
...
action cancel;
}
```### statische Aktionen
```cds
define behavior for ZI_Address alias Address
...
{
...
static action markDuplicates;
}
```### Factory Aktionen
```cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
...
factory action copy [1];
}
``````cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
...
factory action deepCopy parameter zrap_s_so_copy_ops [1];
}
```### Eingabeparameter
```cds
define behavior for ZI_SalesOrder alias SalesOrder
...
{
...
action cancel parameter ZRAP_A_CancellationOpts;
}
```### Rückgabeparameter
```cds
define behavior for ZI_Address alias Address
...
{
...
action setAsDefault result [1] $self;
}
```### Aktionen implementieren
```cds
define behavior for ZMIND2RAP_I_Travel alias Travel
...
{
...
action ( features : instance ) cancelTravel result [1] $self;
}
``````abap
METHOD cancelTravel.
MODIFY ENTITIES OF ZMIND2RAP_I_Travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
status = 'X' ) ).READ ENTITIES OF ZMIND2RAP_I_Travel IN LOCAL MODE
ENTITY travel
ALL FIELDS WITH
CORRESPONDING #( keys )
RESULT DATA(travels).result = VALUE #( FOR travel IN travels
( %tky = travel-%tky
%param = travel ) ).
ENDMETHOD.
```### Aktionen: Dynamische Feature Control
```cds
define behavior for ZMIND2RAP_I_Travel alias Travel
...
{
...
action ( features : instance ) bookTravel parameter ZMIND2RAP_A_BookTravel result [1] $self;
action ( features : instance ) cancelTravel result [1] $self;
}
``````abap
METHOD get_features.
READ ENTITIES OF ZMIND2RAP_I_Travel IN LOCAL MODE
ENTITY travel
FIELDS ( travel_id overall_status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel_result).result = VALUE #( FOR ls_travel IN lt_travel_result
( %tky = ls_travel-%tky
%field-travel_id = if_abap_behv=>fc-f-read_only
%features-%action-rejectTravel = COND #( WHEN ls_travel-overall_status = 'X'
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
%features-%action-acceptTravel = COND #( WHEN ls_travel-overall_status = 'A'
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
%assoc-_Booking = COND #( WHEN ls_travel-overall_status = 'X'
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
) ).
```### Aktionen: Fiori Elements
```cds
define root view entity ZMIND2RAP_C_Travel
provider contract transactional_query
as projection on ZMIND2RAP_I_Travel
{
@UI.lineItem: [
{ type: #FOR_ACTION, dataAction: 'bookTravel', label: 'Book Travel', position: 10 },
{ type: #FOR_ACTION, dataAction: 'cancelTravel', label: 'Cancel Travel', position: 20 }
]
@UI.identification: [
{ type: #FOR_ACTION, dataAction: 'bookTravel', label: 'Book Travel', position: 10 },
{ type: #FOR_ACTION, dataAction: 'cancelTravel', label: 'Cancel Travel', position: 20 }
]key TravelId,
...
```## Funktionen
```cds
define behavior for DEMO_CDS_FUNCTION_1 alias PurchaseDocument
{
...// instance function
function getDetails result [0..*] $self;// static function
static function calculateTotal result [1] demo_sales_total_price;//function with input parameter
function calculateDiscount parameter DEMO_CDS_DEDUCT_DISCOUNT
result [1] $self;
...
}
``````abap
CLASS lhc_PurchaseDocument
DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS getDetails FOR READ
IMPORTING keys FOR FUNCTION PurchaseDocument~getDetails
RESULT result.
METHODS calculateTotal FOR READ
IMPORTING keys FOR FUNCTION PurchaseDocument~calculateTotal
RESULT result.
METHODS calculateDiscount FOR READ
IMPORTING keys FOR FUNCTION PurchaseDocument~calculateDiscount
RESULT result.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR PurchaseDocument RESULT result.
ENDCLASS.CLASS lhc_PurchaseDocument IMPLEMENTATION.
METHOD getDetails.
DATA(lt_keys) = keys.
CHECK lt_keys IS NOT INITIAL.READ ENTITIES OF demo_cds_function_1 IN LOCAL MODE
ENTITY PurchaseDocument
FIELDS ( PurchaseDocument Price Status )
WITH CORRESPONDING #( lt_keys )
RESULT DATA(lt_item)
FAILED DATA(read_failed).failed = CORRESPONDING #( DEEP read_failed ).
LOOP AT lt_item ASSIGNING FIELD-SYMBOL().
APPEND VALUE #( %tky = -%tky
%param = CORRESPONDING #( ) ) TO result.
ENDLOOP.
ENDMETHOD.METHOD calculateTotal.
SELECT *
FROM demo_purch_doc
WHERE status = 'O'
INTO TABLE @DATA(lt_db_new_purch).READ ENTITIES OF demo_cds_function_1 IN LOCAL MODE
ENTITY PurchaseDocument
FIELDS ( Price )
WITH CORRESPONDING #( lt_db_new_purch )
RESULT DATA(read_result)
FAILED failed
REPORTED reported.DATA lv_sum TYPE demo_cds_function_1-Price.
CLEAR lv_sum.LOOP AT read_result ASSIGNING FIELD-SYMBOL().
lv_sum += -Price.
ENDLOOP.result = VALUE #( ( %cid = keys[ 1 ]-%cid
%param = lv_sum ) ).
ENDMETHOD.METHOD calculateDiscount.
DATA lt_reduced_purch TYPE TABLE FOR FUNCTION RESULT
demo_cds_function_1\\PurchaseDocument~calculateDiscount.
DATA lt_update_purch TYPE TABLE FOR UPDATE
demo_cds_function_1\\PurchaseDocument.
DATA(lt_keys) = keys.LOOP AT lt_keys
ASSIGNING FIELD-SYMBOL()
WHERE %param-discount_percent IS INITIAL
OR %param-discount_percent > 100
OR %param-discount_percent <= 0.APPEND VALUE #( %tky = -%tky ) TO failed-purchasedocument.
APPEND VALUE #( %tky = -%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'function failed' )
%element-price = if_abap_behv=>mk-on )
TO reported-purchasedocument.
DELETE lt_keys.
ENDLOOP.CHECK lt_keys IS NOT INITIAL.
"get total price
READ ENTITIES OF demo_cds_function_1 IN LOCAL MODE
ENTITY PurchaseDocument
ALL FIELDS
WITH CORRESPONDING #( lt_keys )
RESULT DATA(lt_purc)
FAILED DATA(read_failed).failed = CORRESPONDING #( DEEP read_failed ).
LOOP AT lt_purc ASSIGNING FIELD-SYMBOL().
DATA lv_percentage TYPE decfloat16.
DATA(lv_discount_percent) = lt_keys[
KEY entity %tky = -%tky ]-%param-discount_percent.
lv_percentage = lv_discount_percent / 100 .
-Price = -price * ( 1 - lv_percentage ) .APPEND VALUE #( %tky = -%tky
%param = CORRESPONDING #( ) )
TO lt_reduced_purch.
ENDLOOP.result = VALUE #( FOR purchase IN lt_reduced_purch
( %tky = purchase-%tky
%param = purchase-%param ) ).
ENDMETHOD.
METHOD get_instance_authorizations.
ENDMETHOD.ENDCLASS.
```## Berechtigungen
### Lesende Berechtigungen
```cds
@EndUserText.label: 'Carrier'
@MappingRole: true
define role ZMIND2E_C_CARRIER {
grant select on ZMIND2E_C_CARRIER
where (AirlineId) = aspect pfcg_auth(S_CARRID, CARRID, ACTVT = '03' );
}
```### Authorization Master
```cds
define behavior for /DMO/I_Travel_D alias Travel
...
authorization master ( global, instance )
{
create;
update;
delete;
action acceptTravel ...;
...
}
```### Authorization Dependent
```cds
define behavior for /DMO/I_Booking_D alias Booking
...
authorization dependent by _Travel
{
update;
delete;
association _Travel { }
}
```### Global Authorization
```abap
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.PRIVATE SECTION.
...
METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR travel RESULT result.ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD get_global_authorizations.
IF requested_authorizations-%create EQ if_abap_behv=>mk-on.
IF is_create_granted( ) = abap_true.
result-%create = if_abap_behv=>auth-allowed.
ELSE.
result-%create = if_abap_behv=>auth-unauthorized.
APPEND VALUE #( %msg = NEW /DMO/CM_FLIGHT_MESSAGES(
textid = /DMO/CM_FLIGHT_MESSAGES=>not_authorized
severity = if_abap_behv_message=>severity-error )
%global = if_abap_behv=>mk-on
) TO reported-travel.ENDIF.
ENDIF."Edit is treated like update
IF requested_authorizations-%update = if_abap_behv=>mk-on OR
requested_authorizations-%action-Edit = if_abap_behv=>mk-on.IF is_update_granted( ) = abap_true.
result-%update = if_abap_behv=>auth-allowed.
result-%action-Edit = if_abap_behv=>auth-allowed.ELSE.
result-%update = if_abap_behv=>auth-unauthorized.
result-%action-Edit = if_abap_behv=>auth-unauthorized.APPEND VALUE #( %msg = NEW /DMO/CM_FLIGHT_MESSAGES(
textid = /DMO/CM_FLIGHT_MESSAGES=>not_authorized
severity = if_abap_behv_message=>severity-error )
%global = if_abap_behv=>mk-on
) TO reported-travel.ENDIF.
ENDIF.IF requested_authorizations-%delete = if_abap_behv=>mk-on.
IF is_delete_granted( ) = abap_true.
result-%delete = if_abap_behv=>auth-allowed.
ELSE.
result-%delete = if_abap_behv=>auth-unauthorized.
APPEND VALUE #( %msg = NEW /DMO/CM_FLIGHT_MESSAGES(
textid = /DMO/CM_FLIGHT_MESSAGES=>not_authorized
severity = if_abap_behv_message=>severity-error )
%global = if_abap_behv=>mk-on
) TO reported-travel.
ENDIF.
ENDIF.ENDMETHOD.
ENDCLASS.
```### Instance Authorization
```abap
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.PRIVATE SECTION.
...
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR travel RESULT result.ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD get_instance_authorizations.DATA: update_requested TYPE abap_bool,
delete_requested TYPE abap_bool,
update_granted TYPE abap_bool,
delete_granted TYPE abap_bool.READ ENTITIES OF /DMO/R_Travel_D IN LOCAL MODE
ENTITY Travel
FIELDS ( AgencyID )
WITH CORRESPONDING #( keys )
RESULT DATA(travels)
FAILED failed.CHECK travels IS NOT INITIAL.
"Select country_code and agency of corresponding persistent travel instance
"authorization only checked against instance that have active persistence
SELECT FROM /DMO/A_TRAVEL_D AS travel INNER JOIN /DMO/AGENCY AS agency
ON travel~agency_id = agency~agency_id
FIELDS travel~travel_uuid , travel~agency_id, agency~country_code
FOR ALL ENTRIES IN @travels WHERE travel_uuid EQ @travels-TravelUUID
INTO TABLE @DATA(travel_agency_country)."edit is treated like update
update_requested = COND #( WHEN requested_authorizations-%update = if_abap_behv=>mk-on OR
requested_authorizations-%action-Edit = if_abap_behv=>mk-on
THEN abap_true ELSE abap_false ).delete_requested = COND #( WHEN requested_authorizations-%delete = if_abap_behv=>mk-on
THEN abap_true ELSE abap_false ).LOOP AT travels INTO DATA(travel).
"get country_code of agency in corresponding instance on persistent table
READ TABLE travel_agency_country WITH KEY travel_uuid = travel-TravelUUID
ASSIGNING FIELD-SYMBOL()."Auth check for active instances that have before image on persistent table
IF sy-subrc = 0."check auth for update
IF update_requested = abap_true.
update_granted = is_update_granted( -country_code ).
IF update_granted = abap_false.
APPEND VALUE #( %tky = travel-%tky
%msg = NEW /DMO/CM_FLIGHT_MESSAGES(
textid = /DMO/CM_FLIGHT_MESSAGES=>not_authorized_for_agencyid
agency_id = travel-AgencyID
severity = if_abap_behv_message=>severity-error )
%element-AgencyID = if_abap_behv=>mk-on
) TO reported-travel.
ENDIF.
ENDIF."check auth for delete
IF delete_requested = abap_true.
delete_granted = is_delete_granted( -country_code ).
IF delete_granted = abap_false.
APPEND VALUE #( %tky = travel-%tky
%msg = NEW /DMO/CM_FLIGHT_MESSAGES(
textid = /DMO/CM_FLIGHT_MESSAGES=>not_authorized_for_agencyid
agency_id = travel-AgencyID
severity = if_abap_behv_message=>severity-error )
%element-AgencyID = if_abap_behv=>mk-on
) TO reported-travel.
ENDIF.
ENDIF." operations on draft instances and on active instances that have no persistent before image (eg Update on newly created instance)
" create authorization is checked, for newly created instances
ELSE.
update_granted = delete_granted = is_create_granted( ).
IF update_granted = abap_false.
APPEND VALUE #( %tky = travel-%tky
%msg = NEW /DMO/CM_FLIGHT_MESSAGES(
textid = /DMO/CM_FLIGHT_MESSAGES=>not_authorized
severity = if_abap_behv_message=>severity-error )
%element-AgencyID = if_abap_behv=>mk-on
) TO reported-travel.
ENDIF.
ENDIF.APPEND VALUE #( LET upd_auth = COND #( WHEN update_granted = abap_true THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized )
del_auth = COND #( WHEN delete_granted = abap_true THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized )
IN
%tky = travel-%tky
%update = upd_auth
%action-Edit = upd_auth%delete = del_auth
) TO result.
ENDLOOP.ENDMETHOD.
ENDCLASS.
```#### Instance Authorization Beispiel
```abap
METHOD get_instance_authorizations.
data: update_requested type abap_bool,
delete_requested type abap_bool.read entities of ZMIND2RAP_I_Travel in local mode
ENTITY Travel
Fields ( AgencyId )
WITH CORRESPONDING #( keys )
RESULT data(travels)
failed failed.check travels is not INITIAL.
update_requested = COND #( when requested_authorizations-%update = if_abap_behv=>mk-on then abap_true
* Diese Zeile nur wenn Draft Handling aktiviert ist
when requested_authorizations-%action-Edit = if_abap_behv=>mk-on then abap_true
else abap_false ).
delete_requested = COND #( when requested_authorizations-%delete = if_abap_behv=>mk-on then abap_true
else abap_false ).LOOP AT travels ASSIGNING FIELD-SYMBOL() GROUP BY -AgencyId.
data(update_authorized) = cond #( when update_requested = abap_true
then zcl_mind2rap_helper=>is_granted( agency = -AgencyId actvt = '02' )
else abap_false ).data(delete_authorized) = cond #( when delete_requested = abap_true
then zcl_mind2rap_helper=>is_granted( agency = -AgencyId actvt = '06' )
else abap_false ).LOOP AT GROUP ASSIGNING FIELD-SYMBOL().
if ( update_requested = abap_true AND update_authorized = abap_false ) OR
( delete_requested = abap_true AND delete_authorized = abap_false ).
append value #( %tky = -%tky
%msg = new_message(
id = 'ZCM_MIND2RAP_TRAVEL'
number = '007'
severity = if_abap_behv_message=>severity-error
v1 = -TravelId
) ) to reported-travel.
endif.append value #( let update_auth = cond #( when update_authorized = abap_true then if_abap_behv=>auth-allowed
else if_abap_behv=>auth-unauthorized )
delete_auth = cond #( when delete_authorized = abap_true then if_abap_behv=>auth-allowed
else if_abap_behv=>auth-unauthorized )
in
%tky = -%tky
%update = update_auth
%delete = delete_auth
* Diese Aktion nur wenn Draft Handling aktiviert ist
%action-Edit = update_auth ) to result.
ENDLOOP.
ENDLOOP.
ENDMETHOD.
```## Sperren
### Pessimistische Sperren
```cds
define behavior for /DMO/I_Travel_D alias Travel
lock master
...
{
...
}define behavior for /DMO/I_Booking_D alias Booking
lock dependent by _Travel
...
{
...
association _Travel { }
}
```### Optimistische Sperren
```cds
define behavior for /DMO/I_Travel_M alias Travel
etag master LocalLastChangedAt
...define behavior for /DMO/I_Booking_D alias Booking
etag master LocalLastChangedAt
...
``````cds
define behavior for ZI_SalesOrder alias SalesOrder
etag master LastChangedAt
...define behavior for ZI_SalesOrderItem alias Item
etag dependant by _SalesOrder
...
{
association _SalesOrder { }
}
```## Draft Handling
```cds
managed;
strict;
with draft;
define behavior for /DMO/I_Travel_D alias Travel
```### Draft Tabellen
```cds
...
define behavior for /DMO/I_Travel_D alias Travel
...
persistent table /dmo/a_travel_d
draft table /dmo/d_travel_d
...define behavior for /DMO/I_Booking_D alias Booking
...
persistent table /dmo/a_booking_d
draft table /dmo/d_booking_d
...
```### Draft etag Handling
```cds
define behavior for /DMO/I_Travel_D alias Travel
...
total etag LastChangedAt
...
```### Draft Assoziationen
```cds
define behavior for /DMO/I_Travel_D alias Travel
...
{
...
association _Booking { create; with draft; }
}
...
```### Draft Aktionen
```cds
define behavior for /DMO/I_Travel_D alias Travel
...
{
draft action Resume;
draft action Edit;
draft action Activate;
draft action Discard;
draft determine action Prepare
{
validation validateAgency;
validation validateCustomer;
...
}validation validateCustomer on save { ... }
validation validateAgency on save { ... }
...
}
```## Implementierung Speichersequenz
### Managed scenario with unmanaged save
```cds
define behavior for /DMO/I_BookSuppl_M alias booksuppl
implementation in class /DMO/BP_BOOKINGSUPPLEMENT_M unique
with unmanaged save
...
{
...
}
``````abap
CLASS lcl_save DEFINITION INHERITING FROM cl_abap_behavior_saver.PROTECTED SECTION.
METHODS save_modified REDEFINITION.ENDCLASS.
CLASS lcl_save IMPLEMENTATION.
DATA booksuppls_db TYPE STANDARD TABLE OF /dmo/booksuppl_m.
" (1) Get instance data of all instances that have been created
IF create-booksuppl IS NOT INITIAL.
booksuppls_db = CORRESPONDING #( create-booksuppl ).CALL FUNCTION '/DMO/FLIGHT_BOOKSUPPL_C' EXPORTING values = booksuppls_db .
ENDIF.
" (2) Get instance data of all instances that have been updated during the transaction
booksuppls_db = CORRESPONDING #( update-booksuppl ).
IF booksuppls_db IS NOT INITIAL." Read all field values from database
SELECT * FROM /dmo/booksuppl_m FOR ALL ENTRIES IN @booksuppls_db
WHERE booking_supplement_id = @booksuppls_db-booking_supplement_id
INTO TABLE @booksuppls_db ." Take over field values that have been changed during the transaction
LOOP AT update-booksuppl ASSIGNING FIELD-SYMBOL().
ASSIGN booksuppls_db[ travel_id = -travel_id
booking_id = -booking_id
booking_supplement_id = -booking_supplement_id
] TO FIELD-SYMBOL().IF -%control-supplement_id = if_abap_behv=>mk-on.
-supplement_id = -supplement_id.
ENDIF.IF -%control-price = if_abap_behv=>mk-on.
-price = -price.
ENDIF.IF -%control-currency_code = if_abap_behv=>mk-on.
-currency_code = -currency_code.
ENDIF.ENDLOOP.
" Update the complete instance data
CALL FUNCTION '/DMO/FLIGHT_BOOKSUPPL_U' EXPORTING values = booksuppls_db .ENDIF.
" (3) Get keys of all travel instances that have been deleted during the transaction
IF delete-booksuppl IS NOT INITIAL.
booksuppls_db = CORRESPONDING #( delete-booksuppl ).CALL FUNCTION '/DMO/FLIGHT_BOOKSUPPL_D' EXPORTING values = booksuppls_db .
ENDIF.
ENDMETHOD.
ENDCLASS.
```