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:
- @Semantics.quantity.unitOfMeasure: 'UnitOfMeasure'
- @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.
- Class /IWWRK/IF_TGW_RFCS, method WF_TGW_TASK_DET_QUERY
- Shared among other requests
- 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/