Custom entities in RAP

In this post we collect patterns and examples for working with custom entites in RAP.

Adding a read-only custom entity to an existing RAP BO

🔢 Implemented in S/4 HANA ON PREMISE 2023 – SP02

Use case: Display a document preview that is calculated at runtime. The data may come from application tables as well as customizing data, but the result is read-only and cannot be modified.

A custom entity is a nice way to realize this scenario since it allows you to dynamically provide data without persistence.

There is no need to include the custom entity in the behavior definition. Also there is no need for interface/consumption view layer differentiation. Just create one view for the custom entity.

Define Custom Entities

The data logic is implemented in the query provider class – see Code template for if_rap_query_provider

Header Entity

@EndUserText.label: '##GENERATED ZFI_XXX_POSPREV'

@ObjectModel.query.implementedBy: 'ABAP:ZCL_XXX_POSPREV_QUERY'

define custom entity ZR_FI_XXX_POSPREV

{

  

key RunUUID : sysuuid_x16;

key PosPrevUUID : sysuuid_x16;

  

CompanyCode : bukrs;

FiscalYear : fis_gjahr_no_conv;

DocumentDate : bldat;

PostingDate : budat;

Period : fins_fiscalperiod;

Currency : fis_hwaer;

Ledger : fins_ledger;

  

_PostingPreviewItems : composition [0..*] of ZR_FI_XXX_POSPREVITM;

  

}

Item Entity

@EndUserText.label: '##GENERATED ZFI_XXX_POSPREV_ITM'

@ObjectModel.query.implementedBy: 'ABAP:ZCL_XXX_POSPREVI_QUERY'

define custom entity ZR_FI_XXX_POSPREVITM

{

key RunUUID : sysuuid_x16;

key PosPrevUUID : sysuuid_x16;

key CompanyCode : bukrs;

key ItmPosition : posnr_acc;

TransactionType : rmvct;

Account : racct;

AccountName : fis_txt50_skat;

PostingKey : bschl;

@Semantics.amount.currencyCode : 'Currency'

Amount : fis_dr_hsl;

Currency : fis_hwaer;

  

_PostingPreview : association to parent ZR_FI_XXX_POSPREV on $projection.RunUUID = _PostingPreview.RunUUID

and $projection.PosPrevUUID = _PostingPreview.PosPrevUUID;

  
  

}

  

Expose Custom Entity in Root BO

To make the custom entity available in the application, we need to associate it with the root entity.

Interface view

Create an association from the root entity to the custom entity.

@AccessControl.authorizationCheck: #CHECK

@EndUserText.label: '##GENERATED ZFI_XXX_RUN'

define root view entity ZR_FI_XXX_RUN

association [0..1] to ZR_FI_XXX_POSPREV as _PostingPreview on $projection.RunUUID = _PostingPreview.RunUUID

{

...

_PostingPreview

}

Consumption view

Expose the association in the projection view so it becomes available in the UI.

@AccessControl.authorizationCheck: #CHECK

@Metadata.allowExtensions: true

@EndUserText.label: 'Projection View for ZR_FI_XXX_RUN'

define root view entity ZC_FI_XXX_RUN

provider contract transactional_query

as projection on ZR_FI_XXX_RUN

{

...

_PostingPreview

  

}

UI Annotations for Fiori

💡Limitations of custom entities:

  • Metadata extensions are not supported – annotations must be defined directly in the custom entity
  • Text associations are not automatically resolved – texts must be populated manually and exposed via annotations

Header Annotations

Defines the structure (facets + field groups) of the preview in the Fiori object page.

@EndUserText.label: '##GENERATED ZFI_XXX_POSPREV'

@ObjectModel.query.implementedBy: 'ABAP:ZCL_XXX_POSPREV_QUERY'

define custom entity ZR_FI_XXX_POSPREV

{

@UI.facet : [{

id: 'POSTING_PREVIEW',

type : #FIELDGROUP_REFERENCE,

label : 'Kopfdaten',

position: 10,

targetQualifier: 'POSTING_PREVIEW' },

{ id : 'POSTING_PREVIEW_ITEMS',

type : #LINEITEM_REFERENCE,

label : 'Positionen',

position: 20,

targetElement: '_PostingPreviewItems'}]

  

@UI.hidden : true

key RunUUID : sysuuid_x16;

@UI.hidden : true

key PosPrevUUID : sysuuid_x16;

  

@UI.fieldGroup : [ { qualifier: 'POSTING_PREVIEW', position: 10} ]

CompanyCode : bukrs;

@UI.fieldGroup : [ { qualifier: 'POSTING_PREVIEW', position: 20} ]

FiscalYear : fis_gjahr_no_conv;

@UI.fieldGroup : [ { qualifier: 'POSTING_PREVIEW', position: 30} ]

DocumentDate : bldat;

@UI.fieldGroup : [ { qualifier: 'POSTING_PREVIEW', position: 40} ]

PostingDate : budat;

@EndUserText.label : 'Periode'

@UI.fieldGroup : [ { qualifier: 'POSTING_PREVIEW', position: 50} ]

Period : fins_fiscalperiod;

@EndUserText.label : 'Währung'

@UI.fieldGroup : [ { qualifier: 'POSTING_PREVIEW', position: 60} ]

Currency : fis_hwaer;

@EndUserText.label : 'Ledger-Gruppe'

@UI.fieldGroup : [ { qualifier: 'POSTING_PREVIEW', position: 70} ]

Ledger : fins_ledger;

  

_PostingPreviewItems : composition [0..*] of ZR_FI_XXX_POSPREVITM;

  

}

  

Item Annotations

Defines the line item table shown in the preview.

@EndUserText.label: '##GENERATED ZFI_XXX_POSPREV_ITM'

@ObjectModel.query.implementedBy: 'ABAP:ZCL_XXX_POSPREVI_QUERY'

@UI: {

headerInfo: {

typeName: 'Position',

typeNamePlural: 'Positionen',

title: { type: #STANDARD, label: 'Position', value : 'ItmPosition' }

}

}

define custom entity ZR_FI_XXX_POSPREVITM

{

@UI.hidden : true

key RunUUID : sysuuid_x16;

@UI.hidden : true

key PosPrevUUID : sysuuid_x16;

@EndUserText.label: 'Buchungskreis'

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

key CompanyCode : bukrs;

@EndUserText.label: 'Position'

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

key ItmPosition : posnr_acc;

@UI.lineItem : [{ position: 50 }]

TransactionType : rmvct;

@EndUserText.label: 'Konto'

@UI.lineItem : [{ position: 40 }]

@ObjectModel.text.element: [ 'AccountName' ]

Account : racct;

AccountName : fis_txt50_skat;

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

PostingKey : bschl;

@EndUserText.label: 'Betrag'

@Semantics.amount.currencyCode : 'Currency'

@UI.lineItem : [{ position: 60 }]

Amount : fis_dr_hsl;

@UI.hidden : true

@EndUserText.label: 'Währung'

Currency : fis_hwaer;

  

_PostingPreview : association to parent ZR_FI_XXX_POSPREV on $projection.RunUUID = _PostingPreview.RunUUID

and $projection.PosPrevUUID = _PostingPreview.PosPrevUUID;

  
  

}

  

Root entity Annotations

Finally, expose the preview section via the root entity metadata extension.

@UI.facet: [ {

id: 'POSTING_PREVIEW_SECTION',

label: 'Belegvorschau',

type: #COLLECTION,

position: 40,

targetQualifier: 'POSTING_PREVIEW_SECTION'

},

{

id: 'POSTING_PREVIEW',

purpose: #STANDARD,

parentId: 'POSTING_PREVIEW_SECTION',

label: 'Kopfdaten',

type: #FIELDGROUP_REFERENCE,

position: 41,

targetElement: '_PostingPreview',

targetQualifier: 'POSTING_PREVIEW'

},

{

id: 'POSTING_PREVIEW_ITEMS',

purpose: #STANDARD,

parentId: 'POSTING_PREVIEW_SECTION',

label: 'Positionsdaten',

type: #LINEITEM_REFERENCE,

position: 42,

targetElement: '_PostingPreview._PostingPreviewItems'

} ]

Leave a Reply

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