Tutoriel RAP Partie 2 : Fonctionnalités avancées - Actions, Validations et Determinations

Catégorie
Tutorial
Publié
Auteur
Johannes

Bienvenue dans la Partie 2 de la série de tutoriels RAP ! Dans la Partie 1, vous avez créé une application Fiori fonctionnelle. Maintenant, nous allons la rendre vraiment intelligente avec de la logique métier.

Ce que vous allez apprendre

  • Actions : Boutons personnalisés pour les opérations métier
  • Validations : Vérification des données (ex. format ISBN)
  • Determinations : Définir automatiquement des valeurs
  • Value Helps : Listes déroulantes
  • Feature Control : Afficher/masquer dynamiquement des boutons

Base : Nous construisons sur l’application Book Management de la Partie 1.

Temps estimé : 45-60 minutes


Prérequis

  • Partie 1 terminée
  • L’application Book Management fonctionne
  • ADT (Eclipse) ouvert

Fonctionnalité 1 : Gestion du statut avec Actions

Nous ajoutons un Status (Nouveau, En lecture, Terminé) et des Actions pour changer le statut.

Étape 1 : Étendre la table

Ouvrez ZBOOK_TAB et ajoutez :

define table zbook_tab {
// ... champs existants ...
status : abap.char(1); // N=Nouveau, R=En lecture, F=Terminé
// ... created_by, etc. ...
}

Activer : Ctrl+F3

Étape 2 : Étendre les CDS Views

Dans ZI_BOOK :

define root view entity ZI_BOOK
as select from zbook_tab
{
// ... champs existants ...
status as Status,
// Texte du statut via Association
case status
when 'N' then 'Nouveau"
when 'R' then 'En lecture"
when 'F' then 'Terminé"
else 'Inconnu"
end as StatusText,
// ... created_by, etc. ...
}

Dans ZC_BOOK :

define root view entity ZC_BOOK
as projection on ZI_BOOK
{
// ... champs existants ...
@ObjectModel.text.element: ['StatusText']
Status,
StatusText,
// ... created_by, etc. ...
}

Activer les deux !

Étape 3 : Étendre la Behavior Definition - Ajouter des Actions

Ouvrez la BDEF Interface (ZI_BOOK -> Behavior Definition) :

managed implementation in class zbp_i_book unique;
strict ( 2 );
define behavior for ZI_BOOK alias Book
persistent table zbook_tab
lock master
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
field ( readonly ) BookId;
field ( readonly ) CreatedBy, CreatedAt, LastChangedBy, LastChangedAt;
field ( numbering : managed ) BookId;
// NOUVEAU : Actions avec Feature Control
action ( features : instance ) startReading result [1] $self;
action ( features : instance ) markAsFinished result [1] $self;
action ( features : instance ) resetStatus result [1] $self;
// NOUVEAU : Validation à la sauvegarde
validation validateIsbn on save { field Isbn; }
validation validatePages on save { field Pages; }
// NOUVEAU : Determination à la création
determination setDefaultStatus on modify { create; }
mapping for zbook_tab
{
BookId = book_id;
Title = title;
Author = author;
Publisher = publisher;
Isbn = isbn;
Price = price;
CurrencyCode = currency_code;
Pages = pages;
PublicationYear = publication_year;
Language = language;
Status = status; // NOUVEAU
CreatedBy = created_by;
CreatedAt = created_at;
LastChangedBy = last_changed_by;
LastChangedAt = last_changed_at;
}
}

Activer : Ctrl+F3

Étape 4 : Étendre la Projection BDEF

Ouvrez la Behavior Definition de ZC_BOOK :

projection;
strict ( 2 );
define behavior for ZC_BOOK alias Book
{
use create;
use update;
use delete;
// NOUVEAU : Exposer les Actions
use action startReading;
use action markAsFinished;
use action resetStatus;
}

Activer !

Étape 5 : Behavior Implementation - Implémenter les Actions

ADT a automatiquement créé ZBP_I_BOOK. Ouvrez la classe et ajoutez :

Local Types (à la fin de la classe) :

CLASS lhc_book DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS:
" Feature Control (quelles Actions sont disponibles ?)
get_instance_features FOR INSTANCE FEATURES
IMPORTING keys REQUEST requested_features FOR Book
RESULT result,
" Actions
startReading FOR MODIFY
IMPORTING keys FOR ACTION Book~startReading
RESULT result,
markAsFinished FOR MODIFY
IMPORTING keys FOR ACTION Book~markAsFinished
RESULT result,
resetStatus FOR MODIFY
IMPORTING keys FOR ACTION Book~resetStatus
RESULT result,
" Validations
validateIsbn FOR VALIDATE ON SAVE
IMPORTING keys FOR Book~validateIsbn,
validatePages FOR VALIDATE ON SAVE
IMPORTING keys FOR Book~validatePages,
" Determinations
setDefaultStatus FOR DETERMINE ON MODIFY
IMPORTING keys FOR Book~setDefaultStatus.
ENDCLASS.
CLASS lhc_book IMPLEMENTATION.
" ===== FEATURE CONTROL =====
METHOD get_instance_features.
" Lire les livres actuels
READ ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_books)
FAILED failed.
" Feature Control basé sur le Status
result = VALUE #( FOR ls_book IN lt_books
( %tky = ls_book-%tky
" startReading : Disponible uniquement si Status = 'N' (Nouveau)
%features-%action-startReading = COND #(
WHEN ls_book-Status = 'N' THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" markAsFinished : Disponible uniquement si Status = 'R' (En lecture)
%features-%action-markAsFinished = COND #(
WHEN ls_book-Status = 'R' THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" resetStatus : Toujours disponible sauf pour 'N"
%features-%action-resetStatus = COND #(
WHEN ls_book-Status <> 'N' THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
)
).
ENDMETHOD.
" ===== ACTIONS =====
METHOD startReading.
" Mettre le Status à 'R' (En lecture)
MODIFY ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
UPDATE FIELDS ( Status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
Status = 'R' ) )
FAILED failed
REPORTED reported.
" Retourner les livres mis à jour
READ ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT result.
ENDMETHOD.
METHOD markAsFinished.
" Mettre le Status à 'F' (Terminé)
MODIFY ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
UPDATE FIELDS ( Status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
Status = 'F' ) )
FAILED failed
REPORTED reported.
READ ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT result.
ENDMETHOD.
METHOD resetStatus.
" Remettre le Status à 'N' (Nouveau)
MODIFY ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
UPDATE FIELDS ( Status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
Status = 'N' ) )
FAILED failed
REPORTED reported.
READ ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT result.
ENDMETHOD.
" ===== VALIDATIONS =====
METHOD validateIsbn.
" Lire les livres
READ ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
FIELDS ( Isbn )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_books).
LOOP AT lt_books INTO DATA(ls_book).
" L'ISBN doit avoir 10 ou 13 caractères
DATA(lv_isbn_length) = strlen( ls_book-Isbn ).
IF lv_isbn_length <> 10 AND lv_isbn_length <> 13.
APPEND VALUE #(
%tky = ls_book-%tky
%element-Isbn = if_abap_behv=>mk-on
) TO failed-book.
APPEND VALUE #(
%tky = ls_book-%tky
%element-Isbn = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'L''ISBN doit avoir 10 ou 13 caractères"
)
) TO reported-book.
ENDIF.
" L'ISBN ne doit contenir que des chiffres (vérification simplifiée)
IF ls_book-Isbn IS NOT INITIAL AND
ls_book-Isbn CO '0123456789' = abap_false.
APPEND VALUE #(
%tky = ls_book-%tky
%element-Isbn = if_abap_behv=>mk-on
) TO failed-book.
APPEND VALUE #(
%tky = ls_book-%tky
%element-Isbn = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'L''ISBN ne doit contenir que des chiffres"
)
) TO reported-book.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD validatePages.
READ ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
FIELDS ( Pages )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_books).
LOOP AT lt_books INTO DATA(ls_book).
" Le nombre de pages doit être > 0
IF ls_book-Pages IS NOT INITIAL AND ls_book-Pages <= 0.
APPEND VALUE #(
%tky = ls_book-%tky
%element-Pages = if_abap_behv=>mk-on
) TO failed-book.
APPEND VALUE #(
%tky = ls_book-%tky
%element-Pages = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Le nombre de pages doit être supérieur à 0"
)
) TO reported-book.
ENDIF.
ENDLOOP.
ENDMETHOD.
" ===== DETERMINATIONS =====
METHOD setDefaultStatus.
" Lire les livres nouvellement créés
READ ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_books).
" Définir le Status par défaut à 'N' (Nouveau)
MODIFY ENTITIES OF zi_book IN LOCAL MODE
ENTITY Book
UPDATE FIELDS ( Status )
WITH VALUE #( FOR ls_book IN lt_books
WHERE ( Status IS INITIAL )
( %tky = ls_book-%tky
Status = 'N' ) )
REPORTED reported.
ENDMETHOD.
ENDCLASS.

Activer : Ctrl+F3

Étape 6 : UI-Annotations pour les Actions

Ouvrez la Metadata Extension (ZC_BOOK) :

@Metadata.layer: #CORE
annotate view ZC_BOOK with
{
@UI.headerInfo: {
typeName: 'Livre',
typeNamePlural: 'Livres',
title: { value: 'Title' },
description: { value: 'Author' }
}
@UI.facet: [
{
id: 'BookDetails',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Détails du livre',
position: 10
}
]
// NOUVEAU : Actions dans la liste
@UI.lineItem: [
{ position: 10, importance: #HIGH },
{ type: #FOR_ACTION, dataAction: 'startReading', label: 'Commencer la lecture' },
{ type: #FOR_ACTION, dataAction: 'markAsFinished', label: 'Marquer comme terminé' },
{ type: #FOR_ACTION, dataAction: 'resetStatus', label: 'Réinitialiser le statut' }
]
@UI.identification: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
BookId;
@UI.lineItem: [{ position: 20, importance: #HIGH }]
@UI.identification: [{ position: 20 }]
@UI.selectionField: [{ position: 20 }]
Title;
@UI.lineItem: [{ position: 30, importance: #HIGH }]
@UI.identification: [{ position: 30 }]
@UI.selectionField: [{ position: 30 }]
Author;
@UI.lineItem: [{ position: 40 }]
@UI.identification: [{ position: 40 }]
Publisher;
@UI.identification: [{ position: 50 }]
Isbn;
@UI.lineItem: [{ position: 50 }]
@UI.identification: [{ position: 60 }]
Price;
@UI.identification: [{ position: 70 }]
Pages;
@UI.lineItem: [{ position: 60 }]
@UI.identification: [{ position: 80 }]
PublicationYear;
@UI.identification: [{ position: 90 }]
Language;
// NOUVEAU : Afficher le Status
@UI.lineItem: [{ position: 35, importance: #HIGH, criticality: 'Status' }]
@UI.identification: [{ position: 35 }]
@UI.selectionField: [{ position: 40 }]
Status;
}

Activer !

Étape 7 : Republier le Service Binding

  1. Ouvrir ZUI_BOOK_O4 (Service Binding)
  2. Cliquer sur Unpublish
  3. Cliquer sur Publish

Étape 8 : Tester !

  1. Ouvrir Preview
  2. Créer un livre
  3. Les boutons apparaissent :
    • “Commencer la lecture” (uniquement si Status = Nouveau)
    • “Marquer comme terminé” (uniquement si Status = En lecture)
    • “Réinitialiser le statut” (pas pour Nouveau)

Essayez :

  • Cliquez sur “Commencer la lecture” -> Le statut passe à “En lecture”
  • Maintenant “Marquer comme terminé” apparaît
  • Tester la validation : Entrez un ISBN avec des lettres -> Erreur !

Fonctionnalité 2 : Value Help (Liste déroulante pour le Status)

Actuellement, le statut doit être saisi manuellement. Mieux : Liste déroulante avec sélection !

Étape 1 : Créer des valeurs fixes de domaine

Dans la Metadata Extension ZC_BOOK :

annotate view ZC_BOOK with
{
// ... autres champs ...
@UI.lineItem: [{ position: 35, importance: #HIGH }]
@UI.identification: [{ position: 35 }]
@UI.selectionField: [{ position: 40 }]
@Consumption.valueHelpDefinition: [{
entity: { name: 'I_Status_VH', element: 'StatusCode' }
}]
Status;
}

Mieux : Value Help personnalisée via CDS View

Créez une nouvelle Data Definition ZI_BOOK_STATUS_VH :

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Value Help pour le statut du livre"
define view entity ZI_BOOK_STATUS_VH
as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T(
p_domain_name: 'ZBOOK_STATUS"
)
{
@ObjectModel.text.element: ['Description']
key domain_name as DomainName,
key value_position as ValuePosition,
@Semantics.language: true
key language as Language,
value_low as StatusCode,
text as Description
}

Alternative : Version plus simple sans domaine

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Book Status Value Help"
define view entity ZI_BOOK_STATUS_VH
as select from I_Language
{
key 'N' as StatusCode,
cast( 'Nouveau' as abap.char(20) ) as StatusText
}
union select from I_Language
{
key 'R' as StatusCode,
cast( 'En lecture' as abap.char(20) ) as StatusText
}
union select from I_Language
{
key 'F' as StatusCode,
cast( 'Terminé' as abap.char(20) ) as StatusText
}

Activer et référencer dans la Metadata Extension :

@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_BOOK_STATUS_VH', element: 'StatusCode' }
}]
Status;

Ce que nous avons appris

Actions

  • Définition : action startReading result [1] $self;
  • Feature Control : Rendre les boutons disponibles dynamiquement
  • Implémentation : MODIFY ENTITIES pour changer le statut
  • UI : Afficher les Actions dans @UI.lineItem

Validations

  • Quand : on save (avant sauvegarde) ou on modify (immédiatement)
  • Vérifier les champs : Format ISBN, nombre de pages > 0
  • Signaler les erreurs : Remplir failed + reported
  • UI : Champs marqués en rouge, message d’erreur affiché

Determinations

  • Quand : on modify { create; } (à la création)
  • Objectif : Définir des valeurs par défaut (ex. Status = ‘N’)
  • Implémentation : MODIFY ENTITIES pour définir

Feature Control

  • Boutons dynamiques : Basés sur les données (ex. Status)
  • Méthode : get_instance_features
  • Logique : if_abap_behv=>fc-o-enabled vs. disabled

Prochaines étapes

Dans la Partie 3 : Bonnes pratiques :

  • Optimisation des performances (Performance SELECT, EML Batching)
  • Gestion des erreurs et Logging
  • Tests unitaires pour RAP
  • Déploiement et versioning
  • Éviter les erreurs courantes

Aperçu du code

Objets nouveaux/modifiés :

  • ZBOOK_TAB (champ Status ajouté)
  • ZI_BOOK (Status, StatusText)
  • ZC_BOOK (exposer Status)
  • BDEF Interface (Actions, Validations, Determinations)
  • BDEF Projection (exposer les Actions)
  • ZBP_I_BOOK (Implémentation)
  • Metadata Extension (UI-Annotations pour les Actions)

Des questions ?

  • Les Actions fonctionnent-elles ?
  • Les Validations s’affichent-elles correctement ?
  • Quelle logique métier souhaiteriez-vous ajouter ?

Continuez avec la Partie 3 : Bonnes pratiques ->