// TARGET OBJECT : behavior definition ZR_CHANGEAPPROVAL (base BDEF, managed) - README step U6, UI leg // abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Behavior%20Definitions/ZR_CHANGEAPPROVAL/zr_changeapproval.bdef.json // ACTION : create via ADT MCP (objectType BDEF/BDO, implementationType Managed, README U6) once the view // ZR_CHANGEAPPROVAL is active, replace entire content, save, then activate BEFORE the behavior pool // class exists. SAP's RAP exercise activates the BDEF first and only then creates the behavior // implementation class [source: abap-docs /abap-platform-rap-opensap/week4/unit3#step-3-create-and-implement-the-behavior-implementation-bil-class-for-the-travel-entity, // verified 2026-09-16]. The three ZD_* abstract entities (U2-U4) must be active. That exercise is an // unmanaged, non-strict BDEF, so if activation refuses because class ZBP_R_CHANGEAPPROVAL does not exist // (an error, not a warning), create the class (README U7), paste it, and activate BDEF + class in one call. // Sources (all verified 2026-09-15): // action syntax incl. ( features : instance ), parameter, result [1] $self // [abap-docs /abap-docs-cloud/ABENBDL_ACTION, ABENBDL_ACTIONS_FC, ABENBDL_ACTION_INPUT_PARAM, ABENBDL_ACTION2_ABEXA] // internal operations (usable only from the behavior pool) [abap-docs /abap-docs-cloud/ABENBDL_INTERNAL] // field ( readonly, numbering : managed ) for a UUID key [abap-docs /abap-docs-cloud/ABENBDL_FIELD_NUMBERING; /abap-fiori-showcase/01_general_features#readonly] // field ( readonly : update, mandatory : create ) combination [abap-docs /abap-fiori-showcase/06_object_page_content (StreamIsReadOnly)] // determination on modify { create; } sets the initial status [abap-docs /abap-docs-cloud/ABENBDL_DETERMINATIONS (setStatustoNew)] // readonly fields written by determinations/actions IN LOCAL MODE [same source: field ( readonly ) AmountSum + TotalPrice determination] // etag master [abap-docs /abap-docs-cloud/ABENBDL_ETAG]; explicit mapping because CDS aliases differ from table fields [abap-docs /abap-docs-cloud/ABENBDL_TYPE_MAPPING] // authorization master ( none ): "no authorization checks for the entire RAP BO" - access is governed exclusively by the // IAM app / business catalog (ADR-002, ARN-007) and read access by DCL [abap-docs /abap-docs-cloud/ABENBDL_AUTHORIZATION]. // NOT FINAL: ( none ) vs global authorization is open question PRD OQ-8, decided before business roles are assigned. // Sources (verified 2026-09-16): // validation ValName on save { create; } - invoked in the save sequence; a failing validation rejects the complete // transactional buffer of the RAP transaction; EML MODIFY is not allowed in a validation // [abap-docs /abap-docs-cloud/ABENBDL_VALIDATIONS] // State machine (PRD ARN-002, M1 decision 2026-09-16): // create -> PENDING; approve: PENDING -> APPROVED; reject: PENDING -> REJECTED (terminal); // markExecuting: APPROVED -> EXECUTING; markSynced: EXECUTING -> SYNCED (terminal); markFailed: EXECUTING -> FAILED; // retrySync: FAILED -> APPROVED (the worker re-claims it through markExecuting). Only markExecuting writes EXECUTING. // Open point (falsifiable at activation): StatusText/StatusCriticality/IsApprovable/IsRetriable are CDS-calculated and // deliberately absent from the mapping. ABENBDL_TYPE_MAPPING only requires a mapping where table and entity field // NAMES differ; it is silent on calculated elements. If activation reports an error (not a warning) for the unmapped // elements, fall back to persisting them (add the four columns to the table + mapping) and maintain them in the actions. managed implementation in class zbp_r_changeapproval unique; strict ( 2 ); define behavior for ZR_CHANGEAPPROVAL alias ChangeApproval persistent table zchangeapproval lock master authorization master ( none ) etag master LocalLastChangedAt { create; internal update; field ( readonly, numbering : managed ) ID; field ( readonly : update, mandatory : create ) ItemNumber, ChangeType, ArenaEcoId; field ( mandatory : create ) SapPreview; field ( readonly ) Status, StatusText, StatusCriticality, IsApprovable, IsRetriable, RequestedBy, RequestedOn, DecidedBy, DecidedOn, SapChangeNumber, ErrorMessage, RejectReason, CreatedBy, CreatedAt, LastChangedBy, LastChangedAt, LocalLastChangedAt; // Business-user actions (UI projection): PENDING -> APPROVED | REJECTED, FAILED -> APPROVED (PRD RAP-1/RAP-2) action ( features : instance ) approve result [1] $self; action ( features : instance ) reject parameter ZD_CHANGEAPPROVAL_REJECTP result [1] $self; action ( features : instance ) retrySync result [1] $self; // Worker actions (A2X projection): APPROVED -> EXECUTING -> SYNCED | FAILED (PRD RAP-6) action ( features : instance ) markExecuting result [1] $self; action ( features : instance ) markSynced parameter ZD_CHANGEAPPROVAL_SYNCEDP result [1] $self; action ( features : instance ) markFailed parameter ZD_CHANGEAPPROVAL_FAILEDP result [1] $self; determination setInitialStatus on modify { create; } // Semantic key ItemNumber + ChangeType + ArenaEcoId (PRD RAP-8) is unique among non-REJECTED records validation checkDuplicate on save { create; } mapping for zchangeapproval { ID = id; ItemNumber = item_number; ItemName = item_name; ChangeType = change_type; ArenaEcoId = arena_eco_id; Status = status; RequestedBy = requested_by; RequestedOn = requested_on; DecidedBy = decided_by; DecidedOn = decided_on; SapChangeNumber = sap_change_number; ErrorMessage = error_message; RejectReason = reject_reason; SapPreview = sap_preview; CreatedBy = created_by; CreatedAt = created_at; LastChangedBy = last_changed_by; LastChangedAt = last_changed_at; LocalLastChangedAt = local_last_changed_at; } }