RAP Determinations et Validations : Le guide complet

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

Determinations et Validations sont les deux mecanismes dans RAP pour executer automatiquement la logique metier. Les Determinations definissent des valeurs, les Validations les verifient. La bonne comprehension du timing (quand quoi est execute) est cruciale pour des RAP Business Objects sans erreur.

La difference en un coup d’oeil

┌─────────────────────────────────────────────────────────────┐
Action utilisateur (Create/Update) │
└────────────────────┬────────────────────────────────────────┘
┌───────────────────────┐
│ DETERMINATION │ ← Definit automatiquement les valeurs
"Qu'est-ce qui │ (Status, Numeros, Valeurs par defaut)
│ manque ?" │
└───────────┬───────────┘
┌───────────────────────┐
│ VALIDATION │ ← Verifie les regles metier
"Est-ce correct ?" │ (Logique de dates, Champs obligatoires)
└───────────┬───────────┘
▼ (seulement en cas de succes)
┌───────────────────────┐
Save to Database
└───────────────────────┘
AspectDeterminationValidation
ObjectifDefinir/calculer des valeursVerifier des valeurs
Timingon modify ou on saveon save
Modifications✅ Peut modifier l’entite❌ Lecture seule, pas de modifications
ErreursPas d’erreurs directesRemplit FAILED & REPORTED
ExempleDefinir le status a ‘O’Verifier que la date de fin est apres le debut
OrdreD’abord (avant Validation)Ensuite (apres Determination)

Determinations : Definition automatique des valeurs

Quand utiliser les Determinations ?

Parfait pour :

  • Definir les valeurs par defaut (Status = ‘Open’)
  • Calculer des champs (Prix total = Prix × Quantite)
  • Mettre a jour les champs dependants
  • Definir les timestamps (CreatedAt, LastChangedAt)
  • Valeurs basees sur la logique metier (Remise selon la categorie client)

Syntaxe dans la Behavior Definition

define behavior for ZI_Travel alias Travel
{
// Syntaxe Determination :
determination <MethodName> on <Trigger> { <TriggerCondition>; }
// Trigger : modify (immediat) ou save (avant DB-Commit)
// TriggerCondition : create, update, field <FieldName>
}

Exemple 1 : Definir le status lors de la creation

// Behavior Definition
define behavior for ZI_Travel alias Travel
persistent table ztravel
{
create;
update;
field ( readonly ) TravelId, Status;
field ( readonly ) CreatedBy, CreatedAt;
// Determination : Lors de Create → Definir le Status a 'O' (Open)
determination setInitialStatus on modify { create; }
}
// Behavior Implementation
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS setInitialStatus FOR DETERMINE ON MODIFY
IMPORTING keys FOR Travel~setInitialStatus.
ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD setInitialStatus.
" 1. Lire les donnees actuelles
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
" 2. Mettre a jour uniquement les entites sans Status
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status CreatedBy CreatedAt )
WITH VALUE #( FOR travel IN lt_travel WHERE ( Status IS INITIAL )
( %tky = travel-%tky
Status = 'O' " Open
CreatedBy = cl_abap_context_info=>get_user_name( )
CreatedAt = cl_abap_context_info=>get_system_date( ) ) )
REPORTED DATA(update_reported).
ENDMETHOD.
ENDCLASS.

Deroulement :

Utilisateur : CREATE Travel avec Description = 'Voyage d affaires"
Framework : Create en memoire
Determination : setInitialStatus
→ Status = 'O"
→ CreatedBy = sy-uname
→ CreatedAt = today
(Les validations sont executees)
Framework : INSERT INTO ztravel

Exemple 2 : Calculer le prix total (on modify)

// Behavior Definition
define behavior for ZI_Travel alias Travel
{
// Lors d'un changement de BeginDate ou EndDate → Recalculer le prix
determination calculateTotalPrice on modify {
field BeginDate, EndDate;
}
}
METHOD calculateTotalPrice.
" Lire les donnees
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( TravelId BeginDate EndDate )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
LOOP AT lt_travel INTO DATA(ls_travel).
" Calculer le nombre de jours
DATA(lv_days) = ls_travel-EndDate - ls_travel-BeginDate + 1.
" Prix de base par jour (ex. depuis le customizing)
DATA(lv_price_per_day) = 100. " EUR
" Prix total
DATA(lv_total) = lv_days * lv_price_per_day.
" Remise pour voyages longs
IF lv_days > 7.
lv_total = lv_total * '0.90'. " 10% de remise
ENDIF.
" Definir la valeur
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( TotalPrice )
WITH VALUE #( ( %tky = ls_travel-%tky
TotalPrice = lv_total ) ).
ENDLOOP.
ENDMETHOD.

Exemples de triggers :

" Executer lors de CREATE
determination setDefaults on modify { create; }
" Executer lors de UPDATE
determination recalculate on modify { update; }
" Lors de CREATE et UPDATE
determination calculate on modify { create; update; }
" Seulement lorsque certains champs sont modifies
determination updateDependentFields on modify {
field Price, Quantity, Discount;
}
" Lors de SAVE (juste avant le DB-Commit)
determination finalizeData on save { create; update; }

Exemple 3 : Definir les champs dependants (on save)

// Behavior Definition
define behavior for ZI_Travel alias Travel
{
// Juste avant le Save : Definir les champs d'approbation
determination setApprovalData on save { update; }
}
METHOD setApprovalData.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status ApprovedBy ApprovedAt )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( ApprovedBy ApprovedAt )
WITH VALUE #( FOR travel IN lt_travel
WHERE ( Status = 'A' AND ApprovedBy IS INITIAL )
( %tky = travel-%tky
ApprovedBy = cl_abap_context_info=>get_user_name( )
ApprovedAt = cl_abap_context_info=>get_system_date( ) ) )
REPORTED DATA(update_reported).
ENDMETHOD.

Validations : Verifier les regles metier

Quand utiliser les Validations ?

Parfait pour :

  • Verifier les champs obligatoires
  • Logique de dates (Date de fin apres le debut)
  • Verification des plages de valeurs (Remise ≤ 100%)
  • Verifier les cles etrangeres (Le client existe-t-il ?)
  • Regles metier complexes

PAS pour :

  • Definir des valeurs (→ Determination!)
  • Calculs (→ Determination!)
  • Juste enregistrer des warnings (→ OK, mais pas comme erreur)

Syntaxe dans la Behavior Definition

define behavior for ZI_Travel alias Travel
{
// Syntaxe Validation :
validation <MethodName> on save { <TriggerCondition>; }
// Trigger : TOUJOURS "on save" (juste avant le DB-Commit)
// TriggerCondition : create, update, field <FieldName>
}

Exemple 1 : Verifier la logique des dates

// Behavior Definition
define behavior for ZI_Travel alias Travel
{
create;
update;
// Validation : Lors du Save → Verifier la date
validation validateDates on save {
field BeginDate, EndDate;
}
}
// Behavior Implementation
CLASS lhc_travel IMPLEMENTATION.
METHOD validateDates.
" 1. Lire les donnees
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( TravelId BeginDate EndDate )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
" 2. Verifier chaque entite
LOOP AT lt_travel INTO DATA(ls_travel).
" Regle 1 : EndDate doit etre apres BeginDate
IF ls_travel-EndDate < ls_travel-BeginDate.
" Remplir FAILED (erreur technique)
APPEND VALUE #(
%tky = ls_travel-%tky
%element-EndDate = if_abap_behv=>mk-on
) TO failed-travel.
" Remplir REPORTED (message d'erreur pour UI)
APPEND VALUE #(
%tky = ls_travel-%tky
%element-EndDate = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |La date de fin ({ ls_travel-EndDate DATE = USER }) | &&
|doit etre apres la date de debut ({ ls_travel-BeginDate DATE = USER })|
)
) TO reported-travel.
ENDIF.
" Regle 2 : BeginDate ne doit pas etre dans le passe
IF ls_travel-BeginDate < cl_abap_context_info=>get_system_date( ).
APPEND VALUE #(
%tky = ls_travel-%tky
%element-BeginDate = if_abap_behv=>mk-on
) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-BeginDate = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Le debut du voyage ne peut pas etre dans le passe"
)
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Que se passe-t-il en cas d’erreur ?

Utilisateur : UPDATE Travel, EndDate = '20250101', BeginDate = '20250115"
(Les determinations sont executees)
Validation : validateDates
→ Verification : EndDate < BeginDate? → OUI!
→ FAILED-travel rempli
→ REPORTED-travel rempli
Framework : ROLLBACK (pas d'INSERT/UPDATE)
UI : Afficher le message d'erreur

Exemple 2 : Verifier les cles etrangeres

// Behavior Definition
define behavior for ZI_Travel alias Travel
{
validation validateCustomer on save {
field CustomerId;
}
}
METHOD validateCustomer.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( CustomerId )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
" Collecter tous les CustomerIds
DATA(lt_customer_ids) = VALUE string_table(
FOR travel IN lt_travel ( travel-CustomerId )
).
" Verifier si les clients existent (via Released API)
SELECT Customer
FROM I_Customer
FOR ALL ENTRIES IN @lt_customer_ids
WHERE Customer = @lt_customer_ids-table_line
INTO TABLE @DATA(lt_valid_customers).
" Erreur pour les clients inexistants
LOOP AT lt_travel INTO DATA(ls_travel).
IF NOT line_exists( lt_valid_customers[ table_line = ls_travel-CustomerId ] ).
APPEND VALUE #(
%tky = ls_travel-%tky
%element-CustomerId = if_abap_behv=>mk-on
) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-CustomerId = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Le client { ls_travel-CustomerId } n'existe pas|
)
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.

Exemple 3 : Regle metier complexe

// Validation : Remise seulement pour les clients Premium
validation validateDiscount on save {
field Discount, CustomerId;
}
METHOD validateDiscount.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( CustomerId Discount TotalPrice )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
" Charger les categories clients
SELECT Customer, CustomerClassification
FROM I_Customer
FOR ALL ENTRIES IN @lt_travel
WHERE Customer = @lt_travel-CustomerId
INTO TABLE @DATA(lt_customers).
LOOP AT lt_travel INTO DATA(ls_travel).
" Regle : > 10% de remise seulement pour clients Premium (Categorie 'A')
IF ls_travel-Discount > 10.
DATA(ls_customer) = VALUE #( lt_customers[ Customer = ls_travel-CustomerId ] OPTIONAL ).
IF ls_customer-CustomerClassification <> 'A'.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-Discount = if_abap_behv=>mk-on
) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-Discount = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Remise superieure a 10% seulement pour clients Premium (actuel : { ls_customer-CustomerClassification })|
)
) TO reported-travel.
ENDIF.
ENDIF.
" Regle 2 : Remise max. 50% du prix total
IF ls_travel-Discount > ( ls_travel-TotalPrice / 2 ).
APPEND VALUE #(
%tky = ls_travel-%tky
%element-Discount = if_abap_behv=>mk-on
) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-Discount = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'La remise ne peut pas depasser 50% du prix total"
)
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.

Timing : on modify vs on save

on modify (seulement Determination!)

determination calculate on modify { create; update; }

Quand execute :

  • ✅ Immediatement apres l’operation CREATE/UPDATE
  • ✅ AVANT que la Validation ne s’execute
  • ✅ Plusieurs fois possible (a chaque Modify)

Cas d’utilisation :

  • Definir les valeurs par defaut immediatement
  • Calculer les champs qui sont verifies dans la Validation
  • Feedback utilisateur (le champ est rempli immediatement dans l’UI)

on save (Determination & Validation!)

determination finalize on save { update; }
validation validateData on save { field Status; }

Quand execute :

  • ✅ Juste avant le DB-Commit
  • ✅ APRES toutes les Determinations on modify
  • ✅ Seulement 1 fois par cycle de Save

Cas d’utilisation Determination :

  • Calculs finaux (ex. checksums)
  • Champs d’audit (LastChangedBy, LastChangedAt)
  • Attribution de numeros depuis les plages de numeros DB

Cas d’utilisation Validation :

  • Verifier les regles metier
  • Assurer la coherence
  • Valider les cles etrangeres

Ordre d’execution

Action utilisateur : CREATE/UPDATE
┌───────────────────────────────────────┐
│ 1. DETERMINATION on modify (create) │ ← Immediatement
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ 2. DETERMINATION on modify (update) │ ← A chaque Update
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ Utilisateur : Appeler COMMIT ENTITIES │
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ 3. DETERMINATION on save │ ← Juste avant la DB
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ 4. VALIDATION on save │ ← Verifications
└───────────────┬───────────────────────┘
├─ Erreur? → ROLLBACK, l'utilisateur voit le message d'erreur
▼ Succes
┌───────────────────────────────────────┐
│ 5. INSERT/UPDATE dans la base de donnees │ ← Persistant!
└───────────────────────────────────────┘

Exemple avec les deux :

define behavior for ZI_Travel alias Travel
{
create;
update;
// Etape 1 : Definir le status immediatement
determination setInitialStatus on modify { create; }
// Etape 2 : Recalculer lors d'un changement de champ
determination calculateTotal on modify { field BeginDate, EndDate; }
// Etape 3 : Valeurs finales avant le Save
determination setApprovalData on save { update; }
// Etape 4 : Validations
validation validateDates on save { field BeginDate, EndDate; }
validation validateCustomer on save { field CustomerId; }
}

Concevoir correctement les messages d’erreur

Niveaux de severite

" ERROR : Bloque le Save
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'La date de fin doit etre apres la date de debut"
)
" WARNING : Permet le Save, affiche un avertissement
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-warning
text = 'Le voyage est tres court (< 3 jours)"
)
" INFO : Seulement informatif
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-information
text = 'La remise a ete appliquee automatiquement"
)
" SUCCESS : Confirmation positive
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-success
text = 'Voyage approuve avec succes"
)

Message avec Message Class

" Au lieu de texte code en dur → Utiliser une Message Class
APPEND VALUE #(
%tky = ls_travel-%tky
%element-EndDate = if_abap_behv=>mk-on
%msg = new_message(
id = 'ZTRAVEL_MSG' " Message Class (SE91)
number = '001' " Message Number
severity = if_abap_behv_message=>severity-error
v1 = ls_travel-BeginDate " Parametre &1
v2 = ls_travel-EndDate " Parametre &2
)
) TO reported-travel.
" Dans SE91 : Message ZTRAVEL_MSG/001
" Texte : "La date de fin &2 doit etre apres la date de debut &1"

Marquer plusieurs champs

" L'erreur concerne BeginDate ET EndDate
APPEND VALUE #(
%tky = ls_travel-%tky
%element-BeginDate = if_abap_behv=>mk-on
%element-EndDate = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Periode de voyage invalide"
)
) TO reported-travel.
" L'UI marque LES DEUX champs en rouge

Bonnes pratiques

✅ A FAIRE : Determinations

" ✅ Definir des valeurs, ne pas verifier
METHOD setDefaults.
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status Currency )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
Status = 'O"
Currency = 'EUR' ) ).
ENDMETHOD.
" ✅ on modify pour le feedback utilisateur
determination calculatePrice on modify { field Quantity, UnitPrice; }
" → L'utilisateur voit immediatement le nouveau prix
" ✅ on save pour les valeurs finales
determination generateDocumentNumber on save { create; }
" → Le numero est attribue seulement lors du Save final

✅ A FAIRE : Validations

" ✅ Seulement verifier, ne pas modifier
METHOD validateAmount.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel FIELDS ( Amount ) WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
LOOP AT lt_travel INTO DATA(ls_travel) WHERE Amount <= 0.
APPEND VALUE #( %tky = ls_travel-%tky ) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Le montant doit etre superieur a 0"
)
) TO reported-travel.
ENDLOOP.
ENDMETHOD.
" ✅ Performance : Bulk-Read au lieu de boucle
SELECT Customer FROM I_Customer
FOR ALL ENTRIES IN @lt_travel
WHERE Customer = @lt_travel-CustomerId
INTO TABLE @DATA(lt_valid).
" ✅ Messages d'erreur explicites
text = |Le client { ls_travel-CustomerId } n'existe pas dans le systeme|
" Au lieu de : "Validation echouee"

❌ A NE PAS FAIRE

" ❌ NE PAS modifier dans une Validation
METHOD validateData.
" FAUX : Une Validation ne doit PAS modifier!
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel UPDATE FIELDS ( Status ) WITH ...
" → Peut causer des incoherences!
ENDMETHOD.
" ❌ NE PAS verifier et abandonner dans une Determination
METHOD setDefaults.
IF ls_travel-Amount <= 0.
" FAUX : Une Determination ne devrait pas valider!
APPEND ... TO failed-travel. " ❌ Utilisez une Validation!
ENDIF.
ENDMETHOD.
" ❌ NE PAS utiliser on modify pour les acces DB
determination getCustomerData on modify { field CustomerId; }
" → A chaque modification du champ = appel DB
" → Mieux : on save (seulement 1x avant le Commit)
" ❌ NE PAS utiliser des messages d'erreur generiques
text = 'Erreur' " ❌ Pas utile
text = 'Validation failed' " ❌ Quel est le probleme?
" → Concret : "La date de fin doit etre apres la date de debut"

Tests

CLASS ltc_determinations DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_env TYPE REF TO if_cds_test_environment.
METHODS:
setup,
teardown,
test_set_initial_status FOR TESTING,
test_calculate_total FOR TESTING.
ENDCLASS.
CLASS ltc_determinations IMPLEMENTATION.
METHOD setup.
mo_env = cl_cds_test_environment=>create( i_for_entity = 'ZI_Travel' ).
ENDMETHOD.
METHOD test_set_initial_status.
" Arrange : Creer un Travel sans Status
MODIFY ENTITIES OF zi_travel
ENTITY Travel
CREATE FIELDS ( AgencyId CustomerId )
WITH VALUE #( ( %cid = 'T1' AgencyId = '001' CustomerId = '042' ) )
MAPPED DATA(mapped).
COMMIT ENTITIES.
" Act : La Determination devrait avoir defini le Status
READ ENTITIES OF zi_travel
ENTITY Travel FIELDS ( Status )
WITH VALUE #( ( %cid = 'T1' ) )
RESULT DATA(lt_travel).
" Assert : Status = 'O"
cl_abap_unit_assert=>assert_equals(
exp = 'O"
act = lt_travel[ 1 ]-Status
msg = 'La Determination devrait definir le Status a O"
).
ENDMETHOD.
METHOD test_calculate_total.
" Test pour la determination de calcul
" ... (analogue a ci-dessus)
ENDMETHOD.
METHOD teardown.
ROLLBACK ENTITIES.
mo_env->destroy( ).
ENDMETHOD.
ENDCLASS.
CLASS ltc_validations DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_env TYPE REF TO if_cds_test_environment.
METHODS:
setup,
test_validate_dates_error FOR TESTING,
test_validate_dates_success FOR TESTING.
ENDCLASS.
CLASS ltc_validations IMPLEMENTATION.
METHOD setup.
mo_env = cl_cds_test_environment=>create( i_for_entity = 'ZI_Travel' ).
ENDMETHOD.
METHOD test_validate_dates_error.
" Arrange : EndDate < BeginDate
MODIFY ENTITIES OF zi_travel
ENTITY Travel
CREATE FIELDS ( BeginDate EndDate )
WITH VALUE #( ( %cid = 'T1"
BeginDate = '20250615"
EndDate = '20250601' ) ) " FAUX!
FAILED DATA(failed).
COMMIT ENTITIES
RESPONSE OF zi_travel
FAILED DATA(commit_failed)
REPORTED DATA(commit_reported).
" Assert : Erreur attendue
cl_abap_unit_assert=>assert_not_initial(
act = commit_failed-travel
msg = 'La Validation devrait signaler une erreur"
).
" Verifier le message
cl_abap_unit_assert=>assert_bound(
act = commit_reported-travel[ 1 ]-%msg
msg = 'Un message d erreur devrait etre present"
).
ENDMETHOD.
METHOD test_validate_dates_success.
" Arrange : Donnees correctes
MODIFY ENTITIES OF zi_travel
ENTITY Travel
CREATE FIELDS ( BeginDate EndDate )
WITH VALUE #( ( %cid = 'T1"
BeginDate = '20250601"
EndDate = '20250615' ) )
FAILED DATA(failed).
COMMIT ENTITIES
RESPONSE OF zi_travel
FAILED DATA(commit_failed).
" Assert : Pas d'erreur
cl_abap_unit_assert=>assert_initial(
act = commit_failed-travel
msg = 'La Validation devrait reussir"
).
ENDMETHOD.
ENDCLASS.

Notes importantes / Bonnes pratiques

  • Determination = Definir, Validation = Verifier : Ne jamais melanger!
  • Respecter le timing : on modify pour un feedback immediat, on save pour les operations finales
  • La Validation ne doit PAS modifier : Seulement lire et remplir FAILED/REPORTED
  • Performance : Operations en masse au lieu de boucles avec des appels DB individuels
  • Messages explicites : Decrire concretement ce qui est faux
  • Marquer %element : Montre a l’utilisateur exactement quel champ pose probleme
  • IN LOCAL MODE : Toujours utiliser dans les Behavior Implementations
  • Bonne severite : ERROR bloque, WARNING permet le Save
  • Utiliser les Message Classes : Au lieu de textes codes en dur → Traductibilite
  • Ordre : Determinations → Validations → DB Save
  • Tester : Ecrire des tests unitaires pour CHAQUE Determination et Validation
  • Collecter les erreurs : Signaler toutes les erreurs d’un coup, ne pas abandonner a la premiere

Ressources supplementaires