Imagine enhancing your Poetry Slam Manager application with information from an external system. For instance, you might reference a sales order from SAP S/4HANA Cloud Public Edition that includes the sponsoring of a poetry slam event.
This section describes how the Poetry Slam Manager application is enhanced to support the "Sponsoring of a Poetry Slam Event" integration scenario with SAP S/4HANA Cloud Public Edition.
As a result, the Poetry Slam Manager API service is called, and the PoetrySlams entity is updated with the sales order information. In the Poetry Slam Manager application, the poetry slam displays the Sales Order ID and Customer Name in a new UI section called Sponsoring Data. The Customer Name is directly read from the SAP S/4HANA Cloud Public Edition application.
After the Poetry Slam Manager application is enhanced, the Poetry Slam Manager API can be called from an on-stack extension within SAP S/4HANA Cloud Public Edition using the ABAP RESTful Application Programming Model (RAP). This is described in detail in the Cross-Stack Partner Reference Extension Poetry Slam Event Commerce.
This process requires enabling and provisioning the service broker. The tutorials Enable API Access to SAP BTP Applications Using Service Broker, Configure and Consume the APIs of the SAP BTP Application, and Create an API Service for Remote Integrations without Draft Handling describe these steps. Follow all enablement steps described there first.
No additional entitlements or modules are required beyond the multitenancy version and the service broker enablement.
To explore this feature with the Poetry Slam Manager, you have two options:
-
Clone the repository of the Partner Reference Application. Check out the main-multi-tenant branch and enhance the application step by step.
-
Alternatively, check out the main-multi-tenant-features branch where the feature is already included.
The following describes how to enhance the main-multi-tenant branch (option 1).
In this tutorial, the application is enhanced in steps to support the described scenario:
- The SAP BTP application is enhanced to store and show the sales order information and to connect the Sales Order (A2X) and Business Partner (A2X) OData services of SAP S/4HANA Cloud Public Edition.
- The SAP BTP consumer subaccount and the SAP S/4HANA Cloud Public Edition of the consumer are configured to support the sales order integration scenario.
You use the Sales Order (A2X) and Business Partner (A2X) OData services of SAP S/4HANA Cloud Public Edition to read sales orders and business partners in the context of user interactions. These OData services are available on SAP Business Accelerator Hub.
-
Download the metadata files (.edmx files) from the API Specification section:
- Sales Order (A2X) (OData v4)
- Business Partner (A2X) (OData v2)
-
Rename the metadata files (.edmx files) and add the prefix
S4HC_to avoid naming conflicts:S4HC_CE_SALESORDER_0001.edmxS4HC_API_BUSINESS_PARTNER.edmx
-
To import the SAP S/4HANA Cloud Public Edition OData service into the SAP CAP project in SAP Business Application Studio, create a folder named
external_resourcesin the root folder of the application. -
Open the context menu of the external_resources folder and upload the .edmx file with the OData services as remote services.
-
Open a terminal. Navigate to the root folder of the application and import the remote services using these commands:
cds import ./external_resources/S4HC_CE_SALESORDER_0001.edmx --as cdscds import ./external_resources/S4HC_API_BUSINESS_PARTNER.edmx --as cds
As a result, the system creates CDS files in the ./srv/external folder for all remote services and enhances the package.json file with CDS configurations referring to the remote services. Additionally, this command also adds the following node modules to your project:
- @sap-cloud-sdk/connectivity
- @sap-cloud-sdk/http-client
- @sap-cloud-sdk/resilience
Note: Avoid using the
--keep-namespaceparameter in the CDS import command. It can cause service name clashes when importing multiple SAP S/4HANA Cloud Public Edition OData services. -
Enhance the package.json file with development configurations for local testing and productive configurations. Ensure that the csrf and csrfInBatch flags are set in package.json file. This enables the management of cross-site request forgery tokens, which are required for POST requests at runtime when using destinations.
"cds": { "S4HC_CE_SALESORDER_0001": { "kind": "odata", "model": "srv/external/S4HC_CE_SALESORDER_0001", "csrf": true, "csrfInBatch": true, "[development]": { "credentials": { "url": "https://{{S4HC-hostname}}/sap/opu/odata4/sap/api_salesorder/srvd_a2x/sap/salesorder/0001", "authentication": "BasicAuthentication", "username": "{{test-user}}", "password": "{{test-password}}" } }, "[production]": { "credentials": { "destination": "s4hc", "path": "/sap/opu/odata4/sap/api_salesorder/srvd_a2x/sap/salesorder/0001" } } }, "S4HC_API_BUSINESS_PARTNER": { "kind": "odata-v2", "model": "srv/external/S4HC_API_BUSINESS_PARTNER", "csrf": true, "csrfInBatch": true, "[development]": { "credentials": { "url": "https://{{S4HC-hostname}}/sap/opu/odata/sap/API_BUSINESS_PARTNER", "authentication": "BasicAuthentication", "username": "{{test-user}}", "password": "{{test-password}}" } }, "[production]": { "credentials": { "destination": "s4hc", "path": "/sap/opu/odata/sap/API_BUSINESS_PARTNER" } } } }
Note: The package.json refers to the s4hc destination that must be created in the consumer SAP BTP subaccount. It is used for remote service calls with principal propagation. See the next section for more details.
Note: For local testing, replace
{{S4HC-hostname}},{{test-user}}, and{{test-password}}with a system, user, and password from SAP S/4HANA Cloud Public Edition. However, don't push this information to your GitHub repository. For more information, see Test and Troubleshoot an ERP Integration.
In SAP Business Application Studio, enhance the SAP CAP entity models in /db/poetrySlamManagerModel.cds file with elements to store sales order information, which makes it possible to associate poetry slams with sales orders in the remote ERP system.
-
Extend the PoetrySlams entity:
extend PoetrySlams with { salesOrderID : String(70); };
-
Enhance the annotations of the PoetrySlams entity with the following element:
salesOrderID @title: '{i18n>salesOrderID}';
-
Enhance the labels of PoetrySlams entity in the /db/i18n/i18n.properties file with the following label:
salesOrderID = Sales OrderIn the reference example, the /db/i18n/i18n_de.properties file with the German texts is available, too. You can use these texts as needed.
-
In SAP Business Application Studio, open the srv/api/poetrySlamManagerAPI.cds service models file to extend the SAP CAP API service model by the sales order information.
-
Extend the PoetrySlams entity with the salesOrderID.
// Extend service entity with SalesOrderID for S/4HANA integration scenario extend PoetrySlams with columns { salesOrderID };
-
In SAP Business Application Studio, open the srv/poetryslam/poetrySlamService.cds service models file to extend the SAP CAP service model by remote entities.
-
Add a projection of the SAP S/4HANA Cloud Public Edition sales order partner to the service model for consumption in the SAP Fiori elements UI:
// ------------------------------------------------------------------------------- // Extend service PoetrySlamService by SAP S/4HANA Cloud sales order (principal propagation) using {S4HC_CE_SALESORDER_0001 as RemoteS4HCSalesOrder} from '../external/S4HC_CE_SALESORDER_0001'; extend service PoetrySlamService with { entity S4HCSalesOrderPartner as projection on RemoteS4HCSalesOrder.SalesOrderPartner { key SalesOrder as salesOrderUUID, Customer as customer } };
-
Enhance the service model of the PoetrySlamService service with virtual elements and an association to the remote sales order and business partner in SAP S/4HANA Cloud Public Edition. The virtual elements are calculated in the implementation class of the service. The customerFullName is determined from the business partner (role customer) of the sales order. The salesOrderURL is a direct URL to the referenced sales order.
// Poetry Slams (draft enabled) @odata.draft.enabled @Common.SemanticObject: 'poetryslams' @Common.SemanticKey : [ID] entity PoetrySlams as select from poetrySlamManagerModel.PoetrySlams { // Selects all fields of the PoetrySlams domain model *, maxVisitorsNumber - freeVisitorSeats as bookedSeats : Integer @title : '{i18n>bookedSeats}', // Relevant for coloring of status in UI to show criticality virtual null as statusCriticality : Integer @title : '{i18n>statusCriticality}', // SAP S/4HANA Cloud projects: visibility of button "Create Project in SAP S/4HANA Cloud", code texts virtual null as customerFullName : String(50) @title: '{i18n>customerFullName}' @odata.Type: 'Edm.String', virtual null as salesOrderURL : String(255) @title: '{i18n>salesOrderURL}' @odata.Type: 'Edm.String', virtual null as isS4HC : Boolean @odata.Type: 'Edm.Boolean', // Projection of remote service data as required by the UI toS4HCSalesOrderPartner : Association to PoetrySlamService.S4HCSalesOrderPartner on toS4HCSalesOrderPartner.salesOrderUUID = $self.salesOrderID }
You can define reuse functions that handle the connection for the different ERP systems in separate files.
- Copy the file srv/lib/destination.js to your project. The reuse functions readDestination, getDestinationURL, and getDestinationDescription are required to read the destination from the subscriber subaccount. This system behavior is achieved by passing the JSON Web Token of the logged-in user to the function to get the destination. The JSON Web Token contains the tenant information. The reuse function getDestinationDescription returns the destination description from the SAP BTP consumer subaccount.
- Create a new folder named connector in the /srv/poetryslam path.
- Create a file with the path /srv/poetryslam/connector/connector.js. This file is reused for different ERP integrations.
- Copy the ERP connection reuse functions in the /srv/poetryslam/connector/connector.js file into your project. It delegates the OData requests and reads the destinations.
Reuse functions specific to SAP S/4HANA Cloud Public Edition are defined in a separate file.
- Create a file with the path /srv/poetryslam/connector/connectorS4HC.js.
- Copy the general and sales order related constants and functions of the connectorS4HC.js file into the newly created file. They are grouped with a specific comment. These functions help to read SAP S/4HANA Cloud Public Edition sales order and business partner data, and to determine the navigation URL to the Sales Order application in SAP S/4HANA Cloud Public Edition of the customer.
In SAP Business Application Studio, enhance the implementation of the SAP CAP services to create and read SAP S/4HANA Cloud Public Edition sales order data using the remote SAP S/4HANA Cloud Public Edition OData service.
-
Delegate requests to the remote OData service.
-
Create a new file named srv/poetryslam/poetrySlamServiceERPImplementation.js in your project.
-
Copy the following code snippet into the newly created file. As a reference, you can have a look at the poetrySlamServiceERPImplementation.js file in the reference application.
'strict' const cds = require('@sap/cds'); // Add connector for project management systems const ConnectorS4HC = require('./connector/connectorS4HC'); module.exports = async (srv) => { const { S4HCSalesOrderPartner } = this.entities; // ------------------------------------------------------------------------------------------------- // Implementation of remote OData services (back-channel integration with SAP S/4HANA Cloud) // ------------------------------------------------------------------------------------------------- // Delegate OData requests to SAP S/4HANA Cloud remote sales order entities srv.on('READ', S4HCSalesOrderPartner, async (req) => { const connector = await ConnectorS4HC.createConnectorInstance(req); return await connector.delegateODataRequests( req, ConnectorS4HC.SALES_ORDER_SERVICE ); }); }
Note: Without delegation, the remote entities return the error code 500 with the message: SQLITE_ERROR: no such table (local testing).
-
-
Enhance the /srv/poetryslam/poetrySlamServiceImplementation.js to call the ERP implementation.
const erpForwardHandler = require('./poetrySlamServiceERPImplementation'); module.exports = class extends cds.ApplicationService { async init() { ... await erpForwardHandler(this); // Forward handler to the ERP systems ... } };
-
In the /srv/poetryslam/poetrySlamServicePoetrySlamsImplementation.js file, the poetry slams entity is enriched with SAP S/4HANA Cloud Public Edition specific data. The connected back-end system is determined and the sales order data is read from the remote system.
- Import the SAP S/4HANA Cloud Public Edition connector.
const ConnectorS4HC = require('./connector/connectorS4HC');
- Add the on-read event handler.
// Expand poetry slams srv.on('READ', [PoetrySlams.drafts, PoetrySlams], async (req, next) => { // Read the PoetrySlams instances let poetrySlams = await next(); // In this method, the data from the database is enriched by external data and calculated fields. // In case none of these enriched fields are requested, it is not required to read data from the external services. // First, check if the requested columns contain any of the enriched columns and return if not const requestedColumns = req.query.SELECT.columns?.map((item) => Array.isArray(item.ref) ? item.ref[0] : item.as ); const enrichedFields = [ 'salesOrderURL', 'isS4HC', 'toS4HCSalesOrderPartner' ]; if ( requestedColumns && !enrichedFields.some((item) => requestedColumns?.includes(item)) ) { return poetrySlams; } // SAP S/4HANA Cloud // Check and read SAP S/4HANA Cloud sales order related data const connectorS4HC = await ConnectorS4HC.createConnectorInstance(req); if (connectorS4HC?.isConnected()) { poetrySlams = await connectorS4HC.readSalesOrder(poetrySlams); } for (const poetrySlam of convertToArray(poetrySlams)) { if (poetrySlam.salesOrderID) { poetrySlam.salesOrderURL = connectorS4HC.determineSalesOrderURL( poetrySlam.salesOrderID ); } // Update the back-end system connected indicator used in UI for controlling visibility of UI elements poetrySlam.isS4HC = connectorS4HC.isConnected(); } // Return remote data return poetrySlams; });
Note: The destinations called s4hc and s4hc-url connect to the ERP system. You create the destinations later on in the SAP BTP consumer subaccount.
-
In the srv folder, edit language-dependent labels in the /srv/i18n/i18n.properties file. Add labels for sales order fields:
# ------------------------------------------------------------------------------------- # Remote Sales Order Elements customerFullName = Sponsoring Businesss Partner Name salesOrderURL = Sales Order URLIn the reference example, the /srv/i18n/i18n_de.properties file with the German texts is available, too. You can use these texts as needed.
-
In SAP Business Application Studio, open the srv/poetryslam/poetrySlamServiceAuthorizations.cds file with the authorization annotations to extend the authorization annotation of the SAP CAP service model by restrictions referring to the remote services.
-
Enhance the authorization model for the S4HCSalesOrderPartner service entity:
// S/4 sales order partner: Managers can read remote sales order partners annotate PoetrySlamService.S4HCSalesOrderPartner with @(restrict: [{ grant: ['READ'], to : 'PoetrySlamFull' }]);
-
Adopt the SAP Fiori elements annotations of the web app in the /app/poetryslams/annotations.cds file.
-
Add project annotations to the PoetrySlams entity.
isS4HC @UI.Hidden;
-
Add a facet named Sales Order Data to display information from the remote service by following the toS4HCSalesOrderPartner association:
-
Add facet:
{ $Type : 'UI.ReferenceFacet', Label : '{i18n>salesOrderData}', ID : 'SalesOrderData', Target : @UI.FieldGroup #SalesOrderData, // Display SalesOrderData only in case a SAP S/4HANA Cloud system is connected and Sales Order ID is filled ![@UI.Hidden]: {$edmJson: {$Or: [ {$Eq: [ {$Path: 'salesOrderID'}, {$Null: null} ]}, {$Not: {$Path: 'isS4HC'}} ]}} },
-
Add a field group named #SalesOrderData with the SAP S/4HANA Cloud Public Edition project-specific fields:
FieldGroup #SalesOrderData : { $Type: 'UI.FieldGroupType', Data : [ { $Type : 'UI.DataFieldWithUrl', Value : salesOrderID, Url : salesOrderURL, ![@Common.FieldControl]: #ReadOnly, ![@UI.Hidden] : {$edmJson: {$Not: {$Path: 'isS4HC'}}} }, { $Type : 'UI.DataField', Label : '{i18n>businessPartnerId}', Value : toS4HCSalesOrderPartner.customer, ![@Common.FieldControl]: #ReadOnly, ![@UI.Hidden] : {$edmJson: {$Not: {$Path: 'isS4HC'}}} }, { $Type : 'UI.DataField', Value : customerFullName, ![@Common.FieldControl]: #ReadOnly, ![@UI.Hidden] : {$edmJson: {$Not: {$Path: 'isS4HC'}}} } ] },
-
-
-
In the web app folder, edit language-dependent labels in the app/poetryslams/i18n/i18n.properties file. Add a label for the facet project data:
salesOrderData = Sponsoring Data # ID texts of CDS is overwritten to more specific UI text salesOrderID = Advertising Sales Order businessPartnerId = Sponsoring Business PartnerIn the reference example, the app/poetryslams/i18n/i18n_de.properties file with the German texts is available, too. ou can use these texts as needed.
Unit tests are available to test this feature:
-
Testing the sales order enhancement:
- Copy the test/srv/api/poetrySlamManagerSalesOrderAPI.test.js file to your project.
-
To run the automated SAP CAP tests:
- Enter the
npm installcommand in a terminal in SAP Business Application Studio. - Enter the
npm run testcommand. All tests are carried out and the result is shown afterwards.
- Enter the
The goal of local tests is to connect to integrated ERP systems without using destinations. Therefore, you need to adjust the code slightly, as shown below:
- To edit the development credentials in the package.json file, replace the placeholders such as
{{S4HC-hostname}},{{test-user}}, and{{test-password}}with the information of your ERP test system.
Note: If you don't have a user, see the next chapter for information on how to provide one.
-
In connectorS4HC.js, method createConnectorInstance, change the value of connector.isConnectedIndicator to true after the connector instance is created:
const connector = new ConnectorS4HC(data); connector.isConnectedIndicator = true;
Note: This change is required as the isConnectedIndicator value is dependent on destination setup in the SAP BTP consumer subaccount. These are not available locally.
-
Open a terminal and start the app with the development profile using the
cds watch --profile developmentrun command. -
Use the test users as listed in the .cdsrc.json file.
-
Test the S4HCSalesOrderPartner service endpoint to SAP S/4HANA Cloud Public Edition. The system returns the respective data from SAP S/4HANA Cloud Public Edition.
Note: If you would like to use a different user, clear the browser cache first.
Note: The changes to the user interface aren't visible unless a sales order ID is set in the poetry slam. This topic is covered in the next chapter.
Update your application in the provider subaccount. For detailed instructions, refer to Deploy Your SAP BTP Multi-Tenant Application.
Note: Make sure that any local changes have been reverted before deployment.
You have now successfully deployed the application to the provider subaccount and you're ready to Configure the Integration Scenario with SAP S/4HANA Cloud Public Edition.