Skip to Content
Technical Articles
Author's profile photo Lorenzo Te

Extending SAP Fiori App: My Inbox – Approve Purchase Requisitions (F0401A)

Back-end system: S/4HANA 1709 (SP 102)

Overview

The intent of this blog post is to provide some initial insight in extending the standard SAP Fiori – My Inbox application. Specifically, this will deal with the SAP Fiori app: My Inbox – Approve Purchase Requisition (F0401A). Take note that this will not go into the details of setting up the SAP Business Workflow that will be using this, but only extending the SAP Fiori app itself. Fortunately, once set-up properly, we only need look at the ABAP Core Data Services (CDS) views to modify the front-end output.

In particular, the UI.Facet annotations within the CDS view will now drive the changes to the output, without the need to update the annotation MDL xml file in server. As we will see in the below example, there is no need to change the delivered CDS views. Creating an extend view will suffice.

 

Reference Configuration

Just to provide some reference, the following are the entries maintained in back-end system (SAP S/4HANA) for the SAP Business Workflow configuration:

Transaction Code: SPRO

Path: SAP Reference IMG -> SAP Customizing Implementation Guide -> SAP Netweaver -> SAP Gateway Service Enablement -> Content -> Workflow Settings -> Maintain Task Names and Decision Options

Transaction Code: SWFVISU

 

Front-End Visualization

The following images show the areas in which the enhancements will be reflected when opening the SAP Fiori App

 

Extending CDS views

For Header level changes, we will be extending C_PurRequisitionFs. This CDS view will have data at the PR header level. The following will be the definition of the CDS extend view ZC_PurRequistionFSExt

@AbapCatalog.sqlViewAppendName: 'ZCPURREQFSEXT'
@EndUserText.label: 'Extension view for C_PurRequistionFS'
extend view C_PurRequisitionFs with ZC_PurRequistionFSExt {
. . .
}
  • To change the Header Area (“Administrative Data” section), the following annotations are used:
    • Annotation “@UI.identification”
      @UI.identification:{importance: #HIGH, position: 1000}
      _Facts.CreatedByUser as CreatedByUserExt,  
      
      @Semantics.amount.currencyCode: 'DisplayCurrency'
      @UI.identification:{label:'Total Net Value', importance: #HIGH, valueFormat.numberOfFractionalDigits: 2, position: 1020} 
      cast(cast(_Facts.PurReqnTotalAmountInDspCrcy as abap.curr( 15, 2 )) as mm_pur_requisition_tnetvalue)  as PurReqnTotalAmountInDspCrcyExt
    • ’importance’ needs to be set to #HIGH for the field to appear
    • ‘position’ will define where the field will be shown
    • ’valueFormat.numberOfFractionalDigits’ can be used to change the number of decimal places shown for the value
    • ’label’ can be used to define the field description, else it will take this from the CDS view definition
    • Annotations “@Semantics.amount.currencyCode” and “@Semantics.quantity.unitOfMeasure” can be used to relate the field to the appropriate unit field

 

For Item level changes, we will be extending C_PurRequisitionItemFs. This CDS view will have data at the PR Item level. The following will be the definition of the CDS extend view ZC_PurRequistionItemFSExt

@AbapCatalog.sqlViewAppendName: 'ZCPURREQITMFSEXT'
@EndUserText.label: 'Extension view for C_PurRequistionItemFS'
extend view C_PurRequisitionItemFs with ZC_PurRequistionItemFSExt {
. . .
}
  • To change the Item Summary table (Section below “Administrative Data”), the following annotations are used:
    • Annotation “@UI.lineItem”
      @UI.lineItem:{position: 900, importance: #HIGH, label: ‘Test Label’}
      I_Purchaserequisitionitem.FieldName as NewFieldName,
      
      @Semantics.amount.currencyCode: 'NewCurrency'
      @UI.lineItem:{position: 1000, importance: #HIGH, label: 'Amount Value'}
      I_Purchaserequisitionitem.AmountField as NewAmountField,
      @Semantics.currencyCode: true
      I_Purchaserequisitionitem.PurReqnItemCurrency as NewCurrency,
      
      @Semantics.quantity.unitOfMeasure: 'NewUoM'
      @UI.lineItem:{position: 1100, importance: #HIGH, label: 'Test7'}
      I_Purchaserequisitionitem.QuantityField as NewQuantityField,
      @Semantics.unitOfMeasure: true
      I_Purchaserequisitionitem.BaseUnit as NewUoM
    • ‘position’ will define where the field will be shown in the table.
    • ’importance’ needs to be set to #HIGH for the field to appear
    • ’label’ can be used to define the field description, else it will take this from the CDS view definition
    • Annotations “@Semantics.amount.currencyCode” and “@Semantics.quantity.unitOfMeasure” can be used to relate the field to the appropriate unit field
    • Annotation “@Semantics.unitOfMeasure: true” can be used when defining a new unit field, if one is not already available
  • To change the Item Detail section, when navigating/double clicking on the individual items, the following annotations are used:
    • Annotation “@UI.facet”
      • This will identify the different sections (or facets) that will be available/shown
      • An initial entry is needed to define the collection of facets, even if only a single facet is needed:
        @UI.facet: [{ 
                  id: 'xxx',
                  isSummary: true,
                  type: #COLLECTION
              },
        ...
              ]
      • The parameter ‘id’ can be defined as you want, however, ‘isSummary’ and ‘type’ need to be defined as shown
      • Next, the different sections need to be defined:
        {
            parentId: 'xxx',
            id: 'yyy',
            type: #FIELDGROUP_REFERENCE,
            targetQualifier: 'nnn',
            label: 'Description Here'
        }
      • ’parameterID’ needs to refer to the collection define in the previous step
      • ’id’, ‘targetQualifier’ and ‘label’ can be defined as you want
      • ’type’ needs to be defined as shown
      • Multiple sections can be defined; ensure that these are separated using a comma
    • Annotation “@UI. fieldGroup”
      • This will now define what is shown in the output
      • Each field will have its own entry, and will use the qualifier (targetQualifier) defined in the previous step to determine where the field will be output
      • @UI.fieldGroup: [{ qualifier: 'nnn',
                           position: 10,
                           label: ‘Label Here’  }]
        I_Purchaserequisitionitem.FieldName as NewFieldName,
      • Parameter ‘qualifier’ should refer to the appropriate ‘targetQualifier’ of the section maintained in the annotation @UI.facet
      • ’position’ will define the order that the field will be displayed within the section
      • If ‘label’ is not defined, it will take the description of the CDS View field
      • The following can also be added after the UI.fieldGroup annotation, as needed, to add the unit to the display:
        1. @Semantics.quantity.unitOfMeasure: ‘UnitOfMeasure’
        2. @Semantics.amount.currencyCode: ‘CurrencyField’

 

And now here is the full code to the 2 CDS extend views that correspond to the images shown above:

CDS View ZC_PurRequistionFSExt

@AbapCatalog.sqlViewAppendName: 'ZCPURREQFSEXT'
@EndUserText.label: 'Extension view for C_PurRequistionFS'
extend view C_PurRequisitionFs with ZC_PurRequistionFSExt {
  @UI.identification:{importance: #HIGH, position: 1000}
  _Facts.CreatedByUser as CreatedByUserExt,  

   @Semantics.amount.currencyCode: 'DisplayCurrency'
   @UI.identification:{label:'Total Net Value', importance: #HIGH,  valueFormat.numberOfFractionalDigits: 2, position: 1020} 
   cast(cast(_Facts.PurReqnTotalAmountInDspCrcy as abap.curr( 15, 2 )) as mm_pur_requisition_tnetvalue)  as PurReqnTotalAmountInDspCrcyExt,
   
   @UI.identification:{ importance: #HIGH, position: 1030}  
   _Facts.PurchaseRequisitionType as PurchaseRequisitionTypeExt,

   @UI.identification:{ importance: #HIGH, position: 1040, label: 'Test8'}
   @ObjectModel.text.association: '_PurchasingDocumentTypeText'  
   _Facts.PurchaseRequisitionType as PurchaseRequisitionTypeExt2,

   @Semantics.amount.currencyCode: 'DisplayCurrency'
   @UI.identification:{label:'Test9', importance: #HIGH, valueFormat.numberOfFractionalDigits: 3, position: 1050} 
   cast(cast(_Facts.PurReqnTotalAmountInDspCrcy as abap.curr( 15, 2 )) as mm_pur_requisition_tnetvalue)  as PurReqnTotalAmountExt2
}

CDS View ZC_PurRequistionItemFSExt

@AbapCatalog.sqlViewAppendName: 'ZCPURREQITMFSEXT'
@EndUserText.label: 'Extension view for C_PurRequistionItemFS'
extend view C_PurRequisitionItemFs with ZC_PurRequistionItemFSExt {
      @UI.facet: [{ 
                id: 'ItemDetails',
                isSummary: true,
                type: #COLLECTION
            },
            {
                parentId: 'ItemDetails',
                id: 'ItemDetailsInfo',
                type: #FIELDGROUP_REFERENCE,
                targetQualifier: 'one',
                label: 'PR Line Item Details'
            }] 
                 
      @UI.fieldGroup: [{ qualifier: 'one', position: 10  }]
      I_Purchaserequisitionitem.RequisitionerName as RequisitionerNameExt2,

      @UI.fieldGroup: [{ qualifier: 'one', position: 20  }]
      I_Purchaserequisitionitem.RequirementTracking as RequirementTrackingExt2,

      @UI.fieldGroup: [{ qualifier: 'one', position: 30, label: 'Test Label'  }]
      I_Purchaserequisitionitem.RequirementTracking as RequirementTrackingExt3,

      @UI.fieldGroup: [{ qualifier: 'one', position: 40, label: 'Test Value'  }]
      @Semantics.quantity.unitOfMeasure: 'BaseUnitExt3'
      @UI.identification: {position: 40, valueFormat.numberOfFractionalDigits: 4, importance: #HIGH}
      I_Purchaserequisitionitem.RequestedQuantity as RequestedQuantityExt3,
      @Semantics.unitOfMeasure: true
      I_Purchaserequisitionitem.BaseUnit as BaseUnitExt3,

//Start of Summary Table enhancement
      @UI.lineItem:{position: 1000, importance: #HIGH, label: 'Test5'}
      I_Purchaserequisitionitem.PurchaseRequisitionType as PurchaseRequisitionTypExt3,
      
      @Consumption.semanticObject: 'PurchaseRequisitionItem'
      @Semantics.amount.currencyCode: 'PurReqnItemCurrencyExt'
      @UI.lineItem:{position: 1100, importance: #HIGH, label: 'Test6'}
      I_Purchaserequisitionitem.PurchaseRequisitionPrice as PurchaseRequisitionPriceExt,
      @Semantics.currencyCode: true
      I_Purchaserequisitionitem.PurReqnItemCurrency as PurReqnItemCurrencyExt,

      @Consumption.semanticObject: 'PurchaseRequisitionItem'
      @Semantics.quantity.unitOfMeasure: 'BaseUnitExt'
      @UI.lineItem:{position: 1200, importance: #HIGH, label: 'Test7'}
      @UI.identification: {position: 1200, importance: #HIGH}
      I_Purchaserequisitionitem.RequestedQuantity as RequestedQuantityExt,
      @Semantics.unitOfMeasure: true
      I_Purchaserequisitionitem.BaseUnit as BaseUnitExt,

      @Consumption.semanticObject: 'PurchaseRequisitionItem'
      @UI.lineItem:{position: 1300, importance: #HIGH, label: 'Test8'}
      @UI.identification: {position: 1300, importance: #HIGH}
      I_Purchaserequisitionitem.RequestedQuantity as RequestedQuantityExt2

}

 

Conclusion

It now becomes pretty simple to update/enhance the output of the SAP Fiori App: My Inbox – Approve Purchase Requisitions (F0401A) for anyone familiar with CDS views. Generally speaking, as long as the needed field (or even reference field/s for a join) is within the underlying CDS views, then there is no need to edit anything else but the extend views.

However, I am sure that there would additional requirements for other enhancements. As such, I have prepared some additional notes which may be useful below. If I have the time, I will try to expound on them in future blog posts.

Additional Note

  • Additional changes can be done using ABAP by implicit enhancements in the function module (FM): /IWWRK/WF_TGW_TASK_DET_QUERY

Example: if you want to enhance the output of the log, you do this when the FM is called with the following parameter:

IS_REQUESTED_SPEC-WORKFLOW_LOG = X

Here you can influence what is shown when clicking on the “Show Log” button.

Using this as a starting point, you can determine at which level you want to add the code to modify the log. In this FM, a few other class methods are called to determine the content of the log.

  1. Class /IWWRK/IF_TGW_RFCS, method WF_TGW_TASK_DET_QUERY
    • Shared among other requests
  2. Class /IWWRK/IF_TGW_TASK, method QUERY_WORKFLOW_LOG
    • Specific to workflow log only

 

If you want to influence what is shown when clicking on the “Attachments” button, then you can us the same FM with parameter IS_REQUESTED_SPEC-ATTACHMENTS = X

Similar to above, the first class method is called, and then another class method is called specifically for attachments: class /IWWRK/IF_TGW_TASK method QUERY_ATTACHMENTS

In any of the cases above, be sure to set a filter for when the code will get executed, as this is a shared class, and will not just be executed for the PR Approval app. Additionally, if multiple things need to be updated (ex. Both logs and attachments), it may be easier to maintain if the enhancement code is placed in Class /IWWRK/IF_TGW_RFCS, method WF_TGW_TASK_DET_QUERY.

 

  • If there is a special requirement for a field that requires additional ABAP coding (ex. Adding long text that can only be read by FM READ_TEXT), the following blog can be helpful:

https://blogs.sap.com/2020/01/13/using-virtual-elements-with-cds-in-fiori-elements/

 

Assigned tags

      3 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Tanoy Bhattacherjee
      Tanoy Bhattacherjee

      Hi Lorenzo Te,

      After the extension of the cds build, do we need to register this with the FIORI My Inbox app for the new extended CDS to reflect with the new functionality.

      BTW, Excellent Blog!

      Regards,

      Tanoy

      Author's profile photo Fabio Junckes
      Fabio Junckes

      Hello Lorenzo Te,

       

      Thanks for sharing this information.

      I've extended the C_PurRequisitionItemFs and added the new fields but after that the original fields were replaced by the new one.

      Do you know how can I mantain the existing fields and only add new fields?

      Thanks.

      Best regards,

      Fabio

      Author's profile photo Fabio Junckes
      Fabio Junckes

      Hi Lorenzo Te,

      I was able to display the field using the annotation @UI.fieldGroup.

      Best regards,

      Fabio