RAP Basics
Architect / Cross-trackintermediate

RAP Basics Part 7: Actions, Determinations and Validations — Design Decisions

Key takeaway

Decide where each piece of business logic belongs in a RAP BO: validations (check on save, reject with messages), determinations (derive values on modify or on save), actions (explicit user or API operations, instance, static and factory), side effects for Fiori, and the trigger conditions that keep logic efficient.

Explanation

📌 KEY POINTS
✅ Validation = check; runs on save (and in draft Prepare), reports failed keys and messages, never changes data.

✅ Determination = derivation; on modify (immediate, e.g. default values, recalculated totals) or on save (e.g. draw number, set final status).

✅ Action = explicit operation triggered by the user or API (acceptTravel, copy, recalculate) — instance, static, or factory (creates a new instance).

✅ Trigger conditions (on create; field AgencyID;) decide when logic runs — narrow triggers keep performance under control.

⚠️ Putting checks into determinations or derivations into validations breaks the transactional model — validations must not modify, determinations must not reject.

━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE

Part 6 controlled operations and fields. Now we place business logic. Part 9 shows the implementation code.

━━━━━━━━━━━━━━━━━━━━
▶ 1. VALIDATIONS

  • validation validateCustomer on save { create; field CustomerID; }
  • Read data, check, fill failed-travel and reported-travel.
  • A failed validation stops the save; with draft it runs in Prepare/Activate.

━━━━━━━━━━━━━━━━━━━━
▶ 2. DETERMINATIONS

  • determination setInitialStatus on modify { create; } — default status 'O' (open).
  • determination calculateTotal on modify { field BookingFee, CurrencyCode; } — immediate recalculation.
  • determination drawTravelID on save { create; } — number assigned only when saving.
  • Determinations run IN LOCAL MODE: they may set readonly fields.

━━━━━━━━━━━━━━━━━━━━
▶ 3. ACTIONS

  • Instance action: action acceptTravel result [1] $self; — operates on selected instances.
  • Static action: static action massRecalculate; — no instance.
  • Factory action: factory action copyTravel [1]; — creates a new instance from an existing one.
  • Actions can take a parameter (abstract entity) for user input.

━━━━━━━━━━━━━━━━━━━━
▶ 4. DRAFT AND SIDE EFFECTS

  • draft determine action Prepare { validation validateCustomer; } — run validations before activation.
  • side effects { field BookingFee affects field TotalPrice; } — tells Fiori to reload affected fields.

━━━━━━━━━━━━━━━━━━━━
▶ 5. DECISION GUIDE

  • "Must not be saved if…" → validation.
  • "Should always be filled/recalculated when…" → determination.
  • "User clicks a button to…" → action.
  • "Different users may/may not…" → authorization or features, not validation.

━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP

  1. List business rules and classify each as validation, determination or action.
  2. Define triggers as narrowly as possible.
  3. Declare them in the BDEF; add side effects for recalculated fields.
  4. Add validations to draft determine action Prepare.
  5. Generate method stubs (quick fix) and implement (Part 9).

✅ CHECKPOINT: for any rule, you can say whether it is a validation, determination or action and which trigger it uses.

Code example

ABAP Code
// ===== STEP 1: logic declarations in the BDEF =====define behavior for ZI_Travel alias Travelpersistent table ztravel_adraft table ztravel_dlock master total etag LastChangedAtauthorization master ( instance )etag master LocalLastChangedAt{  create; update; delete;  association _Booking { create; with draft; } // ===== STEP 2: validations - check only, on save =====  validation validateCustomer on save { create; field CustomerID; }  validation validateDates    on save { create; field BeginDate, EndDate; } // ===== STEP 3: determinations - on modify vs on save =====  determination setInitialStatus on modify { create; }  determination calculateTotal   on modify { field BookingFee, CurrencyCode; }  determination drawTravelID     on save   { create; } // ===== STEP 4: actions - instance and factory =====  action ( features : instance ) acceptTravel result [1] $self;  action ( features : instance ) rejectTravel result [1] $self;  factory action copyTravel [1]; // ===== STEP 5: draft preparation and Fiori side effects =====  draft action Edit;  draft action Activate optimized;  draft action Discard;  draft action Resume;  draft determine action Prepare  {    validation validateCustomer;    validation validateDates;  }   side effects  {    field BookingFee affects field TotalPrice;  }}

Real project scenario

On an expense-claim BO, the team implemented the total amount calculation as a determination on save. Users entered line items in the Fiori object page but saw a total of zero until they pressed Save, and many rejected their own claims as "wrong". The architect changed it to determination on modify with trigger fields Amount and Currency, plus a side effect "field Amount affects field TotalAmount". The total now updated as soon as a line changed. In the same review, a "claim must not exceed policy limit" rule that had been written as a determination (resetting the amount to the limit) was moved into a validation, so users got a clear error instead of silently changed data.

Common mistakes

  • Implementing checks in determinations (silently correcting data) instead of rejecting in a validation.
  • Using determination on save for values the user expects to see immediately.
  • Broad triggers (every field) causing logic to run on every keystroke in draft.
  • Forgetting to list validations in draft determine action Prepare, so errors appear only at activation.
  • Using an action for something that should happen automatically (determination).

Best practices

  • Classify every rule before coding: validation, determination or action.
  • Keep triggers narrow — only the fields the logic depends on.
  • Draw numbers in determinations on save, never on modify with draft.
  • Add side effects so Fiori refreshes derived fields.
  • Keep actions small and return result $self so the UI refreshes.

Interview angle

Questions: "Difference between validation and determination?", "On modify vs on save — when do you use which?", "What is a factory action?"
Strong answer: validations check and reject with messages on save (and in Prepare for draft) and never change data; determinations derive values — on modify for immediate feedback, on save for final values like numbers. Actions are explicit operations; factory actions create new instances (copy). Senior answers mention narrow triggers, side effects for Fiori and draft determine action Prepare.

Practice this lesson

Quick check

1. A new travel should show status 'Open' immediately after the user clicks Create in Fiori. Which declaration fits?

2. Which RAP concept should stop the save of a travel whose end date is before its begin date?

3. What does a factory action such as copyTravel do in RAP?

Interview questions

1. An expense app put defaulting, validation and status transitions all into one big determination on save. Users get no immediate feedback, and wrong amounts are silently corrected. How would you restructure the logic?

Answer it in your own words first, then compare.

2. What is a determination?

Answer it in your own words first, then compare.

Practice more with Interview AI →

Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.

More lessons in this topic

Interview questions on this topic

Related SAP topics