Skip to Content

In this post we will  integrate the SAP S/4HANA Cloud SDK into the Application Programming Model for SAP Cloud Platform-Cloud Foundry applications. If you want to follow this tutorial, we highly recommend checking out the first part of this blog series.

Note: This post is part of a series. For a complete overview visit the SAP S/4HANA Cloud SDK Overview.

 

Goal of this Blogpost

With SAPPHIRE 2018, SAP has introduced the SAP Cloud Application Programming Model as a new methodology to build SAP Cloud Platform – Cloud Foundry  applications simpler and faster.

From the official documentation: “The application programming model for SAP Cloud Platform helps you implement data models, services and UIs to develop your own stand-alone business applications or extend other cloud solutions, like SAP S/4 HANA or SAP SuccessFactors. The programming model includes languages, libraries and APIs and focuses on back-end development”

However, this raises the question how this interacts and integrates with other SAP frameworks that SAP has introduced over the past year such as the SAP S/4HANA Cloud SDK.

Therefore, this blog provides a hands-on guide to create  SAP Cloud Application Programming Model-based applications and leverage the capabilities of other existing frameworks in this context.

In particular, you will learn how to integrate the  SAP S/4HANA Cloud SDK into the SAP Cloud Application Programming Model by using a Create-Read-Update scenario of Business Partners.

Specifically, the following steps will be explained:

  1. Generate a SAP Business Application in the SAP WebIDE
  2. Setup the  SAP S/4HANA Cloud SDK in the Application Programming Model
  3. Define the CDS service model
  4. Add custom handlers to call the SAP S/4HANA System
    1. Query Business Partner
    2. Select  Business Partner byKey
    3. Create  Business Partner
    4. Update Business Partner
  5. Deploy to Cloud Foundry
  6. Calling your application
  7. Troubleshooting
  8. Appendix

Note: This tutorial requires access to an SAP S/4HANA system (see prerequisites below).

It is not necessary to have detailed knowledge of the SAP Cloud Application Programming Model to follow this blogpost. However, this is not a general introduction to this topic, but is focused on the  SAP S/4HANA Cloud SDK integration aspects.

If you like to know more about Application Programming Model specifics, we kindly ask you to take a look at the blogpost from Daniel Hutzel and refer to the official docs.

We are going to use the SAP WebIDE to develop the application. There is a general introduction available on how to develop SAP Cloud Platform Business Applications in the SAP WebIDE and a series demonstrating Java development in the SAP WebIDE Full-Stack.

Prerequisites:

In order to execute this tutorial successfully, we assume a working and reachable system of SAP S/4HANA on-premise or S/4HANA Cloud. Please refer to the prerequisites part of Step 4 – Calling an Odata Service for further information.

Alternatively, use a mock server as described here: https://sap.github.io/cloud-s4-sdk-book/pages/mock-odata.html

There is either a database system or a Database-as-a-service instance required  in your SAP Cloud Platform – Cloud Foundry space.

1. Generate a SAP Business Application in the SAP WebIDE

To use the SAP WebIDE, you need a trial account on SAP Cloud Platform as described in Step 3 – Hello World on SCP Cloud Foundry in the section Setup for CloudFoundry. With your SCP trial account, you also get a trial account in the NEO environment. After logging in to SCP, choose NEO Trial, go to Services and start the service Web IDE Full-Stack (You might want to bookmark it for later use).

Choose File > New > Project from Template from the menu and select SAP Cloud Platform Business Application. Enter an project ID, go to the next screen, enter an application ID (or keep it) and press finish.

This generates the typical SAP Cloud Application Programming Model – application structure as shown below. To see also hidden files, please click the “Eye”- symbol located in the outline of the SAP WebIDE.

I briefly go over the  generated outline and at which place the integration of the SAP S/4HANA Cloud SDK takes place.

1. Data-model.cds

The data-model.cds file defines the data-model of the application, that is the basis for our persistent data model (database schemas/views) in SAP HANA. For more information on CDS, see Core Data and Services (CDS) Language Reference:

This works by  compiling the CDS into the targed database syntax (.hdbcds files for SAP HANA) and then deploy it to the database with help of the SAP HANA XS Advanced HANA Deployment Infrastructure (HDI) – service on Cloud Foundry.

2. The Java Module of this application.

The Java module (called “srv” by default) contains all the source files for the Java application that is providing the extension functionality that we will create in this blogpost.

Hence, this is where we will later use the SAP S/4HANA Cloud SDK.

3. Manifest.yml

Th Cloud Foundry deployment descriptor can be used to individually deploy the Java module of this application to Cloud Foundry. However, we are using the SAP WebIDE for deployment.

More Information on that topic can be found in this previous blogpost.

4. Service.cds

This file contains the service model of the application. In general, it provides the ability to define OData services through CDS syntax.

The service definition can be based on entities defined in the data-model.cds file.

From the service definition, there are OData – EDMX files and a Core Schema Notation file (CSN – a plain JavaScript object-based representation of CDS models, bundling both entity definition and service definitions)  being created, that are automatically picked up at the startup of the application. As a result, a full CRUD OData Service for the entity referenced by the service, is provided out of the box.

This allows easy creation of business applications using persistence from Cloud Foundry.

Important: It is also possible to define entities in the service.cds file that do not automatically create a database persistence. We will do that in step 3. Scenarios that include both persistence in Cloud Foundry and integration to SAP S/4HANA, are subject to another blogpost.

5. Mta.yaml

The Multi-target Application (MTA) deployment descriptor defines the Cloud Foundry prerequisites and dependencies for the deployment of this application.

If you want to more about MTA, please take a look here. Nevertheless, knowledge about MTA is not required to follow this post.

The SAP WebIDE is able to build and deploy the application based on that definition. The mta.yaml already contains the following content (at the time of writing):

  • A database module with the name “db”
  • A  Java module with the name “srv”.
  • A resource with the name “hdi_db” of type com.sap.xs.hdi-container. This defines the already mentioned HDI-container.

Upon deployment, the SAP WebIDE deploys all the modules to Cloud Foundry, creates missing services and bindings (here: between the HDI service and both modules)  as well as environment variables.

These bindings  and environment variables are a Cloud Foundry-specific concept and are used to share information and enable communication between applications and services. In the SAP Cloud Application Programming Model, the Java module requires the HDI resource in order to know the runtime name of the HDI container that subsequently enables the app to access the SAP HANA database on SAP Cloud Platform – Cloud Foundry.

As a sidenote: In this tutorial, we do not require a Cloud Foundry persistence. Nevertheless, it’s worth mentioning because of  the inclusion of the HDI-container in the default template. Also it is useful when building more advanced scenarios with the SAP Cloud Application Programming Model and the  SAP S/4HANA Cloud SDK. If you want to remove the database requirement from the default template, please follow the steps in the appendix.

6. Package.json

The MTA builder tool used by the SAP WebIDE, executes a npm command based on the definitions in the Package.json.

This triggers the compilation of the CDS files that are then bundled within the .mtar archive.

2. Setup the  SAP S/4HANA Cloud SDK in the Application Programming Model

The  pom.xml of the template application  already includes all the necessary dependencies to start using the  SAP S/4HANA Cloud SDK right away.

3. Define the CDS service model

Generally there are several ways to define the CDS service model for our use case. The  SAP S/4HANA Cloud SDK can be used in conjunction with one of the following CDS definitions:

  •  CDS Action

This creates a OData endpoint that can be called via http POST and returns data of arbitrary format.

There are two types of actions: bound to an entity and unbound.

Use a bound action, when you want to provide additional functionality for a certain entity. For instance a calculation for an entity.

Unbound actions are the way to go when you need to create certain functionality that is independent from an entity. For instance: calling your favorite weather forecast API or an action in your SAP S/4HANA system that is exposed via OData .

  • CDS Function

Functions are similar to actions but expose http GET Endpoints and should therefore not modify anything.

  • CDS service based on entity definition

The service model can be based on entities defined in the data-model.cds file.

We pick the this option because for entity definitions, the SAP Cloud Application Programming Model provides handy custom handler capabilities that we are using to make the call to the SAP S/4HANA system.

In order to define the CDS Business Partner entity , add the following code to the db/data-model.cds file.

entity BusinessPartner {
  Key BusinessPartner:String(10);
  LastName:String(40);
  FirstName:String(40);
}

In this example we only create the minimum required properties for the Business Partner.

The type information for the properties is taken from the OData metadata document of the SAP S/4HANA Business Partner service.

You can obtain the document from your SAP S/4HANA System or directly from the SAP API Business Hub.

Create the service model by adding the following code to the srv/my-service.cds file:

using my.app from '../db/data-model';

service CrudService {
	@cds.persistence.skip
	Entity BusinessPartner as projection on app.BusinessPartner;
}

By using the “as projection on” syntax, the service model refers to the entity definition in the data_model.cds file. The annotation @cds.persitence.skip is being introduced in the next section.

Alternative: Service definition via model reuse from the SAP S/4HANA system

In the last step we defined the BusinessPartner database schema manually in the data.model.cds file. This can be cumbersome for larger entities.

Instead, SAP S/4 Hana systems expose definitions of their exposed OData service in Core Schema Notation (CSN), a plain JavaScript object-based representation of CDS models. This model can then be reused in our service model definition in CDS syntax.

Firstly, obtain the CSN file directly through the SAP WebIDE (that is pulling the files from the SAP API Business Hub).

In the project outline, target the “srv” folder -> new -> Data Model from External Service

Select the SAP API Business Hub with the API package SAP S/4HANA Cloud and import the OData Service for Business Partner.

This creates a sub- folder named “external” under “srv” containing two other folders with the EDMX and a CSN (.json ending) file for the Business Partner service.

In this post, we rename the CSN file to API_BUSINESS_PARTNER.json.

Because we want to reference the content of this file in our service model, we need to import it to our service-model.cds file.

Add the following code:

using API_BUSINESS_PARTNER as bp from './external/csn/API_BUSINESS_PARTNER';

Next, create the service model based on the CSN definition in the service.cds file. For your reference, this is whole CDS:

using API_BUSINESS_PARTNER as bp from './external/csn/API_BUSINESS_PARTNER';

service CrudService{

 @cds.persistence.skip
 Entity BusinessPartner as projection on bp.A_BusinessPartnerType{
   BusinessPartner,
   LastName,
   FirstName,
   BusinessPartnerCategory
  };
}

Notice that we, compared to the previous approach, do not use the data-model.cds file anymore.

Also, we only specify the property names of the Business Partner and are not required to define the type (e.g LastName instead of LastName: String(40)). This type information is already obtained from the CSN definition of the BusinessPartnerType within the API_BUSINESS_PARTNER.json file:

3. Add custom handlers to call the SAP S/4HANA System

Our goal is to create the possibility to create, read and update Business Partners from an SAP S/4HANA System through an OData service provided by a Java Application on SAP Cloud Platform-Cloud Foundry.

But before we actually create the Java coding for the handler, there is an important detail in the service model definition to talk about .

By defining the service model based on the data model of the application, the SAP Cloud Application Programming Model provides an automatic way of exposing the persistence layer of an cloud foundry via an OData service. Yet the Business Partner entity is annotated with @cds.persitence.skip.

This tells the SAP Cloud Platform SDK for service development  (that is included in SAP Cloud Application Programming Model applications and is e.g. responsible for OData service provisioning) to not create a database schema for the entity, consequently also skipping automatic OData service generation.

In this scenario without Cloud Foundry persistence, by defining a service model, we only define the return format of our manually created OData service.

This is because we do not persist anything in the cloud in our simple scenario, ergo we do not want to create a schema for our entity definition.

By the same token, we will not deploy the CDS data-model to a database/hdi-container as you would usually do.

Consequently, we have to manually create the OData endpoints. We accomplish that by leveraging the custom handler capabilities/lifecycle hooks available in SAP Cloud Application Programming Model applications.

 

Query Business Partners

The SAP Cloud Platform SDK for service development  provides a lifecycle hook for querying the Business Partner entity set. This allows the retrieval of Business Partners by using standard OData capabilities like sorting, filtering etc.

The methods of the Java Class need the appropriate annotation and signature to be discovered by the framework.

Create an new Java class in srv/your.package/crud with the name BusinessPartnerRead.java. Please use the following code:

public class BusinessPartnerRead {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Read(serviceName = "CrudService", entity = "BusinessPartner")
    public ReadResponse readSingleCustomerByKey(ReadRequest readRequest) {
        logger.info("Received the following keys: {} ", readRequest.getKeys().entrySet().stream().map(x -> x.getKey() + ":" + x.getValue())
                .collect(Collectors.joining(" | ")));

        String id = String.valueOf(readRequest.getKeys().get("BusinessPartner"));

        BusinessPartner partner = new BusinessPartnerReadByKeyCommand (new ErpConfigContext(), id).execute();

        ReadResponse readResponse = ReadResponse.setSuccess().setData(partner).response();

        return readResponse;
    }

    @Query(serviceName = "CrudService", entity = "BusinessPartner")
    public QueryResponse queryCustomers(QueryRequest qryRequest) {

        List<BusinessPartner> businessPartners = new BusinessPartnerReadCommand(new ErpConfigContext(),
                qryRequest.getTopOptionValue(),
                qryRequest.getSkipOptionValue(),
                qryRequest.getSelectProperties(),
                qryRequest.getOrderByProperties())
                .execute();

        QueryResponse queryResponse = QueryResponse.setSuccess().setData(businessPartners).response();
        return queryResponse;
    }
}

The annotation @Query, like all the other annotations being used in the following, refers to a CDS service name and entity. That is how this specific extension is linked with the service model defined in the service.cds file.

The provided QueryRequest object contains all the request information. We retrieve the top, skip, select and order by information and hand it over to a Hystrix command.

Please create the class with the name GetBusinessPartnerCommand.java in \srv\src\main\java\<your.package.>\commands using the following coding:

 

public class BusinessPartnerReadCommand extends ErpCommand<List<BusinessPartner>> {

    private final int top;
    private final int skip;
    private final BusinessPartnerField[] selectedProperties;
    private final List<OrderByExpression> orderByProperties;
    private final ErpConfigContext erpConfigContext;
 
    public BusinessPartnerReadCommand(ErpConfigContext erpConfigContext, int top, int skip, List<String> properties, List<OrderByExpression> orderByProperties) {
        super(BusinessPartnerReadCommand.class, erpConfigContext);
        this.erpConfigContext = erpConfigContext;
        this.top = top;
        this.skip = skip;
        selectedProperties = properties.stream().
                map(property -> new BusinessPartnerField(property))
                .toArray(BusinessPartnerField[]::new);
        this.orderByProperties = orderByProperties;
    }

    @Override
    protected List<BusinessPartner> run() {

        BusinessPartnerFluentHelper service = new DefaultBusinessPartnerService()
                .getAllBusinessPartner();

        orderByProperties.stream().forEach(expression -> service.orderBy(new BusinessPartnerField<>(expression.getOrderByProperty()), expression.isDescending() ? Order.DESC : Order.ASC));

        service.select(selectedProperties);

        if (skip > 0)
            service.skip(skip);

        if (top > 0)
            service.top(top);

        try {
            return service.execute(erpConfigContext);

        } catch (final ODataException e) {
            throw new HystrixBadRequestException(e.getMessage(), e);
        }
    }
}

It contains the coding to call the SAP S/4HANA system using the SAP S/4HANA Cloud SDK. For a more detailed explanation, look at this previously published blogpost: https://blogs.sap.com/2017/06/23/step-5-resilience-with-hystrix/

In the step Number 5 Calling your application – you will see how to make a request against this created endpoint.

 

Select BusinessPartners byKey

The @Read annotation over the readSingleBusinessPartnerbyKey method in the BusinessPartnerRead.java class creates an OData endpoint to retrieve an entity by key.

We first read the key of the Business Partner entity from the provided ReadRequest object. Then we use it to call the Hystrix command GetBusinessPartnerCommandByKey executing the SAP S/4HANA Cloud SDK.

Create the needed Hystrix command in srv/your.package/commands with the name GetBusinessPartnerCommandByKey.java:

public class BusinessPartnerReadByKeyCommand extends ErpCommand<BusinessPartner> {

    private final ErpConfigContext erpConfigContext;
    private String businessPartner;

    public BusinessPartnerReadByKeyCommand(ErpConfigContext erpConfigContext, String businessPartner) {
        super(BusinessPartnerReadByKeyCommand.class, erpConfigContext);
        this.businessPartner = businessPartner;
        this.erpConfigContext = erpConfigContext;
    }

    @Override
    protected BusinessPartner run() {

        BusinessPartnerByKeyFluentHelper service = new DefaultBusinessPartnerService()
                .getBusinessPartnerByKey(businessPartner);

        try {
            return service.execute(erpConfigContext);
        } catch (final ODataException e) {
            throw new HystrixBadRequestException(e.getMessage(), e);
        }
    }
}

The created OData endpoint expects a key identifier as parameter addressing a single resource/entity.

In our case we expect the Business Partner Id to retrieve a single Business Partner from the SAP S/4HANA system.

 

Create BusinessPartners

Please add the following dependency to the srv/pom.xml file. We use this library to map the generic create request of the custom handler to the SAP S/4HANA Cloud SDK Virtual Data Model (VDM) representation of a Business Partner.

<dependency>
   <groupId>org.modelmapper</groupId>
   <artifactId>modelmapper</artifactId>
   <version>2.1.1</version>
</dependency>

Analogously create an new Java class in srv/your.package/crud with the name BusinessPartnerCreate.java and code:

public class BusinessPartnerCreate {

    private static final Logger logger = CloudLoggerFactory.getLogger("BusinessPartnerCreate");
    private static final ModelMapper mapperToBusinessPartner = new ModelMapper();

    @Create(serviceName = "CrudService", entity = "BusinessPartner")
    public CreateResponse createBusinessPartner(CreateRequest createRequest) {

        if (createRequest.getMapData().isEmpty() || createRequest.getMapData() == null)
            throw new BadRequestException();

        BusinessPartner entity = mapperToBusinessPartner.map(createRequest.getMapData(), BusinessPartner.class);

        logger.debug("Received the following BusinessPartner for create Request: {} ", entity.getBusinessPartner());

        BusinessPartner response;
        try {
            response = new CreateBusinessPartnerCommand(new ErpConfigContext(),
                    new DefaultBusinessPartnerService(),
                    entity
            ).execute();
        } catch (HystrixBadRequestException e) {
            logger.error("S/4 Error", e);
            return CreateResponse.setError(new ErrorResponseImpl(400, null, e.getMessage(), e.getCause(), null));
        }

        CreateResponse readResponse = CreateResponse.setSuccess().setData(response).response();

        return readResponse;
    }
}
}

The necessary annotation to create a POST endpoint on the Business Partner entity, is @Create.

From the provided object CreateRequest, we can retrieve the body of the HTTP POST call in form of an EntityData object. In our case this would contain the data of a Business Partner to be created. We map this generic entity object to a Business Partner.

Next, we are executing the Hystrix command and handing over the Business Partner. Create the command in srv/your.package/commands with the name CreateBusinessPartnerCommand.java:

public class CreateBusinessPartnerCommand extends ErpCommand<BusinessPartner> {

    private final ErpConfigContext erpConfigContext;
    private BusinessPartnerService businessPartnerService;
    private BusinessPartner businessPartner;

    public CreateBusinessPartnerCommand(ErpConfigContext erpConfigContext, BusinessPartnerService businessPartnerService, BusinessPartner entity) {
        super(CreateBusinessPartnerCommand.class, erpConfigContext);
        this.erpConfigContext = erpConfigContext;
        this.businessPartnerService = businessPartnerService;
        this.businessPartner = entity;
    }


    @Override
    protected BusinessPartner run() {
        try {
            return businessPartnerService
                            .createBusinessPartner(businessPartner)
                            .execute(erpConfigContext);
        } catch (final ODataException e) {
            throw new HystrixBadRequestException(e.getMessage(), e);
        }
    }
}

In the Hystrix Command we then use the VDM to create the Business Partner in the SAP S/4HANA System.

 

Update BusinessPartners

Create an new Java class in srv/your.package/crud with the name BusinessPartnerUpdate.java. Use this code:

public class BusinessPartnerUpdate {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private static final ModelMapper mapperToBusinessPartner = new ModelMapper();


    @Update(serviceName = "CrudService", entity = "BusinessPartner")
    public UpdateResponse updateBusinessPartner(UpdateRequest updateRequest) {

        if (updateRequest.getMapData().isEmpty() || updateRequest.getMapData() == null)
            throw new BadRequestException();
        
        logger.info("Received the following map data for update Request: {} ", updateRequest.getMapData().entrySet().stream().map(x -> x.getKey() + ":" + x.getValue()).collect(Collectors.joining(" | ")));
        logger.info("Received the following keys for update Request: {} ", updateRequest.getKeys().entrySet().stream().map(x -> x.getKey() + ":" + x.getValue()).collect(Collectors.joining(" | ")));
        
        BusinessPartner entity = mapperToBusinessPartner.map(updateRequest.getMapData(), BusinessPartner.class);

        ODataUpdateResult updateResult;
        try {
            updateResult = new UpdateBusinessPartnerCommand(new ErpConfigContext(),
                    new DefaultBusinessPartnerService(),
                    entity
            ).execute();
        }
        catch (HystrixBadRequestException e){
            return UpdateResponse.setError(new ErrorResponseImpl(500, null, e.getMessage(), e.getCause(), null ));
        }

        UpdateResponse response;

        int httpStatusCode = updateResult.getHttpStatusCode();
        if (httpStatusCode < 200 || httpStatusCode >= 300)
            response = UpdateResponse.setError(new ErrorResponseImpl(httpStatusCode, null, updateResult.toString(), null, null));
        else
            response = UpdateResponse.setSuccess().response();

        return response;
    }
}

The @Update annotation creates a PUT endpoint on the Business Partner entity. Similar to the @Create annotation, we get the EntityData, map it to a Business Partner and hand it over to a Hystrix command to perform the actual update operation.

Create the command in srv/your.package/commands with the name UpdateBusinessPartnerCommand.java:

public class UpdateBusinessPartnerCommand extends ErpCommand<ODataUpdateResult> {

    private final ErpConfigContext erpConfigContext;
    private BusinessPartnerService businessPartnerService;
    private BusinessPartner businessPartner;

    public UpdateBusinessPartnerCommand(ErpConfigContext erpConfigContext, BusinessPartnerService businessPartnerService, BusinessPartner entity) {
        super(UpdateBusinessPartnerCommand.class, erpConfigContext);
        this.erpConfigContext = erpConfigContext;
        this.businessPartnerService = businessPartnerService;
        this.businessPartner = entity;
    }


    @Override
    protected ODataUpdateResult run() {
        try {
            return businessPartnerService
                    .updateBusinessPartner(businessPartner)
                    .execute(erpConfigContext);
        } catch (final ODataException e) {
            throw new HystrixBadRequestException(e.getMessage(), e);
        }
    }
}

Again, we execute the update using the SAP S/4HANA Cloud SDK.

5. Deploy to Cloud Foundry

Before deployment to Cloud Foundry, please make sure to properly set up the connection to an S/4HANA System. Please refer to this previous blogpost.

With all the necessary coding and configuration in place, deploy the application to Cloud Foundry. First, run the integrated MTA builder to create a deployable MTA archive from the project. To do so, press “build” at the root folder of the project.

 

Generally, the MTA builder builds every module and packages everything into the final .mtar file. For the Java module, a maven goal is being executed in the Java directory to generate a  .war file.        For the second module, an npm build step is run in the db folder.

The npm step instructs the CDS compiler to generate the necessary files out of CDS syntax. Also note the addition of dependencies in the db/node_modules folder, the generated .hbdcds artifacts and the created xml/edmx file.

The final output of the command is a cloud-platform specific .mtar file located in the  MTA_Archives directory, bundling all the build modules and generated files.

The next step is to deploy that .mtar to Cloud Foundry. Right click on the file and select Deploy to Cloud Foundry.

The MTA deployer then sets up everything on cloud foundry as already mentioned in the beginning of this blogpost.

In case you stumble upon errors, please refer to the troubleshooting section in the end of this post address the issue in the comment section.

6. Calling your application

Now that your OData service is running on cloud foundry, you can call the created OData endpoints.

Query Business Partners

The @Query annotated method exposes an OData GET Endpoint that can be called with:

https://<baseurl>/odata/v2/CrudService/BusinessPartner

We can query the Business Partners with standard OData parameters like top, skip & orderby.

The response is a list of Business Partners matching the query.

Get Business Partner by Key

The @Read annotated method exposes an  OData GET Endpoint  that can be called with:

https://<baseurl>:443/odata/v2/CrudService/BusinessPartner(‘<buPaKey>’)

The response is single BusinessPartner matching the given key.

Create Business Partner

The @Create annotated method exposes an  OData POST Endpoint  that can be used to create a new BusinessPartner in the S/4 system.

Call the following Url

https://<baseurl>/odata/v2/CrudService/BusinessPartner

…with the body containing the details of your new Business Partner like:

{
   "BusinessPartner": "MYBUPA",
   "BusinessPartnerCategory": "1",
   "LastName": "1708HFC6",
   "FirstName": "Test"
 }

In the domain of Business Partners, the shown body is the minimum information needed.

The response is the newly created BusinessPartner.

Update Business Partner

The @Update annotated method exposes an OData PUT Endpoint  that can be used to update an existing BusinessPartner in the S/4 system.

Call the Url

https://<baseurl>:443/odata/v2/CrudService/BusinessPartner(‘<buPaKey>’)

… with the key of the Business Partner also in the body along with the new field values.

{
   "BusinessPartner": "MYBUPA",
   "FirstName": "NewFirstName",
   "LastName": "NewLastName"
 }

 

Troubleshooting

A lot of errors are already visible during startup of the application.  So please use the “cf logs <appName> –recent” command to make sure the app does not throw errors on startup.

1) Problem: “Operation not supported”  when accessing the OData Endpoints

Possible Solution: In case the application does not pick up the annotations, thus does not generate OData endpoints, please  add your custom package path to the pom.xml. This directs the application to the correct packages containing the annotations. The newest template already includes this property definition.

2) Problem: Error when making first MTA Deployment: “Cannot provide hdi-service / Database System missing”

Possible Solution: Please make sure to have a database system available and enough quota so that the MTA Deployer can provide the HDI-service.

Otherwise follow the steps in the Appendix on how to remove the persistence requirements from the default SAP Cloud Platform Business Application template.

3) Problem:  Org.slf4j classNot Found error during application deployment /servlet startup of the Java application

Possible Solution:  This ClassNotFound error typically indicates conflicting maven dependencies in your project. Remove all additional maven dependencies to the S/4HANA Cloud SDK in the pom.xml of your project. It is already included in the parent-pom.xml of the default SAP Cloud Platform Business Application template.

4) Problem: Database Connection not working after startup. DriverManager error complaining about null url

  • Make sure that the application is bound to the HDI service as shown below in the SAP Cloud Platform – Cloud Foundry Service Bindings Overview:

 

  • When being deployed from from local machine (not WebIDE) make sure that the manifest.yml is correctly setup to create all the service bindings and environment variables as defined in the mta.yml. You can check the difference by deploying first with the MTA Deployer and after using the manifest.yml. Compare the service bindings and environment variables after each deployment method.
  • Make sure the environment variable “hdi-container-name” for the HDI Container is being set.  This happens in the mta.yaml and the manifest.yaml as shown below:

    In question, replace all the environment variables referenced in the Java coding, with the hard-coded name of the hdi-service.

    To do that, adjust all the three files shown below in the srv/src/main/webapp folder

                                                      For example in the resource.xml 

Appendix

1) Remove the persistence from the default SAP Cloud Platform Business Application template

Adjust your mta.yml in the following way:

  • Remove the “db” module
  • Remove the resource of type com.sap.xs.hdi-container
  • Remove the requiring of the HDI resource from the “srv” module including the properties from the requiring resource
  • Add the xsuaa and destination service as required to the “srv” module”
    properties:
      TARGET_RUNTIME: tomee 
   requires:
      - name: my-xsuaa
      - name: my-destination
         
resources:
  - name: my-destination
    type: destination
    description: Destination Service
  - name: my-xsuaa
    type: com.sap.xs.uaa
To report this post you need to login first.

9 Comments

You must be Logged on to comment or reply to a post.

  1. Simon Kemp

    Hi Daniel

    Thanks for sharing this blog post, it contains a lot of great information. I was wondering if it’s also possible to deploy this type of application on the SCP Neo environment or is the new APM and Full Stack WebIDE targeting Cloud Foundry only?

    Thanks,
    Simon

    (0) 
  2. Tri Minh Le

    Hello Daniel,

    Thanks for a great blog.

    I have questions regarding section 6.

    1. So far APM is based on SAP Cloud Platform SDK for service development. I would like to know if this can handle filter option since I check the document https://help.sap.com/viewer/8be3667edfd34d71a80afe9f7f2b42a9/Cloud/en-US/639ab6d75b664714ae7fd0c7976696c1.html, $filter is not applicable. For example:  https://<baseurl>/odata/v2/CrudService/BusinessPartner?$filter=BusinessPartnerCategory eq ‘<some_value>’
    2. In case if it doesn’t support filter, how can we workaround?
    3. I also tried $orderby, but it seems not working.

    Regards,

    Tri

    (0) 
    1. Daniel Foehr
      Post author

      Hi,

      1) UPDATE: Currently filtering is not available in the SAP Cloud Platform SDK but on the roadmap.

      2)  Here is a workaround using custom Query options to call the S/4HANA Cloud SDK  in a custom handler. Make a request like …. BusinessPartner?$top=10&$skip=1&BusinessPartner eq 1&BusinessPartnerCategory < 1

      However this is very “hacky” and I cannot recommend this approach.

      3) Currently taking a look into the $orderby option. Did you check that this works on your OData service directly?

      Best Regards,

      Daniel

      (1) 
      1. Tri Minh Le

        Hi Daniel,

        Thanks for your workaround.

        And I’ve tested against the oData service directly with $orderby: /sap/opu/odata/sap/API_BUSINESS_PARTNER

        It’s working perfectly.

        One more thing is $skip & $top do not work when their values are equal.

        Regards,

        Tri

        (0) 
  3. Tri Minh Le

    Hi Daniel,

    When the template generates, in POM file

    <parent>
            <groupId>com.sap.cloud.servicesdk.prov</groupId>
    	<artifactId>projects-parent-odatav2</artifactId>
    	<version>1.17.1</version>
    </parent>

    Does this mean it is using odata v2?

    Can you please show me how to switch from odata v2 to v4?

    Regards,

    Tri

    (0) 
    1. Daniel Foehr
      Post author

      Hi,

      Currently the  SAP Cloud Platform SDK for service development only supports OData v2. However they might add V4 support in the future. Because I am not part of the responsible team, I cannot tell you when & if it is coming for sure.

      BR,

      Daniel

      (0) 
  4. Scott Stefanich

    Daniel, you mention, ‘Scenarios that include both persistence in Cloud Foundry and integration to SAP S/4HANA, are subject to another blogpost.’

    Do you have any recommendations for the following scenario?

    1. The data model has two entities, BusinessPartner and LocalStructure. BusinessPartner has an association with LocalStructure (1:1).

    2. Business Partners are persisted in S/4HANA Cloud. LocalStructure data is persisted in a SCP CF HDI container.

    3. The service uses the S/4HANA Cloud SDK to read partners from S/4HANA Cloud (API_BUSINESS_PARTNER). The service then reads LocalStructure data from the HDI container for the BusinessPartner entities.

    4. Navigation from BusinessPartner to LocalStructure includes an OData $expand.

     

    Thank you for the excellent blog,

    Scott

    (0) 
    1. Henning Heitkoetter

      Hello Scott,

      in the following, I assume you explicitly decided to store the local structure on Cloud Platform and not as a custom business object in S/4HANA.

      I believe you do not have access to the expand query option value in the custom handler of the application programming model. However, you should be able to model a business partner entity in your CDS model that includes the local structure properties, or reference the local structure – this being a 1:1 relationship. In the most simple case, just fill the local structure fields whenever a business partner is being read, no matter if there is an expand query option.

      In case you are looking for a more sophisticated solution, I would like to point you to the experts for the application programming model at answers.sap.com.

      Best regards,

      Henning

      (0) 

Leave a Reply