how to call sap cloud for customer soap api for account

20
How to consume an account web service via PHP 1 How-To Guide Document Version: 1.0 2014.12.05 How to Call SAP Cloud for Customer SOAP API for Account Creation and Query from an External PHP Application Copyright

Upload: others

Post on 21-Nov-2021

8 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 1

How-To Guide Document Version: 1.0 2014.12.05

How to Call SAP Cloud for Customer SOAP API for

Account Creation and Query from an External PHP

Application

Copyright

Page 2: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 2

Content

1 Introduction ..................................................................................................................................................... 3

1.1 Business Scenario ........................................................................................................................................ 3

1.2 Prerequisites ................................................................................................................................................. 3

2 Download WSDL files from C4C ................................................................................................................... 4

2.1 Edit the WSDL files ....................................................................................................................................... 5

3 PHP consumption application structure ...................................................................................................... 6

4 Create application index file .......................................................................................................................... 7

5 Extend PHP class SoapClient ..................................................................................................................... 10

6 Query C4C from PHP using Account ID ..................................................................................................... 11

6.1 Execute query in C4C system .................................................................................................................... 11

6.2 Display query results .................................................................................................................................. 12

6.3 Query an existing account from C4C ......................................................................................................... 14

7 Create an Account ........................................................................................................................................ 15

7.1 Create Account in the C4C system ............................................................................................................ 15

7.2 Display account creation return .................................................................................................................. 17

7.3 Create an account in C4C using web service ............................................................................................ 18

Page 3: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 3

1 Introduction 1.1 Business Scenario

Customers or Partners who use SAP Cloud for Customer solution tend to already have another running system, which needs to export its data to SAP Cloud for Customer system or even display the data stored inside SAP’s solution. This is the reason why a web service integration between SAP Cloud for Customer and other systems is important.

1.2 Prerequisites

SAP Cloud for Customer Initial setup and configuration was already performed in tenant as it is mentioned in the SAP Cloud for Customer Administrator Guide. A business user with Customer work center assigned is required to execute the web service’s requests afterwards. XAMPP (or another PHP Development Environment) PHP applications need an environment to be executed, such as XAMPP or LAMP. Notepad++ (or another text editor) Coding and text edition are required for this guide.

Page 4: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 4

2 Download WSDL files from C4C In order to access the web service, the WSDL file must be downloaded from the Cloud for Customer system. Since this application is going to use both query and creation services, there are two different files that must be downloaded. The WSDL files are located in the path Application and user management > Input and output Management > Service Explorer. Download Maintain Accounts WSDL In the Service Explorer screen, search for “*Maintain Accounts*” in the Find field. Select accordingly and download the WSDL file:

Save the file as “ManageAccounts.wsdl”. Download Find Accounts WSDL Repeat the same steps and search for “*Find Accounts*”. Select accordingly and download the WSDL file:

Save the file as “QueryAccounts.wsdl”.

Page 5: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 5

2.1 Edit the WSDL files

The files downloaded from Cloud for Customer system must be edited before being used, due to security polices issues. Open the files with Notepad++ and search for “UsingPolicy wsdl:required”. The standard value for this field is true, but it must be changed to false:

This change is required in both WSDL files.

Page 6: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 6

3 PHP consumption application structure

The web service consumption is going to be built on PHP language. The application will have the following structure:

The css folder will have the bootstrap library, and the js folder will have jQuery library, validation files and a file containing country and state info, which will be used later by the app. As this is not the focus of the guide, there will just this overview about it. The wsdl folder is where are located the WSDL files which were downloaded and edited in the previous step.

Page 7: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 7

4 Create application index file The index.html file is the home page of the application. It contains two different forms: one for account query and one for account creation. The focus of this guide is not the html part as well, so follows a quick overview about the forms: Query Account form This form will have only the Account ID field, which is the only necessary field for query an account in C4C. The action of the form must send the parameters via POST to the file “search_account.php”. Create Account form This form will have the following fields: • Account Name

• E-mail • Country • State • City • Street • Number • Postal Code • Phone Number • Contact Name • Contact E-mail

The action of this form must send the parameters via POST to the file “new_account.php”. C4C Authentication fields Have in mind that every web service call to a Cloud for Customer system must have a C4C user and password, which give the permission for the request to be completed. In queries and creations, the user will have to enter a valid authentication. For this, the index will have username and password fields, and a checkbox indicating if his connection uses prox. This indicator is required due to a problem with PHP, where it is not able to find the system in proxy-based connections. This issue will be explained in details in section 3.2. The index screen must have the fields as follows:

Page 8: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 8

Page 9: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 9

Page 10: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 10

5 Extend PHP class SoapClient PHP’s default class SoapClient has an issue with proxy-based connections that prevents the requests from reaching the C4C system. As many of SAP’s customers and partners use proxy in their connections, it is necessary to resolve this problem. The workaround for this is defining a login details array, where the proxy host and proxy port are defined, when necessary. Additionally, a new parameter must be added to the location of the system: the sap-language has to be defined as “EN”. At the end, the file must be as follows: <?php

global $loginDetails;

// variable with proxy information, which is completed when necessary

$loginDetails = array(

'proxy_host' => '',

'proxy_port' => '',

'verify_peer' => true,

'allow_self_signed' => true,

'connection_timeout' => 300,

'exceptions' => true,

'login' => '',

'password' => ''

);

class ByDSoapClient extends SoapClient

{

private $defaultLocation = null;

function __construct($wsdl, $location, $options)

{

global $loginDetails;

$this->defaultLocation = $location;

use_soap_error_handler(true);

parent::__construct($wsdl, array_merge($loginDetails, $options));

}

function __doRequest($soapRequest, $location, $action, $version, $one_way = NULL)

{

$domDocument = new DOMDocument("1.0");

$location = $this->defaultLocation;

// Read the language from the configuration file

$language = 'EN';

if (!empty($language)) {

$location = $location . '?sap-language=' . $language;

}

//Consuming the web service

$soapResponse = parent::__doRequest($soapRequest, $location, $action, $version);

if (empty($soapResponse))

{

throw new Exception($this->__soap_fault->faultcode . ": Cannot connect to

host: $location. Reason:" . $this->__soap_fault->getMessage());

}

return $soapResponse;

}

}

?>

This class is going to be instantiated afterwards, in the web service consumption on both queries and creations.

Page 11: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 11

6 Query C4C from PHP using Account ID

This section describes using the PHP application to query C4C. The query section of the application consists in one PHP file responsible for displaying the return on the screen and one PHP class responsible for querying the account on the C4C system.

6.1 Execute query in C4C system

The query is executed in the class QueryAccounts.php, which performs three main steps to query accounts on the C4C system. First, it generates the XML that is going to be used later on the web service request. This XML is a predefined string, with all the parameters required by C4C system to query an account, concatenated with the account ID received via parameter from the form. After that, the XML string is converted into a SOAP variable that will be passed as a parameter later on the query. The final step is execute the query. The SOAP client created refers to the extended class (created in step 3.2) which receives the WSDL location, the web service location and the authentication data as a parameter. The authentication data may or may not have proxy information, depending on the user’s connection. The complete class must look like this: <?php

require_once 'ByDSoapClient.php';

class QueryAccounts

{

public function execute($accountId, $username, $password, $proxy_enabled) {

$xml = $this->generateXml($accountId);

$soapVar = $this->generateSoapVar($xml);

$result = $this->executeQuery($soapVar, $username, $password, $proxy_enabled);

return $result;

}

public function executeQuery($soapVar, $username, $password, $proxy_enabled) {

$auth = null;

if ($proxy_enabled == true) {

$auth = array(

'proxy_host' => 'proxy',

'proxy_port' => '8080',

'login' => $username,

'password' => $password

);

} else {

$auth = array(

'proxy_host' => '',

'proxy_port' => '',

'login' => $username,

'password' => $password

);

}

$wsdl = 'wsdl/QueryAccounts.wsdl';

$location =

'https://<YOUR_SYSTEM_TENANT_HERE>/sap/bc/srt/scs/sap/querycustomerin1?sap-

vhost=<YOUR_SYSTEM_TENANT_HERE>';

$soapClient = new ByDSoapClient($wsdl, $location, $auth);

try {

$result = $soapClient->FindByElements(

new SoapParam($soapVar, 'CustomerSelectionByElements')

);

return $result;

} catch(Exception $e) {

Page 12: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 12

$message = $e->getMessage();

}

}

public function generateSoapVar($xml) {

try {

$soapVar = new SoapVar($xml, XSD_ANYXML, null, null, null);

return $soapVar;

} catch(Exception $e) {

$message = $e->getMessage();

}

}

public function generateXml($accountId) {

$xml = '<ns1:CustomerByElementsQuery_sync>

<CustomerSelectionByElements>

<SelectionByInternalID>

<InclusionExclusionCode>I</InclusionExclusionCode>

<IntervalBoundaryTypeCode>1</IntervalBoundaryTypeCode>

<LowerBoundaryInternalID>' . $accountId .'</LowerBoundaryInternalID>

<UpperBoundaryInternalID></UpperBoundaryInternalID>

</SelectionByInternalID>

</CustomerSelectionByElements>

<ProcessingConditions>

<QueryHitsUnlimitedIndicator>true</QueryHitsUnlimitedIndicator>

</ProcessingConditions>

</ns1:CustomerByElementsQuery_sync>';

return $xml;

}

}

As seen, the XML does not need the <soapenv:Envelope>, <soapenv:Header> and <soapenv:Body> tags, since they are provided automatically when the XML is converted to a SOAP variable. In addition, the InclusionExclusionCode is hardcoded to I, which means the selection must return an account with an ID equal to the ID given. The ProcessingConditions determine that the query can return an unlimited number of registers, but our application will only be able to handle the first one. Additionally, since it searches by ID, there must not be duplicated registers on the system. The generateSoapVar function has the only purpose of converting the string into an SOAP parameter, passing the required parameters to the standard PHP class SoapVar. The function executeQuery is the one that runs the web service. The authentication has a validation for the proxy, and the SOAP client is created using the extended class created on step 3.2. The SOAP client created has all the web service’s operations, and the one used by the application’s query is “FindByElements”. This operation requires a SOAP parameter, which has the name “CustomerSelectionByElements”. All the errors that might happen (such as no account found for that ID or authentication error) are treated in the PHP file that displays the return of the query.

6.2 Display query results

This is the file to which the action the form points, meaning that it receives all the parameters from POST, passes it to the QueryAccounts class (created in step 6.1) and treats the result to display it accordingly on the screen. After receiving the parameters via POST, an instance of QueryAccounts class is created and the query is executed passing the required parameters. After that, the return from the query is treated as follows:

If the result is not set, there was an authentication error with the query preventing it from being executed and an error is shown.

The response from C4C has a field where the number of accounts found by the query is returned. It is located in ProcessingConditions > ReturnedQueryHitsNumberValue. If this number is equal to zero, then an error message is shown.

If none of this errors occur, the results must be displayed.

The file must look like as follows:

Page 13: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 13

<?php

require_once 'QueryAccounts.php';

$accountId = $_POST['accountId'];

$username = $_POST['username'];

$password = $_POST['password'];

$proxy_enabled = (isset($_POST['proxy']) ? true : false);

$query = new QueryAccounts();

$result = $query->execute($accountId, $username, $password, $proxy_enabled);

// Verify if the query returned any account

if (isset($result)) {

$num_registers = $result->ProcessingConditions->ReturnedQueryHitsNumberValue;

// if the query did not find any account

if ($num_registers == 0) {

displayErrorNotFound($accountId);

}

// if the query find an account

else {

displayQueryResults($result);

}

}

// if the result is not set, the user and password given are incorrect

else {

displayErrorAuthentication();

}

function displayQueryResults($info) {

$account_id = (isset($info->Customer->InternalID) ? $info->Customer->InternalID : " ");

$organization = (isset($info->Customer->Organisation->FirstLineName) ? $info->Customer-

>Organisation->FirstLineName : " ");

$address = (isset($info->Customer->AddressInformation->Address->FormattedAddress-

>FormattedPostalAddress) ? $info->Customer->AddressInformation->Address->FormattedAddress-

>FormattedPostalAddress : " ");

$address1 = (isset($address->FirstLineDescription) ? $address->FirstLineDescription : " ");

$address2 = (isset($address->SecondLineDescription) ? $address->SecondLineDescription : "

");

$address3 = (isset($address->ThirdLineDescription) ? $address->ThirdLineDescription : " ");

$phone = (isset($info->Customer->AddressInformation->Address->Telephone-

>FormattedNumberDescription) ? $info->Customer->AddressInformation->Address->Telephone-

>FormattedNumberDescription : " ");

$email = (isset($info->Customer->AddressInformation->Address->EmailURI->_) ? $info-

>Customer->AddressInformation->Address->EmailURI->_ : " ");

$contact_name = (isset($info->Customer->ContactPerson->GivenName) ? $info->Customer-

>ContactPerson->GivenName : " ");

$contact_name = (isset($info->Customer->ContactPerson->FamilyName) ? $contact_name . " " .

$info->Customer->ContactPerson->FamilyName : $contact_name);

$contact_email = (isset($info->Customer->ContactPerson->WorkplaceEmailURI->_) ? $info-

>Customer->ContactPerson->WorkplaceEmailURI->_ : " ");

echo "<h3>Account " . $account_id . "</h3>

<dl class='dl-horizontal'>

<dt>Organization</dt>

<dd>" . $organization . "</dd>

<dt>Address</dt>

<dd>" . $address1 . " <br> " . $address2 ." <br> " . $address3 . "</dd>

<dt>Phone</dt>

<dd>" . $phone . "</dd>

<dt>E-Mail</dt>

<dd>" . $email . "</dd>

<dt>Primary Contact</dt>

<dd>" . $contact_name . "</dd>

<dt>Contact E-Mail</dt>

<dd>" . $contact_email . "</dd>

</dl>";

}

function displayErrorNotFound($id) {

echo 'The Account ID ' . $id . ' was not found on the Cloud for Customer System. Try again

with another Account ID.';

}

function displayErrorAuthentication() {

echo 'Authentication error! Check username, password and proxy settings then try again.';

}

?>

Page 14: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 14

As seen, the only work done by this PHP file is receive the parameters from form, pass them to QueryAccounts class, check the response and display the results by just accessing its relative path in the response itself.

6.3 Query an existing account from C4C

To perform a quick test in the application, log into the Cloud for Customer system and get an account ID. For test purposes, the account ID chosen is 10009, which is a relevant ID in the system being used. This is the account on the C4C system:

After executing the query by ID number 10009 on the PHP application, besides inserting correct C4C login information, the result has to bring exactly the same data show in C4C:

Page 15: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 15

7 Create an Account This section describes how to create an account in C4C from the PHP application. The create section of the application consists in one PHP file responsible for displaying a message whether the account was successfully created showing its ID and another PHP file responsible for creating the account on the C4C system.

7.1 Create Account in the C4C system

The account is created in the CreateAccount class, which receives all the fields by parameter, prepare a XML with the values in it and execute the web service. Actually the steps performed by the CreateAccount class are identical to the ones performed by the QueryAccounts class (created in step 6.1), but of course performing a different action. The difference between the two classes is the WSDL used, the web service location and the XML passed as parameter. First the XML is generated based on the parameters received, returning a string which is then converted to a SOAP variable. The final step is create the account. A SOAP client is created using the extended class (created in step 5) which receives the WSDL location, the web service location and the authentication data as a parameter. The authentication data may or may not have proxy information, depending on the user’s connection. The complete class must look like this: <?php

require_once 'ByDSoapClient.php';

class CreateAccount

{

public function execute($username, $password, $accountName, $email, $countryCode,

$countryName, $stateCode, $stateName, $postalCode, $street, $number, $phoneNumber, $city,

$givenName, $familyName, $contactEmail, $proxy_enabled) {

$xml = $this->generateXml($accountName, $email, $countryCode, $countryName,

$stateCode, $stateName, $postalCode, $street, $number, $phoneNumber, $city,

$givenName, $familyName, $contactEmail);

$soapVar = $this->generateSoapVar($xml);

$result = $this->create($soapVar, $username, $password, $proxy_enabled);

return $result;

}

public function create($soapVar, $username, $password, $proxy_enabled) {

$auth = null;

if ($proxy_enabled == true) {

$auth = array(

'proxy_host' => 'proxy',

'proxy_port' => '8080',

'login' => $username,

'password' => $password

);

} else {

$auth = array(

'proxy_host' => '',

'proxy_port' => '',

'login' => $username,

'password' => $password

);

}

$wsdl = 'wsdl/ManageAccounts.wsdl';

$location =

'https://<YOUR_SYSTEM_TENANT_HERE>/sap/bc/srt/scs/sap/managecustomerin1?sap-

vhost=<YOUR_SYSTEM_TENANT_HERE>';

$soapClient = new ByDSoapClient($wsdl, $location, $auth);

try {

$result = $soapClient->MaintainBundle_V1(

Page 16: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 16

new SoapParam($soapVar, 'CustomerBundleMaintainRequestMessage')

);

return $result;

} catch(Exception $e) {

$message = $e->getMessage();

}

}

public function generateSoapVar($xml) {

try {

$soapVar = new SoapVar($xml, XSD_ANYXML, null, null, null);

return $soapVar;

} catch(Exception $e) {

$message = $e->getMessage();

}

}

public function generateXml($accountName, $email, $countryCode, $countryName, $stateCode,

$stateName, $postalCode, $street, $number, $phoneNumber, $city, $givenName, $familyName,

$contactEmail) {

$xml = '

<ns1:CustomerBundleMaintainRequest_sync_V1>

<Customer actionCode="01">

<CategoryCode>2</CategoryCode>

<CustomerIndicator>true</CustomerIndicator>

<Organisation>

<FirstLineName>'. $accountName .'</FirstLineName>

<SecondLineName></SecondLineName>

<ThirdLineName></ThirdLineName>

<FourthLineName></FourthLineName>

</Organisation>

<AddressInformation actionCode="01">

<Address actionCode="01" telephoneListCompleteTransmissionIndicator="true">

<EmailURI>' . $email . '</EmailURI>

<PostalAddress>

<CountryCode>' . $countryCode . '</CountryCode>

<RegionCode>' . $stateCode . '</RegionCode>

<CountyName>' . $countryName . '</CountyName>

<CityName>' . $city . '</CityName>

<AdditionalCityName></AdditionalCityName>

<DistrictName>' . $stateName . '</DistrictName>

<StreetPostalCode>' . $postalCode . '</StreetPostalCode>

<POBoxPostalCode>' . $postalCode . '</POBoxPostalCode>

<StreetPrefixName></StreetPrefixName>

<StreetName>' . $street . '</StreetName>

<HouseID>' . $number . '</HouseID>

</PostalAddress>

<Telephone>

<FormattedNumberDescription>' . $phoneNumber . '</FormattedNumberDescription>

</Telephone>

</Address>

</AddressInformation>

<ContactPerson actionCode="01">

<GivenName>' . $givenName . '</GivenName>

<FamilyName>' . $familyName . '</FamilyName>

<WorkplaceEmailURI>' . $contactEmail . '</WorkplaceEmailURI>

</ContactPerson>

</Customer>

</ns1:CustomerBundleMaintainRequest_sync_V1>';

return $xml;

}

}

?>

Just like in the QueryAccounts class, the XML file does not contain <soapenv:Envelope>, <soapenv:Header> and <soapenv:Body> sections. In Customer, AddressInformation and ContactPerson, the action code is set as 01, which means that it is a creation and not an update. The CategoryCode is hardcoded to “2” meaning that it is an account being created, and not an individual customer. In addition, the CustomerIndicator is hardcoded as “true”, meaning that this is a customer account. The generateSoapVar function is the same as in QueryAccounts class, with the only purpose of converting the string into an SOAP parameter, passing the required parameters to the standard PHP class SoapVar. The function create is responsible for running the web service and creating the account. The authentication follows the same process of validation for the proxy, and the SOAP client is created using the extended class created on step 3.2. The SOAP client created has all the web service’s operations, and the one used

Page 17: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 17

for the creation is called “MaintainBundle_V1”. This function requires a SOAP parameter named “CustomerBundleMaintainRequestMessage”. All the errors that might happen (such as no account found for that ID or authentication error) are treated in the PHP file that runs this class and displays the ID of the created account.

7.2 Display account creation return

The POST parameters from the form are sent to this PHP file, which instantiates and executes the CreateAcount class, displaying the created account ID afterwards or an error message, in case it happens. The only error case that might happen is an authentication error, due to all the fields from the form being required, avoiding errors caused by lack of information in the parameter of the XML. The file must look as follows: <?php

require_once 'CreateAccount.php';

$username = $_POST['username2'];

$password = $_POST['password2'];

$accountName = $_POST['accountName'];

$email = $_POST['accountEmail'];

$countryCode = $_POST['accountCountryCode'];

$countryName = $_POST['accountCountryName'];

$stateCode = $_POST['accountStateCode'];

$stateName = $_POST['accountStateName'];

$postalCode = $_POST['accountPostalCode'];

$street = $_POST['accountStreet'];

$number = $_POST['accountNumber'];

$phoneNumber = $_POST['accountPhone'];

$city = $_POST['accountCity'];

$givenName = $_POST['contactGivenName'];

$familyName = $_POST['contactFamilyName'];

$contactEmail = (isset($_POST['contactEmail']) ? $_POST['contactEmail'] : " ");

$proxy_enabled = (isset($_POST['proxy2']) ? true : false);

$account = new CreateAccount();

$result = $account->execute(

$username,

$password,

$accountName,

$email,

$countryCode,

$countryName,

$stateCode,

$stateName,

$postalCode,

$street,

$number,

$phoneNumber,

$city,

$givenName,

$familyName,

$contactEmail,

$proxy_enabled

);

if ($result != null) {

displaySuccess($result);

}

else {

displayError();

}

function displaySuccess($info) {

echo '<h3>Account ' . $info->Customer->InternalID . ' Created</h3>';

}

function displayError() {

echo 'Authentication error! Check username, password and proxy settings then try again.';

}

?>

Page 18: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 18

As seen, this PHP file only receives the parameters and submits them to CreateAccount class, which creates the account and returns the Account ID or an authentication error.

7.3 Create an account in C4C using web service

To perform a test in the create part of the application, complete the form and insert valid login and password information for the Cloud for Customer system. After sending the information, the account is created on the C4C system.

After clicking in create, the web service is executed and the account is created on the system:

Page 19: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 19

Searching the system for the account ID, the same data inserted in the PHP application must appear on the account:

Page 20: How to Call SAP Cloud for Customer SOAP API for Account

How to consume an account web service via PHP 20

© 2014 SAP SE or an SAP affiliate company. All rights reserved.

No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP SE or an SAP affiliate company.

SAP and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP SE (or an SAP affiliate company) in Germany and other countries. Please see http://global.sap.com/corporate-

en/legal/copyright/index.epx#trademark for additional trademark information and notices.

Some software products marketed by SAP SE and its distributors contain proprietary software components of other software vendors.

National product specifications may vary.

These materials are provided by SAP SE or an SAP affiliate company for informational purposes only, without representation or warranty of any kind, and SAP SE or its affiliated companies shall not be liable for errors or omissions with respect to the materials. The only warranties for SAP SE or SAP affiliate company products and services are those that are set forth in the express warranty statements accompanying such products and services, if any. Nothing herein should be construed as constituting an additional warranty.

In particular, SAP SE or its affiliated companies have no obligation to pursue any course of business outlined in this document or any related presentation, or to develop or release any functionality mentioned therein. This document, or any related presentation, and SAP SE’s or its affiliated companies’ strategy and possible future developments, products, and/or platform directions and functionality are all subject to change and may be changed by SAP SE or its affiliated companies at any time for any reason without notice. The information in this document is not a commitment, promise, or legal obligation to deliver any material, code, or functionality. All forward-looking statements are subject to various risks and uncertainties that could cause actual results to differ materially from expectations. Readers are cautioned not to place undue reliance on these forward-looking statements, which speak only as of their dates, and they should not be relied upon in making purchasing decisions.