Sync current sources: clean RAP handover names, app rebind, tooling
Working-tree state as of 2026-09-29, uncommitted since the initial "upload current sources" commit: - docs/handover/rap/: renamed the 11 generator-suffixed sources (zz*000) to the clean object names built on the tenant, plus the A2X leg and parameter-entity edits. - app/: manifest, annotations, i18n, mock data and local/mock ui5 configs updated to the live service shape. - PRD.md, CHANGELOG.md, KNOWLEDGE.md: build record through 2026-09-19, including the rejected reentrance-ticket path. - tools/adt-reentrance-login/: retained login helper (new). - docs/v2/zui_arena_change_appr_o4.metadata.xml: captured live $metadata (new). - Dropped a stray 0.3GB-class Eclipse installer that the initial commit had tracked under a URL-mangled filename, and the machine-specific 0M7DEJI.code-workspace. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+607
-151
@@ -1,176 +1,632 @@
|
||||
# RAP handover — Arena change-approval BO (stage 1, 2026-09-15)
|
||||
# RAP handover: Arena change-approval BO, built from an empty package (rev. 2026-09-16, corrected after the UI leg went live)
|
||||
|
||||
Target: development tenant `my431353` (ADT destination `0M7DEJI`), package `ZARENA_PLM`
|
||||
(sub-package of `ZLOCAL`, no transport). The ADT MCP Server can create objects and activate
|
||||
them but cannot write source (PRD V-4), so every file in this folder is a **ready-to-paste
|
||||
source** for the VS Code ADT editor. Each file header names the target object, its
|
||||
`abap:` URI and says "replace entire content".
|
||||
Target: development tenant `my431353` (ADT destination `0M7DEJI`), package `ZARENA_PLM`, a
|
||||
sub-package of `ZLOCAL` with no transport. No generator is used. Every object is created empty
|
||||
through the ADT MCP `abap_creation-create_object`, filled by pasting a file from this folder into
|
||||
the VS Code ADT editor, saved, and activated through `abap_activate_objects`. The ADT MCP cannot
|
||||
write source (PRD V-4).
|
||||
|
||||
Every SAP behavioral claim in these files carries a `[source: … , verified 2026-09-15]`
|
||||
tag; the sources are `abap-docs` (ABAP Cloud keyword docs + SAP samples), `sap-docs`
|
||||
(SAP Help) and `sap-released-objects` (release states).
|
||||
Most source files start with a header comment that names the target object, its `abap:` URI and its
|
||||
README step. **The two service definition sources (U13 `zui_arena_change_approval.srvd.srvdsrv`, W4
|
||||
`zapi_arena_change_approval.srvd.srvdsrv`) carry no comment at all**, because a comment blocks SRVD
|
||||
activation on this tenant (see Landmines). Their former header content is in the U13 and W4 notes
|
||||
below. Where a header's `abap:` URI disagrees with this README, this README and the `filePath`
|
||||
returned by `create_object` win. The U6 and U9 BDEF headers still name the generator-era `.bdef.json`;
|
||||
they are left as they were, because those objects are already active. The W3 header, not yet pasted,
|
||||
names `.bdef.abdl`.
|
||||
|
||||
## What exists in the tenant right now
|
||||
The entity set, properties and actions match the Fiori app contract: entity set `ChangeApproval`,
|
||||
key `ID`, bound actions `approve`, `reject(RejectReason)`, `retrySync`. The UI service is published
|
||||
at `/sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/` (the UI
|
||||
binding was shortened to fit the 26-character limit, D-1). The app was reconciled to that live
|
||||
service on 2026-09-16 (CHANGELOG): dataSource URL, namespace
|
||||
`com.sap.gateway.srvd.zui_arena_change_approval.v0001` (taken from the **service definition**, not
|
||||
the binding) and entity type `ChangeApprovalType` (no underscore), all from the live `$metadata` in
|
||||
`docs/v2/zui_arena_change_appr_o4.metadata.xml` (live 2026-09-16; KNOWLEDGE 2026-09-16). Text in
|
||||
this folder that says `ChangeApproval_Type`, or that the binding name sets the namespace, predates
|
||||
that capture and is marked where it remains.
|
||||
|
||||
Generated by `x-ui-service` (all **active**, ATC 0 findings on 12 objects, 2026-09-15):
|
||||
Citations use `[source: <server> <doc-id>, verified <date>]`. The servers are `abap-docs`,
|
||||
`sap-docs`, `sap-released-objects`, and `adt-mcp` for live tool answers on `0M7DEJI`. Observations
|
||||
made in the editor or browser, with no tool answer to cite, are marked `(live <date>)`.
|
||||
|
||||
| Object | Type | Notes |
|
||||
|---|---|---|
|
||||
| `ZZCHNGPPROVAL000` | TABL | persistent table (generator naming) |
|
||||
| `ZZR_CHANGEAPPROVAL000` | DDLS / BDEF / DCLS | root view entity, managed BDEF, access control |
|
||||
| `ZZBP_R_CHANGEAPPROVAL000` | CLAS | behavior pool of the base BDEF |
|
||||
| `ZZC_CHANGEAPPROVAL000` | DDLS / BDEF / DDLX / DCLS | UI projection view, projection BDEF, metadata extension, access control |
|
||||
| `ZZBP_C_CHANGEAPPROVAL000` | CLAS | projection behavior pool — **delete it** (step 9) |
|
||||
| `ZZUI_ARENA_CHANGE_APPRVL000_O4` | SRVD + SRVB | service definition and OData V4 **UI** binding (same name), **unpublished** |
|
||||
| `ZZARENA_CHANGE_APPROVAL000` | RONT + NONT | SAP object type / node type |
|
||||
## Status (2026-09-16)
|
||||
|
||||
Created empty via `create_object` (exist, **no source, inactive**):
|
||||
- **UI leg U1–U14: ACTIVE and ATC-clean.** All 14 objects answered "Activation successful." ATC over
|
||||
the 14 objects: 0 errors, 0 warnings, 43 infos (worklist `12ACF6BD93811FE1ACB8096AC6763BD6`)
|
||||
[source: adt-mcp abap_activate_objects, abap_atc_get_result on 0M7DEJI, verified 2026-09-16]. The
|
||||
MCP returns only totals by priority, so the 43 infos are read in the ADT ATC view. Infos do not
|
||||
gate publishing.
|
||||
- **UI binding `ZUI_ARENA_CHANGE_APPR_O4`: PUBLISHED 2026-09-16 04:26**, with the **Publish code
|
||||
lens** in the binding's `.srvb.json` source editor (U15). The ADT MCP has no publish tool, and VS
|
||||
Code shows no confirmation beyond "<binding> published locally". The publish was therefore verified
|
||||
by tool: `fetch_services` reports `isPublished: true`, and `fetch_service_information` returns
|
||||
`https://my431353-api.s4hana.cloud.sap/sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/?sap-client=080`
|
||||
with entity set `ChangeApproval` [source: adt-mcp abap_business_services-fetch_services,
|
||||
fetch_service_information on 0M7DEJI, verified 2026-09-16].
|
||||
- **Where the live service answers:** on the UI host `my431353.s4hana.cloud.sap`. The same path on
|
||||
the `-api` host that `fetch_service_information` reports is refused to a business user as
|
||||
"Forbidden / blocked by UCON" (live 2026-09-16; KNOWLEDGE 2026-09-16). The `-api` host is the
|
||||
communication-user entry point.
|
||||
- **Worker leg W1–W5:** started on the tenant 2026-09-16 06:14 (PRD status). Run it exactly as in
|
||||
"Worker leg" below. This README records no worker-leg result.
|
||||
- **Package:** `ZARENA_PLM` exists again under `ZLOCAL` (recreated 2026-09-16; validation in it
|
||||
succeeded live at 02:27, CHANGELOG). Historical, before step 0: the package had been deleted
|
||||
together with its contents, and `abap_creation-run_validation` answered "Package 'ZARENA_PLM' does
|
||||
not exist." for TABL, DDLS and CLAS [source: adt-mcp on 0M7DEJI, verified 2026-09-16].
|
||||
|
||||
| Object | Type | Purpose |
|
||||
|---|---|---|
|
||||
| `ZD_CHANGEAPPROVAL_REJECTP` | DDLS | abstract entity — `reject` parameter (`RejectReason`) |
|
||||
| `ZD_CHANGEAPPROVAL_SYNCEDP` | DDLS | abstract entity — `markSynced` parameter (`SapChangeNumber`) |
|
||||
| `ZD_CHANGEAPPROVAL_FAILEDP` | DDLS | abstract entity — `markFailed` parameter (`ErrorMessage`) |
|
||||
| `ZC_CHANGEAPPROVAL_A2X` | DDLS + DCLS | A2X projection view (worker) and its access control |
|
||||
| `ZAPI_ARENA_CHANGE_APPROVAL` | SRVD | Web API service definition (worker) |
|
||||
## Object inventory and name limits
|
||||
|
||||
Not yet creatable (the MCP validation refuses until the referenced objects are active):
|
||||
| Step | Object | Type (create code) | Source file(s) | Length / limit |
|
||||
|---|---|---|---|---|
|
||||
| U1 | `ZCHANGEAPPROVAL` | TABL (`TABL/DT`) | `zchangeapproval.tabl.asddls` | 15 / 16 |
|
||||
| U2 | `ZD_CHANGEAPPROVAL_REJECTP` | DDLS (`DDLS/DF`) | `zd_changeapproval_rejectp.ddls.asddls` | 25 / 30 |
|
||||
| U3 | `ZD_CHANGEAPPROVAL_SYNCEDP` | DDLS (`DDLS/DF`) | `zd_changeapproval_syncedp.ddls.asddls` | 25 / 30 |
|
||||
| U4 | `ZD_CHANGEAPPROVAL_FAILEDP` | DDLS (`DDLS/DF`) | `zd_changeapproval_failedp.ddls.asddls` | 25 / 30 |
|
||||
| U5 | `ZR_CHANGEAPPROVAL` | DDLS (`DDLS/DF`) | `zr_changeapproval.ddls.asddls` | 17 / 30 |
|
||||
| U6 | `ZR_CHANGEAPPROVAL` | BDEF (`BDEF/BDO`) | `zr_changeapproval.bdef.asbdef` | 17 / 30 |
|
||||
| U7 | `ZBP_R_CHANGEAPPROVAL` | CLAS (`CLAS/OC`) | `zbp_r_changeapproval.clas.abap` + `.clas.locals_imp.abap` | 20 / 30 |
|
||||
| U8 | `ZC_CHANGEAPPROVAL` | DDLS (`DDLS/DF`) | `zc_changeapproval.ddls.asddls` | 17 / 30 |
|
||||
| U9 | `ZC_CHANGEAPPROVAL` | BDEF (`BDEF/BDO`) | `zc_changeapproval.bdef.asbdef` | 17 / 30 |
|
||||
| U10 | `ZR_CHANGEAPPROVAL` | DCLS (`DCLS/DL`) | `zr_changeapproval.dcls.asdcls` | 17 / 30 |
|
||||
| U11 | `ZC_CHANGEAPPROVAL` | DCLS (`DCLS/DL`) | `zc_changeapproval.dcls.asdcls` | 17 / 30 |
|
||||
| U12 | `ZC_CHANGEAPPROVAL` | DDLX (`DDLX/EX`) | `zc_changeapproval.ddlx.asddlx` | 17 / 40 |
|
||||
| U13 | `ZUI_ARENA_CHANGE_APPROVAL` | SRVD (`SRVD/SRV`) | `zui_arena_change_approval.srvd.srvdsrv` (no comments) | 25 / 30 |
|
||||
| U14 | `ZUI_ARENA_CHANGE_APPR_O4` | SRVB (`SRVB/SVB`), OData V4 - UI | none in this folder; `create_object` returns `.srvb.json` | 24 / 26 (D-1) |
|
||||
| W1 | `ZC_CHANGEAPPROVAL_A2X` | DDLS (`DDLS/DF`) | `zc_changeapproval_a2x.ddls.asddls` | 21 / 30 |
|
||||
| W2 | `ZC_CHANGEAPPROVAL_A2X` | DCLS (`DCLS/DL`) | `zc_changeapproval_a2x.dcls.asdcls` | 21 / 30 |
|
||||
| W3 | `ZC_CHANGEAPPROVAL_A2X` | BDEF (`BDEF/BDO`) | `zc_changeapproval_a2x.bdef.asbdef` | 21 / 30 |
|
||||
| W4 | `ZAPI_ARENA_CHANGE_APPROVAL` | SRVD (`SRVD/SRV`) | `zapi_arena_change_approval.srvd.srvdsrv` (no comments) | 26 / 30 |
|
||||
| W5 | `ZAPI_ARENA_CHANGE_APPR_A2X` | SRVB (`SRVB/SVB`), Web API (see W5 for the exact `bindingType` value) | none in this folder; `.srvb.json` expected, as U14 | 26 / 26 (D-1) |
|
||||
|
||||
| Object | Type | Blocker seen 2026-09-15 |
|
||||
|---|---|---|
|
||||
| `ZC_CHANGEAPPROVAL_A2X` | BDEF (projection) | "The referenced STOB object ZC_CHANGEAPPROVAL_A2X does not exist" |
|
||||
| `ZAPI_ARENA_CHANGE_APPROVAL_A2X` | SRVB (OData V4 - Web API) | "An active version of the Service Definition ZAPI_ARENA_CHANGE_APPROVAL does not exist" |
|
||||
Limits: `TABL/DT` 16; `DDLS/DF`, `BDEF/BDO` and `SRVD/SRV` 30 [source: adt-mcp
|
||||
`abap_creation-get_object_type_details` on 0M7DEJI, verified 2026-09-16]. Service bindings: 26 per
|
||||
SAP Help. The ADT MCP accepts 30 for `SRVB/SVB`, but that is undocumented and not used here (D-1).
|
||||
The documentation agrees
|
||||
for tables ("maximum of 16 characters") [source: abap-docs /abap-docs-cloud/ABENDDIC_DBTAB_NAMES,
|
||||
verified 2026-09-16] and for CDS view entities ("maximum of 30 characters"; the DDL source and the
|
||||
CDS entity must have the same name) [source: abap-docs /abap-docs-cloud/ABENCDS_DEFINE_VIEW_ENTITY,
|
||||
verified 2026-09-16]. `CLAS/OC` and `DCLS/DL` allow 30 and `DDLX/EX` allows 40 [source: adt-mcp
|
||||
abap_creation-get_object_type_details on 0M7DEJI, verified 2026-09-16] (KNOWLEDGE 2026-09-16; these
|
||||
were "not recorded" in the pre-build revision).
|
||||
|
||||
## Paste-and-activate sequence
|
||||
Not created: a projection behavior pool (see design decisions) and an SAP object type or node type.
|
||||
No documentation found makes an SAP object type mandatory for a RAP BO. SAP Help lists it only as
|
||||
one of the objects the "OData UI Service from Scratch" wizard generates [source: sap-docs sap-help
|
||||
loio d3f5e90a306a44b6b37b8b05f04d2c10, verified 2026-09-16]. Business events are the case that
|
||||
requires `@ObjectModel.sapObjectNodeType.name` [source: sap-docs
|
||||
/btp-cloud-platform/30-development/log-custom-business-events-6ecc451, verified 2026-09-16]. Add
|
||||
one if the BO later raises business events.
|
||||
|
||||
Open each object in the VS Code ADT editor (or ADT Eclipse), replace the whole source with
|
||||
the file content, save, activate. Activation order matters — dependencies are top-down.
|
||||
Split: the **UI leg** has 14 source files (13 objects with source + the U14 binding). The **worker
|
||||
leg** has 4 source files (+ the W5 binding). The `markSynced`/`markFailed` parameter entities
|
||||
(U3, U4) belong to the UI leg because the base BDEF (U6) names them. They must be active before
|
||||
U6 activates.
|
||||
|
||||
1. `zzchngpproval000.tabl.asddls` → table `ZZCHNGPPROVAL000`. (File name uses the
|
||||
abap-file-formats extension by analogy with `.ddls.asddls`; the tenant object is the
|
||||
same regardless.)
|
||||
2. `zd_changeapproval_rejectp.ddls.asddls`, `zd_changeapproval_syncedp.ddls.asddls`,
|
||||
`zd_changeapproval_failedp.ddls.asddls` → the three abstract entities.
|
||||
3. `zzr_changeapproval000.ddls.asddls` → root view entity.
|
||||
4. `zzr_changeapproval000.bdef.asbdef` → base BDEF.
|
||||
Watch for a message about the unmapped elements `StatusText`, `StatusCriticality`,
|
||||
`IsApprovable`, `IsRetriable` (CDS-calculated, deliberately not in the mapping). A
|
||||
warning is acceptable; an **error** means the fallback in the file header applies.
|
||||
5. `zzbp_r_changeapproval000.clas.abap` (global class) and
|
||||
`zzbp_r_changeapproval000.clas.locals_imp.abap` (Local Types tab) → behavior pool.
|
||||
6. `zzc_changeapproval000.ddls.asddls` and `zc_changeapproval_a2x.ddls.asddls` → both
|
||||
projection views.
|
||||
7. `zzc_changeapproval000.bdef.asbdef` → UI projection BDEF.
|
||||
8. Create the A2X projection BDEF (now possible): ADT *New Behavior Definition* on
|
||||
`ZC_CHANGEAPPROVAL_A2X`, implementation type *Projection* — or via MCP:
|
||||
`abap_creation-run_validation` + `create_object` with objectType `BDEF/BDO` and
|
||||
`{"behaviorDefinitionType":"definition","packageName":"ZARENA_PLM","rootEntity":"ZC_CHANGEAPPROVAL_A2X","name":"ZC_CHANGEAPPROVAL_A2X","description":"Arena change approval: A2X projection behavior","implementationType":"Projection"}`,
|
||||
transport `""`. Then paste `zc_changeapproval_a2x.bdef.asbdef`, activate.
|
||||
9. Delete the generated class `ZZBP_C_CHANGEAPPROVAL000` (no longer referenced by the
|
||||
projection BDEF; a projection needs a behavior pool only for new actions/functions
|
||||
[source: abap-docs /abap-docs-cloud/ABENBDL_BDEF_PROJECTION_HEADER, verified 2026-09-15]).
|
||||
10. `zzr_changeapproval000.dcls.asdcls`, then `zzc_changeapproval000.dcls.asdcls` and
|
||||
`zc_changeapproval_a2x.dcls.asdcls` → access controls.
|
||||
11. `zzc_changeapproval000.ddlx.asddlx` → metadata extension.
|
||||
12. `zzui_arena_change_apprvl000_o4.srvd.srvdsrv` and
|
||||
`zapi_arena_change_approval.srvd.srvdsrv` → service definitions.
|
||||
13. Create the Web API binding (now possible): ADT *New Service Binding* on
|
||||
`ZAPI_ARENA_CHANGE_APPROVAL`, binding type *OData V4 - Web API*, name
|
||||
`ZAPI_ARENA_CHANGE_APPROVAL_A2X` — or via MCP `create_object` with objectType
|
||||
`SRVB/SVB` and
|
||||
`{"packageName":"ZARENA_PLM","name":"ZAPI_ARENA_CHANGE_APPROVAL_A2X","description":"Arena change approval: OData V4 Web API binding (worker)","bindingType":"OData V4 - Web API","serviceDefinition":"ZAPI_ARENA_CHANGE_APPROVAL"}`.
|
||||
Activate. **Do not publish** either binding (publishing is a later brief, together
|
||||
with the IAM app / communication scenario).
|
||||
## Resolved decisions
|
||||
|
||||
## Activation URIs for `abap_activate_objects` (after pasting)
|
||||
- **D-1: service binding names stay within 26 characters (resolved 2026-09-16).** SAP Help gives
|
||||
26 characters as the maximum length for a service binding name in every version checked: ABAP
|
||||
Cloud [source: sap-docs sap-help loio 4bad0d7280b742a68dd2d42b1441f09a, verified 2026-09-16], SAP
|
||||
Cloud Platform [source: sap-docs sap-help loio f3e608ace2a64aada33bdd3e2419113a and
|
||||
6709cab6cb5b4c01b28463d760429a9a, verified 2026-09-16], and ABAP Platform 2021 [source: sap-docs
|
||||
sap-help loio 777e027f61c3490dba0433443d9143a6, verified 2026-09-16]. The ADT MCP's 30 is
|
||||
undocumented. The bindings are therefore:
|
||||
- UI binding `ZUI_ARENA_CHANGE_APPR_O4` (24), replacing the 28-character long form.
|
||||
- Web API binding `ZAPI_ARENA_CHANGE_APPR_A2X` (26), replacing the 30-character long form.
|
||||
|
||||
Pattern learned live 2026-09-15: `abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/<folder>/<NAME>/<name>.<ext>`
|
||||
with these folders/extensions (all verified by a successful activation):
|
||||
The service definitions `ZUI_ARENA_CHANGE_APPROVAL` (25) and `ZAPI_ARENA_CHANGE_APPROVAL` (26)
|
||||
and every other object name are unchanged. Consequence: the binding name is the first URL
|
||||
segment, so the app's dataSource URL had to change. **Live correction (2026-09-16):** the
|
||||
pre-build text here also said the binding name sets the schema namespace. It does not; the live
|
||||
namespace `com.sap.gateway.srvd.zui_arena_change_approval.v0001` comes from the service definition
|
||||
(live 2026-09-16, `docs/v2/zui_arena_change_appr_o4.metadata.xml`; KNOWLEDGE 2026-09-16). The app
|
||||
was reconciled to the live service on 2026-09-16 (CHANGELOG). The PRD worker contract row now
|
||||
names `ZAPI_ARENA_CHANGE_APPR_A2X` (PRD read 2026-09-16), so that governance item is closed. U14
|
||||
published under its 24-character name, so a name within 26 is proven to publish. Whether
|
||||
publishing accepts more than 26 is still unknown (KNOWLEDGE 2026-09-16).
|
||||
|
||||
| Type | Folder | Extension |
|
||||
|---|---|---|
|
||||
| TABL | `Dictionary/Database%20Tables` | `.tabl.json` |
|
||||
| DDLS | `Core%20Data%20Services/Data%20Definitions` | `.ddls.acds` |
|
||||
| BDEF | `Core%20Data%20Services/Behavior%20Definitions` | `.bdef.json` (`.bdef.acds`, `.bdef.asbdef`, `.bdef.abap` all fail with "array element 0 is null") |
|
||||
| DDLX | `Core%20Data%20Services/Metadata%20Extensions` | `.ddlx.acds` |
|
||||
| DCLS | `Core%20Data%20Services/Access%20Controls` | `.dcls.acds` |
|
||||
| CLAS | `Source%20Code%20Library/Classes` | `.clas.abap` |
|
||||
| SRVD | `Business%20Services/Service%20Definitions` | `.srvd.acds` |
|
||||
| SRVB | `Business%20Services/Service%20Bindings` | `.srvb.json` |
|
||||
| RONT | `Business%20Services/SAP%20Object%20Types` | `.ront.json` |
|
||||
| NONT | `Business%20Services/SAP%20Object%20Node%20Types` | `.nont.json` |
|
||||
## Preconditions
|
||||
|
||||
In sequence order (`B` = `abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM`):
|
||||
1. VS Code with ADT (`sapse.adt-vscode`) is running, destination `0M7DEJI` is logged on, and the
|
||||
ADT MCP answers on `http://127.0.0.1:2236/mcp`. After a VS Code reload, refresh the bearer
|
||||
token in `.mcp.json` (CLAUDE.md). A Claude Code session exposes the `adt-mcp` tools only if the
|
||||
server was up when the session started (KNOWLEDGE 2026-09-16).
|
||||
2. `abap_list_destinations` lists `0M7DEJI`.
|
||||
|
||||
## Step 0: recreate the package (done 2026-09-16)
|
||||
|
||||
Done: `ZARENA_PLM` exists again under `ZLOCAL`, validation in it succeeded live at 02:27, and
|
||||
`abap_transport-get` answered `isRecordingRequired: false` (CHANGELOG 2026-09-16). The steps below
|
||||
are kept as the record.
|
||||
|
||||
In ADT (VS Code or Eclipse), create development package **`ZARENA_PLM` with super-package
|
||||
`ZLOCAL`**, no transport. The ADT MCP has no package tool. Use a `ZLOCAL` sub-package because
|
||||
`ZLOCAL` itself is a structure package, `$TMP` fails the language-version authorization, and
|
||||
sub-packages of `ZLOCAL` created from release 2508 need no workbench request [source: sap-docs
|
||||
sap-help loio a0d80f14fcb74cb1ac8fb6f3d9ad48cc (2608), verified 2026-09-15; refusals live
|
||||
2026-09-15, KNOWLEDGE].
|
||||
|
||||
Check it read-only: `abap_creation-run_validation` for `TABL/DT` with the U1 JSON must no longer
|
||||
answer "Package 'ZARENA_PLM' does not exist". Then call `abap_transport-get` once for U1
|
||||
(`objectType` `TABL/DT`, `developmentPackage` `ZARENA_PLM`, `isCreation` true) and expect "recording
|
||||
not required". Every `create_object` below uses `"transportRequestNumber": ""`.
|
||||
|
||||
## Per-object routine
|
||||
|
||||
For every step:
|
||||
|
||||
1. `abap_creation-get_object_type_details` (objectType, name, description). It lists the required
|
||||
fields and limits. If it names a required field that the JSON below lacks, add it and note it.
|
||||
2. `abap_creation-run_validation` with the JSON.
|
||||
3. `abap_creation-create_object` with the same JSON, `destination` `0M7DEJI`, transport `""`.
|
||||
**Record the `filePath` it returns.** That path is both the paste target and the activation URI.
|
||||
4. Open that **source** file in the VS Code ADT editor, replace the whole content with the handover
|
||||
file (its header comment included where it has one; the SRVD files have none and must stay
|
||||
comment-free), and save. A DDIC database table is edited as Dictionary DDL source generated from its
|
||||
metadata [source: abap-docs /abap-docs-cloud/ABENDDIC_DEFINE_TABLE, verified 2026-09-16].
|
||||
5. `abap_activate_objects` with the returned `filePath` (URL-encoded, spaces as `%20`). The
|
||||
activation table below is a cross-check, not a substitute. Fix errors before the next step.
|
||||
|
||||
**General rule (live 2026-09-16): in the VS Code ADT workspace, the `.json` file in an object folder
|
||||
is header metadata and never receives pasted source. Always use the `filePath` returned by
|
||||
`create_object`.** For example, `zchangeapproval.tabl.json` holds only formatVersion, description,
|
||||
originalLanguage and `abapLanguageVersion`, and the table source lives in `zchangeapproval.tabl.ddic`
|
||||
[source: adt-mcp abap_creation-create_object / abap_activate_objects on 0M7DEJI, verified
|
||||
2026-09-16]. The returned source files are TABL `.tabl.ddic`, DDLS `.ddls.acds`, DCLS `.dcls.acds`,
|
||||
DDLX `.ddlx.acds`, BDEF `.bdef.abdl`, CLAS `.clas.abap` and SRVD `.srvd.acds`. Among the types in
|
||||
this build, the one returned `filePath` that is a `.json` is the service binding's `.srvb.json`.
|
||||
Nothing is pasted into it, the binding is activated through it (U14), and its editor carries the
|
||||
Publish code lens (U15).
|
||||
|
||||
Create-metadata tags per type [source: adt-mcp `abap_creation-get_object_type_details` on 0M7DEJI,
|
||||
verified 2026-09-16]:
|
||||
|
||||
- `TABL/DT`: `packageName`, `name`, `description`.
|
||||
- `DDLS/DF`: `packageName`, `name`, `description`, optional `referencedObject` (omitted here).
|
||||
- `SRVD/SRV`: `packageName`, `name`, `description`, `sourceType` (`S` | `X` | none). Use `"S"`: it
|
||||
worked live, and omitting it fails with "serviceDefinitionInfo.sourceType is null" (live 2026-09-15).
|
||||
`SRVD/SRV` also offers an optional `referencedObject` (omitted here) [source: adt-mcp
|
||||
get_object_type_details on 0M7DEJI, verified 2026-09-16].
|
||||
- `SRVB/SVB`: `packageName`, `name`, `description`, `bindingType`, `serviceDefinition`. Proven
|
||||
`bindingType` value: `OData V4 - UI` (U14, 2026-09-16). The Web API value is not proven; see W5.
|
||||
- `BDEF/BDO`: `behaviorDefinitionType`, `packageName`, `rootEntity`, `name`, `description`,
|
||||
`implementationType` (`Managed` | `Unmanaged` | `Projection` | `Abstract` | `Interface`).
|
||||
- `CLAS/OC`: `packageName`, `name` (≤30), `description`, optional superclass and interfaces (none
|
||||
needed here). `DCLS/DL`: `packageName`, `name` (≤30), `description`, optional `protectedEntity`.
|
||||
`DDLX/EX`: `packageName`, `name` (≤40), `description`, optional `extendedEntity` [source: adt-mcp
|
||||
abap_creation-get_object_type_details on 0M7DEJI, verified 2026-09-16]. The pre-build revision
|
||||
marked these three "tags not recorded"; the JSON in the UI-leg table below still carries that
|
||||
marker as the record.
|
||||
|
||||
Descriptions are kept at 40 characters or fewer. The per-type description limit was not recorded.
|
||||
|
||||
BDEF and SRVB creation validates the referenced DDLS/SRVD's **active** version (live 2026-09-15:
|
||||
"The referenced STOB object … does not exist"; "An active version of the Service Definition … does
|
||||
not exist"). The sequence below always activates the referenced object first.
|
||||
|
||||
## UI leg (first; done 2026-09-16)
|
||||
|
||||
**Done: U1–U14 are active, ATC-clean, and the U14 binding is published (see Status).** Do not re-run
|
||||
this table. It is kept as the build record. The JSON column is the pre-build plan: the `(tags
|
||||
unconfirmed)` markers were settled on 2026-09-16 (per-object routine), and U10 was created with
|
||||
`protectedEntity` added (CHANGELOG 2026-09-16).
|
||||
|
||||
| Step | create_object JSON (objectType) | Paste | Depends on (active) |
|
||||
|---|---|---|---|
|
||||
| U1 | `TABL/DT` `{"packageName":"ZARENA_PLM","name":"ZCHANGEAPPROVAL","description":"Arena change approval"}` | `zchangeapproval.tabl.asddls` | none |
|
||||
| U2 | `DDLS/DF` `{"packageName":"ZARENA_PLM","name":"ZD_CHANGEAPPROVAL_REJECTP","description":"Arena approval: reject parameter"}` | `zd_changeapproval_rejectp.ddls.asddls` | none |
|
||||
| U3 | `DDLS/DF` `{"packageName":"ZARENA_PLM","name":"ZD_CHANGEAPPROVAL_SYNCEDP","description":"Arena approval: markSynced parameter"}` | `zd_changeapproval_syncedp.ddls.asddls` | none |
|
||||
| U4 | `DDLS/DF` `{"packageName":"ZARENA_PLM","name":"ZD_CHANGEAPPROVAL_FAILEDP","description":"Arena approval: markFailed parameter"}` | `zd_changeapproval_failedp.ddls.asddls` | none |
|
||||
| U5 | `DDLS/DF` `{"packageName":"ZARENA_PLM","name":"ZR_CHANGEAPPROVAL","description":"Arena change approval"}` | `zr_changeapproval.ddls.asddls` | U1 |
|
||||
| U6 | `BDEF/BDO` `{"behaviorDefinitionType":"definition","packageName":"ZARENA_PLM","rootEntity":"ZR_CHANGEAPPROVAL","name":"ZR_CHANGEAPPROVAL","description":"Arena change approval behavior","implementationType":"Managed"}` | `zr_changeapproval.bdef.asbdef` | U2, U3, U4, U5 |
|
||||
| U7 | `CLAS/OC` `{"packageName":"ZARENA_PLM","name":"ZBP_R_CHANGEAPPROVAL","description":"Arena change approval behavior pool"}` (tags unconfirmed) | `zbp_r_changeapproval.clas.abap` (global class) + `zbp_r_changeapproval.clas.locals_imp.abap` (Local Types) | U6 |
|
||||
| U8 | `DDLS/DF` `{"packageName":"ZARENA_PLM","name":"ZC_CHANGEAPPROVAL","description":"Arena change approval UI projection"}` | `zc_changeapproval.ddls.asddls` | U5 (U6/U7 done) |
|
||||
| U9 | `BDEF/BDO` `{"behaviorDefinitionType":"definition","packageName":"ZARENA_PLM","rootEntity":"ZC_CHANGEAPPROVAL","name":"ZC_CHANGEAPPROVAL","description":"Arena approval UI projection behavior","implementationType":"Projection"}` | `zc_changeapproval.bdef.asbdef` | U6, U7, U8 |
|
||||
| U10 | `DCLS/DL` `{"packageName":"ZARENA_PLM","name":"ZR_CHANGEAPPROVAL","description":"Arena change approval access"}` (tags unconfirmed) | `zr_changeapproval.dcls.asdcls` | U5 |
|
||||
| U11 | `DCLS/DL` `{"packageName":"ZARENA_PLM","name":"ZC_CHANGEAPPROVAL","description":"Arena approval UI projection access"}` (tags unconfirmed) | `zc_changeapproval.dcls.asdcls` | U8, U10 |
|
||||
| U12 | `DDLX/EX` `{"packageName":"ZARENA_PLM","name":"ZC_CHANGEAPPROVAL","description":"Arena approval UI annotations"}` (tags unconfirmed) | `zc_changeapproval.ddlx.asddlx` | U8 |
|
||||
| U13 | `SRVD/SRV` `{"packageName":"ZARENA_PLM","name":"ZUI_ARENA_CHANGE_APPROVAL","description":"Arena change approval UI service","sourceType":"S"}` | `zui_arena_change_approval.srvd.srvdsrv` | U8, U9 |
|
||||
| U14 | `SRVB/SVB` `{"packageName":"ZARENA_PLM","name":"ZUI_ARENA_CHANGE_APPR_O4","description":"Arena change approval UI binding","bindingType":"OData V4 - UI","serviceDefinition":"ZUI_ARENA_CHANGE_APPROVAL"}` | none | U13 |
|
||||
|
||||
Notes per step:
|
||||
|
||||
- **U1:** paste `zchangeapproval.tabl.asddls` into **`zchangeapproval.tabl.ddic`**, never into
|
||||
`zchangeapproval.tabl.json` (metadata only, see the per-object routine). Proven: U1 activated
|
||||
through `.tabl.ddic` [source: adt-mcp abap_activate_objects on 0M7DEJI, verified 2026-09-16].
|
||||
- **U6 then U7 (order matters).** **Resolved live 2026-09-16:** U6 activated through `.bdef.abdl` on
|
||||
the first attempt, before class `ZBP_R_CHANGEAPPROVAL` existed, so the fallback below was not
|
||||
needed. U6 and U7 were then activated together in one call [source: adt-mcp abap_activate_objects
|
||||
on 0M7DEJI, verified 2026-09-16]. The pre-build instruction follows as the record.
|
||||
Activate the base BDEF **before** the behavior pool class exists,
|
||||
then create the class. SAP's RAP exercise does it that way [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]. That exercise is an unmanaged, non-strict BDEF. If U6 activation fails with
|
||||
an **error** saying class `ZBP_R_CHANGEAPPROVAL` does not exist, run U7's create and paste, then
|
||||
activate U6 and U7 together in one `abap_activate_objects` call. Also watch U6 for messages about
|
||||
the unmapped CDS-calculated elements `StatusText`, `StatusCriticality`, `IsApprovable` and
|
||||
`IsRetriable`. A warning is acceptable. An error triggers the fallback in the BDEF file header.
|
||||
- **U7:** paste the global class, then switch to the Local Types include and paste the handlers.
|
||||
Save both. Activate through the `.clas.abap` URI. The Local Types include also implements the
|
||||
`checkDuplicate` validation. Its duplicate query uses `OPTIONS PRIVILEGED ACCESS`. If the syntax
|
||||
check refuses that form, the documented fallback is in the include header. `create_object` for
|
||||
the class returned only the global `.clas.abap` path, no Local Types path (KNOWLEDGE 2026-09-16).
|
||||
- **U9:** no behavior pool is created for the projection (see design decisions). `use etag` is in
|
||||
the entity header, not the body (design decisions). `create_object` returned `.bdef.abdl`, and U9
|
||||
activated through it [source: adt-mcp abap_creation-create_object, abap_activate_objects on
|
||||
0M7DEJI, verified 2026-09-16].
|
||||
- **U13: service definition `ZUI_ARENA_CHANGE_APPROVAL` (UI service).** This note holds what the
|
||||
source file's header comment used to say. The header is gone, because it blocked activation.
|
||||
- `abap:` URI:
|
||||
`abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Business%20Services/Service%20Definitions/ZUI_ARENA_CHANGE_APPROVAL/zui_arena_change_approval.srvd.acds`
|
||||
- Action: create empty through the ADT MCP (`SRVD/SRV`, `sourceType` `"S"`), replace the entire
|
||||
content with `zui_arena_change_approval.srvd.srvdsrv`, save, and activate after the
|
||||
`ZC_CHANGEAPPROVAL` view (U8) and BDEF (U9). Then create the OData V4 UI binding
|
||||
`ZUI_ARENA_CHANGE_APPR_O4` on it (U14).
|
||||
- **What happened live (2026-09-16):** the first activation failed with "Comments are not supported
|
||||
and will be deleted on save" (Ln 1, the header block comment) and "oData V4 services with no
|
||||
draft capability will be primarily READ-ONLY" (Ln 21). The same definition, re-saved without the
|
||||
comment, activated. The comment was the blocker; the draft message was not (the BO has no draft,
|
||||
by design) (live 2026-09-16; CHANGELOG 2026-09-16).
|
||||
- Contract: exposes exactly one entity set, `ChangeApproval`. The service URL (live, published) is
|
||||
`/sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/`. The
|
||||
first segment is the binding (service group `ZUI_ARENA_CHANGE_APPR_O4`, 24 characters, within
|
||||
SAP Help's 26-character binding limit, D-1). The segment after `srvd/sap/` is the binding's
|
||||
service alias (the service name in the binding editor), which can differ from this definition's
|
||||
name and can be renamed only while the binding is unpublished [source: sap-docs community-14433266
|
||||
"How to rename an OData V4 service?" (SAP, 2026-07-04), verified 2026-09-16]. The former header
|
||||
called the app reconciliation pending. It was done on 2026-09-16 (CHANGELOG).
|
||||
- `expose … as <alias>`: the alias becomes the entity set (`ChangeApproval`) and the entity type
|
||||
(`ChangeApproval_Type`) [source: abap-docs /abap-fiori-showcase/06_object_page_content (Service
|
||||
Definition), verified 2026-09-15]. **Live correction:** the entity set is `ChangeApproval`, but
|
||||
the entity type is `ChangeApprovalType`, with no underscore (live 2026-09-16,
|
||||
`docs/v2/zui_arena_change_appr_o4.metadata.xml`; KNOWLEDGE 2026-09-16).
|
||||
- `provider contracts odata_v4_ui` switches on the UI-binding syntax checks and must match the
|
||||
binding type [source: abap-docs /abap-docs-cloud/ABENSRVD_PROVIDER_CONTRACT, verified 2026-09-15].
|
||||
- **U14:** **Obsolete, removed:** the pre-build instruction to open the binding in the editor
|
||||
*before activating* to check the alias. What was done and proven on 2026-09-16: `create_object`
|
||||
returned `.srvb.json`, U14 was activated through that `filePath`, and the alias was verified
|
||||
**after** activation with `fetch_services`: service `ZUI_ARENA_CHANGE_APPROVAL`, version `0001`,
|
||||
OData V4, unpublished [source: adt-mcp abap_creation-create_object, abap_activate_objects,
|
||||
abap_business_services-fetch_services on 0M7DEJI, verified 2026-09-16]. The alias check must
|
||||
come before publishing, not before activating. The URL segment after `srvd/sap/` is that alias,
|
||||
not necessarily the definition name, and it can be renamed only while the binding is unpublished
|
||||
[source: sap-docs community-14433266 "How to rename an OData V4 service?", verified 2026-09-16].
|
||||
The binding name `ZUI_ARENA_CHANGE_APPR_O4` (24) is within SAP Help's 26-character limit (D-1).
|
||||
|
||||
### U15: checks and publish of the UI binding (done 2026-09-16)
|
||||
|
||||
1. `abap_atc_run` on all 14 UI-leg objects: `ZCHANGEAPPROVAL` TABL; `ZD_CHANGEAPPROVAL_REJECTP`,
|
||||
`ZD_CHANGEAPPROVAL_SYNCEDP`, `ZD_CHANGEAPPROVAL_FAILEDP`, `ZR_CHANGEAPPROVAL`, `ZC_CHANGEAPPROVAL`
|
||||
DDLS; `ZR_CHANGEAPPROVAL`, `ZC_CHANGEAPPROVAL` BDEF; `ZBP_R_CHANGEAPPROVAL` CLAS;
|
||||
`ZR_CHANGEAPPROVAL`, `ZC_CHANGEAPPROVAL` DCLS; `ZC_CHANGEAPPROVAL` DDLX;
|
||||
`ZUI_ARENA_CHANGE_APPROVAL` SRVD; `ZUI_ARENA_CHANGE_APPR_O4` SRVB. Then
|
||||
`abap_atc_get_result`. **Result:** 0 errors, 0 warnings, 43 infos (worklist
|
||||
`12ACF6BD93811FE1ACB8096AC6763BD6`) [source: adt-mcp abap_atc_get_result on 0M7DEJI, verified
|
||||
2026-09-16].
|
||||
2. `abap_business_services-fetch_services` on `ZUI_ARENA_CHANGE_APPR_O4`. **Result:**
|
||||
`isPublished: false`, service `ZUI_ARENA_CHANGE_APPROVAL`, version `0001`, OData V4.
|
||||
3. **Publish with the Publish code lens, not a button.** Open the binding's `.srvb.json` source in
|
||||
the VS Code ADT editor and choose the **Publish** code lens in the source. In ADT for VS Code a
|
||||
service binding is a source-based editor, and publish, unpublish and preview are code lenses
|
||||
[source: sap-docs sap-help loio dd6f5de63e7245a7abe7e39389841596 "ABAP RAP Tools", verified
|
||||
2026-09-16]. (Superseded wording: "the Publish button in the ADT service binding editor" describes
|
||||
the Eclipse form-based editor.) The binding must be active first [source: sap-docs sap-help loio
|
||||
b58a3c27df4e406f9335d4b346f6be04, verified 2026-09-16]. The ADT MCP has no publish tool. VS Code
|
||||
shows no confirmation beyond "<binding> published locally", so step 4 is the proof. **Done
|
||||
2026-09-16 04:26.**
|
||||
4. `fetch_services` again (expect `isPublished: true`), then
|
||||
`abap_business_services-fetch_service_information`. The service URL path must equal
|
||||
`/sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/`
|
||||
exactly, and the entity set must be `ChangeApproval`. **Result:** both hold, on host
|
||||
`my431353-api.s4hana.cloud.sap` with `sap-client=080` [source: adt-mcp
|
||||
abap_business_services-fetch_services, fetch_service_information on 0M7DEJI, verified
|
||||
2026-09-16]. Business users and browser checks use the UI host `my431353.s4hana.cloud.sap`
|
||||
instead; `-api` refuses them (Landmines).
|
||||
5. Hand back the live `$metadata` for PRD V-2. **Done:** it is captured in
|
||||
`docs/v2/zui_arena_change_appr_o4.metadata.xml`, and the app was reconciled to it on 2026-09-16
|
||||
(CHANGELOG). The pre-build expectation `ChangeApproval_Type` was wrong; the live entity type is
|
||||
`ChangeApprovalType`. See "App contract check" for the settled types.
|
||||
|
||||
## Worker leg (second; run exactly this sequence)
|
||||
|
||||
Prerequisites, all met on 2026-09-16: the U5 root view, U6 base BDEF, U7 behavior pool and U10 root
|
||||
access control are active. Every step uses the per-object routine (details → validation → create →
|
||||
paste into the returned `filePath` → activate through the same `filePath`).
|
||||
|
||||
| Step | create_object JSON (objectType) | Paste | Needs (active) |
|
||||
|---|---|---|---|
|
||||
| W1 | `DDLS/DF` `{"packageName":"ZARENA_PLM","name":"ZC_CHANGEAPPROVAL_A2X","description":"Arena approval A2X projection"}` | `zc_changeapproval_a2x.ddls.asddls` into `.ddls.acds` | activation: U5 (U6, U7 done) |
|
||||
| W2 | `DCLS/DL` `{"packageName":"ZARENA_PLM","name":"ZC_CHANGEAPPROVAL_A2X","description":"Arena approval A2X projection access"}` (no `protectedEntity`, see round 1) | `zc_changeapproval_a2x.dcls.asdcls` into `.dcls.acds` | activation: W1, U10 |
|
||||
| W3 | `BDEF/BDO` `{"behaviorDefinitionType":"definition","packageName":"ZARENA_PLM","rootEntity":"ZC_CHANGEAPPROVAL_A2X","name":"ZC_CHANGEAPPROVAL_A2X","description":"Arena approval A2X behavior","implementationType":"Projection"}` | `zc_changeapproval_a2x.bdef.asbdef` into `.bdef.abdl` | **creation: W1**; activation: W1, U6, U7 |
|
||||
| W4 | `SRVD/SRV` `{"packageName":"ZARENA_PLM","name":"ZAPI_ARENA_CHANGE_APPROVAL","description":"Arena change approval Web API","sourceType":"S"}` | `zapi_arena_change_approval.srvd.srvdsrv` (no comments) into `.srvd.acds` | activation: W1, W3 |
|
||||
| W5 | `SRVB/SVB` `{"packageName":"ZARENA_PLM","name":"ZAPI_ARENA_CHANGE_APPR_A2X","description":"Arena change approval Web API binding","bindingType":"OData V4 - Web API","serviceDefinition":"ZAPI_ARENA_CHANGE_APPROVAL"}` (check `bindingType`, step 7) | none | **creation: W4**; activation: W4 |
|
||||
|
||||
**Round 1: W1, W2 and W4 created empty and pasted; W1 and W2 activated.**
|
||||
|
||||
1. Create W1 (DDLS), W2 (DCLS) and W4 (SRVD) empty. Record each returned `filePath`.
|
||||
- W2: leave out the optional `protectedEntity`. W1 has no active version yet. BDEF creation is
|
||||
known to validate its referenced entity's active version; whether DCLS creation does the same
|
||||
for `protectedEntity` is untested. The pasted source replaces the skeleton anyway.
|
||||
- W4: `"sourceType":"S"` is required. Leave out the optional `referencedObject`.
|
||||
2. Paste W1, W2 and W4 into their returned source files and save all three. Never paste into a
|
||||
`.json`. W4 is pasted now but activated in round 2.
|
||||
3. Activate W1, then W2, in that order.
|
||||
|
||||
**Round 2: W3 created and pasted; W3 then W4 activated.**
|
||||
|
||||
4. Create W3 (BDEF, `Projection`). This needs W1 **active**, because BDEF creation validates the
|
||||
referenced entity's active version (live 2026-09-15). Expect a `filePath` ending in `.bdef.abdl`.
|
||||
5. Paste W3 into that `.bdef.abdl` file and save.
|
||||
6. Activate W3, then W4.
|
||||
|
||||
**Binding: W5 created and activated, not published.**
|
||||
|
||||
7. **Check the `bindingType` string before creating.** `OData V4 - UI` is proven (U14). The Web API
|
||||
value has not been seen live. SAP Help names the type `OData V4 - Web API` [source: sap-docs
|
||||
/btp-cloud-platform/30-development/service-bindings-c6dee8e, verified 2026-09-16], but the 2608
|
||||
release note for ADT for VS Code calls it "OData V4 – API" [source: sap-docs sap-help loio
|
||||
7f674e6190564228a5bb217ebf382611 (APPL-VSC-0011), verified 2026-09-16]. Take the exact value from
|
||||
`get_object_type_details` for `SRVB/SVB` if it lists one; otherwise `run_validation` with
|
||||
`OData V4 - Web API` settles it. If validation refuses the value and no allowed value is listed,
|
||||
stop and report the message rather than trying label variants. The type must be the Web API one: the provider contract
|
||||
`odata_v4_webapi` and the binding type must match, or an error occurs [source: abap-docs
|
||||
/abap-docs-cloud/ABENSRVD_PROVIDER_CONTRACT, verified 2026-09-16].
|
||||
8. Create W5 `ZAPI_ARENA_CHANGE_APPR_A2X` (needs W4 active). Activate it through its returned
|
||||
`filePath` (`.srvb.json` expected, as U14).
|
||||
9. Verify with `abap_business_services-fetch_services` on `ZAPI_ARENA_CHANGE_APPR_A2X`. Expect
|
||||
service `ZAPI_ARENA_CHANGE_APPROVAL`, version `0001`, OData V4, and `isPublished: false`. That
|
||||
unpublished state is the intended end state of this handover. Do not follow the tool's prompt to
|
||||
have it published, and do not call `fetch_service_information` for W5.
|
||||
|
||||
**W5 is NOT published in this handover.** Web API exposure to the worker's communication user goes
|
||||
through a custom communication scenario (PRD V-2), together with the IAM app. That is a separate
|
||||
brief. The communication user will reach it on the `-api` host, the communication-user entry point
|
||||
(KNOWLEDGE 2026-09-16). The W5 name `ZAPI_ARENA_CHANGE_APPR_A2X` is 26 characters, exactly SAP Help's
|
||||
limit (D-1), and the PRD worker contract row names it.
|
||||
|
||||
Follow-up, not part of the sequence above: `abap_atc_run` on W1–W5 (DDLS, DCLS, BDEF, SRVD, SRVB),
|
||||
as U15 step 1 did for the UI leg.
|
||||
|
||||
Notes per step:
|
||||
|
||||
- **W3:** the source header's `abap:` URI line was corrected from `.bdef.json` to `.bdef.abdl` on
|
||||
2026-09-16 (comment only; no BDL change). Still use the returned `filePath`.
|
||||
- **W4: service definition `ZAPI_ARENA_CHANGE_APPROVAL` (Web API service for the worker).** This note
|
||||
holds what the source file's header comment used to say. The header is gone, for the U13 reason.
|
||||
- `abap:` URI:
|
||||
`abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Business%20Services/Service%20Definitions/ZAPI_ARENA_CHANGE_APPROVAL/zapi_arena_change_approval.srvd.acds`
|
||||
- Action: create empty through the ADT MCP (`SRVD/SRV`, `sourceType` `"S"`), replace the entire
|
||||
content with `zapi_arena_change_approval.srvd.srvdsrv`, save, and activate after the
|
||||
`ZC_CHANGEAPPROVAL_A2X` view (W1) and BDEF (W3). Then create the Web API binding
|
||||
`ZAPI_ARENA_CHANGE_APPR_A2X` on it (W5), and do not publish it.
|
||||
- **Keep the source comment-free.** A leading comment blocked U13's activation (U13 note).
|
||||
On U13 the "no draft capability … READ-ONLY" message did not block. If W4 activation fails and
|
||||
lists only that message, read its severity in the editor's Problems view before changing
|
||||
anything; the BO has no draft by design (CHANGELOG 2026-09-16).
|
||||
- Sources: as `ZUI_ARENA_CHANGE_APPROVAL` (U13 note); `odata_v4_webapi` is the Web API contract
|
||||
[ABENSRVD_PROVIDER_CONTRACT], re-read as [source: abap-docs
|
||||
/abap-docs-cloud/ABENSRVD_PROVIDER_CONTRACT, verified 2026-09-16].
|
||||
|
||||
## Activation URIs for `abap_activate_objects`
|
||||
|
||||
**Rule: activate through the `filePath` that `create_object` returned for the object** (per-object
|
||||
routine). The table below is a cross-check. Pattern, learned live 2026-09-15 and unchanged for every
|
||||
object built on 2026-09-16:
|
||||
`abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/<folder>/<NAME>/<name>.<ext>`.
|
||||
In the VS Code workspace the `.json` file in an object folder is header metadata and never receives
|
||||
pasted source. Among the types in this build, SRVB is the one whose returned `filePath` is the
|
||||
`.json` (nothing is pasted there).
|
||||
|
||||
Extensions as returned by `create_object` for this build and proven by activation on 2026-09-16
|
||||
[source: adt-mcp abap_creation-create_object, abap_activate_objects on 0M7DEJI, verified
|
||||
2026-09-16]:
|
||||
|
||||
| Type | Folder | Extension | Proven by |
|
||||
|---|---|---|---|
|
||||
| TABL | `Dictionary/Database%20Tables` | `.tabl.ddic` | U1. `.tabl.json` is header metadata only; it activated a **generator-era** table on 2026-09-15 and is not used |
|
||||
| DDLS | `Core%20Data%20Services/Data%20Definitions` | `.ddls.acds` | U2–U5, U8 |
|
||||
| BDEF | `Core%20Data%20Services/Behavior%20Definitions` | `.bdef.abdl` | U6, U9. **Generator-era record (2026-09-15, not for this build):** `.bdef.json` activated a generator BDEF, and `.bdef.acds`, `.bdef.asbdef` and `.bdef.abap` failed with "array element 0 is null" |
|
||||
| DDLX | `Core%20Data%20Services/Metadata%20Extensions` | `.ddlx.acds` | U12 |
|
||||
| DCLS | `Core%20Data%20Services/Access%20Controls` | `.dcls.acds` | U10, U11 |
|
||||
| CLAS | `Source%20Code%20Library/Classes` | `.clas.abap` | U7 (no Local Types path is returned) |
|
||||
| SRVD | `Business%20Services/Service%20Definitions` | `.srvd.acds` | U13 (after the comment-free re-save) |
|
||||
| SRVB | `Business%20Services/Service%20Bindings` | `.srvb.json` | U14 (returned by `create_object`, activated through it) |
|
||||
|
||||
In step order. The U lines are the URIs of the active objects. The W lines follow the proven
|
||||
pattern; confirm each against the returned `filePath`.
|
||||
|
||||
```
|
||||
B/Dictionary/Database%20Tables/ZZCHNGPPROVAL000/zzchngpproval000.tabl.json
|
||||
B/Core%20Data%20Services/Data%20Definitions/ZD_CHANGEAPPROVAL_REJECTP/zd_changeapproval_rejectp.ddls.acds
|
||||
B/Core%20Data%20Services/Data%20Definitions/ZD_CHANGEAPPROVAL_SYNCEDP/zd_changeapproval_syncedp.ddls.acds
|
||||
B/Core%20Data%20Services/Data%20Definitions/ZD_CHANGEAPPROVAL_FAILEDP/zd_changeapproval_failedp.ddls.acds
|
||||
B/Core%20Data%20Services/Data%20Definitions/ZZR_CHANGEAPPROVAL000/zzr_changeapproval000.ddls.acds
|
||||
B/Core%20Data%20Services/Behavior%20Definitions/ZZR_CHANGEAPPROVAL000/zzr_changeapproval000.bdef.json
|
||||
B/Source%20Code%20Library/Classes/ZZBP_R_CHANGEAPPROVAL000/zzbp_r_changeapproval000.clas.abap
|
||||
B/Core%20Data%20Services/Data%20Definitions/ZZC_CHANGEAPPROVAL000/zzc_changeapproval000.ddls.acds
|
||||
B/Core%20Data%20Services/Data%20Definitions/ZC_CHANGEAPPROVAL_A2X/zc_changeapproval_a2x.ddls.acds
|
||||
B/Core%20Data%20Services/Behavior%20Definitions/ZZC_CHANGEAPPROVAL000/zzc_changeapproval000.bdef.json
|
||||
B/Core%20Data%20Services/Behavior%20Definitions/ZC_CHANGEAPPROVAL_A2X/zc_changeapproval_a2x.bdef.json
|
||||
B/Core%20Data%20Services/Access%20Controls/ZZR_CHANGEAPPROVAL000/zzr_changeapproval000.dcls.acds
|
||||
B/Core%20Data%20Services/Access%20Controls/ZZC_CHANGEAPPROVAL000/zzc_changeapproval000.dcls.acds
|
||||
B/Core%20Data%20Services/Access%20Controls/ZC_CHANGEAPPROVAL_A2X/zc_changeapproval_a2x.dcls.acds
|
||||
B/Core%20Data%20Services/Metadata%20Extensions/ZZC_CHANGEAPPROVAL000/zzc_changeapproval000.ddlx.acds
|
||||
B/Business%20Services/Service%20Definitions/ZZUI_ARENA_CHANGE_APPRVL000_O4/zzui_arena_change_apprvl000_o4.srvd.acds
|
||||
B/Business%20Services/Service%20Definitions/ZAPI_ARENA_CHANGE_APPROVAL/zapi_arena_change_approval.srvd.acds
|
||||
B/Business%20Services/Service%20Bindings/ZZUI_ARENA_CHANGE_APPRVL000_O4/zzui_arena_change_apprvl000_o4.srvb.json
|
||||
B/Business%20Services/Service%20Bindings/ZAPI_ARENA_CHANGE_APPROVAL_A2X/zapi_arena_change_approval_a2x.srvb.json
|
||||
U1 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Dictionary/Database%20Tables/ZCHANGEAPPROVAL/zchangeapproval.tabl.ddic
|
||||
U2 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZD_CHANGEAPPROVAL_REJECTP/zd_changeapproval_rejectp.ddls.acds
|
||||
U3 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZD_CHANGEAPPROVAL_SYNCEDP/zd_changeapproval_syncedp.ddls.acds
|
||||
U4 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZD_CHANGEAPPROVAL_FAILEDP/zd_changeapproval_failedp.ddls.acds
|
||||
U5 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZR_CHANGEAPPROVAL/zr_changeapproval.ddls.acds
|
||||
U6 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Behavior%20Definitions/ZR_CHANGEAPPROVAL/zr_changeapproval.bdef.abdl
|
||||
U7 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Source%20Code%20Library/Classes/ZBP_R_CHANGEAPPROVAL/zbp_r_changeapproval.clas.abap
|
||||
U8 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZC_CHANGEAPPROVAL/zc_changeapproval.ddls.acds
|
||||
U9 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Behavior%20Definitions/ZC_CHANGEAPPROVAL/zc_changeapproval.bdef.abdl
|
||||
U10 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Access%20Controls/ZR_CHANGEAPPROVAL/zr_changeapproval.dcls.acds
|
||||
U11 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Access%20Controls/ZC_CHANGEAPPROVAL/zc_changeapproval.dcls.acds
|
||||
U12 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Metadata%20Extensions/ZC_CHANGEAPPROVAL/zc_changeapproval.ddlx.acds
|
||||
U13 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Business%20Services/Service%20Definitions/ZUI_ARENA_CHANGE_APPROVAL/zui_arena_change_approval.srvd.acds
|
||||
U14 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Business%20Services/Service%20Bindings/ZUI_ARENA_CHANGE_APPR_O4/zui_arena_change_appr_o4.srvb.json
|
||||
W1 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZC_CHANGEAPPROVAL_A2X/zc_changeapproval_a2x.ddls.acds
|
||||
W2 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Access%20Controls/ZC_CHANGEAPPROVAL_A2X/zc_changeapproval_a2x.dcls.acds
|
||||
W3 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Behavior%20Definitions/ZC_CHANGEAPPROVAL_A2X/zc_changeapproval_a2x.bdef.abdl
|
||||
W4 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Business%20Services/Service%20Definitions/ZAPI_ARENA_CHANGE_APPROVAL/zapi_arena_change_approval.srvd.acds
|
||||
W5 abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Business%20Services/Service%20Bindings/ZAPI_ARENA_CHANGE_APPR_A2X/zapi_arena_change_appr_a2x.srvb.json
|
||||
```
|
||||
|
||||
Then re-run ATC on the package objects (`abap_atc_run`; omit RONT/NONT — the ATC API
|
||||
answers "No valid data model exists for object type RONT/ROT") and
|
||||
`abap_business_services-fetch_services` on both bindings.
|
||||
## App contract check (source vs `app/webapp/localService/mainService/metadata.xml`, 2026-09-16)
|
||||
|
||||
## Design decisions baked into the files (falsifiable, dated 2026-09-15)
|
||||
**Settled by the live `$metadata` (2026-09-16).** The table below is the pre-activation comparison,
|
||||
kept as the record. The live capture `docs/v2/zui_arena_change_appr_o4.metadata.xml` (live
|
||||
2026-09-16; read for this revision) settles every open row:
|
||||
|
||||
- **Two projections, two service definitions.** The brief asked for both bindings on the
|
||||
generated service definition *and* for the UI to expose only approve/reject/retrySync
|
||||
while the worker gets create + mark*. A service definition exposes one projection, and a
|
||||
projection BDEF exposes exactly what it lists (no automatic inheritance
|
||||
[source: abap-docs /abap-docs-cloud/ABENBDL_USE_PROJECTION]). Both requirements cannot
|
||||
hold on one definition, so the A2X path got its own projection view/BDEF/definition and
|
||||
the Web API binding sits on `ZAPI_ARENA_CHANGE_APPROVAL`. The RAP-2 "read-only from the
|
||||
UI" requirement wins over the structural wording.
|
||||
- **`authorization master ( none )`** instead of the generator's `( global )`: ADR-002
|
||||
makes the IAM app / business catalog the only access control and DCL governs reads;
|
||||
`( none )` is the documented way to declare "no RAP authorization checks"
|
||||
[source: abap-docs /abap-docs-cloud/ABENBDL_AUTHORIZATION]. Flip to `( global )` plus a
|
||||
`FOR GLOBAL AUTHORIZATION` handler when a custom authorization object exists.
|
||||
- **Derived fields are computed, not persisted.** `StatusText`, `StatusCriticality`,
|
||||
`IsApprovable`, `IsRetriable` are CASE expressions in the root view; a transactional
|
||||
query projection cannot hold expressions
|
||||
[source: abap-docs /abap-docs-cloud/ABENCDS_DEFINE_VIEW_AS_PROJECTION]. They are
|
||||
`field ( readonly )` and absent from the mapping — see step 4.
|
||||
- **Action parameters are abstract entities** (`ZD_*`), one element each, because action
|
||||
input must be an abstract entity or DDIC type
|
||||
[source: abap-docs /abap-docs-cloud/ABENBDL_ACTION_INPUT_PARAM]. `markSynced` and
|
||||
`markFailed` therefore take `SapChangeNumber` / `ErrorMessage` as parameters — the only
|
||||
way an action can "set" them from the worker.
|
||||
- **`internal update`** keeps `update` out of every OData surface while the actions and
|
||||
the determination still update fields `IN LOCAL MODE`
|
||||
[source: abap-docs /abap-docs-cloud/ABENBDL_INTERNAL].
|
||||
- **RequestedBy** is the technical user of the creator (the worker's communication user in
|
||||
the A2X flow). Change to `mandatory : create` if the Arena requester should be shown.
|
||||
- Namespace `com.sap.gateway.srvd.zui_arena_change_approval.v0001`. Entity type
|
||||
`ChangeApprovalType`, not `ChangeApproval_Type`. Entity set `ChangeApproval`.
|
||||
- `ID` `Edm.Guid`. `StatusText` `Edm.String` MaxLength 29. `StatusCriticality` `Edm.Byte`.
|
||||
`IsApprovable`/`IsRetriable` `Edm.Boolean`. `RequestedOn`/`DecidedOn` `Edm.DateTimeOffset`
|
||||
Precision 7. `SapPreview` `Edm.String` without MaxLength.
|
||||
- `reject` parameter `RejectReason` `Edm.String` `Nullable="false"` MaxLength 255, the same as the app.
|
||||
- Action enablement `Core.OperationAvailable Path="_it/__OperationControl/<action>"` for `approve`,
|
||||
`reject` and `retrySync`.
|
||||
- Insertable, Updatable and Deletable are all `false`.
|
||||
|
||||
## Landmines learned live (KNOWLEDGE.md candidates)
|
||||
The app was reconciled to this metadata on 2026-09-16, including backend-owned action enablement
|
||||
(CHANGELOG). Rows below marked UNVERIFIED, "unknown until live" or "intended difference" are resolved
|
||||
by this list.
|
||||
|
||||
- [2026-09-15] `x-ui-service` generator: every field needs `semanticType` (e.g. `custom`)
|
||||
or validation fails with "Builtin type of field X is invalid"; semantic-key fields pass
|
||||
without it. The generator prepends its own `Z` to the `prefix` (`Z` → `ZZ…`) and appends
|
||||
`000` to every artifact name even with `suffix: ""`; service definition and UI binding
|
||||
get the same name (`ZZUI_ARENA_CHANGE_APPRVL000_O4`). There is no delete tool in the ADT
|
||||
MCP, so a naming mistake is permanent from the agent side.
|
||||
- [2026-09-15] `create_object` for SRVD needs `sourceType` (`"S"` worked; omitted →
|
||||
All 17 app properties exist in `ZC_CHANGEAPPROVAL` with the same names and case. The three actions
|
||||
`approve`/`reject`/`retrySync` are in `ZC_CHANGEAPPROVAL` (projection BDEF), and
|
||||
`ZUI_ARENA_CHANGE_APPROVAL` exposes exactly `ZC_CHANGEAPPROVAL as ChangeApproval`. `expose … as`
|
||||
sets the entity set name and `<alias>_Type` [source: abap-docs /abap-fiori-showcase/06_object_page_content,
|
||||
verified 2026-09-15] (live: `<alias>Type`, see above). The source is not changed for the open items below. Decisions sit with the
|
||||
coordinator and are confirmed at U15 / V-2.
|
||||
|
||||
| Item | App mock | Source | Status |
|
||||
|---|---|---|---|
|
||||
| Service URL / schema namespace | `manifest.json` dataSource `/sap/opu/odata4/sap/<UI binding, 28-character long form>/srvd/sap/zui_arena_change_approval/0001/`; namespace `com.sap.gateway.srvd.<same long form>.v0001` | binding `ZUI_ARENA_CHANGE_APPR_O4` (D-1): intended `/sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/` | **intended difference**; the app's dataSource URL, mock namespace and annotation targets are reconciled at V-2 from the live `$metadata` (separate Fiori brief) |
|
||||
| Entity set / entity type / key | `ChangeApproval` / `ChangeApproval_Type` / `ID` | `expose ZC_CHANGEAPPROVAL as ChangeApproval` | match |
|
||||
| String lengths (ItemNumber 18, ItemName 40, ChangeType 15, Status 10, ArenaEcoId 20, RequestedBy/DecidedBy 12, SapChangeNumber 12, ErrorMessage/RejectReason 255) | as listed | same CHAR lengths in `ZCHANGEAPPROVAL` | match |
|
||||
| `SapPreview` | Edm.String, no MaxLength | `abap.string(0)` (RAP-7) | match expected |
|
||||
| `StatusText` | absent | CASE result, CHAR(29) by the max-type rule [source: abap-docs /abap-docs-cloud/ABENCDS_CASE_EXPRESSION_V2, verified 2026-09-16]; RAP-3 text element | extra; keep |
|
||||
| `LocalLastChangedAt` | absent | etag field for `use etag` | extra; keep |
|
||||
| `StatusCriticality` | Edm.Byte | integer literals typed INT1..INT8 by value [source: abap-docs /abap-docs-cloud/ABENCDS_UNTYPED_LITERAL_V2, verified 2026-09-16] | INT1 → Edm.Byte UNVERIFIED |
|
||||
| `IsApprovable`, `IsRetriable` | Edm.Boolean | `cast(… as abap_boolean)` | ABAP_BOOLEAN → Edm.Boolean UNVERIFIED |
|
||||
| `RequestedOn`, `DecidedOn` | Edm.DateTimeOffset Precision 7 | `abap.utclong` | UTCLONG mapping UNVERIFIED |
|
||||
| `ID` | Edm.Guid, `Core.Computed` | `sysuuid_x16`, `readonly, numbering : managed` | expected, UNVERIFIED |
|
||||
| `reject` parameter `RejectReason` | Nullable="false", MaxLength 255 | `ZD_CHANGEAPPROVAL_REJECTP` CHAR(255), not declared mandatory; the handler rejects an empty reason | differs in metadata, behavior meets RAP-2 |
|
||||
| Action enablement | `Core.OperationAvailable Path="IsApprovable"/"IsRetriable"` (mock only) | RAP generates it from `( features : instance )` | path form unknown until live |
|
||||
| Insert/Update/Delete restrictions | all false | UI projection BDEF exposes no create/update/delete | expected |
|
||||
|
||||
## Design decisions baked into the files (falsifiable, dated 2026-09-15 unless noted)
|
||||
|
||||
- **State machine** (PRD ARN-002; `retrySync` target decided 2026-09-16):
|
||||
|
||||
| Action | From | To | Caller |
|
||||
|---|---|---|---|
|
||||
| create (determination `setInitialStatus`) | none | PENDING | worker (A2X) |
|
||||
| `approve` | PENDING | APPROVED | business user (UI) |
|
||||
| `reject(RejectReason)` | PENDING | REJECTED (terminal) | business user (UI) |
|
||||
| `markExecuting` | APPROVED | EXECUTING | worker (A2X) |
|
||||
| `markSynced(SapChangeNumber)` | EXECUTING | SYNCED (terminal) | worker (A2X) |
|
||||
| `markFailed(ErrorMessage)` | EXECUTING | FAILED | worker (A2X) |
|
||||
| `retrySync` | FAILED | **APPROVED** (clears `ErrorMessage`, keeps `DecidedBy`/`DecidedOn`) | business user (UI) |
|
||||
|
||||
Only `markExecuting` writes EXECUTING. A retried record goes back through `markExecuting`, so the
|
||||
worker re-claims it the same way as a first approval. Feature control is unchanged: `retrySync` is
|
||||
enabled only for FAILED. Each action re-checks the status in the handler as well.
|
||||
- **RAP action implementation contract** (2026-09-16). Every action handler returns failed rows
|
||||
with `%fail-cause` (not_found or unspecific; `locked` is mapped to unspecific) and
|
||||
`%op-%action-<name>`. Reported messages carry `%op-%action-<name>`. Failures and messages of the
|
||||
internal UPDATE are merged into `failed`/`reported`, and `result` holds only keys that did not
|
||||
fail [source: sap-docs sap-help loio de6569d4b92e40a0911c926170140beb (Action contract),
|
||||
1040b81372d44ed38b07a409fa0e1769 (General contract), abaprap_impl_rules (allowed fail causes),
|
||||
verified 2026-09-16]. Under `strict(2)`, contract violations are runtime errors [source: abap-docs
|
||||
/abap-docs-cloud/ABENBDL_STRICT_2, verified 2026-09-16].
|
||||
- **Semantic key enforced on create** (2026-09-16). `validation checkDuplicate on save { create; }`
|
||||
fails a create when another record with the same `ItemNumber` + `ChangeType` + `ArenaEcoId`
|
||||
exists and is not REJECTED, or when the same request contains that key twice. Validation syntax,
|
||||
handler signature and effect (the whole transactional buffer is rejected) [source: abap-docs
|
||||
/abap-docs-cloud/ABENBDL_VALIDATIONS, ABAPHANDLER_METH_VALIDATE, verified 2026-09-16].
|
||||
- Fail cause: validations may only use `cause-unspecific`.
|
||||
- Messages are state messages with `%state_area` and `%element`.
|
||||
- Persisted rows are read from `ZR_CHANGEAPPROVAL` with `OPTIONS PRIVILEGED ACCESS`, because a
|
||||
handler SELECT on an access-controlled view without it violates the RAP BO contract [source:
|
||||
sap-docs sap-help abaprap_impl_rules; abap-docs /abap-docs-cloud/ABAPSELECT_PRIVILEGED_ACCESS,
|
||||
ABAPDERIVED_TYPES_STATE_AREA, verified 2026-09-16].
|
||||
- A validation is not something a projection lists [source: abap-docs
|
||||
/abap-docs-cloud/ABENBDL_USE_PROJECTION, verified 2026-09-16], so both projections are unchanged.
|
||||
- **`use etag` in the entity header** (2026-09-16). In both projection BDEFs `use etag` sits between
|
||||
`define behavior for … alias ChangeApproval` and `{`, without a semicolon. It is an entity behavior
|
||||
characteristic, not a body statement [source: abap-docs /abap-docs-cloud/ABENBDL_CHARACTER_PROJECTION,
|
||||
ABENBDL_DEFINE_BEH_PROJECTION, verified 2026-09-16].
|
||||
- **Two projections, two service definitions.** The UI projection `ZC_CHANGEAPPROVAL` exposes only
|
||||
approve/reject/retrySync on `ZUI_ARENA_CHANGE_APPROVAL`. The worker's `ZC_CHANGEAPPROVAL_A2X`
|
||||
exposes create + markExecuting/markSynced/markFailed on `ZAPI_ARENA_CHANGE_APPROVAL`. A projection
|
||||
BDEF exposes exactly what it lists, with no automatic inheritance [source: abap-docs
|
||||
/abap-docs-cloud/ABENBDL_USE_PROJECTION]. PRD RAP-5's wording (two bindings on one definition) is
|
||||
superseded by this design and is a governance item. (Closed: PRD RAP-5 was amended to this
|
||||
design on 2026-09-16; PRD read 2026-09-16.)
|
||||
- **No projection behavior pool** (2026-09-16: never created). A projection BDEF needs one only for
|
||||
new actions/functions [source: abap-docs /abap-docs-cloud/ABENBDL_BDEF_PROJECTION_HEADER].
|
||||
- **`authorization master ( none )`**: ADR-002 makes the IAM app / business catalog the only access
|
||||
control, and DCL governs reads [source: abap-docs /abap-docs-cloud/ABENBDL_AUTHORIZATION]. Switch
|
||||
to `( global )` plus a `FOR GLOBAL AUTHORIZATION` handler when a custom authorization object
|
||||
exists. **Not final:** `( none )` versus global authorization is open question PRD OQ-8, to be
|
||||
decided before business roles are assigned.
|
||||
- **Derived fields are computed, not persisted.** `StatusText`, `StatusCriticality`, `IsApprovable`
|
||||
and `IsRetriable` are CASE expressions in `ZR_CHANGEAPPROVAL`, because a transactional query
|
||||
projection cannot hold expressions [source: abap-docs
|
||||
/abap-docs-cloud/ABENCDS_DEFINE_VIEW_AS_PROJECTION]. They are `field ( readonly )` and absent from
|
||||
the mapping (see U6).
|
||||
- **Action parameters are abstract entities** (`ZD_*`, one element each), because action input must
|
||||
be an abstract entity or DDIC type [source: abap-docs /abap-docs-cloud/ABENBDL_ACTION_INPUT_PARAM].
|
||||
- **`internal update`** keeps `update` off every OData surface. Actions and the determination still
|
||||
update fields `IN LOCAL MODE` [source: abap-docs /abap-docs-cloud/ABENBDL_INTERNAL].
|
||||
- **RequestedBy** holds the technical user of the creator (the worker's communication user in the
|
||||
A2X flow). Change it to `mandatory : create` if the Arena requester should be shown.
|
||||
- **No SAP object type** (2026-09-16), see the inventory section.
|
||||
- **Released objects used** (all level A, public_cloud): `SYSUUID_X16`, `ABP_CREATION_USER`,
|
||||
`ABP_CREATION_TSTMPL`, `ABP_LASTCHANGE_USER`, `ABP_LASTCHANGE_TSTMPL`,
|
||||
`ABP_LOCINST_LASTCHANGE_TSTMPL`, `ABAP_BOOLEAN`, `CL_ABAP_BEHAVIOR_HANDLER`, `CL_ABAP_CONTEXT_INFO`,
|
||||
`IF_ABAP_BEHV`, `IF_ABAP_BEHV_MESSAGE` [source: sap-released-objects
|
||||
sap_check_clean_core_compliance, verified 2026-09-16].
|
||||
|
||||
## Landmines (live-learned, dated)
|
||||
|
||||
- [2026-09-15] `create_object` for SRVD needs `sourceType` (`"S"` worked; omitting it fails with
|
||||
"serviceDefinitionInfo.sourceType is null"). BDEF/SRVB creation validates the referenced
|
||||
DDLS/SRVD **active** version, so source-less objects block dependent creations.
|
||||
- [2026-09-15] Activation URIs: see table above; BDEF is `.bdef.json`, table `.tabl.json`,
|
||||
SAP object types live under `Business Services`.
|
||||
- [2026-09-15] The MCP session id from `get_schema` `referenceContent` is single-use in
|
||||
practice — fetch a fresh one before each `generate_objects` attempt.
|
||||
DDLS/SRVD's **active** version, so source-less objects block dependent creations.
|
||||
- [2026-09-15, **superseded 2026-09-16**] Activation URIs recorded on 2026-09-15 came from
|
||||
generator objects: BDEF `.bdef.json` and TABL `.tabl.json` (both generator-era). They are wrong for
|
||||
objects created with `create_object`; see the per-type entry below.
|
||||
- [2026-09-16] **Per-type file extensions: use the `filePath` returned by `create_object`.** Returned
|
||||
and proven by activation: TABL `.tabl.ddic` (U1), DDLS `.ddls.acds`, DCLS `.dcls.acds`, DDLX
|
||||
`.ddlx.acds`, BDEF **`.bdef.abdl`** (U6, U9), CLAS `.clas.abap` (global class only; no Local Types
|
||||
path is returned), SRVD `.srvd.acds` (U13), SRVB **`.srvb.json`** (U14) [source: adt-mcp
|
||||
abap_creation-create_object / abap_activate_objects on 0M7DEJI, verified 2026-09-16].
|
||||
- [2026-09-16] A `.json` file in an object folder of the VS Code ADT workspace is metadata only
|
||||
(`zchangeapproval.tabl.json`: formatVersion, description, originalLanguage,
|
||||
`abapLanguageVersion: cloudDevelopment`). Never paste source into it. The table source goes into
|
||||
`.tabl.ddic` (live observation 2026-09-16). The binding's `.srvb.json` is the exception by type:
|
||||
it is the returned `filePath`, nothing is pasted into it, and activation and publish go through
|
||||
it (U14, U15).
|
||||
- [2026-09-16] **Service definition sources must carry no comments.** A leading `/* … */` header made
|
||||
U13's activation fail with "Comments are not supported and will be deleted on save" (Ln 1), and the
|
||||
same definition without it activated (live 2026-09-16). The DCLS, DDLX and BDEF headers did not
|
||||
block. CDS SDL follows the general CDS syntax rules, which allow comments [source: abap-docs
|
||||
/abap-docs-cloud/ABENCDS_F1_SDL_SYNTAX, ABENCDS_GENERAL_SYNTAX_RULES, verified 2026-09-16], so this
|
||||
is the tooling, not the language. Both SRVD files in this folder are comment-free; keep them so.
|
||||
- [2026-09-16] **`abap_activate_objects` output is thin.** Success returns only "Activation
|
||||
successful.", with no warnings. Failure lists messages with line and column but no severity, so read
|
||||
severity in the editor [source: adt-mcp abap_activate_objects on 0M7DEJI, verified 2026-09-16].
|
||||
- [2026-09-16] **Publishing a binding in ADT for VS Code is a code lens.** Open the binding's
|
||||
`.srvb.json` source and choose the **Publish** code lens; Unpublish and Preview… work the same way
|
||||
[source: sap-docs sap-help loio dd6f5de63e7245a7abe7e39389841596 "ABAP RAP Tools", verified
|
||||
2026-09-16]. The extension contributes no publish command, the SAP ADT MCP has no publish tool, and
|
||||
the only visible feedback is "<binding> published locally". Verify with `fetch_services`
|
||||
(`isPublished: true`) (KNOWLEDGE 2026-09-16; U14 published 2026-09-16 04:26).
|
||||
- [2026-09-16] **UI host vs `-api` host.** `fetch_service_information` reports the service URL on
|
||||
`my431353-api.s4hana.cloud.sap` with `sap-client=080` [source: adt-mcp
|
||||
abap_business_services-fetch_service_information on 0M7DEJI, verified 2026-09-16]. A business user
|
||||
calling that host from the browser is refused as "Forbidden / blocked by UCON". The same path on
|
||||
`my431353.s4hana.cloud.sap` returns `$metadata` (live 2026-09-16; KNOWLEDGE 2026-09-16). The UI
|
||||
service and the Fiori app use the UI host. The `-api` host is the communication-user entry point,
|
||||
so the worker's Web API (W5) is reached there only through a custom communication scenario (PRD
|
||||
V-2), never through the UI service.
|
||||
- [2026-09-15] The ADT MCP has no delete tool and no package tool. A wrong name is permanent from
|
||||
the agent side, and a missing package must be created in ADT.
|
||||
- [2026-09-15] ATC via MCP rejects RONT/NONT ("No valid data model exists for object type
|
||||
RONT/ROT"). Not relevant here because no SAP object type is created.
|
||||
- [2026-09-16] A missing package shows up read-only as "Package '<name>' does not exist" from
|
||||
`abap_creation-run_validation` [source: adt-mcp on 0M7DEJI, verified 2026-09-16].
|
||||
- [2026-09-16] Service binding name limit: SAP Help says 26 in every version checked, while the
|
||||
ADT MCP validation accepts 30 (undocumented). The 26 limit is used here (D-1, resolved). U14 (24
|
||||
characters) published on 2026-09-16.
|
||||
- [2026-09-16] The V4 URL's second segment is the binding's service alias, renamable only while
|
||||
unpublished (U14). For U14 it was verified after activation with `fetch_services`, before
|
||||
publishing; opening the binding before activation is not needed. U14 is now published, so its
|
||||
alias is fixed.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/* TARGET OBJECT : service definition ZAPI_ARENA_CHANGE_APPROVAL (created empty via ADT MCP 2026-09-15)
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Business%20Services/Service%20Definitions/ZAPI_ARENA_CHANGE_APPROVAL/zapi_arena_change_approval.srvd.acds
|
||||
ACTION : replace entire content, then activate (after ZC_CHANGEAPPROVAL_A2X view + BDEF).
|
||||
Sources: as ZZUI_ARENA_CHANGE_APPRVL000_O4; odata_v4_webapi is the Web API contract [ABENSRVD_PROVIDER_CONTRACT]. */
|
||||
@EndUserText.label: 'Arena change approval - Web API (worker)'
|
||||
define service ZAPI_ARENA_CHANGE_APPROVAL
|
||||
provider contracts odata_v4_webapi
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
" TARGET OBJECT : class ZBP_R_CHANGEAPPROVAL - GLOBAL CLASS include (behavior pool) - README step U7, UI leg
|
||||
" abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Source%20Code%20Library/Classes/ZBP_R_CHANGEAPPROVAL/zbp_r_changeapproval.clas.abap
|
||||
" ACTION : after BDEF ZR_CHANGEAPPROVAL is active (README U6), create empty via ADT MCP (objectType CLAS/OC,
|
||||
" README U7), replace entire content of the global class; the handlers go into "Local Types"
|
||||
" (locals_imp file). Save both, then activate the class.
|
||||
" Source: FOR BEHAVIOR OF defines the ABAP behavior pool; the global class implements nothing itself
|
||||
" [source: abap-docs /abap-docs-cloud/ABAPCLASS_FOR_BEHAVIOR_OF, ABENABAP_BEHAVIOR_POOLS, verified 2026-09-15].
|
||||
CLASS zbp_r_changeapproval DEFINITION
|
||||
PUBLIC
|
||||
ABSTRACT
|
||||
FINAL
|
||||
FOR BEHAVIOR OF zr_changeapproval.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS zbp_r_changeapproval IMPLEMENTATION.
|
||||
ENDCLASS.
|
||||
@@ -0,0 +1,765 @@
|
||||
" TARGET OBJECT : class ZBP_R_CHANGEAPPROVAL - LOCAL TYPES include (Local Types tab in ADT) - README step U7, UI leg
|
||||
" abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Source%20Code%20Library/Classes/ZBP_R_CHANGEAPPROVAL/zbp_r_changeapproval.clas.locals_imp.abap
|
||||
" ACTION : replace entire content, save, then activate the class (README U7; BDEF ZR_CHANGEAPPROVAL must be
|
||||
" active first). Activation goes through the class URI (.clas.abap), not this include.
|
||||
"
|
||||
" Sources (verified 2026-09-15 unless dated otherwise):
|
||||
" handler class inherits from CL_ABAP_BEHAVIOR_HANDLER (released) [sap-released-objects public_cloud A, verified 2026-09-16]
|
||||
" FOR INSTANCE FEATURES signature + result via %tky / %features-%action-<name> / if_abap_behv=>fc-o-enabled|disabled
|
||||
" [abap-docs /abap-docs-cloud/ABAPHANDLER_METH_FEATURES, ABAPDERIVED_TYPES_FEATURES, ABENBDL_ACTIONS_FC]
|
||||
" FOR MODIFY ... FOR ACTION with RESULT; %param carries the action parameter (keys) and the result ($self)
|
||||
" [abap-docs /abap-docs-cloud/ABENBDL_ACTION2_ABEXA, ABAPDERIVED_TYPES_PARAM]
|
||||
" READ ENTITIES ... IN LOCAL MODE ... FIELDS ( ) WITH CORRESPONDING #( keys ) RESULT
|
||||
" [abap-docs /abap-docs-cloud/ABENBDL_ACTIONS_FC example]
|
||||
" MODIFY ENTITIES ... IN LOCAL MODE (skips feature control and authorization) with UPDATE FIELDS ( ) WITH <table>
|
||||
" [abap-docs /abap-docs-cloud/ABAPMODIFY_ENTITY_ENTITIES, ABAPMODIFY_ENTITY_ENTITIES_OP, ABENBDL_AUTHORIZATION;
|
||||
" sap-docs sap-help loio e75275489fe648f6b00977be76f0bc06 (deductDiscount: collect valid keys, update, read, result), verified 2026-09-16]
|
||||
" FOR DETERMINE ON MODIFY signature [abap-docs /abap-docs-cloud/ABAPHANDLER_METH_DET]
|
||||
" utclong_current( ) [abap-docs /abap-docs-cloud/ABENUTCLONG_CURRENT]
|
||||
" cl_abap_context_info=>get_user_technical_name( ) (released class) [sap-docs sap-help loio 7be24435b3e24540a9edad9a2535175a;
|
||||
" sap-released-objects CL_ABAP_CONTEXT_INFO public_cloud A, verified 2026-09-16]
|
||||
" if_abap_behv / if_abap_behv_message are released [sap-released-objects INTF public_cloud A, verified 2026-09-16]
|
||||
" RAP action implementation contract (verified 2026-09-16):
|
||||
" - an unsuccessful action returns one row per failed input identifier in failed "with the correct fail cause and
|
||||
" flags the %action component on the correct action"; for every failed identifier with a cause other than
|
||||
" not_found there is one error message in reported [sap-docs sap-help loio de6569d4b92e40a0911c926170140beb]
|
||||
" - for fail causes other than not_found/locked the failed operation in %op must be provided; reported always fills
|
||||
" %op; result contains only input identifiers not in failed, without duplicates
|
||||
" [sap-docs sap-help loio 1040b81372d44ed38b07a409fa0e1769]
|
||||
" - %op groups the operation flags incl. %action [abap-docs /abap-docs-cloud/ABAPDERIVED_TYPES_OP]; %fail-cause values
|
||||
" are defined in IF_ABAP_BEHV [abap-docs /abap-docs-cloud/ABAPDERIVED_TYPES_FAIL]; %op-%action-<name> = mk-on in
|
||||
" reported [sap-docs loio e75275489fe648f6b00977be76f0bc06]
|
||||
" - allowed fail causes: actions any cause except if_abap_behv=>cause-locked; validations on save only
|
||||
" if_abap_behv=>cause-unspecific; with a non-initial %state_area only %element may be flagged in %op
|
||||
" [sap-docs sap-help abaprap_impl_rules "RAP Implementation Rules"]
|
||||
" - strict(2) turns RAP BO contract violations into runtime errors [abap-docs /abap-docs-cloud/ABENBDL_STRICT_2]
|
||||
" - merging a MODIFY response: CORRESPONDING #( DEEP APPENDING BASE ( reported ) ... ). DEEP alone replaces a nested
|
||||
" table such as reported-changeapproval and would drop the messages appended earlier in the handler; DEEP APPENDING
|
||||
" BASE "ensures that the nested target tables are not deleted" and "appends the lines of the nested source tables"
|
||||
" [abap-docs /abap-docs-cloud/ABENCORRESPONDING_CONSTR_ARG_TYPE, ABENNEWS-783-ASSIGNMENTS, verified 2026-09-16]
|
||||
" Validation (verified 2026-09-16):
|
||||
" - METHODS meth FOR VALIDATE ON SAVE IMPORTING keys FOR bdef~val; failed/reported implicit
|
||||
" [abap-docs /abap-docs-cloud/ABAPHANDLER_METH_VALIDATE]; no EML MODIFY in validations; a failing validation
|
||||
" rejects the whole transactional buffer [abap-docs /abap-docs-cloud/ABENBDL_VALIDATIONS]
|
||||
" - state message pattern: invalidate %tky + %state_area first, then fail + message with %state_area and %element
|
||||
" [abap-docs /abap-docs-cloud/ABAPDERIVED_TYPES_STATE_AREA, ABENBDL_VALIDATIONS example]
|
||||
" - a SELECT on an access-controlled CDS view without OPTIONS PRIVILEGED ACCESS inside a RAP handler is a RAP BO
|
||||
" contract violation [sap-docs sap-help abaprap_impl_rules "Non-privileged access"]; PRIVILEGED ACCESS disables CDS
|
||||
" access control for the SELECT, OPTIONS goes at the end of the statement
|
||||
" [abap-docs /abap-docs-cloud/ABAPSELECT_PRIVILEGED_ACCESS, ABAPSELECT_OPTIONS]
|
||||
" Design notes:
|
||||
" - State machine (PRD ARN-002; retrySync 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. Only markExecuting writes EXECUTING, so a
|
||||
" retried record is re-claimed by the worker through markExecuting and cannot be executed twice in parallel.
|
||||
" - Status transitions are enforced twice: get_instance_features disables the action (UI greys it out / EML fails
|
||||
" with an entry in failed [ABENBDL_ACTIONS_FC]) AND each action re-checks the current status so an EML caller
|
||||
" IN LOCAL MODE cannot skip the state machine.
|
||||
" - The six actions repeat the same read/check/update/read pattern on purpose: each action flags its own
|
||||
" %op-%action-<name> component, so a generic helper would need additional derived-type plumbing.
|
||||
" - A failed UPDATE with cause locked is reported as unspecific, because locked is not an allowed cause for actions.
|
||||
" - RequestedBy is the technical user of the creator (for the A2X flow: the worker's communication user).
|
||||
" If the Arena requester should be shown instead, make RequestedBy mandatory:create in the BDEF and drop it
|
||||
" from the determination.
|
||||
" - checkDuplicate: the SELECT only sees persisted rows (a validation runs in the save sequence before the new
|
||||
" instances are written), so duplicates inside the same request are checked separately on the buffer data.
|
||||
" UNVERIFIED 2026-09-16: the list of SELECT additions that cannot be combined with PRIVILEGED ACCESS was not
|
||||
" retrievable; this uses SELECT SINGLE without FOR ALL ENTRIES. The syntax check at U7 activation is the proof.
|
||||
" abaplint (abap-docs abap_lint, 2026-09-16) does not parse `OPTIONS PRIVILEGED ACCESS` but parses the FROM-clause
|
||||
" form. If the tenant syntax check refuses the OPTIONS form, use the equally documented
|
||||
" `SELECT SINGLE FROM zr_changeapproval WITH PRIVILEGED ACCESS FIELDS ID WHERE ... INTO @DATA(existing_id).`
|
||||
" (affects only that entity; not combinable with OPTIONS PRIVILEGED ACCESS)
|
||||
" [source: abap-docs /abap-docs-cloud/ABAPSELECT_DATA_SOURCE, verified 2026-09-16].
|
||||
|
||||
CLASS lhc_changeapproval DEFINITION INHERITING FROM cl_abap_behavior_handler.
|
||||
PRIVATE SECTION.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF status,
|
||||
pending TYPE zchangeapproval-status VALUE 'PENDING',
|
||||
approved TYPE zchangeapproval-status VALUE 'APPROVED',
|
||||
executing TYPE zchangeapproval-status VALUE 'EXECUTING',
|
||||
synced TYPE zchangeapproval-status VALUE 'SYNCED',
|
||||
rejected TYPE zchangeapproval-status VALUE 'REJECTED',
|
||||
failed TYPE zchangeapproval-status VALUE 'FAILED',
|
||||
END OF status.
|
||||
|
||||
CONSTANTS state_area_duplicate TYPE string VALUE `CHECK_DUPLICATE`.
|
||||
|
||||
METHODS get_instance_features FOR INSTANCE FEATURES
|
||||
IMPORTING keys REQUEST requested_features FOR ChangeApproval RESULT result.
|
||||
|
||||
METHODS approve FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~approve RESULT result.
|
||||
|
||||
METHODS reject FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~reject RESULT result.
|
||||
|
||||
METHODS retrySync FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~retrySync RESULT result.
|
||||
|
||||
METHODS markExecuting FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~markExecuting RESULT result.
|
||||
|
||||
METHODS markSynced FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~markSynced RESULT result.
|
||||
|
||||
METHODS markFailed FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~markFailed RESULT result.
|
||||
|
||||
METHODS setInitialStatus FOR DETERMINE ON MODIFY
|
||||
IMPORTING keys FOR ChangeApproval~setInitialStatus.
|
||||
|
||||
METHODS checkDuplicate FOR VALIDATE ON SAVE
|
||||
IMPORTING keys FOR ChangeApproval~checkDuplicate.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS lhc_changeapproval IMPLEMENTATION.
|
||||
|
||||
METHOD get_instance_features.
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals)
|
||||
FAILED failed.
|
||||
|
||||
result = VALUE #( FOR approval IN approvals
|
||||
( %tky = approval-%tky
|
||||
%features-%action-approve = COND #( WHEN approval-Status = status-pending
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-reject = COND #( WHEN approval-Status = status-pending
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-retrySync = COND #( WHEN approval-Status = status-failed
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-markExecuting = COND #( WHEN approval-Status = status-approved
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-markSynced = COND #( WHEN approval-Status = status-executing
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-markFailed = COND #( WHEN approval-Status = status-executing
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled ) ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD approve.
|
||||
" PENDING -> APPROVED; records the decision, never writes SapChangeNumber (PRD RAP-1)
|
||||
DATA approvals_for_update TYPE TABLE FOR UPDATE zr_changeapproval.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals).
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-not_found
|
||||
%op-%action-approve = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-pending.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific
|
||||
%op-%action-approve = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%op-%action-approve = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only PENDING records can be approved (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
Status = status-approved
|
||||
DecidedBy = cl_abap_context_info=>get_user_technical_name( )
|
||||
DecidedOn = utclong_current( ) ) TO approvals_for_update.
|
||||
ENDLOOP.
|
||||
|
||||
IF approvals_for_update IS NOT INITIAL.
|
||||
MODIFY ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status DecidedBy DecidedOn )
|
||||
WITH approvals_for_update
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
|
||||
" Propagate the internal UPDATE response into the action response
|
||||
LOOP AT update_reported-changeapproval ASSIGNING FIELD-SYMBOL(<update_message>).
|
||||
<update_message>-%op-%action-approve = if_abap_behv=>mk-on.
|
||||
ENDLOOP.
|
||||
reported = CORRESPONDING #( DEEP APPENDING BASE ( reported ) update_reported ).
|
||||
|
||||
LOOP AT update_failed-changeapproval INTO DATA(update_failure).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%fail-cause = COND #( WHEN update_failure-%fail-cause = if_abap_behv=>cause-locked
|
||||
THEN if_abap_behv=>cause-unspecific
|
||||
ELSE update_failure-%fail-cause )
|
||||
%op-%action-approve = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
IF update_failure-%fail-cause <> if_abap_behv=>cause-not_found
|
||||
AND NOT line_exists( update_reported-changeapproval[ ID = update_failure-ID ] ).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%op-%action-approve = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'The approval could not be recorded' ) )
|
||||
TO reported-changeapproval.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDIF.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
LOOP AT updated INTO DATA(row).
|
||||
IF NOT line_exists( failed-changeapproval[ ID = row-ID ] ).
|
||||
APPEND VALUE #( %tky = row-%tky %param = row ) TO result.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD reject.
|
||||
" PENDING -> REJECTED with a mandatory reason (PRD RAP-2); REJECTED is terminal
|
||||
DATA approvals_for_update TYPE TABLE FOR UPDATE zr_changeapproval.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals).
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-not_found
|
||||
%op-%action-reject = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-pending.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific
|
||||
%op-%action-reject = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%op-%action-reject = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only PENDING records can be rejected (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF key-%param-RejectReason IS INITIAL.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific
|
||||
%op-%action-reject = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%op-%action-reject = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'A reject reason is required' ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
Status = status-rejected
|
||||
RejectReason = key-%param-RejectReason
|
||||
DecidedBy = cl_abap_context_info=>get_user_technical_name( )
|
||||
DecidedOn = utclong_current( ) ) TO approvals_for_update.
|
||||
ENDLOOP.
|
||||
|
||||
IF approvals_for_update IS NOT INITIAL.
|
||||
MODIFY ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status RejectReason DecidedBy DecidedOn )
|
||||
WITH approvals_for_update
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
|
||||
LOOP AT update_reported-changeapproval ASSIGNING FIELD-SYMBOL(<update_message>).
|
||||
<update_message>-%op-%action-reject = if_abap_behv=>mk-on.
|
||||
ENDLOOP.
|
||||
reported = CORRESPONDING #( DEEP APPENDING BASE ( reported ) update_reported ).
|
||||
|
||||
LOOP AT update_failed-changeapproval INTO DATA(update_failure).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%fail-cause = COND #( WHEN update_failure-%fail-cause = if_abap_behv=>cause-locked
|
||||
THEN if_abap_behv=>cause-unspecific
|
||||
ELSE update_failure-%fail-cause )
|
||||
%op-%action-reject = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
IF update_failure-%fail-cause <> if_abap_behv=>cause-not_found
|
||||
AND NOT line_exists( update_reported-changeapproval[ ID = update_failure-ID ] ).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%op-%action-reject = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'The rejection could not be recorded' ) )
|
||||
TO reported-changeapproval.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDIF.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
LOOP AT updated INTO DATA(row).
|
||||
IF NOT line_exists( failed-changeapproval[ ID = row-ID ] ).
|
||||
APPEND VALUE #( %tky = row-%tky %param = row ) TO result.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD retrySync.
|
||||
" FAILED -> APPROVED (decision 2026-09-16): clears the previous error and keeps DecidedBy/DecidedOn of the original
|
||||
" approval. The worker re-claims the record through markExecuting (APPROVED -> EXECUTING) and re-executes the staged
|
||||
" payload (ARN-002 amendment, ARN-010). retrySync never writes EXECUTING itself.
|
||||
DATA approvals_for_update TYPE TABLE FOR UPDATE zr_changeapproval.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals).
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-not_found
|
||||
%op-%action-retrySync = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-failed.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific
|
||||
%op-%action-retrySync = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%op-%action-retrySync = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only FAILED records can be retried (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
Status = status-approved
|
||||
ErrorMessage = '' ) TO approvals_for_update.
|
||||
ENDLOOP.
|
||||
|
||||
IF approvals_for_update IS NOT INITIAL.
|
||||
MODIFY ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status ErrorMessage )
|
||||
WITH approvals_for_update
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
|
||||
LOOP AT update_reported-changeapproval ASSIGNING FIELD-SYMBOL(<update_message>).
|
||||
<update_message>-%op-%action-retrySync = if_abap_behv=>mk-on.
|
||||
ENDLOOP.
|
||||
reported = CORRESPONDING #( DEEP APPENDING BASE ( reported ) update_reported ).
|
||||
|
||||
LOOP AT update_failed-changeapproval INTO DATA(update_failure).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%fail-cause = COND #( WHEN update_failure-%fail-cause = if_abap_behv=>cause-locked
|
||||
THEN if_abap_behv=>cause-unspecific
|
||||
ELSE update_failure-%fail-cause )
|
||||
%op-%action-retrySync = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
IF update_failure-%fail-cause <> if_abap_behv=>cause-not_found
|
||||
AND NOT line_exists( update_reported-changeapproval[ ID = update_failure-ID ] ).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%op-%action-retrySync = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'The retry could not be recorded' ) )
|
||||
TO reported-changeapproval.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDIF.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
LOOP AT updated INTO DATA(row).
|
||||
IF NOT line_exists( failed-changeapproval[ ID = row-ID ] ).
|
||||
APPEND VALUE #( %tky = row-%tky %param = row ) TO result.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD markExecuting.
|
||||
" APPROVED -> EXECUTING (worker claims the record; the UI never offers Approve on an executing record, PRD RAP-6).
|
||||
" The only place that writes EXECUTING.
|
||||
DATA approvals_for_update TYPE TABLE FOR UPDATE zr_changeapproval.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals).
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-not_found
|
||||
%op-%action-markExecuting = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-approved.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific
|
||||
%op-%action-markExecuting = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%op-%action-markExecuting = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only APPROVED records can start executing (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
Status = status-executing ) TO approvals_for_update.
|
||||
ENDLOOP.
|
||||
|
||||
IF approvals_for_update IS NOT INITIAL.
|
||||
MODIFY ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status )
|
||||
WITH approvals_for_update
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
|
||||
LOOP AT update_reported-changeapproval ASSIGNING FIELD-SYMBOL(<update_message>).
|
||||
<update_message>-%op-%action-markExecuting = if_abap_behv=>mk-on.
|
||||
ENDLOOP.
|
||||
reported = CORRESPONDING #( DEEP APPENDING BASE ( reported ) update_reported ).
|
||||
|
||||
LOOP AT update_failed-changeapproval INTO DATA(update_failure).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%fail-cause = COND #( WHEN update_failure-%fail-cause = if_abap_behv=>cause-locked
|
||||
THEN if_abap_behv=>cause-unspecific
|
||||
ELSE update_failure-%fail-cause )
|
||||
%op-%action-markExecuting = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
IF update_failure-%fail-cause <> if_abap_behv=>cause-not_found
|
||||
AND NOT line_exists( update_reported-changeapproval[ ID = update_failure-ID ] ).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%op-%action-markExecuting = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'The execution start could not be recorded' ) )
|
||||
TO reported-changeapproval.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDIF.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
LOOP AT updated INTO DATA(row).
|
||||
IF NOT line_exists( failed-changeapproval[ ID = row-ID ] ).
|
||||
APPEND VALUE #( %tky = row-%tky %param = row ) TO result.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD markSynced.
|
||||
" EXECUTING -> SYNCED (terminal success); SAP is the ledger, the change number is the receipt (ARN-006)
|
||||
DATA approvals_for_update TYPE TABLE FOR UPDATE zr_changeapproval.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals).
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-not_found
|
||||
%op-%action-markSynced = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-executing.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific
|
||||
%op-%action-markSynced = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%op-%action-markSynced = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only EXECUTING records can be marked synced (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF key-%param-SapChangeNumber IS INITIAL.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific
|
||||
%op-%action-markSynced = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%op-%action-markSynced = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'The SAP change number is required to mark a record synced' ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
Status = status-synced
|
||||
SapChangeNumber = key-%param-SapChangeNumber
|
||||
ErrorMessage = '' ) TO approvals_for_update.
|
||||
ENDLOOP.
|
||||
|
||||
IF approvals_for_update IS NOT INITIAL.
|
||||
MODIFY ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status SapChangeNumber ErrorMessage )
|
||||
WITH approvals_for_update
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
|
||||
LOOP AT update_reported-changeapproval ASSIGNING FIELD-SYMBOL(<update_message>).
|
||||
<update_message>-%op-%action-markSynced = if_abap_behv=>mk-on.
|
||||
ENDLOOP.
|
||||
reported = CORRESPONDING #( DEEP APPENDING BASE ( reported ) update_reported ).
|
||||
|
||||
LOOP AT update_failed-changeapproval INTO DATA(update_failure).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%fail-cause = COND #( WHEN update_failure-%fail-cause = if_abap_behv=>cause-locked
|
||||
THEN if_abap_behv=>cause-unspecific
|
||||
ELSE update_failure-%fail-cause )
|
||||
%op-%action-markSynced = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
IF update_failure-%fail-cause <> if_abap_behv=>cause-not_found
|
||||
AND NOT line_exists( update_reported-changeapproval[ ID = update_failure-ID ] ).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%op-%action-markSynced = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'The sync result could not be recorded' ) )
|
||||
TO reported-changeapproval.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDIF.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
LOOP AT updated INTO DATA(row).
|
||||
IF NOT line_exists( failed-changeapproval[ ID = row-ID ] ).
|
||||
APPEND VALUE #( %tky = row-%tky %param = row ) TO result.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD markFailed.
|
||||
" EXECUTING -> FAILED with the error text; distinct from REJECTED (predecessor defect, ARN-002)
|
||||
DATA approvals_for_update TYPE TABLE FOR UPDATE zr_changeapproval.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals).
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-not_found
|
||||
%op-%action-markFailed = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-executing.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific
|
||||
%op-%action-markFailed = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%op-%action-markFailed = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only EXECUTING records can be marked failed (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF key-%param-ErrorMessage IS INITIAL.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific
|
||||
%op-%action-markFailed = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
%op-%action-markFailed = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'An error message is required to mark a record failed' ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
APPEND VALUE #( %tky = key-%tky
|
||||
Status = status-failed
|
||||
ErrorMessage = key-%param-ErrorMessage ) TO approvals_for_update.
|
||||
ENDLOOP.
|
||||
|
||||
IF approvals_for_update IS NOT INITIAL.
|
||||
MODIFY ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status ErrorMessage )
|
||||
WITH approvals_for_update
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
|
||||
LOOP AT update_reported-changeapproval ASSIGNING FIELD-SYMBOL(<update_message>).
|
||||
<update_message>-%op-%action-markFailed = if_abap_behv=>mk-on.
|
||||
ENDLOOP.
|
||||
reported = CORRESPONDING #( DEEP APPENDING BASE ( reported ) update_reported ).
|
||||
|
||||
LOOP AT update_failed-changeapproval INTO DATA(update_failure).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%fail-cause = COND #( WHEN update_failure-%fail-cause = if_abap_behv=>cause-locked
|
||||
THEN if_abap_behv=>cause-unspecific
|
||||
ELSE update_failure-%fail-cause )
|
||||
%op-%action-markFailed = if_abap_behv=>mk-on ) TO failed-changeapproval.
|
||||
IF update_failure-%fail-cause <> if_abap_behv=>cause-not_found
|
||||
AND NOT line_exists( update_reported-changeapproval[ ID = update_failure-ID ] ).
|
||||
APPEND VALUE #( %tky = update_failure-%tky
|
||||
%op-%action-markFailed = if_abap_behv=>mk-on
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'The failure could not be recorded' ) )
|
||||
TO reported-changeapproval.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDIF.
|
||||
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
LOOP AT updated INTO DATA(row).
|
||||
IF NOT line_exists( failed-changeapproval[ ID = row-ID ] ).
|
||||
APPEND VALUE #( %tky = row-%tky %param = row ) TO result.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD setInitialStatus.
|
||||
" Every created record starts PENDING with the requester audit fields (ARN-002)
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals).
|
||||
|
||||
DELETE approvals WHERE Status IS NOT INITIAL.
|
||||
IF approvals IS INITIAL.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
MODIFY ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status RequestedBy RequestedOn )
|
||||
WITH VALUE #( FOR approval IN approvals
|
||||
( %tky = approval-%tky
|
||||
Status = status-pending
|
||||
RequestedBy = cl_abap_context_info=>get_user_technical_name( )
|
||||
RequestedOn = utclong_current( ) ) )
|
||||
REPORTED DATA(update_reported).
|
||||
|
||||
reported = CORRESPONDING #( DEEP update_reported ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD checkDuplicate.
|
||||
" Semantic key ItemNumber + ChangeType + ArenaEcoId (PRD RAP-8) must be unique among records that are not REJECTED.
|
||||
" Checks (1) duplicates among the instances of this request and (2) persisted records, read through the CDS view
|
||||
" with privileged access (released access only; the view is access-controlled, see header sources).
|
||||
READ ENTITIES OF zr_changeapproval IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( ItemNumber ChangeType ArenaEcoId )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals).
|
||||
|
||||
LOOP AT approvals INTO DATA(approval).
|
||||
" Invalidate a state message left by an earlier run of this validation for the instance
|
||||
APPEND VALUE #( %tky = approval-%tky
|
||||
%state_area = state_area_duplicate ) TO reported-changeapproval.
|
||||
|
||||
DATA(same_key_in_request) = REDUCE i( INIT count = 0
|
||||
FOR other IN approvals
|
||||
WHERE ( ItemNumber = approval-ItemNumber
|
||||
AND ChangeType = approval-ChangeType
|
||||
AND ArenaEcoId = approval-ArenaEcoId )
|
||||
NEXT count = count + 1 ).
|
||||
|
||||
DATA(is_duplicate) = xsdbool( same_key_in_request > 1 ).
|
||||
|
||||
IF is_duplicate = abap_false.
|
||||
SELECT SINGLE FROM zr_changeapproval
|
||||
FIELDS ID
|
||||
WHERE ItemNumber = @approval-ItemNumber
|
||||
AND ChangeType = @approval-ChangeType
|
||||
AND ArenaEcoId = @approval-ArenaEcoId
|
||||
AND Status <> @status-rejected
|
||||
AND ID <> @approval-ID
|
||||
INTO @DATA(existing_id)
|
||||
OPTIONS PRIVILEGED ACCESS.
|
||||
is_duplicate = xsdbool( sy-subrc = 0 ).
|
||||
ENDIF.
|
||||
|
||||
IF is_duplicate = abap_true.
|
||||
APPEND VALUE #( %tky = approval-%tky
|
||||
%fail-cause = if_abap_behv=>cause-unspecific ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = approval-%tky
|
||||
%state_area = state_area_duplicate
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |A change approval for item { approval-ItemNumber }, | &&
|
||||
|change type { approval-ChangeType } and ECO { approval-ArenaEcoId } | &&
|
||||
|already exists and is not rejected| )
|
||||
%element-ItemNumber = if_abap_behv=>mk-on
|
||||
%element-ChangeType = if_abap_behv=>mk-on
|
||||
%element-ArenaEcoId = if_abap_behv=>mk-on ) TO reported-changeapproval.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
@@ -0,0 +1,26 @@
|
||||
// TARGET OBJECT : behavior definition ZC_CHANGEAPPROVAL (UI projection BDEF) - README step U9, UI leg
|
||||
// abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Behavior%20Definitions/ZC_CHANGEAPPROVAL/zc_changeapproval.bdef.json
|
||||
// ACTION : create via ADT MCP (objectType BDEF/BDO, implementationType Projection, README U9) once the view
|
||||
// ZC_CHANGEAPPROVAL is active, replace entire content, save, then activate (BDEF ZR_CHANGEAPPROVAL and
|
||||
// class ZBP_R_CHANGEAPPROVAL must be active).
|
||||
// No behavior pool is created for this projection: a projection BDEF needs one only when it defines
|
||||
// new actions/functions, and this one reuses everything
|
||||
// [source: abap-docs /abap-docs-cloud/ABENBDL_BDEF_PROJECTION_HEADER, verified 2026-09-15].
|
||||
// Contract : approve / reject / retrySync are the bound-action names the Fiori app calls (exact case).
|
||||
// Sources (verified 2026-09-15): use action, use etag - no automatic inheritance - only what is listed is exposed,
|
||||
// which is how create/update/delete and the worker actions are kept out of the UI service (PRD RAP-2)
|
||||
// [abap-docs /abap-docs-cloud/ABENBDL_USE_PROJECTION]. Feature control of reused actions is passed on automatically (same source).
|
||||
// `use etag` is an entity behavior characteristic: it sits between `define behavior for ... alias ...` and `{`,
|
||||
// without a semicolon [source: abap-docs /abap-docs-cloud/ABENBDL_CHARACTER_PROJECTION and
|
||||
// /abap-docs-cloud/ABENBDL_DEFINE_BEH_PROJECTION, verified 2026-09-16]; it must be stated per entity or optimistic
|
||||
// concurrency control is lost [source: abap-docs /abap-docs-cloud/ABENBDL_USE_PROJECTION, verified 2026-09-16].
|
||||
projection;
|
||||
strict ( 2 );
|
||||
|
||||
define behavior for ZC_CHANGEAPPROVAL alias ChangeApproval
|
||||
use etag
|
||||
{
|
||||
use action approve;
|
||||
use action reject;
|
||||
use action retrySync;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/* TARGET OBJECT : access control ZC_CHANGEAPPROVAL - README step U11, UI leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Access%20Controls/ZC_CHANGEAPPROVAL/zc_changeapproval.dcls.acds
|
||||
ACTION : create empty via ADT MCP (objectType DCLS/DL, README U11), replace entire content, save, then activate
|
||||
(after view ZC_CHANGEAPPROVAL and access control ZR_CHANGEAPPROVAL).
|
||||
A transactional query needs its own DCL, inheriting the base view's conditions - there is no implicit inheritance
|
||||
[source: abap-docs /abap-platform-rap-opensap/week2/unit7#step-5-create-cds-access-control-for-travel-bo-projection-view-and-check-the-result;
|
||||
/abap-docs-cloud/ABENCDS_DEFINE_VIEW_AS_PROJECTION (access control must be symmetric), verified 2026-09-15]. */
|
||||
@EndUserText.label: 'Access control for ZC_CHANGEAPPROVAL'
|
||||
@MappingRole: true
|
||||
define role ZC_CHANGEAPPROVAL {
|
||||
grant select on ZC_CHANGEAPPROVAL
|
||||
where inheriting conditions from entity ZR_CHANGEAPPROVAL;
|
||||
}
|
||||
+9
-5
@@ -1,6 +1,10 @@
|
||||
/* TARGET OBJECT : data definition ZZC_CHANGEAPPROVAL000 (UI projection, generated 2026-09-15)
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZZC_CHANGEAPPROVAL000/zzc_changeapproval000.ddls.acds
|
||||
ACTION : replace entire content, then activate (after ZZR_CHANGEAPPROVAL000).
|
||||
/* TARGET OBJECT : data definition ZC_CHANGEAPPROVAL (UI projection) - README step U8, UI leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZC_CHANGEAPPROVAL/zc_changeapproval.ddls.acds
|
||||
ACTION : create empty via ADT MCP (objectType DDLS/DF, README U8), replace entire content, save, then activate
|
||||
(after ZR_CHANGEAPPROVAL).
|
||||
Contract : element names are the OData property names of entity type ChangeApproval_Type in the Fiori app
|
||||
(app/webapp/localService/mainService/metadata.xml, 17 properties, exact case). StatusText (RAP-3 text
|
||||
element) and LocalLastChangedAt (etag) are in addition to the app's mock - see README "App contract check".
|
||||
Notes: provider contract transactional_query [source: abap-docs /abap-docs-cloud/ABENCDS_DEFINE_VIEW_AS_PROJECTION, verified 2026-09-15];
|
||||
@ObjectModel.semanticKey (PRD RAP-8) [source: abap-docs /abap-fiori-showcase/05_object_page_header#handling-semantic-key-fields, verified 2026-09-15];
|
||||
@Metadata.allowExtensions is required for the metadata extension [source: abap-docs /abap-docs-cloud/ABENCDS_F1_ANNOTATE_VIEW, verified 2026-09-15]. */
|
||||
@@ -8,9 +12,9 @@
|
||||
@AccessControl.authorizationCheck: #CHECK
|
||||
@Metadata.allowExtensions: true
|
||||
@ObjectModel.semanticKey: ['ItemNumber', 'ChangeType', 'ArenaEcoId']
|
||||
define root view entity ZZC_CHANGEAPPROVAL000
|
||||
define root view entity ZC_CHANGEAPPROVAL
|
||||
provider contract transactional_query
|
||||
as projection on ZZR_CHANGEAPPROVAL000
|
||||
as projection on ZR_CHANGEAPPROVAL
|
||||
{
|
||||
key ID,
|
||||
ItemNumber,
|
||||
+5
-4
@@ -1,6 +1,7 @@
|
||||
/* TARGET OBJECT : metadata extension ZZC_CHANGEAPPROVAL000 (generated 2026-09-15)
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Metadata%20Extensions/ZZC_CHANGEAPPROVAL000/zzc_changeapproval000.ddlx.acds
|
||||
ACTION : replace entire content, then activate (after ZZC_CHANGEAPPROVAL000 view).
|
||||
/* TARGET OBJECT : metadata extension ZC_CHANGEAPPROVAL - README step U12, UI leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Metadata%20Extensions/ZC_CHANGEAPPROVAL/zc_changeapproval.ddlx.acds
|
||||
ACTION : create empty via ADT MCP (objectType DDLX/EX, README U12), replace entire content, save, then activate
|
||||
(after ZC_CHANGEAPPROVAL view).
|
||||
Mirrors app/webapp/annotations/annotation.xml (line items, filter bar, header, facets, actions); the app's local
|
||||
annotations still apply on top at runtime. Labels are literals here; the app carries the i18n texts.
|
||||
Sources (all verified 2026-09-15, abap-docs /abap-fiori-showcase):
|
||||
@@ -31,7 +32,7 @@
|
||||
visualizations: [ { type: #AS_LINEITEM } ]
|
||||
} ]
|
||||
}
|
||||
annotate entity ZZC_CHANGEAPPROVAL000 with
|
||||
annotate entity ZC_CHANGEAPPROVAL with
|
||||
{
|
||||
@UI.facet: [
|
||||
{ id: 'StatusPoint', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'StatusPoint' },
|
||||
@@ -1,16 +1,20 @@
|
||||
// TARGET OBJECT : behavior definition ZC_CHANGEAPPROVAL_A2X (A2X projection BDEF) - DOES NOT EXIST YET.
|
||||
// The ADT MCP refused to create it while ZC_CHANGEAPPROVAL_A2X (DDLS) had no active source
|
||||
// ("The referenced STOB object ZC_CHANGEAPPROVAL_A2X does not exist", 2026-09-15).
|
||||
// Create it after the projection view is active: ADT > New Behavior Definition on ZC_CHANGEAPPROVAL_A2X,
|
||||
// implementation type Projection (or re-run abap_creation-create_object BDEF/BDO, see README), paste, activate.
|
||||
// Sources: as ZZC_CHANGEAPPROVAL000. use create lets the worker stage records (ARN-010: the staged payload is what
|
||||
// gets executed); the worker never sees approve/reject/retrySync (PRD RAP-6).
|
||||
// TARGET OBJECT : behavior definition ZC_CHANGEAPPROVAL_A2X (A2X projection BDEF) - README step W3, worker leg
|
||||
// abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Behavior%20Definitions/ZC_CHANGEAPPROVAL_A2X/zc_changeapproval_a2x.bdef.abdl
|
||||
// ACTION : create via ADT MCP (objectType BDEF/BDO, implementationType Projection, README W3) only once the view
|
||||
// ZC_CHANGEAPPROVAL_A2X is active - the MCP validates the referenced entity's active version (live
|
||||
// 2026-09-15: "The referenced STOB object ZC_CHANGEAPPROVAL_A2X does not exist" while the view had no
|
||||
// active source). Replace entire content, save, then activate.
|
||||
// Sources: as ZC_CHANGEAPPROVAL (incl. `use etag` as an entity behavior characteristic in the header, not in the body).
|
||||
// use create lets the worker stage records (ARN-010: the staged payload is what gets executed); the worker never
|
||||
// sees approve/reject/retrySync (PRD RAP-6). The base BDEF's validation checkDuplicate runs on every create; it is
|
||||
// not something a projection lists (validations are not in the `use` list [source: abap-docs
|
||||
// /abap-docs-cloud/ABENBDL_USE_PROJECTION, verified 2026-09-16]).
|
||||
projection;
|
||||
strict ( 2 );
|
||||
|
||||
define behavior for ZC_CHANGEAPPROVAL_A2X alias ChangeApproval
|
||||
use etag
|
||||
{
|
||||
use etag;
|
||||
use create;
|
||||
|
||||
use action markExecuting;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/* TARGET OBJECT : access control ZC_CHANGEAPPROVAL_A2X (created empty via ADT MCP 2026-09-15)
|
||||
/* TARGET OBJECT : access control ZC_CHANGEAPPROVAL_A2X - README step W2, worker leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Access%20Controls/ZC_CHANGEAPPROVAL_A2X/zc_changeapproval_a2x.dcls.acds
|
||||
ACTION : replace entire content, then activate (after ZC_CHANGEAPPROVAL_A2X view and ZZR_CHANGEAPPROVAL000 DCL).
|
||||
Sources: as ZZC_CHANGEAPPROVAL000 DCL. */
|
||||
ACTION : create empty via ADT MCP (objectType DCLS/DL, README W2), replace entire content, save, then activate
|
||||
(after ZC_CHANGEAPPROVAL_A2X view and ZR_CHANGEAPPROVAL DCL).
|
||||
Sources: as ZC_CHANGEAPPROVAL DCL. */
|
||||
@EndUserText.label: 'Access control for ZC_CHANGEAPPROVAL_A2X'
|
||||
@MappingRole: true
|
||||
define role ZC_CHANGEAPPROVAL_A2X {
|
||||
grant select on ZC_CHANGEAPPROVAL_A2X
|
||||
where inheriting conditions from entity ZZR_CHANGEAPPROVAL000;
|
||||
where inheriting conditions from entity ZR_CHANGEAPPROVAL;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
/* TARGET OBJECT : data definition ZC_CHANGEAPPROVAL_A2X (A2X projection for the worker; created empty via ADT MCP 2026-09-15)
|
||||
/* TARGET OBJECT : data definition ZC_CHANGEAPPROVAL_A2X (A2X projection for the worker) - README step W1, worker leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZC_CHANGEAPPROVAL_A2X/zc_changeapproval_a2x.ddls.acds
|
||||
ACTION : replace entire content, then activate (after ZZR_CHANGEAPPROVAL000).
|
||||
ACTION : create empty via ADT MCP (objectType DDLS/DF, README W1), replace entire content, save, then activate
|
||||
(after the UI leg; needs ZR_CHANGEAPPROVAL).
|
||||
Notes: separate projection so the Web API exposes create + mark* while the UI projection stays read-only
|
||||
(PRD RAP-2 / RAP-6); same syntax sources as ZZC_CHANGEAPPROVAL000. No metadata extension here -
|
||||
(PRD RAP-2 / RAP-6); same syntax sources as ZC_CHANGEAPPROVAL. No metadata extension here -
|
||||
a Web API binding carries no UI annotations [source: sap-docs sap-help loio 248b36b7ebce4f7e8c7670c9371adee1, verified 2026-09-15]. */
|
||||
@EndUserText.label: 'Arena change approval - A2X projection (worker)'
|
||||
@AccessControl.authorizationCheck: #CHECK
|
||||
@ObjectModel.semanticKey: ['ItemNumber', 'ChangeType', 'ArenaEcoId']
|
||||
define root view entity ZC_CHANGEAPPROVAL_A2X
|
||||
provider contract transactional_query
|
||||
as projection on ZZR_CHANGEAPPROVAL000
|
||||
as projection on ZR_CHANGEAPPROVAL
|
||||
{
|
||||
key ID,
|
||||
ItemNumber,
|
||||
|
||||
+12
-5
@@ -1,17 +1,24 @@
|
||||
/* TARGET OBJECT : database table ZZCHNGPPROVAL000 (generated 2026-09-15 by x-ui-service)
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Dictionary/Database%20Tables/ZZCHNGPPROVAL000/zzchngpproval000.tabl.json
|
||||
ACTION : replace entire content, then activate.
|
||||
/* TARGET OBJECT : database table ZCHANGEAPPROVAL (persistence of the approval BO) - README step U1, UI leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Dictionary/Database%20Tables/ZCHANGEAPPROVAL/zchangeapproval.tabl.ddic
|
||||
(returned by create_object 2026-09-16; activation extension pending live proof - README activation table)
|
||||
ACTION : create empty via ADT MCP (objectType TABL/DT, README U1), then paste into the .tabl.ddic file, NEVER the
|
||||
.tabl.json file: in the VS Code ADT workspace zchangeapproval.tabl.json holds only header metadata
|
||||
(formatVersion, description, originalLanguage, abapLanguageVersion) - live observation 2026-09-16.
|
||||
Replace entire content of the .tabl.ddic file, save, then activate.
|
||||
A DDIC database table is edited as Dictionary DDL source code generated from, and saved back into, the
|
||||
table metadata [source: abap-docs /abap-docs-cloud/ABENDDIC_DEFINE_TABLE, verified 2026-09-16].
|
||||
Name : 15 characters; TABL/DT allows 16 [source: adt-mcp abap_creation-get_object_type_details on 0M7DEJI, verified 2026-09-16].
|
||||
Notes: sap_preview is abap.string(0) (RAP-7; char is capped at 1333 for table fields
|
||||
[source: abap-docs /abap-docs-cloud/ABENDDIC_BUILTIN_TYPES, verified 2026-09-15];
|
||||
abap.string(0) table-field syntax [source: abap-docs /abap-docs-cloud/ABENDDICDDL_DEFINE_TABLE_COMPS, verified 2026-09-15]).
|
||||
Timestamps are abap.utclong (UTCLONG built-in type, same source). Admin fields use the released
|
||||
ABP_* data elements and SYSUUID_X16 [source: sap-released-objects public_cloud level A, verified 2026-09-15]. */
|
||||
ABP_* data elements and SYSUUID_X16 [source: sap-released-objects public_cloud level A, verified 2026-09-16]. */
|
||||
@EndUserText.label : 'Arena change approval (staging + state machine)'
|
||||
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
|
||||
@AbapCatalog.tableCategory : #TRANSPARENT
|
||||
@AbapCatalog.deliveryClass : #A
|
||||
@AbapCatalog.dataMaintenance : #RESTRICTED
|
||||
define table zzchngpproval000 {
|
||||
define table zchangeapproval {
|
||||
key client : abap.clnt not null;
|
||||
key id : sysuuid_x16 not null;
|
||||
item_number : abap.char(18);
|
||||
@@ -1,6 +1,8 @@
|
||||
/* TARGET OBJECT : data definition ZD_CHANGEAPPROVAL_FAILEDP (abstract entity = parameter of action markFailed; created empty via ADT MCP 2026-09-15)
|
||||
/* TARGET OBJECT : data definition ZD_CHANGEAPPROVAL_FAILEDP (abstract entity = parameter of action markFailed) - README step U4, UI leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZD_CHANGEAPPROVAL_FAILEDP/zd_changeapproval_failedp.ddls.acds
|
||||
ACTION : replace entire content, then activate.
|
||||
ACTION : create empty via ADT MCP (objectType DDLS/DF, README U4), replace entire content, save, then activate.
|
||||
Leg : UI leg although only the worker calls markFailed - the base BDEF ZR_CHANGEAPPROVAL (U6) names this
|
||||
entity as the markFailed parameter, so it is ordered before that BDEF.
|
||||
Sources: as ZD_CHANGEAPPROVAL_REJECTP. */
|
||||
@EndUserText.label: 'Arena change approval: markFailed parameter'
|
||||
define abstract entity ZD_CHANGEAPPROVAL_FAILEDP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* TARGET OBJECT : data definition ZD_CHANGEAPPROVAL_REJECTP (abstract entity = parameter of action reject; created empty via ADT MCP 2026-09-15)
|
||||
/* TARGET OBJECT : data definition ZD_CHANGEAPPROVAL_REJECTP (abstract entity = parameter of action reject) - README step U2, UI leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZD_CHANGEAPPROVAL_REJECTP/zd_changeapproval_rejectp.ddls.acds
|
||||
ACTION : replace entire content, then activate.
|
||||
ACTION : create empty via ADT MCP (objectType DDLS/DF, README U2), replace entire content, save, then activate.
|
||||
Notes: action input parameters must be a CDS abstract entity or DDIC type; @EndUserText.label on the element
|
||||
gives the UI label [source: abap-docs /abap-docs-cloud/ABENBDL_ACTION_INPUT_PARAM, verified 2026-09-15];
|
||||
abstract-entity syntax [source: abap-docs /abap-docs-cloud/ABENBDL_ACTION2_ABEXA, verified 2026-09-15].
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* TARGET OBJECT : data definition ZD_CHANGEAPPROVAL_SYNCEDP (abstract entity = parameter of action markSynced; created empty via ADT MCP 2026-09-15)
|
||||
/* TARGET OBJECT : data definition ZD_CHANGEAPPROVAL_SYNCEDP (abstract entity = parameter of action markSynced) - README step U3, UI leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZD_CHANGEAPPROVAL_SYNCEDP/zd_changeapproval_syncedp.ddls.acds
|
||||
ACTION : replace entire content, then activate.
|
||||
ACTION : create empty via ADT MCP (objectType DDLS/DF, README U3), replace entire content, save, then activate.
|
||||
Leg : UI leg although only the worker calls markSynced - the base BDEF ZR_CHANGEAPPROVAL (U6) names this
|
||||
entity as the markSynced parameter, so it is ordered before that BDEF.
|
||||
Sources: as ZD_CHANGEAPPROVAL_REJECTP. */
|
||||
@EndUserText.label: 'Arena change approval: markSynced parameter'
|
||||
define abstract entity ZD_CHANGEAPPROVAL_SYNCEDP
|
||||
|
||||
+27
-9
@@ -1,6 +1,12 @@
|
||||
// TARGET OBJECT : behavior definition ZZR_CHANGEAPPROVAL000 (base BDEF, managed; generated 2026-09-15)
|
||||
// abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Behavior%20Definitions/ZZR_CHANGEAPPROVAL000/zzr_changeapproval000.bdef.json
|
||||
// ACTION : replace entire content, then activate (after the three ZD_* abstract entities and ZZR_CHANGEAPPROVAL000).
|
||||
// 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]
|
||||
@@ -11,16 +17,25 @@
|
||||
// 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]
|
||||
// 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 zzbp_r_changeapproval000 unique;
|
||||
managed implementation in class zbp_r_changeapproval unique;
|
||||
strict ( 2 );
|
||||
|
||||
define behavior for ZZR_CHANGEAPPROVAL000 alias ChangeApproval
|
||||
persistent table zzchngpproval000
|
||||
define behavior for ZR_CHANGEAPPROVAL alias ChangeApproval
|
||||
persistent table zchangeapproval
|
||||
lock master
|
||||
authorization master ( none )
|
||||
etag master LocalLastChangedAt
|
||||
@@ -36,7 +51,7 @@ etag master LocalLastChangedAt
|
||||
SapChangeNumber, ErrorMessage, RejectReason,
|
||||
CreatedBy, CreatedAt, LastChangedBy, LastChangedAt, LocalLastChangedAt;
|
||||
|
||||
// Business-user actions (UI projection): PENDING -> APPROVED | REJECTED, FAILED -> EXECUTING (PRD RAP-1/RAP-2)
|
||||
// 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;
|
||||
@@ -48,7 +63,10 @@ etag master LocalLastChangedAt
|
||||
|
||||
determination setInitialStatus on modify { create; }
|
||||
|
||||
mapping for zzchngpproval000
|
||||
// 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;
|
||||
+7
-6
@@ -1,12 +1,13 @@
|
||||
/* TARGET OBJECT : access control ZZR_CHANGEAPPROVAL000 (generated 2026-09-15)
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Access%20Controls/ZZR_CHANGEAPPROVAL000/zzr_changeapproval000.dcls.acds
|
||||
ACTION : replace entire content, then activate.
|
||||
/* TARGET OBJECT : access control ZR_CHANGEAPPROVAL - README step U10, UI leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Access%20Controls/ZR_CHANGEAPPROVAL/zr_changeapproval.dcls.acds
|
||||
ACTION : create empty via ADT MCP (objectType DCLS/DL, README U10), replace entire content, save, then activate
|
||||
(view ZR_CHANGEAPPROVAL must be active).
|
||||
Full access rule: read access is governed by the IAM app / business catalog (ADR-002); SAP delivers no full-access
|
||||
roles but customers may use them [source: abap-docs /abap-docs-cloud/ABENCDS_DCL_ROLE_GRANT_RULE, verified 2026-09-15].
|
||||
@MappingRole: true assigns the role to every user [source: abap-docs /abap-platform-rap-opensap/week2/unit7, verified 2026-09-15].
|
||||
Tighten later with a custom authorization object + pfcg_auth condition if per-user data restrictions are needed. */
|
||||
@EndUserText.label: 'Access control for ZZR_CHANGEAPPROVAL000'
|
||||
@EndUserText.label: 'Access control for ZR_CHANGEAPPROVAL'
|
||||
@MappingRole: true
|
||||
define role ZZR_CHANGEAPPROVAL000 {
|
||||
grant select on ZZR_CHANGEAPPROVAL000;
|
||||
define role ZR_CHANGEAPPROVAL {
|
||||
grant select on ZR_CHANGEAPPROVAL;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/* TARGET OBJECT : data definition ZR_CHANGEAPPROVAL (root view entity) - README step U5, UI leg
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZR_CHANGEAPPROVAL/zr_changeapproval.ddls.acds
|
||||
ACTION : create empty via ADT MCP (objectType DDLS/DF, README U5), replace entire content, save, then activate
|
||||
(table ZCHANGEAPPROVAL must be active first).
|
||||
Notes: StatusText / StatusCriticality / IsApprovable / IsRetriable are derived from Status with CASE
|
||||
expressions here, because a transactional_query projection list may only contain elements of the
|
||||
projected entity, path expressions, associations and virtual elements - no expressions
|
||||
[source: abap-docs /abap-docs-cloud/ABENCDS_DEFINE_VIEW_AS_PROJECTION, verified 2026-09-15].
|
||||
CASE syntax [source: abap-docs /abap-docs-cloud/ABENCDS_CASE_EXPRESSION_V2, verified 2026-09-15];
|
||||
cast of a case distinction to a data element (abap_boolean, released) [source: abap-docs /abap-docs-cloud/ABENCDS_CAST_EXPRESSION_V2, verified 2026-09-16].
|
||||
@ObjectModel.text.element [source: abap-docs /abap-fiori-showcase/06_object_page_content#displaying-text-instead-of-id, verified 2026-09-15].
|
||||
@Semantics admin-field annotations [source: abap-docs /abap-platform-rap-opensap/week2/unit3#step-1-create-the-interface-cds-view-for-the-travel-entity, verified 2026-09-15].
|
||||
Criticality values 2/2/5/3/1/1 per PRD RAP-1.
|
||||
ABAP_BOOLEAN is released [source: sap-released-objects DTEL ABAP_BOOLEAN public_cloud level A, verified 2026-09-16].
|
||||
Result types of the CASE expressions:
|
||||
- A CASE result gets the maximum technical data type of all THEN and ELSE branches, and keeps a data element
|
||||
only if every branch with that type carries the same one [source: abap-docs /abap-docs-cloud/ABENCDS_CASE_EXPRESSION_V2,
|
||||
verified 2026-09-16]. StatusText is therefore CHAR as long as its longest literal (29), not Status's CHAR(10).
|
||||
- IsApprovable / IsRetriable cast the WHOLE case distinction to abap_boolean once. Casting inside the branches does
|
||||
not work: a cast to a data element passes on its semantics, "An exception to this is the use of the CAST expression
|
||||
within a case distinction" [source: abap-docs /abap-docs-cloud/ABENCDS_CAST_EXPRESSION_V2, verified 2026-09-16].
|
||||
- The branches use typed literals abap.char'X' / abap.char' ': length is "derived from the literal value" and "the type
|
||||
length includes the trimmed trailing blanks", so both are CHAR(1) and the CASE result is CHAR(1) [source: abap-docs
|
||||
/abap-docs-cloud/ABENCDS_TYPED_LITERAL_V2, verified 2026-09-16]. (Untyped 'X' would not prove it: its DB length is only
|
||||
"at least as large as" the literal [source: abap-docs /abap-docs-cloud/ABENCDS_UNTYPED_LITERAL_V2, verified 2026-09-16].)
|
||||
- PRESERVING TYPE needs the operand's built-in type and length to match the data element exactly [source: abap-docs
|
||||
/abap-docs-cloud/ABENCDS_CAST_EXPRESSION_V2, verified 2026-09-16]. ABAP_BOOLEAN is "of data type CHAR of length 1"
|
||||
[source: abap-docs /abap-docs-standard/ABENDATAOBJECTS_TRUE_VALUE_GUIDL, verified 2026-09-16], so the types match.
|
||||
If activation rejects the cast anyway, delete
|
||||
"preserving type": a plain cast still inherits the data element's semantics, and a same-type warning "can be ignored"
|
||||
[source: abap-docs /abap-docs-cloud/ABENCDS_CAST_EXPRESSION_V2, verified 2026-09-16].
|
||||
- An untyped integer literal is INT1, INT2, INT4 or INT8 depending on its value [source: abap-docs
|
||||
/abap-docs-cloud/ABENCDS_UNTYPED_LITERAL_V2, verified 2026-09-16], so StatusCriticality (0..5) is expected INT1.
|
||||
Open (UNVERIFIED 2026-09-16 - no doc found): the OData EDM types the UI binding emits for INT1 (app expects
|
||||
Edm.Byte), ABAP_BOOLEAN (app expects Edm.Boolean) and UTCLONG (app expects Edm.DateTimeOffset Precision 7).
|
||||
Read them from the live $metadata after publishing (README step U15); do not change this source without a cited rule. */
|
||||
@AccessControl.authorizationCheck: #CHECK
|
||||
@EndUserText.label: 'Arena change approval'
|
||||
define root view entity ZR_CHANGEAPPROVAL
|
||||
as select from zchangeapproval
|
||||
{
|
||||
key id as ID,
|
||||
item_number as ItemNumber,
|
||||
item_name as ItemName,
|
||||
change_type as ChangeType,
|
||||
arena_eco_id as ArenaEcoId,
|
||||
|
||||
@ObjectModel.text.element: ['StatusText']
|
||||
status as Status,
|
||||
|
||||
case status
|
||||
when 'PENDING' then 'Pending approval'
|
||||
when 'APPROVED' then 'Approved - awaiting execution'
|
||||
when 'EXECUTING' then 'Executing in SAP'
|
||||
when 'SYNCED' then 'Synced to SAP'
|
||||
when 'REJECTED' then 'Rejected'
|
||||
when 'FAILED' then 'Execution failed'
|
||||
else status
|
||||
end as StatusText,
|
||||
|
||||
case status
|
||||
when 'PENDING' then 2
|
||||
when 'APPROVED' then 2
|
||||
when 'EXECUTING' then 5
|
||||
when 'SYNCED' then 3
|
||||
when 'REJECTED' then 1
|
||||
when 'FAILED' then 1
|
||||
else 0
|
||||
end as StatusCriticality,
|
||||
|
||||
requested_by as RequestedBy,
|
||||
requested_on as RequestedOn,
|
||||
decided_by as DecidedBy,
|
||||
decided_on as DecidedOn,
|
||||
sap_change_number as SapChangeNumber,
|
||||
error_message as ErrorMessage,
|
||||
reject_reason as RejectReason,
|
||||
sap_preview as SapPreview,
|
||||
|
||||
cast( case status
|
||||
when 'PENDING' then abap.char'X'
|
||||
else abap.char' '
|
||||
end as abap_boolean preserving type ) as IsApprovable,
|
||||
|
||||
cast( case status
|
||||
when 'FAILED' then abap.char'X'
|
||||
else abap.char' '
|
||||
end as abap_boolean preserving type ) as IsRetriable,
|
||||
|
||||
@Semantics.user.createdBy: true
|
||||
created_by as CreatedBy,
|
||||
@Semantics.systemDateTime.createdAt: true
|
||||
created_at as CreatedAt,
|
||||
@Semantics.user.lastChangedBy: true
|
||||
last_changed_by as LastChangedBy,
|
||||
@Semantics.systemDateTime.lastChangedAt: true
|
||||
last_changed_at as LastChangedAt,
|
||||
@Semantics.systemDateTime.localInstanceLastChangedAt: true
|
||||
local_last_changed_at as LocalLastChangedAt
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
@EndUserText.label: 'Arena change approval - UI service'
|
||||
define service ZUI_ARENA_CHANGE_APPROVAL
|
||||
provider contracts odata_v4_ui
|
||||
{
|
||||
expose ZC_CHANGEAPPROVAL as ChangeApproval;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
" TARGET OBJECT : class ZZBP_R_CHANGEAPPROVAL000 - GLOBAL CLASS include (behavior pool; generated 2026-09-15)
|
||||
" abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Source%20Code%20Library/Classes/ZZBP_R_CHANGEAPPROVAL000/zzbp_r_changeapproval000.clas.abap
|
||||
" ACTION : replace entire content of the global class; the handlers go into "Local Types" (locals_imp file).
|
||||
" Source: FOR BEHAVIOR OF defines the ABAP behavior pool; the global class implements nothing itself
|
||||
" [source: abap-docs /abap-docs-cloud/ABAPCLASS_FOR_BEHAVIOR_OF, ABENABAP_BEHAVIOR_POOLS, verified 2026-09-15].
|
||||
CLASS zzbp_r_changeapproval000 DEFINITION
|
||||
PUBLIC
|
||||
ABSTRACT
|
||||
FINAL
|
||||
FOR BEHAVIOR OF zzr_changeapproval000.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS zzbp_r_changeapproval000 IMPLEMENTATION.
|
||||
ENDCLASS.
|
||||
@@ -1,426 +0,0 @@
|
||||
" TARGET OBJECT : class ZZBP_R_CHANGEAPPROVAL000 - LOCAL TYPES include (Local Types tab in ADT)
|
||||
" abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Source%20Code%20Library/Classes/ZZBP_R_CHANGEAPPROVAL000/zzbp_r_changeapproval000.clas.locals_imp.abap
|
||||
" ACTION : replace entire content, then activate the class (BDEF ZZR_CHANGEAPPROVAL000 must be active first).
|
||||
"
|
||||
" Sources (all verified 2026-09-15):
|
||||
" handler class inherits from CL_ABAP_BEHAVIOR_HANDLER (released) [sap-released-objects public_cloud A]
|
||||
" FOR INSTANCE FEATURES signature + result via %tky / %features-%action-<name> / if_abap_behv=>fc-o-enabled|disabled
|
||||
" [abap-docs /abap-docs-cloud/ABAPHANDLER_METH_FEATURES, ABAPDERIVED_TYPES_FEATURES, ABENBDL_ACTIONS_FC]
|
||||
" FOR MODIFY ... FOR ACTION with RESULT; %param carries the action parameter (keys) and the result ($self)
|
||||
" [abap-docs /abap-docs-cloud/ABENBDL_ACTION2_ABEXA, ABAPDERIVED_TYPES_PARAM]
|
||||
" READ ENTITIES ... IN LOCAL MODE ... FIELDS ( ) WITH CORRESPONDING #( keys ) RESULT ... FAILED failed
|
||||
" [abap-docs /abap-docs-cloud/ABENBDL_ACTIONS_FC example]
|
||||
" MODIFY ENTITIES ... IN LOCAL MODE (skips feature control and authorization) with UPDATE FIELDS
|
||||
" [abap-docs /abap-docs-cloud/ABAPMODIFY_ENTITY_ENTITIES, ABAPMODIFY_ENTITY_ENTITIES_OP, ABENBDL_AUTHORIZATION]
|
||||
" %msg = new_message_with_text( ... ) into reported [abap-docs /abap-docs-cloud/ABENBDL_ACTIONS_FC example]
|
||||
" FOR DETERMINE ON MODIFY signature [abap-docs /abap-docs-cloud/ABAPHANDLER_METH_DET]
|
||||
" utclong_current( ) [abap-docs /abap-docs-cloud/ABENUTCLONG_CURRENT]
|
||||
" cl_abap_context_info=>get_user_technical_name( ) (released class) [sap-docs sap-help loio 7be24435b3e24540a9edad9a2535175a;
|
||||
" sap-released-objects CL_ABAP_CONTEXT_INFO public_cloud A]
|
||||
" Design notes:
|
||||
" - Status transitions are enforced twice: get_instance_features disables the action (UI greys it out / EML fails
|
||||
" with an entry in failed [ABENBDL_ACTIONS_FC]) AND each action re-checks the current status so an EML caller
|
||||
" IN LOCAL MODE cannot skip the state machine.
|
||||
" - The six actions repeat the same read/check/update/read pattern on purpose: each action has its own derived
|
||||
" key type, so a generic helper would need additional derived-type plumbing that is not worth it for six methods.
|
||||
" - RequestedBy is the technical user of the creator (for the A2X flow: the worker's communication user).
|
||||
" If the Arena requester should be shown instead, make RequestedBy mandatory:create in the BDEF and drop it
|
||||
" from the determination.
|
||||
|
||||
CLASS lhc_changeapproval DEFINITION INHERITING FROM cl_abap_behavior_handler.
|
||||
PRIVATE SECTION.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF status,
|
||||
pending TYPE zzchngpproval000-status VALUE 'PENDING',
|
||||
approved TYPE zzchngpproval000-status VALUE 'APPROVED',
|
||||
executing TYPE zzchngpproval000-status VALUE 'EXECUTING',
|
||||
synced TYPE zzchngpproval000-status VALUE 'SYNCED',
|
||||
rejected TYPE zzchngpproval000-status VALUE 'REJECTED',
|
||||
failed TYPE zzchngpproval000-status VALUE 'FAILED',
|
||||
END OF status.
|
||||
|
||||
METHODS get_instance_features FOR INSTANCE FEATURES
|
||||
IMPORTING keys REQUEST requested_features FOR ChangeApproval RESULT result.
|
||||
|
||||
METHODS approve FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~approve RESULT result.
|
||||
|
||||
METHODS reject FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~reject RESULT result.
|
||||
|
||||
METHODS retrySync FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~retrySync RESULT result.
|
||||
|
||||
METHODS markExecuting FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~markExecuting RESULT result.
|
||||
|
||||
METHODS markSynced FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~markSynced RESULT result.
|
||||
|
||||
METHODS markFailed FOR MODIFY
|
||||
IMPORTING keys FOR ACTION ChangeApproval~markFailed RESULT result.
|
||||
|
||||
METHODS setInitialStatus FOR DETERMINE ON MODIFY
|
||||
IMPORTING keys FOR ChangeApproval~setInitialStatus.
|
||||
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS lhc_changeapproval IMPLEMENTATION.
|
||||
|
||||
METHOD get_instance_features.
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals)
|
||||
FAILED failed.
|
||||
|
||||
result = VALUE #( FOR approval IN approvals
|
||||
( %tky = approval-%tky
|
||||
%features-%action-approve = COND #( WHEN approval-Status = status-pending
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-reject = COND #( WHEN approval-Status = status-pending
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-retrySync = COND #( WHEN approval-Status = status-failed
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-markExecuting = COND #( WHEN approval-Status = status-approved
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-markSynced = COND #( WHEN approval-Status = status-executing
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled )
|
||||
%features-%action-markFailed = COND #( WHEN approval-Status = status-executing
|
||||
THEN if_abap_behv=>fc-o-enabled
|
||||
ELSE if_abap_behv=>fc-o-disabled ) ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD approve.
|
||||
" PENDING -> APPROVED; records the decision, never writes SapChangeNumber (PRD RAP-1)
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals)
|
||||
FAILED failed.
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-pending.
|
||||
APPEND VALUE #( %tky = <approval>-%tky ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = <approval>-%tky
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only PENDING records can be approved (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
MODIFY ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status DecidedBy DecidedOn )
|
||||
WITH VALUE #( ( %tky = <approval>-%tky
|
||||
Status = status-approved
|
||||
DecidedBy = cl_abap_context_info=>get_user_technical_name( )
|
||||
DecidedOn = utclong_current( ) ) )
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
ENDLOOP.
|
||||
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
result = VALUE #( FOR row IN updated ( %tky = row-%tky %param = row ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD reject.
|
||||
" PENDING -> REJECTED with a mandatory reason (PRD RAP-2); REJECTED is terminal
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals)
|
||||
FAILED failed.
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-pending.
|
||||
APPEND VALUE #( %tky = <approval>-%tky ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = <approval>-%tky
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only PENDING records can be rejected (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF key-%param-RejectReason IS INITIAL.
|
||||
APPEND VALUE #( %tky = <approval>-%tky ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = <approval>-%tky
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'A reject reason is required' ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
MODIFY ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status RejectReason DecidedBy DecidedOn )
|
||||
WITH VALUE #( ( %tky = <approval>-%tky
|
||||
Status = status-rejected
|
||||
RejectReason = key-%param-RejectReason
|
||||
DecidedBy = cl_abap_context_info=>get_user_technical_name( )
|
||||
DecidedOn = utclong_current( ) ) )
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
ENDLOOP.
|
||||
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
result = VALUE #( FOR row IN updated ( %tky = row-%tky %param = row ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD retrySync.
|
||||
" FAILED -> EXECUTING; clears the previous error so the worker re-executes the staged payload (ARN-002 amendment)
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals)
|
||||
FAILED failed.
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-failed.
|
||||
APPEND VALUE #( %tky = <approval>-%tky ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = <approval>-%tky
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only FAILED records can be retried (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
MODIFY ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status ErrorMessage )
|
||||
WITH VALUE #( ( %tky = <approval>-%tky
|
||||
Status = status-executing
|
||||
ErrorMessage = '' ) )
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
ENDLOOP.
|
||||
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
result = VALUE #( FOR row IN updated ( %tky = row-%tky %param = row ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD markExecuting.
|
||||
" APPROVED -> EXECUTING (worker claims the record; the UI never offers Approve on an executing record, PRD RAP-6)
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals)
|
||||
FAILED failed.
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-approved.
|
||||
APPEND VALUE #( %tky = <approval>-%tky ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = <approval>-%tky
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only APPROVED records can start executing (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
MODIFY ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status )
|
||||
WITH VALUE #( ( %tky = <approval>-%tky
|
||||
Status = status-executing ) )
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
ENDLOOP.
|
||||
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
result = VALUE #( FOR row IN updated ( %tky = row-%tky %param = row ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD markSynced.
|
||||
" EXECUTING -> SYNCED (terminal success); SAP is the ledger, the change number is the receipt (ARN-006)
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals)
|
||||
FAILED failed.
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-executing.
|
||||
APPEND VALUE #( %tky = <approval>-%tky ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = <approval>-%tky
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only EXECUTING records can be marked synced (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF key-%param-SapChangeNumber IS INITIAL.
|
||||
APPEND VALUE #( %tky = <approval>-%tky ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = <approval>-%tky
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'The SAP change number is required to mark a record synced' ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
MODIFY ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status SapChangeNumber ErrorMessage )
|
||||
WITH VALUE #( ( %tky = <approval>-%tky
|
||||
Status = status-synced
|
||||
SapChangeNumber = key-%param-SapChangeNumber
|
||||
ErrorMessage = '' ) )
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
ENDLOOP.
|
||||
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
result = VALUE #( FOR row IN updated ( %tky = row-%tky %param = row ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD markFailed.
|
||||
" EXECUTING -> FAILED with the error text; distinct from REJECTED (predecessor defect, ARN-002)
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals)
|
||||
FAILED failed.
|
||||
|
||||
LOOP AT keys INTO DATA(key).
|
||||
ASSIGN approvals[ ID = key-ID ] TO FIELD-SYMBOL(<approval>).
|
||||
IF sy-subrc <> 0.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF <approval>-Status <> status-executing.
|
||||
APPEND VALUE #( %tky = <approval>-%tky ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = <approval>-%tky
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = |Only EXECUTING records can be marked failed (status is { <approval>-Status })| ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
IF key-%param-ErrorMessage IS INITIAL.
|
||||
APPEND VALUE #( %tky = <approval>-%tky ) TO failed-changeapproval.
|
||||
APPEND VALUE #( %tky = <approval>-%tky
|
||||
%msg = new_message_with_text(
|
||||
severity = if_abap_behv_message=>severity-error
|
||||
text = 'An error message is required to mark a record failed' ) )
|
||||
TO reported-changeapproval.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
MODIFY ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status ErrorMessage )
|
||||
WITH VALUE #( ( %tky = <approval>-%tky
|
||||
Status = status-failed
|
||||
ErrorMessage = key-%param-ErrorMessage ) )
|
||||
FAILED DATA(update_failed)
|
||||
REPORTED DATA(update_reported).
|
||||
ENDLOOP.
|
||||
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
ALL FIELDS WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(updated).
|
||||
|
||||
result = VALUE #( FOR row IN updated ( %tky = row-%tky %param = row ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
METHOD setInitialStatus.
|
||||
" Every created record starts PENDING with the requester audit fields (ARN-002)
|
||||
READ ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
FIELDS ( Status )
|
||||
WITH CORRESPONDING #( keys )
|
||||
RESULT DATA(approvals).
|
||||
|
||||
DELETE approvals WHERE Status IS NOT INITIAL.
|
||||
IF approvals IS INITIAL.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
MODIFY ENTITIES OF zzr_changeapproval000 IN LOCAL MODE
|
||||
ENTITY ChangeApproval
|
||||
UPDATE FIELDS ( Status RequestedBy RequestedOn )
|
||||
WITH VALUE #( FOR approval IN approvals
|
||||
( %tky = approval-%tky
|
||||
Status = status-pending
|
||||
RequestedBy = cl_abap_context_info=>get_user_technical_name( )
|
||||
RequestedOn = utclong_current( ) ) )
|
||||
REPORTED DATA(update_reported).
|
||||
|
||||
reported = CORRESPONDING #( DEEP update_reported ).
|
||||
ENDMETHOD.
|
||||
|
||||
ENDCLASS.
|
||||
@@ -1,20 +0,0 @@
|
||||
// TARGET OBJECT : behavior definition ZZC_CHANGEAPPROVAL000 (UI projection BDEF; generated 2026-09-15)
|
||||
// abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Behavior%20Definitions/ZZC_CHANGEAPPROVAL000/zzc_changeapproval000.bdef.json
|
||||
// ACTION : replace entire content, then activate (after ZZR_CHANGEAPPROVAL000 BDEF + ZZC_CHANGEAPPROVAL000 view).
|
||||
// Then DELETE the generated class ZZBP_C_CHANGEAPPROVAL000 in ADT: a projection BDEF needs no behavior
|
||||
// pool unless it defines new actions/functions, and this one reuses everything
|
||||
// [source: abap-docs /abap-docs-cloud/ABENBDL_BDEF_PROJECTION_HEADER, verified 2026-09-15].
|
||||
// Sources (verified 2026-09-15): use action / use etag; no automatic inheritance - only what is listed is exposed,
|
||||
// which is how create/update/delete and the worker actions are kept out of the UI service (PRD RAP-2)
|
||||
// [abap-docs /abap-docs-cloud/ABENBDL_USE_PROJECTION]. Feature control of reused actions is passed on automatically (same source).
|
||||
projection;
|
||||
strict ( 2 );
|
||||
|
||||
define behavior for ZZC_CHANGEAPPROVAL000 alias ChangeApproval
|
||||
{
|
||||
use etag;
|
||||
|
||||
use action approve;
|
||||
use action reject;
|
||||
use action retrySync;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/* TARGET OBJECT : access control ZZC_CHANGEAPPROVAL000 (generated 2026-09-15)
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Access%20Controls/ZZC_CHANGEAPPROVAL000/zzc_changeapproval000.dcls.acds
|
||||
ACTION : replace entire content, then activate (after ZZR_CHANGEAPPROVAL000 DCL).
|
||||
A transactional query needs its own DCL, inheriting the base view's conditions - there is no implicit inheritance
|
||||
[source: abap-docs /abap-platform-rap-opensap/week2/unit7#step-5-create-cds-access-control-for-travel-bo-projection-view-and-check-the-result;
|
||||
/abap-docs-cloud/ABENCDS_DEFINE_VIEW_AS_PROJECTION (access control must be symmetric), verified 2026-09-15]. */
|
||||
@EndUserText.label: 'Access control for ZZC_CHANGEAPPROVAL000'
|
||||
@MappingRole: true
|
||||
define role ZZC_CHANGEAPPROVAL000 {
|
||||
grant select on ZZC_CHANGEAPPROVAL000
|
||||
where inheriting conditions from entity ZZR_CHANGEAPPROVAL000;
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/* TARGET OBJECT : data definition ZZR_CHANGEAPPROVAL000 (root view entity, generated 2026-09-15)
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Core%20Data%20Services/Data%20Definitions/ZZR_CHANGEAPPROVAL000/zzr_changeapproval000.ddls.acds
|
||||
ACTION : replace entire content, then activate (table ZZCHNGPPROVAL000 must be active first).
|
||||
Notes: StatusText / StatusCriticality / IsApprovable / IsRetriable are derived from Status with CASE
|
||||
expressions here, because a transactional_query projection list may only contain elements of the
|
||||
projected entity, path expressions, associations and virtual elements - no expressions
|
||||
[source: abap-docs /abap-docs-cloud/ABENCDS_DEFINE_VIEW_AS_PROJECTION, verified 2026-09-15].
|
||||
CASE syntax [source: abap-docs /abap-docs-cloud/ABENCDS_CASE_EXPRESSION_V2, verified 2026-09-15];
|
||||
cast of a literal to a data element (abap_boolean, released) [source: abap-docs /abap-docs-cloud/ABENCDS_CAST_EXPRESSION_V2, verified 2026-09-15].
|
||||
@ObjectModel.text.element [source: abap-docs /abap-fiori-showcase/06_object_page_content#displaying-text-instead-of-id, verified 2026-09-15].
|
||||
@Semantics admin-field annotations [source: abap-docs /abap-platform-rap-opensap/week2/unit3#step-1-create-the-interface-cds-view-for-the-travel-entity, verified 2026-09-15].
|
||||
Criticality values 2/2/5/3/1/1 per PRD RAP-1. */
|
||||
@AccessControl.authorizationCheck: #CHECK
|
||||
@EndUserText.label: 'Arena change approval'
|
||||
define root view entity ZZR_CHANGEAPPROVAL000
|
||||
as select from zzchngpproval000
|
||||
{
|
||||
key id as ID,
|
||||
item_number as ItemNumber,
|
||||
item_name as ItemName,
|
||||
change_type as ChangeType,
|
||||
arena_eco_id as ArenaEcoId,
|
||||
|
||||
@ObjectModel.text.element: ['StatusText']
|
||||
status as Status,
|
||||
|
||||
case status
|
||||
when 'PENDING' then 'Pending approval'
|
||||
when 'APPROVED' then 'Approved - awaiting execution'
|
||||
when 'EXECUTING' then 'Executing in SAP'
|
||||
when 'SYNCED' then 'Synced to SAP'
|
||||
when 'REJECTED' then 'Rejected'
|
||||
when 'FAILED' then 'Execution failed'
|
||||
else status
|
||||
end as StatusText,
|
||||
|
||||
case status
|
||||
when 'PENDING' then 2
|
||||
when 'APPROVED' then 2
|
||||
when 'EXECUTING' then 5
|
||||
when 'SYNCED' then 3
|
||||
when 'REJECTED' then 1
|
||||
when 'FAILED' then 1
|
||||
else 0
|
||||
end as StatusCriticality,
|
||||
|
||||
requested_by as RequestedBy,
|
||||
requested_on as RequestedOn,
|
||||
decided_by as DecidedBy,
|
||||
decided_on as DecidedOn,
|
||||
sap_change_number as SapChangeNumber,
|
||||
error_message as ErrorMessage,
|
||||
reject_reason as RejectReason,
|
||||
sap_preview as SapPreview,
|
||||
|
||||
case status
|
||||
when 'PENDING' then cast( 'X' as abap_boolean )
|
||||
else cast( ' ' as abap_boolean )
|
||||
end as IsApprovable,
|
||||
|
||||
case status
|
||||
when 'FAILED' then cast( 'X' as abap_boolean )
|
||||
else cast( ' ' as abap_boolean )
|
||||
end as IsRetriable,
|
||||
|
||||
@Semantics.user.createdBy: true
|
||||
created_by as CreatedBy,
|
||||
@Semantics.systemDateTime.createdAt: true
|
||||
created_at as CreatedAt,
|
||||
@Semantics.user.lastChangedBy: true
|
||||
last_changed_by as LastChangedBy,
|
||||
@Semantics.systemDateTime.lastChangedAt: true
|
||||
last_changed_at as LastChangedAt,
|
||||
@Semantics.systemDateTime.localInstanceLastChangedAt: true
|
||||
local_last_changed_at as LocalLastChangedAt
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/* TARGET OBJECT : service definition ZZUI_ARENA_CHANGE_APPRVL000_O4 (generated 2026-09-15)
|
||||
abap: URI : abap:/repotree-v1/0M7DEJI/System%20Library/ZLOCAL/ZARENA_PLM/Business%20Services/Service%20Definitions/ZZUI_ARENA_CHANGE_APPRVL000_O4/zzui_arena_change_apprvl000_o4.srvd.acds
|
||||
ACTION : replace entire content, then activate (after ZZC_CHANGEAPPROVAL000 view + BDEF).
|
||||
expose ... as <alias>: the alias becomes the entity set (ChangeApproval) and the entity type (ChangeApproval_Type)
|
||||
[source: abap-docs /abap-fiori-showcase/06_object_page_content (Service Definition), verified 2026-09-15].
|
||||
provider contracts odata_v4_ui switches on the UI-binding syntax checks and must match the binding type
|
||||
[source: abap-docs /abap-docs-cloud/ABENSRVD_PROVIDER_CONTRACT, verified 2026-09-15]. */
|
||||
@EndUserText.label: 'Arena change approval - UI service'
|
||||
define service ZZUI_ARENA_CHANGE_APPRVL000_O4
|
||||
provider contracts odata_v4_ui
|
||||
{
|
||||
expose ZZC_CHANGEAPPROVAL000 as ChangeApproval;
|
||||
}
|
||||
@@ -0,0 +1,593 @@
|
||||
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" xmlns="http://docs.oasis-open.org/odata/ns/edm" Version="4.0">
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_AGGREGATION',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="Org.OData.Aggregation.V1" Alias="SAP__aggregation"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_ANALYTICS',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.Analytics.v1" Alias="SAP__analytics"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_AUTHORIZATION',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="Org.OData.Authorization.V1" Alias="SAP__authorization"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_CAPABILITIES',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="Org.OData.Capabilities.V1" Alias="SAP__capabilities"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_CODELIST',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.CodeList.v1" Alias="SAP__CodeList"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_COMMON',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.Common.v1" Alias="SAP__common"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_COMMUNICATION',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.Communication.v1" Alias="SAP__communication"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_CORE',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="Org.OData.Core.V1" Alias="SAP__core"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_HIERARCHY',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.Hierarchy.v1" Alias="SAP__hierarchy"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_HTML5',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.HTML5.v1" Alias="SAP__HTML5"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_MEASURES',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="Org.OData.Measures.V1" Alias="SAP__measures"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_ODM',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.ODM.v1" Alias="SAP__ODM"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_PDF',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.PDF.v1" Alias="SAP__PDF"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_PERSONALDATA',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.PersonalData.v1" Alias="SAP__personalData"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_SESSION',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.Session.v1" Alias="SAP__session"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_SUPPORT',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.Support.v1" Alias="SAP__support"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_UI',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="com.sap.vocabularies.UI.v1" Alias="SAP__UI"/>
|
||||
</edmx:Reference>
|
||||
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_VALIDATION',Version='0001',SAP__Origin='LOCAL')/$value">
|
||||
<edmx:Include Namespace="Org.OData.Validation.V1" Alias="SAP__validation"/>
|
||||
</edmx:Reference>
|
||||
<edmx:DataServices>
|
||||
<Schema Namespace="com.sap.gateway.srvd.zui_arena_change_approval.v0001" Alias="SAP__self">
|
||||
<Annotation Term="SAP__core.SchemaVersion" String="1.0.0"/>
|
||||
<EntityType Name="ChangeApprovalType">
|
||||
<Key>
|
||||
<PropertyRef Name="ID"/>
|
||||
</Key>
|
||||
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
|
||||
<Property Name="ItemNumber" Type="Edm.String" Nullable="false" MaxLength="18"/>
|
||||
<Property Name="ItemName" Type="Edm.String" Nullable="false" MaxLength="40"/>
|
||||
<Property Name="ChangeType" Type="Edm.String" Nullable="false" MaxLength="15"/>
|
||||
<Property Name="ArenaEcoId" Type="Edm.String" Nullable="false" MaxLength="20"/>
|
||||
<Property Name="Status" Type="Edm.String" Nullable="false" MaxLength="10"/>
|
||||
<Property Name="StatusText" Type="Edm.String" Nullable="false" MaxLength="29"/>
|
||||
<Property Name="StatusCriticality" Type="Edm.Byte" Nullable="false"/>
|
||||
<Property Name="RequestedBy" Type="Edm.String" Nullable="false" MaxLength="12"/>
|
||||
<Property Name="RequestedOn" Type="Edm.DateTimeOffset" Precision="7"/>
|
||||
<Property Name="DecidedBy" Type="Edm.String" Nullable="false" MaxLength="12"/>
|
||||
<Property Name="DecidedOn" Type="Edm.DateTimeOffset" Precision="7"/>
|
||||
<Property Name="SapChangeNumber" Type="Edm.String" Nullable="false" MaxLength="12"/>
|
||||
<Property Name="ErrorMessage" Type="Edm.String" Nullable="false" MaxLength="255"/>
|
||||
<Property Name="RejectReason" Type="Edm.String" Nullable="false" MaxLength="255"/>
|
||||
<Property Name="SapPreview" Type="Edm.String" Nullable="false"/>
|
||||
<Property Name="IsApprovable" Type="Edm.Boolean" Nullable="false"/>
|
||||
<Property Name="IsRetriable" Type="Edm.Boolean" Nullable="false"/>
|
||||
<Property Name="LocalLastChangedAt" Type="Edm.DateTimeOffset" Precision="7"/>
|
||||
<Property Name="__OperationControl" Type="com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalOperationControl"/>
|
||||
<Property Name="SAP__Messages" Type="Collection(com.sap.gateway.srvd.zui_arena_change_approval.v0001.SAP__Message)" Nullable="false"/>
|
||||
</EntityType>
|
||||
<ComplexType Name="ChangeApprovalOperationControl">
|
||||
<Property Name="approve" Type="Edm.Boolean" Nullable="false"/>
|
||||
<Property Name="reject" Type="Edm.Boolean" Nullable="false"/>
|
||||
<Property Name="retrySync" Type="Edm.Boolean" Nullable="false"/>
|
||||
</ComplexType>
|
||||
<ComplexType Name="SAP__Message">
|
||||
<Property Name="code" Type="Edm.String" Nullable="false"/>
|
||||
<Property Name="message" Type="Edm.String" Nullable="false"/>
|
||||
<Property Name="target" Type="Edm.String"/>
|
||||
<Property Name="additionalTargets" Type="Collection(Edm.String)" Nullable="false"/>
|
||||
<Property Name="transition" Type="Edm.Boolean" Nullable="false"/>
|
||||
<Property Name="numericSeverity" Type="Edm.Byte" Nullable="false"/>
|
||||
<Property Name="longtextUrl" Type="Edm.String"/>
|
||||
</ComplexType>
|
||||
<Action Name="retrySync" EntitySetPath="_it" IsBound="true">
|
||||
<Parameter Name="_it" Type="com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType" Nullable="false"/>
|
||||
<ReturnType Type="com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType" Nullable="false"/>
|
||||
</Action>
|
||||
<Action Name="approve" EntitySetPath="_it" IsBound="true">
|
||||
<Parameter Name="_it" Type="com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType" Nullable="false"/>
|
||||
<ReturnType Type="com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType" Nullable="false"/>
|
||||
</Action>
|
||||
<Action Name="reject" EntitySetPath="_it" IsBound="true">
|
||||
<Parameter Name="_it" Type="com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType" Nullable="false"/>
|
||||
<Parameter Name="RejectReason" Type="Edm.String" Nullable="false" MaxLength="255"/>
|
||||
<ReturnType Type="com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType" Nullable="false"/>
|
||||
</Action>
|
||||
<EntityContainer Name="Container">
|
||||
<EntitySet Name="ChangeApproval" EntityType="com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType"/>
|
||||
</EntityContainer>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/ID">
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
<Annotation Term="SAP__UI.Hidden"/>
|
||||
<Annotation Term="SAP__common.Label" String="UUID"/>
|
||||
<Annotation Term="SAP__common.QuickInfo" String="16 Byte UUID in 16 Bytes (Raw Format)"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/ItemNumber">
|
||||
<Annotation Term="SAP__common.Label" String="Item number"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/ItemName">
|
||||
<Annotation Term="SAP__common.Label" String="Item name"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/ChangeType">
|
||||
<Annotation Term="SAP__common.Label" String="Change type"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/ArenaEcoId">
|
||||
<Annotation Term="SAP__common.Label" String="Arena ECO"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/Status">
|
||||
<Annotation Term="SAP__common.Label" String="Status"/>
|
||||
<Annotation Term="SAP__common.Text" Path="StatusText">
|
||||
<Annotation Term="SAP__UI.TextArrangement" EnumMember="SAP__UI.TextArrangementType/TextOnly"/>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/StatusText">
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
<Annotation Term="SAP__UI.Hidden"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/StatusCriticality">
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
<Annotation Term="SAP__UI.Hidden"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/RequestedBy">
|
||||
<Annotation Term="SAP__common.Label" String="Requested by"/>
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/RequestedOn">
|
||||
<Annotation Term="SAP__common.Label" String="Requested on"/>
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/DecidedBy">
|
||||
<Annotation Term="SAP__common.Label" String="Decided by"/>
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/DecidedOn">
|
||||
<Annotation Term="SAP__common.Label" String="Decided on"/>
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/SapChangeNumber">
|
||||
<Annotation Term="SAP__common.Label" String="SAP change number"/>
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/ErrorMessage">
|
||||
<Annotation Term="SAP__common.Label" String="Error message"/>
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/RejectReason">
|
||||
<Annotation Term="SAP__common.Label" String="Reject reason"/>
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/SapPreview">
|
||||
<Annotation Term="SAP__common.Label" String="Staged payload"/>
|
||||
<Annotation Term="SAP__UI.MultiLineText"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/IsApprovable">
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
<Annotation Term="SAP__UI.Hidden"/>
|
||||
<Annotation Term="SAP__common.Label" String="Truth Value"/>
|
||||
<Annotation Term="SAP__common.QuickInfo" String="Truth Value: True/False"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/IsRetriable">
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
<Annotation Term="SAP__UI.Hidden"/>
|
||||
<Annotation Term="SAP__common.Label" String="Truth Value"/>
|
||||
<Annotation Term="SAP__common.QuickInfo" String="Truth Value: True/False"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/LocalLastChangedAt">
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
<Annotation Term="SAP__common.Label" String="Changed On"/>
|
||||
<Annotation Term="SAP__common.QuickInfo" String="Local Instance Last Change Date Time"/>
|
||||
<Annotation Term="SAP__common.DocumentationRef" String="urn:sap-com:documentation:key?=type=DE&id=ABP_LOCINST_LASTCHANGE_TSTMPL"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType/__OperationControl">
|
||||
<Annotation Term="SAP__core.Computed"/>
|
||||
<Annotation Term="SAP__UI.HiddenFilter"/>
|
||||
<Annotation Term="SAP__UI.Hidden"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.retrySync(SAP__self.ChangeApprovalType)">
|
||||
<Annotation Term="SAP__core.OperationAvailable" Path="_it/__OperationControl/retrySync"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.approve(SAP__self.ChangeApprovalType)">
|
||||
<Annotation Term="SAP__core.OperationAvailable" Path="_it/__OperationControl/approve"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.reject(SAP__self.ChangeApprovalType)/RejectReason">
|
||||
<Annotation Term="SAP__common.Label" String="Reject reason"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.reject(SAP__self.ChangeApprovalType)">
|
||||
<Annotation Term="SAP__core.OperationAvailable" Path="_it/__OperationControl/reject"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalType">
|
||||
<Annotation Term="SAP__common.Label" String="Arena change approval - UI projection"/>
|
||||
<Annotation Term="SAP__common.SemanticKey">
|
||||
<Collection>
|
||||
<PropertyPath>ArenaEcoId</PropertyPath>
|
||||
<PropertyPath>ChangeType</PropertyPath>
|
||||
<PropertyPath>ItemNumber</PropertyPath>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.DataPoint" Qualifier="StatusPoint">
|
||||
<Record>
|
||||
<PropertyValue Property="Value" Path="Status"/>
|
||||
<PropertyValue Property="Title" String="Status"/>
|
||||
<PropertyValue Property="Criticality" Path="StatusCriticality"/>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.HeaderFacets">
|
||||
<Collection>
|
||||
<Record Type="SAP__UI.ReferenceFacet">
|
||||
<PropertyValue Property="Label" String="Reference numbers"/>
|
||||
<PropertyValue Property="ID" String="Keys"/>
|
||||
<PropertyValue Property="Target" AnnotationPath="@SAP__UI.FieldGroup#Keys"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.ReferenceFacet">
|
||||
<PropertyValue Property="ID" String="StatusPoint"/>
|
||||
<PropertyValue Property="Target" AnnotationPath="@SAP__UI.DataPoint#StatusPoint"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.Facets">
|
||||
<Collection>
|
||||
<Record Type="SAP__UI.ReferenceFacet">
|
||||
<PropertyValue Property="Label" String="Change"/>
|
||||
<PropertyValue Property="ID" String="Change"/>
|
||||
<PropertyValue Property="Target" AnnotationPath="@SAP__UI.FieldGroup#Change"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.ReferenceFacet">
|
||||
<PropertyValue Property="Label" String="Staged payload"/>
|
||||
<PropertyValue Property="ID" String="Payload"/>
|
||||
<PropertyValue Property="Target" AnnotationPath="@SAP__UI.FieldGroup#Payload"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.ReferenceFacet">
|
||||
<PropertyValue Property="Label" String="Approval"/>
|
||||
<PropertyValue Property="ID" String="Approval"/>
|
||||
<PropertyValue Property="Target" AnnotationPath="@SAP__UI.FieldGroup#Approval"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.ReferenceFacet">
|
||||
<PropertyValue Property="Label" String="Execution"/>
|
||||
<PropertyValue Property="ID" String="Execution"/>
|
||||
<PropertyValue Property="Target" AnnotationPath="@SAP__UI.FieldGroup#Execution"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.FieldGroup" Qualifier="Approval">
|
||||
<Record>
|
||||
<PropertyValue Property="Data">
|
||||
<Collection>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Criticality" Path="StatusCriticality"/>
|
||||
<PropertyValue Property="Value" Path="Status"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="RequestedBy"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="RequestedOn"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="DecidedBy"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="DecidedOn"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="RejectReason"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.FieldGroup" Qualifier="Change">
|
||||
<Record>
|
||||
<PropertyValue Property="Data">
|
||||
<Collection>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ItemNumber"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ItemName"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ChangeType"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ArenaEcoId"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.FieldGroup" Qualifier="Execution">
|
||||
<Record>
|
||||
<PropertyValue Property="Data">
|
||||
<Collection>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="SapChangeNumber"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ErrorMessage"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.FieldGroup" Qualifier="Keys">
|
||||
<Record>
|
||||
<PropertyValue Property="Data">
|
||||
<Collection>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ArenaEcoId"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="SapChangeNumber"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.FieldGroup" Qualifier="Payload">
|
||||
<Record>
|
||||
<PropertyValue Property="Data">
|
||||
<Collection>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="SapPreview"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.HeaderInfo">
|
||||
<Record>
|
||||
<PropertyValue Property="TypeName" String="Change Approval"/>
|
||||
<PropertyValue Property="TypeNamePlural" String="Change Approvals"/>
|
||||
<PropertyValue Property="TypeImageUrl" String="sap-icon://approvals"/>
|
||||
<PropertyValue Property="Title">
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ItemNumber"/>
|
||||
</Record>
|
||||
</PropertyValue>
|
||||
<PropertyValue Property="Description">
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ItemName"/>
|
||||
</Record>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.Identification">
|
||||
<Collection>
|
||||
<Record Type="SAP__UI.DataFieldForAction">
|
||||
<PropertyValue Property="Label" String="Approve"/>
|
||||
<PropertyValue Property="Action" String="com.sap.gateway.srvd.zui_arena_change_approval.v0001.approve(com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType)"/>
|
||||
<PropertyValue Property="InvocationGrouping" EnumMember="SAP__UI.OperationGroupingType/Isolated"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataFieldForAction">
|
||||
<PropertyValue Property="Label" String="Reject"/>
|
||||
<PropertyValue Property="Action" String="com.sap.gateway.srvd.zui_arena_change_approval.v0001.reject(com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType)"/>
|
||||
<PropertyValue Property="InvocationGrouping" EnumMember="SAP__UI.OperationGroupingType/Isolated"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataFieldForAction">
|
||||
<PropertyValue Property="Label" String="Retry sync"/>
|
||||
<PropertyValue Property="Action" String="com.sap.gateway.srvd.zui_arena_change_approval.v0001.retrySync(com.sap.gateway.srvd.zui_arena_change_approval.v0001.ChangeApprovalType)"/>
|
||||
<PropertyValue Property="InvocationGrouping" EnumMember="SAP__UI.OperationGroupingType/Isolated"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.LineItem">
|
||||
<Collection>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ItemNumber"/>
|
||||
<Annotation Term="SAP__UI.Importance" EnumMember="SAP__UI.ImportanceType/High"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ItemName"/>
|
||||
<Annotation Term="SAP__UI.Importance" EnumMember="SAP__UI.ImportanceType/Low"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ChangeType"/>
|
||||
<Annotation Term="SAP__UI.Importance" EnumMember="SAP__UI.ImportanceType/High"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Criticality" Path="StatusCriticality"/>
|
||||
<PropertyValue Property="Value" Path="Status"/>
|
||||
<Annotation Term="SAP__UI.Importance" EnumMember="SAP__UI.ImportanceType/High"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="RequestedOn"/>
|
||||
<Annotation Term="SAP__UI.Importance" EnumMember="SAP__UI.ImportanceType/Medium"/>
|
||||
</Record>
|
||||
<Record Type="SAP__UI.DataField">
|
||||
<PropertyValue Property="Value" Path="ArenaEcoId"/>
|
||||
<Annotation Term="SAP__UI.Importance" EnumMember="SAP__UI.ImportanceType/Medium"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.PresentationVariant">
|
||||
<Record>
|
||||
<PropertyValue Property="SortOrder">
|
||||
<Collection>
|
||||
<Record Type="SAP__common.SortOrderType">
|
||||
<PropertyValue Property="Property" PropertyPath="Status"/>
|
||||
<PropertyValue Property="Descending" Bool="false"/>
|
||||
</Record>
|
||||
<Record Type="SAP__common.SortOrderType">
|
||||
<PropertyValue Property="Property" PropertyPath="RequestedOn"/>
|
||||
<PropertyValue Property="Descending" Bool="true"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
<PropertyValue Property="Visualizations">
|
||||
<Collection>
|
||||
<AnnotationPath>@SAP__UI.LineItem</AnnotationPath>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__UI.SelectionFields">
|
||||
<Collection>
|
||||
<PropertyPath>ItemNumber</PropertyPath>
|
||||
<PropertyPath>Status</PropertyPath>
|
||||
<PropertyPath>ChangeType</PropertyPath>
|
||||
<PropertyPath>ArenaEcoId</PropertyPath>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__common.Messages" Path="SAP__Messages"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.Container/ChangeApproval">
|
||||
<Annotation Term="SAP__capabilities.SearchRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Searchable" Bool="false"/>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__capabilities.FilterRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Filterable" Bool="true"/>
|
||||
<PropertyValue Property="FilterExpressionRestrictions">
|
||||
<Collection>
|
||||
<Record>
|
||||
<PropertyValue Property="Property" PropertyPath="SapPreview"/>
|
||||
<PropertyValue Property="AllowedExpressions" String="SearchExpression"/>
|
||||
</Record>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
<PropertyValue Property="NonFilterableProperties">
|
||||
<Collection>
|
||||
<PropertyPath>__OperationControl</PropertyPath>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__capabilities.SortRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="NonSortableProperties">
|
||||
<Collection>
|
||||
<PropertyPath>SapPreview</PropertyPath>
|
||||
<PropertyPath>__OperationControl</PropertyPath>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__capabilities.InsertRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Insertable" Bool="false"/>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__capabilities.DeleteRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Deletable" Bool="false"/>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__capabilities.UpdateRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Updatable" Bool="false"/>
|
||||
<PropertyValue Property="QueryOptions">
|
||||
<Record>
|
||||
<PropertyValue Property="SelectSupported" Bool="true"/>
|
||||
</Record>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__core.OptimisticConcurrency">
|
||||
<Collection>
|
||||
<PropertyPath>LocalLastChangedAt</PropertyPath>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.Container">
|
||||
<Annotation Term="SAP__common.ApplyMultiUnitBehaviorForSortingAndFiltering" Bool="true"/>
|
||||
<Annotation Term="SAP__capabilities.FilterFunctions">
|
||||
<Collection>
|
||||
<String>eq</String>
|
||||
<String>ne</String>
|
||||
<String>gt</String>
|
||||
<String>ge</String>
|
||||
<String>lt</String>
|
||||
<String>le</String>
|
||||
<String>and</String>
|
||||
<String>or</String>
|
||||
<String>contains</String>
|
||||
<String>startswith</String>
|
||||
<String>endswith</String>
|
||||
<String>any</String>
|
||||
<String>all</String>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__support.TechnicalInfoLinks">
|
||||
<Record>
|
||||
<PropertyValue Property="Url" String="../../../../default/iwbep/common/0001/$metadata"/>
|
||||
<PropertyValue Property="FunctionImport" String="GetTechnicalInfoLinks"/>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__capabilities.SupportedFormats">
|
||||
<Collection>
|
||||
<String>application/json</String>
|
||||
<String>application/pdf</String>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__PDF.Features">
|
||||
<Record>
|
||||
<PropertyValue Property="DocumentDescriptionReference" String="../../../../default/iwbep/common/0001/$metadata"/>
|
||||
<PropertyValue Property="DocumentDescriptionCollection" String="MyDocumentDescriptions"/>
|
||||
<PropertyValue Property="ArchiveFormat" Bool="true"/>
|
||||
<PropertyValue Property="Border" Bool="true"/>
|
||||
<PropertyValue Property="CoverPage" Bool="true"/>
|
||||
<PropertyValue Property="FitToPage" Bool="true"/>
|
||||
<PropertyValue Property="FontName" Bool="true"/>
|
||||
<PropertyValue Property="FontSize" Bool="true"/>
|
||||
<PropertyValue Property="HeaderFooter" Bool="true"/>
|
||||
<PropertyValue Property="IANATimezoneFormat" Bool="true"/>
|
||||
<PropertyValue Property="Margin" Bool="true"/>
|
||||
<PropertyValue Property="Padding" Bool="true"/>
|
||||
<PropertyValue Property="ResultSizeDefault" Int="20000"/>
|
||||
<PropertyValue Property="ResultSizeMaximum" Int="20000"/>
|
||||
<PropertyValue Property="Signature" Bool="true"/>
|
||||
<PropertyValue Property="TextDirectionLayout" Bool="true"/>
|
||||
<PropertyValue Property="Treeview" Bool="true"/>
|
||||
<PropertyValue Property="UploadToFileShare" Bool="true"/>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__capabilities.BatchSupport">
|
||||
<Record>
|
||||
<PropertyValue Property="SupportedFormats">
|
||||
<Collection>
|
||||
<String>application/json</String>
|
||||
<String>multipart/mixed</String>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="SAP__capabilities.KeyAsSegmentSupported"/>
|
||||
<Annotation Term="SAP__capabilities.AsynchronousRequestsSupported"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalOperationControl/approve">
|
||||
<Annotation Term="SAP__common.Label" String="Dyn. Action Control"/>
|
||||
<Annotation Term="SAP__common.Heading" String="Dynamic Action Control"/>
|
||||
<Annotation Term="SAP__common.QuickInfo" String="Dynamic Action Property"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalOperationControl/reject">
|
||||
<Annotation Term="SAP__common.Label" String="Dyn. Action Control"/>
|
||||
<Annotation Term="SAP__common.Heading" String="Dynamic Action Control"/>
|
||||
<Annotation Term="SAP__common.QuickInfo" String="Dynamic Action Property"/>
|
||||
</Annotations>
|
||||
<Annotations Target="SAP__self.ChangeApprovalOperationControl/retrySync">
|
||||
<Annotation Term="SAP__common.Label" String="Dyn. Action Control"/>
|
||||
<Annotation Term="SAP__common.Heading" String="Dynamic Action Control"/>
|
||||
<Annotation Term="SAP__common.QuickInfo" String="Dynamic Action Property"/>
|
||||
</Annotations>
|
||||
</Schema>
|
||||
</edmx:DataServices>
|
||||
</edmx:Edmx>
|
||||
Reference in New Issue
Block a user