"Actions Popup dans RAP : Demander des saisies utilisateur avant l

Catégorie
RAP
Publié
Auteur
Johannes

Parfois, un simple clic sur un bouton ne suffit pas. Avant d’annuler une réservation, l’utilisateur doit indiquer une raison. Avant un transfert, de nouvelles données doivent être saisies. Les Actions Popup dans RAP permettent exactement cela : des saisies utilisateur structurées avant l’exécution d’une action.

Le concept : Action avec entité de paramètres

Une action popup se compose de trois composants :

  1. Abstract Entity : Définit la structure du popup (champs, types de données)
  2. Behavior Definition : Lie l’action au paramètre
  3. Implementation : Traite les valeurs saisies
┌─────────────────────────────────────────────────────────────────┐
│ Annuler la réservation [X] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Raison de l'annulation * │
│ ┌─────────────────────────────────────┐ │
│ │ Modification client ▼ │ │
│ └─────────────────────────────────────┘ │
│ │
│ Remarque │
│ ┌─────────────────────────────────────┐ │
│ │ Client a réservé un vol ultérieur │ │
│ │ vers Munich. │ │
│ └─────────────────────────────────────┘ │
│ │
│ ☑ Notifier le client par e-mail │
│ │
│ Montant du remboursement │
│ ┌───────────────┐ EUR │
│ │ 450,00 │ │
│ └───────────────┘ │
│ │
│ [ Annuler ] [ Valider ] │
└─────────────────────────────────────────────────────────────────┘

Étape 1 : Définir l’Abstract Entity

L’Abstract Entity décrit les champs du dialogue popup :

@EndUserText.label: 'Données d\'annulation"
define abstract entity ZA_CancelBookingParams
{
@EndUserText.label: 'Raison de l\'annulation"
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_CancellationReasonVH', element: 'ReasonCode' }
}]
CancellationReason : abap.char(2);
@EndUserText.label: 'Remarque"
@UI.multiLineText: true
Remarks : abap.string(500);
@EndUserText.label: 'Notifier le client"
NotifyCustomer : abap_boolean;
@EndUserText.label: 'Montant du remboursement"
@Semantics.amount.currencyCode: 'Currency"
RefundAmount : abap.curr(15,2);
@EndUserText.label: 'Devise"
@Semantics.currencyCode: true
Currency : abap.cuky;
}

Annotations importantes pour le popup :

AnnotationEffet
@EndUserText.labelLibellé du champ dans le popup
@Consumption.valueHelpDefinitionDropdown/Value Help
@UI.multiLineText: trueChamp de texte multiligne
@Semantics.amount.currencyCodeChamp de devise avec formatage

Étape 2 : Behavior Definition

Associez l’action avec le paramètre :

managed implementation in class zbp_i_flightbooking unique;
strict ( 2 );
define behavior for ZI_FlightBooking alias FlightBooking
persistent table zflight_book
lock master
authorization master ( instance )
{
// CRUD standard
create;
update;
delete;
// Action AVEC entité de paramètres
action cancelBooking
parameter ZA_CancelBookingParams
result [1] $self;
// Action sans paramètre (pour comparaison)
action confirmBooking result [1] $self;
// Validation pour l'annulation
validation validateCancellation on save
{ field BookingStatus; }
}

Le mot-clé parameter fait en sorte que Fiori Elements génère automatiquement un dialogue.

Étape 3 : Implementation de l’action

Dans la Behavior Implementation Class, vous traitez les paramètres :

CLASS lhc_flightbooking DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS cancelBooking FOR MODIFY
IMPORTING keys FOR ACTION FlightBooking~cancelBooking
RESULT result.
ENDCLASS.
CLASS lhc_flightbooking IMPLEMENTATION.
METHOD cancelBooking.
" Lire les données actuelles
READ ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
FIELDS ( booking_id booking_status flight_price currency_code )
WITH CORRESPONDING #( keys )
RESULT DATA(bookings).
LOOP AT keys ASSIGNING FIELD-SYMBOL(<key>).
" Récupérer la réservation du résultat
READ TABLE bookings INTO DATA(booking)
WITH KEY booking_id = <key>-booking_id.
IF sy-subrc <> 0.
" Réservation non trouvée
APPEND VALUE #(
%tky = <key>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Réservation non trouvée' )
) TO reported-flightbooking.
APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking.
CONTINUE.
ENDIF.
" === Lire les paramètres du popup ===
DATA(cancel_reason) = <key>-%param-CancellationReason.
DATA(remarks) = <key>-%param-Remarks.
DATA(notify) = <key>-%param-NotifyCustomer.
DATA(refund_amount) = <key>-%param-RefundAmount.
DATA(currency) = <key>-%param-Currency.
" Validation : champ obligatoire raison de l'annulation
IF cancel_reason IS INITIAL.
APPEND VALUE #(
%tky = <key>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'La raison de l\'annulation est un champ obligatoire' )
) TO reported-flightbooking.
APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking.
CONTINUE.
ENDIF.
" Validation : le remboursement ne peut pas être supérieur au prix de la réservation
IF refund_amount > booking-flight_price.
APPEND VALUE #(
%tky = <key>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Le remboursement ne peut pas être supérieur à {
booking-flight_price } { booking-currency_code
}| )
) TO reported-flightbooking.
APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking.
CONTINUE.
ENDIF.
" Mettre le statut sur Annulé
MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
UPDATE FIELDS ( booking_status cancellation_reason remarks )
WITH VALUE #( (
%tky = <key>-%tky
booking_status = 'X' " Cancelled
cancellation_reason = cancel_reason
remarks = remarks
) ).
" Optionnel : Notifier le client
IF notify = abap_true.
send_cancellation_email(
booking_id = booking-booking_id
reason = cancel_reason
remarks = remarks
).
ENDIF.
" Optionnel : Traiter le remboursement
IF refund_amount > 0.
process_refund(
booking_id = booking-booking_id
amount = refund_amount
currency = currency
).
ENDIF.
ENDLOOP.
" Retourner les données mises à jour
READ ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(updated_bookings).
result = VALUE #( FOR bk IN updated_bookings (
%tky = bk-%tky
%param = bk
) ).
" Message de succès
APPEND VALUE #(
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-success
text = |{ lines( updated_bookings ) } réservation(s) annulée(s)| )
) TO reported-flightbooking.
ENDMETHOD.
ENDCLASS.

Annotations UI pour la mise en page du popup

Affinez la mise en page du popup avec des annotations supplémentaires :

@EndUserText.label: 'Données d\'annulation"
define abstract entity ZA_CancelBookingParams
{
@EndUserText.label: 'Raison de l\'annulation"
@UI.defaultValue: 'KA"
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_CancellationReasonVH', element: 'ReasonCode' },
useForValidation: true
}]
CancellationReason : abap.char(2);
@EndUserText.label: 'Remarque"
@UI.multiLineText: true
@UI.placeholder: 'Optionnel : Informations supplémentaires sur l\'annulation"
Remarks : abap.string(500);
@EndUserText.label: 'Notifier le client"
@UI.defaultValue: 'true"
NotifyCustomer : abap_boolean;
@EndUserText.label: 'Montant du remboursement"
@Semantics.amount.currencyCode: 'Currency"
@UI.defaultValue: '0.00"
RefundAmount : abap.curr(15,2);
@EndUserText.label: 'Devise"
@Semantics.currencyCode: true
@UI.defaultValue: 'EUR"
@Consumption.valueHelpDefinition: [{
entity: { name: 'I_Currency', element: 'Currency' }
}]
Currency : abap.cuky;
}

Annotations UI importantes

AnnotationEffetExemple
@UI.defaultValueValeur pré-remplie'EUR'
@UI.placeholderTexte d’espace réservé'Saisir une remarque...'
@UI.multiLineTextChamp de saisie multilignePour les textes longs
@UI.hiddenMasquer le champChamps techniques
@Consumption.valueHelpDefinitionValue Help/DropdownChamps de sélection

Différents types de champs dans le popup

@EndUserText.label: 'Priorité"
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_PriorityVH', element: 'Priority' }
}]
Priority : abap.char(1);

Champ de date

@EndUserText.label: 'Nouvelle date de vol"
@UI.defaultValue: '#(TODAY)"
NewFlightDate : abap.dats;

Checkbox

@EndUserText.label: 'Envoyer une confirmation par e-mail"
@UI.defaultValue: 'false"
SendConfirmation : abap_boolean;

Texte multiligne

@EndUserText.label: 'Justification"
@UI.multiLineText: true
Justification : abap.string(1000);

Montant en devise

@EndUserText.label: 'Montant"
@Semantics.amount.currencyCode: 'Currency"
Amount : abap.curr(15,2);
@EndUserText.label: 'Devise"
@Semantics.currencyCode: true
Currency : abap.cuky;

Champ de quantité

@EndUserText.label: 'Quantité"
@Semantics.quantity.unitOfMeasure: 'Unit"
Quantity : abap.quan(13,3);
@EndUserText.label: 'Unité"
@Semantics.unitOfMeasure: true
Unit : abap.unit(3);

Exemple complet de réservation de vol

Voici un exemple complet de bout en bout pour une action de transfert :

Abstract Entity : Paramètres de transfert

@EndUserText.label: 'Paramètres de transfert"
define abstract entity ZA_RescheduleParams
{
@EndUserText.label: 'Nouvelle date de vol"
NewFlightDate : abap.dats;
@EndUserText.label: 'Nouveau numéro de vol"
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_FlightConnectionVH', element: 'FlightId' }
}]
NewFlightId : abap.numc(4);
@EndUserText.label: 'Accepter la différence de prix"
AcceptPriceDiff : abap_boolean;
@EndUserText.label: 'Remarque"
@UI.multiLineText: true
Remarks : abap.string(500);
}

Behavior Definition

define behavior for ZI_FlightBooking alias FlightBooking
{
action rescheduleBooking
parameter ZA_RescheduleParams
result [1] $self;
}

Projection Behavior

projection implementation in class zbp_c_flightbooking unique;
define behavior for ZC_FlightBooking alias FlightBooking
{
use action rescheduleBooking;
}

Implementation

METHOD rescheduleBooking.
" Lire les réservations actuelles
READ ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(bookings).
LOOP AT keys ASSIGNING FIELD-SYMBOL(<key>).
READ TABLE bookings INTO DATA(booking)
WITH KEY booking_id = <key>-booking_id.
" === Paramètres du popup ===
DATA(new_date) = <key>-%param-NewFlightDate.
DATA(new_flight) = <key>-%param-NewFlightId.
DATA(accept_diff) = <key>-%param-AcceptPriceDiff.
DATA(remarks) = <key>-%param-Remarks.
" Validation : date dans le futur
IF new_date < cl_abap_context_info=>get_system_date( ).
APPEND VALUE #(
%tky = <key>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'La date de vol doit être dans le futur' )
) TO reported-flightbooking.
APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking.
CONTINUE.
ENDIF.
" Calculer la différence de prix
DATA(new_price) = get_flight_price( new_flight ).
DATA(price_diff) = new_price - booking-flight_price.
" Augmentation de prix sans acceptation = erreur
IF price_diff > 0 AND accept_diff = abap_false.
APPEND VALUE #(
%tky = <key>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Différence de prix de { price_diff } {
booking-currency_code } doit être acceptée| )
) TO reported-flightbooking.
APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking.
CONTINUE.
ENDIF.
" Effectuer le transfert
MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
UPDATE FIELDS ( flight_date flight_id flight_price remarks )
WITH VALUE #( (
%tky = <key>-%tky
flight_date = new_date
flight_id = new_flight
flight_price = new_price
remarks = remarks
) ).
ENDLOOP.
" Retourner le résultat
READ ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(updated).
result = VALUE #( FOR bk IN updated (
%tky = bk-%tky
%param = bk
) ).
" Message de succès
APPEND VALUE #(
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-success
text = |{ lines( updated ) } réservation(s) transférée(s)| )
) TO reported-flightbooking.
ENDMETHOD.

Intégration UI dans CDS View

@EndUserText.label: 'Réservation de vol"
define view entity ZC_FlightBooking
as projection on ZI_FlightBooking
{
@UI.lineItem: [
{ position: 10 },
{ type: #FOR_ACTION, dataAction: 'cancelBooking',
label: 'Annuler', criticality: #NEGATIVE },
{ type: #FOR_ACTION, dataAction: 'rescheduleBooking',
label: 'Transférer' }
]
@UI.identification: [
{ position: 10 },
{ type: #FOR_ACTION, dataAction: 'rescheduleBooking',
label: 'Transférer' }
]
key BookingId,
// autres champs...
}

Validation des saisies popup

Dans le code de l’action (recommandé)

" Vérifier le champ obligatoire
IF <key>-%param-CancellationReason IS INITIAL.
APPEND VALUE #(
%tky = <key>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'La raison de l\'annulation est requise' )
) TO reported-flightbooking.
APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking.
RETURN.
ENDIF.

Avec Validation dans le Behavior

define behavior for ZI_FlightBooking
{
action cancelBooking
parameter ZA_CancelBookingParams
result [1] $self;
" La validation est exécutée après l'action
validation validateAfterCancel on save
{ field booking_status; }
}

Best Practices pour les actions popup

1. Identifier les champs obligatoires

@EndUserText.label: 'Raison *' " Astérisque dans le label
@ObjectModel.mandatory: true " Champ obligatoire
Reason : abap.char(2);

2. Valeurs par défaut judicieuses

@UI.defaultValue: 'EUR' " Pour la devise
@UI.defaultValue: 'true' " Pour la checkbox
@UI.defaultValue: '#(TODAY)' " Pour la date

3. Value Helps pour les champs de sélection

@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_ReasonVH', element: 'Code' },
useForValidation: true
}]

4. Messages d’erreur clairs

" ❌ Mauvais
text = 'Erreur de saisie"
" ✅ Bon
text = |Le remboursement ({ refund_amount } { currency }) ne peut pas être supérieur au prix de la réservation ({ booking-flight_price } { booking-currency_code })|

5. Limiter la taille du popup

Maximum 5-6 champs par popup. Pour des saisies plus complexes : utiliser un wizard ou une page séparée.

ScénarioRecommandation
1-2 valeurs supplémentairesAction popup
Formulaires complexesPage d’objet séparée
Modification en masseÉdition en ligne ou application dédiée
Confirmation sans saisieAction sans paramètre

Résumé

Les actions popup dans RAP permettent des saisies utilisateur interactives avant l’exécution :

ComposantTâche
Abstract EntityDéfinit les champs et types de données du popup
Behavior DefinitionLie l’action avec parameter
ImplementationLit %param et traite les valeurs
Annotations UIContrôle l’apparence et le comportement

Avec quelques annotations et une structure claire, vous créez des dialogues conviviaux qui s’intègrent parfaitement dans Fiori Elements.

Articles complémentaires : RAP Actions et Functions pour les bases des actions, RAP Nachrichten pour la gestion des erreurs, RAP CDS Pattern pour une architecture simplifiée et CDS Annotations pour plus de possibilités d’annotations.