Appearance
Lesson 13 — RAP Validations, Determinations, and Messages
In Lesson 10, you modeled the Reservation Business Object.
In Lesson 11, you added managed behavior.
In Lesson 12, you consumed that behavior with EML.
You can now:
text
CREATE
READ
UPDATE
DELETE
COMMIT
ROLLBACKBut the Business Object still accepts almost any technically valid Reservation.
For example:
text
blank Customer Name
past Reservation Date
zero Fee
missing CurrencyThe database table can store technically valid values.
The managed runtime can perform standard CRUD.
But neither one automatically knows your business rules.
That changes today.
You will add:
text
Determination
→ automatically derives data
Validation
→ checks whether data is acceptable
Message
→ explains a business problem to the consumerThe architecture becomes:
text
EML Consumer
↓
RAP Business Object
├─ Determinations
├─ Validations
└─ Messages
↓
Managed PersistenceThis is where the Behavior Pool starts containing real application logic.
Lesson information
| Teacher-led time | About 3 hours |
| Self-practice time | About 3 hours |
| Environment | SAP BTP ABAP Trial |
| Prerequisite | Lesson 12 |
| Business Object | ZR_RESERVATION_### |
| Behavior Pool | ZBP_R_RESV_### |
| Runtime test class | ZCL_RESV_RULES_### |
| Main outcome | Enforce and explain business rules |
| New behavior concepts | Determinations, validations, messages |
Replace:
text
###with your own student/group suffix.
Learning objectives
After the teacher-led part, you should be able to:
- explain the difference between technical validity and business validity;
- explain what a RAP determination does;
- explain what a RAP validation does;
- distinguish
on modifyfromon save; - define determinations and validations in a BDEF;
- generate handler methods with ADT Quick Fix;
- use
READ ENTITIES ... IN LOCAL MODEinside a Behavior Pool; - use
MODIFY ENTITIES ... IN LOCAL MODEinside a determination; - default a field automatically during the interaction phase;
- mark an invalid instance in
FAILED; - return an error message in
REPORTED; - attach a message to a specific field with
%element; - create messages with
new_message_with_text; - explain why a message by itself does not reject an instance;
- observe validation failure through
COMMIT ENTITIES; - prove that a failed save does not persist invalid data;
- repair invalid input and rerun the RAP transaction.
1. Technical rules are not enough
Your persistence already has technical definitions such as:
text
UUID
CHAR lengths
DATS
CURR
CUKY
NOT NULL
Domain fixed valuesThose are important.
But consider:
text
CustomerName = ''
ReservationDate = yesterday
Fee = 0
CurrencyCode = ''All of those values can still require application-level business decisions.
A database type cannot answer:
Is this Reservation acceptable for our application?
That belongs to business behavior.
2. Three new RAP concepts
Today introduces:
text
Determination
Validation
MessageDetermination
Automatically derives or defaults data when a trigger occurs.
Validation
Checks whether an instance satisfies a business rule.
Message
Communicates information, warning, or error details back to a consumer.
3. Determination vs validation
Use this simple distinction:
text
Determination
→ "I can derive/fix this automatically."
Validation
→ "The consumer must provide acceptable data."Example:
text
Status missing on create
→ determination can default it to NBut:
text
Customer Name missing
→ validation rejects the saveWe do not silently invent a customer name.
4. The Reservation rules for today
Add one determination:
text
If a new Reservation has no Status
→ set Status = NAdd three validations:
text
Customer Name
→ must not be initial
Reservation Date
→ must be today or later
Fee / Currency
→ Fee must be greater than zero
→ Currency Code must not be initialThese are deliberately small rules.
The goal is to understand the RAP mechanism.
5. Trigger timing matters
RAP behavior can run at different times.
Today the important timings are:
text
on modify
on saveon modify
Runs during the interaction phase when its trigger condition is met.
on save
Runs as part of the save processing before persistence is finalized.
That difference will be visible in your EML test.
6. Our determination runs on modify
We want Status to appear automatically as soon as a create request enters the RAP transaction.
So define:
text
setInitialStatus
→ on modify
→ trigger = createExpected flow:
text
EML CREATE without Status
↓
determination runs
↓
Status becomes N
↓
EML READ before COMMIT sees N7. Our validations run on save
The validation rules should decide whether the transaction may be saved.
Expected flow:
text
EML CREATE
↓
interaction phase
↓
COMMIT ENTITIES
↓
validations run
↓
valid?
↙ ↘
yes no
↓ ↓
save FAILED + REPORTED8. Open the existing Behavior Definition
Open the Behavior Definition for:
text
ZR_RESERVATION_###Do not create a second BDEF.
You are extending the behavior contract you built in Lesson 11.
9. Add the determination declaration
Inside the behavior body, add:
abap
determination setInitialStatus on modify { create; }Read it as:
text
Behavior implementation name:
setInitialStatus
Timing:
on modify
Trigger:
create10. Add the customer validation
Add:
abap
validation validateCustomer on save
{ create; field CustomerName; }This validation is relevant when:
text
an instance is createdor when:
text
CustomerName is changed11. Add the date validation
Add:
abap
validation validateDate on save
{ create; field ReservationDate; }The validation will reject a date earlier than the current system date.
12. Add the fee validation
Add:
abap
validation validateFee on save
{ create; field Fee, CurrencyCode; }The method will enforce both parts of the monetary business rule.
13. BDEF after adding business rules
The behavior should now contain these declarations in addition to the Lesson 11 content:
abap
determination setInitialStatus on modify { create; }
validation validateCustomer on save
{ create; field CustomerName; }
validation validateDate on save
{ create; field ReservationDate; }
validation validateFee on save
{ create; field Fee, CurrencyCode; }Do not remove:
text
create
update
delete
managed UUID numbering
read-only fields
mapping
lock master
ETagThe new rules extend the existing contract.
14. Complete BDEF reference
Your complete BDEF should now be equivalent to:
abap
managed implementation in class zbp_r_resv_### unique;
strict ( 2 );
define behavior for ZR_Reservation_### alias Reservation
persistent table zresv_###
lock master
authorization master ( none )
etag master LocalLastChangedAt
{
create;
update;
delete;
field ( numbering : managed, readonly ) Uuid;
field ( readonly )
LocalCreatedBy,
LocalCreatedAt,
LocalLastChangedBy,
LocalLastChangedAt,
LastChangedAt;
determination setInitialStatus on modify { create; }
validation validateCustomer on save
{ create; field CustomerName; }
validation validateDate on save
{ create; field ReservationDate; }
validation validateFee on save
{ create; field Fee, CurrencyCode; }
mapping for zresv_###
{
Uuid = uuid;
ReservationNo = reservation_no;
CustomerName = customer_name;
CustomerEmail = customer_email;
WorkshopCode = workshop_code;
ReservationDate = reservation_date;
Status = status;
Fee = fee;
CurrencyCode = currency_code;
Notes = notes;
LocalCreatedBy = local_created_by;
LocalCreatedAt = local_created_at;
LocalLastChangedBy = local_last_changed_by;
LocalLastChangedAt = local_last_changed_at;
LastChangedAt = last_changed_at;
}
}15. Generate the handler methods
After adding the determination and validations, ADT will know that implementation methods are required.
Place the cursor on each declaration or unresolved handler requirement.
Use:
text
Ctrl+1Choose the Quick Fix that adds the missing implementation methods to the Behavior Pool.
Open:
text
ZBP_R_RESV_###The implementation is placed in local handler code inside the Behavior Pool.
16. The handler method signatures
Your local handler will need methods equivalent to:
abap
METHODS setInitialStatus
FOR DETERMINE ON MODIFY
IMPORTING keys FOR Reservation~setInitialStatus.
METHODS validateCustomer
FOR VALIDATE ON SAVE
IMPORTING keys FOR Reservation~validateCustomer.
METHODS validateDate
FOR VALIDATE ON SAVE
IMPORTING keys FOR Reservation~validateDate.
METHODS validateFee
FOR VALIDATE ON SAVE
IMPORTING keys FOR Reservation~validateFee.Let ADT generate the signatures when possible.
Do not manually guess framework method signatures if Quick Fix is available.
17. Why behavior implementation uses IN LOCAL MODE
Inside the Behavior Pool, the implementation needs to work with its own BO transaction.
Use EML such as:
text
READ ENTITIES ... IN LOCAL MODE
MODIFY ENTITIES ... IN LOCAL MODEIN LOCAL MODE is available when a Behavior Pool accesses its own BO. It bypasses access, authorization, feature-control, and precheck restrictions where applicable; determinations and save validations still apply.
It is different from the Lesson 12 external consumer class.
Lesson 12 correctly did not use it.
18. Implement setInitialStatus
The determination must:
- read the affected Reservation instances;
- find instances where
Statusis initial; - update only those instances to
N.
Use:
abap
METHOD setInitialStatus.
READ ENTITIES OF ZR_Reservation_### IN LOCAL MODE
ENTITY Reservation
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(reservations).
DATA updates TYPE TABLE FOR UPDATE ZR_Reservation_###.
LOOP AT reservations INTO DATA(reservation)
WHERE Status IS INITIAL.
APPEND VALUE #(
%tky = reservation-%tky
Status = 'N'
) TO updates.
ENDLOOP.
IF updates IS NOT INITIAL.
MODIFY ENTITIES OF ZR_Reservation_### IN LOCAL MODE
ENTITY Reservation
UPDATE FIELDS ( Status )
WITH updates.
ENDIF.
ENDMETHOD.Replace ###.
19. Why read before determining?
The determination receives:
text
keysfor the affected instances.
The method still needs the current BO data to answer:
text
Is Status initial?So it reads:
text
Statusfrom the transactional BO state.
20. Why not overwrite an existing Status?
The determination applies only when:
text
Status IS INITIALThis matters.
A determination should not blindly replace a value the consumer intentionally provided.
Example:
text
Consumer creates Reservation with Status = COur determination does not force it back to:
text
NBusiness rules can become stricter later if required.
21. What does the determination change?
The determination modifies:
text
RAP transactional statenot the database table directly.
It does not use:
abap
UPDATE zresv_###The implementation talks to its own BO using EML.
22. Implement validateCustomer
Use:
abap
METHOD validateCustomer.
READ ENTITIES OF ZR_Reservation_### IN LOCAL MODE
ENTITY Reservation
FIELDS ( CustomerName )
WITH CORRESPONDING #( keys )
RESULT DATA(reservations).
LOOP AT reservations INTO DATA(reservation).
IF reservation-CustomerName IS INITIAL.
APPEND VALUE #(
%tky = reservation-%tky
) TO failed-reservation.
APPEND VALUE #(
%tky = reservation-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Customer name is required'
)
%element-CustomerName = if_abap_behv=>mk-on
) TO reported-reservation.
ENDIF.
ENDLOOP.
ENDMETHOD.23. FAILED and REPORTED have different jobs
This distinction is essential.
FAILED
Marks an instance as failed.
It is what tells RAP:
text
this instance must not successfully complete the requested processingREPORTED
Carries messages and information.
It explains:
text
whythe business rule failed.
A message alone is not a reliable failure signal.
24. Why append the same %tky?
The validation is working on one specific BO instance.
The technical transactional key:
text
%tkyconnects both:
text
FAILED entry
REPORTED messageto that instance.
25. Create a message with new_message_with_text
This helper:
abap
new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Customer name is required'
)creates a RAP message.
Today we use direct text so the mechanism remains easy to see.
Later production designs may use message classes and translatable texts.
26. Message severity
Common RAP message severities include concepts such as:
text
success
information
warning
errorOur validation failures use:
abap
if_abap_behv_message=>severity-errorbecause the data must not be saved.
27. Attach the message to a field
This component:
abap
%element-CustomerName = if_abap_behv=>mk-ontargets the message at:
text
CustomerNameThis becomes especially useful when a UI consumes the BO later.
A consumer can understand:
text
the error belongs to this fieldrather than receiving only a generic message.
28. Implement validateDate
Use:
abap
METHOD validateDate.
READ ENTITIES OF ZR_Reservation_### IN LOCAL MODE
ENTITY Reservation
FIELDS ( ReservationDate )
WITH CORRESPONDING #( keys )
RESULT DATA(reservations).
DATA(today) = cl_abap_context_info=>get_system_date( ).
LOOP AT reservations INTO DATA(reservation).
IF reservation-ReservationDate < today.
APPEND VALUE #(
%tky = reservation-%tky
) TO failed-reservation.
APPEND VALUE #(
%tky = reservation-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Reservation date cannot be in the past'
)
%element-ReservationDate = if_abap_behv=>mk-on
) TO reported-reservation.
ENDIF.
ENDLOOP.
ENDMETHOD.29. Why use the system date helper?
Use:
abap
cl_abap_context_info=>get_system_date( )instead of hard-coding a date.
The validation must remain correct whenever the exercise is run.
This rule applies when creating a Reservation or changing its date. It does not prohibit an existing Reservation from becoming historical, and changing only its notes does not trigger the date check.
30. Implement validateFee
Use:
abap
METHOD validateFee.
READ ENTITIES OF ZR_Reservation_### IN LOCAL MODE
ENTITY Reservation
FIELDS ( Fee CurrencyCode )
WITH CORRESPONDING #( keys )
RESULT DATA(reservations).
LOOP AT reservations INTO DATA(reservation).
DATA(instance_failed) = abap_false.
IF reservation-Fee <= 0.
instance_failed = abap_true.
APPEND VALUE #(
%tky = reservation-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Fee must be greater than zero'
)
%element-Fee = if_abap_behv=>mk-on
) TO reported-reservation.
ENDIF.
IF reservation-CurrencyCode IS INITIAL.
instance_failed = abap_true.
APPEND VALUE #(
%tky = reservation-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Currency code is required'
)
%element-CurrencyCode = if_abap_behv=>mk-on
) TO reported-reservation.
ENDIF.
IF instance_failed = abap_true.
APPEND VALUE #(
%tky = reservation-%tky
) TO failed-reservation.
ENDIF.
ENDLOOP.
ENDMETHOD.Mark each instance failed once within this validation while reporting a separate message for each invalid field. The Companion's fee validation reference uses the same pattern.
31. Activate the behavior changes
Use:
text
Ctrl+F2for syntax check.
Then activate related objects:
text
Ctrl+Shift+F3Verify:
text
Behavior Definition active
Behavior Pool active
Root CDS activeDo not begin the runtime test until the BO activates cleanly.
32. Create the runtime test class
Create:
text
ZCL_RESV_RULES_###Implement:
text
IF_OO_ADT_CLASSRUNThis class is an external BO consumer.
Therefore it must use normal EML:
text
MODIFY ENTITIES
READ ENTITIES
COMMIT ENTITIES
ROLLBACK ENTITIESIt must not use:
text
IN LOCAL MODE33. Use reserved Lesson 13 numbers
Use:
text
94000001
94000002Meaning:
text
94000001
→ valid Reservation
94000002
→ deliberately invalid ReservationDo not reuse the Lesson 12 numbers.
34. Make the exercise repeatable
Before the tests, remove old Lesson 13 rows safely if they exist.
Recommended pattern:
text
read root CDS to discover UUIDs
↓
delete those UUIDs through EML
↓
COMMIT ENTITIESNever run an unrestricted table delete.
Use the Companion's cleanup reference, including its failure guards, before starting either test.
35. Test 1 — create a valid Reservation without Status
The first create deliberately omits:
text
StatusUse values equivalent to:
text
ReservationNo = 94000001
CustomerName = RAP Rules Student
CustomerEmail = rules@example.com
WorkshopCode = RAP201
ReservationDate = today
Fee = 200.00
CurrencyCode = EUR
Notes = Determination testDo not provide:
text
Status
Uuid
administrative fields36. Execute the valid CREATE
Use:
abap
MODIFY ENTITIES OF ZR_Reservation_###
ENTITY Reservation
CREATE FIELDS (
ReservationNo
CustomerName
CustomerEmail
WorkshopCode
ReservationDate
Fee
CurrencyCode
Notes )
WITH VALUE #(
( %cid = 'VALID'
ReservationNo = '94000001'
CustomerName = 'RAP Rules Student'
CustomerEmail = 'rules@example.com'
WorkshopCode = 'RAP201'
ReservationDate = cl_abap_context_info=>get_system_date( )
Fee = '200.00'
CurrencyCode = 'EUR'
Notes = 'Determination test' ) )
MAPPED DATA(mapped_valid)
FAILED DATA(failed_valid_modify)
REPORTED DATA(reported_valid_modify).37. What should happen during MODIFY?
The determination is:
text
on modifySo during this interaction phase:
text
Status initial
↓
setInitialStatus
↓
Status = NThe on-save validations have not yet reached their save trigger.
38. Read the valid Reservation before COMMIT
Retrieve the mapped UUID and read the instance.
Check the interaction response before accessing its mapping:
abap
IF failed_valid_modify IS NOT INITIAL
OR NOT line_exists( mapped_valid-reservation[ %cid = 'VALID' ] ).
out->write( failed_valid_modify ).
out->write( reported_valid_modify ).
ROLLBACK ENTITIES.
RETURN.
ENDIF.
DATA(uuid_valid) =
mapped_valid-reservation[ %cid = 'VALID' ]-Uuid.Then:
abap
READ ENTITIES OF ZR_Reservation_###
ENTITY Reservation
FIELDS (
Uuid
ReservationNo
CustomerName
Status
Fee
CurrencyCode )
WITH VALUE #( ( Uuid = uuid_valid ) )
RESULT DATA(valid_before_commit)
FAILED DATA(failed_valid_read).Output the result.
Expected:
text
ReservationNo = 94000001
Status = NThat is your first direct proof of a determination.
39. Commit the valid Reservation
Use:
abap
COMMIT ENTITIES
RESPONSE OF ZR_Reservation_###
FAILED DATA(failed_valid_commit)
REPORTED DATA(reported_valid_commit).
DATA(valid_commit_subrc) = sy-subrc.
out->write( failed_valid_commit ).
out->write( reported_valid_commit ).
IF valid_commit_subrc <> 0 OR failed_valid_commit IS NOT INITIAL.
ROLLBACK ENTITIES.
RETURN.
ENDIF.Expected:
text
no validation failure
save succeedsCheck:
text
FAILED
REPORTED
sy-subrc40. Test 2 — deliberately invalid create
Prepare:
abap
DATA yesterday TYPE d.
yesterday = cl_abap_context_info=>get_system_date( ) - 1.Create Reservation 94000002 with:
text
CustomerName = blank
ReservationDate = yesterday
Fee = 0
CurrencyCode = blank
Status = omittedThe determination can still default Status.
But the validations must reject the save.
41. Invalid CREATE request
Use an EML create equivalent to:
abap
MODIFY ENTITIES OF ZR_Reservation_###
ENTITY Reservation
CREATE FIELDS (
ReservationNo
CustomerName
CustomerEmail
WorkshopCode
ReservationDate
Fee
CurrencyCode
Notes )
WITH VALUE #(
( %cid = 'INVALID'
ReservationNo = '94000002'
CustomerName = ''
CustomerEmail = 'invalid@example.com'
WorkshopCode = 'RAP201'
ReservationDate = yesterday
Fee = '0.00'
CurrencyCode = ''
Notes = 'Validation test' ) )
MAPPED DATA(mapped_invalid)
FAILED DATA(failed_invalid_modify)
REPORTED DATA(reported_invalid_modify).42. The important observation before COMMIT
Inspect:
text
failed_invalid_modify
reported_invalid_modifyThe save validations are declared:
text
on saveSo the interaction-phase create can reach the transactional buffer before the save checks reject it.
This is the key Lesson 13 observation:
text
MODIFY accepted into RAP transaction
does not automatically mean
transaction can be saved43. Commit the invalid Reservation
Now execute:
abap
COMMIT ENTITIES
RESPONSE OF ZR_Reservation_###
FAILED DATA(failed_invalid_commit)
REPORTED DATA(reported_invalid_commit).
DATA(invalid_commit_subrc) = sy-subrc.This is where the validation rules become visible to the external consumer.
Inspect both response structures.
Expect invalid_commit_subrc = 4 and a nonempty failed_invalid_commit. If the save unexpectedly succeeds, repair the validation declarations and implementations and remove the persisted test row through the EML cleanup before rerunning. A later rollback cannot undo an already successful commit.
44. Expected failed instance
The save response should identify the invalid Reservation in:
text
FAILEDThat is the programmatic signal that the instance failed validation.
Do not detect failure only by searching message text.
45. Expected messages
REPORTED should contain messages equivalent to:
text
Customer name is required
Reservation date cannot be in the past
Fee must be greater than zero
Currency code is requiredValidation execution order is not fixed, so do not depend on message order. To print readable message text from %msg, use the Companion's console example.
The important content is:
text
instance
severity
message
target element46. Messages explain; FAILED rejects
Memorize the relationship, not the syntax:
text
FAILED
→ this instance failed
REPORTED
→ here is useful information about itSAP RAP does not treat a message by itself as a reliable signal that processing must terminate.
Your implementation must mark the failed instance.
47. Roll back after the failed save test
After inspecting the failed save response, reset the RAP transaction:
abap
ROLLBACK ENTITIES.This removes the invalid buffered test state.
Do not leave the consumer in an unresolved transaction.
48. Verify invalid data was not persisted
Open:
text
ZR_RESERVATION_###with:
text
F8Filter or locate:
text
94000002Expected:
text
not persistedBut:
text
94000001should exist with:
text
Status = N49. Test 3 — invalid UPDATE
Now prove validations also protect an existing instance.
Take the surviving:
text
94000001and attempt to update:
text
ReservationDate = yesterdayUse EML UPDATE FIELDS.
The interaction-phase update enters the transaction.
The save validation should reject it at commit.
50. Roll back the invalid UPDATE
After the validation failure:
abap
ROLLBACK ENTITIES.Read 94000001 again.
Expected:
text
ReservationDate
=
original valid dateThe invalid update was not persisted.
51. Determination and validation live in the provider
Notice where the rules are implemented:
text
ZBP_R_RESV_###not:
text
ZCL_RESV_RULES_###The consumer does not decide:
text
default Status = N
date must not be past
Fee must be positiveThe Business Object owns those rules.
That means future consumers can reuse them.
52. Why this matters for future OData consumers
Later you will expose the BO through an OData service.
A Fiori application should not need to reimplement:
text
Reservation Date validation
Fee validation
default StatusThe Business Object already owns the rules.
Architecture:
text
ABAP EML consumer
↘
RAP BO rules
↗
OData / Fiori consumerDifferent consumers can share the same business behavior.
53. Determinations are not validations
Do not write a determination that silently changes:
text
Fee = -10into:
text
Fee = 10unless that is genuinely the business rule.
Automatic correction can hide bad input.
A determination is appropriate when data is legitimately derivable.
A validation is appropriate when the consumer must correct invalid input.
54. Trigger design matters
A validation should not run for every possible change if it only depends on one field.
For example:
abap
validation validateCustomer on save
{ create; field CustomerName; }expresses its relevant triggers.
This improves clarity and avoids unnecessary execution.
55. Do not duplicate rules in the consumer
Wrong architecture:
text
ZCL_RESV_RULES_###
checks CustomerName
↓
then calls BOCorrect architecture:
text
Consumer sends request
↓
RAP BO validates CustomerNameA consumer may perform user-experience checks later.
But the authoritative backend rule belongs in the BO.
56. Messages today are simple text messages
Today we use:
abap
new_message_with_text( )because it makes the RAP message mechanism easy to see.
For larger applications, you normally want:
text
translatable messages
message classes
stable message identitiesThat is a refinement, not the core concept of this lesson.
57. State vs transition messages — awareness only
RAP supports different message lifecycles.
Today our simple validation examples focus on:
text
failed instance
reported error message
field targetWe are not yet building:
text
draft UI message persistence
state-area lifecycle
advanced service message handlingThose concepts are easier to understand once the service and draft layers exist.
58. Common mistake — message but no failed entry
This is incomplete:
abap
APPEND VALUE #(
%tky = reservation-%tky
%msg = ...
) TO reported-reservation.if your intention is:
text
reject the invalid instanceAlso add it to:
text
failed-reservation59. Common mistake — direct SQL in the Behavior Pool
Do not implement the determination with:
abap
UPDATE zresv_###Use:
text
MODIFY ENTITIES ... IN LOCAL MODEThe provider should work with RAP transactional state.
60. Common mistake — IN LOCAL MODE in the external consumer
Provider implementation:
text
IN LOCAL MODEExternal consumer:
text
normal EMLDo not copy provider-side EML syntax into ZCL_RESV_RULES_###.
61. Common mistake — validating only in the UI
A UI-only validation can be bypassed by:
text
another UI
EML
API client
integrationThe BO must protect its own business invariants.
62. Architecture at the end of Lesson 13
You now have:
text
Consumer
↓
EML / future OData
↓
ZR_RESERVATION_###
↓
Managed Behavior
├─ standard CRUD
├─ determination
├─ validations
└─ messages
↓
ZRESV_###This is a much more realistic transactional backend.
63. Knowledge check
1. What is the difference between technical validity and business validity?
2. What does a determination do?
3. What does a validation do?
4. Why does setInitialStatus run on modify?
5. Why do our validations run on save?
6. What is the difference between FAILED and REPORTED?
7. Why is a message alone not enough to reject an instance?
8. What does %element-CustomerName communicate?
9. Why does provider implementation use IN LOCAL MODE?
10. Why should an external consumer not use IN LOCAL MODE?
11. Why does the determination read the affected instance before updating it?
12. Why should it not overwrite an explicitly supplied Status?
13. Where should authoritative Reservation rules live?
14. What should happen to invalid data when COMMIT ENTITIES runs?
15. Why is the same backend validation useful for both EML and future OData consumers?
64. Teacher-led completion checklist
65. End-of-day mental model
Before leaving Lesson 13, explain:
text
Determination
→ derive/default valid business data
Validation
→ protect a business rule
FAILED
→ reject the affected instance
REPORTED
→ explain what happened
%element
→ point the message at a fieldAnd draw:
text
MODIFY ENTITIES
↓
on-modify determination
↓
transactional buffer
↓
COMMIT ENTITIES
↓
on-save validations
↙ ↘
valid invalid
↓ ↓
save FAILED + REPORTEDThat model prepares you for Lesson 14:
text
Actions
Field Control
Dynamic Feature Control