Sie sind auf Seite 1von 19

The SAP Fiori Reference App Manage Products

Applies to:
SAP Fiori Reference Apps
SAP Web IDE 1.14
SAP Netweaver 7.40 SPS 10

Summary
This document provides an overview of the technical aspects of the SAP Fiori Reference App Manage
Products, which has been implemented in namespace nw.epm.refapps.ext.prod.manage.
.

Authors: Dr. Stephan Naundorf, Ian Robert Taylor, Christian Kolbowski


Company: SAP SE
Created on: February 17, 2015
Updated on: August 13, 2015 to reflect changes delivered with Web IDE 1.14

Author Bio

Dr. Stephan Naundorf is a Development Architect in the SAP Global Design team of SAP SE.

Ian Robert Taylor is a Senior Developer in the SAP Global Design team of SAP SE.

Christian Kolbowski is a Development Architect in the SAP Global Design team of SAP SE.

Table of Contents

Contents
Features of the App ............................................................................................................................................ 3
Draft Pattern .................................................................................................................................................... 3
Implementation ................................................................................................................................................... 4
Main Building Blocks ....................................................................................................................................... 4
Lifecycle .......................................................................................................................................................... 5
Error Handling ................................................................................................................................................. 6
Busy handling .................................................................................................................................................. 7
Edit View ......................................................................................................................................................... 8
Further Topics ............................................................................................................................................... 10
Backend Implementation .................................................................................................................................. 12
Development Environment ............................................................................................................................ 12
Overview of the Gateway Service ................................................................................................................. 12
Service Implementation................................................................................................................................. 13
OData Requests............................................................................................................................................ 14
Copyright........................................................................................................................................................... 19

The SAP Fiori Reference App Manage


Products
Technical documentation
This document provides an overview of the technical aspects of the SAP Fiori Reference App Manage
Products, which has been implemented in namespace nw.epm.refapps.ext.prod.manage.

Features of the App


The app implements the master-detail pattern. In the master list, it provides an overview of available
products. This list can be filtered, grouped, and sorted according to several properties of the products.
The detail area has two possible modes: Display and Edit. The first mode allows users to only view details
for the selected product. The second mode allows users to modify an existing product. Moreover, the Edit
mode can also be used to create new products.
Deletion of products is possible in the master list (mass deletion, quick deletion via swipe) and in the detail
area (deletion of the product currently selected).
Draft Pattern
A special feature of this app is the use of the draft pattern. This usage is normally not recognized by users.
In fact, a draft product is created whenever a user starts an editing session1.
A draft object is owned by the user who created it. It serves as a lock in two senses:
While a draft exists for a product, this product cannot be edited or deleted by another user.
A user may not possess more than one draft, so it is not possible to edit more than one product at a
time.
Normally, the draft is deleted at the end of this session, either by explicitly saving the product or by
discarding (cancelling) the changes. In the first case, the content of the draft entity is checked for consistency
and (if possible) copied into the real entity before the draft entity is deleted.
The only time users are actually confronted with drafts is when they end an editing session in an uncontrolled
way (for example, by switching off their computer). Only in this case does the draft survive the closing of the
app. Such a draft is called a lost draft.
When users start the app, the system first checks whether they have a lost draft. If this is the case, the
system asks whether the user wants to continue editing this draft or discard it.
In order to provide this feature, the draft is stored in the background whenever the user changes the content
of a field. Thus, the state of the draft can be viewed as a snapshot of the users screen.2
Properties of Draft Objects
Draft objects possess the same properties as real products. In addition, a draft contains two more
properties:
Information on whether the draft belongs to a new product or an existing one.
The dirty flag, which contains the information on whether the user has already performed any
changes to this draft.

for creating a new product or modifying an existing one

This snapshot is actually taken with a small delay. Normally the draft is stored when the user moves from
one field to another.

If the dirty flag of a draft is false, the draft is deleted without notice. That means that no data-loss dialog
appears when the user cancels the editing session for a non-dirty draft and lost drafts are ignored when they
are not dirty.
Note that the ID of a draft is identical to the ID of the corresponding product. Hence, a draft created for
editing reuses the ID of the product and vice versa a newly-created product reuses the ID of the draft that
was used to create it.

Implementation
The structure of the app has been adapted to the SAPUI5 Master-Detail Application template. However, note
that this app covers a much more complex scenario than the template. Therefore, additional concepts have
been added.
On the other hand, some pieces of code that are not used in this app have been removed in order to keep
the code as simple as possible3.
Main Building Blocks
According to the general rule for Fiori Apps, this app is started using class
nw.epm.refapps.ext.prod.manage.Component, which inherits from sap.ui.core.UIComponent. As usual, this
class contains the metadata for routing, OData access, icons, and so on. Moreover, the class possesses an
init-method which creates some global models used by the app and initializes the ApplicationController (see
below) and the router.
Application Controller
The implementation of the app is delegated to class nw.epm.refapps.ext.prod.manage.controller.Application,
which serves as (singleton) controller for the app. The single instance of this class is added to the application
model as property applicationController (see below). Thus, it can be easily accessed by all view controllers
(more generally: by all pieces of code that have access to the component).
Note that the state handling of the app is rather sophisticated, so it turns out to be easier to have one central
instance responsible for managing this state handling compared to the approach of distributing the state
handling of the app across the single views.
Obviously it would have been possible to enhance the component object itself such that it could serve as an
application controller. However, this object inherits from sap.ui.core.UIComponent. Thus, each property or
method added to the controller would potentially produce a conflict with any property or method of the base
class that has the same name by chance.
The topmost views
The (split-) app as a whole is hosted by view nw.epm.refapps.ext.prod.manage.view.App.
Master and detail view are implemented by nw.epm.refapps.ext.prod.manage.view.S2_ProductMaster and
nw.epm.refapps.ext.prod.manage.view.S3_ProductDetail.4 Note that these views are attached to the
corresponding routes in the components metadata. Therefore, instantiation of the views is automatically
performed via the router.
As already mentioned, all views have access to the application controller via the application model. On the
other hand, master view and detail view register with the application controller using methods
registerMaster() and registerDetail().5

One example would be method _createMetadataPromise in class Component.js from the template, which is
not used in this app.
4

According to the structure given by the template, the corresponding controllers (as for all views) can be
found in folder controller.
5

The app view is simply retrieved from the component. Thus, the application controller has access to all
three topmost views (or their controllers) via attributes _oMainView, _oMasterController, _oDetailController.

Standard models
Class nw.epm.refapps.ext.prod.manage.model.models.js was copied from the template and adapted to this
app. This class provides the code for creating the i18n-model, the device model (a JSON model that
provides access to information about the device being used), and the v2-OData model used in this app.
Component.js uses this facility and attaches the models to the component (as the named models i18n,
device, and as the default model).
The OData model uses OData service EPM_REF_APPS_PROD_MAN_SRV. Note that the OData service
has distinct entity types for products and product drafts (called Product and ProductDraft). An alternative
solution could model both entities in one entity type. The distinction between drafts and real products would
be implemented using a suitable property.
Application Model
The application controller instantiates an additional JSON model and attaches it to the component (with
name appProperties) such that it can be accessed by all views.
This model contains data describing the global state of the app (for example, whether the app is currently in
display or in edit mode).
This model is accessed declaratively and programmatically in various places.
Navigation Manager
nw.epm.refapps.ext.prod.manage.controller.NavigationManager is a helper class of the application controller.
It is responsible for all navigation tasks. In particular all interaction with the router (after its initialization) is
handled by this class. This means that this class is the only one listening to the router events and it is the
only one calling the navTo-method of the router.
Lifecycle
Global Lifecycle
The global lifecycle of the app is controlled by the application controller and its helper class, the navigation
manager.
In particular, the application controller listens to the standard event onMetadataLoaded and the navigation
manager listens to the standard event onRoutePatternMatched.
Moreover, all navigation that is triggered programmatically is performed using the navigation manager (see
method _executeNavigation() and the public methods utilizing this6). Note that attribute
_bNavigationByManualHashChange is used to distinguish between route changes that are caused externally
(for example, the user changing the URL-hash manually) and those caused programmatically.
In addition, the application controller also listens to the following specific events:
Deletion of one or more products (see deleteListener)
handleLostDraft (normally only during startup)
Lifecycle of the Main Views
The topmost views are initialized by the router as normal. This triggers the lifecycle method onInit() of the
corresponding controllers.7 As already stated, the controllers of the main views register with the application
controller at this point in time.

The application controller contains wrapper methods for these public methods such that all other classes
can access them via the application controller without needing to know the helper class.
7

Note that at this point in time the global models have not yet been attached to the views. Therefore, the
models are always accessed via the component here.

The controller of the master view expose methods findtem(),prepareForDelete(), and


adaptToDetailSelection(), which are used by the application controller and the navigation manager at
suitable points in time.
The controller of the detail view exposes methods editModeChanged() and productChanged(), which are
called to inform the detail view that it should adapt to changes in edit/display mode or a change in the
selected product. The implementations of these methods take the current state of the app from the global
application model.
Both controllers also have several event handlers for interactive controls (mainly buttons). Moreover, the
master controller listens to the update of the list (onUpdateStarted(), onUpdateFinished()).
Switch Between Display and Edit Mode
As stated, view S3_ProductDetail implements both display mode and edit mode. This is necessary because
the URL should not change when switching between these modes. On the other hand, implementation of
display mode and edit mode differs so much that it seems to be more appropriate to create a separate view
for each purpose.
Therefore, subviews ProductDisplay and ProductEdit have been defined, implementing those two modes.
S3_ProductDetail consists of a single NavContainer, which hosts one instance of each of these views. It
utilizes the methods show() and leave() of the controllers of these two views to inform them of the following:
When they should adapt themselves to the current product
When they become invisible because of a switch between display and edit mode
In particular, both controllers bind the corresponding view to a context path derived from the current product
ID when method show() is called.
Error Handling
Note that nw.epm.refapps.ext.prod.manage.controller.messages.showErrorMessage is a reuse function that
displays error messages for the user.
Startup
During startup, two operations take place that may result in errors:
Loading of metadata
Check for lost draft
The app is programmed in a way that allows a retry when one of these steps is unsuccessful.8
Note that the app is busy until these two operations have finished (successfully or with errors).9
If the loading of the metadata was already unsuccessful, all elements of the app remain disabled with the
exception of the Search field and Refresh facility in the master list.
Each time the user uses one of these facilities, the refresh() method of the application controller is called. If
the metadata has not been loaded at this point in time, loading of the metadata is triggered again. In this
case, refreshing the list is deferred until the metadata has been loaded. Technically this is implemented in
method whenMetadataLoaded of the application controller.
If the metadata has been loaded successfully but the request for lost drafts is unsuccessful, the app is
started anyway. However, all editing functions are disabled until the lost draft information has been read
successfully. A new attempt to read the lost draft information is triggered on each refresh of the list as well.
However, this happens asynchronously. Hence, in this case we accept that the decision popup for lost draft
(or another error message) may appear unexpectedly for the user just when this call has ended.

And each of these unsuccessful attempts is displayed to the users using the showErrorMessage utility.

When these operations have finished successfully, users might be asked to deal with a lost draft. This
would probably be irritating if they have already started working with the app. Therefore, it seems appropriate
to set the screen to busy during startup.

Errors During Editing


Changes that the user performs during an edit session are silently saved in the draft object. This may be
unsuccessful due to severe inconsistencies in the draft. For example, the user might have entered a nonnumeric string in the Price field.
In this case, we do not want to disturb the users editing session with an error dialog. However, the input field
containing the error should be flagged accordingly.
Actually, batch group editproduct is used to save changes entered by the users of the draft. This is
implemented in method _submitChanges() of class nw.epm.refapps.ext.prod.manage.model.Products.
Note that the submitChanges()-method of the OData model is used here.
If the update of the draft is unsuccessful due to the usage of batch jobs here, the result may nevertheless
end up in the success handler of submitChanges(). Therefore, the batch response must be traversed in order
to check for errors.
This happens in the local function fnSuccess defined within _submitChanges().
Busy handling
Busy handling has two purposes:
Give user feedback that something is happening
Lock the screen or parts of it until a consistent state has been reached again
From an implementation point of view, it would be easiest to lock the whole screen whenever some
asynchronous operation is pending. In order to optimize user experience, we may strive for a smarter
solution. However, this will put additional burden on the implementation.
Granularities of being busy
In this app, we decided to have three visual units that can have a busy state:
The whole app
The master area
The detail area
We will discuss these three cases in detail now.
Busy state of the whole app
The busy state of the whole app is implemented in view nw.epm.refapps.ext.prod.manage.view.App. The
busy state of this view is bound to property isAppBusy of the global application model.
Function fnInitBusyHandling in file nw.epm.refapps.ext.prod.manage.Application.js shows how this property
is controlled: It listens to other properties defined in the global application model and sets isAppBusy to true
exactly when one of those properties has a predefined value.
So we can see that the whole app is busy during startup and when a change operation is in progress.10
Busy state of the master area
The busy state of the master area is implemented in view
nw.epm.refapps.ext.prod.manage.view.S2_ProductMaster. The busy state of this view is bound to property
isListLoading of the global application model. This means that the master area is busy while the entries of
the master list are retrieved from the backend.
In order to avoid the app and a subview indicating a busy state at the same time, the busy state of the view is
actually bound to an expression that ensures that the master view does not become busy when the whole
app is busy.

10

Exception: The deletion of a draft is done totally asynchronously. Attribute _oWhenNoDraft in class
nw.epm.refapps.ext.prod.manage.model.Products is used to ensure that the deletion of a draft does not
interfere with other operations.

Moreover, the control which is used for the list itself has a built-in busy handling. In order to avoid duplicate
busy indications here, property enableBusyIndicator of the list is set to false.
The idea for pushing up the busy state to the view level is that otherwise the list operations, such as filtering,
would still be open while the list is loading. These operations seem to be so closely connected to the list itself
that it was decided to lock them while the list is loading.
Busy state of the detail area
The edit view cannot be set to busy on its own. All operations requiring a busy state here result in the whole
app becoming busy. Therefore, the busy state of the detail area is implemented in view
nw.epm.refapps.ext.prod.manage.controller.ProductDisplay. The busy state of this view is bound to (the
negation of) property dataLoaded of the local view properties model, since the view is supposed to be busy
as long as no data is there to display.
Again we want to avoid duplicate busy indications. Therefore, the busy state of the app is bound to an
expression ensuring that the view is not busy while the whole app is busy at the same time.11
Busy indicator delay
In most scenarios backend calls are fast. User experience would suffer if busy indicators appear for a short
time with every action. Therefore, SAPUI5 controls do not only possess an attribute busy indicating whether
the control is busy but also an attribute busyIndicatorDelay, which defines a time period that the app waits for
until the busy indication is actually shown.
This attribute possesses a reasonable default. In this app, we sometimes switch between this default and a
value of 0. Thereby, we rely on the fact that the default value is used when the attribute busyIndicatorDelay
is set to null.12
For simplification, the delay is set to 0 during startup and whenever a change operation is performed. This is
acceptable because these operations are rare and the user expects them to last a certain time.
Therefore, the delay is set to the fixed value 0 in the definition of nw.epm.refapps.ext.prod.manage.view.App.
Master and detail view should normally have the default delay. However, when the busy state follows
immediately after the whole app being busy, it should be 0 in order to avoid flickering of busy states.
Therefore, the corresponding delays are bound to properties detailBusyIndicatorDelay and
masterBusyIndicatorDelay of the global application model, which are initialized as 0 (startup phase) and set
to null when the corresponding data has been loaded once.
When the whole app is set to the busy state again (change operations) detailBusyIndicatorDelay is set to 0
once more because the detail area has to be updated again after the change has been executed.13 It will be
set back to null when the detail screen is filled the next time.
It might seem that the same is necessary for the master view. However, the request for updating the master
list is actually batched with the request performing the change operation. Therefore, the master view itself
does not become busy at all in these scenarios.
Edit View
Introduction
The edit view is an important aspect of the SAP Fiori Reference App Manage Products because it
demonstrates how to provide help to the user on entering valid data. In particular, value lists are presented to

11

Moreover, the expression ensures that the view is not busy in the exceptional situation that loading of
metadata is unsuccessful. Obviously, in this case the data are not loading although property dataLoaded is
false.
12

This assumption is true for views, but might be false for other controls overriding the generic busy handling
of SAPUI5. Therefore it might be suitable to retrieve the default value programmatically and switch between
this value and 0 from then on when handling the busy state with finer granularity.
13

See function fnRefreshBusyState in the application controller.

the user in the form of either ComboBox or Select controls. These are used according to the UX Guidelines
so that for fields where the number of possible values does not exceed 20, the Select control is used. Where
there are more than 20 values, the ComboBox control is used. Whereas the Select control only allows the
user to pick a value from a list of possible values, the ComboBox allows the user to start typing the value and
thereby limits the list of possible values.
User Changes
A user selects to edit an existing product by choosing Edit on the view S3_ProductDetail. The contents of the
chosen product are copied to a Draft. Changes made by the user in the input fields are saved to the Draft
when the cursor leaves the respective input field. The event change on the input field controls sap.m.Input
and sap.m.Select and event selectionChange for the control sap.m.ComboBox are used to trigger an update
of the Draft. The Draft is updated using method submitChanges from the v2 OData model and the changed
field is written to the Draft in the backend system via the OData call Merge, called by the OData model.
Select Value Lists
The fields for the units of Length, Width and Height and for the Weight unit present the possible values using
the control sap.m.Select because there are less than 20 possible values to choose from. The values of the
dimension units are obtained from the OData service from the entity set DimensionUnits and the weight units
from the OData service entity set WeightUnits.
ComboBox Value Lists
Similarly to the Select value lists, the value lists for the fields that use ComboBox to display the possible
values also use OData service entity sets. For example, the Currencies entity set for the permitted currency
codes.
Category Value List
There is a unique set of possible Category Values for each Main Category Value. Changes to the Main
Category field therefore need to define a new list of Category Values according to the Main Category. A filter
is defined on the OData binding of the field Category in method _setCategoryFilter in the Edit controller so
only the relevant categories are shown. Additionally, the Category is set to empty when the user selects a
new Main Category.
Supplier Value List
The Supplier field has two variants for providing possible values. The entity set Suppliers provided by the
OData service is used to provide a Type Ahead suggestion using showSuggestion="true" in the XML part of
the Edit view. As a user types the name of the supplier, a proposal list is provided by the sap.m.Input control
from which the user can select the corresponding entry.
Additionally, a search help is provided for Supplier. When the user chooses the icon consisting of two
overlapping squares at the end of the input field, a search dialog appears in which the user can search for,
then select the entry required. In this case, the list of possible Supplier values is obtained by annotations in
the OData service. The path Product/SupplierName retrieves the possible SupplierName and SupplierId
values.
In order to make use of this search help, it is currently necessary to create the class
sap.ui.comp.providers.ValueHelpProvider in the controller for the edit screen. This class then provides the
search help dialog. In future releases of SAPUI5, the search help will be facilitated merely from the field
definition in OData without requiring any implementation in the app.
Error Checking of Field Changes
As stated, the changes are saved to the Draft in the back end after each field is changed. The SAP Gateway
and the OData service implementations in the back end make validation checks on the content of fields, for
example the Price and Weight fields.
In the event that the field contents do not match the definitions in the back end, the OData call returns an
error message. We assume that the error message relates to the field that was changed. The error message
is obtained from the OData response call. Since OData batch requests are used, the error messages may

appear in a batch call where the overall status is Success and thus you must check method
_submitChanges in nw.epm.refapps.ext.prod.manage.model.Products for possible error messages.
Error messages found are displayed on the Edit screen using the value state text of the input field in which
the last change was made and the value state is set to Error, resulting in the field being highlighted in red.

Error Checking on Save Product


When a user wants to save a product, the system checks that all mandatory fields have content. All
mandatory input fields that are not filled are highlighted with the value state Error by method
_checkAndMarkEmptyMandatoryFields in the Edit controller. The respective value state texts are defined for
each input field in the XML Edit view.
A Save request to the back end that copies the contents of Draft to Product only happens if there are no
missing mandatory fields and there are no input fields marked with the value state Error.
Any error messages that are returned by the OData draft activation cannot be assigned to any field and are
displayed in a dialog box using the reuse method
nw.epm.refapps.ext.prod.manage.controller.messages.showErrorMessage.

Further Topics
Modularization
We have already discussed the main components of the app and how they interact. However, there are
some other classes that take over certain tasks.
The most prominent of them is nw.epm.refapps.ext.prod.manage.model.Products. A singleton instance of
this class is created by the application controller and can be accessed using method getODataHelper().
This class is responsible for performing all explicit OData calls needed in the app. To remove objects, it uses
helper class nw.epm.refapps.ext.prod.manage.model.RemoveService, which is instantiated on demand.
The handling of searching, sorting, filtering, and grouping in the master list is delegated to the following
classes:
nw.epm.refapps.ext.prod.manage.controller.TableOperations
nw.epm.refapps.ext.prod.manage.controller.SubControllerForFGS
Note that the services provided by the first class are agnostic with respect to specifics of the entity handled
by this app (products) and may therefore be reused by any other app using the master-detail pattern.
The implementation of the Share button that is available on the DispIay and Edit screens is done by fragment
nw.epm.refapps.ext.prod.manage.view.ShareSheet and class
nw.epm.refapps.ext.prod.manage.controller.SubControllerForShare.
Adjusting the Master List
One of the most delicate tasks of the app is to bring the master list into the correct state. In particular this
means the following, as appropriate:
Ensure that the correct list item is selected
Ensure that the selected list item is scrolled to
Ensure that a list item is selected at all
Which one of these actions really should be taken depends on several factors. Here are some examples to
illustrate this:
Normally, the list item corresponding to the product currently shown in the detail area should be
selected in the master list. This is not true in multi-select mode.

10

Moreover, note that there are cases in which there is no list item that corresponds to the product
currently shown in the detail area.14
In certain cases, the master list should scroll to the list item corresponding to the product currently
shown in the detail area. This is particularly true when the app is started with a URL that specifies
the product to be displayed. In other cases, the master list is supposed to hold its position. This is
particularly true when the user manually selects an item in the master list.

In certain scenarios, the list item to be selected is predetermined (such as when the user starts the app with
a URL that specifies a certain product). In this case, the empty page appears if the product is not available.
In other scenarios, we have a preference for the item to be selected (such as when the user deletes the
currently selected product. In this case, the next item in the list should preferably be selected if still
available).
Finally, we have scenarios in which just any item (the first one in the list) is to be selected (such as when the
user starts the app with no specific product selected and no lost draft available).
Method findItem() in the controller of S2_ProductMaster is responsible for determining the item to be
displayed, if necessary. Note that this method is called each time the list is updated.

14

For example, this can happen if users apply a filter to the master list that excludes the product they have
selected beforehand.

11

Backend Implementation
The OData service for the Manage Products app was modelled in a Gateway project. The classes,
model, and model design aspects are outlined here.
We assume that you are already familiar with the basic concepts of OData services. For more information
about OData, see the specification: OData V2

You should not use the technical names provided in the examples here but base your names on the
appropriate naming conventions for your product or app.

Development Environment

GW software component: SAP_GWFND 740

Gateway Service Builder: transaction SEGW


Gateway project name: EPM_REF_APPS_PROD_MAN
ABAP package: S_EPM_REF_APPS_PROD_MAN_ODATA

Overview of the Gateway Service


Data Provider Classes

CL_ EPM_REF_APPS_PROD_M_DPC: Base class for data provisioning providing a default implementation
for all service artifacts raising a not-implemented exception. This class is regenerated each time that the
service is regenerated in the service builder.
CL_ EPM_REF_APPS_PRD_M_DPC_EXT: Derived from the base class, where methods of the data service
are overwritten (for example, method REVIEWS_CREATE_ENTITY) this means not-overwritten methods
show the default behavior not implemented. This class is not affected by regeneration of the service in the
service builder. For the Manage Products service, all CRUD operations and function imports are handled in
the data provider class. All the data retrieval is handled via the SADL runtime by making use of core data
services.
CL_EPM_RAMP_DRAFT: Helper class for the handling of CRUD operations on product draft instances.
Model Provider Classes

CL_ EPM_REF_APPS_PROD_M_MPC: Contains the EDM model data generated from the service builder.
This class is regenerated each time that the service is regenerated in the service builder.
CL_ EPM_REF_APPS_PROD_M_MPC_EXT: Implements changes to the service model not modeled in the
service builder. This class is not affected by the regeneration of the service in the service builder.
The implementation contains the necessary annotations for the different value help lists used in the app.

12

The EDM Model


This diagram provides an overview of the data model with its entity types and associations. The Manage
Products app implements a variant of the draft pattern. In stateless scenarios, the draft pattern can be used
to prevent the user losing data while creating a new entity or editing an existing one.
The handling of drafts is described below.
Note: Entity types and their corresponding entity sets that are only required for value help (Currency,
DimensionUnit, QuantityUnit, WeightUnit) are omitted from the diagram.

MainCategory

SubCategoryMainCategories

0..n

SubCategory

ProductDraftImageDrafts

0..n

1
ProductsSupplier

ProductsSubCategory

ImageDraft

Supplier

0..n

ProductDraft

0..n

0..1

0..1

Product

Service Implementation
While all CRUD operations and function imports of the service are handled in the corresponding method
implementations of the data provider class CL_ EPM_REF_APPS_PRD_M_DPC_EXT, the data retrieval is
handled by the SADL runtime by making use of core data services. For each of the service entity sets, this
means that their corresponding GetEntity and GetEntitySet methods are not redefined in the data provider
class; instead the SADL runtime is called directly from the data provider base class method.
For example, for entity set Products, the DPC base class method implementation looks as follows:
if_sadl_gw_dpc_util~get_dpc( )->get_entityset(
EXPORTING io_tech_request_context = io_tech_request_context
IMPORTING et_data
= et_entityset
es_response_context
= es_response_context ).

Taking entity set Products as an example, in the project service implementation view of the Gateway Service
Builder, it is directly mapped to the corresponding core data service (CDS) view
SEPM_C_RAMP_PRODUCT.
You can find all corresponding CDS views in the packages dictionary section under ABAP DDL sources.
Please note that you need ABAP in Eclipse to display their content.

13

OData Requests
This section describes the start screen of the EPM Manage Products app with the corresponding OData
requests required by the SAPUI5 controls.

GET Operations

1. The data for the product list is retrieved using this call:
GET Products?$skip=0&$top=20&$orderby=Name asc&$select=Id%2cImageUrl%2cName%2cPrice
%2cCurrencyCode%2cSubCategoryName%2cMainCategoryName%2cQuantityUnit%2cStockQuantity
&$inlinecount=allpages
2.

From the first calls result, the property ImageUrl points to the location in the MIME repository where
the corresponding product image is stored for each result set entry. The images are then retrieved
using separate GET requests:
GET /sap/public/bc/NWDEMO_MODEL/IMAGES/HT-2001.JPG

3. In the master list, the lead selection is automatically set to the first list item. To display the product
information in the detail area, a call to the product entity set is performed.
GET Products('HT-2001')?$expand=Supplier

4. With the same call, an $expand to the Supplier entity retrieves all supplier details displayed in the
linked business card.

14

5. In parallel, a call to the ProductDrafts entity set is made in order to determine whether users were
editing a product the last time they accessed the app:
GET ProductDrafts

If the browser session was terminated unexpectedly, the next time users start the app they are asked
whether they want to continue editing this draft:

Choosing Resume closes the dialog and displays the Edit screen.Choosing Discard triggers a delete
request to the entity set ProductDrafts:
DELETE ProductDrafts('HT-2000')

6. The master list provides a search field. When entering a search pattern and choosing Enter, a backend
search is performed for the product name.
GET Products?$skip=0&$top=20&$orderby=Name asc&$select=&search=Beam&$inlinecount=allpages

7. The master list footer toolbar offers buttons for sorting, filtering, and grouping.
Group by produces the same OData request as list sorting, additionally the list control groups the result
using the respective group criteria.
Example of sorting by Price and Name in ascending order:
GET Products?skip=0&$top=20&$orderby=Price asc, Name asc&$select=

Example of filtering by Price between 500 1000:


GET Products?$skip=0&$top=20&$orderby=StockQuantity asc,Name asc,Price asc
&$filter=(Price ge 500M and Price le 1000M)&$select=

CRUD Operations/Function Imports


While the actions Create and Delete are implemented as standard CRUD operations in the data provider
class, the actions Edit and Copy and Activate are implemented as function imports, since for them the
request target entity set does not correspond to the result target entity set (entity sets Product <->
ProductDraft).
For implementation details of the function imports, see class CL_EPM_REF_APPS_PROD_M_DPC_EXT,
method /iwbep/if_mgw_appl_srv_runtime~execute_action.

15

Draft Handling
New Draft

8. The + button triggers the creation of a new product. By passing an empty payload to the back end, a
new draft product is created.
POST ProductDrafts
Payload: {"ProductId":""}

The OData response contains the new product draft entity:


/ProductDrafts('HT-2001')

With this information, a GET request is triggered, retrieving the new draft entity:
GET ProductDrafts('HT-2001')?$expand=Images

Edit Draft

9. Editing of an existing product triggers function import EditProduct, passing the respective product ID:
POST EditProduct?ProductId='HT-2001'

In the back end, the system first checks whether a draft entity already exists for the requested product;
in that case it checks whether the user that wants to edit it is the draft owner (then the draft is
returned, if not an exception is triggered). Then a deep copy of the existing product is created and
stored in the draft persistency (DB tables SEPM_RAMP_PDDRFT for the draft product,
SEPM_RAMP_IMDRFT for the draft product images).
In a second get call, entity set ProductDrafts is addressed with the respective product ID (as mentioned
in the UI documentation, the existing product ID is reused for the edit case too).
GET ProductDrafts('HT-2001')?$expand=Images

A second call to entity set SubCategories retrieves the value list for the current main categories, and
finally a call to entity set QuantityUnits retrieves the value list for the unit of measures.
GET SubCategories?$skip=0&$top=100&$orderby=Name%20asc&$filter=startswith(MainCategoryName,
TV Video HiFi)&$inlinecount=allpages
GET QuantityUnits?$skip=0&$top=20&$orderby=Shorttext%20asc

Depending on the edit state, when the user chooses Cancel, the draft instance is either discarded
without further notice (edit state unchanged) or the user is warned that his or her entries will be lost.
While editing, changes to the product are implicitly saved each time the input-field focus is changed. In
the payload of the call, all collected changes made to the entity are passed (this is handled by SAPUI5
automatically).
MERGE ProductDrafts('HT-2001')

When the user chooses Save, function import ActivateProduct is called:


POST ActivateProduct?ProductDraftId='HT-2001'

In the back end, the product is again read from the draft persistency and an update is triggered against
the EPM persistency where the original product is persisted. If this is successful, the entry in the draft
persistency is deleted.
The OData response now contains the data of the product just updated with the same shared ID.
10.

Deleting the product currently selected triggers the following requests:


DELETE Products('HT-2000')

16

The next two calls retrieve the updated list of products and the details of the new lead selection in the
product list, which is set automatically:
GET Products?$skip=0&$top= $orderby=Name asc&$select=
GET Products('HT-2001')

11. Copying the product currently selected triggers the following requests:
POST CopyProduct?ProductId='HT-2001'

In the response, you receive the URL to the new draft product:
/sap/opu/odata/sap/EPM_REF_APPS_PROD_MAN_SRV/ProductDrafts('EPM-000002')

The response ID is used to query the product draft entity. Since we have a deep copy including all
images, an expand to entity Images is done.
GET ProductDrafts('EPM-000002')?$expand=Images

The response includes an image URI that points to the ImageDraft entity set:

/sap/opu/odata/sap/EPM_REF_APPS_PROD_MAN_SRV/ImageDrafts(guid'005056A7-004E-1EE4-B1E402BC1F3F70BF')

Copying a product basically runs through the same routine as creating a product, except that additionally
the ID for the product to be copied is passed with the request, which is used to select the existing
product data used for the copy.

17

Related Content
For more information, visit the links below:
Fiori Reference Apps on SCN

http://scn.sap.com/docs/DOC-59963

SAP Web IDE - SAP's Browser-Based


Development Tool for SAPUI5

http://scn.sap.com/docs/DOC-55465

SAP Web IDE Cloud trial access

http://marketplace.saphana.com/Industries/CrossIndustry/SAP-River-Rapid-DevelopmentEnvironment/p/3334

Detailed description:
Reference App - Shop

http://scn.sap.com/docs/DOC-60841

Detailed description:
Reference App - Approve Purchase Orders

http://scn.sap.com/docs/DOC-60846

Detailed description: Reference App Manage Products

http://scn.sap.com/docs/DOC-61464

18

Copyright
2015 SAP SE SE or an SAP SE 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.
The information contained herein may be changed without prior notice.
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 and its affiliated companies (SAP SE Group) for informational
purposes only, without representation or warranty of any kind, and SAP SE Group shall not be liable for
errors or omissions with respect to the materials. The only warranties for SAP SE Group 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.
SAP SE and other SAP SE products and services mentioned herein as well as their respective logos are
trademarks or registered trademarks of SAP SE in Germany and other countries.
Please see
http://www.sap.com/corporate-en/legal/copyright/index.epx#trademark
for additional trademark information and notices.

19

Das könnte Ihnen auch gefallen