Add BO-enhancements (Virtual Elements) using RAP Cloud Environment
Desarrollo de ampliaciones con código de cliente en una aplicación en ABAP RAP en Ambiente Cloud (Virtual Elements).
Objetivo
Adecuar una aplicación CRUD para añadir ampliaciones a lógica de negocio o código de cliente, con el modelo RestFul Application programming model en Eclipse utilizando ABAP Development Tools.
Prerequisitos
- Desarrollo de un servicio OData para una aplicación FIORI (Managed).
- Añadir lógica de negocio a una aplicación ABAP RAP ambienteCloud.
- Añadir una entidad al modelo de datos de una aplicación ABAP RAP ambiente Cloud.
Cuando desarrollamos una aplicación por lo regular tenemos algunos datos que se calculan en tiempo de ejecución, es decir, no se graban en tablas pero es necesario mostrarlos en pantalla.
Pasos
- Añadir el virtual element y su correspondiente anotación en la definición del projection.
- Crear la clase ABAP para implementar el cálculo del elemento virtual.
- Ajusta anotación en el metadata del Travel.
- Visualizar la Aplicación (Preview).
1.- Añadir el elemento virtual al projection view.
Agregamos el siguiente código al projection view de Travel.
El código queda de la siguiente manera.
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
@EndUserText.label: '##GENERATED Travel App (DEV_100)'
@Search.searchable: true
@ObjectModel.semanticKey: ['TravelID'] //case-sensitive
define root view entity ZC_RAP100_TRAVEL_M
provider contract transactional_query
as projection on ZR_RAP100_TRAVEL_M
{
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.90
key TravelID,
@Search.defaultSearchElement: true
@ObjectModel.text.element: ['AgencyName'] //case-sensitive
@Consumption.valueHelpDefinition: [{ entity : {name: '/DMO/I_Agency_StdVH', element: 'AgencyID' },
useForValidation: true }]
AgencyID,
_Agency.Name as AgencyName,
@Search.defaultSearchElement: true
@ObjectModel.text.element: ['CustomerName'] //case-sensitive
@Consumption.valueHelpDefinition: [{ entity : {name: '/DMO/I_Customer_StdVH', element: 'CustomerID' },
useForValidation: true }]
CustomerID,
_Customer.LastName as CustomerName,
BeginDate,
EndDate,
BookingFee,
TotalPrice,
@Consumption.valueHelpDefinition: [{ entity: {name: 'I_CurrencyStdVH', element: 'Currency' },
useForValidation: true }]
CurrencyCode,
Description,
@ObjectModel.text.element: ['OverallStatusText'] //case-sensitive
@Consumption.valueHelpDefinition: [{ entity: {name: '/DMO/I_Overall_Status_VH', element: 'OverallStatus' },
useForValidation: true }]
OverallStatus,
_OverallStatus._Text.Text as OverallStatusText : localized,
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZRAPDEV_CALC_TRAV_ELEM_100'
@EndUserText.label: 'Overall Status Indicator'
virtual OverallStatusIndicator : abap.int2,
Attachment,
MimeType,
FileName,
LocalLastChangedAt,
// public associations
_Booking : redirected to composition child ZC_RAP100_BOOK_M,
_Agency,
_Customer,
_OverallStatus,
_Currency
}
Grabar (Ctrl+S) y (después de implementar la clase) Activar (CTRL+F3).
2.- Implementar la clase para el calculo del Virtual Element.
Crear a clase a implementar.
Seleccionar el paquete de la aplicación.
En el menú contextual seleccionar la opción New -> ABAP Class
Capturar el nombre y una descripción de la clase especificada en el projection para el campo virtual.
Presionar Next.
Seleccionar un Transport Request. Presionar Finish.
Implementar el siguiente código en la clase creada.
CLASS zrapdev_calc_trav_elem_100 DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
* interfaces IF_SADL_EXIT .
INTERFACES if_sadl_exit_calc_element_read .
CLASS-METHODS:
calculate_trav_status_ind
IMPORTING is_original_data TYPE ZC_RAP100_TRAVEL_M
RETURNING VALUE(result) TYPE ZC_RAP100_TRAVEL_M.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zrapdev_calc_trav_elem_100 IMPLEMENTATION.
METHOD if_sadl_exit_calc_element_read~calculate.
IF it_requested_calc_elements IS INITIAL.
EXIT.
ENDIF.
LOOP AT it_requested_calc_elements ASSIGNING FIELD-SYMBOL(<fs_req_calc_elements>).
CASE <fs_req_calc_elements>.
"virtual elements from TRAVEL entity
WHEN 'OVERALLSTATUSINDICATOR'.
DATA lt_trav_original_data TYPE STANDARD TABLE OF ZC_RAP100_TRAVEL_M WITH DEFAULT KEY.
lt_trav_original_data = CORRESPONDING #( it_original_data ).
LOOP AT lt_trav_original_data ASSIGNING FIELD-SYMBOL(<fs_trav_original_data>).
<fs_trav_original_data> = zrapdev_calc_trav_elem_100=>calculate_trav_status_ind( <fs_trav_original_data> ).
ENDLOOP.
ct_calculated_data = CORRESPONDING #( lt_trav_original_data ).
ENDCASE.
ENDLOOP.
ENDMETHOD.
METHOD if_sadl_exit_calc_element_read~get_calculation_info.
IF iv_entity EQ 'ZC_RAP100_TRAVEL_M'. "Travel BO node
LOOP AT it_requested_calc_elements ASSIGNING FIELD-SYMBOL(<fs_travel_calc_element>).
CASE <fs_travel_calc_element>.
WHEN 'OVERALLSTATUSINDICATOR'.
APPEND 'OVERALLSTATUS' TO et_requested_orig_elements.
ENDCASE.
ENDLOOP.
ENDIF.
ENDMETHOD.
METHOD calculate_trav_status_ind.
result = CORRESPONDING #( is_original_data ).
"travel status indicator
"(criticality: 1 = red | 2 = orange | 3 = green)
CASE result-OverallStatus.
WHEN 'X'.
result-OverallStatusIndicator = 1.
WHEN 'O'.
result-OverallStatusIndicator = 2.
WHEN 'A'.
result-OverallStatusIndicator = 3.
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
ENDCLASS.
Grabar (Ctrl+S) y Activar (CTRL+F3).
3.- Ajustar la anotación en el Metadata Extensión del Travel.
Ajustamos la anotación para que muestre un icono de criticalidad de acuerdo al estatus calculado.
@Metadata.layer: #CUSTOMER
@UI: {
headerInfo: {
typeName: 'Travel',
typeNamePlural: 'Travels',
imageUrl: 'Attachment', //case-sensitive
description: { type: #STANDARD, value: 'TravelID' } //case-sensitive
}
}
annotate view ZC_RAP100_TRAVEL_M with
{
@UI.facet: [ {
id: 'idCollection',
type: #COLLECTION,
label: 'Travel',
position: 10
},
{
id: 'idIdentification',
parentId: 'idCollection',
type: #IDENTIFICATION_REFERENCE,
label: 'General Information',
position: 10
},
{
id: 'idLineitem',
type: #LINEITEM_REFERENCE,
label: 'Booking',
position: 20 ,
targetElement: '_Booking'
} ]
@UI.lineItem: [
{ position: 10 , importance: #HIGH }
,{ type: #FOR_ACTION, dataAction: 'copyTravel', label: 'Copy Travel' }
,{ type: #FOR_ACTION, dataAction: 'acceptTravel', label: 'Accept Travel' }
,{ type: #FOR_ACTION, dataAction: 'rejectTravel', label: 'Reject Travel' }
]
@UI.identification: [
{ position: 10 , importance: #HIGH }
,{ type: #FOR_ACTION, dataAction: 'deductDiscount', label: 'Deduct Discount' }
,{ type: #FOR_ACTION, dataAction: 'acceptTravel', label: 'Accept Travel' }
,{ type: #FOR_ACTION, dataAction: 'rejectTravel', label: 'Reject Travel' }
]
@UI.selectionField: [ {
position: 10
} ]
TravelID;
@UI: {
lineItem: [ { position: 20, importance: #HIGH } ],
identification: [ { position: 20 } ],
selectionField: [ { position: 20 } ]
}
AgencyID;
@UI: {
lineItem: [ { position: 30, importance: #HIGH } ],
identification: [ { position: 30 } ],
selectionField: [ { position: 30 } ]
}
CustomerID;
@UI: {
lineItem: [ { position: 40, importance: #MEDIUM } ],
identification: [ { position: 40 } ]
}
BeginDate;
@UI: {
lineItem: [ { position: 50, importance: #MEDIUM } ],
identification: [ { position: 50 } ]
}
EndDate;
@UI.identification: [ { position: 60 } ]
BookingFee;
@UI.identification: [ { position: 70 } ]
TotalPrice;
@UI.identification: [ { position: 90 } ]
Description;
@UI.lineItem: [ {
position: 100 ,
importance: #HIGH
,criticality: 'OverallStatusIndicator'
} ]
@UI.identification: [ {
position: 100
,criticality: 'OverallStatusIndicator'
} ]
@UI.textArrangement: #TEXT_ONLY
OverallStatus;
@UI.identification: [ { position: 110 } ]
Attachment;
@UI.hidden: true
MimeType;
@UI.hidden: true
FileName;
@UI.hidden: true
LocalLastChangedAt;
}
4.- Visualizar la aplicación.
Seleccionar el Service Binding de la aplicación.
Presionar el botón Preview.
Presionar el botón Go.
Aparece la criticalidad en el campo de Estatus de acuerdo al valor del elemento virtual.
Continua…
Agregar Internal Actions a la aplicación creada.
Add BO-enhancements (Internal Actions) using RAP Cloud Environment