Appearance
Lesson 13 Practice — Add Business Rules to Support Issues
In Lesson 12 Practice, you consumed the Support Issue Business Object with EML.
Now make the Business Object enforce its own business rules.
Target architecture:
text
ZCL_ISSUE_RULES_###
↓
EML
↓
ZR_ISSUE_###
↓
Managed RAP Behavior
├─ determination
├─ validations
└─ messages
↓
ZISSUE_###This practice is deliberately more independent than the guided Reservation lesson.
Do not copy the Reservation method implementations line for line.
Translate the concepts to the Issue domain.
Practice information
| Time | About 3 hours |
| Prerequisite | Lesson 13 teacher-led work |
| Business Object | ZR_ISSUE_### |
| Behavior Pool | ZBP_R_ISSUE_### |
| New test class | ZCL_ISSUE_RULES_### |
| Main focus | Business rules + RAP messages |
1. Verify the starting point
Before changing behavior, verify that these still activate:
text
ZR_ISSUE_###
Behavior Definition for ZR_ISSUE_###
ZBP_R_ISSUE_###
ZCL_ISSUE_EML_###Your Lesson 12 BO should already support:
text
create
update
delete
managed UUID numbering
locking
ETag
persistence mappingRepair prerequisite defects before adding new rules.
2. Business rules to implement
Add one determination:
text
If a new Issue has no Status
→ set Status = OAdd three validations:
text
Title
→ required
ReportedOn
→ cannot be in the future
EstimatedCost / CurrencyCode
→ cost cannot be negative
→ if cost is nonzero, CurrencyCode is required3. Decide the mechanisms before coding
Complete:
| Rule | Determination or Validation? | Timing |
|---|---|---|
Default Status to O | ||
| Title required | ||
| Reported date not future | ||
| Cost not negative | ||
| Currency required for nonzero cost |
Explain each choice.
4. Add the determination declaration
Add one BDEF determination for:
text
setInitialStatusRequirements:
text
timing = on modify
trigger = createDo not trigger it on every field change.
5. Add the Title validation declaration
Create:
text
validateTitleRequirements:
text
timing = on save
trigger = create or Title change6. Add the ReportedOn validation declaration
Create:
text
validateReportedOnRequirements:
text
timing = on save
trigger = create or ReportedOn change7. Add the cost validation declaration
Create:
text
validateCostRequirements:
text
timing = on save
trigger = create or EstimatedCost/CurrencyCode change8. Preserve the Lesson 11 behavior
Do not remove or replace:
text
create
update
delete
managed UUID numbering
read-only administrative fields
lock master
ETag master
persistence mappingThe new business rules extend the existing BO.
9. Generate handler methods
Use:
text
Ctrl+1from the BDEF where appropriate.
Generate/add the required handler methods inside:
text
ZBP_R_ISSUE_###Do not create a second Behavior Pool.
10. Implement the Status determination
Your method must:
- read the affected Issue instances with EML in local mode;
- inspect
Status; - select only Issues whose Status is initial;
- update those instances to:
text
O- use RAP EML, not direct SQL.
The final implementation must not overwrite a Status already provided by the consumer.
11. Prove the determination is idempotent
Explain why this logic is safe if RAP invokes it more than once:
text
only set O when Status is initialWhat would be wrong with:
text
always set Status = O?
12. Implement validateTitle
Read:
text
Titlefor the affected instances using:
text
READ ENTITIES ... IN LOCAL MODEIf Title is initial:
text
append instance to FAILED
append error message to REPORTED
target Title with %elementSuggested text:
text
Title is required13. Implement validateReportedOn
Read:
text
ReportedOnand compare it with:
text
current system dateReject:
text
ReportedOn > todaySuggested text:
text
Reported date cannot be in the futureTarget:
text
ReportedOn14. Implement validateCost
Read:
text
EstimatedCost
CurrencyCodeBusiness rules:
text
EstimatedCost < 0
→ invalid
EstimatedCost <> 0
AND CurrencyCode is initial
→ invalidSuggested messages:
text
Estimated cost cannot be negative
Currency code is required when cost is providedTarget the corresponding fields.
15. Why zero cost is allowed here
For this practice, assume:
text
EstimatedCost = 0means:
text
no estimate entered yetTherefore:
text
0 + blank currencyis acceptable.
This is a business assumption for the exercise.
Write it down.
Do not accidentally implement the Reservation fee rule, which was different.
16. FAILED vs REPORTED
For every validation implementation, explain:
text
What goes into FAILED?
What goes into REPORTED?
Why do you need both?A correct answer must make clear that a message alone does not reject an Issue.
17. Field-targeted messages
Your final validation messages should target:
text
Title
ReportedOn
EstimatedCost
CurrencyCodewhere relevant.
Do not return only generic unbound error text.
18. Activate the BO
Run:
text
Ctrl+F2Then activate related objects:
text
Ctrl+Shift+F3Final active objects must include:
text
ZR_ISSUE_###
Behavior Definition
ZBP_R_ISSUE_###19. Create the runtime test class
Create:
text
ZCL_ISSUE_RULES_###Implement:
text
IF_OO_ADT_CLASSRUNThis is an external consumer.
Do not use:
text
IN LOCAL MODEin this class.
20. Reserved Lesson 13 Issue Numbers
Use:
text
95000001
95000002Meaning:
text
95000001
→ valid determination test
95000002
→ invalid validation testDo not reuse Lesson 12 practice numbers.
21. Make the test repeatable
Before creating new test data:
- discover old
95000001/95000002rows; - retrieve their UUIDs;
- delete them through EML;
- commit the cleanup;
- inspect cleanup failures.
Continue only if both the delete and its commit succeed. On failure, output the responses, execute ROLLBACK ENTITIES, and stop the class. Capture sy-subrc immediately after each COMMIT ENTITIES before other operations.
Do not use direct SQL modification.
22. Test A — valid create without Status
Create Issue:
text
IssueNo = 95000001
Title = RAP rule practice
Description = Determination test
RequesterEmail = practice@example.com
Priority = H
Status = omitted
ReportedOn = today
EstimatedCost = 100.00
CurrencyCode = EURDo not provide:
text
Uuid
Status
administrative fields23. Inspect the interaction response
Request:
text
MAPPED
FAILED
REPORTEDfor the create.
Check that the create has a generated UUID.
Do not commit yet.
24. Read before COMMIT
Use:
text
READ ENTITIESto read Issue 95000001 from the current RAP transaction.
Expected:
text
Status = ORecord:
text
Status supplied by consumer:
Status read before commit:Explain what caused the difference.
25. Commit the valid Issue
Use:
text
COMMIT ENTITIESwith save responses.
Inspect:
text
FAILED
REPORTED
sy-subrcExpected:
text
successful save26. Verify valid persistence
Use:
text
F8on:
text
ZR_ISSUE_###Confirm:
text
95000001 exists
Status = O27. Test B — create an invalid Issue
Prepare a date-typed test value:
abap
DATA tomorrow TYPE d.
tomorrow = cl_abap_context_info=>get_system_date( ) + 1.Create 95000002 with:
text
Title = blank
ReportedOn = tomorrow
EstimatedCost = -25.00
CurrencyCode = blank
Status = omittedUse reasonable values for the other fields.
28. Inspect MODIFY responses before save
After:
text
MODIFY ENTITIESrecord:
text
MAPPED:
FAILED:
REPORTED:Then answer:
Why can the create reach the interaction phase even though the data will later fail validation?
29. Commit the invalid Issue
Now run:
text
COMMIT ENTITIESwith:
text
FAILED
REPORTEDsave responses.
Expected business problems:
text
Title is required
Reported date cannot be in the future
Estimated cost cannot be negativeBecause cost is nonzero and CurrencyCode is blank, also expect:
text
Currency code is required when cost is providedUse two independent checks in validateCost so that a negative cost with blank currency produces both cost messages. Add one FAILED row per invalid instance within that method. Validation execution order is not fixed, so compare the message contents and targets rather than their order.
Expect the commit return code to be 4 and the save FAILED response to identify the invalid Issue. If the commit unexpectedly succeeds, repair the rules and remove the saved test row through EML before rerunning; rollback cannot undo an earlier successful commit.
30. Prove the failed instance
Do not rely only on message text.
Identify the invalid instance in:
text
FAILEDThen identify the detailed problems in:
text
REPORTEDRecord:
text
Failed instance key:
Message 1:
Target:
Message 2:
Target:
Message 3:
Target:
Message 4:
Target:31. Roll back the failed test
After inspecting the save response:
text
ROLLBACK ENTITIESThen verify with CDS Data Preview:
text
95000002 is not persisted32. Test C — invalid update
Take the valid surviving Issue:
text
95000001Attempt to update:
text
ReportedOn = tomorrowDo not change anything else.
Run:
text
MODIFY ENTITIESthen:
text
COMMIT ENTITIESInspect the save validation response.
33. Roll back the invalid update
Use:
text
ROLLBACK ENTITIESRead the Issue again.
Expected:
text
ReportedOn = original valid dateDocument:
text
Attempted date:
Persisted date after rollback:34. Test D — valid update
Now perform a valid update:
text
EstimatedCost = 125.00
CurrencyCode = EURCommit it.
Verify through:
text
READ ENTITIES
F8 Data PreviewThis proves the cost validation allows valid changes.
35. Explain provider vs consumer
Complete:
text
Business rule implementation:
____________________________
External runtime test:
____________________________
Which class owns the rules?
____________________________
Which class merely proves them?
____________________________36. Explain IN LOCAL MODE
Why is it appropriate in:
text
ZBP_R_ISSUE_###but not in:
text
ZCL_ISSUE_RULES_###?
Use:
text
provider
consumer
BO contractin your explanation.
37. Repair exercise A — remove FAILED
Temporarily reason about this broken validation:
text
message added to REPORTED
but instance not added to FAILEDDo not leave your final code broken.
Answer:
Would the message alone be a reliable instruction to reject the instance?
38. Repair exercise B — wrong field target
Temporarily target the Title validation message at:
text
CurrencyCodeReview the result conceptually.
Restore:
text
TitleExplain why %element quality matters for future UI consumers.
39. Repair exercise C — overwrite Status
Temporarily change your determination logic to:
text
always set Status = OThink through this create:
text
consumer explicitly provides Status = IRestore the correct default-only implementation.
Explain why determinations should preserve valid explicit input unless the business rule requires otherwise.
40. Repair exercise D — direct SQL in provider
Do not execute this.
Explain why this would be wrong inside the determination:
abap
UPDATE zissue_###
SET status = 'O'
WHERE uuid = ...Your answer must mention:
text
transactional buffer
RAP provider
EML
business-object state41. Repair exercise E — validate persistence instead of BO state
Suppose the consumer changes:
text
ReportedOnin the current transaction but the validation selects only the database table.
Explain why the validation could inspect stale data.
What should it use instead?
42. Trigger audit
For each behavior rule, record exactly what triggers it:
| Rule | Create | Field trigger | Timing |
|---|---|---|---|
| setInitialStatus | |||
| validateTitle | |||
| validateReportedOn | |||
| validateCost |
Do not guess.
Read your BDEF.
43. Response audit
Complete from your actual test run:
| Test | Interaction FAILED | Save FAILED | REPORTED messages | Persisted? |
|---|---|---|---|---|
| Valid create | ||||
| Invalid create | ||||
| Invalid update | ||||
| Valid update |
44. Business-rule audit
For each rule, answer:
Could the database type alone enforce it?
Could a UI enforce it?
Why should the RAP BO still own it?
45. Certification-style mini task
Without looking at the guided Reservation implementation:
Add one new validation called
validatePrioritythat accepts onlyL,M, orH, returns a field-targeted error message for any other value, and rejects the invalid instance during save.
Requirements:
text
declare it in BDEF
generate handler method
read Priority in local mode
fill FAILED
fill REPORTED
target Priority
test with Priority = Z
prove no invalid persistenceIf your practice persistence already uses a Domain with fixed values for Priority, still explain why a backend business validation can provide clearer RAP failure/message behavior.
46. Optional challenge — message class
Research how RAP messages can be created from an ABAP message class instead of:
text
new_message_with_textDo not replace the guided solution unless you understand:
text
message class
message number
severity
variables
translationRecord one advantage of a message class.
47. Optional challenge — state messages
Research:
text
%state_areaand answer:
What makes a RAP state message different from the transition-style messages used in this lesson?
Why might state messages become more relevant with draft/Fiori scenarios?
Do not add state-message handling to the required solution.
48. Submission checklist
49. End-of-practice explanation
Without looking at the lesson, explain:
text
A determination derives data automatically.
A validation protects business invariants.
FAILED tells RAP which instance failed.
REPORTED explains the problem.
%ELEMENT connects a message to a field.
Provider implementation reads the current BO state
with EML in local mode.
External consumers see the resulting behavior
through normal EML or, later, OData.If you can explain and demonstrate those ideas, you are ready for Lesson 14.