Skip to content

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 ​

TimeAbout 3 hours
PrerequisiteLesson 13 teacher-led work
Business ObjectZR_ISSUE_###
Behavior PoolZBP_R_ISSUE_###
New test classZCL_ISSUE_RULES_###
Main focusBusiness 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 mapping

Repair prerequisite defects before adding new rules.


2. Business rules to implement ​

Add one determination:

text
If a new Issue has no Status
→ set Status = O

Add three validations:

text
Title
→ required

ReportedOn
→ cannot be in the future

EstimatedCost / CurrencyCode
→ cost cannot be negative
→ if cost is nonzero, CurrencyCode is required

3. Decide the mechanisms before coding ​

Complete:

RuleDetermination 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
setInitialStatus

Requirements:

text
timing = on modify
trigger = create

Do not trigger it on every field change.


5. Add the Title validation declaration ​

Create:

text
validateTitle

Requirements:

text
timing = on save
trigger = create or Title change

6. Add the ReportedOn validation declaration ​

Create:

text
validateReportedOn

Requirements:

text
timing = on save
trigger = create or ReportedOn change

7. Add the cost validation declaration ​

Create:

text
validateCost

Requirements:

text
timing = on save
trigger = create or EstimatedCost/CurrencyCode change

8. 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 mapping

The new business rules extend the existing BO.


9. Generate handler methods ​

Use:

text
Ctrl+1

from 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:

  1. read the affected Issue instances with EML in local mode;
  2. inspect Status;
  3. select only Issues whose Status is initial;
  4. update those instances to:
text
O
  1. 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 initial

What would be wrong with:

text
always set Status = O

?


12. Implement validateTitle ​

Read:

text
Title

for the affected instances using:

text
READ ENTITIES ... IN LOCAL MODE

If Title is initial:

text
append instance to FAILED
append error message to REPORTED
target Title with %element

Suggested text:

text
Title is required

13. Implement validateReportedOn ​

Read:

text
ReportedOn

and compare it with:

text
current system date

Reject:

text
ReportedOn > today

Suggested text:

text
Reported date cannot be in the future

Target:

text
ReportedOn

14. Implement validateCost ​

Read:

text
EstimatedCost
CurrencyCode

Business rules:

text
EstimatedCost < 0
→ invalid

EstimatedCost <> 0
AND CurrencyCode is initial
→ invalid

Suggested messages:

text
Estimated cost cannot be negative
Currency code is required when cost is provided

Target the corresponding fields.


15. Why zero cost is allowed here ​

For this practice, assume:

text
EstimatedCost = 0

means:

text
no estimate entered yet

Therefore:

text
0 + blank currency

is 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
CurrencyCode

where relevant.

Do not return only generic unbound error text.


18. Activate the BO ​

Run:

text
Ctrl+F2

Then activate related objects:

text
Ctrl+Shift+F3

Final 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_CLASSRUN

This is an external consumer.

Do not use:

text
IN LOCAL MODE

in this class.


20. Reserved Lesson 13 Issue Numbers ​

Use:

text
95000001
95000002

Meaning:

text
95000001
→ valid determination test

95000002
→ invalid validation test

Do not reuse Lesson 12 practice numbers.


21. Make the test repeatable ​

Before creating new test data:

  1. discover old 95000001 / 95000002 rows;
  2. retrieve their UUIDs;
  3. delete them through EML;
  4. commit the cleanup;
  5. 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   = EUR

Do not provide:

text
Uuid
Status
administrative fields

23. Inspect the interaction response ​

Request:

text
MAPPED
FAILED
REPORTED

for the create.

Check that the create has a generated UUID.

Do not commit yet.


24. Read before COMMIT ​

Use:

text
READ ENTITIES

to read Issue 95000001 from the current RAP transaction.

Expected:

text
Status = O

Record:

text
Status supplied by consumer:
Status read before commit:

Explain what caused the difference.


25. Commit the valid Issue ​

Use:

text
COMMIT ENTITIES

with save responses.

Inspect:

text
FAILED
REPORTED
sy-subrc

Expected:

text
successful save

26. Verify valid persistence ​

Use:

text
F8

on:

text
ZR_ISSUE_###

Confirm:

text
95000001 exists
Status = O

27. 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         = omitted

Use reasonable values for the other fields.


28. Inspect MODIFY responses before save ​

After:

text
MODIFY ENTITIES

record:

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 ENTITIES

with:

text
FAILED
REPORTED

save responses.

Expected business problems:

text
Title is required
Reported date cannot be in the future
Estimated cost cannot be negative

Because cost is nonzero and CurrencyCode is blank, also expect:

text
Currency code is required when cost is provided

Use 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
FAILED

Then identify the detailed problems in:

text
REPORTED

Record:

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 ENTITIES

Then verify with CDS Data Preview:

text
95000002 is not persisted

32. Test C — invalid update ​

Take the valid surviving Issue:

text
95000001

Attempt to update:

text
ReportedOn = tomorrow

Do not change anything else.

Run:

text
MODIFY ENTITIES

then:

text
COMMIT ENTITIES

Inspect the save validation response.


33. Roll back the invalid update ​

Use:

text
ROLLBACK ENTITIES

Read the Issue again.

Expected:

text
ReportedOn = original valid date

Document:

text
Attempted date:
Persisted date after rollback:

34. Test D — valid update ​

Now perform a valid update:

text
EstimatedCost = 125.00
CurrencyCode  = EUR

Commit it.

Verify through:

text
READ ENTITIES
F8 Data Preview

This 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 contract

in your explanation.


37. Repair exercise A — remove FAILED ​

Temporarily reason about this broken validation:

text
message added to REPORTED
but instance not added to FAILED

Do 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
CurrencyCode

Review the result conceptually.

Restore:

text
Title

Explain why %element quality matters for future UI consumers.


39. Repair exercise C — overwrite Status ​

Temporarily change your determination logic to:

text
always set Status = O

Think through this create:

text
consumer explicitly provides Status = I

Restore 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 state

41. Repair exercise E — validate persistence instead of BO state ​

Suppose the consumer changes:

text
ReportedOn

in 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:

RuleCreateField triggerTiming
setInitialStatus
validateTitle
validateReportedOn
validateCost

Do not guess.

Read your BDEF.


43. Response audit ​

Complete from your actual test run:

TestInteraction FAILEDSave FAILEDREPORTED messagesPersisted?
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 validatePriority that accepts only L, M, or H, 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 persistence

If 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_text

Do not replace the guided solution unless you understand:

text
message class
message number
severity
variables
translation

Record one advantage of a message class.


47. Optional challenge — state messages ​

Research:

text
%state_area

and 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.