Coffee Subscription

Étude de cas — SAP ABAP RAP (Managed, Draft, OData V4, Fiori Elements)

RAP CDS BDEF Draft Validations Determinations OData V4 ADT
Navigation rapide

Contexte métier & étude de cas

Ce projet s’inscrit dans ma montée en compétence sur RAP, menée en parallèle de mes missions. L’objectif est de simuler un cas proche de la production, avec une architecture robuste, des règles métier claires, une UI Fiori propre et un parcours de debug réaliste. Le tout en respectant les bonnes pratiques SAP pour un delivery propre et maintenable.

Ce que démontre ce projet
  • Capacité à concevoir un objet métier complet en RAP
  • Compréhension du lien métier ↔ technique
  • Maîtrise des concepts clés (draft, validations, determinations)
  • Démarche proche d’un projet de production

Cas métier simulé — Coffee Subscription

L’application Coffee Subscription simule un cas métier réaliste de gestion d’abonnements, inspiré de scénarios fréquemment rencontrés en production (abonnements clients, contrats récurrents, services à fréquence définie).

Le principe est volontairement simple et représentatif : un client peut souscrire à un abonnement de café en choisissant un type de café, une fréquence de livraison et un statut de souscription. Ces informations sont ensuite gérées tout au long du cycle de vie de l’abonnement : création, modification, validation et activation.

D’un point de vue métier, ce cas est directement comparable à :

  • des abonnements de services (SaaS, maintenance, contrats récurrents),
  • des contrats clients avec règles de gestion spécifiques,
  • ou plus largement à des objets métiers critiques nécessitant un pilotage fin de leur cycle de vie.

Ce projet m’a permis de reproduire des problématiques proches de la production, notamment :

  • le contrôle des données à la création et à la modification,
  • la gestion des états via le mode draft,
  • des validations métier bloquantes,
  • des déterminations automatiques,
  • et l’exposition d’une UI Fiori cohérente et guidée pour l’utilisateur final.

L’objectif n’était pas de réaliser une simple application “démo”, mais bien de concevoir une architecture propre, extensible et maintenable, alignée avec les bonnes pratiques SAP RAP, dans une logique proche d’un contexte projet réel.

Architecture

Schéma d’architecture Coffee Subscription
Voir explication
L’architecture de l’application repose sur le modèle RAP Managed, qui permet de séparer clairement les responsabilités entre les données, le comportement métier et l’interface utilisateur.
Les tables de persistance stockent les données actives et les données draft. Les CDS Interface Views (ZI) définissent le modèle sémantique et les relations métier. Les CDS Projection Views (ZC) exposent uniquement les champs nécessaires à l’UI et portent les annotations Fiori.
Le Behavior Definition (BDEF) centralise les règles transactionnelles : création, modification, suppression, validations, déterminations et actions. Le Service Definition et le Service Binding OData V4 exposent ensuite ces objets à l’interface.
Enfin, l’UI Fiori Elements est générée automatiquement à partir des métadonnées, garantissant une application cohérente, maintenable et alignée avec les standards SAP.
Cette architecture est extensible et proche d’un contexte projet réel, tout en facilitant les évolutions fonctionnelles et techniques.

Artefacts ADT

Type Exemple Rôle
Tables ZCS_SUB_TRL, ZCS_SUB_TRL_D Persistence + draft
CDS Interface ZI_COFFEE_SUB_TRL Modèle métier
CDS Projection ZC_COFFEE_SUB_TRL, ZC_*_VH Exposition UI
Behavior ZBP_I_COFFEE_SUB_TRL Règles et draft
Service ZUI_COFFEE_SUB_TRL + Binding O4 OData V4

Chronologie

1. Tables

Objectif : structurer la persistence et le draft.

Capture ADT des tables
Voir explication
🗄️ Rôle des tables dans l’architecture RAP
Dans une architecture SAP RAP, les tables jouent le rôle de socle de persistance, mais leur utilisation est plus structurée que dans un développement ABAP classique.
Une table de persistance stocke les données actives de l’objet métier (abonnements validés). Une table draft associée permet de gérer les modifications temporaires tant que l’utilisateur n’a pas encore validé l’enregistrement.
Cette séparation est essentielle pour offrir une expérience utilisateur guidée et sécurisée, sans impacter les données actives tant que les règles métier ne sont pas respectées.
🔁 Comparaison avec l’ABAP classique
En ABAP classique, les données sont généralement écrites directement en base lors du SAVE, et la gestion des états intermédiaires repose sur :
  • des tables Z temporaires,
  • des flags de statut,
  • ou une logique applicative complexe.
En RAP, cette gestion est nativement prise en charge par le framework grâce au mécanisme draft, ce qui :
  • réduit la complexité du code,
  • améliore la robustesse transactionnelle,
  • et standardise le comportement de l’application.
🎯 Position dans l’architecture RAP
Les tables constituent le point de départ du flux RAP :
  • elles alimentent les CDS Interface Views (ZI),
  • qui sont ensuite projetées vers l’UI,
  • et manipulées via le Behavior Definition.
Ce modèle garantit une séparation claire entre données, logique métier et interface, alignée avec les bonnes pratiques SAP modernes.
2. CDS

Objectif : modéliser ZI et projections ZC.

Capture ADT des CDS
Voir explication
📐 CDS Interface & CDS Projection dans l’architecture RAP
🔹 CDS Interface View (ZI_*)
Les CDS Interface Views représentent le modèle sémantique central de l’objet métier dans une architecture RAP.
Elles sont directement construites au-dessus des tables de persistance et de draft, et définissent :
  • la structure métier,
  • les relations (associations),
  • les clés,
  • et les aspects sémantiques (types, unités, statuts).
Les vues ZI constituent une base stable et indépendante de l’UI, pensée pour être réutilisable et extensible dans le temps.
Rôle clé
La CDS Interface est la source de vérité métier : elle décrit ce qu’est l’objet, sans se soucier de comment il est affiché.
🔹 CDS Projection View (ZC_*)
Les CDS Projection Views exposent une vue contrôlée et orientée UI de l’objet métier.
Elles permettent de :
  • sélectionner les champs réellement nécessaires à l’application,
  • masquer la complexité du modèle interne,
  • et adapter l’exposition selon le contexte fonctionnel.
Annotations UI & métadonnées
Les annotations UI (lineItem, identification, selectionFields, etc.) sont portées au niveau des projections afin de :
  • définir le comportement de l’UI Fiori,
  • structurer les listes et les pages objet,
  • guider l’utilisateur dans la saisie et la navigation.
🧩 Metadata Extensions
Les Metadata Extensions permettent de séparer le modèle de données des annotations UI. Cette approche :
  • améliore la lisibilité du code,
  • facilite la maintenance,
  • permet des adaptations UI sans toucher au cœur du modèle CDS.
C’est une bonne pratique essentielle dans les projets RAP structurés.
🔀 Value Helps (VH)
Les Value Helps sont généralement implémentées via :
  • des CDS dédiées (Projection ou VH),
  • associées aux champs concernés dans la CDS Projection.
Elles permettent :
  • de sécuriser la saisie utilisateur,
  • de proposer des valeurs cohérentes,
  • et de standardiser l’expérience Fiori.
Dans RAP, les VH sont intégrées nativement au modèle, sans logique UI spécifique.
🎯 Position dans l’architecture RAP
Ensemble, les CDS Interface et Projection forment le cœur du modèle RAP :
  • ZI : définition métier stable et réutilisable
  • ZC : exposition maîtrisée et orientée UI
  • Annotations & Extensions : pilotage du comportement Fiori
Cette séparation permet une architecture propre, évolutive et alignée avec les standards SAP, tout en facilitant les extensions futures.
3. Service Binding

Objectif : exposer l’API OData V4.

Capture ADT du service binding
Voir explication
🔗 Service Definition & Service Binding dans RAP
🔹 Service Definition
La Service Definition définit le contrat d’exposition de l’objet métier RAP.
Elle permet de sélectionner précisément quelles entités (projections CDS) sont exposées à l’extérieur, sans impacter le modèle interne.
Son rôle est comparable à une API contractuelle : elle garantit une interface stable entre le backend et les consommateurs (UI ou services externes).
Points clés
  • Exposition contrôlée des entités RAP
  • Séparation claire entre modèle interne et surface exposée
  • Préparation à une consommation UI ou intégration future
🔹 Service Binding (OData V4)
Le Service Binding est l’étape finale qui rend l’objet RAP consommable.
Il lie la Service Definition à un protocole concret, généralement OData V4, et génère :
  • le service technique,
  • le $metadata,
  • les endpoints nécessaires à l’UI Fiori Elements.
C’est à ce niveau que le service est activé, testé et publié.
OData V4 & Fiori Elements
L’utilisation d’OData V4 permet :
  • une meilleure intégration avec RAP,
  • une gestion native du draft,
  • et une génération UI Fiori Elements cohérente et standardisée.
🔄 Comparaison avec l’ABAP classique
En ABAP classique, l’exposition des données repose souvent sur :
  • des services OData écrits manuellement (SEGW),
  • une logique de mapping complexe,
  • et une maintenance plus lourde.
En RAP, la Service Definition et le Binding :
  • réduisent drastiquement le code spécifique,
  • standardisent l’exposition,
  • et alignent l’application avec les architectures SAP modernes.
🎯 Position dans l’architecture RAP
La Service Definition et le Service Binding constituent le pont final entre le modèle RAP et l’interface utilisateur :
CDS Projection → Service Definition → Service Binding → UI Fiori
Cette approche garantit une exposition maîtrisée, testable et évolutive, adaptée à des contextes projet réels.
4. Draft

Objectif : permettre l’édition en brouillon.

Capture Fiori du draft
Voir snippet
managed implementation in class ZBP_I_COFFEE_SUB_TRL unique;
strict ( 2 );
with draft; // active draft handling
define behavior for ZI_COFFEE_SUB_TRL
persistent table zcs_sub_trl
draft table zcs_sub_trl_d // draft persistence
lock master
total etag local_last_changed_at
etag master local_last_changed_at
authorization master ( global )
{
  create;
  update;
  delete;
  field ( numbering : managed, readonly )
  subscription_uuid;
  field ( readonly )
  created_by,
  created_at,
  last_changed_by,
  last_changed_at,
  local_last_changed_at,
  next_delivery_date,
  status;
  action ( features : instance ) pause;
  action ( features : instance ) unpause;
  action ( features : instance ) cancel;
  validation validate_qty on save { create; update; field qty_grams; }
  validation validate_start_date on save { create; field start_date; }
  validation validate_status_transition on save { create; update; field status; }
  validation validate_email on save { create; update; field customer_email; }
  validation validate_frequency on save { create; update; field frequency; }
  determination set_defaults on modify { create; field status; }
  determination calc_next_delivery on modify { create; update; field start_date; }
  draft determine action Prepare // draft prepare flow
  {
    validation validate_qty; // draft validations
    validation validate_start_date; // draft validations
    validation validate_email; // draft validations
    validation validate_frequency; // draft validations
    validation validate_status_transition; // draft validations
  }
  draft action Edit; // draft edit
  draft action Activate optimized; // draft activation
  draft action Discard; // draft discard
  draft action Resume; // draft resume
  side effects
  {
    action pause affects field status;
    action unpause affects field status;
    action cancel affects field status;
  }
}
Voir explication
📝 Le mode Draft dans l’architecture RAP
🔹 Rôle du Draft
Le mode Draft permet de gérer des modifications temporaires d’un objet métier sans impacter immédiatement les données actives.
Lorsqu’un utilisateur crée ou modifie un objet, les données sont d’abord stockées dans une instance draft. Elles ne deviennent actives qu’après une validation explicite (Save/Activate).
Ce mécanisme est essentiel pour :
  • sécuriser la saisie utilisateur,
  • appliquer les règles métier avant activation,
  • offrir une expérience proche des applications SAP standards.
📐 Place du Draft dans l’architecture RAP
Le Draft s’intègre naturellement dans le flux RAP :
  • Tables de persistance : données actives
  • Tables draft : données temporaires
  • CDS Interface & Projection : exposent les deux états
  • Behavior Definition : pilote le cycle de vie (draft → active)
  • UI Fiori Elements : gère automatiquement l’état brouillon
Le framework RAP se charge de la synchronisation entre les états draft et actif.
🗂️ Où le Draft est défini (artefacts clés)
1️⃣ Tables
Une table draft dédiée est associée à la table de persistance. Elle est générée ou définie pour stocker les modifications en cours.
2️⃣ Behavior Definition (BDEF)
Le Draft est activé directement dans la Behavior Definition :
define behavior for ZI_COFFEE_SUB_TRL
  persistent table zcs_sub_trl
  draft table zcs_sub_trl_d
  with draft;
C’est le point central de configuration du draft.
3️⃣ Service Binding OData V4
Le support du Draft est nativement pris en charge par OData V4 et Fiori Elements, sans code UI spécifique.
🔄 Cycle de vie d’un Draft (exemple concret)
  • L’utilisateur clique sur Créer un abonnement
  • Une instance draft est créée
  • L’utilisateur renseigne les champs (Value Helps, déterminations)
  • Les validations sont exécutées
  • Si erreur → le draft est conservé
  • Si OK → Activation → données copiées vers la table active, draft supprimé
⚠️ Points d’attention importants
Lors de l’utilisation du Draft, il faut être attentif à :
  • la cohérence des validations (elles s’exécutent aussi en draft),
  • les déterminations (elles doivent gérer les deux états),
  • la gestion des messages d’erreur (bloquants vs informatifs),
  • la présence correcte de la table draft et des champs techniques.
Une mauvaise configuration du draft peut entraîner :
  • des erreurs de $metadata,
  • des comportements incohérents en UI,
  • ou des problèmes à l’activation.
🧩 Quelques syntaxes RAP courantes liées au Draft
Activation du Draft
with draft;
Validations exécutées en mode Draft
validation check_quantity on save { field quantity; }
Détermination en création Draft
determination set_defaults on modify { create; }
Ces règles s’appliquent avant l’activation, garantissant la qualité des données.
🎯 Pourquoi le Draft est un point clé du projet
Le mode Draft permet de concevoir des applications : plus robustes, plus proches des standards SAP, et adaptées à des cas métier complexes. Sa bonne maîtrise est un indicateur fort de maturité RAP dans un contexte projet réel.
5. Validations

Objectif : contrôles métier à la sauvegarde.

Capture Fiori des validations
Voir snippet
METHOD validate_qty.
    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      FIELDS ( qty_grams )
      WITH CORRESPONDING #( keys )
      RESULT DATA(lt_sub).
    LOOP AT lt_sub ASSIGNING FIELD-SYMBOL(<s>).
      IF <s>-qty_grams IS INITIAL OR <s>-qty_grams <= 0.
        APPEND VALUE #( %tky = <s>-%tky ) TO failed-zi_coffee_sub_trl.
        APPEND VALUE #(
          %tky = <s>-%tky
          %element-qty_grams = if_abap_behv=>mk-on
          %msg = new_message(
                   id       = 'ZC_COFFEE_MSG'
                   number   = '010'
                   severity = if_abap_behv_message=>severity-error
                 )
        ) TO reported-zi_coffee_sub_trl.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.
  METHOD validate_start_date.
    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      FIELDS ( start_date )
      WITH CORRESPONDING #( keys )
      RESULT DATA(lt_sub).

    LOOP AT lt_sub ASSIGNING FIELD-SYMBOL(<s>).
      IF <s>-start_date IS INITIAL OR <s>-start_date < sy-datum.

        APPEND VALUE #( %tky = <s>-%tky ) TO failed-zi_coffee_sub_trl.

        APPEND VALUE #(
          %tky = <s>-%tky
          %element-start_date = if_abap_behv=>mk-on
          %msg = new_message(
                   id       = 'ZC_COFFEE_MSG'
                   number   = '012'
                   severity = if_abap_behv_message=>severity-error
                 )
        ) TO reported-zi_coffee_sub_trl.

      ENDIF.
    ENDLOOP.

  ENDMETHOD.
  METHOD validate_status_transition.
  ENDMETHOD.
  METHOD validate_email.

    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      FIELDS ( customer_email )
      WITH CORRESPONDING #( keys )
      RESULT DATA(lt_sub).

    LOOP AT lt_sub ASSIGNING FIELD-SYMBOL(<s>).
      DATA lv_mail TYPE string.
      lv_mail = <s>-customer_email.
      CONDENSE lv_mail NO-GAPS.

      IF lv_mail IS INITIAL
   OR lv_mail NS '@'
   OR lv_mail CP '@*'
   OR lv_mail CP '*@'
   OR lv_mail NS '.'.

        APPEND VALUE #( %tky = <s>-%tky ) TO failed-zi_coffee_sub_trl.

        APPEND VALUE #(
          %tky = <s>-%tky
          %element-customer_email = if_abap_behv=>mk-on
          %msg = new_message(
                   id       = 'ZC_COFFEE_MSG'
                   number   = '011'
                   severity = if_abap_behv_message=>severity-error
                 )
        ) TO reported-zi_coffee_sub_trl.

      ENDIF.
    ENDLOOP.
  ENDMETHOD.
  METHOD validate_frequency.
    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      FIELDS ( frequency )
      WITH CORRESPONDING #( keys )
      RESULT DATA(lt_sub).

    LOOP AT lt_sub ASSIGNING FIELD-SYMBOL(<s>).
      IF <s>-frequency IS INITIAL.

        APPEND VALUE #( %tky = <s>-%tky ) TO failed-zi_coffee_sub_trl.

        APPEND VALUE #(
          %tky = <s>-%tky
          %element-frequency = if_abap_behv=>mk-on
          %msg = new_message(
                   id       = 'ZC_COFFEE_MSG'
                   number   = '013'
                   severity = if_abap_behv_message=>severity-error
                 )
        ) TO reported-zi_coffee_sub_trl.

      ENDIF.
    ENDLOOP.
  ENDMETHOD.
Voir explication
✅ Les validations dans SAP RAP
🔹 Rôle des validations
Les validations permettent de contrôler la cohérence des données avant qu’un objet métier ne soit enregistré ou activé.
Elles sont utilisées pour bloquer une action lorsque une règle métier n’est pas respectée (champ obligatoire, valeur incohérente, règle fonctionnelle violée).
En cas d’erreur, l’utilisateur reçoit un message bloquant, et l’instance reste en mode draft.
📐 Place des validations dans l’architecture RAP
Les validations font partie intégrante du Behavior Definition (BDEF) et sont exécutées :
  • lors de la création,
  • lors de la modification,
  • et surtout avant l’activation du draft.
Elles s’insèrent donc juste avant le passage de l’état draft à l’état actif, garantissant que seules des données valides soient persistées.
🗂️ Où définir les validations
1️⃣ Behavior Definition (BDEF)
Les validations sont déclarées dans la Behavior Definition :
validation check_quantity on save { field quantity; }
on save : la validation est exécutée à l’enregistrement / activation
field quantity : champ concerné par la règle
2️⃣ Behavior Implementation (classe ZBP_*)
La logique métier de la validation est implémentée dans la classe de comportement :
METHOD check_quantity.
  IF quantity <= 0.
    APPEND VALUE #( %msg = new_message(
      id       = 'ZMSG'
      number   = '001'
      severity = if_abap_behv_message=>severity-error
      v1       = 'Quantity must be greater than zero'
    ) ) TO reported.
  ENDIF.
ENDMETHOD.
🔄 Exemple concret (cas Coffee Subscription)
Lors de la création d’un abonnement :
  • la quantité doit être strictement positive,
  • la fréquence ne doit pas être initiale,
  • le type de café doit être renseigné.
Si une de ces règles n’est pas respectée :
  • l’enregistrement est bloqué,
  • un message d’erreur est affiché dans l’UI,
  • le draft est conservé pour correction.
⚠️ Points d’attention importants
Lors de l’implémentation des validations, il faut faire attention à :
  • utiliser des messages bloquants (severity-error) uniquement lorsque nécessaire,
  • cibler précisément les champs concernés,
  • éviter les validations trop lourdes (performance),
  • ne pas dupliquer la logique entre validation et détermination.
Une validation mal conçue peut :
  • bloquer inutilement l’utilisateur,
  • dégrader l’expérience Fiori,
  • ou compliquer l’évolution du code.
🔁 Comparaison avec l’ABAP classique
En ABAP classique, les validations sont souvent implémentées :
  • dans des CHECK dispersés,
  • ou dans la logique PAI des écrans.
En RAP, les validations sont :
  • centralisées,
  • déclaratives,
  • et exécutées automatiquement par le framework.
Cela améliore la maintenabilité, la lisibilité et la robustesse du code.
🎯 Pourquoi les validations sont essentielles
Les validations garantissent que :
  • seules des données cohérentes atteignent la base,
  • les règles métier sont appliquées de manière uniforme,
  • l’application se comporte comme un standard SAP.
Leur bonne utilisation est un marqueur fort de qualité et de maturité RAP.
6. Determinations

Objectif : automatiser les règles.

Capture ADT des determinations
Voir snippet
METHOD calc_next_delivery.
  READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
    ENTITY zi_coffee_sub_trl
    FIELDS ( start_date next_delivery_date status )
    WITH CORRESPONDING #( keys )
    RESULT DATA(lt_sub).
  DATA lt_upd TYPE TABLE FOR UPDATE zi_coffee_sub_trl.
  LOOP AT lt_sub ASSIGNING FIELD-SYMBOL(<s>).
    IF <s>-start_date IS INITIAL OR <s>-start_date = '00000000'.
      CONTINUE.
    ENDIF.
    "si deja CANCELED, ne plus recalculer
    IF <s>-status = 'CANCELED'.
      CONTINUE.
    ENDIF.
    DATA lv_next TYPE d.
    lv_next = <s>-start_date + 2.
    "Decaler si week-end (6=sam / 7=dim)
    DATA(lv_wd) = weekday( lv_next ).
    IF lv_wd = 6.
      lv_next = lv_next + 2.
    ELSEIF lv_wd = 7.
      lv_next = lv_next + 1.
    ENDIF.
    IF <s>-next_delivery_date <> lv_next.
      APPEND VALUE #( %tky = <s>-%tky next_delivery_date = lv_next ) TO lt_upd.
    ENDIF.
  ENDLOOP.

  IF lt_upd IS NOT INITIAL.
    MODIFY ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      UPDATE FIELDS ( next_delivery_date )
      WITH lt_upd.
  ENDIF.

ENDMETHOD.

  METHOD weekday.
    IF iv_date IS INITIAL OR iv_date = '00000000'.
      rv_wd = 1.
      RETURN.
    ENDIF.
    DATA lv TYPE string.
    lv = |&#123; iv_date &#125;|. "YYYYMMDD
    DATA y TYPE i.
    DATA m TYPE i.
    DATA d TYPE i.
    y = lv(4).
    m = lv+4(2).
    d = lv+6(2).
    IF m < 1 OR m > 12.
      rv_wd = 1.
      RETURN.
    ENDIF.
    DATA t TYPE STANDARD TABLE OF i WITH EMPTY KEY.
    t = VALUE #( ( 0 ) ( 3 ) ( 2 ) ( 5 ) ( 0 ) ( 3 ) ( 5 ) ( 1 ) ( 4 ) ( 6 ) ( 2 ) ( 4 ) ).
    IF m < 3.
      y = y - 1.
    ENDIF.
    DATA idx TYPE i.
    idx = m. "1..12
    DATA w TYPE i.
    w = ( y + y / 4 - y / 100 + y / 400 + t[ idx ] + d ) MOD 7.
    IF w = 0.
      rv_wd = 7.
    ELSE.
      rv_wd = w.
    ENDIF.
  ENDMETHOD.
Voir explication
Les déterminations dans SAP RAP
Rôle des déterminations
Les déterminations permettent d’enrichir ou d’ajuster automatiquement les données d’un objet métier, sans bloquer l’utilisateur.
Contrairement aux validations, une détermination :
  • ne bloque pas l’enregistrement,
  • est déclenchée automatiquement par le framework,
  • sert à calculer, compléter ou synchroniser des champs.
Elles sont idéales pour appliquer des règles métier implicites, qui ne nécessitent pas d’intervention utilisateur.
Place des déterminations dans l’architecture RAP
Les déterminations font partie du Behavior Definition (BDEF) et sont exécutées :
  • lors de la création d’un draft,
  • lors de la modification de certains champs,
  • avant l’activation de l’objet.
Elles s’exécutent à l’intérieur du cycle draft, ce qui garantit que les données actives sont toujours cohérentes.
Où définir les déterminations
1. Behavior Definition (BDEF)
Les déterminations sont déclarées dans la Behavior Definition :
determination set_defaults on modify { create; }
Cette déclaration indique :
  • quand la détermination est déclenchée,
  • dans quel contexte (create / modify),
  • et sur quel événement.
2. Behavior Implementation (classe ZBP_*)
La logique est implémentée dans la classe de comportement :
METHOD set_defaults.
  IF status IS INITIAL.
    status = 'NEW'.
  ENDIF.

  IF delivery_frequency IS NOT INITIAL.
    next_delivery_date = sy-datum + 30.
  ENDIF.
ENDMETHOD.
Exemple concret — Coffee Subscription
Dans le projet Coffee Subscription, les déterminations sont utilisées pour :
  • initialiser automatiquement le statut de souscription lors de la création,
  • calculer la date de prochaine livraison à partir de la fréquence choisie,
  • maintenir la cohérence entre les champs métier.
L’utilisateur n’a pas besoin de saisir ces informations : elles sont déduites automatiquement par le système.
Points d’attention importants
Lors de l’utilisation des déterminations, il faut faire attention à :
  • ne pas remplacer une validation par une détermination,
  • éviter les effets de bord (boucles involontaires),
  • gérer correctement les champs déjà renseignés par l’utilisateur,
  • garder une logique simple et prédictible.
Une détermination mal conçue peut :
  • écraser des données utilisateur,
  • rendre le comportement difficile à comprendre,
  • compliquer le debug.
Comparaison avec l’ABAP classique
En ABAP classique, ce type de logique est souvent dispersé :
  • dans des MOVE-CORRESPONDING,
  • des IF en PAI,
  • ou du code spécifique à l’écran.
En RAP, les déterminations sont :
  • centralisées,
  • déclaratives,
  • automatiquement exécutées par le framework.
Cela améliore la lisibilité, la testabilité et la maintenabilité.
Pourquoi les déterminations sont clés dans ce projet
Les déterminations permettent à l’application Coffee Subscription de :
  • réduire la saisie utilisateur,
  • fiabiliser les données,
  • et offrir une expérience proche des applications SAP standards.
Leur bonne utilisation démontre une compréhension avancée du cycle de vie RAP et des règles métier implicites.
7. Actions

Objectif : déclencher des actions ciblées.

Capture Fiori des actions
Voir snippet
METHOD pause.
    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      FIELDS ( status )
      WITH CORRESPONDING #( keys )
      RESULT DATA(lt_sub).
    DATA lt_upd TYPE TABLE FOR UPDATE zi_coffee_sub_trl.
    LOOP AT lt_sub ASSIGNING FIELD-SYMBOL(<s>).
      IF <s>-status = 'ACTIVE'.
        APPEND VALUE #( %tky = <s>-%tky status = 'PAUSED' ) TO lt_upd.
      ELSE.
        APPEND VALUE #(
          %tky = <s>-%tky
          %msg = new_message(
                   id       = 'ZC'
                   number   = '001'
                   severity = if_abap_behv_message=>severity-error
                   v1       = |Pause allowed only for ACTIVE|
                 )
        ) TO reported-zi_coffee_sub_trl.
      ENDIF.
    ENDLOOP.
    IF lt_upd IS NOT INITIAL.
      MODIFY ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
        ENTITY zi_coffee_sub_trl
        UPDATE FIELDS ( status )
        WITH lt_upd.
    ENDIF.
    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      ALL FIELDS WITH CORRESPONDING #( keys )
      RESULT DATA(lt_read).
  ENDMETHOD.

  METHOD unpause.
    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      FIELDS ( status )
      WITH CORRESPONDING #( keys )
      RESULT DATA(lt_sub).
    DATA lt_upd TYPE TABLE FOR UPDATE zi_coffee_sub_trl.
    LOOP AT lt_sub ASSIGNING FIELD-SYMBOL(<s>).
      IF <s>-status = 'PAUSED'.
        APPEND VALUE #( %tky = <s>-%tky status = 'ACTIVE' ) TO lt_upd.
      ELSE.
        APPEND VALUE #(
          %tky = <s>-%tky
          %msg = new_message(
                   id       = 'ZC'
                   number   = '002'
                   severity = if_abap_behv_message=>severity-error
                   v1       = |Unpause allowed only for PAUSED|
                 )
        ) TO reported-zi_coffee_sub_trl.
      ENDIF.
    ENDLOOP.
    IF lt_upd IS NOT INITIAL.
      MODIFY ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
        ENTITY zi_coffee_sub_trl
        UPDATE FIELDS ( status )
        WITH lt_upd.
    ENDIF.
    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      ALL FIELDS WITH CORRESPONDING #( keys )
      RESULT DATA(lt_read).
  ENDMETHOD.

  METHOD cancel.
    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      FIELDS ( status )
      WITH CORRESPONDING #( keys )
      RESULT DATA(lt_sub).
    DATA lt_upd TYPE TABLE FOR UPDATE zi_coffee_sub_trl.
    LOOP AT lt_sub ASSIGNING FIELD-SYMBOL(<s>).
      IF <s>-status <> 'CANCELED'.
        APPEND VALUE #( %tky = <s>-%tky status = 'CANCELED' ) TO lt_upd.
      ELSE.
        APPEND VALUE #(
          %tky = <s>-%tky
          %msg = new_message(
                   id       = 'ZC'
                   number   = '003'
                   severity = if_abap_behv_message=>severity-information
                   v1       = |Already canceled|
                 )
        ) TO reported-zi_coffee_sub_trl.
      ENDIF.
    ENDLOOP.
    IF lt_upd IS NOT INITIAL.
      MODIFY ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
        ENTITY zi_coffee_sub_trl
        UPDATE FIELDS ( status )
        WITH lt_upd.
    ENDIF.
    READ ENTITIES OF zi_coffee_sub_trl IN LOCAL MODE
      ENTITY zi_coffee_sub_trl
      ALL FIELDS WITH CORRESPONDING #( keys )
      RESULT DATA(lt_read).
  ENDMETHOD.
Voir explication
▶️ Les actions dans SAP RAP — Coffee Subscription
🔹 Rôle des actions
Les actions RAP permettent de déclencher une opération métier explicite, initiée volontairement par l’utilisateur.
Dans le projet Coffee Subscription, les actions représentent des transitions de cycle de vie claires et contrôlées de l’abonnement.
📐 Place des actions dans l’architecture RAP
Les actions font partie du Behavior Definition (BDEF) et sont :
  • exposées automatiquement dans l’UI Fiori Elements sous forme de boutons,
  • disponibles via le service OData V4,
  • exécutées dans la classe de comportement de manière transactionnelle.
Elles interviennent uniquement sur des abonnements existants, lorsque l’utilisateur souhaite modifier leur état.
🗂️ Où définir les actions
1️⃣ Behavior Definition (BDEF)
Les actions sont déclarées dans la Behavior Definition :
action pause result [1] $self;
action unpause result [1] $self;
action cancel result [1] $self;
Chaque action correspond à une intention métier précise.
2️⃣ Behavior Implementation (classe ZBP_*)
La logique métier est implémentée dans la classe de comportement :
METHOD pause.
  status = 'PAUSED'.
ENDMETHOD.

METHOD unpause.
  status = 'ACTIVE'.
ENDMETHOD.

METHOD cancel.
  status = 'CANCELED'.
ENDMETHOD.
🔄 Exemple concret — Cycle de vie Coffee Subscription
Dans l’application Coffee Subscription, un abonnement peut suivre le cycle de vie suivant :
  • ACTIVE : abonnement en cours de livraison
  • PAUSED : abonnement temporairement suspendu
  • CANCELED : abonnement définitivement arrêté
Les actions permettent de piloter ce cycle :
  • Pause → ACTIVE → PAUSED
  • Unpause → PAUSED → ACTIVE
  • Cancel → ACTIVE / PAUSED → CANCELED
Ces transitions reflètent des gestes métier réels, similaires à ceux rencontrés dans des applications de gestion d’abonnements ou de contrats.
⚠️ Points d’attention importants
Lors de l’implémentation des actions, il est important de :
  • vérifier la cohérence de l’état courant avant d’autoriser l’action,
  • empêcher les transitions invalides (ex : Unpause sur un abonnement ACTIVE),
  • gérer correctement les messages utilisateur,
  • sécuriser les actions via les autorisations si nécessaire.
Une action mal contrôlée peut entraîner :
  • des états incohérents,
  • une mauvaise expérience utilisateur,
  • ou des erreurs fonctionnelles.
🔁 Comparaison avec l’ABAP classique
En ABAP classique, ce type de logique est souvent réparti :
  • dans des boutons d’écran,
  • via des OKCODE,
  • ou dans du code événementiel spécifique.
En RAP, les actions sont :
  • centralisées dans le modèle métier,
  • déclaratives,
  • et automatiquement intégrées à l’UI Fiori.
Cela améliore la lisibilité, la cohérence fonctionnelle et la maintenabilité.
🎯 Pourquoi les actions sont un point fort du projet
Les actions permettent à l’application Coffee Subscription de :
  • représenter clairement le cycle de vie métier d’un abonnement,
  • offrir des interactions utilisateur explicites et contrôlées,
  • se rapprocher du comportement des applications SAP standards.
8. Value Helps

Objectif : simplifier la saisie.

Capture Fiori des value helps
Voir explication
🧭 Value Helps (VH) dans SAP RAP
Les Value Helps permettent de guider la saisie utilisateur en proposant des valeurs contrôlées directement dans l’UI Fiori.
Dans RAP, elles sont généralement implémentées via :
  • une CDS dédiée (VH),
  • associée à un champ dans la CDS Projection.
Cette approche permet :
  • de sécuriser les données,
  • d’améliorer l’expérience utilisateur,
  • et de centraliser la logique de sélection.
Mise en œuvre (principe)
  • Créer une CDS Value Help exposant les valeurs autorisées
  • L’associer au champ concerné via une annotation
  • Fiori Elements gère automatiquement l’affichage
Exemple d’usage — Coffee Subscription
Les VH sont utilisées pour :
  • le type de café,
  • la fréquence de livraison,
  • et les statuts.
L’utilisateur sélectionne une valeur cohérente, sans saisie libre.
Point clé
Les Value Helps sont intégrées nativement au modèle RAP, sans logique UI spécifique, ce qui garantit une application propre et maintenable.
9. Error handling

Objectif : gérer les erreurs proprement.

Capture Fiori des erreurs
Voir explication
⚠️ Error Handling dans SAP RAP
🔹 Principe général
En SAP RAP, la gestion des erreurs est centralisée et pilotée par le framework. Les messages sont retournés directement à l’UI Fiori, sans logique spécifique côté interface.
Les erreurs sont généralement émises depuis :
  • Validations
  • Actions
  • Determinations (rarement bloquantes)
🧭 Types de messages RAP
Type Effet Usage
Error Bloquant Donnée invalide, règle métier violée
Warning Non bloquant Information importante
Information Informatif Retour utilisateur
Success Succès Confirmation d’action
👉 En pratique, Error est le plus utilisé pour les règles métier critiques.
🧪 Syntaxe simple (exemple)
APPEND VALUE #(
  %msg = new_message(
    id       = 'ZMSG'
    number   = '001'
    severity = if_abap_behv_message=>severity-error
    v1       = 'Invalid subscription data'
  )
) TO reported.
  • severity-error → bloque l’enregistrement
  • Le message est affiché automatiquement dans l’UI
☕ Exemple concret — Coffee Subscription
Dans l’application Coffee Subscription, le Error Handling est utilisé par exemple lorsque :
  • la quantité est nulle ou négative,
  • la fréquence de livraison n’est pas renseignée,
  • une action (Pause / Unpause / Cancel) est déclenchée dans un état invalide.
Dans ces cas :
  • un message bloquant est affiché,
  • l’objet reste en mode draft,
  • l’utilisateur peut corriger sans perte de données.
🎯 Bonnes pratiques
  • Utiliser des messages clairs et orientés métier
  • Bloquer uniquement lorsque nécessaire
  • Laisser le draft actif pour correction
  • Tester systématiquement les messages dans l’UI
🔑 Point clé
Un bon Error Handling en RAP garantit : des données fiables, une expérience utilisateur fluide, et un comportement proche des applications SAP standards.

Messages clairs, erreurs bloquantes et reprise via draft.

Règles métier

Règles de validation à la sauvegarde, déterminations automatiques et cohérence des statuts pour simuler un contexte proche de la production.

Cycle RAP (du point de vue utilisateur)

Creer un abonnement → Draft créé
Choix type/frequence → Value Helps
Determinations auto (ex: prochaine livraison)
Validations (quantité > 0, frequence non initiale)
Erreur : message affiché, draft conservé
OK : Enregistrer/Activer → instance active, draft supprimé

Exemple : Type Arabica, Fréquence mensuelle, Quantité 3. La prochaine livraison est pré-calculée, les validations passent, l’instance active est créée.

Aperçu de l’application

Debug & difficultés

Problème

Métadonnées bloquantes, l’UI ne s’ouvre pas.

Analyse

Incohérence sur une annotation de criticality.

Correction

Nettoyage des annotations et re-test OData.

Leçon

Toujours valider les métadonnées après un changement.

Problème

Draft non sauvegardé correctement.

Analyse

Champ obligatoire manquant en persistence.

Correction

Alignement table et CDS.

Leçon

Tester les cas limites dès le début.

Problème

Erreurs sur déterminations.

Analyse

Type non conforme dans le handler.

Correction

Correction signatures + logs ciblés.

Leçon

Isoler les handlers critiques.

Conclusion

Ce projet m’a permis de consolider les bases RAP, de mieux structurer l’architecture et d’améliorer ma capacité à débugger. En V2, j’ajouterai des optimisations de performance et davantage d’automatisations UI. Si vous voulez en savoir plus sur ma méthode de travail ou sur des sujets SAP (RAP, ABAP, Fiori, performance, debug…), je partage tout dans ma page Blogs.

Lire blogs