Implementing the Behavior of Draft-Enabled Business Objects

Objectives

After completing this lesson, you will be able to:
  • Enable draft handling in an OData UI service.
  • Explain the difference between transition messages and state messages.
  • Describe the draft-specifics in behavior implementations.

Draft in SAP Fiori Elements

Editing of data in a Draft Instance

When you edit data in a draft enabled SAP Fiori elements application, the framework regularly sends your entries to the backend where they are saved in a draft instance. Even if the data is still inconsistent or incomplete.

The application indicates this at the bottom of the Object Page, next to the Save and Cancel buttons.

When the user chooses Save, the framework first executes the determine action PREPARE, then copies the draft to the active data (action ACTIVATE). Finally, it executes all validations and determinations on the active instance. Then it saves the active instance to the database and deletes the draft from the draft table.

When the user chooses Discard Draft, the framework discards the draft instance (action DISCARD) and deletes the draft from the draft table.

When the user navigates back or closes the application, or in the case of any failure, the draft remains and the user can pick up editing anytime.

Visualization of existing drafts

On the Report List, a Draft link below the text field of a node indicates that this entry is a draft instance. Choosing the link displays a dialog window with administrative data of the draft.

Draft-specific filter field

A draft enabled SAP Fiori elements app displays an additional filter field labeled as Editing Status. This filter field allows the user to hide the drafts or to hide the instances for which a draft exists. For the drafts, the user can filter for own drafts and drafts created by another user. It is still protected by a pessimistic lock and drafts created by another user for which the pessimistic lock is already expired. The latter is called Unsaved Changes by Another User.

Note

Changing the filter does not apply the filter directly. Choose Go to trigger a new selection that includes the filter.

Determine Action Prepare

Draft determine action PREPARE

All validations, and the determinations defined with on save, are evaluated on the active instances, just before they are written to the database tables. In a draft-enabled scenario, this means that they are evaluated during the activation of a draft after the copy of the draft instance to the active instance.

Before a draft is activated, the framework implicitly executes the draft determine action PREPARE. That way, any determinations and validations linked to PREPARE are also executed on the draft data before the draft instance is copied to the active instance.

Note

It is also possible that the consumer of a draft-enabled business object executes PREPARE explicitly to check the consistency of the draft instance.

Like all other draft actions, PREPARE is implicitly enabled when the business object is draft enabled. However, without an explicit declaration, no determinations and validations are assigned to it. The assignment of determinations and validations must be done explicitly in the behavior definition. To assign validations and determinations, add a pair of curly brackets after the action name and list the validations and determinations there.

The following restrictions apply:

  • Only determinations and validations that are defined and implemented for the BO can be used.
  •  Only determinations defined with on save can be assigned.
Optimized draft action ACTIVATE

Without further measures, the validations and determinations assigned to draft determine action PREPARE are executed twice when you activate a draft instance: Once on the draft instance before it is copied to the active instance (as part of the PREPARE action). Then again before the active data is stored on the database (as part of the usual save implementation). Most of the time this second execution is redundant because the data does not change between the two executions.

It is recommended that you define draft action ACTIVATE with the optimized addition. The optimized addition speeds up the activation of draft instances considerably by avoiding the redundant executions of validations and determinations.

Caution

It is an important prerequisite for addition optimized, that the validations and determinations handle draft and active instances identically.

Transition Messages and State Messages

State Messages and Transition Messages

 Transition MessageState Message
Refers toTrigger requestBO instance and data
Definition%state_area initial%state_area not initial
Binding

Entity Instance or general

Always Entity Instance
LifetimeWhile displayedUntil BO state changes
Visualization with Draft

Pop-up message, no highlighting of fields

Pop-over message, highlight related fields (if any)

Visualization without Draft

Pop-over message, highlight related fields (if any)

The RAP framework distinguishes Transition Messages and State Messages. While transition messages refer to a triggered request, state messages refer to a business object instance and its values. A typical example for a transition message could be "Business Object is locked by user &1", which relates to a triggered request (Edit) and to an (unsuccessful) transition from display to edit mode. A typical example for a state message could be "The order date &1 lies in the past" which relates to an invalid value in a field and an inconsistent state of the business object instance.

You define a state message by filling the %state_area component in the REPORTED structure with a non initial string value. Messages with initial%state_area component are treated as transition messages.

Note

As we did not set the %state_area value, yet. All our messages so-far were transition messages.

Transition messages can either be bound to a BO entity instance or be more general. That is, entered in component %others of the REPORTED structure. State messages must always be bound to an entity instance. They are not supported in the %others component.

The most important difference between state messages and transition messages is the message lifetime and the UI visualization in draft scenarios.

In draft scenarios, a transition message appears as a pop-up message and is gone once the pop-up window is closed.

State messages are displayed in a message pop-over until the state of the business object changes. If a message is assigned to a field in %ELEMENT, the respective field is framed in the severity color to illustrate the link between the field values and a message to improve the user experience. For a business object with draft capabilities, state messages are persisted until the state that caused the message is changed. And in a managed scenario, the messages are buffered until the end of the session.

Note

In non draft scenarios, SAP Fiori makes no difference in the visualization of transition messages and state messages.

Example of transition message in draft-enabled SAP Fiori apps

The example shows the display of a transition message in a draft-enabled SAP Fiori application. The message is displayed in a pop-up window that blocks the application until closed by the user. When closing the window, the messages are deleted. Even though the message is connected to a field, because the application logic reported it with a non initial structure %element, this connection is not visualized. There is a no link to navigate from the message to the field nor is the field highlighted, for example, with a red border.

State message in draft-enabled SAP Fiori apps

This next example shows the display of the same message, but this time the message was reported as a state message during the draft determine action PREPARE.

The message is displayed in a pop-over window that does not block the application. The user can close the window but this does not delete the message. The connection to the assigned field is visualized by a navigation link on the message text and a red border to highlight the field.

Steps to Create and delete state messages

A message becomes a state message when the %state_area component in the REPORTED structure is filled with a non initial value. You can choose any string value but it is recommended that you stick to ASCII characters.

In draft scenarios, state messages reported during draft determine action PREPARE are persisted with the draft data and, in managed scenarios, they are buffered until the end of the session. If the same request, for example, a validation, is triggered multiple times on the same instance, the same messages are added to the message table again and again. To avoid this, you have to delete state messages explicitly.

In managed scenarios, it is sufficient to add a special row to the related component of REPORTED. This row only contains a value for the key (%tky) of the entity instance and the state area ID (%state_area). All other components like %msg, %element, and so on, remain initial. With this entry, you make the framework delete all messages of the same state area for the specified entity instance.

Note

In unmanaged scenarios, more coding is needed in the implementation of the DELETE operation, to make sure that the related state messages are removed when deleting a draft instance.

The value for %state_area is used to group state messages that are related and should be invalidated together. The value is not displayed on the UI and it is not contained in the OData metadata.

For the sake of readability, we recommend choosing a name that uniquely identifies the condition that the message originates from. For example, if a validation checks if a description is valid, the %state_area value "Invalid_Customer" can be helpful in characterizing the condition because of which the validation failed. Alternatively, you can choose the name of the operation a message is thrown in as %state_area, for example "ValidateCustomer".

Hint

Define constants for the state area IDs to avoid typos and to facilitate refactoring.

Implementation Aspects of Draft

An additional component %IS_DRAFT, used to distinguish between active instances and draft instances

For a draft-enabled business object, the derived types for its entities contain an additional component %IS_DRAFT that is used to distinguish between active instances and draft instances. The field is of binary type abp_behv_flag. Allowed values are the components of constant structure if_abap_bhev=>mk. The value of %is_draft equals the value of mk-on ( = 01 in hexadecimal writing) for draft instances and mk-off (= 00) for active instances.

The example shows screenshots from the table display tool in the ABAP debugger.

For edit drafts, the primary key fields have the same values as in the active instance. The %is_draft field is the only way to distinguish between draft and active data.

Because of this, %is_draft must be treated like an additional key field that is mandatory when accessing data via EML and in RAP implementations. The framework supports this by automatically including component %is_draft in the %tky field group.

The component groups %tky and %key

If you therefore use %tky to address the primary key of an entity, you do not have to change your business logic implementation when draft-enabling the business object. The business functionality runs smoothly without adapting your code after draft-enabling your business object.

If you use field group %key in your business logic implementation, or addressed the key fields directly via their individual component names, you have to revise the implementation when draft-enabling the business object.

Note

The recommendation is to only use %tky in your business logic implementation, unless you want to read the active instance for a draft instance.

An example of feature control for draft instance

In the behavior implementation for a draft-enabled business object, import parameter keys always contains the technical key fields and the draft indicator %is_draft. When you use component group %tky to set up the input for a READ ENTITIES statement, you read draft data for draft instances and active data for active instances.

However, there can be situations where it becomes necessary to evaluate the active data for a draft instance and not the draft data itself. A good example is the implementation of instance feature control.

Let’s consider a flight travel that becomes read-only when the travel end date lies in the past. When feature control is based on the draft data, the draft becomes read-only when the user changes the end date in the draft. If this change was done accidentally, the user has no chance to undo it in the current edit process. The only remaining option is to cancel the draft and start editing again. But if feature control is based on the active instance, the draft data remain editable until the active data is updated.

To read the related active data for draft instance, use the %key field group instead of %tky and setting the draft indicator %is_draft explicitly.

Note

For readability reasons, we recommend to the draft indicator to if_abap_behv=>mk-off instead of leaving it initial, even though the result is the same.