Skip to Content

Connecting Apps for Office with SAP - Part I: Word App

PUBLISHED

July 2013

AUTHOR

Christoph Schuler

REVIEWERS

Juergen Grebe, Microsoft

Holger Bruchelt, SAP

1 Introduction                     

This document is part of series of articles and code samples on the topic of Connecting Apps for Office with SAP.

Connecting Apps for Office with SAP - Part I: Word App

Connecting Apps for Office with SAP - Part II: Excel App

Connecting Apps for Office with SAP - Part III: Mail App


The app described in this document is available as a free download from the Office Store. Look for the 'SAP Vendor Lookup' app.

1.1 Apps for Office

With Office 2013, Microsoft has introduced the apps for Office platform which enables the user to experience the power of the web within the Office 2013 applications (Word, Excel, Outlook, PowerPoint, and Project).

An app for Office is basically a webpage that is hosted inside the Office client application. You can use apps to extend the functionality of a document, workbook, email message, or appointment. Apps can run in multiple environments and clients, including rich Office desktop clients, Office Web Apps, mobile browsers, and also on-premises and in the cloud. After you develop and publish your apps to the Office Store or to an onsite catalog, they will be available to consumers within their Office 2013 and Office 365 applications.

Using the web technologies (like HTML5, XML, CSS3, JavaScript, and REST APIs) and tools that developers know and love, different types of apps for Office can be developed:

Task pane apps for Office. These are document-centric apps that can assist the user when working with one or more documents in Word, Excel, PowerPoint and Project.
Content apps for Office. These are document-centric apps that add embedded content/functionality into a document in Excel and Excel Web Application.
Mail apps for Office. These are mailbox-centric apps in the Outlook client or Outlook Web App (OWA) client and they extend Outlook items with custom UI and behaviors.

An app for Office can provide the user experience of any modern web application. What makes the platform really powerful is the ability of the app to interact with a document through an API. The app can read and write to a document, workbook, presentation, project plan, message or appointment and handle application and user events.

This document focuses on the specific aspects of developing an app for Office that connects with an SAP business system. The solution outlined in this document is a simple solution which illustrates the capabilities of the new app for Office platform and the types of enterprise productivity scenarios that it enables.

 

1.2 SAP Vendor Lookup App

The app described in this document is the SAP Vendor Lookup app, a task pane app in Word.

The scenario for the sample app is a user authoring a document in Word, for example a Preferred Vendor Agreement that is to be sent to one or more vendors. Vendor master data, including the vendors name, number and full address are maintained in the purchasing module of the SAP ERP system. With the SAP Vendor Lookup app, the user is able to easily locate a vendor record from the SAP system and insert the details of the vendor into the document, right from within the Word application.

Using the standard Apps for Office button on the Office 2013 ribbon, the user can browse an app catalog, find the right app and insert it into the application.

An app for Office can be published to the public Office Store or to an organization’s internal app catalog on a SharePoint server. For this sample app, a SharePoint Online site in Office 365 was provisioned as app catalog.

With the app inserted into Word, the user can lookup vendor information from a connected SAP ERP system, either by specifying a vendor name or a vendor number. As the user starts typing in the Vendor field, the app will provide autocomplete functionality to assist in identifying a matching vendor record.

The user can get the details for a vendor, including name, address and phone number and insert the details into the document at the current cursor position.

                

2     Architecture

2.1 App Hosting

The web application files of your app for Office have to be hosted on a web server. You have the choice between two approaches for how your app for Office will be hosted.

Provider hosted – the web app is hosted in a web site hosting infrastructure of your choice, for example in a Windows Azure web site.

Autohosted – the web app is hosted in a Windows Azure web site that is auto-created behind the scenes and associated with a SharePoint Online account. For this hosting option you will need to use Visual Studio 2012 to package the app and an Office 365 account. Note that this approach only works for task pane and content apps, not for mail apps.

For the sample SAP Vendor Lookup app, the app was autohosted to illustrate how the app can work together with an Office 365 environment.

         

2.2 SAP Data Access

2.2.1 Vendor Data in SAP ERP

Vendor data in an SAP ERP system is accessible through BAPIs. The standard method BAPI_VENDOR_GETDETAIL can be used to return the details for a vendor, including address information.

To get a list of vendor records from the SAP ERP system, a custom function module Z_VENDOR_GETLIST was developed. This function module calls the BAPI_VENDOR_FIND method internally to read the vendor records. An optional Name input parameter can be used to return vendor records that match a name pattern (wildcards are supported).

Using the approach of writing a small ABAP wrapper function module has the benefit of allowing you to optimize for performance. Only the data that you need to display in the app (vendor number and name) is returned. It also allows you to return the data in a structure that can simplify the data model definition in NetWeaver Gateway.

         

2.2.2 SAP NetWeaver Gateway

Using SAP NetWeaver Gateway, access to business data in SAP ERP (backend system) can be enabled for a variety of consumers and devices in a standardized format based on the REST/OData protocols. NetWeaver Gateway provides a number of different configuration and integration options.

For this sample application, a data model was developed using the built-in modeling tools. The data model defines an entity (Vendor), an entity set (VendorCollection) as well as the basic read operations for the entity (Query and Read). The data provider interfaces and backend operation proxies were auto-generated by the Service Builder tool in NetWeaver Gateway and did not require any additional coding effort.

 

             

2.3 Security & Authentication

2.3.1 Same-origin Policy

A common problem for a JavaScript developer is the same-origin policy enforced by the browser. The same-origin policy prevents a script loaded from one domain from getting or manipulating properties of a webpage from another domain. Because apps for Office are hosted in a browser control, the same-origin policy applies to script running in their web pages as well.

For example, this policy will prevent a webpage in one domain (Azure web site) from calling a web service as XMLHttpRequest in another domain (SAP web service).

There are a number of ways of overcoming same-origin policy enforcement when you develop an app for Office, however some of them require support on the resource server. Among the techniques that are often referenced as ways to deal with the same-origin policy issue are JSON/P and CORS (cross-origin resource sharing), however they are currently not supported on SAP NetWeaver Gateway.

Another technique is to set up a reverse proxy on the web server. With a reverse proxy, the web app can forward a request to the resource server, without the browser knowing that another remote server is involved. Because our sample app was autohosted in an Office 365 environment, a reverse proxy could not be configured.

The approach used for the sample app was to use a server-side request handler (server-side proxy). The request handler is part of the web app and invoked by the client-side script with a relative URI.

The request handler does the work of making the resource request to the SAP NetWeaver Gateway server and passes the result set back to the client script.

 

2.3.2 App Permissions

The developer can specify the level of permissions that the app will require in the app manifest file, ranging from Restricted to ReadWriteDocument. The end user has visibility to the requested permission of the app before the app is installed and loaded for the first time. For the sample app, the permission level is ReadWriteDocument.

2.3.3 SAP NetWeaver Gateway Security

For incoming requests from a client application, the SAP NetWeaver system supports several authentication mechanisms. In addition to basic authentication, X.509 client certificates and SAML assertions are supported for single sign-on (SSO) scenarios.

For the sample SAP Vendor Lookup app, basic authentication over HTTPS was implemented.

Note that for solutions that modify SAP data (e.g. POST requests), SAP NetWeaver Gateway requires a CSRF (Cross-Site Request Forgery) token to be retrieved and then submitted with the modifying request.

For the connection to the SAP ERP system, a trusted RFC connection was configured between the two SAP systems.

2.4 Performance

To optimize for performance, the sample solution only retrieves the data from the SAP ERP system that the user requires. There are two possible approaches to this, both were utilized in the sample solution.

In the first approach, a standard function module in the SAP ERP system is utilized. In the model on the NetWeaver Gateway, only the fields that the consuming app requires are mapped to the entity and its operations. This approach was used for the Read operation which is mapped to the BAPI_VENDOR_GETDETAILS method in the ERP system. The BAPI method returns additional information that is not mapped in the data model.

In the second approach, a custom function module was developed in the SAP ERP system which is optimized for the consuming app, i.e. it only returns the data that the user requires.

The advantage of the first approach is that no ABAP development has to be done in the SAP ERP system and depending on the complexity of the data structures it may not require any adaptation coding in the model in NetWeaver Gateway either.

The second approach has the advantage that the optimization can occur directly at the source of the data. Often a small wrapper can be very useful, does not require much effort to implement and greatly simplifies the development of the model.

 

3     Sample Solution Details

This section describes the main elements and code that was developed for the SAP Vendor Lookup solution.

The complete solution is available on http://code.msdn.microsoft.com/Connecting-Apps-for-Office-f7693b85

You will need Visual Studio 2012, the Microsoft Office Developer Tools for Visual Studio 2012 and Word 2013 to compile and run the sample solution.

3.1 App Manifest

The XML manifest file of an app for Office enables the developer to declaratively describe properties that identify and describe the app for deployment. For the sample app, the properties shown below were used.

          

3.2 App Loading and Initialization

Inside the <head> element of the Home.html file, the JavaScript and CSS files that are used by the app are referenced. For the sample app, the JQuery-UI reference library and CSS file was added to enable the autocomplete functionality of the vendor input field.

Home.html

<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8" />

    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />

    <title></title>

    <link href="../../Content/jquery-ui-1.10.2.custom.css" rel="stylesheet" type="text/css" />

    <script src="../../Scripts/jquery-1.7.1.js" type="text/javascript">&lt;/script>

    <script src="../../Scripts/jquery-ui-1.10.2.custom.js" type="text/javascript">&lt;/script>

   

    <link href="../../Content/Office.css" rel="stylesheet" type="text/css" />

    <script src="../../Scripts/Office/MicrosoftAjax.js" type="text/javascript">&lt;/script>      

    <script src="../../Scripts/Office/1.0/office.js" type="text/javascript">&lt;/script>         

   
<link href="../App.css" rel="stylesheet" type="text/css" />

    <script src="../App.js" type="text/javascript">&lt;/script>

    <link href="Home.css" rel="stylesheet" type="text/css" />

    <script src="Home.js" type="text/javascript">&lt;/script>

</head>

...

 

The Home.js file contains the initialize function that must be executed when a page is loaded. It will make the Office.context property available for other functions that follow.

Common app functionality, such as notifications, are defined in the App.js file of the project and are initialized with the app.initialize() function call.

The event handlers for the UI controls are registered using JQuery methods.

Finally, the getVendorList() function is called to get a list of vendor records from SAP.

Home.js

...

(function () {

    "use strict";

    // The initialize function must be run each time a new page is loaded

Office.initialize = function (reason) {

$(document).ready(function () {

app.initialize();

            $('input:radio[name="searchoption"]').change(formatVendorList);

            $('#btnGet').click(getVendorItem);

            $('#insert-id').click(insertId);

            $('#insert-address').click(insertAddress);

            $('#insert-phone').click(insertPhone);

getVendorList();

        });

    };

})();

...

 

3.3 Task Pane Content

When the app is loaded, the Home.html page is displayed in the task pane. The page is divided into a header and a content area.

The header area displays an SAP logo with a background image that is defined in App.css.

The content area displays the lookup radio buttons, the vendor input field and a button next to it.

The vendor details (id, address and phone) are not displayed when the app loads. After the user has selected a vendor and clicks on the Get button, the vendor details slide down into the content area using CSS keyframes. This was implemented to demonstrate how motion can be added to a task pane app.

         

Home.html

...

<body>

    <!-- Page content -->

    <div id="content-header">

            <div id="header-logo"><img src="../../Content/Images/sap_logo.png" /></div>

            <div id="header-text">Vendor Lookup</div>

    </div>

    <div id="content-main">

          <div id="vendor-search">

                <div class="lookup">Lookup by:

<input type="radio" name="searchoption" id="byname" value="byname"

checked="checked" />

<label for="byname">Name</label>

<input type="radio" name="searchoption" id="bynumber"

                        value="bynumber" />

<label for="bynumber">Number</label>

</div>

<div class="vendor-input">

<div>Vendor:</div>

<input type="text" name="Vendor" id="vendor" />

<input type="hidden" id="vendor-attr" />

<button id="btnGet">Get</button>

</div>

            </div>

            <div class="vendor-details">

<div id="vendor-id">

                    <div class="label">Vendor ID:</div>

<div class="value" id="vendorId">&lt;/div>

<div class="link"><a href="#" id="insert-id">Insert</a></div>

</div>

<div class="break"></div>

                <div id="vendor-address">

<div class="label">Address:</div>

<div class="value" id="vendorName">&lt;/div>

<div class="link"><a href="#" id="insert-address">Insert</a></div>

<div class="valuex" id="vendorStreet">&lt;/div>

<div class="valuex" id="vendorCity">&lt;/div>

<div class="valuex" id="vendorRegionPostalCode">&lt;/div>

<div class="valuex" id="vendorCountry">&lt;/div>

                </div>

<div class="break"></div>

<div id="vendor-phone">

<div class="label">Phone:</div>

<div class="value" id="vendorPhone">&lt;/div>

<div class="link"><a href="#" id="insert-phone">Insert</a></div>

</div>

            </div>

         </div>

    </body>

...

 

3.4 Reading Vendor Records and Autocomplete

When the app is loaded, a list of vendor records is retrieved from SAP to enable the autocomplete function of the vendor input field.

Reading the vendor records involves two requests. The first request is a JQuery AJAX request to an ASP.NET request handler. The request handler uses the .NET WebClient.DownloadString() method to get the vendor records from the NetWeaver Gateway OData resource.

The vendor list has only two columns, the vendor name and vendor number. This is all we need to display the autocomplete functionality and it improves the performance and load time of the app.

3.4.1 getVendorList()

This function makes the JQuery AJAX request to the .ashx request handler. After the successful return of vendor records, the data is stored in an array and the formatVendorList() function is called to enable the JQUERY-UI autocomplete functionality.

Home.js

...

var vendorList = new Array;

...

function getVendorList() {

$.ajax(

{

type: "GET",

url: '/RequestHandler.ashx',

dataType: "json",

success: function (data) {

$.each(data.d.results, function (i, item) {

                            var oVendor = {

                                label: data.d.results[i].Name,

                                value: data.d.results[i].VendorNo

                            };

vendorList.push(oVendor);

                        })

formatVendorList();

                        $("#vendor").css({"background-image":"none"});

},

error: function (msg, url, line) {

app.showNotification(msg.statusText);

}

});

    }

...

 

3.4.2 RequestHandler.ashx.cs

The request handler performs the actual work of making the OData request to the SAP NetWeaver Gateway server. The request handler adds the credentials to the request and either invokes the Query or the Read operation, depending on whether the “id” parameter was included in the request URL. The certificate validation callback function was added to handle situations where a name mismatch can occur between the domain name in the certificate and the domain name in the request URL (e.g. when the NetWeaver Gateway system is cloud-hosted).

The JSON formatted response data is sent back to the client script.

RequestHandler.ashx.cs

...

public class RequestHandler : IHttpHandler

    {

        public void ProcessRequest(HttpContext context)

        {

           WebClient wclient = new WebClient();

wclient.Credentials = new NetworkCredential("[username]", "[password]");

           string resourceUrl =

"https://[host]:[port]/sap/opu/odata/sap/Z_OFFICE_APPS_DEMOS_SRV/VendorCollection";

           string id = context.Request.QueryString["id"];

           if (id == null)

           {

resourceUrl += "/";

           }

           else

           {

resourceUrl += "('" + id + "')";

           }

           ServicePointManager.ServerCertificateValidationCallback =

               ValidateServerCertificate;

           string urlOptions = "?$format=json";

           // Make a request to the resource and capture its result.

           string response = wclient.DownloadString(resourceUrl + urlOptions);

           // Relay the API response back down to the client.

           context.Response.Write(response);

        }

    }

...

 

3.4.3 formatVendorList()

The vendor list is formatted into a name/value pair list based on the radio selection in the UI. If a lookup by name was selected, the list will have the vendor name as label and the vendor number as value. If a lookup by number was selected, the list will have the vendor number as label and the vendor name as value. The formatted list is used as the data source for the JQuery-UI autocomplete function.

Home.js

...

function formatVendorList() {

        var radio = $('input[name=searchoption]');

        var selRadio = radio.filter(':checked').val();

        if (selRadio == 'byname')

        {

            var listItems = new Array;

$.each(vendorList, function (i, item) {

var oItem = {

label: item.label,

value: item.value

}

listItems.push(oItem)

            });

        }

        else

        {

            var listItems = new Array;

$.each(vendorList, function (i, item) {

var oItem = {

label: item.value,

value: item.label

                }

listItems.push(oItem)

            });

        }

       $("#vendor").val('');

       $("#vendor").autocomplete({

minLength:0,

source: listItems,

focus: function (event, ui) {

$("#vendor").val(ui.item.label);

return false;

            },

select: function (event, ui) {

$( "#vendor" ).val( ui.item.label);

$( "#vendor-attr" ).val( ui.item.value );

return false;

            }

        })

        .data( "ui-autocomplete" )._renderItem = function( ul, item ) {

            return $( "&lt;li>" )

.append( "<a>" + item.label + " (" + item.value + ") " + "</a>" )

.appendTo( ul );

        };

    }

...

     

3.5 Vendor Data in SAP ERP

3.5.1 Structure ZVENDORRECORD

A custom structure ZVENDORRECORD is used to return the vendor records in a table format with function module Z_VENDOR_GET_LIST. The structure only contains the field required for the app, i.e. the vendor number and vendor name.

 

3.5.2 Function Z_VENDOR_GETLIST

The remote custom function Z_VENDOR_GET_LIST is used to return a list of vendor records and is mapped to the Query operation of the Vendor entity. Internally, the function uses BAPI_VENDOR_FIND to read records. An optional Name input parameter can be used as a filter to only return vendor records that match a certain name pattern.

Z_VENDOR_GETLIST

FUNCTION Z_VENDOR_GETLIST.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(NAME) TYPE  LFA1-NAME1 OPTIONAL
*"  TABLES
*"      VENDORS STRUCTURE  ZVENDORRECORD
*"----------------------------------------------------------------------
DATA:
lt_selopt
LIKE BAPIVENDOR_10 OCCURS 0 WITH HEADER LINE,
lt_results
LIKE BAPIVENDOR_11 OCCURS 0 WITH HEADER LINE,
lt_vendors
LIKE ZVENDORRECORD OCCURS 0 WITH HEADER LINE
.

lt_selopt
-COMP_CODE = ''.
lt_selopt
-TABNAME = 'LFA1'.
lt_selopt
-FIELDNAME = 'NAME1'.
IF name eq ''.
lt_selopt
-FIELDVALUE = '*'.
ELSE.
lt_selopt
-FIELDVALUE = name.
ENDIF.

APPEND lt_selopt.

CALL FUNCTION 'BAPI_VENDOR_FIND'
EXPORTING
MAX_CNT         
= 0
PL_HOLD         
= 'X'
* IMPORTING
*   RETURN           =
TABLES
SELOPT_TAB      
= lt_selopt
RESULT_TAB      
= lt_results
.
* Check if records returned
IF lt_results-NUMBER NE '062'.
LOOP AT lt_results.
lt_vendors
-vendor = lt_results-vendor_no.
lt_vendors
-name = lt_results-fieldvalue.
APPEND lt_vendors.
ENDLOOP.
ENDIF.

vendors[]
= lt_vendors[].

ENDFUNCTION.

 

3.5.3 Function BAPI_VENDOR_GETDETAIL

The standard method BAPI_VENDOR_GETDETAIL is used to return the details of a vendor record, including address information. The BAPI method requires the vendor number as input parameter.

Address information for the vendor record is returned in the GENERALDETAIL export parameter of the method.

3.6 NetWeaver Gateway Data Model

3.6.1 Entity Type Vendor

You use the SAP NetWeaver Gateway Service Builder (transaction SEGW) to define your data model.

The Vendor entity was defined using the menu option Import -> RFC/BOR interface and is based on the GENERALDETAIL export parameter of the method BAPI_VENDOR_GETDETAIL.

          

 

3.6.2 Entity Set VendorCollection

Based on the Vendor entity, you define the VendorCollection entity set.

          

 

3.6.3 GetEntity (Read) Mapping

The GetEntity operation is mapped to data source BAPI_VENDOR_GETDETAIL.

The property VendorNo is used as both input and output, all other properties are output parameters.

           

 

3.6.4 GetEntitySet (Query) Mapping

The GetEntitySet operation is mapped to data source Z_VENDOR_GETLIST.

The property Name is used as input, the properties Vendors/Vendor and Vendors/Name are output parameters.

           

 

3.6.5 Service Maintenance

Using transaction /IWFND/MAINT_SERVICE you can maintain the OData service in NetWeaver Gateway.

Ensure that your service is created, that you have an active OData service (ICF) node and that a system alias for the SAP ERP system is assigned

          

 

3.6.6 Testing the OData service

Using the SAP NetWeaver Gateway Client (transaction /IWFND/GW_CLIENT), you can test the service

To test the Query operation, specify as Request URI: /sap/opu/odata/sap/Z_OFFICE_APPS_DEMOS_SRV/VendorCollection

To test the Read operation, specify as Request URI: /sap/opu/odata/sap/Z_OFFICE_APPS_DEMOS_SRV/VendorCollection(‘BP04’)

The value ‘BP04’ represents a vendor ID in your SAP system.

        

 

3.7 Publishing the app

In your Visual Studio project, in Solution Explorer, select the project for your app to display its properties. To deploy and host your app in a SharePoint online server, select the Autohosted app for SharePoint option in the project properties.

          

After you publish the app, a deployable .app file is created that you can import to SharePoint.

  .

          

 

As a perquisite you need to have an app catalog configured on your SharePoint Online server.

Go to the Apps for SharePoint library and upload the .app file for the SAP VendorLookup app. Note that even though you have developed an App for Office, the deployment procedure for autohosted apps is to upload the .app file to the Apps for SharePoint library. During this step, you can specify details about your app that the user will see while browsing the app catalog, including an icon for the app, a category, the publisher or screenshots of the app.

         

Switch to Site Contents and select add an app. Select the VendorLookup app and when prompted select to Trust it.

           

3.8 Using the app

For the user to be able to browse the SharePoint app catalog, the catalog has to be added to the list of Trusted Catalogs in Office. In your Office application (e.g. Word), go to File -> Options -> Trust Center -> Trust Center Settings -> Trusted App Catalogs and add the Url of the app catalog to the list.

         

The apps in the catalog are now available in the Insert -> Apps for Office -> See All dialog, in the My Organization category.

           

4     Conclusion

The sample SAP VendorLookup solution outlined in this document illustrates how an app for Office can be connected with an SAP ERP system and enable new types of enterprise productivity solutions.

The app provides an easy-to-use and responsive user experience that consumers are expecting from today’s web applications. Further, the app illustrates how SAP data can be integrated in to a productivity scenario in a way that was previously not possible.

Apps for Office are easy to discover and ready to use when the user needs them. Office 2013 connects seamlessly with Office 365 where documents can be stored and kept in sync, and where new apps can be published to an organizations app catalog.

For the application developer, this type of app can be developed with commonly used tools and techniques, including HTML5, JavaScript, CSS, and .NET.

The solution showcases SAP NetWeaver Gateway, a technology from SAP to connect consumers and devices to data inside an SAP business system. Using the Service Modeler in SAP NetWeaver Gateway, data can be exposed in a standardized OData format and does not require the app developer to have any specific SAP knowledge. Although outside of the scope of this document, single sign-on and write-back scenarios are enabled by SAP NetWeaver Gateway.

5     For more Information

6     About the Author


Christoph Schuler has been involved in the design and development of integrated SAP solutions for over 15 years. He has been leading the design and development of commercial software products for Microsoft/SAP interoperability, including the .NET Data Provider and Duet Enterprise.

Christoph works as a consultant, architect and instructor for Microsoft/SAP solutions and is the principal consultant at Connected ERP.

You can reach him at christoph@connected-erp.com

Tags:
Former Member