cancel
Showing results for 
Search instead for 
Did you mean: 
jannes_schofeld
Employee
Employee

Currently the "Developing with SAP Extension Suite" Learning Journey has some limitations, because code snippets required in some of the exercises are yet to be included. This blog post provides the snippets for the individual exercises in unit 1 to unit 3 until they are included in the official Learning Journey.

See also Code snippets for the "Developing with SAP Extension Suite" Learning Journey Unit 4 to Unit 6

Exercise: Create a CAP-based Service

schema.cds file

 

namespace riskmanagement;
using { managed } from '@sap/cds/common';

entity Risks : managed {
    key ID      : UUID  @(Core.Computed : true);
    title       : String(100);
    owner       : String;
    prio        : String(5);
    descr       : String;
    miti        : Association to Mitigations;
    impact      : Integer;
    //bp          : Association to BusinessPartners;
    // You will need this definition in a later step
    criticality : Integer;
}

entity Mitigations : managed {
    key ID       : UUID  @(Core.Computed : true);
    descr        : String;
    owner        : String;
    timeline     : String;
    risks        : Association to many Risks on risks.miti = $self;
}

 

 

risk-service.cds file

 

using { riskmanagement as rm } from '../db/schema';

@path: 'service/risk'
service RiskService {
  entity Risks as projection on rm.Risks;
    annotate Risks with @odata.draft.enabled;
  entity Mitigations as projection on rm.Mitigations;
    annotate Mitigations with @odata.draft.enabled;
  //@readonly entity BusinessPartners as projection on rm.BusinessPartners;
}

 

 

riskmanagement-Risks.csv file

 

ID;createdAt;createdBy;title;owner;prio;descr;miti_id;impact;
20466922-7d57-4e76-b14c-e53fd97dcb11;2019-10-24;SYSTEM;CFR non-compliance;Fred Fish;3;Recent restructuring might violate CFR code 71;20466921-7d57-4e76-b14c-e53fd97dcb11;10000;
20466922-7d57-4e76-b14c-e53fd97dcb12;2019-10-24;SYSTEM;SLA violation with possible termination cause;George Gung;2;Repeated SAL violation on service delivery for two successive quarters;20466921-7d57-4e76-b14c-e53fd97dcb12;90000;
20466922-7d57-4e76-b14c-e53fd97dcb13;2019-10-24;SYSTEM;Shipment violating export control;Herbert Hunter;1;Violation of export and trade control with unauthorized downloads;20466921-7d57-4e76-b14c-e53fd97dcb13;200000;

 

 

riskmanagement-Mitigations.csv file

 

ID;createdAt;createdBy;descr;owner;timeline
20466921-7d57-4e76-b14c-e53fd97dcb11;2019-10-24;SYSTEM;SLA violation: authorize account manager to offer service credits for recent delivery issues;suitable BuPa;Q2 2020
20466921-7d57-4e76-b14c-e53fd97dcb12;2019-10-24;SYSTEM;"SLA violation: review third party contractors to ease service delivery challenges; trigger budget review";suitable BuPa;Q3 2020
20466921-7d57-4e76-b14c-e53fd97dcb13;2019-10-24;SYSTEM;Embargo violation: investigate source of shipment request, revoke authorization;SFSF Employee with link possible?;29.03.2020
20466921-7d57-4e76-b14c-e53fd97dcb14;2019-10-24;SYSTEM;Embargo violation: review shipment proceedure and stop delivery until further notice;SFSF Employee with link possible?;01.03.2020

 

 

Exercise: Generate the User Interface using SAP Fiori Elements

common.cds file

 

using riskmanagement as rm from '../db/schema';

// Annotate Risk elements
annotate rm.Risks with {
ID     @title : 'Risk';
title  @title : 'Title';
owner  @title : 'Owner';
prio   @title : 'Priority';
descr  @title : 'Description';
miti   @title : 'Mitigation';
impact @title : 'Impact';
}

// Annotate Miti elements
annotate rm.Mitigations with {
ID     @(
    UI.Hidden,
    Commong : {Text : descr}
);
owner  @title : 'Owner';
descr  @title : 'Description';
}

annotate rm.Risks with {
miti @(Common : {
    //show text, not id for mitigation in the context of risks
    Text            : miti.descr,
    TextArrangement : #TextOnly,
    ValueList       : {
    Label          : 'Mitigations',
    CollectionPath : 'Mitigations',
    Parameters     : [
        {
        $Type             : 'Common.ValueListParameterInOut',
        LocalDataProperty : miti_ID,
        ValueListProperty : 'ID'
        },
        {
        $Type             : 'Common.ValueListParameterDisplayOnly',
        ValueListProperty : 'descr'
        }
    ]
    }
});
}

 

 

Include common.cds file into services.cds file

 

using from './risks/annotations';
using from './common';

 

 

UI annotations in apps/risks/annotations.cds file

 

using RiskService from '../../srv/risk-service';

// Risk List Report Page
annotate RiskService.Risks with @(UI : {
    HeaderInfo      : {
        TypeName       : 'Risk',
        TypeNamePlural : 'Risks',
        Title          : {
            $Type : 'UI.DataField',
            Value : title
        },
        Description    : {
         $Type : 'UI.DataField',
            Value : descr
        }
    },
    SelectionFields : [prio],
    Identification  : [{Value : title}],
    // Define the table columns
    LineItem        : [
        {Value : title},
        {Value : miti_ID},
        {Value : owner},
        {
            Value       : prio,
            Criticality : criticality
        },
        {
            Value       : impact,
            Criticality : criticality
        },
    ],
});

// Risk Object Page
annotate RiskService.Risks with @(UI : {
    Facets           : [{
        $Type  : 'UI.ReferenceFacet',
        Label  : 'Main',
        Target : '@UI.FieldGroup#Main',
    }],
    FieldGroup #Main : {Data : [
        {Value : miti_ID},
        {Value : owner},
        {
            Value       : prio,
            Criticality : criticality
        },
        {
            Value       : impact,
            Criticality : criticality
        }
    ]},
});

 

 

Exercise: Add Custom Business Logic to Your Application

risk-service.js file

 

// Imports
const cds = require("@sap/cds");

/**
 * The service implementation with all service handlers
 */
module.exports = cds.service.impl(async function () {
  // Define constants for the Risk and BusinessPartners entities from the risk-service.cds file
  const { Risks, BusinessPartners } = this.entities;

  /**
   * Set criticality after a READ operation on /risks
   */
  this.after("READ", Risks, (data) => {
    const risks = Array.isArray(data) ? data : [data];

    risks.forEach((risk) => {
      if (risk.impact >= 100000) {
        risk.criticality = 1;
      } else {
        risk.criticality = 2;
      }
    });
  });
});

 

 

Exercise: Add an External Service

Additional code for db/schema.cds file

 

// using an external service from S/4
using {  API_BUSINESS_PARTNER as external } from '../srv/external/API_BUSINESS_PARTNER.csn';

entity BusinessPartners as projection on external.A_BusinessPartner {
    key BusinessPartner,
    LastName,
    FirstName
}

 

 

 Additional lines for package.json file

 

"credentials": {
    "url": "https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_BUSINESS_PARTNER/"
}

 

 

Additional code for risk-service.js file

 

  // connect to remote service
  const BPsrv = await cds.connect.to("API_BUSINESS_PARTNER");

  /**
   * Event-handler for read-events on the BusinessPartners entity.
   * Each request to the API Business Hub requires the apikey in the header.
   */
  this.on("READ", BusinessPartners, async (req) => {
    // The API Sandbox returns alot of business partners with empty names.
    // We don't want them in our application
    req.query.where("LastName <> '' and FirstName <> '' ");

    return await BPsrv.transaction(req).send({
      query: req.query,
      headers: {
        apikey: process.env.apikey,
      },
    });
  });

 

 

New riskmanagement-Risks.csv file content

 

ID;createdAt;createdBy;title;owner;prio;descr;miti_id;impact;bp_BusinessPartner
20466922-7d57-4e76-b14c-e53fd97dcb11;2019-10-24;SYSTEM;CFR non-compliance;Fred Fish;3;Recent restructuring might violate CFR code 71;20466921-7d57-4e76-b14c-e53fd97dcb11;10000;9980000448
20466922-7d57-4e76-b14c-e53fd97dcb12;2019-10-24;SYSTEM;SLA violation with possible termination cause;George Gung;2;Repeated SAL violation on service delivery for two successive quarters;20466921-7d57-4e76-b14c-e53fd97dcb12;90000;9980002245
20466922-7d57-4e76-b14c-e53fd97dcb13;2019-10-24;SYSTEM;Shipment violating export control;Herbert Hunter;1;Violation of export and trade control with unauthorized downloads;20466921-7d57-4e76-b14c-e53fd97dcb13;200000;9980000230

 

 

New app/common.cds file content

Note: Lines starting with //### BEGIN OF INSERT and ending with //### END OF INSERT have been added to the previous version of the file.

 

using riskmanagement as rm from '../db/schema';

// Annotate Risk elements
annotate rm.Risks with {
    ID          @title : 'Risk';
    title       @title : 'Title';
    owner       @title : 'Owner';
    prio        @title : 'Priority';
    descr       @title : 'Description';
    miti        @title : 'Mitigation';
    impact      @title : 'Impact';
    //### BEGIN OF INSERT
    bp          @title : 'Business Partner';
    //### END OF INSERT
    criticality @title : 'Criticality';
}

// Annotate Miti elements
annotate rm.Mitigations with {
    ID    @(
        UI.Hidden,
        Commong : {Text : descr}
    );
    owner @title : 'Owner';
    descr @title : 'Description';
}

//### BEGIN OF INSERT
annotate rm.BusinessPartners with {
    BusinessPartner @(
        UI.Hidden,
        Common : {Text : LastName}
    );
    LastName        @title : 'Last Name';
    FirstName       @title : 'First Name';
}
//### END OF INSERT

annotate rm.Risks with {
    miti @(Common : {
        //show text, not id for mitigation in the context of risks
        Text            : miti.descr,
        TextArrangement : #TextOnly,
        ValueList       : {
            Label          : 'Mitigations',
            CollectionPath : 'Mitigations',
            Parameters     : [
                {
                    $Type             : 'Common.ValueListParameterInOut',
                    LocalDataProperty : miti_ID,
                    ValueListProperty : 'ID'
                },
                {
                    $Type             : 'Common.ValueListParameterDisplayOnly',
                    ValueListProperty : 'descr'
                }
            ]
        }
    });
    //### BEGIN OF INSERT
    bp   @(Common : {
        Text            : bp.LastName,
        TextArrangement : #TextOnly,
        ValueList       : {
            Label          : 'Business Partners',
            CollectionPath : 'BusinessPartners',
            Parameters     : [
                {
                    $Type             : 'Common.ValueListParameterInOut',
                    LocalDataProperty : bp_BusinessPartner,
                    ValueListProperty : 'BusinessPartner'
                },
                {
                    $Type             : 'Common.ValueListParameterDisplayOnly',
                    ValueListProperty : 'LastName'
                },
                {
                    $Type             : 'Common.ValueListParameterDisplayOnly',
                    ValueListProperty : 'FirstName'
                }
            ]
        }
    })
//### END OF INSERT
}

 

 

Line that needs to be added in app/risks/annotations.cds in LineItem array and  FieldGroup - Data array

 

{Value : bp_BusinessPartner},

 

 

New event handler to be added in srv/risk-service.js file

 

/**
   * Event-handler on risks.
   * Retrieve BusinessPartner data from the external API
   */
  this.on("READ", Risks, async (req, next) => {
    /*
        Check whether the request wants an "expand" of the business partner
        As this is not possible, the risk entity and the business partner entity are in different systems (SAP BTP and S/4 HANA Cloud),
        if there is such an expand, remove it
        */
    if (!req.query.SELECT.columns) return next();
    const expandIndex = req.query.SELECT.columns.findIndex(
      ({ expand, ref }) => expand && ref[0] === "bp"
    );
    console.log(req.query.SELECT.columns);
    if (expandIndex < 0) return next();

    req.query.SELECT.columns.splice(expandIndex, 1);
    if (
      !req.query.SELECT.columns.find((column) =>
        column.ref.find((ref) => ref == "bp_BusinessPartner")
      )
    ) {
      req.query.SELECT.columns.push({ ref: ["bp_BusinessPartner"] });
    }

    /*
        Instead of carrying out the expand, issue a separate request for each business partner
        This code could be optimized, instead of having n requests for n business partners, just one bulk request could be created
        */
    try {
      const res = await next();
      await Promise.all(
        res.map(async (risk) => {
          const bp = await BPsrv.transaction(req).send({
            query: SELECT.one(this.entities.BusinessPartners)
              .where({ BusinessPartner: risk.bp_BusinessPartner })
              .columns(["BusinessPartner", "LastName", "FirstName"]),
            headers: {
              apikey: process.env.apikey,
            },
          });
          risk.bp = bp;
        })
      );
    } catch (error) {}
  });

 

 

7 Comments