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:
@@ -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.
|
||||
Reference in New Issue
Block a user