Skip to Content
Technical Articles
Author's profile photo Canan Özdemir

Using Virtual Elements with CDS in Fiori elements

Overview

In this post you will learn, how we can use ‘READ_TEXT’ function for Fiori elements application. Consumption CDS is generating the Fiori elements application but sometimes we need Abap Logic calculation. (Calculate field values using Abap resources one of them read text belongs to material or orders etc.).

In this case, we can use the CDS with Virtual Element.

What are the Virtual Elements and Why we use that?

Sometimes when we make a report, we need calculations for fields and we can not easily make calculations with CDS so that their values can be calculated directly on SAP HANA. Virtual elements represent temporary fields in applications. They are defined consumption CDS view with annotations within the SELECT list. However, the field calculations display by Abap classes that implement the specific code exit interfaces provided for this purpose.

The code exit class for virtual elements. We should implement suitable interfaces according to the use case;

You can find more information about Virtual Element with Sap standard documents link.

https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/7.51.7/en-US/a7fc007921d44263b09ccc092392b05f.html

https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/7.51.6/en-US/8cbf576babc348668d00b93387612a1c.html

 

Implementation Steps:

 

  1. Use Eclipse for creating CDS View. Use Virtual element in CDS with annotations.

You can find more information about create the CDS View for beginners.

https://blogs.sap.com/2019/11/07/developing-app-with-sap-fiori-elements-list-report-page-object-page-using-cds-view-and-annotations-abap-programming-model-on-sap-s-4-hana./

 

CDS View;

@AbapCatalog.sqlViewName: 'ZI_V_GOODPACK'

@AbapCatalog.compiler.compareFilter: true

@AbapCatalog.preserveKey: true

@AccessControl.authorizationCheck: #CHECK

@EndUserText.label: 'Goodpack Series No - Basic View'


@OData: { publish: true }


@UI.headerInfo:{ typeNamePlural: 'GoodPack'}

define view ZI_GOODPACK


  as select from    likp             as l1

    inner join      lips             as l2 on  l2.vbeln = l1.vbeln and l2.pstyv = 'ZPAC'

    left outer join kna1             as k1 on k1.kunnr = l1.kunnr

    left outer join vbfa             as v1 on  v1.vbelv   = l1.vbeln and v1.vbtyp_n = '8'

    left outer join vttk             as v2 on v2.tknum = l1.vbeln

    left outer join /scdl/db_proch_o as t1 on t1.docno = l1.vbeln

    left outer join /scwm/huref      as t2 on t2.docid = t1.docid

    left outer join /scwm/hu_ident   as t3 on  t3.guid_hu = t2.guid_hu and t3.idart   = 'Y'

    left outer join lips             as l3 on l3.vbeln = l1.vbeln

    left outer join vbrp             as v4 on  v4.vgbel = l1.vbeln and v4.vgpos = l3.posnr

    left outer join vbrk             as v5 on  v5.vbeln = v4.vbeln and sfakn    = ''


{


      @UI: { lineItem: [ { position: 10, label: 'Delivery'} ]}

  key l1.vbeln,


      @UI.hidden: false

      @UI.selectionField: [{ position: 10 }]

      @Consumption.valueHelpDefinition:[{entity:{name:'ZI_VKORGSH',element:'vkorg'}}]

      @Consumption.filter : { selectionType : #RANGE, multipleSelections : true, defaultValue : '1250'}

      l1.vkorg,


      @UI.hidden: false

      @UI.selectionField: [{ position: 20 }]

      @Consumption.valueHelpDefinition:[{entity:{name:'ZI_WERKSSH',element:'werks'}}]

      l1.werks,


      @UI: { lineItem: [ { position: 20, label: 'Customer'} ]}

      @UI.selectionField: [{ position: 30 }]

      @Consumption.valueHelpDefinition:[{entity:{name:'ZI_KUNNRSH',element:'kunnr'}}]

      l1.kunnr,


      @UI: { lineItem: [ { position: 30, label: 'Customer Name'} ]}

      concat( concat( k1.name1, ' '), k1.name2 ) as name1,


      @UI: { lineItem: [ { position: 40, label: 'Delivery Note'} ]}

      l1.xblnr,


      @UI: { lineItem: [ { position: 40, label: 'Container ID'} ]}

      v2.signi,


      @UI: { lineItem: [ { position: 50, label: 'Actual Goods Movement Date'} ]}

      l1.wadat_ist,


      @UI: { lineItem: [ { position: 60, label: 'Material Number'} ]}

      l2.matnr,


      @UI: { lineItem: [ { position: 70, label: 'Short text for sales order item'} ]}

      l2.arktx,


      @UI: { lineItem: [ { position: 80} ]}

      v1.vbeln                                   as vbfa_vbeln,


      @UI: { lineItem: [ { position: 90} ]}

      t4.konsimento_tarih,

      @UI: { lineItem: [ { position: 100} ]}

      t4.konsimento_no,


      @UI: { lineItem: [ { position: 110, label: 'Virtual Element'} ]}

      @ObjectModel.virtualElement: true

      @ObjectModel.virtualElementCalculatedBy: 'ZCL_DEMO_CDS_CALC'

      cast( ''  as abap.char(255))               as note


}

group by

  l1.vbeln,

  l1.vkorg,

  l1.werks,

  l1.kunnr,

  k1.name1,

  k1.name2,

  l1.xblnr,

  l1.wadat_ist,

  l2.matnr,

  l2.arktx,

  v1.vbeln,

  v2.signi,

  t2.guid_hu,

  t3.huident,

  t4.konsimento_tarih,

  t4.konsimento_no

 

Define relationship with CDS, ODATA and Custom Class.


2. Create custom class and implement intarface ‘IF_SADL_EXIT_CALC_ELEMENT_READ’.   Implement both methods ‘GET_CALCULATE_INFO’ and ‘CALCULATE’.

  • Method GET_CALCULATION_INFO is used to provide the list of fields which is required for the calculation.
  • Method CALCULATE is actual method where we implement the custom logic.

  • Implementation Step 1 : We called custom class in CDS view.
       @ObjectModel.virtualElement: true

       @ObjectModel.virtualElementCalculatedBy: 'ZCL_DEMO_CDS_CALC'

       cast( ''  as abap.char(255))  as note

 

Use the CALCULATE method for utilizing ABAP resource.

3. Use SAP Web IDE for creating List Reporting App.

You can find detail information about List Reporting App.

https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/1709%20000/en-US/8dec506e13f949c2a82e8c775a94b73b.html

Output

Conclusion

In this blog, we learn how we can utilize the CDS virtual elements. I welcome all suggestions for improvement or questions. Thanks for reading.


References

http://sapabapcentral.blogspot.com/2019/04/fiori-elements-utilizing-cds-with.html

https://blogs.sap.com/2019/04/26/fiori-elements-utilizing-cds-with-virtual-elements

 

Canan Özdemir.

Assigned Tags

      55 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo ibrahim öztekin
      ibrahim öztekin

      Great Blog !

      Thanks for sharing.

      Author's profile photo Sandra Rossi
      Sandra Rossi

      Can you provide the code of the method GET_CALCULATION_INFO please? Thank you.

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hello Sandra Rossi,

      You can check the this links;

      https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/7.51.6/en-US/04e64a8ffffe49b8a8a5469796f397c0.html

      https://help.sap.com/viewer/923180ddb98240829d935862025004d6/Cloud/en-US/c65942c284dd490a9c3791630d4d4e41.html

      get_calculation_info: This method is called before the actual data retrieval.
      It ensures that all the relevant elements that are needed for the calculation of the virtual element are selected.

      I followed basic example and tried use to "GET_CALCULATION_INFO" method.
      But ı want to say; ı wrote 'price' in "get_calculation_info" method but I could use without writing.
      I am not sure about using this method.

      CDS CODE;

      @AbapCatalog.sqlViewName: 'ZDEMO_CDS_V_005'
      @AbapCatalog.compiler.compareFilter: true
      @AccessControl.authorizationCheck: #CHECK
      @EndUserText.label: 'CDS to Test Access Control'

      @OData: {
      publish: true
      }
      define view ZDEMO_CDS_005
      as select from sflight as a
      inner join sflconnpos as b on a.carrid = b.carrid
      {
      key $session.user as MyName,
      key a.carrid as MyFlightCarrier,
      b.agencynum as MyAgencyNumber,
      a.fldate,
      a.connid,

      @UI: { lineItem: [ { position: 110, label: 'Virtual Element'} ]}
      @ObjectModel.virtualElement: true
      @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_DEMO_CDS_CALC'
      cast( '' as abap.char(255)) as note,

      @Semantics.amount.currencyCode: 'CURRENCY'
      CURRENCY_CONVERSION(
      amount => price,
      source_currency => currency,
      target_currency => cast( 'EUR' as abap.cuky ),
      exchange_rate_date => a.fldate,
      error_handling => 'SET_TO_NULL' ) as price,

      @Semantics.currencyCode: true
      cast( 'EUR' as abap.cuky ) as currency

      }

      where a.carrid = 'AA' and a.fldate = '20170706'

      ABAP CODE;
      METHOD if_sadl_exit_calc_element_read~get_calculation_info.
      LOOP AT it_requested_calc_elements ASSIGNING FIELD-SYMBOL(<fs_calc_element>).
      CASE <fs_calc_element>.
      WHEN 'NOTE'.
      APPEND 'PRICE' TO et_requested_orig_elements.
      ENDCASE.
      ENDLOOP.
      ENDMETHOD.

      METHOD if_sadl_exit_calc_element_read~calculate.

      DATA(lv_today) = cl_abap_context_info=>get_system_date( ).
      DATA lt_original_data TYPE STANDARD TABLE OF ZDEMO_CDS_V_005 WITH DEFAULT KEY.

      lt_original_data = CORRESPONDING #( it_original_data ).

      LOOP AT lt_original_data ASSIGNING FIELD-SYMBOL(<fs_original_data>).

      IF <fs_original_data>-price GT 1000.
      <fs_original_data>-note = | High Price|.
      ELSE.
      <fs_original_data>-note = | Low Price|.
      ENDIF.

      ENDLOOP.

      ct_calculated_data = CORRESPONDING #( lt_original_data ).

      ENDMETHOD.

      Author's profile photo Sandra Rossi
      Sandra Rossi

      I was more looking for some code related to the code you have posted in your post but thank you. I guess the code related to your post should be something like that (in your example, the field NOTE is calculated based on input fields SPRAS and VBELN):

      METHOD if_sadl_exit_calc_element_read~get_calculation_info.
        IF iv_entity <> 'ZI_GOODPACK'.
          RAISE EXCEPTION TYPE /dmo/cx_calc_exit. " any class inheriting from CX_SADL_EXIT
        ENDIF.
        LOOP AT it_requested_calc_elements ASSIGNING FIELD-SYMBOL(<fs_calc_element>).
          CASE <fs_calc_element>.
            WHEN 'NOTE'.
              APPEND 'SPRAS' TO et_requested_orig_elements.
      *        APPEND 'VBELN' TO et_requested_orig_elements. "NOT NEEDED BECAUSE IT'S PART OF KEY !
            WHEN OTHERS.
              RAISE EXCEPTION TYPE /dmo/cx_calc_exit.
          ENDCASE.
        ENDLOOP.
      ENDMETHOD.
      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli

      Hi Sandra Rossi

      Your question really made me curious and I started reading the standard documentation, which is actually correct but doesn’t explain the scenario why it was required.

      (Scenario: It will be properly utilized in case of $select query option is used  in odata service to fetch limited fields and the SADL will not fetch the data for those fields that are not in the $select query and so the method “CALCULATE” will not have that data in those fields to perform the calculation).

      Your code looks fine but you don’t need to pass “VBELN” to requested requested_orig_elements as VBELN will always be filled with value as it is a key field.

      This doesn’t change anything & even passing it will not be a problem, it is just redundant. Just thought to share this information ? ?

       

      Thanks,

      Mahesh

       

       

      Author's profile photo Sandra Rossi
      Sandra Rossi

      Thank you for the check and confirmation! I'm adding the info in the code.

      Author's profile photo Suleyman Dogu
      Suleyman Dogu

      Thanks for the explanation in detail.

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli

      Great example showcasing the ABAP Virtual elements 🙂

      small advise, please replace the "References" section link with the below link

      https://blogs.sap.com/2019/04/26/fiori-elements-utilizing-cds-with-virtual-elements/

      That reference link blog post is copy of the above SAP blog post.

       

      Thanks,
      Mahesh

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hello Mahesh Kumar Palavalli,

      Thank you for advice, if I saw this block I added it as a reference. I will added link.

      Best regards.

      Canan Özdemir.

      Author's profile photo Emre Çetinkaya
      Emre Çetinkaya

      Hello Canan,

      Thank you for sharing a useful and great article.

      Author's profile photo Denis Galand
      Denis Galand

      That is a feature i just discovered, i wish i had known it before, could have helped in past projects, thanks for the share, great feature 🙂

      Author's profile photo Tjarliman Rusadi
      Tjarliman Rusadi

      Hi Canan,

      Great blog with great explanation.

      I have question, in this blog you are using virtual element to display data from the back end to the report in FIORI. My question is, is it possible to use virtual element to hold data input by user, in the form for example, and then post to SAP?

      Regards,

      Tj

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hello Tjarliman Rusadi,

      Thank you for comment. I tried to answer the question as far as I understand.
      Can you explain much more hold data input by user ?

      We created Abap class and implemented IF_SADL_EXIT_CALC_ELEMENT_READ fo using Virtual Elements.
      It is exit and call automaticly when you run report.

      * If you create a form and send data to SAP with button;
      you should use different class. You have 2 options for List Report;

      1- You can create button and BOPF business object action in CDS view and give action name for button press event.
      In this case your class created automaticly with action and you can write to code.

      @UI.lineItem:
      [
      { type: #FOR_ACTION, position: 2, dataAction: 'BOPF:ZACTIONTEST', label: 'Testt' }
      ]

      2- You can create extention button and call your custom oData Service.

      * When push to search button for display table's data and in that time If you want to save table's data you can use Virtual Elements class.
      if it is independent of this, you should use a new class.

       

      Best regards.

      Canan Özdemir.

      Author's profile photo Tjarliman Rusadi
      Tjarliman Rusadi

      Hi Canan,

      Thanks for replying. Really sorry it's been a while replying to you.

      To your question about 'hold user's input data' in the form.

      Actually, i have a list report application of material master, and the source data is from MARA table, etc. Based on that table i created CDS, and web service based on that CDS was created.

      This app has the capabilities of create data as well with draft capabilities, so user can enter data in a form and save it by clicking standard button, and save those data into a custom table.

      But now, user want to input some additonal data in the form, and these data is not exist in the std table which I chose to be as based table for my CDS (MARA, etc).

      So my questiom is, how can I add those additional fields in my CDS (or in my web servive) as they dont exist in any tables?. Can I use this virtual element concept to add these fields especially in the form so user can enter values to it, and then later save it into a custom table.

      Hopefully it is clear to you.

       

      Thanks

      Tj

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hi Tjarliman Rusadi,

      I created CDS view and added field that field does not exist any table and When ı activated cds view, automatically it added draft table.
      Also if ı change this field, new value save by draft table but ıf ı want to save my data to database table ı used draft class and method name is "COPY_DRAFT_TO_ACTIVE_ENTITY" for save my data. I want to share picture but ı can not loaded sorry.

      you can find draft class: ( Business object overview -> go to the root node )

      you can check this link :

      https://blogs.sap.com/2019/01/09/abap-programming-model-for-sap-fiori-draft-based-for-non-guid-keys-much-more../

       

      Best regards.

      Canan Özdemir.

       

      Author's profile photo Tjarliman Rusadi
      Tjarliman Rusadi

      Hi Canan,

       

      Sorry for late reply.

      "I created CDS view and added field that field does not exist any table and When ı activated cds view, automatically it added draft table."

      Could you pls. tell me how to add that field in the CDS view?

      Are you using the same annotation like you mentioned above like

      @ObjectModel.virtualElement: true
      
      @ObjectModel.virtualElementCalculatedBy: 'ZCL_DEMO_CDS_CALC'
      
      cast( ''  as abap.char(255))               as note
      
      ?
      
      Regards,
      Tj
      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hi Tjarliman Rusadi,

      Yes, you can use like that.

      cast( '' as abap.char(255)) as note

       

      Ragards,

      Canan Özdemir.

      Author's profile photo Abdul Rauf Shoukat
      Abdul Rauf Shoukat

      Great Blog

      Author's profile photo Serkan Keleş
      Serkan Keleş

      This is very useful.

      Thanks for sharing.

      Author's profile photo vishwanath vedula
      vishwanath vedula

      Helpful.

      Author's profile photo Abhijeet Kankani
      Abhijeet Kankani

      Nice Blog.

      Author's profile photo Vijay Sharma
      Vijay Sharma

      Good info. Thanks for sharing !!

      Vijay

      Author's profile photo Shubhangi Pandey
      Shubhangi Pandey

      Hi Canan , nice blog. Just wanted to know, if we can reuse this class between multiple independent CDS views?

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hello Shubhangi Pandey,

       

      1- We can see entity name in GET_CALCULATION_INFO method. For example we can check entity name.

      2- I couldn’t find separated parameter in CALCULATION method. If you have to use same class for two CDS you can use one column for parameter in table. You can send default parameter and read it in method. This is just idea.

       

      3- You can create two differents class for each CDS. I think, it can be best method.

       

      Ragards,

      Canan Özdemir.

      Author's profile photo Gaspar Zoltan Erdelyi
      Gaspar Zoltan Erdelyi

      The performance of the example could be improved by calling function READ_TEXT_TABLE.
      LOOP ... CALL FUNCTION 'READ_TEXT' ... ENDLOOP is causing lots of small queries on STX* tables which are more bundled with READ_TEXT_TABLE.
      See SAP Note 2261311 for details.

      Author's profile photo Ranadheer Bandi
      Ranadheer Bandi

      Hi Canan,

      Excellent Blog, Thanks for sharing.

      I have a doubt, can we use virtual elements in extend of standard CDS view: C_MAINTOBJBREAKDOWNQUERY_CDS, and I have tried, but I am getting errors.

       

      Thanks

      Rana

      Author's profile photo Jorge Sousa Villafaina
      Jorge Sousa Villafaina

      Thanks for sharing this blog! I have a doubt about the use of Virtual Elements... Can be used with analytics.query view annotation for display their content in multidimensional reports of S/4HANA?

      Author's profile photo Kanika Malhotra
      Kanika Malhotra

      Hi Jorge

      Any luck on the same?

      Thanks

      Kanika

      Author's profile photo Tarun Chhichhia
      Tarun Chhichhia

      Thanks for sharing the details. I tried a simple example but it seems to come out blank :

       

      • Basic View with ABAP class
      • Consumption view
        • ODATA service to test

      BASIC

      @AbapCatalog.sqlViewName: 'ZIAIRLINE'
      @AbapCatalog.compiler.compareFilter: true
      @AccessControl.authorizationCheck: #NOT_REQUIRED
      @EndUserText.label: 'Airline' 
      @VDM.viewType: #BASIC
      @Analytics.dataCategory: #DIMENSION
      @Analytics.dataExtraction.enabled: true
      @ObjectModel.representativeKey: 'Airline'
      define view ZI_AIRLINE as select from scarr 
      association [0..1]  to ZI_AIRLINE_TEXT as _Text
      on $projection.Airline = _Text.Airline
      {
         @ObjectModel.text.association: '_Text'
         key carrid as Airline,
          @Semantics.currencyCode: true
          
          currcode as AirlineLocalCurrency,
          @Semantics.url: true
           cast (scarr.url as abap.char(250) ) as AirlineURL, 
           
          @ObjectModel.readOnly: true
          @ObjectModel.virtualElement:true
          @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_CDS_FUNCTION' 
          cast( '' as abap.char(250)) as FmText,
               // Associations 
           _Text  
           
       }
      

      Consumption :

       

      @AbapCatalog.sqlViewName: 'ZCAIRLINEQ'
      @AbapCatalog.compiler.compareFilter: true
      @AccessControl.authorizationCheck: #NOT_REQUIRED
      @EndUserText.label: 'Airline'
      @VDM.viewType: #CONSUMPTION
      @Analytics.query: true
      @OData.publish: true
      define view ZC_AIRLINEQUERY 
      as select from ZI_AIRLINE {
          //ZI_AIRLINE
          @AnalyticsDetails.query.display : #KEY_TEXT
          @AnalyticsDetails.query.axis: #ROWS
          key Airline,
          @AnalyticsDetails.query.axis: #ROWS
          AirlineLocalCurrency,
          @AnalyticsDetails.query.axis: #ROWS   
          FmText    
       }
      

      Odata%20service

      Odata service

      Odata Service : Blank ??

       

      ABap Class

       

        METHOD IF_SADL_EXIT_CALC_ELEMENT_READ~CALCULATE.
      
       data: lt_calc_data type standard table of ZI_AIRLINE with default key.
      
        move-corresponding it_original_data   to lt_calc_data.
      
        loop at lt_calc_data assigning field-symbol(<fs_data>).
          <fs_data>-fmtext  = ' Test Virtual elem'.
        endloop.
      
         move-corresponding lt_calc_data to ct_calculated_data.
      
        ENDMETHOD.

       

       

      Author's profile photo Che Eky
      Che Eky

      Can I ask if Virtual Elements are only supported when using "@OData.publish: true"  ??????

      I have an OData service where the CDS was imported as a Business Entity in SADL and the code behind the virtual elements is not executed.

      Thank You

       

      Author's profile photo Bhargava Tanguturi
      Bhargava Tanguturi

      Hi,

      Nice Blog. Thanks for sharing.

      I have a question. Are the virtual elements will work on analytical query CDS?

      I have tried but didn't see any difference even class method is not executed.

       

      Thanks,

      Bhargava

      Author's profile photo Che Eky
      Che Eky

      No virtual elements do not work with Analytical CDS. The class and method will not be called and you can see this in debug.

      Author's profile photo Kameswara Rao Gonugunta
      Kameswara Rao Gonugunta

      Hi

       

      if virtual elements dont work for analytical CDS . Is there any option to pull virtual column in analytical  CDS.

      Author's profile photo DurgaPrasanth vemula
      DurgaPrasanth vemula

      Hi,

      Issue in Using Virtual Elements in ABAP CDS in using Analytics query Annotation

       

      1. Created a ABAP CDS Views "ZACCOUNTING" which i am fetching the Data from the tables and it is @Analytics.dataCategory: #CUBE and also added the below Virtual element where it has call the CLASS ZCL_BRF_NEW_VALUE . Please find the detail code down

      @ObjectModel.virtualElement: true

      @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_BRF_NEW_VALUE'

      cast( '' as abap.char(250)) as NewValue

      2. Now Created Consumption view ZNALYTICAL fetching the data from the ZACCOUNTING which created in step 1 and now in this I added the @Analytics.query: true and @Analytics.dataExtraction.enabled: true

      3.I had registered the ODATA of the ZNALYTICAL in the tcode: /iwnd/maint_service tcode

      4.When i try to execute the OData Service and it is not calling the CLASS 'ZCL_BRF_NEW_VALUE'.

      But if I had not use the @Analytics.query related Annotations in the CONSUMPTION view then it is calling the class 'ZCL_BRF_NEW_VALUE'..

      Could you please tell me any approach is there to call a CLASS 'ZCL_BRF_NEW_VALUE'. even if use @Analytics.query related Annotations

       

      1)CUBE View

      @AbapCatalog.sqlViewName: 'ZBKPF'
      @AbapCatalog.compiler.compareFilter: true
      @AbapCatalog.preserveKey: true
      @AccessControl.authorizationCheck: #CHECK
      @EndUserText.label: 'Accounting Document Header'

      @Analytics.dataCategory: #CUBE

      define view ZACCOUNTING as select from bkpf as SO left outer join bseg as SOI on SO.bukrs = SOI.bukrs and
      SO.belnr = SOI.belnr and SO.gjahr = SO.gjahr {

       

      key SO.belnr,

      key SO.bukrs,

      key SO.gjahr,

      key SOI.buzei,

      SO.blart,
      SOI.dmbtr,
      @ObjectModel.virtualElement: true
      @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_BRF_NEW_VALUE'
      cast( '' as abap.char(250)) as NewValue

      }

       

      2) Consumption View

      @AbapCatalog.sqlViewName: 'ZACCOUNT'
      @AbapCatalog.compiler.compareFilter: true
      @AbapCatalog.preserveKey: true
      @AccessControl.authorizationCheck: #NOT_REQUIRED
      @EndUserText.label: 'ANALTICAL'

      @Analytics.query: true

      @VDM.viewType: #CONSUMPTION

      @Analytics.dataExtraction.enabled: true

      @OData.publish: true

      @UI.selectionPresentationVariant: [{
      qualifier: 'KPIWeightByCountry',
      presentationVariantQualifier: 'KPIWeightByCountry',
      selectionVariantQualifier: 'KPIWeightByCountry'
      },{
      qualifier: 'Default',
      presentationVariantQualifier: 'Default',
      selectionVariantQualifier: 'Default'
      }]
      @UI.presentationVariant: [{
      qualifier: 'KPIWeightByCountry',
      text: 'KPI: Amount per Country',
      visualizations: [{
      type: #AS_CHART,
      qualifier: 'AmountByCompany'
      },{
      type: #AS_DATAPOINT,
      qualifier: 'dmbtr'
      }]
      },{
      qualifier: 'LineItemByYear',
      text: 'Filter: LineItem by Year',
      visualizations: [{
      type: #AS_CHART,
      qualifier: 'ChartBookingsByYear'
      }]
      },{
      qualifier: 'Default',
      visualizations: [{
      type: #AS_CHART,
      qualifier: 'ChartDefault'
      }]
      }]

      @UI.selectionVariant: [{
      qualifier: 'KPIWeightByCountry',
      text: 'Default'
      },{
      qualifier: 'Default',
      text: 'Default'
      }]

      @UI.chart: [{
      qualifier: 'AmountByCompany',
      chartType: #COLUMN,
      dimensions: [ 'bukrs' ],
      measures: [ 'dmbtr' ],
      dimensionAttributes: [{
      dimension: 'bukrs',
      role: #CATEGORY
      }],
      measureAttributes: [{
      measure: 'dmbtr',
      role: #AXIS_1
      }]
      },{
      qualifier: 'ChartBookingsByYear',
      chartType: #DONUT,
      dimensions: [ 'gjahr' ],
      measures: [ 'buzei' ],
      dimensionAttributes: [{
      dimension: 'gjahr',
      role: #CATEGORY
      }],
      measureAttributes: [{
      measure: 'buzei',
      role: #AXIS_1
      }]
      },{
      qualifier: 'ChartDefault',
      chartType: #COLUMN,
      dimensions: [ 'gjahr', 'belnr' ],
      measures: [ 'buzei' ],
      dimensionAttributes: [{
      dimension: 'gjahr',
      role: #SERIES
      },{
      dimension: 'belnr',
      role: #CATEGORY
      }],
      measureAttributes: [{
      measure: 'buzei',
      role: #AXIS_1
      }]
      }]

       

      define view ZNALYTICAL as select from ZACCOUNTING {

       

      @AnalyticsDetails.query.display: #KEY_TEXT
      @UI.lineItem.position: 10
      key belnr as DocumentNumber,

      @AnalyticsDetails.query.display: #KEY_TEXT
      key bukrs as CompanyCode,

      @UI.selectionField.position: 10
      key gjahr as FiscalYear,

      @UI.lineItem.position: 20
      key buzei as LineItem,

      @UI.lineItem.position: 30
      blart as DocumentType,

      @UI.dataPoint.title: 'Amount'
      @UI.lineItem.position: 40
      dmbtr as Amount,

      @UI.lineItem.position: 50
      NewValue

      }

      Author's profile photo DurgaPrasanth vemula
      DurgaPrasanth vemula

      Hi,

      virtual elements not working for analytical CDS . Is there any option to pull virtual column in analytical  CDS.

      Please Suggest any alternative.

      Thanks

       

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hi Durga Prasanth Vemula,

      I have never tried it for analytical CDS so I don't know any answer sorry for this.

       

      Best Regards,

      Canan Özdemir.

      Author's profile photo Ajit Yadav
      Ajit Yadav

      Hi Canan,

      How it_original_data get the data?

      can we debug method from cds view ?

      Thanks,

      Ajit

       

       

      Author's profile photo Chandra Shekar Agrawal
      Chandra Shekar Agrawal

      Hi,

      Is this IF_SADL_EXIT_FILTER_TRANSFORM work with the Draft enabled entity? I mean virtual element using @ObjectModel.filter.transformedBy: 'ABAP: ClassName' but BO is draft enabled.

      gives this error: Draft entity &1: Virtual element &2 has no calculation exit

      Author's profile photo Jennifer Schneidmüller
      Jennifer Schneidmüller

      Any solution to this question? I am getting the same error in my use case.

      Author's profile photo Chandra Shekar Agrawal
      Chandra Shekar Agrawal

      You have to implement @ObjectModel.virtualElementCalculatedBy: 'ABAP:Class_name1' also along with @ObjectModel.filter.transformedBy: 'ABAP:Class_name2' for draft BO.

      @ObjectModel.virtualElementCalculatedBy: 'ABAP:CL1'

      @ObjectModel.filter.transformedBy: 'ABAP:C2'

      virtual Field1 : type

       

      After this, it worked for me.

      Author's profile photo Jennifer Schneidmüller
      Jennifer Schneidmüller

      Great, thank you!
      How did you implement the two classes?

      Author's profile photo Chandra Shekar Agrawal
      Chandra Shekar Agrawal

      Hi, Implement the different interfaces to the different classes.

      Author's profile photo Jennifer Schneidmüller
      Jennifer Schneidmüller

      Yes I did. I get another error in my 'transformed by' class because I try to filter on my new calulated virtual element from my first class. Any tips on how to make that work?

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hello Jennifer,

      I tried like this on cds view. It works when you push the Go button.

      @UI.lineItem.position: 80
      @UI.lineItem.label:'Virtual Element Text'
      @UI.identification: [{
      position: 80,
      label:'Virtual Element Text'
      }]
      @ObjectModel.virtualElement: true
      @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_DEMO_VIRTUALELEMENT_CALC'

      @Search.defaultSearchElement: true
      @Search.fuzzinessThreshold: 0.8
      @EndUserText.label: 'Note'
      @UI: {
      selectionField: [{position: 5}]
      }
      @ObjectModel.filter.transformedBy: 'ABAP:ZCL_DEMO_FILTER_TRANSFORM_CALC'
      SalesOrderHeader.note,

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hello Chandra,

       

      Great answer thank you for sharing. I tried same example, it works.

       

      Best Regards,

      Canan

      Author's profile photo Charles Fang
      Charles Fang

      Hi Canan,

      Thanks for the great blog! I have implemented and I am able to display the read text.

      i would like to check though if there is a maximum number of characters for the virtual element? 1024? is there any documentation about this?

      Also for the formatting, is there a way for the columns to be displayed as how it is typed in the READ_TEXT?

       

      Regards,

      Charles

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hello Fang,

      You can try use "FormattedText" for displaying READ_TEXT.

      <m:FormattedText htmlText="{......}"/>

       

      Best Regards,

      Canan

      Author's profile photo Charles Fang
      Charles Fang

      Hello Canan,

      But in order for us to do this, does this mean we have to customize the XML screen? Meaning the screen will no longer be standard?

      Regards,

      Charles

      Author's profile photo Canan Özdemir
      Canan Özdemir
      Blog Post Author

      Hello Charles,

      I did not diplay READ_TEXT columns to be displayed as how it is typed in the table but I displayed it on smart form using FormattedText. This smart form was custom form, not standard as you said.
      Maybe you can try create extention field in your standard app.

      Best Regards,

      Canan

      Author's profile photo Venkata Subba Raju Elluru
      Venkata Subba Raju Elluru

      Are there any limitations

      can we use Virtual Element for Field 1 and Aggregation for another field 2 in lower or upper layers

      I am getting error, I have a base view with a virtual element for field A and in the consumption layer for another field B used aggregation annotation while activating oData getting error while generating metadata by frame work

      Error - "Calculated elements not allowed in analytical views"

      Author's profile photo Prince Joshi
      Prince Joshi

      Hi Canan Özdemir

       

      thank you for sharing above information.

      Just a quick query, is there any performance degradation if we use Virtual Elements to calculate field value on the fly? Because the calculation logic will be at ABAP Layer(Presentation layer) and not in DB Layer. So, I want to know is it good practise to use Virtual Element or it should be used at extreme scenarios.

      Kindly clarify.

       

      Regards,
      Prince

      Author's profile photo Md. Iqbal
      Md. Iqbal

      If the function takes some parameters, how to implement that? I am trying to use the UKM_COMMTS_BUPA_DISPLAY function in CDS to get the credit exposure value, but can't solve it.

      Author's profile photo Ankit Gusain
      Ankit Gusain

      What about input field? I want to get this virtual element as an input field.

      Author's profile photo Ratnakar Jha
      Ratnakar Jha

      Hi

      Can u please suggest on fiori list report how label/text can be added to aggregated value :

      Author's profile photo Bhaskar Nagula
      Bhaskar Nagula

      Thank You canan özdemir for your explanation.

      Could you please let me know how to debug this? for me the class is not getting triggered.