• Inicio
  • Novedades
  • Academia SAP
  • FAQ
  • Blog
  • Contacto
S4PCADEMY_Logo
Twitter Linkedin Instagram
S4PCADEMY_Logo
Twitter Linkedin Instagram
FORMACIÓN SAP

Extienda la aplicación My Inbox Fiori para órdenes de compra y solicitudes de compra en S4 2024

By s4pcademy 


Recientemente hice una extensión para la aplicación My Inbox Fiori para aprobaciones de órdenes de compra y solicitudes de compra. Como principiante, no sabía por dónde empezar inicialmente. Después de investigar un poco, encontré un blog de Ragini Upadhyay (https://blogs.sap.com/2018/06/02/fiori-my-inbox-2.0-extend-approve-purchase-order-s4-hana-1610/) que estaba bien explicado pero tuve que luchar mucho. Hay pocos lugares donde esta solución no fue precisa y no funcionó. Esto podría deberse a la versión S4. Luego encontré alguna solución y finalmente puedo lograrlo. Vamos a oírlo…

Requisito:

Muestre los aprobadores junto con el estado en la pantalla de detalles tanto para la orden de compra como para la solicitud de compra.

Requisito%20para%20Compra%20Pedido%20Aprobación

Requisito para la Aprobación de la Orden de Compra

Requisito%20para%20Compra%20Solicitud%20Aprobación

Requisito para la aprobación de la solicitud de compra

Detalles técnicos:

La pantalla de detalles de mi bandeja de entrada para PR y PO se basa en la anotación de cds. En este caso, las anotaciones se cargan desde el modelo de servicio y los enlaces a continuación cargan estas anotaciones en la aplicación.

Anotación Orden de Compra:

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

Solicitud de compra de anotación:

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

Vista CDS estándar para extensión:

relaciones públicas – C_PurchaseOrderFs

correos – C_PurRequisitionFs

Tablas estándar:

relaciones públicas – EBAN (Detalles de encabezado PR y estrategia de publicación) -> T16FS (Códigos de lanzamiento de la estrategia de lanzamiento) -> T16FD (Códigos de versión del grupo de versión) -> T16FW (ID de usuario de los códigos de liberación) -> USR21 (Número de personal de ID de usuario) -> ADRP (Nombre completo de usuario de Número personal)

correos – EKKO (Detalles del encabezado de la orden de compra) -> T16FD (Códigos de versión del grupo de versión) -> T16FW (ID de usuario de los códigos de liberación) -> USR21 (Número de personal de ID de usuario) -> ADRP (Nombre completo del usuario del número personal)

Aprobaciones de órdenes de compra (4 niveles)

  • Crear vista de CDS ZCDS_PUR_ORD_APP leer ID del aprobador de T16FW. Unión EKKO en T16FW y 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 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
}

Consecuencia de ZCDS_PUR_ORD_APP (Mostrando aprobadores en varias filas)

objid = ID de usuario

frgct = Posición del usuario

Aprobadores%20en%20múltiples%20filas

Aprobadores en varias filas

  • Ahora necesitamos crear una vista de CDS ZCDS_PUR_ORD_APP_F para convertir múltiples filas en una sola fila. Además, se agregó una asociación para leer el nombre completo del usuario de CDS ZCDS_USER_DET.

Ejemplo:

Actual%20Resultado%20para%20Múltiples%20Filas

Resultado actual para varias filas

Convertir%20a%20Single%20Row

Conversión a fila única

Aquí vamos…

@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 '00' then objid end ) as ApproverID1,
    max( case frgco when '11' then objid end ) as ApproverID2,
    max( case frgco when '36' then objid end ) as ApproverID3,
    max( case frgco when '37' then objid end ) as ApproverID4,
    max( case frgco when '00' then frgct end ) as ApprPosition1,
    max( case frgco when '11' then frgct end ) as ApprPosition2,
    max( case frgco when '36' then frgct end ) as ApprPosition3,
    max( case frgco when '37' then frgct end ) as ApprPosition4,
    max( case frgco when '00' then _UserDet.UserFName end ) as ApproverName1,
    max( case frgco when '11' then _UserDet.UserFName end ) as ApproverName2,
    max( case frgco when '36' then _UserDet.UserFName end ) as ApproverName3,
    max( case frgco when '37' 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

Resultado

Aprobadores%20Convertidos%20a%20única%20fila

Aprobadores convertidos a fila única

  • CDS ZCDS_USER_DET para detalles del usuario
@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
}

  • Ahora necesitamos crear una extensión en CDS estándar C_PurchaseOrderFs asociación en ZCDS_PUR_ORD_APP_F junto con anotaciones. Copié anotaciones de CD estándar para un campo y realicé cambios para nuestros nuevos campos.
@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
}

Eso es todo. Hemos terminado.

Aprobaciones de solicitudes de compra (8 niveles):

  • Crear CDS ZCDS_PUR_REQ_APP leer ID del aprobador de T16FW. Unión EBAN en T16FS, T16FW y T16FD. Aquí estamos tomando una tabla más T16FS adicionalmente, de esta estamos tomando estrategias de lanzamiento y códigos de lanzamiento relacionados. Como hay muchas estrategias de lanzamiento, se definen en función de múltiples condiciones.
@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
}

  • Ahora necesitamos crear una vista de CDS ZCDS_PUR_REQ_APP_F para convertir múltiples filas en una sola fila. Además, se agregó una asociación para leer el nombre completo del usuario de 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

  • Ahora necesitamos crear una extensión en CDS estándar C_PurRequisitionFs asociación en ZCDS_PUR_REQ_APP_F junto con anotaciones. Copié anotaciones de CD estándar para un campo y realicé cambios para nuestros nuevos campos.
@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
}

Eso es todo. Disfrutar…
Gracias,




Un nuevo solucionador de redes reinventado para la cadena de suministro de productos lácteos de la granja a la mesa
Previo
Automatización de GCP: implementación de VM con un solo clic con la instalación de la instancia de base de datos de SAP HANA
Siguiente

Madrid

Calle Eloy Gonzalo, 27
Madrid, Madrid.
Código Postal 28010

México

Paseo de la Reforma 26
Colonia Juárez,  Cuauhtémoc
Ciudad de México 06600

Costa Rica

Real Cariari
Autopista General Cañas, 
San José, SJ 40104

Perú

Av. Jorge Basadre 349
San Isidro
Lima, LIM 15073

Twitter Linkedin Instagram
Copyright 2022 | All Right Reserved.