S/4HANA VDM 1 Employing CDS Virtual Data Model for Embedded Analytics

Most of you should be familiar with Core Data Services by now.You DO NOT need to be using SAP on HANA or S/4HANA to use CDS because it is database independent.One innovation that the S/4HANA programming approach is depending on is CDS. We can generate OData, develop SAPUI5 apps, construct graphs, and show charts using CDS. The beauty of CDS is in that.

Now that we are familiar with the fundamentals of CDS, it is imperative that we study the following advanced topic. It’s called the Virtual Data Model, or VDM. Virtual refers to nonexistent.Put differently, VDM functions as an intermediary for the CDS, strategically structured and adjusted to produce a more accurate depiction of the data.

The architecture for creating a Virtual Data Model (VDM) in S/4HANA will be covered in this article. VDM is constructed from CDS. Any discussion of VDM implies that CDS Views, or Core Data Services, are the foundation.

The architecture and programming model of SAP S/4HANA heavily rely on CDS Views. For all SAP Fiori Applications, VDMs and CDS are the primary data sources and data modes. On VDM, all recent advancements in S/4HANA are built.

Why is VDM required?

  • Understandability: Business, non-technical, and functional people can all grasp VDM with ease.
  • Reusability: After they are launched, customers and partners can reuse parts of the VDM perspective, which are expected to be reused by other teams.
  • Leading S/4HANA Programming Model: For all S/4HANA initiatives, VDM is the recommended programming model. CDS/VDM is the basis for other data models, such as Analytic and OData Models. Also, VDM is used in the development of all new SAP standard Fiori Apps.
  • Performance: Because VDM views are run directly at the database level, they take advantage of all of its features and performance.
  • Transport Management: As the foundation of VDM, CDS makes use of the reliable, dependable ABAP Application Infrastructure and Change
  • How Can a Transient Provider Be Created?
  • How Can SAP Analysis for Office (AO) See VDM?
  • How Can UI Annotations and CDS Views Be Used to Build Fiori Apps?

Embedded denotes integrated. With S/4HANA System, embedded analytics refers to built-in analytics. It creates virtual data models, or representations of operational data, using the technology of SAP ABAP Core Data Services, also known as CDS.

SAP HANA Pre-delivered CDS views, which are pre-packaged analytical tools included with Embedded Analytics, allow users to execute real-time data analytics on transactional data without having to know much about the underlying data tables or structures. The views can be used directly or combined with new views (or modified/enhanced views) to generate new data models, depending on the analytical needs of a business.

Building a semantic overlay on top of the current database architecture is the fundamental idea behind a virtual data model.

VDM can be divided into two primary categories:

  • Interface Views
  • Basic View
  • Composite View

Consumption Views

  1. Interface Views
    Because they are built directly on top of DDIC tables or views, Basic Views (Core Entity Views, Text Views, and Hierarchy Views) interface with database tables to retrieve data. To put it briefly, Basic Views are created when you are directly picking data from a database table.
  2. One or more Basic Views serve as the foundation for Composite Views. To create a composite view, several basic views can be put together and calculations made using functions and expressions. Composite views have the option of being reusable or consumption-specific.

2. Consumption View

  • Because Consumption Views are constructed on top of Composite Views, they are incompatible with DDIC tables and Basic Views.
  • The views that are exposed to front-end tools such as SAP Analytics Cloud, BEX Queries, Analysis for Office, Fiori Apps, etc. are called consumption views.
Virtual Data Model Diagram
  • @VDM.viewType: # BASIC , COMPOSITE,CONSUMPTION
  • @Analytics.DataCategory: #DIMENSION , FACT,CUBE
  • @Analytics.Query: # TRUE,FALSE
  • @Analytics.dataExtraction.enabled: #TRUE, FALSE
  • @ObjectModel.dataCategory: #TEXT, HIERARCHY
  • @Odata.Publish: TRUE

Today’s task will involve creating CDS Views for Sales Flow. For VBAK (Sales Header), Basic CDS View ZVDM_I_VBAK is made. Basic CDS View ZVDM_I_LIPS is built for Delivery Header and Item, and Basic View ZVDM_I_VBAP is created for VBAP (Sales Item).

On top of the Basic CDS Views mentioned above is the Composite CDS view ZVDM_CO_SALES.

The Composite View above serves as the foundation for the Consumption View ZVDM_C_SALES.

In our practice today, we also used Partner CDS View and Standard Material CDS View.

We are going to construct CDS Views for Sales Flow as part of today’s activity. ZVDM_I_VBAK, the Basic CDS View, is made for VBAK (Sales Header). For VBAP (Sales Item), Basic View ZVDM_I_VBAP is constructed, and for Delivery Header and Item, Basic CDS View ZVDM_I_LIPS is created.

  • The Basic CDS Views above provide the foundation for the Composite CDS view ZVDM_CO_SALES.
  • Built upon the Composite View mentioned above is the Consumption View ZVDM_C_SALES.
  • In today’s activity, we also employed Partner CDS View and Standard Material CDS View.

Take the CDS Basics Quiz 1.

Exercise 1: Make a Simple CDS See: ZVDM_I_VBAK (FACT, BASIC)

@Analytics.dataCategory: #FACT — Since this is a basic view, we are fetching the transactional table here without using any semantic annotations.

Used the annotations below to specify the CDS view’s size and data class in accordance with the specifications

  • @ObjectModel.dataClass.usageType: #TRADESIONAL
  • UsageType.serviceQuality @ObjectModel: #B
  • UsageType.sizeCategory @ObjectModel.usage: #XL
@AbapCatalog.sqlViewName: 'ZVDM_VIEW_VBAK'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sales header data( Basic View , Fact table)'
@VDM.viewType: #BASIC
@Analytics.dataCategory: #FACT
@Analytics.dataExtraction.enabled: true
@ObjectModel.representativeKey: [ 'SalesDocument' ]
@ObjectModel.usageType.dataClass: #TRANSACTIONAL
@ObjectModel.usageType.serviceQuality: #B
@ObjectModel.usageType.sizeCategory: #XL
define view ZVDM_I_VBAK 
 as select from vbak 
{
      //Key
  key vbeln as SalesDocument,
      
      //Category
      vbak.vbtyp                                           as SDDocumentCategory,
      vbak.auart                                           as SalesDocumentType,
      
      // Created By , Date and Time
      vbak.ernam                                           as CreatedByUser,
      vbak.erdat                                           as CreationDate,
      cast( vbak.erzet as creation_time preserving type )  as CreationTime,
      
      //Organization
      vbak.vkorg                                           as SalesOrganization,
      vbak.vtweg                                           as DistributionChannel,
      vbak.spart                                           as OrganizationDivision,
      vbak.vkgrp                                           as SalesGroup,
      vbak.vkbur                                           as SalesOffice,
      
      //Sales Customer
      vbak.kunnr                                           as SoldToParty,
      
      //Amount
      vbak.netwr                                           as TotalNetAmount,
      vbak.waerk                                           as TransactionCurrency, 
       
      vbak.vdatu                                           as RequestedDeliveryDate, 
      vbak.vsbed                                           as ShippingCondition,
      vbak.autlf                                           as CompleteDeliveryIsDefined,
      vbak.lifsk                                           as DeliveryBlockReason,
      //Reference
      vbak.vgbel                                           as ReferenceSDDocument,
      vbak.vgtyp                                           as ReferenceSDDocumentCategory,
      
      //Status
      vbak.gbstk                                           as OverallSDProcessStatus,
      vbak.abstk                                           as OverallSDDocumentRejectionSts
      
}

Exercise 2: Make a Simple CDS View: ZVDM I VBAP (FACT, BASIC)

Using Association I created a CDS view (Basic, FACT) from VBAP and attached it to the above CDS view (ZVDM_I_VBAK).

@AbapCatalog.sqlViewName: 'ZVDM_VIEW_VBAP'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sales Item data( Basic View , Fact table)'
@VDM.viewType: #BASIC
@Analytics.dataCategory: #FACT
@Analytics.dataExtraction.enabled: true
@ObjectModel.representativeKey: [ 'SalesDocument']
@ObjectModel.usageType.dataClass: #TRANSACTIONAL
@ObjectModel.usageType.serviceQuality: #B
@ObjectModel.usageType.sizeCategory: #XL
define view ZVDM_I_VBAP
  as select from vbap
  association[1..1]  to ZVDM_I_VBAK                    as _vbak         on  $projection.SalesDocument     = _vbak.SalesDocument
  
{
  key vbap.vbeln                                                   as  SalesDocument,
  key vbap.posnr                                                   as  SalesDocumentItem,
      vbap.matnr                                                   as  Material,
      
      vbap.arktx                                                   as  SalesDocumentItemText,
      vbap.posex                                                   as  UnderlyingPurchaseOrderItem,
    
      vbap.kwmeng                                                  as  OrderQuantity,
      vbap.vrkme                                                   as  OrderQuantityUnit,
     
      vbap.zmeng                                                   as  TargetQuantity,
      vbap.zieme                                                   as  TargetQuantityUnit,
     
      //Pricing
      vbap.netwr                                                   as  NetAmount,
      vbap.waerk                                                   as  TransactionCurrency,
      vbap.netpr                                                   as  NetPriceAmount,
      
      //Shipping 
      vbap.vstel                                                   as  ShippingPoint,
      vbap.werks                                                   as  Plant,
      vbap.lgort                                                   as  StorageLocation,
      vbap.route                                                   as  Route,
      
      //Reference Dosument
      vbap.vbelv                                                   as  OriginSDDocument,
      vbap.posnv                                                   as  OriginSDDocumentItem,
      vbap.vgbel                                                   as  ReferenceSDDocument,
      vbap.vgpos                                                   as  ReferenceSDDocumentItem,
      vbap.vgtyp                                                   as  ReferenceSDDocumentCategory,
      vbap.uepos                                                   as  HigherLevelItem,
      
      //Status
      vbap.gbsta                                                   as  SDProcessStatus,
      vbap.absta                                                   as  SDDocumentRejectionStatus,
  
  //Make Association
    _vbak
}

Exercise 3: Make a Simple CDS ZVDM_I_LIPS (BASIC, FACT) is displayed.

utilizing Association a CDS View (Basic, FACT) was created from the LIPS and LIKP data.

@AbapCatalog.sqlViewName: 'ZVDM_VIEW_LIPS'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Delivery Item data( Basic View , Fact table)'
@VDM.viewType: #BASIC
@Analytics.dataCategory: #FACT
@Analytics.dataExtraction.enabled: true
@ObjectModel.representativeKey: [ 'ReferenceSDDocument' ]
@ObjectModel.usageType.dataClass: #TRANSACTIONAL
@ObjectModel.usageType.serviceQuality: #B
@ObjectModel.usageType.sizeCategory: #XL
define view ZVDM_I_LIPS 

as select from lips 
  //Associations
  association[1..1] to likp       as _likp      on $projection.DeliveryDocument    = _likp.vbeln
  
{
  //Keys  
  key vbeln                                                          as DeliveryDocument,
  key posnr                                                          as DeliveryDocumentItem,
  key vgbel                                                          as ReferenceSDDocument,
      matnr                                                          as Material,
      pstyv                                                          as DeliveryDocumentItemCategory,
      lgort                                                          as StorageLocation,
      lgpla                                                          as StorageBin,
      lgtyp                                                          as StorageType,
      
      //delivery
      arktx                                                          as DeliveryDocumentItemText,
      
      @Semantics.unitOfMeasure: true
      vrkme                                                          as DeliveryQuantityUnit,
      
      @DefaultAggregation: #SUM
      @Semantics.quantity.unitOfMeasure: 'DeliveryQuantityUnit'
      lfimg                                                           as ActualDeliveryQuantity,
      
      @DefaultAggregation: #SUM
      @Semantics.quantity.unitOfMeasure: 'DeliveryQuantityUnit'
      ormng                                                           as OriginalDeliveryQuantity,
      
      @Semantics.unitOfMeasure: true
      meins as BaseUnit,
      
      //reference  
      
      vgpos                                                           as ReferenceSDDocumentItem,
      vgtyp                                                           as ReferenceSDDocumentCategory,
      
      //Status
      gbsta                                                           as SDProcessStatus,
      fksta                                                           as DeliveryRelatedBillingStatus,
      
      // Pricing
      vbelv                                                           as OriginSDDocument,
      posnv                                                           as SDDocumentItem,
      vbtyv                                                           as SalesSDDocumentCategory,
      ematn                                                           as BaseUnit1,
      werks                                                           as DelPlant,
//      _likp.kunag                                                     as ShipToParty,
  
   // Make Associations
   _likp
    
}

Worksheet 4: Construct Composite CDS View: ZVDM CO SALES (CUBE, COMPOSITE)

Using the custom CDS views ZVDM_I_VBAP, ZVDM_I_LIPS, and Standard Material CDS views as a basis, a Composite View was created. Partners in SalesDocumentItemPartner, I_Material, and I_MaterialText.

Here, we represented the currency and quantities using semantic annotations in the composite view, and we created the Transient Provider using the specialized annotation @Analytics.datacategory; #CUBE.

Add the RSRTS_ODP_DIS transaction to your favorites. This is for the Temporary Provider Preview.

Use of @Anlytics.dataCategory:#CUBE in the CDS View will result in the creation of a transient provider in the S/4HANA system.It is applicable to several reporting tools.

@AbapCatalog.sqlViewName: 'ZVDM_VIEW_SALES'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sales Composite View(Composite View ,CUBE)'
@VDM.viewType: #COMPOSITE
@Analytics.dataCategory: #CUBE
@ObjectModel.usageType.dataClass: #TRANSACTIONAL
@ObjectModel.usageType.serviceQuality: #B
@ObjectModel.usageType.sizeCategory: #XL
@Search.searchable: true
define view ZVDM_CO_SALES 

  as select from  ZVDM_I_VBAP as VBAP 
  association[0..*]  to ZVDM_I_LIPS                    as _LIPS         on  $projection.SalesDocument        = _LIPS.ReferenceSDDocument and
                                                                            $projection.SalesDocumentItem    = _LIPS.ReferenceSDDocumentItem
  association[1..1]  to I_Material                     as _Material     on  $projection.materialNumber       = _Material.Material
  association[0..*]  to I_MaterialText                 as _MaterialText on  $projection.materialNumber       = _MaterialText.Material
  association[0..*]  to I_SalesDocumentItemPartner     as _Partneritem  on  $projection.SalesDocument        = _Partneritem.SalesDocument  and
                                                                            $projection.SalesDocumentItem    = _Partneritem .SalesDocumentItem                                                
{
  //VBAP
  //@ObjectModel.foreignKey.association: '_vbak'
  @Search.defaultSearchElement: true 
  key VBAP.SalesDocument,
  
  key VBAP.SalesDocumentItem,
  
  _vbak.SalesOrganization as SalesOrganization,
  
  Material as materialNumber,
  
  @EndUserText.label: 'Material Descrption'
  @EndUserText.quickInfo: 'Material Desc'
  @Semantics.text: true
  _MaterialText[ 1:Language = $session.system_language ].MaterialName as MaterialDescrption, 
  
  
  SalesDocumentItemText,
  UnderlyingPurchaseOrderItem,
  case
       when (_LIPS.DeliveryDocument is null ) then 'No Follow ON Document Created'                                           
       else _LIPS.DeliveryDocument
       end as Status,
  _LIPS.DeliveryDocument,
  _LIPS.DeliveryDocumentItem,
  
  @Semantics.unitOfMeasure: true
  OrderQuantityUnit,
  
  @Semantics.unitOfMeasure: true
  TargetQuantityUnit,
  
  @Semantics.currencyCode: true
  TransactionCurrency,
  
  ShippingPoint,
  Plant,
  StorageLocation,
  Route,
  OriginSDDocument,
  OriginSDDocumentItem,
//  ReferenceSDDocument  as SalesDocument NU,
//  ReferenceSDDocumentItem as SalesDocumentItem,
  ReferenceSDDocumentCategory,
  HigherLevelItem,
  SDProcessStatus,
  SDDocumentRejectionStatus,

//  _LIPS.Material,
  _LIPS.DeliveryDocumentItemCategory,
//  _LIPS.StorageLocation,
  _LIPS.StorageBin,
  _LIPS.StorageType,
  _LIPS.DeliveryDocumentItemText,
   
   @Semantics.unitOfMeasure: true
  _LIPS.DeliveryQuantityUnit as DELIVERYQUNATITYUNIT,
  
  @Semantics.quantity.unitOfMeasure: 'DELIVERYQUNATITYUNIT'
  _LIPS.OriginalDeliveryQuantity,
  
  _LIPS.BaseUnit,
//  _LIPS.ReferenceSDDocument,
//  _LIPS.ReferenceSDDocumentItem,
//  _LIPS.ReferenceSDDocumentCategory,
  _LIPS.SDProcessStatus as DeliveryStatus,
  _LIPS.DeliveryRelatedBillingStatus,
//  _LIPS.OriginSDDocument,
//  _LIPS.SDDocumentItem,
  _LIPS.SalesSDDocumentCategory,
  
   //Aggregations 
   @DefaultAggregation:#SUM
   @Semantics.quantity.unitOfMeasure: 'OrderQuantityUnit'
   OrderQuantity,
   
   @Semantics.quantity.unitOfMeasure: 'TargetQuantityUnit'
   @DefaultAggregation:#SUM
   TargetQuantity,
   
   @Semantics.amount.currencyCode: 'TransactionCurrency'
   @DefaultAggregation:#SUM
   NetAmount,
   
   @Semantics.amount.currencyCode: 'TransactionCurrency'
   @DefaultAggregation:#SUM
   NetPriceAmount,
   
   @Semantics.quantity.unitOfMeasure: 'DELIVERYQUNATITYUNIT'
   @DefaultAggregation:#SUM
   _LIPS.ActualDeliveryQuantity,        
   
  /* Associations */
  _vbak,
  _LIPS,
  _Material,
  _MaterialText,
  _Partneritem 

}

With ADT (Eclipse/HANA Studio), you may preview the data of each VDM created individually by simply pressing F8 or right-clicking and selecting Preview.

To learn how to Create Transient Provider was one of the article’s objectives. And we already have knowledge. Transient Provider is automatically created when you construct the Composite View with annotation @Analytics.datacategory; #CUBE.

How Can a Transient Provider Be Used?

Transaction Code: RSRTS_ODP_DIS; execute. Select ODP Name: ZVDM_VIEW_SALES (SQL View Name of Composite and CUBE Name), ODP Context: ABAP Core Data Services.

Note that the SQL View Name was selected, not the CDS Entity View name. You can access SQL View Name at the Data Dictionary Level.

Select the Standard Query option.

From the FREE Characteristics, choose the fields you wish to study (we choose sales order, sales order item, and material).

That is all. Congratulations! Using the Transient Provider was a successful use. The Composite View’s output is visible to you in the Transient Provider. ABAP developers typically don’t use it.It’s for reporting people (you could feel more at ease if your friend is a BI, BO, or BW).

How Can SAP Analysis for Office (AO) See VDM?

  • The only thing Analysis Office is is a SAP Business Objects Add-on for Microsoft Excel and PowerPoint.
  • The two images below illustrate steps 1 through 5 for using CDS view in Analysis for Office.

Please install Analysis Office for Microsoft Excel if you are unable to see the Analysis Menu.

  • As an alternative, you could take the actions listed below.
  • Launch Excel and select the Analysis Menu Tab.

Go to Insert Data Source and hit Select Data Source

Step 6: Select the S/4HANA System and give your credentials.

Step 7:  Search with Composite View SQL Name and Select your CDS view

chosen CDS view.


If for any reason you are unable to locate your CDS SQL Name. Try searching after entering 2C in front of your CDS SQL.In other words.

Step 8: Since we haven’t used any filter annotations or @AnalyticsDetails, the Analysis Office’s first screen will only display measurements automatically.Axis annotations for Query.

While filters are available in Consumption View, we haven’t utilized them here because we’re using Composite Cube View instead of Consumption View. You may give parameters a try.

@consumption.filter annotation:{ MultipleSelections: True, SelectionType: # Range, Mandatory: False}

Step 9: Drag and Drop Required Fields in to Rows.

We can use below annotation to display the fields automatically rows and columns.

Annotation : @AnalyticsDetails.Query.Axis: #Rows /#Columns

That means, if you use @AnalyticsDetails.Query.Axis: #Rows, the Analysis Office would automatically show the data from the VDM. You do not need to drag and drop the fields.

If you do not want to show some fields in the Analysis Office, you may use below annotation with value #FREE. It will not display.

@AnalyticsDetails.Query.Axis: #FREE

This excel sheet can be saved and provided as a template for the end user. End user can change the input parameter via prompts and view data accordingly.

Exercise 5 – Create Consumption View: ZVDM_C_SALES

Finally, let’s created a Consumption View based on the Composite View to create an App in Fiori

We have used semantics annotations in the Consumption View to represent the currency and quantities and also used other UI annotations.      

Below 2 Annotations are used for displaying the text in the Fiori Apps      

@EndUserText.label: ‘Sales Order Number’
@EndUserText.quickInfo: ‘Sales Order NO’

Below 2 Annotations are used for positioning fields and selection fields in the Fiori Apps.  

@UI.lineItem: [{position:10 ,importance: #HIGH}]
@UI.selectionField: [{position: 10}]

It is necessary to publish the CDS view as an OData Service to consume it in Fiori Apps. Below annotation helps.

@ODATA.Publish: true

@AbapCatalog.sqlViewName: 'ZVDM_V_SALES'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Consumption(Sales Information)'
@VDM.viewType: #CONSUMPTION
@OData.publish: true
@Search.searchable: true
define view ZVDM_C_SALES 
//with parameters 
//@EndUserText.label: 'Sales Orgnization'
//@Consumption.defaultValue: 'US01'
//p_salesorg: vkorg
  as select from ZVDM_CO_SALES
 {
    //ZVDM_CO_SALES
    @EndUserText.label: 'Sales Order Number'
    @EndUserText.quickInfo: 'Sales Order NO'
    @UI.lineItem: [{position:10 ,importance: #HIGH}]
    @UI.selectionField: [{position: 10}]
    @ObjectModel.foreignKey.association: '_VBAK'
    @Search.defaultSearchElement: true
    key SalesDocument,
    
    @EndUserText.label: 'Sales Order Item Number'
    @EndUserText.quickInfo: 'Sales Order Item NO'
    @UI.lineItem: [{position:20 }]
    key SalesDocumentItem,
    
    @EndUserText.label: 'Follow On Document'
    @EndUserText.quickInfo: 'Delivery Document'
    @UI.lineItem: [{position:30, importance: #HIGH}]
    Status,
    
    @EndUserText.label: 'Material Number'
    @EndUserText.quickInfo: 'Material NO'
    @UI.lineItem: [{position: 30}]
    materialNumber,
    
    @EndUserText.label: 'Material Dec'
    @EndUserText.quickInfo: 'Material Descrption'
    @UI.lineItem: [{position: 40}]
    MaterialDescrption,
    
    @EndUserText.label: 'Sales Orgnization'
    @EndUserText.quickInfo: 'Sales Org'
    @UI.lineItem: [{position: 50}]
    SalesOrganization   as SalesOrganization,

    @EndUserText.label: 'Sales Doc Type'
    @UI.lineItem: [{position: 60}]
    _vbak.SalesDocumentType as SalesDocType,
    
    @UI.lineItem: [{position: 70}]
    _vbak.DistributionChannel                                       as DChannel,
    
    @UI.hidden: true
    SalesDocumentItemText,
    
    @UI.hidden: true
    UnderlyingPurchaseOrderItem,
    
    @UI.lineItem: [{position: 80}]
    DeliveryDocument,
    
    @UI.lineItem: [{position: 90}]
    DeliveryDocumentItem,
  
    @UI.lineItem: [{position: 110}]
    @Semantics.unitOfMeasure: true
    OrderQuantityUnit,
    
    @UI.lineItem: [{position: 130}]
    @Semantics.unitOfMeasure: true
    TargetQuantityUnit,
    
    @UI.lineItem: [{position: 150}]
    @Semantics.currencyCode: true
    TransactionCurrency,
    
    NetPriceAmount,
    ShippingPoint,
    Plant,
    StorageLocation,
    Route,
    OriginSDDocument,
    OriginSDDocumentItem,
    ReferenceSDDocumentCategory,
    HigherLevelItem,
    SDProcessStatus,
    SDDocumentRejectionStatus,
    DeliveryDocumentItemCategory,
    StorageBin,
    StorageType,
    DeliveryDocumentItemText,
    DELIVERYQUNATITYUNIT,
    ActualDeliveryQuantity,
    OriginalDeliveryQuantity,
    BaseUnit,
    DeliveryStatus,
    DeliveryRelatedBillingStatus,
    SalesSDDocumentCategory,

    
    
    //Aggregations
    @Semantics.quantity.unitOfMeasure: 'ORDERQUANTITYUNIT'
    @DefaultAggregation:#SUM
    @UI.lineItem: [{position: 100}]
    OrderQuantity,
    
    @Semantics.quantity.unitOfMeasure: 'TARGETQUANTITYUNIT'
    @DefaultAggregation:#SUM     
    @UI.lineItem: [{position: 120}]
    TargetQuantity,
    
    @Semantics.amount.currencyCode: 'TRANSACTIONCURRENCY'
    @DefaultAggregation:#SUM
    @UI.lineItem: [{position: 140}]
    NetAmount,
        
    /* Associations */
    //ZVDM_CO_SALES
    _vbak,
    _LIPS,
    _Material,
    _MaterialText,
    _Partneritem
}

OData Service Activation

When we create OData from CDS using annotation, we need to go to the backend SAP System and perform this step manually one time. After we activate the OData Service and create the related DPC and MPC and add the OData Service to the Service Catalog, we do not need to perform this step again, even if we make changes in the original CDS Views.

Let’s see, how we activate the OData Service.

Open the t-code /n/iwfnd/maint_service and press the Add Service button. 

In the Add Selected Services screen provide a System Alias, and then press the Get Services button.  The Technical Service Name field, ZVDM_C_SALES, can be provided to filter the results if necessary. 

Selecting the service should result in the Add Service dialog appearing.  Here you can assign it a package and choose the enter button to complete the process.

The above steps would activate the OData Service and Add it to the Service Catalog. Once it is in the Service Catalog, it is ready to be consumed in the WebIDE while developing Fiori Apps.

If you go back to /N/IWFND/MAINT_SERVICE t-code, you should see your OData Service in the Service Catalog.

Choose your OData and click on SAP Gateway Client (or go to t-code /N/IWFND/GW_CLIENT) to test your OData Service. If it returns status code 200, you are all set. Your OData is working correctly.

Did you notice, the OData Service name is your CDS View name with a suffix _CDS?

Create Fiori Apps Using CDS Views & UI Annotations

Exercise 6 – Fiori Apps using List Report Template

Create Fiori App from Standard Template using SAP WebIDE Full-Stack. This SAP WebIDE Full-Stack will open from SAP Cloud Platform Cockpit.

We connected Cloud Connector and SAP Cloud Platform Cockpit.

Once you are in the WebIDE, select Project from Template in the SAP WebIDE Full-Stack and select the List Report Application.

Select the SAP Backend System and OData Service and click on finish button.

Once, finished, you may Deploy the App to your ABAP repository. You need to do this step, only if you are planning to move your App to your next SAP environment say Quality and then to Production using Transport. For testing, you may skip this step.

Select SAP System and give application name and description. Select the transport request and confirm it so your application is deployed to the backend SAP System.

Now, let’s test our App.

Did you realize? We did not write an single line of code in the App in WebIDE and we are ready to test out of the box. That is the beauty of creating App using CDS/VDM Views.

Click on Run-> Run as Web Application

Select the flpSandbox.html file

Our Fiori App is ready. Click on our app (ZSALES_REPORT).

It will show a blank output.

You need to click on Go button to see the report.

Fiori App  display will change based on the Semantics annotations, UI Annotations, Text Annotations.

We can use different annotations for Charts, Header Info, Images, Navigation etc.

Exercise 7 – Fiori Overview Page Report(OVP) Template

We will not go in to the details of this template but we will just explain few annotations.

Annotation @UI.headerInfo:   Use this annotation to define the typeName which will be shown as the card header, as well as a title and header

@UI.headerInfo: {
typeNamePlural: ‘Sales Orders’,
//  imageUrl: ‘VenkatImg’,
typeName: ‘Sales Order’,
  title: {
    label: ‘Order ID’,
    value: ‘SalesDocument’
  },
  description: {
    label: ‘Customer’,
    value: ‘Customer’
  }
}

Annotation @UI.identification: Used for navigating from one view to other view using Semantic Navigation.

@UI.identification: {type: #FOR_INTENT_BASED_NAVIGATION, semanticObjectAction: ”, label: ”, position: ”}

Annotation @UI.chart : Used for displaying the Charts in the Fiori app.

@UI.chart:[{
    qualifier: ‘chartLineItem’,
    title:’Order Net Amount’,
    chartType: #COLUMN,
    dimensions: [‘SalesDocument’],
    measures: [‘NetAmount’, ‘NetPriceAmount’],
    dimensionAttributes: {dimension: ‘SalesDocument’, role:#SERIES},
    measureAttributes: [{measure: ‘NetAmount’, role: #AXIS_1}, {measure:
NetPriceAmount’, role: #AXIS_1}]
 }]

Annotation @UI.dataPoint : Used for displaying the KPI values.

@UI.dataPoint: {title: ‘Net Amt’,
    criticalityCalculation: {
    improvementDirection: #TARGET,
    deviationRangeLowValue: 000,
    toleranceRangeLowValue: 600,
    toleranceRangeHighValue: 1000,
    deviationRangeHighValue: 1400
    }}

@AbapCatalog.sqlViewName: 'ZVDM_V_SALES1'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sales OVP Report'
@VDM.viewType: #CONSUMPTION
@OData.publish: true
@Search.searchable: true
@UI.headerInfo: {
  typeNamePlural: 'Sales Orders',
//  imageUrl: 'mytestImg',
  typeName: 'Sales Order',
  title: {
    label: 'Order ID',
    value: 'SalesDocument'
  },
  description: {
    label: 'Customer',
    value: 'Customer'
  }
}
@UI.chart:[{
    qualifier: 'chartLineItem',
    title:'Order Net Amount',
    chartType: #COLUMN,
    dimensions: ['SalesDocument'],
    measures: ['NetAmount', 'NetPriceAmount'],
    dimensionAttributes: {dimension: 'SalesDocument', role:#SERIES},
    measureAttributes: [{measure: 'NetAmount', role: #AXIS_1}, {measure: 'NetPriceAmount', role: #AXIS_1}]
 }]
 @UI.presentationVariant: [{qualifier: 'top5Changed', maxItems: '5',  sortOrder.by: 'SalesDocument', sortOrder.direction: #DESC }]
define view ZVDM_C_SALES1
//with parameters 
//@EndUserText.label: 'Sales Orgnization'
//@Consumption.defaultValue: 'US01'
//p_salesorg: vkorg
  as select from ZVDM_CO_SALES
 {
    //ZVDM_CO_SALES
//    @EndUserText.label: 'Sales Order Number'
//    @EndUserText.quickInfo: 'Sales Order NO'
    @UI.lineItem: [{position:10 ,qualifier: 'ordOverView',importance: #HIGH,label: 'Sales Order'}] --,{qualifier: 'chartLineItem'}]
    @UI.selectionField: [{position: 10}]
    //@ObjectModel.foreignKey.association: '_VBAK'
    @Search.defaultSearchElement: true
    key SalesDocument,
    
//    @EndUserText.label: 'Sales Order Item Number'
//    @EndUserText.quickInfo: 'Sales Order Item NO'
//    @UI.lineItem: [{position:20 }]
    key SalesDocumentItem,
    
    @UI.selectionField: [ { position: 20 } ]
    @UI.lineItem:  { position: 20, qualifier:'ordOverView', label: 'Customer' }
    _Partneritem.Customer as Customer,
    
//    @EndUserText.label: 'Follow On Document'
//    @EndUserText.quickInfo: 'Delivery Document'
//   // @UI.lineItem: [{position:30, importance: #HIGH}]
//    @UI.identification: [{position: 10}]
//    @UI.fieldGroup: [{qualifier: 'Account Group' }]
    Status,
    
//    @EndUserText.label: 'Material Number'
//    @EndUserText.quickInfo: 'Material NO'
//    @UI.lineItem: [{position: 30}]
    @UI.identification: [{position: 10}]
    materialNumber,
    _vbak.CreatedByUser as CreatedBy,
    
//    @EndUserText.label: 'Material Dec'
//    @EndUserText.quickInfo: 'Material Descrption'
//    @UI.lineItem: [{position: 40}]
    @UI.identification: [{position: 20}]
    MaterialDescrption,
    
//    @EndUserText.label: 'Sales Orgnization'
//    @EndUserText.quickInfo: 'Sales Org'
//    @UI.lineItem: [{position: 50}]
    SalesOrganization   as SalesOrganization,

//    @EndUserText.label: 'Sales Doc Type'
//    @UI.lineItem: [{position: 60}]
    _vbak.SalesDocumentType as SalesDocType,
    
//    @UI.lineItem: [{position: 70}]
    _vbak.DistributionChannel                                       as DChannel,
    
    @UI.hidden: true
    SalesDocumentItemText,
    
    @UI.hidden: true
    UnderlyingPurchaseOrderItem,
    
//    @UI.lineItem: [{position: 80}]
    DeliveryDocument,
    
//    @UI.lineItem: [{position: 90}]
    DeliveryDocumentItem,
  
//    @UI.lineItem: [{position: 110}]
    @Semantics.unitOfMeasure: true
    OrderQuantityUnit,
    
//    @UI.lineItem: [{position: 130}]
    @Semantics.unitOfMeasure: true
    TargetQuantityUnit,
    
//    @UI.lineItem: [{position: 150}]
    @Semantics.currencyCode: true
    TransactionCurrency,
    
//    @UI.identification: [{position: 20}]
//    @UI.fieldGroup: [{qualifier: 'Account Group' }]
    @UI.dataPoint: {title: 'Price Amount', valueFormat:{ numberOfFractionalDigits: 2 }}
    @UI.lineItem:  [{ position: 40, qualifier:'ordOverView', label: 'Tax Amount', type: #AS_DATAPOINT},{qualifier: 'chartLineItem'}]
    @Semantics.amount.currencyCode: 'TransactionCurrency'
    NetPriceAmount,
    
    ShippingPoint,
    Plant,
    StorageLocation,
    Route,
    OriginSDDocument,
    OriginSDDocumentItem,
    ReferenceSDDocumentCategory,
    HigherLevelItem,
    SDProcessStatus,
    SDDocumentRejectionStatus,
    DeliveryDocumentItemCategory,
    StorageBin,
    StorageType,
    DeliveryDocumentItemText,
    DELIVERYQUNATITYUNIT,
    ActualDeliveryQuantity,
    OriginalDeliveryQuantity,
    BaseUnit,
    DeliveryStatus,
    DeliveryRelatedBillingStatus,
    SalesSDDocumentCategory,  
    
    //Aggregations
    @Semantics.quantity.unitOfMeasure: 'ORDERQUANTITYUNIT'
    @DefaultAggregation:#SUM
//    @UI.lineItem: [{position: 100}]
    OrderQuantity,
    
    @Semantics.quantity.unitOfMeasure: 'TARGETQUANTITYUNIT'
    @DefaultAggregation:#SUM     
//    @UI.lineItem: [{position: 120}]
    TargetQuantity,
    
    @Semantics.amount.currencyCode: 'TRANSACTIONCURRENCY'
    @DefaultAggregation:#SUM
//    @UI.lineItem: [{position: 140}]
   @UI.dataPoint: {title: 'Net Amt', 
    criticalityCalculation: {
    improvementDirection: #TARGET,
    deviationRangeLowValue: 000,
    toleranceRangeLowValue: 600,
    toleranceRangeHighValue: 1000,
    deviationRangeHighValue: 1400
    }}
   @UI.lineItem:  [{ position: 30, qualifier:'ordOverView', label: 'Net Amount', type: #AS_DATAPOINT},{ qualifier: 'chartLineItem'}]
    NetAmount,
        
    /* Associations */
    //ZVDM_CO_SALES
    _vbak,
    _LIPS,
    _Material,
    _MaterialText,
    _Partneritem
}

To get the above OVP results we have to change some code in the Manifest.jason file in the WebIDE tool.

As promised in the beginning of this article, we completed Transient Provider, Analysis For Office and Smart Template Application based on CDS VDM Views.

You can explore more about the annotations in CDS views and surprise yourself.

This is my first article at Technicalgyanguru. Your suggestions are welcomed. Do let me know what topics you want me to cover in Core Data Services and Virtual Data Models.

  • Related Posts

    Section 17 of CDS. How Can I Fix the ABAP CDS GUID Mismatch Linking Issue?

    I attempted to demonstrate Open SQL’s limitations in relation to SQL Script in my most recent piece. Today, I want to draw attention to a CDS constraint and provide a…

    CDS Part 18: Using CDS Views to Create Bar and Donut Charts

    Three batches of students in our instructor-led online ABAP CDS training have just finished. The result of our training is this paper. Without any prior experience with HTML, JS, or…

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    You Missed

    S/4HANA VDM 1 Employing CDS Virtual Data Model for Embedded Analytics

    • By Varad
    • November 1, 2024
    • 4 views

    Section 17 of CDS. How Can I Fix the ABAP CDS GUID Mismatch Linking Issue?

    • By Varad
    • October 31, 2024
    • 4 views

    CDS Part 18: Using CDS Views to Create Bar and Donut Charts

    • By Varad
    • October 30, 2024
    • 5 views

    Eclipse Set-Up for ABAP Cloud in ABAP on Cloud – 3

    • By Varad
    • October 29, 2024
    • 3 views

    ABAP on Cloud – 7 – Insert Records through Class and Create Metadata Extension

    • By Varad
    • October 28, 2024
    • 4 views

    ABAP for Cloud – 8 – Binding & Output, Behavior Definition, and Service Definition

    • By Varad
    • October 26, 2024
    • 5 views