
@EndUserText.label : 'Order processor table'
@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #LIMITED
define table zord_pro_t {
key client : abap.clnt not null;
key processorid : zprocessor_id_e not null;
name : zprocessor_name_e;
}
@EndUserText.label : 'Table for food ordres'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zfood_orders_t {
key client : abap.clnt not null;
key orderid : zorder_id_e not null;
status : zorder_status_e;
receivedtime : timestampl;
processorid : zprocessor_id_e;
last_changed_by : zlast_changedby_e;
last_changed_at : timestampl;
}
@EndUserText.label : 'Food order item table'
@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #LIMITED
define table zfood_ord_item_t {
key client : abap.clnt not null;
key orderid : zorder_id_e not null;
key orderitem : zorder_item_e not null;
deliver_addr : zorder_addr;
ord_comment : zorder_com;
payment_method : zorder_payment_m;
}
@EndUserText.label : 'Food order status'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zfood_ordsta_t {
key client : abap.clnt not null;
key status : zorder_status_e not null;
description : abap.char(20);
}
CLASS zcl_order_table DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_ORDER_TABLE IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA: lt_orders TYPE STANDARD TABLE OF zfood_orders_t.
lt_orders = VALUE #( ( orderid = 'OR00000001' status = '5' receivedtime = '20210810093940.5961061' processorid = 'PR00000001'
last_changed_by = 'JasonLu' last_changed_at = '20210810095040.5961061' )
( orderid = 'OR00000002' status = '2' receivedtime = '20210810094040.5961061' processorid = 'PR00000002'
last_changed_by = 'JasonLu' last_changed_at = '20210810095540.5961061' )
( orderid = 'OR00000003' status = '3' receivedtime = '20210810095040.5961061' processorid = 'PR00000003'
last_changed_by = 'JasonLu' last_changed_at = '20210810095640.5961061' ) ).
DELETE FROM zfood_orders_t.
INSERT zfood_orders_t FROM TABLE @lt_orders.
CLEAR lt_orders.
SELECT *
FROM zfood_orders_t
INTO TABLE @lt_orders.
IF sy-subrc = 0.
out->write( 'data instered to the table!' ).
out->write( lt_orders ).
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS zcl_order_item_table DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_ORDER_ITEM_TABLE IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA: lt_order_item TYPE STANDARD TABLE OF zfood_ord_item_t.
lt_order_item = VALUE #( ( orderid = 'OR00000001' orderitem = 1 deliver_addr = 'test addr' ord_comment = 'asap' payment_method = 'Cash' )
( orderid = 'OR00000001' orderitem = 2 deliver_addr = 'test addr' ord_comment = 'asap' payment_method = 'Cash' )
( orderid = 'OR00000002' orderitem = 1 deliver_addr = 'test addr' ord_comment = 'less salt' payment_method = 'Cash' )
( orderid = 'OR00000003' orderitem = 1 deliver_addr = 'test addr' ord_comment = 'more suger' payment_method = 'Cash' ) ).
DELETE FROM zfood_ord_item_t.
INSERT zfood_ord_item_t FROM TABLE @lt_order_item.
CLEAR lt_order_item.
SELECT *
FROM zfood_ord_item_t
INTO TABLE @lt_order_item.
IF sy-subrc = 0.
out->write( 'data instered to the table!' ).
out->write( lt_order_item ).
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS zcl_processor_table DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_PROCESSOR_TABLE IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA lt_processor TYPE STANDARD TABLE OF ZORD_PRO_T.
lt_processor = value #( ( processorid = 'PR00000001' name = 'PROCESSOR1' )
( processorid = 'PR00000002' name = 'PROCESSOR2' )
( processorid = 'PR00000003' name = 'PROCESSOR3' ) ).
DELETE FROM ZORD_PRO_T.
INSERT ZORD_PRO_T FROM TABLE @lt_processor.
CLEAR lt_processor.
SELECT *
FROM ZORD_PRO_T
INTO TABLE @lt_processor.
IF sy-subrc = 0.
out->write( 'data instered to the table!' ).
out->write( lt_processor ).
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS zcl_food_order_status_table DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_FOOD_ORDER_STATUS_TABLE IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA: lt_status TYPE STANDARD TABLE OF zfood_ordsta_t.
lt_status = VALUE #( ( status = '1' description = 'Order Received')
( status = '2' description = 'Order processing')
( status = '3' description = 'Out of Deliver')
( status = '4' description = 'Order Delivered')
( status = '5' description = 'Order Finish') ).
DELETE FROM zfood_ordsta_t.
INSERT zfood_ordsta_t FROM TABLE @lt_status.
CLEAR lt_status.
SELECT *
FROM zfood_ordsta_t
INTO TABLE @lt_status.
IF sy-subrc = 0.
out->write( 'data instered to the table!' ).
out->write( lt_status ).
ENDIF.
ENDMETHOD.
ENDCLASS.
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Basic CDS View for Food Order Processor table'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel: {
usageType: {
serviceQuality: #B,
sizeCategory: #XL,
dataClass: #TRANSACTIONAL
}
}
define view entity ZI_FOODORD_PROCESSOR as select from zord_pro_t {
key processorid as Processorid,
name as Name
}
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Basic Interface View for Food Order Status'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel: {
usageType: {
serviceQuality: #B,
sizeCategory: #XL,
dataClass: #TRANSACTIONAL
}
}
define view entity ZI_FOOD_ORDSTA as select from zfood_ordsta_t {
@ObjectModel.text.element: ['description']
key status as Status,
description as Description
}
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Basic interface view for food order items'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_FORDER_ITEMS as select from zfood_ord_item_t
association [1..1] to ZI_FOOD_ORDERS as _FoodOrder on $projection.Orderid = _FoodOrder.Orderid
{
key orderid as Orderid,
key orderitem as OrderItem,
deliver_addr as DeliverAddr,
ord_comment as OrdComment,
payment_method as PaymentMethod,
//Associationa
_FoodOrder
}
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Basic interface view for food orders'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel: {
representativeKey: 'Orderid',
usageType: {
dataClass: #TRANSACTIONAL,
serviceQuality: #B,
sizeCategory: #L
}
}
define view entity ZI_FOOD_ORDERS as select from zfood_orders_t
association [0..1] to ZI_FOODORD_PROCESSOR as _Processor on $projection.Processorid = _Processor.Processorid
association [0..1] to ZI_FOOD_ORDSTA as _Status on $projection.Status = _Status.Status
association [1..*] to ZI_FORDER_ITEMS as _Items on $projection.Orderid = _Items.Orderid
{
key orderid as Orderid,
status as Status,
_Status.Description as StatusDesc,
receivedtime as Receivedtime,
processorid as Processorid,
_Processor.Name as ProcessorName,
@Semantics.user.lastChangedBy: true
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt,
//Association
_Processor,
_Status,
_Items
}
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Composite Interface view for Food Orders Items'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel: {
representativeKey: 'Orderid',
usageType: {
dataClass: #TRANSACTIONAL,
serviceQuality: #B,
sizeCategory: #XL
}
}
define view entity ZR_FORDER_ITEMS as select from ZI_FORDER_ITEMS
association to parent ZR_FOOD_ORDERS as _FoodOrder on $projection.Orderid = _FoodOrder.Orderid
{
key Orderid,
key OrderItem,
DeliverAddr,
OrdComment,
PaymentMethod,
/* Associations */
_FoodOrder
}
@AbapCatalog: {
sqlViewName: 'ZFOODORDERS_C',
preserveKey: true,
compiler.compareFilter: true
}
@ObjectModel: {
usageType: {
serviceQuality: #B,
sizeCategory: #XL,
dataClass: #TRANSACTIONAL
},
representativeKey: 'Orderid'
}
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Composite Interface view for Food Orders'
define root view ZR_FOOD_ORDERS as select from ZI_FOOD_ORDERS
composition [1..*] of ZR_FORDER_ITEMS as _Items
{
key Orderid,
Status,
StatusDesc,
Receivedtime,
Processorid,
ProcessorName,
LastChangedBy,
LastChangedAt,
/* Associations */
_Items,
_Processor,
_Status
}
managed implementation in class zbp_r_food_orders unique;
//strict; //Comment this line in to enable strict mode. The strict mode is prerequisite to be future proof regarding syntax and to be able to release your BO.
define behavior for ZR_FOOD_ORDERS alias food_order
persistent table zfood_orders_t
//with unmanaged save
lock master
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
association _Items { create; }
mapping for zfood_orders_t
{
LastChangedBy = last_changed_by;
LastChangedAt = last_changed_at;
}
// validations
validation validateOrderProcessor on save { field Processorid; }
}
define behavior for ZR_FORDER_ITEMS alias food_orderitem
persistent table ZFOOD_ORD_ITEM_T
//with unmanaged save
lock dependent by _FoodOrder
authorization dependent by _FoodOrder
//etag master <field_name>
{
update;
delete;
field ( readonly ) Orderid;
association _FoodOrder;
mapping for ZFOOD_ORD_ITEM_T
{
DeliverAddr = deliver_addr;
}
}
CLASS lhc_ZR_FOOD_ORDERS DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR food_order RESULT result.
METHODS validateorderprocessor FOR VALIDATE ON SAVE
IMPORTING keys FOR food_order~validateorderprocessor.
ENDCLASS.
CLASS lhc_ZR_FOOD_ORDERS IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.
METHOD validateOrderProcessor.
READ ENTITY ZR_FOOD_ORDERS FROM VALUE #(
FOR <root_key> IN keys ( %key-orderid = <root_key>-orderid
%control = VALUE #( Processorid = if_abap_behv=>mk-on ) ) )
RESULT DATA(lt_orders).
READ TABLE lt_orders INTO DATA(ls_order) INDEX 1.
CHECK ls_order IS NOT INITIAL.
SELECT SINGLE *
FROM ZFOOD_ORDERS_T
WHERE status = '2'
AND processorid = @ls_order-Processorid
INTO @DATA(ls_order_c).
IF sy-subrc = 0.
"The processor has linked to other Food Order
APPEND VALUE #( %key = ls_order-%key
Orderid = ls_order-Orderid ) TO failed-food_order. "food_order = Business Object ZR_FOOD_ORDERS
"Create message class ZFOOD_ORDER_MESSAGES with the error message you want to use
APPEND VALUE #( %key = ls_order-%key
%msg = new_message( id = 'ZFOOD_ORDER_MESSAGES'
number = 001
v1 = ls_order-processorid
severity = if_abap_behv_message=>severity-error )
%element-processorid = if_abap_behv=>mk-on ) TO reported-food_order.
ENDIF.
ENDMETHOD.
ENDCLASS.
For the example, we should create a new CDS view refer to the Composite Interface view.
Select 'Define Projection View'.
@EndUserText.label: 'Projection view for Food Orders'
//@AccessControl.authorizationCheck: #CHECK
@UI: { headerInfo: { typeName: 'Food Orders', typeNamePlural: 'Orders', title: { type: #STANDARD, value: 'Orderid' } } }
@Search.searchable: true
define root view entity ZC_FOOD_ORDERS
provider contract transactional_query
as projection on ZR_FOOD_ORDERS {
@UI.facet: [ { id: 'Orders',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Order',
position: 10 } ]
@UI: { lineItem: [ { position: 10, importance: #HIGH } ],
identification: [ { position: 10, label: 'Order IDs' } ] }
key Orderid,
@UI: { lineItem: [ { position: 20, importance: #HIGH } ],
identification: [ { position: 20, label: 'Order Status' } ],
selectionField: [ { position: 20 } ] }
@Consumption.valueHelpDefinition: [{ entity : {name: 'zi_food_ordsta', element: 'Status' } }]
@ObjectModel.text.element: ['Description']
@Search.defaultSearchElement: true
Status as Status,
_Status.Description as Description,
@UI: { lineItem: [ { position: 30, importance: #HIGH } ],
identification: [ { position: 30, label: 'Order Received Time' } ] }
Receivedtime,
@UI: { lineItem: [ { position: 40, importance: #HIGH } ],
identification: [ { position: 40, label: 'Order Processor' } ],
selectionField: [ { position: 40 } ] }
@Consumption.valueHelpDefinition: [{ entity : {name: 'zi_foodord_processor', element: 'Processorid' } }]
@ObjectModel.text.element: ['ProcessorName']
@Search.defaultSearchElement: true
Processorid as Processorid,
_Processor.Name as ProcessorName,
@UI: { lineItem: [ { position: 60, importance: #HIGH } ],
identification: [ { position: 60, label: 'Last Changed By' } ] }
LastChangedBy,
@UI.hidden: true
LastChangedAt,
/* Associations */
_Items,
_Processor,
_Status
}
Right click the just created Projection view and then create the Service Definition.
@EndUserText.label: 'Service definition on Food Orders'
define service ZSRV_C_FOOD_ORDERS {
expose ZC_FOOD_ORDERS;
}
Click the 'Go' button, the test data which we assigned to the database tables will be displayed.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
24 | |
23 | |
22 | |
15 | |
13 | |
10 | |
9 | |
7 | |
7 | |
6 |