Recently I did extension for My Inbox Fiori application for Purchase Order and Purchase Requisition approvals. As beginner, I did not know where to start initially. After some research I found a blog from Ragini Upadhyay (https://blogs.sap.com/2018/06/02/fiori-my-inbox-2.0-extend-approve-purchase-order-s4-hana-1610/which was well explained but I had to struggled a lot. There are few places where this solution wasn’t accurate and wasn’t working. This might be because of the S4 version. Then I found some workaround and finally I’m able to achieve it. Let’s hear it…

 

Requirement:

Display approvers along with status in detail screen for both purchase order and purchase requisition.

Requirement%20for%20Purchase%20Order%20Approval

Requirement for Purchase Order Approval

Requirement%20for%20Purchase%20Requisition%20Approval

Requirement for Purchase Requisition Approval

 

Technical Details:

My Inbox detail screen for PR & PO is cds annotation based. In this case, annotations is being loaded from service model and below links are loading these annotations in the app.

Annotation Purchase Order:

/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Annotations(TechnicalName='C_PURREQUISITION_FS_ANNO_MDL',Version='0001')/$value

Annotation Purchase Requisition:

/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Annotations(TechnicalName='C_PURCHASEORDER_FS_ANNO_MDL',Version='0001')/$value

 

 

Standard CDS View for Extenstion:

PR – C_PurchaseOrderFs

PO – C_PurRequisitionFs

 

Standard Tables:

PR – EBAN (PR Header Details and Release Strategy) -> T16FS (Release Codes from Release Strategy) -> T16FD (Release Codes from Release Group) -> T16FW (User Id’s from Release Codes) -> USR21 (Personnel Number from User Id) -> ADRP (User Full Name from Personal Number)

PO – EKKO (PO Header Details) ->  T16FS (Release Codes from Release Strategy) -> T16FD (Release Codes from Release Group) -> T16FW (User Id’s from Release Codes) -> USR21 (Personnel Number from User Id) -> ADRP (User Full Name from Personal Number)

 

Purchase Order Approvals (4 Levels)

  • Create CDS View ZCDS_PUR_ORD_APP to read Approver ID from T16FW. Joining EKKO on T16FW and T16FD.
@AbapCatalog.sqlViewName: 'ZSQ_PURORD_APP'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS for PO Approvals'
define view ZCDS_PUR_ORD_APP as select from ekko as _PurOrd 
left outer join     t16fs   as      _RelStat        on      _PurOrd.frggr   = _RelStat.frggr 
                                                    and     _PurOrd.frgsx   = _RelStat.frgsx
left outer join     t16fw   as      _RoleRelCode    on      _PurOrd.frggr = _RoleRelCode.frggr
left outer join     t16fd   as      _RelCodeDesc    on      _PurOrd.frggr = _RelCodeDesc.frggr 
                                                    and _RoleRelCode.frgco = _RelCodeDesc.frgco
{
    _PurOrd.ebeln,
    _PurOrd.frggr,
    _PurOrd.frgsx,
    _PurOrd.frgke,
    _PurOrd.frgzu,
    _RoleRelCode.objid,
    _RoleRelCode.otype,
    _RelCodeDesc.frgct,
    _RelCodeDesc.frgco,
    _RelStat.frgc1,
    _RelStat.frgc2,
    _RelStat.frgc3,
    _RelStat.frgc4
}

 

Result of ZCDS_PUR_ORD_APP (Showing approvers in multiple rows)

Objid = User ID

Frgct = User Position

Approvers%20in%20Multiple%20Rows

Approvers in Multiple Rows

 

  • Now we need to Create CDS view ZCDS_PUR_ORD_APP_F to convert multiple rows into single row. Also, association added to read user full name from CDS ZCDS_USER_DET.

Example:

Current%20Result%20for%20Multiple%20Rows

Current Result for Multiple Rows

Converting%20to%20Single%20Row

Converting to Single Row

Here we go…

@AbapCatalog.sqlViewName: 'ZSQ_PO_APPF'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'PO Approvals Final V2'
define view ZCDS_PUR_ORD_APP_F as select from ZCDS_PUR_ORD_APP 
association [1..1] to     ZCDS_USER_DET           as      _UserDet           on      ZCDS_PUR_ORD_APP.objid = _UserDet.UserId {
    ebeln,
    max( case frgco when frgc1 then objid end ) as ApproverID1,
    max( case frgco when frgc2 then objid end ) as ApproverID2,
    max( case frgco when frgc3 then objid end ) as ApproverID3,
    max( case frgco when frgc4 then objid end ) as ApproverID4,
    max( case frgco when frgc1 then frgct end ) as ApprPosition1,
    max( case frgco when frgc2 then frgct end ) as ApprPosition2,
    max( case frgco when frgc3 then frgct end ) as ApprPosition3,
    max( case frgco when frgc4 then frgct end ) as ApprPosition4,
    max( case frgco when frgc1 then _UserDet.UserFName end ) as ApproverName1,
    max( case frgco when frgc2 then _UserDet.UserFName end ) as ApproverName2,
    max( case frgco when frgc3 then _UserDet.UserFName end ) as ApproverName3,
    max( case frgco when frgc4 then _UserDet.UserFName end ) as ApproverName4,
    substring(frgzu,1,1) as ApprovedLevel1,
    substring(frgzu,2,1) as ApprovedLevel2,
    substring(frgzu,3,1) as ApprovedLevel3,
    substring(frgzu,4,1) as ApprovedLevel4
} group by ebeln, frgzu

 

Result

Approvers%20Converted%20to%20Single%20Row

Approvers Converted to Single Row

 

  • CDS ZCDS_USER_DET for User Details
@AbapCatalog.sqlViewName: 'ZSQ_USRDET'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'User Details'
define view ZCDS_USER_DET as select from usr21 as _User
inner join adrp as _PersDet 
    on _User.persnumber = _PersDet.persnumber {
    key _User.bname as UserId,
    _User.persnumber as PersNo,
    _PersDet.name_text as UserFName
}

 

  • Now we need to create extension on Standard CDS C_PurchaseOrderFs association on ZCDS_PUR_ORD_APP_F along with annotations. I have copied annotations from standard cds for one field and made changes for our new fields.
@AbapCatalog.sqlViewAppendName: 'ZSQ_PURORDFS_EXT'
@EndUserText.label: 'Extension for C_PurchaseOrderFs'
extend view C_PurchaseOrderFs with ZC_PurchaseOrderFs_EXT
  association [1..1] to     ZCDS_PUR_ORD_APP_F      as      _Approver       on      I_PurchaseOrderEnhanced.purchaseorder = _Approver.ebeln
{

  @UI.fieldGroup: [{
      qualifier: 'Recipient',
      groupLabel: 'Recipient', groupLabel_asOtr: 'FA163EDF73161EE587C742C45B2B0F3D',
      position: 40,
      exclude: false,
      importance: #HIGH }, {
          qualifier: 'Detail3',
          groupLabel: 'Recipient', groupLabel_asOtr: 'FA163EDF73161EE587C742C45B2B0F3D',
          position: 40,
          exclude: false,
          importance: #HIGH
      }]
  @EndUserText.label: 'Approver Level 1' 
  case when _Approver.ApprovedLevel1 = 'X'
    then CONCAT(_Approver.ApproverName1, ' - Approved')
    else CONCAT(_Approver.ApproverName1, ' - Pending')
    end as ApproverID1,
    
  // _UserDet.UserFName as ApproverName1,

  @UI.fieldGroup: [{
  qualifier: 'Recipient',
  groupLabel: 'Recipient', groupLabel_asOtr: 'FA163EDF73161EE587C742C45B2B0F3D',
  position: 50,
  exclude: false,
  importance: #HIGH }, {
      qualifier: 'Detail3',
      groupLabel: 'Recipient', groupLabel_asOtr: 'FA163EDF73161EE587C742C45B2B0F3D',
      position: 50,
      exclude: false,
      importance: #HIGH
  }]
  @EndUserText.label: 'Approver Level 2' 
  case when _Approver.ApprovedLevel2 = 'X'
    then CONCAT(_Approver.ApproverName2, ' - Approved')
    else CONCAT(_Approver.ApproverName2, ' - Pending')
    end as ApproverID2,

  @UI.fieldGroup: [{
  qualifier: 'Recipient',
  groupLabel: 'Recipient', groupLabel_asOtr: 'FA163EDF73161EE587C742C45B2B0F3D',
  position: 60,
  exclude: false,
  importance: #HIGH }, {
      qualifier: 'Detail3',
      groupLabel: 'Recipient', groupLabel_asOtr: 'FA163EDF73161EE587C742C45B2B0F3D',
      position: 60,
      exclude: false,
      importance: #HIGH
  }]
  @EndUserText.label: 'Approver Level 3' 
  case when _Approver.ApprovedLevel3 = 'X'
    then CONCAT(_Approver.ApproverName3, ' - Approved')
    else CONCAT(_Approver.ApproverName3, ' - Pending')
    end as ApproverID3,
    
  @UI.fieldGroup: [{
  qualifier: 'Recipient',
  groupLabel: 'Recipient', groupLabel_asOtr: 'FA163EDF73161EE587C742C45B2B0F3D',
  position: 70,
  exclude: false,
  importance: #HIGH }, {
      qualifier: 'Detail3',
      groupLabel: 'Recipient', groupLabel_asOtr: 'FA163EDF73161EE587C742C45B2B0F3D',
      position: 70,
      exclude: false,
      importance: #HIGH
  }]
  @EndUserText.label: 'Approver Level 4' 
  case when _Approver.ApprovedLevel4 = 'X'
    then CONCAT(_Approver.ApproverName4, ' - Approved')
    else CONCAT(_Approver.ApproverName4, ' - Pending')
    end as ApproverID4
}

 

That’s it. We are done.

 

Purchase Requisition Approvals (8 Levels):

  • Create CDS ZCDS_PUR_REQ_APP to read Approver ID from T16FW. Joining EBAN on T16FST16FW and T16FD. Here we are taking one more table T16FS additionally, from this we are taking release strategies and related release codes. As there are many release strategies are defined based on multiple conditions.
@AbapCatalog.sqlViewName: 'ZSQ_PURREQ_APP'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS for PR Approvals'
define view ZCDS_PUR_REQ_APP as select from eban as _PurReq 
left outer join     t16fs   as      _RelStat        on      _PurReq.frggr   = _RelStat.frggr 
                                                    and     _PurReq.frgst   = _RelStat.frgsx
                                                    
left outer join     t16fd   as      _RelCodeDesc    on      _PurReq.frggr   = _RelCodeDesc.frggr 
                                                    and     ( _RelStat.frgc1  = _RelCodeDesc.frgco
                                                    or     _RelStat.frgc2  = _RelCodeDesc.frgco
                                                    or     _RelStat.frgc3  = _RelCodeDesc.frgco
                                                    or     _RelStat.frgc4  = _RelCodeDesc.frgco
                                                    or     _RelStat.frgc5  = _RelCodeDesc.frgco
                                                    or     _RelStat.frgc6  = _RelCodeDesc.frgco
                                                    or     _RelStat.frgc7  = _RelCodeDesc.frgco
                                                    or     _RelStat.frgc8  = _RelCodeDesc.frgco )
                                                    
left outer join     t16fw   as      _RoleRelCode    on      _PurReq.frggr   = _RoleRelCode.frggr 
                                                    and     _RelCodeDesc.frgco = _RoleRelCode.frgco
{
    _PurReq.banfn,
    _PurReq.frgkz,
    _PurReq.frgzu,
    _PurReq.frgst,
    _PurReq.frggr,
    _RelStat.frgc1,
    _RelStat.frgc2,
    _RelStat.frgc3,
    _RelStat.frgc4,
    _RelStat.frgc5,
    _RelStat.frgc6,
    _RelStat.frgc7,
    _RelStat.frgc8,
    _RoleRelCode.objid,
    _RoleRelCode.otype,
    _RelCodeDesc.frgct,
    _RelCodeDesc.frgco
}

 

  • Now we need to Create CDS view ZCDS_PUR_REQ_APP_F to convert multiple rows into single row. Also, association added to read user full name from CDS ZCDS_USER_DET.
@AbapCatalog.sqlViewName: 'ZSQ_PR_APPF'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'PR Approvals Final V2'
define view ZCDS_PUR_REQ_APP_F as select from ZCDS_PUR_REQ_APP 
association [1..1] to     ZCDS_USER_DET           as      _UserDet           on      ZCDS_PUR_REQ_APP.objid = _UserDet.UserId {
    banfn,
    max( case frgco when frgc1 then objid end ) as ApproverID1,
    max( case frgco when frgc2 then objid end ) as ApproverID2,
    max( case frgco when frgc3 then objid end ) as ApproverID3,
    max( case frgco when frgc4 then objid end ) as ApproverID4,
    max( case frgco when frgc5 then objid end ) as ApproverID5,
    max( case frgco when frgc6 then objid end ) as ApproverID6,
    max( case frgco when frgc7 then objid end ) as ApproverID7,
    max( case frgco when frgc8 then objid end ) as ApproverID8,
    max( case frgco when frgc1 then _UserDet.UserFName end ) as ApproverName1,
    max( case frgco when frgc2 then _UserDet.UserFName end ) as ApproverName2,
    max( case frgco when frgc3 then _UserDet.UserFName end ) as ApproverName3,
    max( case frgco when frgc4 then _UserDet.UserFName end ) as ApproverName4,
    max( case frgco when frgc5 then _UserDet.UserFName end ) as ApproverName5,
    max( case frgco when frgc6 then _UserDet.UserFName end ) as ApproverName6,
    max( case frgco when frgc7 then _UserDet.UserFName end ) as ApproverName7,
    max( case frgco when frgc8 then _UserDet.UserFName end ) as ApproverName8,
    substring(frgzu,1,1) as ApprovedLevel1,
    substring(frgzu,2,1) as ApprovedLevel2,
    substring(frgzu,3,1) as ApprovedLevel3,
    substring(frgzu,4,1) as ApprovedLevel4,
    substring(frgzu,5,1) as ApprovedLevel5,
    substring(frgzu,6,1) as ApprovedLevel6,
    substring(frgzu,7,1) as ApprovedLevel7,
    substring(frgzu,8,1) as ApprovedLevel8
} group by banfn, frgzu

 

  • Now we need to create extension on Standard CDS C_PurRequisitionFs association on ZCDS_PUR_REQ_APP_F along with annotations. I have copied annotations from standard cds for one field and made changes for our new fields.
@AbapCatalog.sqlViewAppendName: 'ZSQ_PURREQFS_EXT'
@EndUserText.label: 'Extension for C_PurRequisitionFs'
extend view C_PurRequisitionFs with ZC_PurRequisitionFs_EXT 
association [1..1] to     ZCDS_PUR_REQ_APP_F      as      _Approver       on      I_Purchaserequisition.purchaserequisition = _Approver.banfn {

    @EndUserText: {label: 'Approver Level 1'}
    @UI.identification:{label: 'Approver Level 1', importance: #HIGH, position: 500}
    @UI.lineItem:{label: 'Approver Level 1', importance: #MEDIUM, position: 500}
    case when _Approver.ApprovedLevel1 = 'X'
        then CONCAT(_Approver.ApproverName1, ' - Approved')
        else CONCAT(_Approver.ApproverName1, ' - Pending')
    end as ApproverID1,
    
    @EndUserText: {label: 'Approver Level 2'}
    @UI.identification:{label: 'Approver Level 2', importance: #HIGH, position: 600}
    @UI.lineItem:{label: 'Approver Level 2', importance: #MEDIUM, position: 600}
    case when _Approver.ApprovedLevel2 = 'X'
        then CONCAT(_Approver.ApproverName2, ' - Approved')
        else CONCAT(_Approver.ApproverName2, ' - Pending')
    end as ApproverID2,
    
    @EndUserText: {label: 'Approver Level 3'}
    @UI.identification:{label: 'Approver Level 3', importance: #HIGH, position: 700}
    @UI.lineItem:{label: 'Approver Level 3', importance: #MEDIUM, position: 700}
    case when _Approver.ApprovedLevel3 = 'X'
        then CONCAT(_Approver.ApproverName3, ' - Approved')
        else CONCAT(_Approver.ApproverName3, ' - Pending')
    end as ApproverID3,
    
    @EndUserText: {label: 'Approver Level 4'}
    @UI.identification:{label: 'Approver Level 4', importance: #HIGH, position: 800}
    @UI.lineItem:{label: 'Approver Level 4', importance: #MEDIUM, position: 800}
    case when _Approver.ApprovedLevel4 = 'X'
        then CONCAT(_Approver.ApproverName4, ' - Approved')
        else CONCAT(_Approver.ApproverName4, ' - Pending')
    end as ApproverID4,
    
    @EndUserText: {label: 'Approver Level 5'}
    @UI.identification:{label: 'Approver Level 5', importance: #HIGH, position: 900}
    @UI.lineItem:{label: 'Approver Level 5', importance: #MEDIUM, position: 900}
    case when _Approver.ApprovedLevel5 = 'X'
        then CONCAT(_Approver.ApproverName5, ' - Approved')
        else CONCAT(_Approver.ApproverName5, ' - Pending')
    end as ApproverID5,
    
    @EndUserText: {label: 'Approver Level 6'}
    @UI.identification:{label: 'Approver Level 6', importance: #HIGH, position: 1000}
    @UI.lineItem:{label: 'Approver Level 6', importance: #MEDIUM, position: 1000}
    case when _Approver.ApprovedLevel6 = 'X'
        then CONCAT(_Approver.ApproverName6, ' - Approved')
        else CONCAT(_Approver.ApproverName6, ' - Pending')
    end as ApproverID6,
    
    @EndUserText: {label: 'Approver Level 7'}
    @UI.identification:{label: 'Approver Level 7', importance: #HIGH, position: 1100}
    @UI.lineItem:{label: 'Approver Level 7', importance: #MEDIUM, position: 1100}
    case when _Approver.ApprovedLevel7 = 'X'
        then CONCAT(_Approver.ApproverName7, ' - Approved')
        else CONCAT(_Approver.ApproverName7, ' - Pending')
    end as ApproverID7,
    
    @EndUserText: {label: 'Approver Level 8'}
    @UI.identification:{label: 'Approver Level 8', importance: #HIGH, position: 1200}
    @UI.lineItem:{label: 'Approver Level 8', importance: #MEDIUM, position: 1200}
    case when _Approver.ApprovedLevel8 = 'X'
        then CONCAT(_Approver.ApproverName8, ' - Approved')
        else CONCAT(_Approver.ApproverName8, ' - Pending')
    end as ApproverID8
}
Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
1 Comment
Inline Feedbacks
View all comments
Shak Marifkhonov
1 year ago

Hi! Thank you very much! I think some screenshots are missing. Can you please check? Thanks!

1
0
Would love your thoughts, please comment.x
()
x