https://raw.githubusercontent.com/ajmaradiaga/feeds/main/scmt/topics/ABAP-Development-blog-posts.xmlSAP Community - ABAP Development2025-12-16T18:00:02.874531+00:00python-feedgenABAP Development blog posts in SAP Communityhttps://community.sap.com/t5/technology-blog-posts-by-members/call-bapi-in-custom-entity-through-rap/ba-p/14268610CALL BAPI IN CUSTOM ENTITY THROUGH RAP2025-12-09T11:29:06.943000+01:00harsha_reddy24https://community.sap.com/t5/user/viewprofilepage/user-id/2263071<P>Hi RAP Developers, Good Day<BR /><BR /><STRONG>Introduction:</STRONG></P><P>In many business scenarios, we need to expose BAPI-based data to SAP Fiori applications without creating database tables or CDS-based persistency. With the RESTful ABAP Programming Model (RAP), this can be achieved efficiently using <STRONG>Custom Entities</STRONG>, which allow us to call ABAP logic directly—such as BAPIs—and return the data as an OData service.</P><P>In this blog, I will walk through how to build a <STRONG>Custom Entity that fetches bank details by calling a BAPI</STRONG>, how to annotate it for UI consumption, and how to expose it seamlessly to a Fiori Elements application. This approach is useful whenever you want to reuse existing BAPIs and business logic while keeping your RAP model clean, lightweight, and high-performing.</P><P><STRONG>Solution Overview:</STRONG></P><P>This solution demonstrates how RAP can seamlessly integrate with classic SAP functionality by exposing BAPI output through a <STRONG>Custom Entity</STRONG>. Instead of relying on database tables or CDS views, the Custom Entity acts as a virtual data source whose data is supplied dynamically via an ABAP class.</P><P>When a Fiori Elements UI requests the entity, RAP forwards the query to the ABAP implementation class. This class reads the query parameters (filters, sorting, pagination) and uses them to call <STRONG>BAPI_BANK_GETDETAIL</STRONG>. The BAPI returns the bank’s address, master data, and related details, which are then transformed into the response structure expected by the Custom Entity.</P><P>The result is an OData-based, read-only endpoint capable of delivering real-time data from a BAPI with full RAP features such as filtering, sorting, paging, and total count support. This approach makes it easy to modernize existing SAP data retrieval logic while still leveraging stable, proven BAPIs in the backend.</P><P><BR /><STRONG>Custom Entity:<BR /></STRONG></P><UL><LI>custom entity not underlying any data source.</LI><LI>data preview is not possible, becuase this should be implemented in seperate class.</LI><LI>suitable for paging,calling bapi's and external api's.</LI></UL><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Custom Entity calling bapi'
@ObjectModel: {
query: {
implementedBy: 'ABAP:ZCL_BAPI_BANK'
}
}
@UI: {
headerInfo: {
typeName: 'Banks',
typeNamePlural: 'Banks',
title: { value: 'bank_ctry' },
description: { value: 'bank_ctry' }
}
}
@UI: {
presentationVariant: [{
sortOrder: [{
by: 'bank_ctry',
direction: #ASC
}],
visualizations: [{
type: #AS_LINEITEM
}]
}]
}
define root custom entity ZCE_BANK
{
.facet : [
{
id : 'Bank_data',
purpose : #STANDARD,
type : #IDENTIFICATION_REFERENCE,
label : 'Bank Details',
position: 10 }
]
.lineItem : [{ position: 10 }]
.selectionField : [{position: 10}]
.identification : [{position: 10}]
key bank_ctry : banks;
.lineItem : [{ position: 20 }]
.selectionField : [{position: 20}]
.identification : [{position: 20}]
key bank_key : bankk;
.lineItem : [{ position: 30 }]
.identification : [{position: 30}]
bank_name : banka;
.lineItem : [{ position: 40 }]
.identification : [{position: 40}]
street : stras_gp;
.lineItem : [{ position: 50 }]
.identification : [{position: 50}]
city : ort01_gp;
.lineItem : [{ position: 60 }]
.identification : [{position: 60}]
BANK_NO : bankl;
.lineItem : [{ position: 70 }]
.identification : [{position: 70}]
CREAT_DATE : erdat_bf;
.lineItem : [{ position: 80 }]
.identification : [{position: 80}]
creator : ernam_bf;
}</code></pre><P><BR /><STRONG>Implementation:</STRONG></P><pre class="lia-code-sample language-abap"><code>CLASS ZCL_BAPI_BANK DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
" RAP interface for query implementation
INTERFACES IF_RAP_QUERY_PROVIDER.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_BAPI_BANK IMPLEMENTATION.
METHOD IF_RAP_QUERY_PROVIDER~SELECT.
"----------------------------------------------------------------------
" Local type used to return data back to Custom Entity ZCE_BANK
"----------------------------------------------------------------------
TYPES: BEGIN OF TY_BANK_RESULT,
BANK_CTRY TYPE BANKS,
BANK_KEY TYPE BANKK,
BANK_NAME TYPE BANKA,
STREET TYPE STRAS_GP,
CITY TYPE ORT01_GP,
BANK_NO TYPE BANKL,
CREAT_DATE TYPE ERDAT_BF,
CREATOR TYPE ERNAM_BF,
END OF TY_BANK_RESULT.
DATA: LT_RESULT TYPE TABLE OF TY_BANK_RESULT,
LS_RESULT TYPE TY_BANK_RESULT,
LS_ADDRESS TYPE BAPI1011_ADDRESS,
LS_DETAIL TYPE BAPI1011_DETAIL,
LS_RETURN TYPE BAPIRET2.
" Proceed only if the consumer has requested data
IF IO_REQUEST->IS_DATA_REQUESTED( ).
"---------------------------------------------------------------
" Read pagination details (TOP and SKIP)
"---------------------------------------------------------------
DATA(LV_TOP) = IO_REQUEST->GET_PAGING( )->GET_PAGE_SIZE( ).
DATA(LV_SKIP) = IO_REQUEST->GET_PAGING( )->GET_OFFSET( ).
"---------------------------------------------------------------
" Prepare ORDER BY clause based on sort request from UI
"---------------------------------------------------------------
DATA(LT_SORT) = IO_REQUEST->GET_SORT_ELEMENTS( ).
DATA LV_ORDERBY TYPE STRING.
IF LT_SORT IS NOT INITIAL.
CLEAR LV_ORDERBY.
LOOP AT LT_SORT INTO DATA(LS_SORT).
IF SY-TABIX > 1.
LV_ORDERBY = |{ LV_ORDERBY }, |.
ENDIF.
" Construct ORDER BY element (ASCENDING/DESCENDING)
LV_ORDERBY =
|{ LV_ORDERBY }{ LS_SORT-ELEMENT_NAME } {
COND #( WHEN LS_SORT-DESCENDING = ABAP_TRUE
THEN 'DESCENDING'
ELSE 'ASCENDING' ) }|.
ENDLOOP.
ENDIF.
"---------------------------------------------------------------
" Derive SQL filter string from UI filter (if any)
"---------------------------------------------------------------
DATA(lv_conditions) = io_request->get_filter( )->get_as_sql_string( ).
"---------------------------------------------------------------
" Read bank master records (BNKA) based on filters
"---------------------------------------------------------------
SELECT BANKS AS bank_ctry,
BANKL AS bank_key,
BNKLZ AS bank_no,
ERDAT AS creat_date,
ERNAM AS creator
FROM BNKA
WHERE (lv_conditions)
ORDER BY (lv_orderby)
INTO TABLE <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1407137">@DATA</a>(lt_banks)
UP TO <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1419942">@LV</a>_top ROWS
OFFSET <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1419942">@LV</a>_skip.
"---------------------------------------------------------------
" Loop through each BNKA record and enrich details using BAPI
"---------------------------------------------------------------
LOOP AT lt_banks INTO DATA(ls_bank).
" Get detailed bank address info
CALL FUNCTION 'BAPI_BANK_GETDETAIL'
EXPORTING
bankcountry = ls_bank-bank_ctry
bankkey = ls_bank-bank_key
IMPORTING
bank_address = ls_address
bank_detail = ls_detail
return = ls_return.
" Prepare output row
LS_RESULT-bank_ctry = ls_bank-bank_ctry.
LS_RESULT-bank_key = ls_bank-bank_key.
LS_RESULT-bank_name = ls_address-bank_name.
LS_RESULT-street = ls_address-street.
LS_RESULT-city = ls_address-city.
LS_RESULT-bank_no = ls_bank-bank_no.
LS_RESULT-creat_date = ls_bank-creat_date.
LS_RESULT-creator = ls_bank-creator.
APPEND LS_RESULT TO LT_RESULT.
CLEAR: ls_result, ls_address, ls_detail, ls_return.
ENDLOOP.
"---------------------------------------------------------------
" Return total count for UI pagination (if requested)
"---------------------------------------------------------------
IF IO_REQUEST->IS_TOTAL_NUMB_OF_REC_REQUESTED( ).
SELECT COUNT(*)
FROM BNKA
WHERE (lv_conditions)
INTO <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1407137">@DATA</a>(lv_count).
IO_RESPONSE->SET_TOTAL_NUMBER_OF_RECORDS( lv_count ).
ENDIF.
"---------------------------------------------------------------
" Send final result back to RAP framework
"---------------------------------------------------------------
IO_RESPONSE->SET_DATA( LT_RESULT ).
ENDIF.
ENDMETHOD.
ENDCLASS.</code></pre><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="bank.jpg" style="width: 621px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/340394iA7F2C1EEC70EB6A5/image-dimensions/621x294/is-moderation-mode/true?v=v2" width="621" height="294" role="button" title="bank.jpg" alt="bank.jpg" /></span></P><P><STRONG>Conclusion: </STRONG><BR />this approach highlights how RAP can modernize SAP applications by exposing classic BAPI data through Custom Entities. It enables real-time, read-only access with full OData capabilities—filtering, sorting, paging—without changing existing backend logic, bridging the gap between proven SAP functionality and modern Fiori UIs.<BR />Thanks For Reading, Best Wishes</P>2025-12-09T11:29:06.943000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/date-hierarchy-using-tree-alv-fm-amp-oops/ba-p/14267818Date Hierarchy Using Tree ALV(FM & OOPS )2025-12-09T11:37:56.809000+01:00harsha_reddy24https://community.sap.com/t5/user/viewprofilepage/user-id/2263071<P>Hi Everyone<BR /><BR /></P><H3 id="toc-hId-1893824558"><FONT color="#000000"><STRONG><FONT face="Times New Roman, serif"><FONT size="4"><SPAN>Introduction:</SPAN></FONT></FONT></STRONG></FONT></H3><P class="">The user needs an interactive <STRONG>Date Hierarchy</STRONG> display in SAP that provides a structured view of years, months, and individual dates.This helps users quickly navigate through large date ranges and select specific dates for downstream operations such as data extraction, reporting, or analysis.</P><P class="" align="left"><STRONG>Solution Overview:</STRONG></P><P class="" align="left"> </P><UL><LI><P class="">The screen should display a hierarchical <STRONG>Tree ALV</STRONG> titled <STRONG>“DATE HIERARCHY”</STRONG>.</P></LI><LI><P class="">The top-level nodes represent <STRONG>Years</STRONG> (e.g., 2021 to 2025).</P></LI><LI><P class="">When the user <STRONG>expands a Year</STRONG>, the <STRONG>12 months (January to December)</STRONG> are displayed as child nodes.</P></LI><LI><P class="">When the user <STRONG>expands a Month</STRONG>, all <STRONG>valid calendar dates</STRONG> for that month are dynamically generated and displayed.</P></LI><LI><P class="">Each date node should display the date in <STRONG>user’s local format (DD.MM.YYYY)</STRONG>.</P></LI><LI><P class="">The user should be able to:</P><UL><LI><P class="">Expand/collapse nodes dynamically.</P></LI><LI><P class="">View all levels of hierarchy.</P></LI></UL></LI></UL><P class="" align="left"> </P><pre class="lia-code-sample language-abap"><code>TABLES : BKPF.
"Internal table and work area for tree nodes
DATA: IT_NODE TYPE TABLE OF SNODETEXT,
WA_NODE TYPE SNODETEXT.
"Variables for Year, Month, Date calculations
DATA: LV_YEAR TYPE GJAHR,
LV_MONTH TYPE NUMC2,
LV_DATE TYPE DATUM,
LV_DAYS TYPE I,
LV_DAY TYPE NUMC2.
"Keys for hierarchy levels
DATA: LV_YEAR_KEY TYPE CHAR10,
LV_MONTH_KEY TYPE CHAR15,
LV_DATE_KEY TYPE CHAR20.
"Selection range for fiscal year
SELECT-OPTIONS: S_GJAHR FOR BKPF-GJAHR DEFAULT '2021' TO '2025'.
START-OF-SELECTION.
CLEAR: WA_NODE, IT_NODE.
"------------------------------------------------------------"
" Root Node Creation "
"------------------------------------------------------------"
WA_NODE-TYPE = 'T'. "Tree title
WA_NODE-NAME = 'DATE HIERARCHY'.
WA_NODE-TLEVEL = '01'.
WA_NODE-NLENGTH = '18'.
WA_NODE-COLOR = '05'.
APPEND WA_NODE TO IT_NODE.
CLEAR WA_NODE.
"------------------------------------------------------------"
" Build Year → Month → Date Hierarchy "
"------------------------------------------------------------"
LOOP AT S_GJAHR.
DO.
"Loop through each year within the selected range
LV_YEAR = S_GJAHR-LOW + SY-INDEX - 1.
IF LV_YEAR > S_GJAHR-HIGH.
EXIT.
ENDIF.
"--------------------------------------------------------"
" Year Node (Level 02) "
"--------------------------------------------------------"
LV_YEAR_KEY = LV_YEAR.
WA_NODE-TYPE = 'P'.
WA_NODE-ID = LV_YEAR_KEY.
CONCATENATE LV_YEAR ' ' INTO WA_NODE-NAME SEPARATED BY SPACE.
WA_NODE-TLEVEL = '02'.
WA_NODE-NLENGTH = STRLEN( WA_NODE-NAME ).
WA_NODE-COLOR = '03'.
APPEND WA_NODE TO IT_NODE.
CLEAR WA_NODE.
"--------------------------------------------------------"
" 12 Months Loop (Level 03) "
"--------------------------------------------------------"
DO 12 TIMES.
LV_MONTH = SY-INDEX.
CONCATENATE LV_YEAR_KEY LV_MONTH INTO LV_MONTH_KEY.
WA_NODE-TYPE = 'P'.
WA_NODE-ID = LV_MONTH_KEY.
"Month Name Assignment"
CASE LV_MONTH.
WHEN '01'. WA_NODE-NAME = 'January'.
WHEN '02'. WA_NODE-NAME = 'February'.
WHEN '03'. WA_NODE-NAME = 'March'.
WHEN '04'. WA_NODE-NAME = 'April'.
WHEN '05'. WA_NODE-NAME = 'May'.
WHEN '06'. WA_NODE-NAME = 'June'.
WHEN '07'. WA_NODE-NAME = 'July'.
WHEN '08'. WA_NODE-NAME = 'August'.
WHEN '09'. WA_NODE-NAME = 'September'.
WHEN '10'. WA_NODE-NAME = 'October'.
WHEN '11'. WA_NODE-NAME = 'November'.
WHEN '12'. WA_NODE-NAME = 'December'.
ENDCASE.
WA_NODE-TLEVEL = '03'.
WA_NODE-NLENGTH = STRLEN( WA_NODE-NAME ).
WA_NODE-COLOR = '04'.
APPEND WA_NODE TO IT_NODE.
CLEAR WA_NODE.
"------------------------------------------------------"
" Determine number of days in the month "
"------------------------------------------------------"
CONCATENATE LV_YEAR LV_MONTH '01' INTO LV_DATE.
CALL FUNCTION 'SLS_MISC_GET_LAST_DAY_OF_MONTH'
EXPORTING
DAY_IN = LV_DATE
IMPORTING
LAST_DAY_OF_MONTH = LV_DATE.
LV_DAYS = LV_DATE+6(2). "Extract day part → last day of month
"------------------------------------------------------"
" Date Nodes (Level 04) "
"------------------------------------------------------"
DO LV_DAYS TIMES.
LV_DAY = SY-INDEX.
CONCATENATE LV_YEAR LV_MONTH LV_DAY INTO LV_DATE_KEY.
WA_NODE-TYPE = 'P'.
WA_NODE-ID = LV_DATE_KEY.
CONCATENATE LV_DAY '.' LV_MONTH '.' LV_YEAR INTO WA_NODE-NAME.
WA_NODE-TLEVEL = '04'.
WA_NODE-NLENGTH = STRLEN( WA_NODE-NAME ).
WA_NODE-COLOR = '06'.
APPEND WA_NODE TO IT_NODE.
CLEAR WA_NODE.
ENDDO.
ENDDO.
ENDDO.
ENDLOOP.
"------------------------------------------------------------"
" Display the Tree Output "
"------------------------------------------------------------"
CALL FUNCTION 'RS_TREE_CONSTRUCT'
TABLES
NODETAB = IT_NODE.
CALL FUNCTION 'RS_TREE_LIST_DISPLAY'
EXPORTING
CALLBACK_PROGRAM = SY-REPID.</code></pre><P class="" align="left"><STRONG>Output:</STRONG><BR /><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="tree.png" style="width: 812px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/339971i42BB7569A9EF68CF/image-dimensions/812x534/is-moderation-mode/true?v=v2" width="812" height="534" role="button" title="tree.png" alt="tree.png" /></span><BR /><STRONG>OOPS Approach:<BR /></STRONG></P><pre class="lia-code-sample language-abap"><code>TABLES: MARA, BKPF.
*---------------------------------------------------------------------*
* Data Declarations
*---------------------------------------------------------------------*
"ALV Tree objects
DATA: GO_TREE TYPE REF TO CL_GUI_ALV_TREE,
GO_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER.
"ALV field catalog and layout
DATA: GT_FIELDCAT TYPE LVC_T_FCAT,
GS_FIELDCAT TYPE LVC_S_FCAT,
GS_LAYOUT TYPE LVC_S_LAYO.
"Output structure for tree text
TYPES: BEGIN OF TY_OUTPUT,
COLUMN1 TYPE CHAR255, "Single text column for tree nodes
END OF TY_OUTPUT.
DATA: GT_OUTPUT TYPE TABLE OF TY_OUTPUT,
GS_OUTPUT TYPE TY_OUTPUT.
"Variables used for Year → Month → Date hierarchy
DATA: LV_YEAR TYPE GJAHR,
LV_MONTH TYPE NUMC2,
LV_DATE TYPE DATUM,
LV_LAST_DATE TYPE DATUM,
LV_DAYS TYPE I,
LV_DAY TYPE NUMC2,
LV_YEAR_KEY TYPE LVC_NKEY,
LV_MONTH_KEY TYPE LVC_NKEY,
LV_DATES_LINE TYPE STRING.
"Node layout (folder / item)
DATA: LS_NODE_LAYOUT TYPE LVC_S_LAYN.
"Year range for hierarchy
SELECT-OPTIONS: S_GJAHR FOR BKPF-GJAHR DEFAULT '2021' TO '2025'.
*---------------------------------------------------------------------*
* Selection Screen Trigger
*---------------------------------------------------------------------*
START-OF-SELECTION.
CALL SCREEN 100. "Call main screen
*---------------------------------------------------------------------*
* PBO: Set status and create tree
*---------------------------------------------------------------------*
MODULE STATUS_0100 OUTPUT.
SET PF-STATUS 'ZSTANDARD'.
"Create the tree only once
IF GO_CONTAINER IS INITIAL.
PERFORM CREATE_AND_FILL_TREE.
ENDIF.
ENDMODULE.
*---------------------------------------------------------------------*
* PAI: Handle user commands
*---------------------------------------------------------------------*
MODULE USER_COMMAND_0100 INPUT.
CASE SY-UCOMM.
WHEN 'BACK' OR 'EXIT' OR 'CANCEL'.
"Release frontend controls
PERFORM FREE_RESOURCES.
LEAVE TO SCREEN 0.
ENDCASE.
ENDMODULE.
*---------------------------------------------------------------------*
* Create container, tree control, root node and load hierarchy
*---------------------------------------------------------------------*
FORM CREATE_AND_FILL_TREE.
"Create custom container inside screen element 'CONTAINER'
CREATE OBJECT GO_CONTAINER
EXPORTING
CONTAINER_NAME = 'CONTAINER'.
"Build ALV field catalog
PERFORM BUILD_FIELDCAT.
"Create ALV tree control
CREATE OBJECT GO_TREE
EXPORTING
PARENT = GO_CONTAINER
NODE_SELECTION_MODE = CL_GUI_COLUMN_TREE=>NODE_SEL_MODE_SINGLE
ITEM_SELECTION = 'X'
EXCEPTIONS
OTHERS = 1.
"Bind output table and field catalog to tree
CALL METHOD GO_TREE->SET_TABLE_FOR_FIRST_DISPLAY
CHANGING
IT_OUTTAB = GT_OUTPUT
IT_FIELDCATALOG = GT_FIELDCAT.
"---------------------------------------------------------------*
" Create Root Node (DATE HIERARCHY)
"---------------------------------------------------------------*
CLEAR: LS_NODE_LAYOUT, GS_OUTPUT.
LS_NODE_LAYOUT-ISFOLDER = 'X'.
LS_NODE_LAYOUT-N_IMAGE = '@AV@'.
LS_NODE_LAYOUT-EXP_IMAGE = '@AV@'.
GS_OUTPUT-COLUMN1 = 'DATE HIERARCHY'.
"Add root node
CALL METHOD GO_TREE->ADD_NODE
EXPORTING
I_RELAT_NODE_KEY = '' "Root level
I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD
IS_OUTTAB_LINE = GS_OUTPUT
IS_NODE_LAYOUT = LS_NODE_LAYOUT
IMPORTING
E_NEW_NODE_KEY = LV_YEAR_KEY.
"Build full tree under root node
PERFORM BUILD_TREE_NODES USING LV_YEAR_KEY.
"Auto-expand root node
CALL METHOD GO_TREE->EXPAND_NODE
EXPORTING
I_NODE_KEY = LV_YEAR_KEY.
CALL METHOD GO_TREE->FRONTEND_UPDATE.
ENDFORM.
*---------------------------------------------------------------------*
* Create field catalog for ALV tree
*---------------------------------------------------------------------*
FORM BUILD_FIELDCAT.
CLEAR GS_FIELDCAT.
GS_FIELDCAT-FIELDNAME = 'COLUMN1'.
GS_FIELDCAT-COLTEXT = 'Description'.
GS_FIELDCAT-OUTPUTLEN = 255.
APPEND GS_FIELDCAT TO GT_FIELDCAT.
ENDFORM.
*---------------------------------------------------------------------*
* Build YEAR → MONTH → DAY hierarchy inside ALV Tree
*---------------------------------------------------------------------*
FORM BUILD_TREE_NODES USING IV_ROOT_KEY TYPE LVC_NKEY.
DATA: LV_PARENT_YEAR TYPE LVC_NKEY,
LV_PARENT_MONTH TYPE LVC_NKEY,
LV_MONTH_NAME TYPE STRING,
LV_CHUNK TYPE STRING,
LV_CHUNK_COUNT TYPE I,
GV_GROUP_SIZE TYPE I VALUE 10, "Group 10 days per line
LV_DATE_STRING TYPE STRING.
"Loop through selected year range
LOOP AT S_GJAHR.
DO.
LV_YEAR = S_GJAHR-LOW + SY-INDEX - 1.
IF LV_YEAR > S_GJAHR-HIGH.
EXIT.
ENDIF.
"---------------------------------------------------------------*
" Create YEAR Node
"---------------------------------------------------------------*
CLEAR: LS_NODE_LAYOUT, GS_OUTPUT.
LS_NODE_LAYOUT-ISFOLDER = 'X'.
LS_NODE_LAYOUT-N_IMAGE = '@AV@'.
LS_NODE_LAYOUT-EXP_IMAGE = '@AV@'.
GS_OUTPUT-COLUMN1 = |Year: { LV_YEAR }|.
CALL METHOD GO_TREE->ADD_NODE
EXPORTING
I_RELAT_NODE_KEY = IV_ROOT_KEY "Attach to root
I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD
IS_OUTTAB_LINE = GS_OUTPUT
IS_NODE_LAYOUT = LS_NODE_LAYOUT
IMPORTING
E_NEW_NODE_KEY = LV_PARENT_YEAR.
"---------------------------------------------------------------*
" Create MONTH Nodes under each Year
"---------------------------------------------------------------*
DO 12 TIMES.
LV_MONTH = SY-INDEX.
"Month name mapping
CASE LV_MONTH.
WHEN 1. LV_MONTH_NAME = 'January'.
WHEN 2. LV_MONTH_NAME = 'February'.
WHEN 3. LV_MONTH_NAME = 'March'.
WHEN 4. LV_MONTH_NAME = 'April'.
WHEN 5. LV_MONTH_NAME = 'May'.
WHEN 6. LV_MONTH_NAME = 'June'.
WHEN 7. LV_MONTH_NAME = 'July'.
WHEN 8. LV_MONTH_NAME = 'August'.
WHEN 9. LV_MONTH_NAME = 'September'.
WHEN 10. LV_MONTH_NAME = 'October'.
WHEN 11. LV_MONTH_NAME = 'November'.
WHEN 12. LV_MONTH_NAME = 'December'.
ENDCASE.
CLEAR: LS_NODE_LAYOUT, GS_OUTPUT.
LS_NODE_LAYOUT-ISFOLDER = 'X'.
LS_NODE_LAYOUT-N_IMAGE = '@2L@'.
LS_NODE_LAYOUT-EXP_IMAGE = '@2L@'.
GS_OUTPUT-COLUMN1 = LV_MONTH_NAME.
"Add Month node
CALL METHOD GO_TREE->ADD_NODE
EXPORTING
I_RELAT_NODE_KEY = LV_PARENT_YEAR
I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD
IS_OUTTAB_LINE = GS_OUTPUT
IS_NODE_LAYOUT = LS_NODE_LAYOUT
IMPORTING
E_NEW_NODE_KEY = LV_PARENT_MONTH.
"-----------------------------------------------------------*
" Determine last day of month
"-----------------------------------------------------------*
CONCATENATE LV_YEAR LV_MONTH '01' INTO LV_DATE.
CALL FUNCTION 'LAST_DAY_OF_MONTHS'
EXPORTING
DAY_IN = LV_DATE
IMPORTING
LAST_DAY_OF_MONTH = LV_LAST_DATE.
LV_DAYS = LV_LAST_DATE+6(2). "Extract number of days
"-----------------------------------------------------------*
" Add DAY Nodes grouped (10 days per node)
"-----------------------------------------------------------*
CLEAR: LV_CHUNK, LV_CHUNK_COUNT.
DO LV_DAYS TIMES.
LV_DAY = SY-INDEX.
"Format date string: DD.MM.YYYY
LV_DATE_STRING = |{ LV_DAY WIDTH = 2 }.{ LV_MONTH WIDTH = 2 }.{ LV_YEAR }|.
"Build chunk of 10 dates
IF LV_CHUNK IS INITIAL.
LV_CHUNK = LV_DATE_STRING.
ELSE.
CONCATENATE LV_CHUNK LV_DATE_STRING INTO LV_CHUNK SEPARATED BY SPACE.
ENDIF.
ADD 1 TO LV_CHUNK_COUNT.
"Add one group node after every 10 days OR last day
IF LV_CHUNK_COUNT >= GV_GROUP_SIZE OR LV_DAY = LV_DAYS.
CLEAR: LS_NODE_LAYOUT, GS_OUTPUT.
LS_NODE_LAYOUT-ISFOLDER = ''. "Leaf node
LS_NODE_LAYOUT-N_IMAGE = '@3C@'.
GS_OUTPUT-COLUMN1 = LV_CHUNK.
"Add day-chunk node
CALL METHOD GO_TREE->ADD_NODE
EXPORTING
I_RELAT_NODE_KEY = LV_PARENT_MONTH
I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD
IS_OUTTAB_LINE = GS_OUTPUT
IS_NODE_LAYOUT = LS_NODE_LAYOUT.
CLEAR: LV_CHUNK, LV_CHUNK_COUNT.
ENDIF.
ENDDO.
ENDDO. "End Month Loop
ENDDO.
ENDLOOP.
ENDFORM.
*---------------------------------------------------------------------*
* Release frontend controls
*---------------------------------------------------------------------*
FORM FREE_RESOURCES.
IF GO_TREE IS BOUND.
CALL METHOD GO_TREE->FREE.
FREE GO_TREE.
ENDIF.
IF GO_CONTAINER IS BOUND.
CALL METHOD GO_CONTAINER->FREE.
FREE GO_CONTAINER.
ENDIF.
ENDFORM.</code></pre><P class="" align="left"><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="date.jpg" style="width: 619px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/339973i6AA78918170CB894/image-dimensions/619x242/is-moderation-mode/true?v=v2" width="619" height="242" role="button" title="date.jpg" alt="date.jpg" /></span></STRONG></P><P><STRONG> Conclusion:</STRONG><BR />This solution showcases a practical and user-friendly way to visualize date structures by building a dynamic Year–Month–Day hierarchy using the ALV Tree control. By grouping daily entries and leveraging container-based GUI elements, the approach delivers a clean, scalable, and intuitive navigation experience. It also demonstrates how classic ABAP techniques—selection screens, tree controls, and month/day calculations—can be combined to create interactive UI components that enhance data exploration within SAP GUI.<STRONG><BR /><BR /></STRONG></P>2025-12-09T11:37:56.809000+01:00https://community.sap.com/t5/abap-blog-posts/collective-value-helps-in-rap-v2-and-v4-implementation-guide-part-2/ba-p/14286757Collective Value Helps in RAP: V2 and V4 Implementation Guide - Part 22025-12-09T15:35:14.655000+01:00Abhinav_Royhttps://community.sap.com/t5/user/viewprofilepage/user-id/1109<P><SPAN>In <A href="https://community.sap.com/t5/abap-blog-posts/collective-value-helps-in-rap-v2-and-v4-implementation-guide-part-1/ba-p/14271885" target="_blank">Part 1</A> of this series, we explored the fundamentals of <STRONG>Collective Value Helps</STRONG> in RAP, covering implementation patterns across OData V2 and V4 service bindings. The community response has been overwhelming, with particular interest in hierarchical implementations for complex business scenarios.</SPAN></P><P><SPAN>While CDS hierarchies are extensively documented in the SAP ecosystem and widely used for representing parent-child relationships across business objects, a critical implementation gap exists: <STRONG>there are virtually no practical examples of incorporating hierarchical display patterns within Collective Value Helps.</STRONG> <STRONG>Part 2</STRONG> bridges this gap by demonstrating how to seamlessly integrate hierarchical search templates into the collective value help framework we built in Part 1.<BR /><BR /></SPAN><SPAN><STRONG>Watch the demonstration video below</STRONG> to see hierarchical value helps in action, including how they work alongside existing flat list search templates, in a Collective Value Help:<BR /><BR /><div class="video-embed-center video-embed"><iframe class="embedly-embed" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F2Zt9gykfJOE%3Ffeature%3Doembed&display_name=YouTube&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D2Zt9gykfJOE&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F2Zt9gykfJOE%2Fhqdefault.jpg&type=text%2Fhtml&schema=youtube" width="400" height="225" scrolling="no" title="SAP Community Hierarchical Variant - CVH" frameborder="0" allow="autoplay; fullscreen; encrypted-media; picture-in-picture;" allowfullscreen="true"></iframe></div><BR /></SPAN></P><P><FONT color="#339966"><U><SPAN>System Requirements</SPAN></U></FONT></P><P><FONT color="#339966"><EM>**Hierarchical Value Help Dialogs require: **</EM></FONT></P><P><FONT color="#339966"><EM>**SAP S/4HANA Cloud**<BR /></EM><EM>--Minimum Release: 2311<BR /></EM><EM>--Protocol: OData V4 service binding</EM></FONT></P><P><FONT color="#339966"><EM>**SAP S/4HANA On-Premise/Private Edition: **<BR /></EM><EM>--Minimum Release : S/4HANA 2025 onwards<BR /></EM><EM>--Protocol: OData V4 service binding</EM></FONT></P><P><FONT color="#339966"><EM>**Important: ** OData V2 does not support hierarchical</EM> visualization <EM>out of the box via CDS Hierarchy due to protocol limitations. CDS hierarchical patterns require OData V4.</EM></FONT></P><P><STRONG>CDS Hierarchies: Foundation for Hierarchical Value Helps</STRONG></P><P>CDS (Core Data Services) hierarchies are well-established patterns in the SAP landscape for representing parent-child relationships. SAP provides comprehensive documentation and numerous community resources for learning hierarchy fundamentals:</P><UL><LI><SPAN><A href="https://help.sap.com/docs/abap-cloud/abap-data-models/hierarchy-definition" target="_blank" rel="noopener noreferrer">Hierarchy Definition | SAP Help Portal</A></SPAN></LI><LI><SPAN><A href="https://help.sap.com/docs/abap-cloud/abap-rap/treeview-with-read-only-capability?version=sap_btp" target="_blank" rel="noopener noreferrer">Treeviews with Read-Only Capabilities | SAP Help Portal</A></SPAN></LI><LI><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/cds-how-to-define-hierarchy-view/ba-p/13758059" target="_self">SAP Community: CDS Hierarchy Articles</A></LI></UL><P><STRONG>This article focuses specifically on utilizing CDS hierarchies within RAP-compliant value helps</STRONG> and demonstrating how to incorporate hierarchical search templates alongside the flat templates created in Part 1.</P><P><STRONG>Key Use Case:</STRONG> Hierarchies are particularly powerful in domains like Asset Management, where technical objects form complex parent-child structures that users need to navigate when making selections.</P><P><STRONG>Business Context: Asset Management-> Hierarchical Relationships</STRONG></P><P>In Asset Management, technical objects naturally form hierarchical structures that reflect real-world installations and organizational relationships:</P><P><STRONG>Functional Location Hierarchies:</STRONG></P><UL><LI>Parent functional locations contain child functional locations</LI><LI>Example: TATM → TATM-UT3 → TATM-UT3-001</LI><LI>Represents physical plant structure and organizational grouping</LI></UL><P><STRONG>Equipment Hierarchies:</STRONG></P><UL><LI>Equipment can be installed under functional locations</LI><LI>Equipment can be installed under other equipment (sub-assemblies)</LI><LI>Example: Main equipment (11947458) contains sub-equipment (11947627)</LI></UL><P><STRONG>Mixed Hierarchies:</STRONG></P><UL><LI>Equipment installed at functional locations</LI><LI>Sub-equipment installed under main equipment</LI><LI>Creates complex parent-child navigation <SPAN>requirements</SPAN></LI></UL><P><SPAN>A sample Hierarchy in Asset Management:<BR /></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Transaction: IH01 - Structure List" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350113i6B449DCB4E2430AE/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_0-1765275145771.png" alt="Transaction: IH01 - Structure List" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Transaction: IH01 - Structure List</span></span></P><P><STRONG>Why Hierarchical Value Helps Matter:</STRONG></P><P>When users select technical objects in business processes (work orders, maintenance notifications, asset transfers), they need to:</P><UL><LI>Understand the installation hierarchy</LI><LI>Navigate parent-child relationships visually</LI><LI>Select objects while seeing their organizational context</LI><LI>Identify relationships between equipment and functional locations</LI></UL><P>Standard flat list value helps lose this critical hierarchical context, making object selection difficult and error-prone in complex asset structures.</P><P><SPAN>Implementation: Building the Hierarchical VDM Model </SPAN></P><P><STRONG>Step 1: Interface View (I-View) with Parent Association</STRONG></P><P>The foundation of any CDS hierarchy is a self-association that establishes the parent-child relationship.<BR /><BR /></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="I-View" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350176i90BA3A7BE43AA7E5/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_0-1765276862163.png" alt="I-View" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">I-View</span></span></P><P><STRONG>Critical Elements:</STRONG></P><UL><LI><STRONG>Self-Association _ParentNode:</STRONG> Establishes the many-to-one parent relationship</LI><LI><STRONG>Cardinality [0..1]:</STRONG> Each node has either zero (root) or one parent</LI><LI><STRONG>Join Condition:</STRONG> Links child's SuperiorTechnicalObject to parent's TechnicalObject</LI></UL><P>This I-View serves as the data foundation, providing the parent-child relationship that the hierarchy view will consume.</P><P><STRONG>Step 2: Hierarchy View Definition</STRONG></P><P>The hierarchy view transforms the I-View's parent association into an actual hierarchical structure with defined traversal rules.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Hierarchy View" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350177i06598EFF9C04E570/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_1-1765276926694.png" alt="Hierarchy View" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Hierarchy View</span></span></P><P><STRONG>Critical Hierarchy Annotations:</STRONG></P><OL><LI><STRONG>source ZAR_I_TechObjHierarchy:</STRONG> References the I-View containing the parent association</LI><LI><STRONG>child to parent association _ParentNode:</STRONG> Specifies which association defines the hierarchy</LI><LI><STRONG>start where SuperiorTechnicalObject is initial:</STRONG> Defines root nodes (no parent = top of hierarchy)</LI><LI><STRONG>siblings order by TechnicalObject:</STRONG> Sorts nodes at the same level</LI><LI><STRONG>multiple parents not allowed:</STRONG> Enforces strict tree structure (each node has max one parent)</LI></OL><P>This hierarchy view establishes the traversal logic and structural rules for displaying the parent-child relationships.</P><P> </P><P><STRONG>Step 3: Consumption (C-View) Definition </STRONG></P><P>The consumption view serves as the bridge between the CDS hierarchy and the collective value help framework. It exposes the hierarchy as a searchable value help provider while maintaining the hierarchical data structure.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="C-View" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350178i1A66EA4BBEADFDAB/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_2-1765277179651.png" alt="C-View" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">C-View</span></span></P><P><STRONG>Critical Annotations:<BR /></STRONG></P><OL><LI><STRONG>@ObjectModel.supportedCapabilities</STRONG><BR /><STRONG>#VALUE_HELP_PROVIDER</STRONG>: Enables this view to provide value help data<BR /><STRONG>#SEARCHABLE_ENTITY</STRONG>: Allows search functionality within the value help dialog<BR />These capabilities are essential for user interaction</LI><LI><STRONG><a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1599241">@odata</a>.hierarchy.recursiveHierarchy: [{ entity.name: 'ZAR_I_TechObjHierarchyView' }]</STRONG><BR />THE CRITICAL HIERARCHICAL LINK<BR /><STRONG>Note:</STRONG> The entity name should reference the <STRONG>Hierarchy View</STRONG> (from Step 2), not the I-View or C-View itself.<BR />Points to the CDS hierarchy view created in Step 2<BR />Instructs OData V4 service to use hierarchical structure<BR />Without this annotation, hierarchy won't display in value help</LI><LI><STRONG>association of many to one ... as _ParentNode</STRONG><BR />Recreates the parent association in the consumption layer<BR />Must match the join conditions from the I-View<BR />Required for OData V4 hierarchy metadata generation<BR />Links both TechnicalObject AND TechObjIsEquipOrFuncnLoc (composite key)</LI></OL><P><STRONG><BR />Step 4: Including Hierarchical Template in Collective Value Help<BR /><BR /></STRONG>Now we integrate the hierarchical search template into our existing collective value help framework from Part 1:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="CVH V2 Metadata Extension" style="width: 742px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350276iA574D0E8B7D628A7/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_0-1765284016068.png" alt="CVH V2 Metadata Extension" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">CVH V2 Metadata Extension</span></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="CVH V4 Metadata Extension" style="width: 785px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350277i534D6BAD5BEC6D23/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_1-1765284037633.png" alt="CVH V4 Metadata Extension" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">CVH V4 Metadata Extension</span></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Service Definition" style="width: 698px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350278iAF30882ADD5E2AB7/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_2-1765284142136.png" alt="Service Definition" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Service Definition</span></span></P><P><STRONG>OData V2 Service Binding: The Limitation</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Service Binding OData V2" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350279i5E8C2D9DE435F840/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_3-1765284199980.png" alt="Service Binding OData V2" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Service Binding OData V2</span></span></P><P><STRONG>This eliminates the possibility of incorporating hierarchical search templates via CDS hierarchy in V2 collective value helps.</STRONG> OData V2's protocol limitations prevent hierarchy visualization in value help dialogs</P><P><STRONG><BR />OData V4 Service Binding: The Solution Path</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Service Binding OData V4" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350280i61F5F556EF135F3C/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_0-1765284407687.png" alt="Service Binding OData V4" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Service Binding OData V4</span></span></P><P>The V4 service binding successfully exposes the hierarchical template without errors.</P><H3 id="toc-hId-1895640971"><BR />The Problem - Flat List Display</H3><P class="">Even with a properly defined hierarchy view exposed in V4, the initial preview reveals an unexpected result:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Flat List Display (as opposed to expected Hierarchical display)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350282i95E36C0C3779F7B5/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_1-1765284477750.png" alt="Flat List Display (as opposed to expected Hierarchical display)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Flat List Display (as opposed to expected Hierarchical display)</span></span></P><P class=""><STRONG><BR />The Problem:<BR /></STRONG><SPAN>Despite having a hierarchical CDS view, the value help displays data as a </SPAN><STRONG>flat list</STRONG><SPAN> without any parent-child visualization. Users see individual records but lose all hierarchical context.</SPAN></P><P class=""><STRONG>Why This Happens:<BR /></STRONG><SPAN>Creating a CDS hierarchy view is necessary but </SPAN><STRONG>not sufficient</STRONG><SPAN> for hierarchical display in value helps. The RAP framework requires <EM>explicit UI presentation instructions</EM> to render hierarchy in the value help dialog.</SPAN></P><P class=""><STRONG>The Missing Piece:</STRONG> The framework needs explicit instructions via presentation variant annotations to understand that this data should be rendered as a hierarchy tree, not a flat table. Without these annotations, OData V4 treats the hierarchy view as just another data source.<BR /><BR /><STRONG>The Solution - Presentation Variant Annotations</STRONG><BR />To provision hierarchical display in value helps, we must add specific presentation variant annotations that declare hierarchical visualization intent.<BR /><BR /><U>Consumption View (C-View) Annotations</U></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="C-View (Presentation Variant Added)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350296i16DB4408E668ECBE/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_0-1765284859373.png" alt="C-View (Presentation Variant Added)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">C-View (Presentation Variant Added)</span></span></P><P>A presentation variant annotation needs to be included here which will contain the InitialExpansionLevel for the hierarchy and a property RecursiveHierarchyQualifier.</P><P class=""><STRONG>RecursiveHierarchyQualifier</STRONG> - This annotation contains a string with the name of the hierarchy view and make possible that the data is then shown on UI as tree table. The projection view should also have the annotation<BR /><BR /><SPAN><STRONG>InitialExpansionLevel</STRONG> - This annotation indicates up to which level a display hierarchy shall be initially expanded.</SPAN><BR /><BR /><U>Collective Value Help Metadata Extension</U></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="CVH V4 Metadata Extension (Presentation Variant annotation added)" style="width: 668px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350312i4D5761FE4F127D32/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_0-1765285284629.png" alt="CVH V4 Metadata Extension (Presentation Variant annotation added)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">CVH V4 Metadata Extension (Presentation Variant annotation added)</span></span></P><P>A <SPAN><STRONG>presentationVariantQualifier</STRONG> annotation needs to be included here, which should've the same value as the Qualifier in the C-View, i.e., '<STRONG>HIERARCHY</STRONG>', in this case. This annotation indicates how the value help result should be displayed.<BR /><BR /></SPAN></P><P><SPAN><STRONG>The Result: Hierarchical Value Help in Action</STRONG><BR /></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Hierarchical value help display" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350315i8BC8724DE1A9A35B/image-size/large?v=v2&px=999" role="button" title="Abhinav_Roy_1-1765285480130.png" alt="Hierarchical value help display" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Hierarchical value help display</span></span></P><P><STRONG><U>Success! The hierarchical variant now displays</U></STRONG>:</P><UL><LI>Parent-child relationships visualized as tree structure</LI><LI>Expand/collapse controls for navigation</LI><LI>Indentation showing hierarchy levels</LI><LI>Seamless integration with flat templates from Part 1</LI><LI>Full hierarchy traversal in value help dialog</LI></UL><P><STRONG><U>User Experience - End Users can now</U></STRONG>:</P><UL><LI>Switch between flat and hierarchical search templates</LI><LI>Navigate parent-child relationships visually</LI><LI>Expand/collapse hierarchy nodes and even the entire Tree View</LI><LI>Select objects while understanding their organizational context</LI><LI>See equipment installation hierarchies and functional location structures</LI></UL><P><FONT size="5"><STRONG>Key Takeaways: When to Use Hierarchical Collective Value Helps<BR /></STRONG></FONT><BR /><U><STRONG>Use Hierarchical Patterns When</STRONG></U>:</P><UL><LI>Parent-Child Relationships Matter: Business objects naturally form hierarchies (org structures, location hierarchies etc)</LI><LI>Context Aids Selection: Users need to see relationships to make correct selections</LI><LI>Navigation is Important: Users need to browse up/down hierarchies during selection</LI><LI>OData V4 is Available: V2 protocol does not support hierarchy visualization</LI></UL><P><U><STRONG>Implementation Checklist</STRONG></U>:</P><UL><LI>Define I-View with self-association (_ParentNode)</LI><LI>Create hierarchy view with traversal rules (start where, siblings order by)</LI><LI>Use OData V4 service binding (V2 not supported)</LI><LI>Add presentation variant in C-View</LI><LI>Reference presentation variant in CVH metadata extension</LI><LI>Test expand/collapse and hierarchy navigation</LI></UL><P><U><STRONG>Key Implementation points</STRONG></U>:</P><UL><LI>Cardinality Enforcement: multiple parents not allowed ensures tree structure</LI><LI>Root Node Definition: start where clause correctly identifies top-level nodes</LI><LI>Presentation Variant annotation must be added in C-View and CVH metadata</LI><LI>Qualifier Consistency: Same qualifier in C-View and CVH metadata</LI></UL><P><BR /><FONT size="5"><STRONG>Series Conclusion</STRONG></FONT><BR />This two-part series has explored the complete spectrum of collective value helps in RAP:<BR /><STRONG><U>Part 1 established the foundation</U></STRONG>:</P><OL><LI>Basic collective value help concepts and structure</LI><LI>Implementation across OData V2 and V4 service bindings</LI><LI>Service binding architectural differences</LI><LI>Nested value help workarounds</LI><LI>Multi-dimensional search capabilities</LI></OL><P><STRONG><U>Part 2 extended to advanced patterns</U></STRONG>:</P><OL><LI>Hierarchical CDS view construction</LI><LI>VDM model for hierarchy-enabled value helps</LI><LI>OData V2 protocol limitations</LI><LI>Presentation variant configuration for hierarchy visualization</LI><LI>Seamless integration of flat and hierarchical search templates</LI></OL><P>Together, these patterns enable user-centric, multi-criteria search capabilities that leverage RAP's full value help framework while maintaining clean architectural separation and reusability.</P><P><STRONG>Key Architectural Insight</STRONG>:<BR />Collective value helps in RAP provide a powerful, user-centric approach to value help management by enabling multi-criteria search through a single, reusable model. The addition of hierarchical display patterns extends this capability to complex business scenarios requiring parent-child navigation—delivering a comprehensive search experience that adapts to diverse user needs.<BR /><BR /><FONT size="5"><STRONG>Conclusion</STRONG></FONT><BR />Hierarchical collective value helps represent the convergence of RAP's value help framework with CDS hierarchy capabilities, enabling rich, context-aware search experiences for complex business objects. While implementation requires careful attention to presentation variant configuration and V4 protocol requirements, the result is a powerful pattern applicable across any SAP domain where parent-child relationships drive user decision-making.<BR />Whether you're building asset management applications, organizational hierarchies, material master navigation, or any scenario requiring hierarchical context during selection, this pattern provides the foundation for delivering intuitive, efficient user experiences.<BR />The combination of CDS hierarchies, collective value helps, and RAP's presentation variant framework creates a powerful combination for solving complex data selection challenges-no custom coding required, just optimal usage of key annotations.<BR />Thank you for following this two-part series. I welcome your feedback, and experiences implementing collective value helps in your own RAP applications.</P>2025-12-09T15:35:14.655000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/you-are-standing-in-an-open-field-inside-sap-gui/ba-p/14287253You Are Standing in an Open Field... Inside SAP GUI2025-12-09T17:51:44.456000+01:00Alice_Vhttps://community.sap.com/t5/user/viewprofilepage/user-id/609259<P class=""><EM><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="unnamed (4).jpg" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350411i159705E00B82B76C/image-size/large/is-moderation-mode/true?v=v2&px=999" role="button" title="unnamed (4).jpg" alt="unnamed (4).jpg" /></span></EM></P><P> </P><P class=""><EM>How I ported Zork to ABAP in one day and made 46-year reunion of two mainframe legends possible.</EM></P><P class="">1979 was quite a year for the mainframe: In Germany, <STRONG>SAP </STRONG>released <STRONG>R/2</STRONG>, the integrated ERP system that would define enterprise computing. In Massachusetts, <STRONG>Infocom </STRONG>was founded to commercialize <STRONG>Zork</STRONG>, the text adventure born on MIT's PDP-10 mainframes.</P><P class="">For 46 years, they ran on parallel tracks. Until last month.</P><P class=""><STRONG>Microsoft </STRONG><A class="" href="https://opensource.microsoft.com/blog/2025/11/20/preserving-code-that-shaped-generations-zork-i-ii-and-iii-go-open-source" target="_self" rel="nofollow noopener noreferrer">released the original source code</A> for Zork I. The stars aligned. It was time for a family reunion.</P><P class="">I got nostalgic. I wanted to play Zork I: The Great Underground Empire. But I didn't want to play it in a browser or a terminal. I wanted to play it where I spend my time: In SAP GUI.</P><P class="">So, I decided to port the Z-Machine (Infocom's Virtual Machine) into SAP S/4HANA.</P><P class="">The Z-Namespace destiny... you knew it. In SAP development, every custom object must start with the letter Z: <EM>(Also Y, but Y is not used widely. And no one knows why Y is not used)</EM></P><UL><LI>The Machine: <STRONG>Z</STRONG>-Machine.</LI><LI>The Transaction: ZORK.</LI><LI>The Package: $ZORK.</LI></UL><P class="">So it felt like it was meant to be here.</P><H3 id="ember770" id="toc-hId-1895665953">Building a VM in One Day (The "How")</H3><P class="">"<EM>Alice</EM>," you say, "<EM>Writing a Virtual Machine in ABAP takes weeks of reading bit-level specs.</EM>"</P><P class="">It took <STRONG>one day</STRONG>.</P><P class="">And I wrote almost none of it:</P><DIV class=""> </DIV><DIV class=""><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ZORK T-CODE in SAP GUI" style="width: 872px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350406i8DBE61F8B148BACE/image-size/large?v=v2&px=999" role="button" title="zork-abap.png" alt="ZORK T-CODE in SAP GUI" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">ZORK T-CODE in SAP GUI</span></span></DIV><H3 id="ember775" id="toc-hId-1699152448">99% Vibe coded</H3><P class="">I used <STRONG>VSP (Vibing-Steampunk)</STRONG> — my open-source bridge that gives <STRONG>Claude</STRONG> (or Copilot/Codex/Mistral Vibe - any other Assistant) direct access to the SAP system via MCP. I treated the AI not as a chatbot, but as a Senior ABAP Developer who loves retro specs.</P><P class="">Here is what happened when my Z-Machine crashed on the first turn:</P><P class=""><STRONG>Me:</STRONG> "It crashes when I try to LOOK. Plz <STRONG>debug</STRONG>."</P><P class="">Claude didn't guess. Using VSP, Claude:</P><P class=""> </P><OL><LI><STRONG>Set a breakpoint</STRONG> in the ABAP code.</LI><LI><STRONG>Ran the game</STRONG> inside SAP.</LI><LI><STRONG>Inspected the memory</STRONG> (finding a Big-Endian vs Little-Endian mismatch in the object table).</LI><LI><STRONG>Fixed the code.</STRONG></LI></OL><P> </P><P class="">This isn't just generating text. This is <STRONG>Digital Archaeology</STRONG> assisted by <STRONG>Artificial Intelligence</STRONG>.</P><H3 id="ember782" id="toc-hId-1502638943">Why This Matters</H3><P class="">I now have Zork running in S/4HANA.</P><P class="">But the real story isn't the game. It's the capability.</P><P class="">If an AI agent can read a 1980s technical spec, navigate a custom ABAP stack, and debug runtime errors to reunite two pieces of 1979 history...</P><P class="">...imagine what it can do for your 2005 legacy code ^_^ (Yes, even with ECC).</P><UL><LI>The Repo (ZORK-ABAP): <A class="" href="https://github.com/oisee/zork-abap" target="_self" rel="nofollow noopener noreferrer">https://github.com/oisee/zork-abap</A></LI><LI>The Tool (VSP): <A class="" href="https://github.com/oisee/vibing-steampunk" target="_self" rel="nofollow noopener noreferrer">https://github.com/oisee/vibing-steampunk</A> - ADT-to-MCP bridge.</LI></UL><P class=""><STRONG>Credits:</STRONG></P><UL><LI><STRONG>Infocom (1979)</STRONG> for the Z-Machine.</LI><LI><STRONG>SAP (1979)</STRONG> for the R/2 legacy that led us here.</LI><LI><STRONG>Graham Nelson </STRONG>for the Z-Machine Standards Document.</LI><LI><STRONG>Claude (2025)</STRONG> for writing the code.</LI></UL><P class=""><EM>P.S. West of House. There is a transport request here. </EM></P><P class="">#SAP #ABAP #Zork #RetroGaming #AI #MCP #DigitalArchaeology #OpenSource #Microsoft</P><P class="">Shout out to <A class="" href="https://www.linkedin.com/in/shanselman/" target="_blank" rel="noopener nofollow noreferrer">Scott Hanselman</A>: Tnx for driving Open Source initiative ^_^</P>2025-12-09T17:51:44.456000+01:00https://community.sap.com/t5/enterprise-architecture-blog-posts/hana-powered-amdp-crud-framework-a-complete-workflow-from-adt-development/ba-p/14286670HANA-Powered AMDP CRUD Framework: A Complete Workflow from ADT Development to ABAP Execution2025-12-09T19:16:17.595000+01:00rameshreddy_khttps://community.sap.com/t5/user/viewprofilepage/user-id/880970<P><STRONG><SPAN>1.Introduction</SPAN></STRONG><SPAN> </SPAN></P><P><SPAN>In modern SAP applications, performance-critical database operations can be executed directly in </SPAN><SPAN>SAP HANA</SPAN><SPAN> using </SPAN><SPAN>AMDP (ABAP Managed Database Procedures)</SPAN><SPAN>. This approach allows complex CRUD (Create, Read, Update, Delete) operations to be processed efficiently in HANA while keeping the ABAP code clean and maintainable.</SPAN><SPAN> </SPAN><SPAN>In this guide, we explain how to implement a full </SPAN><SPAN>CRUD solution</SPAN><SPAN> using an AMDP class (</SPAN><SPAN>ZCRUD_PROCEDURE</SPAN><SPAN>) and consume it from an ABAP report with Data Base object.</SPAN><SPAN> </SPAN></P><P><SPAN>By the end, you will understand:</SPAN><SPAN> </SPAN></P><UL><LI><SPAN>How to design an AMDP class for CRUD operations</SPAN><SPAN> </SPAN></LI><LI><SPAN>How to call AMDP methods from ABAP</SPAN><SPAN> </SPAN></LI><LI><SPAN>How to handle different modes: Read, Update, Create, Delete</SPAN><SPAN> </SPAN></LI><LI><SPAN>How to display results or messages to users</SPAN><SPAN> </SPAN></LI></UL><P><STRONG><SPAN>2.Business Requirement</SPAN></STRONG><SPAN> </SPAN></P><P><SPAN>A business user needs to manage </SPAN><SPAN>order data </SPAN><SPAN>stored in the custom table </SPAN><SPAN>ZCDS_CRUD</SPAN><SPAN>. The requirements include:</SPAN><SPAN> </SPAN></P><OL><LI><STRONG><SPAN>Read:</SPAN></STRONG><SPAN> Display existing records in display-only mode.</SPAN><SPAN> </SPAN></LI><LI><STRONG><SPAN>Update:</SPAN></STRONG><SPAN> Pre-fill existing records and allow editing of fields.</SPAN><SPAN> </SPAN></LI><LI><STRONG><SPAN>Create:</SPAN></STRONG><SPAN> Insert new records with input from the user.</SPAN><SPAN> </SPAN></LI><LI><STRONG><SPAN>Delete:</SPAN></STRONG><SPAN> Remove a record and display a success/failure message.</SPAN><SPAN> </SPAN></LI><LI><STRONG><SPAN>Performance:</SPAN></STRONG><SPAN> All operations should execute directly on HANA using AMDP for speed.</SPAN><SPAN> </SPAN></LI></OL><P><SPAN>To achieve this, we implement:</SPAN><SPAN> </SPAN></P><UL><LI><SPAN>An</SPAN><SPAN> AMDP class </SPAN><SPAN>containing HANA SQL Script logic for all CRUD operations.</SPAN><SPAN> </SPAN></LI><LI><SPAN>An</SPAN><SPAN> ABAP report </SPAN><SPAN>that interacts with the AMDP class and provides an interactive interface for users.</SPAN><SPAN> </SPAN></LI></UL><P><STRONG><SPAN>3.Technical Components</SPAN></STRONG><SPAN> </SPAN></P><UL><LI><STRONG><SPAN>ABAP Class (AMDP):</SPAN></STRONG><SPAN> </SPAN><SPAN>ZCRUD_PROCEDURE</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Interface: </SPAN><SPAN>IF_AMDP_MARKER_HDB</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Methods: </SPAN><SPAN>READ_DATA</SPAN><SPAN>, </SPAN><SPAN>READ_ALL_DATA</SPAN><SPAN>, </SPAN><SPAN>INSERT_DATA</SPAN><SPAN>, </SPAN><SPAN>UPDATE_DATA</SPAN><SPAN>, </SPAN><SPAN>DELETE_DATA</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>SQLScript logic for CRUD directly on HANA</SPAN><SPAN> </SPAN></LI></UL><UL><LI><STRONG><SPAN>ABAP Report:</SPAN></STRONG><SPAN> </SPAN><SPAN>ZCRUD_REPORT_AMDP</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Selection screen for input fields and CRUD mode checkboxes</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Calls AMDP methods</SPAN><SPAN> </SPAN></LI><LI><SPAN>Handles display, editable fields, empty fields for creation, and delete confirmation</SPAN><SPAN> </SPAN></LI></UL><P><STRONG><SPAN>4.Application Flow</SPAN></STRONG><SPAN> </SPAN></P><OL><LI><SPAN>User opens report </SPAN><SPAN>ZCRUD_REPORT_AMDP</SPAN><SPAN>.</SPAN><SPAN> </SPAN></LI><LI><SPAN>User enters an </SPAN><SPAN>Order Number</SPAN><SPAN> (</SPAN><SPAN>P_ORD</SPAN><SPAN>) and optionally </SPAN><SPAN>Item</SPAN><SPAN>, </SPAN><SPAN>UOM</SPAN><SPAN>, </SPAN><SPAN>Quantity</SPAN><SPAN>.</SPAN><SPAN> </SPAN></LI><LI><SPAN>User selects one or more operation modes: </SPAN><SPAN>Read, Create, Update, Delete.</SPAN><SPAN> </SPAN></LI><LI><SPAN>Report calls </SPAN><SPAN>AMDP class methods</SPAN><SPAN> depending on the selected mode.</SPAN><SPAN> </SPAN></LI></OL><UL><LI><STRONG><SPAN>Read:</SPAN></STRONG><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Calls </SPAN><SPAN>READ_DATA</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Displays record in display-only format</SPAN><SPAN> </SPAN></LI></UL><UL><LI><STRONG><SPAN>Update:</SPAN></STRONG><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Calls </SPAN><SPAN>READ_DATA</SPAN><SPAN> to fetch record</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Prefills fields with existing data</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Updates using </SPAN><SPAN>UPDATE_DATA</SPAN><SPAN> </SPAN></LI></UL><UL><LI><STRONG><SPAN>Create:</SPAN></STRONG><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Uses empty or input fields to call </SPAN><SPAN>INSERT_DATA</SPAN><SPAN> </SPAN></LI></UL><UL><LI><STRONG><SPAN>Delete:</SPAN></STRONG><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Calls </SPAN><SPAN>DELETE_DATA</SPAN><SPAN> </SPAN></LI><LI><SPAN>Displays success/failure message</SPAN><SPAN> </SPAN></LI></UL><P><STRONG><SPAN>5.Key Logic Implementation</SPAN></STRONG><SPAN> </SPAN></P><P><FONT size="4">5.1 AMDP Class Definition </FONT></P><pre class="lia-code-sample language-abap"><code>CLASS zcrud_procedure DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES: tt_type TYPE TABLE OF zcds_crud.
INTERFACES if_amdp_marker_hdb.
CLASS-METHODS read_data
IMPORTING VALUE(iv_order) TYPE zcds_crud-order_number
EXPORTING VALUE(it_data) TYPE tt_type.
CLASS-METHODS read_all_data
EXPORTING VALUE(it_data) TYPE tt_type.
CLASS-METHODS insert_data
IMPORTING VALUE(iv_order) TYPE zcds_crud-order_number
VALUE(iv_item) TYPE zcds_crud-item_number
VALUE(iv_uom) TYPE zcds_crud-uom
VALUE(iv_qty) TYPE zcds_crud-quantity.
CLASS-METHODS update_data
IMPORTING VALUE(iv_order) TYPE zcds_crud-order_number
VALUE(iv_item) TYPE zcds_crud-item_number
VALUE(iv_uom) TYPE zcds_crud-uom
VALUE(iv_qty) TYPE zcds_crud-quantity.
CLASS-METHODS delete_data
IMPORTING VALUE(iv_order) TYPE zcds_crud-order_number.
ENDCLASS. </code></pre><P><SPAN class=""><SPAN class="">5.2 AMDP Method Implementations (</SPAN><SPAN class="">SQL Script</SPAN><SPAN class="">)</SPAN></SPAN><SPAN class=""> </SPAN></P><pre class="lia-code-sample language-abap"><code>CLASS zcrud_procedure IMPLEMENTATION.
METHOD read_data BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
USING zcds_crud.
it_data = SELECT * FROM zcds_crud WHERE order_number = :iv_order;
ENDMETHOD.
METHOD read_all_data BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
USING zcds_crud.
it_data = SELECT * FROM zcds_crud;
ENDMETHOD.
METHOD insert_data BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
USING zcds_crud.
INSERT INTO zcds_crud (order_number, item_number, uom, quantity)
VALUES (:iv_order, :iv_item, :iv_uom, :iv_qty);
ENDMETHOD.
METHOD update_data BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
USING zcds_crud.
UPDATE zcds_crud
SET item_number = :iv_item,
uom = :iv_uom,
quantity = :iv_qty
WHERE order_number = :iv_order;
ENDMETHOD.
METHOD delete_data BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
USING zcds_crud.
DELETE FROM zcds_crud WHERE order_number = :iv_order;
ENDMETHOD.
ENDCLASS. </code></pre><P><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">5.3 ABAP Report: Selection Screen</SPAN></SPAN><SPAN class=""> </SPAN></SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>REPORT zcrud_report_amdp.
PARAMETERS: p_ord TYPE zcds_crud-order_number OBLIGATORY,
p_read AS CHECKBOX DEFAULT abap_true,
p_crea AS CHECKBOX,
p_upd AS CHECKBOX,
p_del AS CHECKBOX.
PARAMETERS: p_item TYPE zcds_crud-item_number,
p_uom TYPE zcds_crud-uom,
p_qty TYPE zcds_crud-quantity.
DATA: lt_data TYPE zcrud_procedure=>tt_type,
ls_data TYPE zcds_crud. </code></pre><P><SPAN class=""><SPAN class="">5.4 ABAP Report: Execution and CRUD Operations</SPAN></SPAN><SPAN class=""> </SPAN></P><pre class="lia-code-sample language-abap"><code>START-OF-SELECTION.
CASE 'X'.
WHEN rb_read.
PERFORM read_data.
WHEN rb_crt.
PERFORM create_screen.
WHEN rb_upd.
PERFORM update_screen.
WHEN rb_dlt.
PERFORM delete_data.
ENDCASE.
*-------------------------------------------------------------*
* READ MODE – SHOW DATA IN ALV (Display Only)
*-------------------------------------------------------------*
FORM read_data.
zcrud_procedure=>read_data(
EXPORTING iv_order = p_ord
IMPORTING it_data = lt_data ).
IF lt_data IS INITIAL.
WRITE: / 'No record found'.
RETURN.
ENDIF.
CALL SCREEN 100.
ENDFORM.
*-------------------------------------------------------------*
* CREATE MODE – EMPTY ALV WITH HEADERS (Editable)
*-------------------------------------------------------------*
FORM create_screen.
CLEAR lt_data.
ls_data-order_number = p_ord.
ls_data-item_number = p_item.
ls_data-uom = p_uom.
ls_data-quantity = p_qty.
TRY.
zcrud_procedure=>insert_data(
EXPORTING
iv_order = ls_data-order_number
iv_item = ls_data-item_number
iv_uom = ls_data-uom
iv_qty = ls_data-quantity
).
* WRITE: / 'Record created successfully.'.
MESSAGE 'Record created successfully' TYPE 'S'.
CATCH cx_amdp_error INTO DATA(lx).
WRITE: / 'Error creating record:', lx->get_text( ).
ENDTRY.
"Add empty row
* APPEND INITIAL LINE TO lt_data.
append ls_data to lt_data.
CALL SCREEN 200.
ENDFORM.
*-------------------------------------------------------------*
* UPDATE MODE – ORDER DISPLAY ONLY, OTHERS EDITABLE
*-------------------------------------------------------------*
FORM update_screen.
IF rb_upd = abap_true.
zcrud_procedure=>read_data(
EXPORTING iv_order = p_ord
IMPORTING it_data = lt_data
).
IF lt_data IS INITIAL.
MESSAGE: 'No record found for update' type 'S'.
ELSE.
ls_data = lt_data[ 1 ].
" Editable mode: overwrite with screen input if provided
IF p_item IS NOT INITIAL.
ls_data-item_number = p_item.
ENDIF.
IF p_uom IS NOT INITIAL.
ls_data-uom = p_uom.
ENDIF.
IF p_qty IS NOT INITIAL.
ls_data-quantity = p_qty.
ENDIF.
TRY.
zcrud_procedure=>update_data(
EXPORTING
iv_order = ls_data-order_number
iv_item = ls_data-item_number
iv_uom = ls_data-uom
iv_qty = ls_data-quantity
).
MESSAGE 'Record updated successfully' TYPE 'S'.
CATCH cx_amdp_error INTO DATA(lxupd).
MESSAGE 'Error updating record:' TYPE 'S'.
ENDTRY.
ENDIF.
ENDIF.
CALL SCREEN 300.
ENDFORM.
*-------------------------------------------------------------*
* DELETE MODE
*-------------------------------------------------------------*
FORM delete_data.
zcrud_procedure=>delete_data(
EXPORTING iv_order = p_ord ).
MESSAGE 'Record Deleted successfully' TYPE 'S'.
ENDFORM.
*--------------------------------------------------------------------*
* SCREEN 100 – READ MODE (DISPLAY ALV)
*--------------------------------------------------------------------*
MODULE status_0100 OUTPUT.
SET PF-STATUS 'SCREEN100'.
CREATE OBJECT gr_cust
EXPORTING container_name = 'CC_ALV'.
CREATE OBJECT gr_alv
EXPORTING i_parent = gr_cust.
CALL METHOD gr_alv->set_table_for_first_display
EXPORTING i_structure_name = 'ZCDS_CRUD'
CHANGING it_outtab = lt_data.
ENDMODULE.
*--------------------------------------------------------------------*
* SCREEN 200 – CREATE MODE (Editable)
*--------------------------------------------------------------------*
MODULE status_0200 OUTPUT.
SET PF-STATUS 'SCREEN200'.
CREATE OBJECT gr_cust
EXPORTING container_name = 'CC_ALV'.
CREATE OBJECT gr_alv
EXPORTING i_parent = gr_cust.
CALL METHOD gr_alv->set_table_for_first_display
EXPORTING i_structure_name = 'ZCDS_CRUD'
i_default = 'X'
CHANGING it_outtab = lt_data.
ENDMODULE.
MODULE user_command_0200 INPUT.
case sy-ucomm.
when 'BACK'.
LEAVE TO SCREEN 0.
ENDCASE.
READ TABLE lt_data INTO ls_data INDEX 1.
TRY.
zcrud_procedure=>insert_data(
EXPORTING
iv_order = ls_data-order_number
iv_item = ls_data-item_number
iv_uom = ls_data-uom
iv_qty = ls_data-quantity ).
MESSAGE 'Record Created Successfully' TYPE 'S'.
CATCH cx_amdp_error INTO DATA(lx).
MESSAGE lx->get_text( ) TYPE 'E'.
ENDTRY.
LEAVE TO SCREEN 0.
ENDMODULE.
*--------------------------------------------------------------------*
* SCREEN 300 – UPDATE MODE (Order display only)
*--------------------------------------------------------------------*
MODULE status_0300 OUTPUT.
SET PF-STATUS 'SCREEN300'.
DATA lt_fieldcat TYPE lvc_t_fcat.
DATA ls_fcat TYPE lvc_s_fcat.
"ITEM/UOM/QTY editable
LOOP AT lt_data INTO ls_data.
ENDLOOP.
"Build field catalog
ls_fcat-fieldname = 'ORDER_NUMBER'.
ls_fcat-scrtext_l = 'Order'.
ls_fcat-edit = ''.
APPEND ls_fcat TO lt_fieldcat.
CLEAR ls_fcat.
ls_fcat-fieldname = 'ITEM_NUMBER'.
ls_fcat-scrtext_l = 'Item'.
ls_fcat-edit = 'X'.
APPEND ls_fcat TO lt_fieldcat.
CLEAR ls_fcat.
ls_fcat-fieldname = 'UOM'.
ls_fcat-scrtext_l = 'UOM'.
ls_fcat-edit = 'X'.
APPEND ls_fcat TO lt_fieldcat.
CLEAR ls_fcat.
ls_fcat-fieldname = 'QUANTITY'.
ls_fcat-scrtext_l = 'Qty'.
ls_fcat-edit = 'X'.
APPEND ls_fcat TO lt_fieldcat.
CREATE OBJECT gr_cust
EXPORTING container_name = 'CC_ALV'.
CREATE OBJECT gr_alv
EXPORTING i_parent = gr_cust.
CALL METHOD gr_alv->set_table_for_first_display
EXPORTING
is_layout = VALUE lvc_s_layo( )
CHANGING
it_outtab = lt_data
it_fieldcatalog = lt_fieldcat.
ENDMODULE.
MODULE user_command_0300 INPUT.
case sy-ucomm.
when 'BACK'.
LEAVE TO SCREEN 0.
ENDCASE.
READ TABLE lt_data INTO ls_data INDEX 1.
TRY.
zcrud_procedure=>update_data(
EXPORTING
iv_order = ls_data-order_number
iv_item = ls_data-item_number
iv_uom = ls_data-uom
iv_qty = ls_data-quantity ).
MESSAGE 'Record Updated Successfully' TYPE 'S'.
CATCH cx_amdp_error INTO DATA(lxupd).
MESSAGE lxupd->get_text( ) TYPE 'E'.
ENDTRY.
LEAVE TO SCREEN 0.
ENDMODULE.
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_0100 INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE user_command_0100 INPUT.
case sy-ucomm.
when 'BACK'.
LEAVE TO SCREEN 0.
ENDCASE.
ENDMODULE.</code></pre><P><STRONG><SPAN class=""><SPAN class="">7. CRUD Operation Outputs (Screenshots Section)</SPAN></SPAN><SPAN class=""> </SPAN></STRONG></P><P><STRONG><SPAN class=""><SPAN class=""><SPAN class="">7.1 READ Operation Output</SPAN></SPAN><SPAN class=""> </SPAN></SPAN></STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="rameshreddy_k_0-1765268285973.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350042i91BA64CA482ABEF8/image-size/medium?v=v2&px=400" role="button" title="rameshreddy_k_0-1765268285973.png" alt="rameshreddy_k_0-1765268285973.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="rameshreddy_k_1-1765268329378.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350043i659C7B772A3DEA1A/image-size/medium?v=v2&px=400" role="button" title="rameshreddy_k_1-1765268329378.png" alt="rameshreddy_k_1-1765268329378.png" /></span></P><P><STRONG><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">7.2 CREATE Operation Output</SPAN></SPAN><SPAN class=""> </SPAN></SPAN></SPAN></STRONG></P><P> </P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="rameshreddy_k_1-1765275266648.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350114iDDF3B687BE10DB5E/image-size/medium?v=v2&px=400" role="button" title="rameshreddy_k_1-1765275266648.png" alt="rameshreddy_k_1-1765275266648.png" /></span><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="rameshreddy_k_2-1765275295767.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350115iF1758D09862FAD43/image-size/medium?v=v2&px=400" role="button" title="rameshreddy_k_2-1765275295767.png" alt="rameshreddy_k_2-1765275295767.png" /></span></P><P> </P><P><STRONG><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">7.3 UPDATE Operation Output</SPAN></SPAN><SPAN class=""> <BR /></SPAN></SPAN></SPAN></SPAN></STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="rameshreddy_k_3-1765275616493.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350122i03269AE5AE06BDEA/image-size/medium?v=v2&px=400" role="button" title="rameshreddy_k_3-1765275616493.png" alt="rameshreddy_k_3-1765275616493.png" /></span><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="rameshreddy_k_4-1765275636486.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350124iC8616148AE2868F9/image-size/medium?v=v2&px=400" role="button" title="rameshreddy_k_4-1765275636486.png" alt="rameshreddy_k_4-1765275636486.png" /></span></P><P> </P><P><STRONG><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""> </SPAN></SPAN></SPAN></SPAN></STRONG></P><P><STRONG><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">7.4 DELETE Operation Output</SPAN></SPAN><SPAN class=""> <BR /></SPAN></SPAN></SPAN></SPAN></SPAN></STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="rameshreddy_k_5-1765276192675.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350141i5B5897A352A213D7/image-size/medium?v=v2&px=400" role="button" title="rameshreddy_k_5-1765276192675.png" alt="rameshreddy_k_5-1765276192675.png" /></span><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="rameshreddy_k_6-1765276228249.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350157iB791E47C618C4811/image-size/medium?v=v2&px=400" role="button" title="rameshreddy_k_6-1765276228249.png" alt="rameshreddy_k_6-1765276228249.png" /></span></P><P> </P><P> </P><P><STRONG><SPAN class=""><SPAN class=""><SPAN class="">6. Conclusion</SPAN></SPAN><SPAN class=""> </SPAN></SPAN></STRONG></P><P><SPAN>This implementation demonstrates how to:</SPAN><SPAN> </SPAN></P><UL><LI><SPAN>Use </SPAN><SPAN>AMDP classes </SPAN><SPAN>to handle CRUD operations directly on HANA</SPAN><SPAN> </SPAN></LI><LI><SPAN>Separate </SPAN><SPAN>data logic </SPAN><SPAN>(AMDP) from </SPAN><SPAN>presentation logic</SPAN><SPAN> (ABAP report)</SPAN><SPAN> </SPAN></LI><LI><SPAN>Handle </SPAN><SPAN>different CRUD modes </SPAN><SPAN>efficiently</SPAN><SPAN> </SPAN></LI><LI><SPAN>Provide clear user messages for all operations</SPAN><SPAN> </SPAN></LI></UL><P><SPAN>This approach ensures </SPAN><SPAN>performance, maintainability, and user-friendliness </SPAN><SPAN>while working with SAP HANA and ABAP together, and it can be extended to other database-intensive operations following the same pattern.</SPAN><SPAN> </SPAN></P><P><STRONG><SPAN class=""><SPAN class=""><BR /><BR /></SPAN></SPAN></STRONG></P>2025-12-09T19:16:17.595000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/rap-based-adobeform-with-custom-action-and-annotations/ba-p/14281893RAP BASED ADOBEFORM WITH CUSTOM ACTION and Annotations2025-12-10T07:53:48.802000+01:00harsha_reddy24https://community.sap.com/t5/user/viewprofilepage/user-id/2263071<P><STRONG>Introduction:</STRONG><BR />In this blog, we explore how RAP and Adobe Forms can be integrated to deliver a fully digital, end-to-end document generation experience directly from Fiori. By leveraging custom actions, virtual elements, and media-stream handling, we can trigger Adobe Form generation from the UI, manage the file output within RAP, and enable users to download the PDF instantly—ensuring a clean, cloud-ready and future-proof architecture.<BR /><BR /><STRONG>Solution Overview:</STRONG></P><P>In modern SAP applications, combining <STRONG>RAP (RESTful ABAP Programming Model)</STRONG> with Adobe Forms unlocks a clean, scalable way to generate and manage documents directly from Fiori. By extending the Fiori Elements UI with a custom action through the Integrative Extension Controller, we can trigger Adobe form generation seamlessly from the frontend. Using RAP virtual elements and media-stream properties, the generated PDF can be stored, retrieved, and downloaded. This approach delivers a fully end-to-end, cloud-ready solution for document creation, storage, and user-triggered actions—all built natively within <STRONG>RAP</STRONG>.</P><P><STRONG>Root Entity:</STRONG></P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED // No authorization checks required for read access
@EndUserText.label: 'ROOT ENTITY FOR ADOBE FORM' // Description for display in tools
@Metadata.ignorePropagatedAnnotations: true // Avoid unwanted propagated annotations
define root view entity ZRV_AFORM
as select from vbap // Based on VBAP (Sales Order Item Data)
{
/*-----------------------------------------------------------
Key Fields for RAP Root Entity
-----------------------------------------------------------*/
key vbeln, // Sales Document Number
posnr, // Item Number
matnr, // Material Number
/*-----------------------------------------------------------
Display text: Shown in UI for SEGW/Fiori preview
Not used for actual functionality, only for readability.
-----------------------------------------------------------*/
'Preview(SEGW)' as ShowPDF,
/*-----------------------------------------------------------
Dynamic URL to download the Adobe Form PDF
Format:
/sap/opu/odata/SAP/ZRAP_ADOBE_FORM_SRV/adobeSet('<VBELN>')/$value
This URL triggers GET_STREAM in the OData service.
-----------------------------------------------------------*/
concat(
'/sap/opu/odata/SAP/ZRAP_ADOBE_FORM_SRV/adobeSet(''',
concat( vbeln, ''')') /$value'
) as LinkToPDF
}</code></pre><P> </P><P><STRONG>OData Service:<BR /></STRONG></P><P>Include <STRONG>vbeln</STRONG> as a property in your entity type, and when the user provides a sales document number, the service should return the corresponding Adobe Form data in the response, implement <STRONG>GET_STREAM</STRONG> Method .<BR /><BR /><STRONG>Implementation:<BR /></STRONG></P><pre class="lia-code-sample language-abap"><code> METHOD /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM.
"---------------------------------------------------------------
" Data Declarations
"---------------------------------------------------------------
DATA: lv_funcname TYPE funcname, " Generated FM name for Adobe Form
ls_o_p TYPE sfpoutputparams, " Output parameters for Adobe Forms
ls_formoutput TYPE fpformoutput, " Adobe form output structure
ls_stream TYPE ty_s_media_resource, " Stream returned to OData
gv_bin_file TYPE xstring. " PDF binary data (unused variable)
"---------------------------------------------------------------
" Read Input Key from OData Request
" Example: /sap/opu/odata/SRV/FormSet(vbeln='12345')/$value
"---------------------------------------------------------------
DATA(lv_vbeln) = VALUE vbeln_vl(
it_key_tab[ name = 'vbeln' ]-value OPTIONAL ).
"---------------------------------------------------------------
" STEP 1: Retrieve Adobe Form Generated Function Module
"---------------------------------------------------------------
TRY.
CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'
EXPORTING
i_name = 'ZSALES_FORM_ITEMS' " Adobe Form interface name
IMPORTING
e_funcname = lv_funcname. " Generated FM name
IF sy-subrc <> 0.
RETURN. " Stop processing if FM not found
ENDIF.
"-----------------------------------------------------------
" STEP 2: Adobe Form Output Setup (Request PDF Only)
"-----------------------------------------------------------
ls_o_p-nodialog = abap_true. " No dialog popups
ls_o_p-getpdf = abap_true. " Request PDF output
ls_o_p-nopreview = abap_true. " Skip preview
" Open Adobe spool job
CALL FUNCTION 'FP_JOB_OPEN'
CHANGING
ie_outputparams = ls_o_p
EXCEPTIONS
cancel = 1
usage_error = 2
system_error = 3
internal_error = 4
OTHERS = 5.
CATCH cx_root.
" Ideally log or raise error
RETURN.
ENDTRY.
"---------------------------------------------------------------
" STEP 3: Call Adobe Form Generated Function Module
"---------------------------------------------------------------
CALL FUNCTION lv_funcname
EXPORTING
p_vbeln = lv_vbeln " Sales document number
IMPORTING
/1bcdwb/formoutput = ls_formoutput " PDF Output (XSTRING)
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
RETURN. " Handle form rendering errors
ENDIF.
"---------------------------------------------------------------
" STEP 4: Close Adobe Print Job
"---------------------------------------------------------------
CALL FUNCTION 'FP_JOB_CLOSE'
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
RETURN.
ENDIF.
"---------------------------------------------------------------
" STEP 5: Populate OData Media Stream
"---------------------------------------------------------------
ls_stream-mime_type = 'application/pdf'. " MIME type for PDF
ls_stream-value = ls_formoutput-pdf. " XSTRING PDF data
"---------------------------------------------------------------
" STEP 6: Set Filename in Response Header
"---------------------------------------------------------------
DATA: ls_header TYPE ihttpnvp,
lv_filename TYPE string.
" Dynamic file name e.g. SalesDoc_80001234.pdf
lv_filename = |SalesDoc_{ lv_vbeln }.pdf|.
ls_header-name = 'Content-Disposition'.
ls_header-value = |attachment; filename="{ lv_filename }"|.
" Add header to OData HTTP response
me->set_header( is_header = ls_header ).
"---------------------------------------------------------------
" STEP 7: Return Stream to OData Framework
"---------------------------------------------------------------
CALL METHOD me->copy_data_to_ref
EXPORTING
is_data = ls_stream
CHANGING
cr_data = er_stream.
ENDMETHOD.</code></pre><P><STRONG>Projection View:</STRONG></P><P>To expose the Adobe Form download link in the Fiori UI, I used a projection view with ui.lineItem and type: <STRONG>WITH_URL</STRONG> so the PDF URL becomes directly clickable in the list and object page. The actual PDF content BASE64 is not stored in the CDS view; instead,<STRONG> I used a RAP virtual element attach calculated by an ABAP class for Custom Action</STRONG>. This virtual element lets me fetch and return the generated Adobe Form dynamically at runtime without persisting the binary in the database.</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED // No auth checks for read access
@EndUserText.label: 'PV FOR ADOBE FORM' // Description of the view
@Metadata.ignorePropagatedAnnotations: true // Prevent annotation inheritance from base view
define root view entity ZPV_AFORM
as projection on ZRV_AFORM // Projection on RAP consumption view
{
/*-----------------------------------------------------------
Key Field: Sales Document (VBELN)
Displayed in UI (List + Object Page)
-----------------------------------------------------------*/
<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.facet: [{ type: #IDENTIFICATION_REFERENCE }]
<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.lineItem: [{ position: 10 }]
<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.identification: [{ position: 10 }]
key vbeln,
/*-----------------------------------------------------------
Item Number
-----------------------------------------------------------*/
<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.lineItem: [{ position: 20 }]
<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.identification: [{ position: 20 }]
posnr,
/*-----------------------------------------------------------
Material
-----------------------------------------------------------*/
<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.lineItem: [{ position: 30 }]
<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.identification: [{ position: 30 }]
matnr,
/*-----------------------------------------------------------
PDF Link Column (UI: Display as clickable URL)
This displays a clickable link "Show PDF" in the List Report.
-----------------------------------------------------------*/
<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.lineItem: [{
position: 10,
type: #WITH_URL, // URL-enabled column
url: 'LinkToPDF' // Field used as hyperlink
}]
<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.identification: [{
position: 61,
type: #WITH_URL,
url: 'LinkToPDF'
}]
ShowPDF, // UI label for the clickable link
/*-----------------------------------------------------------
URL Field - Populated in Behavior Implementation
Used by Fiori to download/open the PDF.
-----------------------------------------------------------*/
LinkToPDF,
/*-----------------------------------------------------------
Virtual Field for Base64 PDF content
RAP calculates this via ZCL_ADOBEFORMM class.
-----------------------------------------------------------*/
@ObjectModel.virtualElement: true
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_ADOBEFORMM'
virtual attach : abap.string(0) // Base64 PDF to be fetched on-demand
}</code></pre><P> </P><P><STRONG>Virtual Elements Implementation:</STRONG></P><pre class="lia-code-sample language-abap"><code>CLASS zcl_adobeformm IMPLEMENTATION.
METHOD if_sadl_exit_calc_element_read~calculate.
" Internal table for virtual elements defined in projection view
DATA: lt_virtual TYPE TABLE OF zpv_aform,
lv_base64 TYPE string.
" Move original RAP data into a working virtual table
lt_virtual = CORRESPONDING #( it_original_data ).
" Loop over each row to calculate the virtual element (Base64 PDF)
LOOP AT lt_virtual INTO DATA(ls_virtual).
" Get Sales Order number from the current row
DATA(lv_vbeln) = ls_virtual-vbeln.
" Create instance of Adobe Form handler class
DATA(lo_inst) = NEW zcl_adobeform( ).
" Call Adobe Form generator to get raw PDF (XSTRING)
DATA(rv_pdf) = lo_inst->get_data(
EXPORTING
p_vbeln = lv_vbeln " Sales Order
).
" Convert PDF (XSTRING) → Base64 string, required for RAP media download
CALL FUNCTION 'SCMS_BASE64_ENCODE_STR'
EXPORTING
input = rv_pdf
IMPORTING
output = lv_base64.
" Assign Base64 string to virtual element field
ls_virtual-attach = lv_base64.
ENDLOOP.
" Move calculated data back to RAP consumption structure
ct_calculated_data = CORRESPONDING #( lt_virtual ).
ENDMETHOD.
ENDCLASS.</code></pre><P><BR /><STRONG>To retrieve the Adobe Form as an XSTRING, I implemented a dedicated ABAP class responsible for generating and returning the PDF content. The implementation code is as follows:<BR /><BR /></STRONG></P><pre class="lia-code-sample language-abap"><code> method GET_DATA.
" Adobe Form name
DATA(lv_form_name) = CONV tdsfname( 'ZSALES_FORM_ITEMS' ).
" Name of the generated function module for the form
DATA(lv_form_fm_name) = VALUE rs38l_fnam( ).
" Structures for Adobe Form parameters
DATA(ls_docparams) = VALUE sfpdocparams( ).
DATA(ls_outputparams) = VALUE sfpoutputparams( ).
DATA(ls_formoutput) = VALUE fpformoutput( ).
*--------------------------------------------------------------------*
* STEP 1: Get the Generated Function Module of the Adobe Form
*--------------------------------------------------------------------*
TRY.
CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'
EXPORTING
i_name = lv_form_name " Form name
IMPORTING
e_funcname = lv_form_fm_name. " Generated FM name
CATCH cx_fp_api INTO DATA(lx_fp_api).
" Handle form API errors
MESSAGE ID lx_fp_api->msgid TYPE lx_fp_api->msgty
NUMBER lx_fp_api->msgno
WITH lx_fp_api->msgv1 lx_fp_api->msgv2
lx_fp_api->msgv3 lx_fp_api->msgv4.
RETURN.
ENDTRY.
*--------------------------------------------------------------------*
* STEP 2: Prepare Output Parameters for PDF Generation
*--------------------------------------------------------------------*
ls_outputparams-nodialog = 'X'. " Avoid popup / preview dialog
ls_outputparams-getpdf = 'X'. " Request PDF output only
*--------------------------------------------------------------------*
* STEP 3: Open Adobe Form Spool Job
*--------------------------------------------------------------------*
CALL FUNCTION 'FP_JOB_OPEN'
CHANGING
ie_outputparams = ls_outputparams
EXCEPTIONS
cancel = 1
usage_error = 2
system_error = 3
internal_error = 4
OTHERS = 5.
IF sy-subrc <> 0.
" Display error message and exit
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
RETURN.
ENDIF.
*--------------------------------------------------------------------*
* STEP 4: Call the Generated Adobe Form Function Module
*--------------------------------------------------------------------*
CALL FUNCTION lv_form_fm_name
EXPORTING
/1BCDWB/DOCPARAMS = ls_docparams " Document parameters
p_vbeln = p_vbeln " Sales document input
IMPORTING
/1BCDWB/FORMOUTPUT = ls_formoutput " Output structure
EXCEPTIONS
USAGE_ERROR = 1
SYSTEM_ERROR = 2
INTERNAL_ERROR = 3
OTHERS = 4.
IF sy-subrc <> 0.
" Errors during form rendering
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
RETURN.
ENDIF.
*--------------------------------------------------------------------*
* STEP 5: Close Adobe Form Spool Job
*--------------------------------------------------------------------*
CALL FUNCTION 'FP_JOB_CLOSE'
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
" Handle spool closing issues
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
RETURN.
ENDIF.
*--------------------------------------------------------------------*
* STEP 6: Return Base64 PDF string to RAP Virtual Element
*--------------------------------------------------------------------*
rv_string = ls_formoutput-pdf. " Base64 encoded PDF
endmethod.</code></pre><UL><LI><EM>generate service definition and binding.</EM></LI><LI><EM><EM>bind our service to list report.<BR /><BR /></EM></EM><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="harsha_reddy24_0-1764672827401.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/347434iD5FFDE825C148890/image-size/medium?v=v2&px=400" role="button" title="harsha_reddy24_0-1764672827401.png" alt="harsha_reddy24_0-1764672827401.png" /></span><P> </P></LI><LI>The link is highlighted in the UI, and when the user clicks it, the corresponding Adobe Form for that specific sales document is downloaded instantly.</LI><LI><P class="" align="left">Right click on web app and click on open guided development.</P></LI><LI>We need custom action to be implemented.</LI><LI>Click on add a custom action.</LI><LI>Add necessary details and click on insert code snippet it will be added to manifest.json, it will add one more controller, where we can add our custom logic.</LI></UL><P><BR /><STRONG>To handle multi-PDF downloads from the List Report, I implemented a custom action in the controller extension. When the user selects one or more rows, a confirmation popup is shown using MessageBox.confirm. After the user confirms, the extension reads each selected entity via the OData model and retrieves the attach virtual element, which contains the Adobe Form as a Base64 string. The code then converts the Base64 into a PDF Blob and automatically triggers a download for each sales document, generating individual files such as Sales_Document_<VBELN>.pdf. This approach provides a smooth, scalable way to download multiple Adobe Forms directly from the Fiori UI without additional backend endpoints.</STRONG></P><pre class="lia-code-sample language-abap"><code>sap.ui.define([
"sap/m/MessageToast",
"sap/m/MessageBox"
], function (MessageToast, MessageBox) {
"use strict";
return {
adf: function (oEvent) {
// Get the SmartTable from the view
var oSmartTable = this.getView().byId("listReport");
if (!oSmartTable) {
MessageToast.show("SmartTable not found");
return;
}
// Get the inner table (GridTable/ResponsiveTable)
var oTable = oSmartTable.getTable();
if (!oTable || typeof oTable.getSelectedContexts !== "function") {
// If table is not ready or does not support selection
MessageToast.show("Table not ready or selection not supported");
return;
}
// Get selected row contexts
var aSelectedContexts = oTable.getSelectedContexts();
if (aSelectedContexts.length === 0) {
// User must select at least one row
MessageToast.show("Please select at least one row.");
return;
}
// Ask user for confirmation before downloading PDFs
MessageBox.confirm("Do you want to download the selected PDF(s)?", {
title: "Confirm Download",
actions: [MessageBox.Action.OK, MessageBox.Action.CANCEL],
onClose: function (oAction) {
if (oAction === MessageBox.Action.OK) {
// Get OData model
var oModel = this.getOwnerComponent().getModel();
// Loop through all selected rows
aSelectedContexts.forEach(function (oContext, index) {
var sPath = oContext.getPath(); // Entity path of the row
// Read entity to fetch Base64 PDF (virtual element)
oModel.read(sPath, {
success: function (odata) {
// Extract Base64 string from response
var base64String = odata.attach;
try {
// Convert Base64 → binary
var binaryString = atob(base64String);
var len = binaryString.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
// Create Blob for PDF download
var blob = new Blob([bytes], { type: "application/pdf" });
// Create a temporary download link
var link = document.createElement("a");
link.href = URL.createObjectURL(blob);
// File name: Sales_Document_<VBELN>.pdf
link.download = "Sales_Document_" + odata.vbeln + ".pdf";
// Trigger download
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch (e) {
// Invalid Base64 or conversion failure
MessageToast.show("Invalid base64 for: " + odata.vbeln);
}
},
// Error while calling OData service
error: function () {
MessageToast.show("Error fetching PDF for: " + sPath);
}
});
});
}
}.bind(this)
});
}
};
});</code></pre><P> </P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="harsha_reddy24_1-1764673727896.png" style="width: 320px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/347441i86766F8B44AFE42D/image-dimensions/320x169?v=v2" width="320" height="169" role="button" title="harsha_reddy24_1-1764673727896.png" alt="harsha_reddy24_1-1764673727896.png" /></span></P><P> </P><P><STRONG>Conclusion:</STRONG><BR />This end-to-end setup demonstrates how RAP, Adobe Forms, and Fiori Elements can work together seamlessly to deliver a modern document-generation experience. By leveraging virtual elements for XSTRING handling, URL-based PDF links, and a custom UI action for multi-file downloads, we can generate, expose, and retrieve Adobe Forms without any custom Gateway coding. The solution is clean, extensible, and fully aligned with SAP’s cloud-ready RAP architecture making it a practical template for building similar document-driven features in enterprise applications.</P><P><STRONG><BR />Thanks For Reading, Good Wishes<BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Connectivity/pd-p/266264953119842772207986043063520" class="lia-product-mention" data-product="313-1">ABAP Connectivity</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/SAP+BTP+ABAP+environment/pd-p/73555000100800001164" class="lia-product-mention" data-product="11-1">SAP BTP ABAP environment</a> </STRONG></P><P> </P>2025-12-10T07:53:48.802000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/sap-rap-data-modeling-handling-virtual-fields-with-amdp-and-table-functions/ba-p/14220974SAP RAP Data Modeling: Handling Virtual Fields with AMDP and Table Functions2025-12-10T08:30:29.592000+01:00manijangitihttps://community.sap.com/t5/user/viewprofilepage/user-id/2174619<P>Hi all,</P><P>In SAP RAP development, it is common to work with fields that should not be physically stored in database tables but must still appear in the service output. Such fields are often required for real-time calculations, business validations, or UI-level display logic.</P><P>This blog demonstrates two powerful techniques to handle these derived fields:</P><UL><LI><P><STRONG>Table Functions (AMDP)</STRONG> for database-side calculations</P></LI><LI><P><STRONG>Virtual Elements</STRONG> for ABAP-based runtime logic</P></LI></UL><P>To make the concept relatable, we use a simple <STRONG>Student Marks Management</STRONG> scenario where:</P><UL><LI><P><STRONG>Total Marks</STRONG> is calculated using a Table Function (AMDP)</P></LI><LI><P><STRONG>Pass/Fail Status</STRONG> is determined using Virtual Elements</P></LI></UL><P>This article will walk you through all necessary components—including CDS view entities, AMDP class implementation, RAP behavior definition, and the virtual element class.</P><P><BR />I am implementing this requirement using two approaches:</P><OL><LI><P><STRONG>Table Function</STRONG> for calculating <STRONG>Total Marks</STRONG></P></LI><LI><P><STRONG>Virtual Field</STRONG> for determining <STRONG>Status</STRONG></P></LI></OL><P>Both methods will be covered in this blog.</P><P><STRONG>Step 1: Create a new database table to store student information.</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="manijangiti_0-1758181540341.png" style="width: 728px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/316300i9468610271916E46/image-dimensions/728x354?v=v2" width="728" height="354" role="button" title="manijangiti_0-1758181540341.png" alt="manijangiti_0-1758181540341.png" /></span></P><P><STRONG>Code:<BR /></STRONG></P><pre class="lia-code-sample language-bash"><code>@EndUserText.label : 'Student Information'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zstudent_info {
key client : abap.clnt not null;
key id : zstudentid_de not null;
name : abap.char(50);
class : abap.int4;
telugu : abap.int4;
hindi : abap.int4;
english : abap.int4;
maths : abap.int4;
science : abap.int4;
social : abap.int4;
}</code></pre><P><STRONG>Step 2: Create a Table Function</STRONG></P><P><STRONG>Real-time Use Case for Table Function</STRONG></P><P>In a Student Marks Management System, Total Marks are calculated dynamically across subjects without storing the result physically. A Table Function, implemented with AMDP and SQLScript, performs this calculation efficiently in the database, improving performance and keeping the data model clean by avoiding redundant storage.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="manijangiti_0-1758184577411.png" style="width: 727px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/316310i4D78C5951FDCB9E9/image-dimensions/727x501?v=v2" width="727" height="501" role="button" title="manijangiti_0-1758184577411.png" alt="manijangiti_0-1758184577411.png" /></span></P><P>For now, I am adding only the Total Marks field to implement the AMDP approach.<BR /><BR /></P><pre class="lia-code-sample language-bash"><code>@EndUserText.label: 'Student Info with Total Marks'
define table function ZTABLE_FUNCTION_STUDENT
with parameters
@Environment.systemField: #CLIENT
p_client : abap.clnt
returns {
client : abap.clnt;
id : zstudentid_de;
name : abap.char(50);
class : abap.int4;
telugu : abap.int4;
hindi : abap.int4;
english : abap.int4;
maths : abap.int4;
science : abap.int4;
social : abap.int4;
totalmarks : abap.int4; // 🆕 Calculated field
}
implemented by method ZCL_TABLE_FUNC_STUDENT=>get_total_data;</code></pre><P><STRONG>Step 3: Now create a class ZCL_TABLE_FUNC_STATUS to implement the logic for calculating Total Marks.</STRONG><BR /><BR /><STRONG>Example Code:<BR /></STRONG></P><pre class="lia-code-sample language-bash"><code>CLASS zcl_table_func_student DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb.
" Table function method declaration
CLASS-METHODS get_total_data
FOR TABLE FUNCTION ztable_function_student.
ENDCLASS.
CLASS zcl_table_func_student IMPLEMENTATION.
METHOD get_total_data
BY DATABASE FUNCTION
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING zstudent_info.
RETURN
SELECT
client,
id,
name,
class,
telugu,
hindi,
english,
maths,
science,
social,
telugu + hindi + english + maths + science + social AS totalmarks
FROM zstudent_info
WHERE client = :p_client;
ENDMETHOD.
ENDCLASS.</code></pre><P><STRONG>Step 4: Execute and test the code by pressing F8 On Table Function.</STRONG></P><P><STRONG>Output:<BR /></STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="manijangiti_1-1758185047368.png" style="width: 698px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/316311i5854F2CCAE027181/image-dimensions/698x396?v=v2" width="698" height="396" role="button" title="manijangiti_1-1758185047368.png" alt="manijangiti_1-1758185047368.png" /></span></P><P> </P><P>Now I am going with <STRONG>Virtual Elements</STRONG>.</P><P>Virtual elements are defined using annotations such as:</P><pre class="lia-code-sample language-bash"><code>@ObjectModel.virtualElement: true
@ObjectModel.virtualElementCalculatedBy: 'ABAP:className'</code></pre><P>The logic for the virtual element is implemented in the specified ABAP class.<BR /><BR /><STRONG>Now I am creating the Root View</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="manijangiti_0-1758186312865.png" style="width: 750px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/316327iFC909F4BEC0D7817/image-dimensions/750x386?v=v2" width="750" height="386" role="button" title="manijangiti_0-1758186312865.png" alt="manijangiti_0-1758186312865.png" /></span></P><pre class="lia-code-sample language-bash"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Student Info with Status'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType: {
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define root view entity zstudent_info_view
as select from ZTABLE_FUNCTION_STUDENT( p_client : $session.client )
{
key id as Id,
name as Name,
class as Class,
telugu as Telugu,
hindi as Hindi,
english as English,
maths as Maths,
science as Science,
social as Social,
totalmarks as TotalMarks,
@ObjectModel.virtualElement: true
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_VIRTUAL_ELEMENT_CALCC'
@EndUserText.label: 'Pass/Fail Status'
cast( '' as abap.char(10) ) as Status
}</code></pre><P><STRONG>Root View Code :<BR /></STRONG></P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Root View'
@Metadata.ignorePropagatedAnnotations: true
define root view entity zstudent_info_view_root as select from zstudent_info_view
{
key Id as Id,
Name as Name,
Class as Class,
Telugu as Telugu,
Hindi as Hindi,
English as English,
Maths as Maths,
Science as Science,
Social as Social,
TotalMarks as TotalMarks,
@ObjectModel.virtualElement: true
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_VIRTUAL_ELEMENT_CALCC'
@EndUserText.label: 'Pass/Fail Status'
cast( '' as abap.char(10) ) as Status
}</code></pre><P><STRONG>Projection View Code :<BR /></STRONG></P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Projection View'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define root view entity ZSTUDENT_INFO_VIEW_ROOT_Pro as projection on zstudent_info_view_root
{
//@Consumption.valueHelpDefinition: [
// { entity: {
// name: 'ZSTUDENT_INFO_VIEW_ROOT',
// element: 'ID'
// } }
// ]
key Id,
// @Consumption.valueHelpDefinition: [
// { entity: {
// name: 'ZSTUDENT_INFO_VIEW_ROOT',
// element: 'Name'
// } }
// ]
Name,
Class,
Telugu,
Hindi,
English,
Maths,
Science,
Social,
TotalMarks, // Virtual field
@ObjectModel.virtualElement: true
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_VIRTUAL_ELEMENT_CALCC'
@EndUserText.label: 'Pass/Fail Status'
Status // Virtual field (Pass/Fail)
}</code></pre><P><STRONG><BR /><BR />Definition of behavior for the root view</STRONG></P><pre class="lia-code-sample language-abap"><code>managed implementation in class zbp_student_info_view_root unique;
strict ( 2 );
define behavior for zstudent_info_view_root alias student
persistent table zstudent_informa
lock master
authorization master ( instance )
// etag master <field_name> " Uncomment if using ETag for concurrency control
{
create;
update;
delete;
field ( readonly ) TotalMarks, Status;
mapping for zstudent_informa
{
Id = id;
Name = name;
Class = class;
Telugu = telugu;
Hindi = hindi;
English = english;
Maths = maths;
Science = science;
Social = social;
}
}</code></pre><P><STRONG>Create classes for the root view and projection view.</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="manijangiti_0-1761548831424.png" style="width: 580px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/332796i891247D0979D4C71/image-dimensions/580x370?v=v2" width="580" height="370" role="button" title="manijangiti_0-1761548831424.png" alt="manijangiti_0-1761548831424.png" /></span></P><P><STRONG>Create a class and logic for the virtual element.</STRONG></P><pre class="lia-code-sample language-abap"><code>CLASS zcl_virtual_element_calcc DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_sadl_exit_calc_element_read.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_virtual_element_calcc IMPLEMENTATION.
METHOD if_sadl_exit_calc_element_read~calculate.
CHECK NOT it_original_data IS INITIAL.
DATA lt_calculated_data TYPE STANDARD TABLE OF zstudent_info_view WITH DEFAULT KEY.
MOVE-CORRESPONDING it_original_data TO lt_calculated_data.
LOOP AT lt_calculated_data ASSIGNING FIELD-SYMBOL(<student>).
" Calculate TotalMarks by summing all subject marks
* <student>-totalmarks = <student>-telugu
* + <student>-hindi
* + <student>-english
* + <student>-maths
* + <student>-science
* + <student>-social.
" Check if any subject marks are less than 25
* IF <student>-telugu < 25 OR
* <student>-hindi < 25 OR
* <student>-english < 25 OR
* <student>-maths < 25 OR
* <student>-science < 25 OR
* <student>-social < 25.
* <student>-status = 'Failed'.
* ELSE.
* <student>-status = 'Passed'.
** ENDIF.
* ENDIF.
IF <student>-totalmarks > 250 .
<student>-status = 'Passed'.
ELSE.
<student>-status = 'Failed'.
ENDIF.
ENDLOOP.
MOVE-CORRESPONDING lt_calculated_data TO ct_calculated_data.
ENDMETHOD.
METHOD if_sadl_exit_calc_element_read~get_calculation_info.
" Tell framework which fields you need from original data
et_requested_orig_elements = VALUE #( BASE et_requested_orig_elements
( CONV #( 'TELUGU' ) )
( CONV #( 'HINDI' ) )
( CONV #( 'ENGLISH' ) )
( CONV #( 'MATHS' ) )
( CONV #( 'SCIENCE' ) )
( CONV #( 'SOCIAL' ) )
( CONV #( 'TOTALMARKS' ) )
).
ENDMETHOD.
ENDCLASS.</code></pre><P><STRONG>Now, create a service definition for the projection view and bind the service.<BR /></STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="manijangiti_1-1761553513670.png" style="width: 711px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/332889i128C5CA6829A447E/image-dimensions/711x123?v=v2" width="711" height="123" role="button" title="manijangiti_1-1761553513670.png" alt="manijangiti_1-1761553513670.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="manijangiti_2-1761553556091.png" style="width: 661px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/332890i41FD980B1426340F/image-dimensions/661x233?v=v2" width="661" height="233" role="button" title="manijangiti_2-1761553556091.png" alt="manijangiti_2-1761553556091.png" /></span></P><P> </P><P><STRONG>Now, we are able to see the virtual element output field in the web application.</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="manijangiti_3-1761553739515.png" style="width: 633px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/332891i6ECD6CEE5A34D071/image-dimensions/633x304?v=v2" width="633" height="304" role="button" title="manijangiti_3-1761553739515.png" alt="manijangiti_3-1761553739515.png" /></span></P><H1 id="toc-hId-1631757642"><STRONG>Conclusion</STRONG></H1><P>This blog demonstrated how to enrich a RAP data model using both <STRONG>Table Functions</STRONG> and <STRONG>Virtual Elements</STRONG>, allowing you to compute fields dynamically without storing redundant values in the database.</P><UL><LI><P><STRONG>Table Functions (AMDP)</STRONG> perform high-performance calculations on the HANA database, such as Total Marks.</P></LI><LI><P><STRONG>Virtual Elements</STRONG> allow ABAP-based runtime logic for UI-visible derived fields like Pass/Fail Status.</P></LI></UL><P>By combining these methods, you achieve a clean, efficient, and scalable RAP model that supports real-time business calculations while keeping the underlying data model simple and maintainable.</P><P>This approach can be extended for validations, analytical measures, financial calculations, or any scenario where derived fields should remain virtual yet visible in the application layer.</P><P><STRONG> <a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Connectivity/pd-p/266264953119842772207986043063520" class="lia-product-mention" data-product="313-1">ABAP Connectivity</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/SAP+BTP+ABAP+environment/pd-p/73555000100800001164" class="lia-product-mention" data-product="11-1">SAP BTP ABAP environment</a> </STRONG></P>2025-12-10T08:30:29.592000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/advanced-abap-programming-syntax/ba-p/14287814Advanced ABAP programming syntax2025-12-10T12:12:09.269000+01:00mkhan2126https://community.sap.com/t5/user/viewprofilepage/user-id/42485<P>This blog is to provide new ABAP programming syntax along with some use case to ease and save development time of beginners and experienced professional who is looking for Advanced ABAP programming.</P><P>Many times, we come across a scenario where we have to bring data from different internal tables. As per traditional ABAP we use to loop the main internal table and then use READ TABLE statement for processing each field value. </P><P>Scenario: An internal table contains data passed from an API, we need to validate the data like check if Material, plant & storage location is valid or invalid from different value tables like T001W, T001L MARA etc</P><P><U><STRONG>Old syntax</STRONG></U>: </P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mkhan2126_0-1765358366494.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350649iF7F2FBBADF658DCC/image-size/medium?v=v2&px=400" role="button" title="mkhan2126_0-1765358366494.png" alt="mkhan2126_0-1765358366494.png" /></span></P><P><U><STRONG>New Syntax:</STRONG></U></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mkhan2126_2-1765358832230.png" style="width: 646px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350660i5468BBB47C132332/image-dimensions/646x424?v=v2" width="646" height="424" role="button" title="mkhan2126_2-1765358832230.png" alt="mkhan2126_2-1765358832230.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mkhan2126_3-1765358944737.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350675i36007311D085F9AD/image-size/medium?v=v2&px=400" role="button" title="mkhan2126_3-1765358944737.png" alt="mkhan2126_3-1765358944737.png" /></span></P><P><STRONG>FOR</STRONG> keyword is used for main <STRONG>LOOP--ENDLOOP</STRONG> and <STRONG>LET---VALUE</STRONG> keyword allows you to declare work area for different Internal table like <STRONG>READ STATEMENTS</STRONG> and <STRONG>COND.. WHEN..THEN</STRONG> keyword will allow you to set the conditions.</P><P>Scenario: Many times, we need to append values to the internal table already holding some records then we have to use the BASE keyword.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mkhan2126_4-1765359503063.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350676i0D787D98A3CD066D/image-size/large?v=v2&px=999" role="button" title="mkhan2126_4-1765359503063.png" alt="mkhan2126_4-1765359503063.png" /></span></P><P>Scenario: To create Range table from entries of different internal table</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mkhan2126_5-1765360022005.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350679iE3DB5C976E884893/image-size/large?v=v2&px=999" role="button" title="mkhan2126_5-1765360022005.png" alt="mkhan2126_5-1765360022005.png" /></span></P><P>Scenario: To pass entries from one internal table to another based on filtering using <STRONG>FILTER</STRONG> keyword. <U><STRONG>Note</STRONG></U>: Internal table should be of SORTED or HASHED table type with KEY.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mkhan2126_6-1765360244322.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350684i833562A942061A24/image-size/large?v=v2&px=999" role="button" title="mkhan2126_6-1765360244322.png" alt="mkhan2126_6-1765360244322.png" /></span></P><P>To calculate sum in internal table we use <STRONG>REDUCE</STRONG> statement</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mkhan2126_7-1765360703664.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350685iA8709E11748F3663/image-size/large/is-moderation-mode/true?v=v2&px=999" role="button" title="mkhan2126_7-1765360703664.png" alt="mkhan2126_7-1765360703664.png" /></span></P><P>Output: Total Salary: 39000</P><P>Scenario: GROUP BY statement is used to group the data like for example Order containing multiple item details and we want to pass each order detail to some BAPI for data update.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mkhan2126_8-1765362214700.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350705iA4C9515FF46A3A49/image-size/large/is-moderation-mode/true?v=v2&px=999" role="button" title="mkhan2126_8-1765362214700.png" alt="mkhan2126_8-1765362214700.png" /></span></P><P>Hope it helps the members looking for quick info on Advanced ABAP programming.</P><P>Next time will try to cover the CDS entities and RAP ABAP blogs. Till then happy coding <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span></P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P>\</P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P>2025-12-10T12:12:09.269000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/convert-xml-file-to-internal-table-and-download-into-csv-format-in-abap/ba-p/14274725Convert XML File to Internal Table And Download Into CSV Format In ABAP2025-12-12T07:59:31.023000+01:00harsha_reddy24https://community.sap.com/t5/user/viewprofilepage/user-id/2263071<P><STRONG>Introduction:</STRONG><BR />In most SAP ABAP projects, file uploads are a very common requirement—particularly in formats like <STRONG>TXT, CSV, or Excel</STRONG>. These formats are straightforward to parse using standard approaches such as <STRONG>GUI_UPLOAD, CL_GUI_FRONTEND_SERVICES</STRONG>, or transformations.</P><UL><LI>However, during a recent requirement, I encountered a different scenario:<BR />the business team wanted to upload an XML file, extract specific fields from the XML structure, convert the values into an ABAP internal table, and finally allow users to download the processed data in CSV format.</LI><LI>While XML is widely used for integrations, parsing XML inside ABAP is not as common in day-to-day development—especially when the XML structure is nested and needs to be converted into a flattened internal table.<BR />This made the requirement both interesting and challenging:</LI><LI>How do we read an XML file from the presentation server?</LI><LI>How do we parse the XML structure into an easily consumable internal table?</LI><LI>How do we convert the extracted data into a CSV file dynamically?</LI><LI>How do we present the parsed data to the user (ALV) before export?</LI><LI>SAP fortunately provides powerful XML-handling tools such as <STRONG>CL_XML_DOCUMENT</STRONG> and <STRONG>SMUM_XML_PARSE</STRONG>, which help convert XML into a tree-like format that can be processed easily. Using these, we can extract required data nodes (like EmpID, EmpName, Salary) and map them into a custom structure.</LI></UL><P><STRONG>This blog explains the complete end-to-end solution:</STRONG></P><UL><LI>Reading XML from local file</LI><LI>Parsing XML using SMUM_XML_PARSE</LI><LI>Populating an internal table</LI><LI>Displaying the result in ALV</LI><LI>Exporting the final output to CSV</LI><LI>This approach can be reused for any XML To ABAP conversion scenario, not just employee data. Whether you are processing orders, invoices, or custom data feeds, the same logic applies with minor adjustments.</LI></UL><pre class="lia-code-sample language-abap"><code>" Data declarations
DATA: gcl_xml TYPE REF TO cl_xml_document,
gv_xml_string TYPE xstring,
gv_size TYPE sytabix,
gt_xml_data TYPE TABLE OF smum_xmltb,
gwa_xml_data TYPE smum_xmltb,
gt_return TYPE TABLE OF bapiret2.
" Employee structure
TYPES: BEGIN OF ty_employee,
empid TYPE char10,
empname TYPE char50,
salary TYPE char15,
END OF ty_employee.
DATA: gt_employees TYPE TABLE OF ty_employee,
gwa_employee TYPE ty_employee.
" File parameter
PARAMETERS: p_file TYPE ibipparms-path.
" F4 help for file selection
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
CALL FUNCTION 'F4_FILENAME'
IMPORTING
file_name = p_file.
START-OF-SELECTION.
" Create XML document object
CREATE OBJECT gcl_xml.
" Import XML from file
gcl_xml->import_from_file( filename = p_file ).
IF sy-subrc = 0.
" Render XML to xstring
gcl_xml->render_2_xstring( IMPORTING
stream = gv_xml_string
size = gv_size ).
IF sy-subrc = 0.
" Parse XML
CALL FUNCTION 'SMUM_XML_PARSE'
EXPORTING
xml_input = gv_xml_string
TABLES
xml_table = gt_xml_data
return = gt_return.
IF sy-subrc = 0.
" Process XML data to extract employee information
LOOP AT gt_xml_data INTO gwa_xml_data.
CASE gwa_xml_data-cname.
WHEN 'EmpID'.
gwa_employee-empid = gwa_xml_data-cvalue.
WHEN 'EmpName'.
gwa_employee-empname = gwa_xml_data-cvalue.
WHEN 'Salary'.
gwa_employee-salary = gwa_xml_data-cvalue.
" Append when all fields are collected
APPEND gwa_employee TO gt_employees.
CLEAR gwa_employee.
ENDCASE.
ENDLOOP.
" Display data using ALV
IF gt_employees IS NOT INITIAL.
TRY.
CALL METHOD cl_salv_table=>factory
IMPORTING
r_salv_table = data(lo_alv)
CHANGING
t_table = gt_employees.
" Get columns object
DATA(lo_columns) = lo_alv->get_columns( ).
lo_columns->set_optimize( abap_true ).
" Set column headers
TRY.
DATA(lo_column) = lo_columns->get_column( columnname = 'EMPID' ).
lo_column->set_long_text( 'Employee ID' ).
lo_column->set_medium_text( 'Emp ID' ).
lo_column->set_short_text( 'EmpID' ).
CATCH cx_salv_not_found.
ENDTRY.
TRY.
lo_column = lo_columns->get_column( columnname = 'EMPNAME' ).
lo_column->set_long_text( 'Employee Name' ).
lo_column->set_medium_text( 'Emp Name' ).
lo_column->set_short_text( 'EmpName' ).
CATCH cx_salv_not_found.
ENDTRY.
TRY.
lo_column = lo_columns->get_column( columnname = 'SALARY' ).
lo_column->set_long_text( 'Employee Salary' ).
lo_column->set_medium_text( 'Salary' ).
lo_column->set_short_text( 'Salary' ).
CATCH cx_salv_not_found.
ENDTRY.
" Display ALV
lo_alv->display( ).
CATCH cx_salv_msg.
ENDTRY.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
Data : IOUT TYPE TABLE OF STRING,
XOUT TYPE STRING.
FIELD-SYMBOLS: <FS>.
LOOP AT GT_EMPLOYEES INTO GWA_EMPLOYEE.
CLEAR XOUT.
DO.
ASSIGN COMPONENT SY-INDEX OF STRUCTURE GWA_EMPLOYEE TO <FS>.
IF SY-SUBRC <> 0.
EXIT.
ENDIF.
IF SY-INDEX = 1.
XOUT = <FS>.
ELSE.
CONCATENATE XOUT <FS> INTO XOUT SEPARATED BY ','.
ENDIF.
ENDDO.
APPEND XOUT TO IOUT.
ENDLOOP.
CALL FUNCTION 'GUI_DOWNLOAD'
EXPORTING
FILENAME = 'C:- Tech_csv.csv'
TABLES
DATA_TAB = IOUT.
</code></pre><P><STRONG>Conclusion:<BR /><BR /></STRONG>This blog demonstrated a clear and practical approach to reading XML files in ABAP and transforming their contents into structured data using the Factory Method pattern. By separating file parsing, object creation, and data handling, the solution becomes more scalable, maintainable, and easy to extend for future XML formats. This design not only improves code readability but also ensures that enhancements or format changes can be accommodated with minimal impact on existing logic.<BR /><BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Connectivity/pd-p/266264953119842772207986043063520" class="lia-product-mention" data-product="313-1">ABAP Connectivity</a> </P>2025-12-12T07:59:31.023000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/dynamic-alv-grid-output-using-salv-and-docking-container-in-abap/ba-p/14271669Dynamic ALV Grid Output Using SALV and Docking Container in ABAP2025-12-12T08:04:03.442000+01:00manijangitihttps://community.sap.com/t5/user/viewprofilepage/user-id/2174619<P>Hi Everyone,</P><P>Recently, I worked on a requirement where the ALV output needed to appear dynamically on the same screen using a docking container instead of a separate list output. This makes the UI much more user-friendly, especially when running programs multiple times during testing.</P><P>While SALV handles the ALV part, the interesting part is embedding it inside a docking container placed at the bottom of the screen.<BR />Below is a simple example using the SFLIGHT table. I drafted this article with support from a generative AI tool, but the explanation and experiences shared here are based on my own learning and practical testing.</P><pre class="lia-code-sample language-abap"><code>REPORT ZALV_SALV_DOCK_DEMO.
CLASS LCL_REPORT DEFINITION.
PUBLIC SECTION.
DATA: LT_DATA TYPE STANDARD TABLE OF SFLIGHT, "Output data
LR_CARRID TYPE RANGE OF SFLIGHT-CARRID. "Select Options
METHODS:
GET_DATA,
GENERATE_OUTPUT.
ENDCLASS.
DATA: LR_REPORT TYPE REF TO LCL_REPORT,
G_CARRID TYPE SFLIGHT-CARRID.
SELECTION-SCREEN BEGIN OF BLOCK BLK1 WITH FRAME TITLE G_TITLE.
SELECT-OPTIONS: S_CARRID FOR G_CARRID.
SELECTION-SCREEN END OF BLOCK BLK1.
INITIALIZATION.
G_TITLE = 'Selection Criteria'.
CREATE OBJECT LR_REPORT.
LR_REPORT->GENERATE_OUTPUT( ).
START-OF-SELECTION.
LR_REPORT->LR_CARRID = S_CARRID[].
LR_REPORT->GET_DATA( ).
*---------------------------------------------------------------------*
* Class Implementation
*---------------------------------------------------------------------*
CLASS LCL_REPORT IMPLEMENTATION.
METHOD GET_DATA.
"Fetch data
SELECT *
FROM SFLIGHT
INTO TABLE ME->LT_DATA
WHERE CARRID IN LR_CARRID.
IF SY-DBCNT IS INITIAL.
MESSAGE S398(00) WITH 'No data selected'.
ENDIF.
"Export to memory
EXPORT DATA = ME->LT_DATA TO MEMORY ID SY-CPROG.
ENDMETHOD.
METHOD GENERATE_OUTPUT.
DATA: LR_DOCK TYPE REF TO CL_GUI_DOCKING_CONTAINER,
LR_CONTAINER TYPE REF TO CL_GUI_CONTAINER,
LR_ALV TYPE REF TO CL_SALV_TABLE.
"Import internal table
IMPORT DATA = ME->LT_DATA FROM MEMORY ID SY-CPROG.
FREE MEMORY ID SY-CPROG.
CHECK ME->LT_DATA IS NOT INITIAL.
"Create docking container at bottom
CREATE OBJECT LR_DOCK
EXPORTING
REPID = SY-CPROG
DYNNR = SY-DYNNR
RATIO = 80
SIDE = CL_GUI_DOCKING_CONTAINER=>DOCK_AT_BOTTOM
NAME = 'DOCK_CONT'.
"Container assignment
LR_CONTAINER ?= LR_DOCK.
TRY.
"Create SALV inside the docking container
CL_SALV_TABLE=>FACTORY(
EXPORTING
LIST_DISPLAY = IF_SALV_C_BOOL_SAP=>FALSE
R_CONTAINER = LR_CONTAINER
CONTAINER_NAME = 'DOCK_CONT'
IMPORTING
R_SALV_TABLE = LR_ALV
CHANGING
T_TABLE = ME->LT_DATA ).
CATCH CX_SALV_MSG.
ENDTRY.
"Enable standard functions
DATA(LR_FUNCTIONS) = LR_ALV->GET_FUNCTIONS( ).
LR_FUNCTIONS->SET_DEFAULT( ABAP_TRUE ).
"Display ALV
LR_ALV->DISPLAY( ).
ENDMETHOD.
ENDCLASS.</code></pre><P> </P><UL><LI><P>The ALV appears at the bottom of the same screen</P></LI><LI><P>All SALV functions like sorting, filtering, and export are enabled</P></LI><LI><P>Code is modular and reusable<BR />This example is useful when building interactive ABAP reports where the user should not leave the main selection screen. Using a docking container provides a clean and modern presentation for your ALV list.</P><P>If you want to display multiple ALVs, add toolbars, or enhance SALV—for example with custom columns—I’d be happy to share extended examples as well.<BR /><BR />Selection Screen :<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="image.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/342152i724AB1EA1B4AB692/image-size/large/is-moderation-mode/true?v=v2&px=999" role="button" title="image.png" alt="image.png" /></span><BR />After Executing :<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="image.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/342154iF7FFC3B0BD7EE243/image-size/large/is-moderation-mode/true?v=v2&px=999" role="button" title="image.png" alt="image.png" /></span></P><H1 id="toc-hId-1636402129"><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span> <STRONG>Conclusion (Detailed & Explanatory)</STRONG></H1><P>By embedding the ALV Grid inside a docking container, we avoid the traditional list output and deliver a more user-friendly experience directly on the selection screen. SALV handles the formatting and functions, while the docking container ensures a flexible and consistent UI layout. This technique is highly useful for interactive reports, dashboards, and test-driven programs. While AI helped in organizing and refining the content, the logic, experimentation, and lessons shared are based on my own practical ABAP development work.</P><BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/SAP+BTP+ABAP+environment/pd-p/73555000100800001164" class="lia-product-mention" data-product="11-1">SAP BTP ABAP environment</a> </LI></UL><P> </P><P> </P>2025-12-12T08:04:03.442000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/editable-alv-report-with-row-based-field-editing-and-custom-f4-help-using/ba-p/14148370Editable ALV Report with Row-Based Field Editing and Custom F4 Help Using OOP in ABAP2025-12-12T08:08:44.264000+01:00mubarakbashasyedhttps://community.sap.com/t5/user/viewprofilepage/user-id/2189365<P><STRONG>Introduction:</STRONG></P><P>This blog shows how to create an editable ALV grid in ABAP using <STRONG>CL_GUI_ALV_GRID</STRONG>, where only selected rows can be changed. It also explains how to add a custom F4 help to guide users with valid input. Together, these features make data editing easier, safer, and more user-friendly.</P><P><STRONG>Solution Overview:</STRONG></P><P>This ABAP report features an editable ALV grid built using Object-Oriented programming with CL_GUI_ALV_GRID. It allows users to edit a specific field only for the rows they explicitly select, ensuring controlled and precise data modification.</P><P>Additionally, a custom F4 help is implemented for one of the fields, providing tailored input assistance beyond the standard SAP search help. This approach improves data accuracy, enhances user experience, and supports business processes that require selective, validated updates to records within an ALV grid. </P><P><STRONG>Selection-Screen:</STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_0-1752068913781.png" style="width: 589px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284573i5E245693BC1BFA7C/image-dimensions/589x99?v=v2" width="589" height="99" role="button" title="mubarakbashasyed_0-1752068913781.png" alt="mubarakbashasyed_0-1752068913781.png" /></span></STRONG></P><P><STRONG>Screen 100 - OUTPUT Module:</STRONG></P><pre class="lia-code-sample language-abap"><code>*------------------------------------------------------------------------------*
* MODULE: PBO
*------------------------------------------------------------------------------*
module status_0100 output.
set pf-status 'ZSTATUS'.
if gr_cont is initial.
create object gr_cont
exporting
container_name = 'CNTNR'.
create object gr_grid
exporting
i_parent = gr_cont.
call method gr_grid->set_table_for_first_display
exporting
i_structure_name = 'TY_STATUS'
is_layout = gs_layout
changing
it_fieldcatalog = gt_fcat
it_outtab = gt_data.
create object gr_event_receiver.
set handler gr_event_receiver->on_f4 for gr_grid.
endif.
endmodule.</code></pre><P><STRONG>Screen 100 - INPUT Module:</STRONG></P><pre class="lia-code-sample language-abap"><code>*------------------------------------------------------------------------------*
* MODULE: PAI
*------------------------------------------------------------------------------*
module user_command_0100 input.
gv_okcode = sy-ucomm.
case gv_okcode.
when 'BACK'.
leave to screen 0.
when 'EDIT'.
gr_grid->check_changed_data( ).
perform set_cell_styles using abap_true .
perform refresh_grid.
when 'SAVE'.
perform save_to_db.
perform set_cell_styles using abap_false.
perform refresh_grid.
when 'REFRESH'.
perform get_data.
perform set_cell_styles using abap_false.
perform refresh_grid.
when 'SELECT'.
perform selectall.
perform refresh_grid.
when 'DESELECT'.
perform deselect.
perform set_cell_styles using abap_false.
perform refresh_grid.
endcase.
endmodule.</code></pre><P><STRONG>Custom F4 Help Event Handler :</STRONG></P><P><STRONG>A handler class registers for the STATUS field's F4 event to display allowed flags ('X', 'P', blank) via F4IF_INT_TABLE_VALUE_REQUEST. </STRONG></P><pre class="lia-code-sample language-abap"><code>class cl_event_receiver definition.
public section.
methods: on_f4 for event onf4 of cl_gui_alv_grid
importing er_event_data e_fieldname es_row_no .
methods: constructor.
endclass.
class cl_event_receiver implementation.
method constructor.
set handler on_f4 for gr_grid.
gr_grid->register_f4_for_fields(
it_f4 = value #( ( fieldname = 'STATUS' register = 'X' chngeafter = 'X' ) ) ).
endmethod.
method on_f4.
DATA: lt_return TYPE TABLE OF DDSHRETVAL.
if e_fieldname = 'STATUS'.
select distinct status from zdel_status into table (lt_flag) WHERE status NE ''.
APPEND INITIAL LINE TO lt_flag.
call function 'F4IF_INT_TABLE_VALUE_REQUEST'
exporting
retfield = 'STATUS'
value_org = 'S'
tables
value_tab = lt_flag
return_tab = lt_return
exceptions
parameter_error = 1
no_values_found = 2
others = 3.
if sy-subrc = 0 and lt_return is not initial.
field-symbols <table_modi> type lvc_t_modi.
assign er_event_data->m_data->* to <table_modi>.
<table_modi> = value #(
base <table_modi>
( row_id = es_row_no-row_id
fieldname = e_fieldname
value = lt_return[ 1 ]-fieldval ) ).
er_event_data->m_event_handled = 'X'.
endif.
endif.
endmethod. </code></pre><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_1-1752069844840.png" style="width: 556px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284585iE7BE65AB90D1C1FC/image-dimensions/556x345?v=v2" width="556" height="345" role="button" title="mubarakbashasyed_1-1752069844840.png" alt="mubarakbashasyed_1-1752069844840.png" /></span></STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_2-1752069893142.png" style="width: 559px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284586i155363553A10EC7E/image-dimensions/559x266?v=v2" width="559" height="266" role="button" title="mubarakbashasyed_2-1752069893142.png" alt="mubarakbashasyed_2-1752069893142.png" /></span></STRONG></P><P><STRONG>Enable Editing on Selected Rows </STRONG></P><P><STRONG>When users click Edit, the STATUS column for selected rows becomes editable. </STRONG></P><pre class="lia-code-sample language-abap"><code>form set_cell_styles using iv_enable type abap_bool .
loop at gt_data assigning field-symbol(<ls_data>).
clear <ls_data>-celltab.
if iv_enable = abap_true and <ls_data>-sel = abap_true.
data(ls_style) = value lvc_s_styl(
fieldname = 'STATUS'
style = cl_gui_alv_grid=>mc_style_enabled ).
append ls_style to <ls_data>-celltab.
endif.
endloop.
endform.
form refresh_grid.
if gr_grid is bound.
gr_grid->refresh_table_display(
exporting is_stable = value lvc_s_stbl( row = 'X' col = 'X' ) ).
endif.
endform.</code></pre><P> </P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_3-1752067655438.png" style="width: 575px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284541iCEC9F1CE52EF7102/image-dimensions/575x246?v=v2" width="575" height="246" role="button" title="mubarakbashasyed_3-1752067655438.png" alt="mubarakbashasyed_3-1752067655438.png" /></span></STRONG></P><P><STRONG>Save Changes Back to Database:</STRONG></P><P><STRONG>Only records marked with sel = abap_true are updated, with feedback on how many records were changed. </STRONG></P><pre class="lia-code-sample language-abap"><code>form save_to_db.
gr_grid->check_changed_data( ).
data count type i.
loop at gt_data assigning field-symbol(<ls_data>) where sel = abap_true.
update zdel_status
set status = <ls_data>-status
where plant = <ls_data>-plant
and deliveryno = <ls_data>-deliveryno.
count = count + 1.
if sy-subrc = 0.
<ls_data>-sel = abap_false.
endif.
endloop.
message count && ' Records Updated Successfully.' type 'S'.
commit work.
endform.</code></pre><P> </P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_5-1752070732836.png" style="width: 520px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284590iFFA84129D256A99D/image-dimensions/520x205?v=v2" width="520" height="205" role="button" title="mubarakbashasyed_5-1752070732836.png" alt="mubarakbashasyed_5-1752070732836.png" /></span></STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_4-1752070610202.png" style="width: 515px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284588iD497693C2EF585F4/image-dimensions/515x408?v=v2" width="515" height="408" role="button" title="mubarakbashasyed_4-1752070610202.png" alt="mubarakbashasyed_4-1752070610202.png" /></span></STRONG></P><P><STRONG>Changes are updated in database table: </STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_6-1752070918598.png" style="width: 543px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284592i4C951C4D88EB5C5C/image-dimensions/543x221?v=v2" width="543" height="221" role="button" title="mubarakbashasyed_6-1752070918598.png" alt="mubarakbashasyed_6-1752070918598.png" /></span></STRONG></P><P><STRONG>When clicking on ‘Refresh’ button it will display the old value of the field. </STRONG></P><P><STRONG>In edit mode of the field :</STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_7-1752067711482.png" style="width: 508px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284545iE2A3DFC9A072F847/image-dimensions/508x276?v=v2" width="508" height="276" role="button" title="mubarakbashasyed_7-1752067711482.png" alt="mubarakbashasyed_7-1752067711482.png" /></span> </STRONG></P><P><STRONG>The values are changed:</STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_8-1752067711483.png" style="width: 517px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284547i503F5E2454859FD3/image-dimensions/517x243?v=v2" width="517" height="243" role="button" title="mubarakbashasyed_8-1752067711483.png" alt="mubarakbashasyed_8-1752067711483.png" /></span></STRONG></P><P><STRONG>Before saving click on refresh :</STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_7-1752071052575.png" style="width: 524px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284594i47E2F2013C4E8494/image-dimensions/524x265?v=v2" width="524" height="265" role="button" title="mubarakbashasyed_7-1752071052575.png" alt="mubarakbashasyed_7-1752071052575.png" /></span></STRONG></P><P><STRONG>When click on ‘Select’, it will select all records through checkboxes :</STRONG></P><pre class="lia-code-sample language-abap"><code>form selectall .
loop at gt_data assigning field-symbol(<ls_data>).
<ls_data>-sel = abap_true.
endloop.
endform. </code></pre><P> </P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_10-1752067741255.png" style="width: 527px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284548i254443464A229470/image-dimensions/527x257?v=v2" width="527" height="257" role="button" title="mubarakbashasyed_10-1752067741255.png" alt="mubarakbashasyed_10-1752067741255.png" /></span></STRONG></P><P><STRONG>All select and edit:</STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_8-1752071764325.png" style="width: 527px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284608i9D7091C02A5284D0/image-dimensions/527x179?v=v2" width="527" height="179" role="button" title="mubarakbashasyed_8-1752071764325.png" alt="mubarakbashasyed_8-1752071764325.png" /></span></STRONG></P><P><STRONG>Clicking ‘Deselect’ will uncheck all currently selected records. </STRONG></P><pre class="lia-code-sample language-abap"><code>form deselect .
loop at gt_data assigning field-symbol(<ls_data>).
<ls_data>-sel = abap_false.
endloop.
endform. </code></pre><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_11-1752067765126.png" style="width: 522px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/284549i7F69375BF3E55472/image-dimensions/522x261?v=v2" width="522" height="261" role="button" title="mubarakbashasyed_11-1752067765126.png" alt="mubarakbashasyed_11-1752067765126.png" /></span></STRONG></P><P> </P><pre class="lia-code-sample language-abap"><code>Tables: zdel_status.
*-----------------------------------------------------------------------------*
* Types Declaration
*-----------------------------------------------------------------------------*
types: begin of ty_status,
sel type abap_bool,
plant type zdel_status-plant, "Plant
deliveryno type zdel_status-deliveryno, "Delivery Number
statustime type zdel_status-statustime, "Status Time
location type zdel_status-location, "Location
status type zdel_status-status, "Status
celltab type lvc_t_styl,
end of ty_status.
*-----------------------------------------------------------------------------*
* Data Declaration
*-----------------------------------------------------------------------------*
data: gt_data type standard table of ty_status,
gr_grid type ref to cl_gui_alv_grid,
gr_cont type ref to cl_gui_custom_container,
gt_fcat type lvc_t_fcat,
gs_layout type lvc_s_layo,
gv_okcode type sy-ucomm.
*------------------------------------------------------------------------------*
* Select Options and Parameters
*------------------------------------------------------------------------------*
selection-screen begin of block bk1 with frame title text-t01.
select-options: s_plant for zdel_status-plant,
s_delv for zdel_status-deliveryno.
selection-screen end of block bk1.
*-------------------------------------------------------------------------------*
* F4 Help Event Handler Class
*-------------------------------------------------------------------------------*
class cl_event_receiver definition.
public section.
methods: on_f4 for event onf4 of cl_gui_alv_grid
importing er_event_data e_fieldname es_row_no .
methods: constructor.
endclass.
class cl_event_receiver implementation.
method constructor.
set handler on_f4 for gr_grid.
gr_grid->register_f4_for_fields(
it_f4 = value #( ( fieldname = 'STATUS' register = 'X' chngeafter = 'X' ) ) ).
endmethod.
method on_f4.
DATA: lt_return TYPE TABLE OF DDSHRETVAL.
if e_fieldname = 'STATUS'.
select distinct status from zdel_status into table (lt_flag) WHERE status NE ''.
APPEND INITIAL LINE TO lt_flag.
call function 'F4IF_INT_TABLE_VALUE_REQUEST'
exporting
retfield = 'STATUS'
value_org = 'S'
tables
value_tab = lt_flag
return_tab = lt_return
exceptions
parameter_error = 1
no_values_found = 2
others = 3.
if sy-subrc = 0 and lt_return is not initial.
field-symbols <table_modi> type lvc_t_modi.
assign er_event_data->m_data->* to <table_modi>.
<table_modi> = value #(
base <table_modi>
( row_id = es_row_no-row_id
fieldname = e_fieldname
value = lt_return[ 1 ]-fieldval ) ).
er_event_data->m_event_handled = 'X'.
endif.
endif.
endmethod.
endclass.
*------------------------------------------------------------------------------*
* Start Of Selection
*------------------------------------------------------------------------------*
start-of-selection.
perform get_data.
perform build_fcat.
perform build_layout.
call screen 100. // using call screen
data: gr_event_receiver type ref to cl_event_receiver.
*------------------------------------------------------------------------------*
* FORM: get data
*------------------------------------------------------------------------------*
form get_data.
clear gt_data.
select plant, deliveryno, statustime, location, status
from zdel_status
into table (lt_status)
where plant in @s_plant.
loop at lt_status into data(ls_status).
append value ty_status(
sel = abap_false
plant = ls_status-plant
deliveryno = ls_status-deliveryno
statustime = ls_status-statustime
location = ls_status-location
status = ls_status-status ) to gt_data.
endloop.
endform.
*------------------------------------------------------------------------------*
* MODULE: PBO
*------------------------------------------------------------------------------*
module status_0100 output.
set pf-status 'ZSTATUS'. //using custom set pf-status
if gr_cont is initial.
create object gr_cont
exporting
container_name = 'CNTNR'.
create object gr_grid
exporting
i_parent = gr_cont.
perform build_fcat.
gs_layout-stylefname = 'CELLTAB'. //container layout
gs_layout-no_rowmark = 'X'.
gs_layout-no_toolbar = 'X'.
call method gr_grid->set_table_for_first_display
exporting
i_structure_name = 'TY_STATUS'
is_layout = gs_layout
changing
it_fieldcatalog = gt_fcat
it_outtab = gt_data.
create object gr_event_receiver.
set handler gr_event_receiver->on_f4 for gr_grid.
endif.
endmodule.
*------------------------------------------------------------------------------*
* FORM: Bulid Field Catalog
*------------------------------------------------------------------------------*
form build_fcat.
clear gt_fcat.
gt_fcat = value lvc_t_fcat( ( fieldname = 'SEL' col_pos = 1 coltext = 'Sel' edit = abap_true checkbox = abap_true )
( fieldname = 'PLANT' col_pos = 2 coltext = 'Plant' edit = abap_false )
( fieldname = 'DELIVERYNO' col_pos = 3 coltext = 'Delivery No' edit = abap_false )
( fieldname = 'STATUSTIME' col_pos = 4 coltext = 'Status Time' edit = abap_false )
( fieldname = 'LOCATION' col_pos = 5 coltext = 'Location' edit = abap_false )
( fieldname = 'STATUS' col_pos = 6 coltext = 'Status' edit = abap_false f4availabl = 'X' ) ).
endform.
*&---------------------------------------------------------------------*
*& Form BUILD_LAYOUT
*&---------------------------------------------------------------------*
form build_layout .
gs_layout-stylefname = 'CELLTAB'.
gs_layout-no_rowmark = 'X'.
gs_layout-no_toolbar = 'X'.
endform.
*------------------------------------------------------------------------------*
* MODULE: PAI
*------------------------------------------------------------------------------*
module user_command_0100 input.
gv_okcode = sy-ucomm.
case gv_okcode.
when 'BACK'.
leave to screen 0.
when 'EDIT'.
gr_grid->check_changed_data( ).
perform set_cell_styles using abap_true .
perform refresh_grid.
when 'SAVE'.
perform save_to_db.
perform set_cell_styles using abap_false .
perform refresh_grid.
when 'REFRESH'.
perform get_data.
perform set_cell_styles using abap_false .
perform refresh_grid.
when 'SELECT'.
perform selectall.
perform refresh_grid.
when 'DESELECT'.
perform deselect.
perform set_cell_styles using abap_false.
perform refresh_grid.
endcase.
endmodule.
*------------------------------------------------------------------------------*
* FORM: Set Cell Style Based On Checkbox
*------------------------------------------------------------------------------*
form set_cell_styles using iv_enable type abap_bool .
loop at gt_data assigning field-symbol(<ls_data>).
clear <ls_data>-celltab.
if iv_enable = abap_true and <ls_data>-sel = abap_true.
data(ls_style) = value lvc_s_styl(
fieldname = 'STATUS'
style = cl_gui_alv_grid=>mc_style_enabled ).
append ls_style to <ls_data>-celltab.
endif.
endloop.
endform.
*------------------------------------------------------------------------------*
* FORM: Refresh Alv
*------------------------------------------------------------------------------*
form refresh_grid.
if gr_grid is bound.
gr_grid->refresh_table_display(
exporting is_stable = value lvc_s_stbl( row = 'X' col = 'X' ) ).
endif.
endform.
*------------------------------------------------------------------------------*
* FORM: Save Changes to ZDEL_STATUS
*------------------------------------------------------------------------------*
form save_to_db.
gr_grid->check_changed_data( ).
data count type i.
loop at gt_data assigning field-symbol(<ls_data>) where sel = abap_true.
update zdel_status
set status = <ls_data>-status
where plant = <ls_data>-plant
and deliveryno = <ls_data>-deliveryno.
count = count + 1.
if sy-subrc = 0.
<ls_data>-sel = abap_false.
endif.
endloop.
message count && ' Records Updated Successfully.' type 'S'.
commit work.
endform.
*&---------------------------------------------------------------------*
*& Form SELECTALL
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
form selectall .
loop at gt_data assigning field-symbol(<ls_data>).
<ls_data>-sel = abap_true.
endloop.
endform.
*&---------------------------------------------------------------------*
*& Form DESELECT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
form deselect .
loop at gt_data assigning field-symbol(<ls_data>).
<ls_data>-sel = abap_false.
endloop.
endform. </code></pre><P><STRONG>Conclusion:</STRONG></P><P>Implementing an editable ALV grid with selective row editing and a custom F4 help provides a powerful yet user-friendly way to manage data within SAP. By allowing updates only for chosen rows, you maintain control and reduce the risk of unintended changes. The addition of a tailored F4 help further enhances data quality by guiding users toward valid, business-specific input.</P><P><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a> </P><P><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Connectivity/pd-p/266264953119842772207986043063520" class="lia-product-mention" data-product="313-1">ABAP Connectivity</a> </P><P><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Extensibility/pd-p/338571334339306322581424656448659" class="lia-product-mention" data-product="315-1">ABAP Extensibility</a> </P><P> </P><P> </P><P> </P>2025-12-12T08:08:44.264000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/send-an-email-for-an-selected-record-using-a-sap-rap-restful-abap/ba-p/14259102Send an Email for an selected record Using a SAP RAP(RESTful ABAP Programming Model)2025-12-12T08:44:04.273000+01:00vinodkumarreddyappannagarihttps://community.sap.com/t5/user/viewprofilepage/user-id/2174225<P>Hi Everyone,</P><P><SPAN><STRONG>Scenario :</STRONG> Sending an Email for a Selected Record Using the RAP Model</SPAN></P><P><STRONG>Introduction:</STRONG></P><P><SPAN>In an SAP S/4HANA system, there is a need to send an email notification when a user selects or processes a specific record in a RAP (RESTful ABAP Programming)–based application. For example, when a sales order, request, or approval record is selected in the Fiori Elements app, an email should automatically be triggered to the responsible user or approver.</SPAN></P><P>1. Creation of <STRONG>Table</STRONG> :</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Service Header Table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zva_hdr_service {
key client : abap.clnt not null;
key serviceno : zva_serviceno not null;
servicename : zva_servicename;
startdate : abap.dats;
enddate : abap.dats;
@Semantics.amount.currencyCode : 'zva_hdr_service.currency'
amount : abap.curr(8,2);
currency : abap.cuky;
createdby : uname;
createdon : datum;
}</code></pre><P><SPAN>2. Creation of <STRONG>Root</STRONG> <STRONG>View Entity</STRONG> : </SPAN></P><P>In the <STRONG>SAP RESTful ABAP Programming Model (RAP)</STRONG>, the <STRONG>Root View Entity</STRONG> is the <STRONG>main CDS view entity</STRONG> that defines the <STRONG>data model</STRONG> and <STRONG>structure</STRONG> of the <STRONG>root business object</STRONG>.<BR />It serves as the <STRONG>entry point</STRONG> for the RAP business object and forms the foundation for its behavior and service exposure.</P><P>A Root View Entity is defined using the CDS keyword <EM>define root view entity.</EM> It typically represents the main database table or a combination of tables that store the business data.</P><P> </P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Root View'
@Metadata.ignorePropagatedAnnotations: true
define root view entity zva_header_serv_root as select from zva_hdr_service as Service
{
key Service.serviceno as Serviceno,
Service.servicename as Servicename,
Service.startdate as Startdate,
Service.enddate as Enddate,
@Semantics.amount.currencyCode: 'currency'
Service.amount as Amount,
Service.currency as Currency
}</code></pre><P> </P><P><SPAN>3. Creation of <STRONG>Projection View </STRONG>for <STRONG>Root View</STRONG> <STRONG>Entity</STRONG>:</SPAN></P><P>In <STRONG>SAP RAP</STRONG>, a <STRONG>Projection View</STRONG> is a <STRONG>Core Data Services (CDS) view</STRONG> that defines <STRONG>which parts of a Business Object (BO)</STRONG> — specifically its data and associations — are <STRONG>exposed to the outside world</STRONG> (for example, through an <STRONG>OData service</STRONG> or <STRONG>Fiori app</STRONG>).</P><P>It acts as a <STRONG>public interface</STRONG> of your business object.<BR />While the <STRONG>Root View Entity</STRONG> defines the <EM>complete internal data model</EM>, the <STRONG>Projection View</STRONG> determines the <EM>external view</EM> that users or external systems can access.</P><P> </P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Projection View'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define root view entity ZVA_HEADER_SERV_ROOT_pro as projection on zva_header_serv_root as Service
{
key Service.Serviceno,
Service.Servicename,
Service.Startdate,
Service.Enddate,
@Semantics.amount.currencyCode: 'Currency'
Service.Amount,
Service.Currency
}</code></pre><P><SPAN>4. Creation of <STRONG>Metadata Extensions</STRONG> for <STRONG>Projection View</STRONG>:</SPAN></P><P><SPAN>Metadata extensions are used to define <STRONG>UI-specific annotations</STRONG> for CDS views. They allow the separation of concerns by keeping the data model independent of UI-related semantics. These extensions are particularly useful for defining Fiori UI layouts and behaviors without modifying the underlying CDS view.</SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CORE
annotate entity ZVA_HEADER_SERV_ROOT_pro
with
{
:{ lineItem:[{ type: #FOR_ACTION , dataAction: 'SendEmail',label: 'Email' } ] }
:{ lineItem:[{ position:1 }],
selectionField: [{ position: 1 ,element: 'Serviceno' }] }
Serviceno;
:{ lineItem: [{ label: 'Service Name' , position:2 }],
selectionField: [{ position: 2 ,element: 'Servicename' }] }
Servicename;
: { lineItem: [{ label: 'Start Date' , position:3 }],
selectionField: [{ position: 3,element: 'Startdate' }] }
Startdate;
: { lineItem: [{ label: 'End Date' , position:4 }],
selectionField: [{ position: 4 ,element: 'Enddate'}] }
Enddate;
.lineItem: [{ label: 'Amount' , position:5 }]
Amount;
.lineItem: [{ label: 'Currency' , position:6 }]
Currency;
}</code></pre><P><SPAN>5. Creation of <STRONG>Root Abstract Entity</STRONG> :</SPAN></P><P><SPAN>A <STRONG>Root Abstract Entity</STRONG> is a CDS construct designed for modeling complex input parameters or non-standard operations in RAP. Unlike root view entities, abstract entities are not tied to database tables.</SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Email'
define root abstract entity zva_email_send
{
// Email : char200;
Email : zva_email;
}</code></pre><P> </P><P><SPAN>6. Creation of<STRONG> Behavior Definition for Root View or Consumption View</STRONG> and implement the classes:</SPAN></P><P><SPAN><STRONG>Behavior Definition (BDEF)</STRONG> is a key component that defines the transactional behavior of a RAP Business Object (BO). It specifies how the BO can be accessed and manipulated by consumers, such as creating, updating, or deleting records. The BDEF is always tied to a <STRONG>Core Data Services (CDS)</STRONG> data model, which includes at least one root entity.</SPAN></P><P><SPAN>A BDEF consists of two main parts: a <STRONG>header</STRONG> and one or more <STRONG>entity behavior definitions</STRONG>. The header defines the overall behavior, while the entity behavior definitions specify the characteristics and operations for each entity. These operations include standard actions like <STRONG><EM>create</EM></STRONG>, <STRONG><EM>update</EM></STRONG>, and <STRONG><EM>delete</EM></STRONG>, as well as custom actions, determinations, and validations.</SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>managed implementation in class zbp_va_header_serv_root unique;
strict ( 2 );
define behavior for zva_header_serv_root alias Service
persistent table ZVA_HDR_SERVICE
lock master
authorization master ( instance )
//etag master <field_name>
{
action SendEmail parameter zva_email_send;
}</code></pre><P><SPAN>Place the cursor on the class name, press ( Ctrl + 1 ), choose Implement the Class, and then activate the class.</SPAN></P><pre class="lia-code-sample language-abap"><code>CLASS lhc_Service DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR Service RESULT result.
METHODS SendEmail FOR MODIFY
IMPORTING keys FOR ACTION Service~SendEmail.
ENDCLASS.
CLASS lhc_Service IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.
METHOD SendEmail.
ENDMETHOD.
ENDCLASS.</code></pre><P><SPAN>Implementation of SendEmail Method:</SPAN></P><pre class="lia-code-sample language-abap"><code> " Implementation of the custom action SendEmail
METHOD SendEmail.
" Get the first selected record from the action context
DATA(ls_keys) = VALUE #( keys[ 1 ] OPTIONAL ).
DATA(p_email) = ls_keys-%param-Email.
"-------------------------
" Step 1: Validate email
"-------------------------
IF p_email IS INITIAL.
" No email provided -> return error message
APPEND VALUE #( %tky = ls_keys-%tky
%msg = new_message( id = 'ZVA_MSG'
number = '000'
severity = if_abap_behv_message=>severity-error ) )
TO reported-Service.
RETURN.
ENDIF.
IF NOT p_email CP '*@*.*'.
" Invalid email format -> return error message
APPEND VALUE #( %tky = ls_keys-%tky
%msg = new_message( id = 'ZVA_MSG'
number = '001'
severity = if_abap_behv_message=>severity-error ) )
TO reported-Service.
RETURN.
ENDIF.
"-------------------------
" Step 2: Read service data
"-------------------------
READ ENTITIES OF zva_header_serv_root
ENTITY Service
ALL FIELDS
WITH VALUE #( ( Serviceno = ls_keys-Serviceno ) )
RESULT DATA(lt_serv).
DATA(ls_serv) = lt_serv[ 1 ].
"-------------------------
" Step 3: Prepare and send email
"-------------------------
TRY.
" Create persistent send request (BCS)
DATA(lo_send_request) = cl_bcs=>create_persistent( ).
" Prepare HTML email body
DATA: lt_body TYPE soli_tab,
lv_html TYPE string,
lv_text TYPE string.
lv_text = 'Hi Good Morning..'.
" Add HTML table header
CONCATENATE
'<html><body>'
'<p>' lv_text '</p>'
'<h3>Service Details</h3>'
'<table border="1" cellpadding="8" cellspacing="0" style="border-collapse:collapse;">'
'<tr>'
'<th>Service Number</th>'
'<th>Service Name</th>'
'<th>StartDate</th>'
'<th>EndDate</th>'
'<th>Amount</th>'
'</tr>'
INTO lv_html SEPARATED BY space.
APPEND lv_html TO lt_body.
CLEAR lv_html.
" Add dynamic service data rows
LOOP AT lt_serv INTO ls_serv.
DATA(lv_amount) = ls_serv-Amount.
CONCATENATE
'<tr>'
'<td>' ls_serv-Serviceno '</td>'
'<td>' ls_serv-Servicename '</td>'
'<td>' ls_serv-Startdate '</td>'
'<td>' ls_serv-Enddate '</td>'
'<td>' lv_amount '</td>'
'</tr>'
INTO lv_html SEPARATED BY space.
APPEND lv_html TO lt_body.
CLEAR lv_html.
ENDLOOP.
" Set up document object for the email
DATA(lo_document) = cl_document_bcs=>create_document(
i_type = 'HTM'
i_text = lt_body
i_subject = 'Service Details' ).
" Add document to send request
lo_send_request->set_document( lo_document ).
" Set sender as current SAP user
lo_send_request->set_sender( cl_sapuser_bcs=>create( sy-uname ) ).
" Add recipient email
lo_send_request->add_recipient(
i_recipient = cl_cam_address_bcs=>create_internet_address( p_email ),
i_express = abap_true ).
" Send the email
DATA(lv_sent_to_all) = lo_send_request->send( ).
ENDTRY.
"-------------------------
" Step 4: Show success or error messages
"-------------------------
IF lv_sent_to_all = abap_true.
" Email sent successfully
APPEND VALUE #( %tky = ls_keys-%tky
%msg = new_message( id = 'ZVA_MSG'
number = '002'
severity = if_abap_behv_message=>severity-success ) )
TO reported-Service.
ELSE.
" Email sending failed
APPEND VALUE #( %tky = ls_keys-%tky
%msg = new_message( id = 'ZVA_MSG'
number = '003'
severity = if_abap_behv_message=>severity-error ) )
TO reported-Service.
ENDIF.
ENDMETHOD.</code></pre><P> </P><P><SPAN>7. Creation of <STRONG>Behavior Definition for Projection View</STRONG> and Implement the classes :</SPAN></P><P><SPAN>A <STRONG>Behavior Projection</STRONG> maps the transactional capabilities of the base behavior definition to a projection view. This allows for further customization of the behavior for specific use cases. For example:</SPAN></P><pre class="lia-code-sample language-abap"><code>projection implementation in class zbp_va_header_serv_root_pro unique;
strict ( 2 );
define behavior for ZVA_HEADER_SERV_ROOT_pro //alias <alias_name>
{
use action SendEmail ;
}</code></pre><P> <SPAN>Place the cursor on the class name, press ( Ctrl + 1 ), choose Implement the Class, and then activate the class.</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_0-1762167079334.png" style="width: 577px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335317iC6B428275E785138/image-dimensions/577x166?v=v2" width="577" height="166" role="button" title="vinodkumarreddyappannagari_0-1762167079334.png" alt="vinodkumarreddyappannagari_0-1762167079334.png" /></span></P><P>8. Creation of Service Definition for Consumption View :</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_1-1762167271502.png" style="width: 598px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335318i3A839E8EAF6EF448/image-dimensions/598x481/is-moderation-mode/true?v=v2" width="598" height="481" role="button" title="vinodkumarreddyappannagari_1-1762167271502.png" alt="vinodkumarreddyappannagari_1-1762167271502.png" /></span></P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Service Definition'
define service ZVA_HEADER_SERV_ROOT_PRO_SD {
expose ZVA_HEADER_SERV_ROOT_pro;
}</code></pre><P>9. Creation of Service Binding for Service Definition:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_0-1762167831491.png" style="width: 529px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335319iF53FABB738D4F17D/image-dimensions/529x357/is-moderation-mode/true?v=v2" width="529" height="357" role="button" title="vinodkumarreddyappannagari_0-1762167831491.png" alt="vinodkumarreddyappannagari_0-1762167831491.png" /></span></P><P>Click on public button and activate </P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_1-1762167958764.png" style="width: 625px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335321i5BC49F9DD2360817/image-dimensions/625x300/is-moderation-mode/true?v=v2" width="625" height="300" role="button" title="vinodkumarreddyappannagari_1-1762167958764.png" alt="vinodkumarreddyappannagari_1-1762167958764.png" /></span></P><P> </P><P>Click on preview button then navigate the fiori .</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Screenshot 2025-11-03 163745.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335322i2D5B81F28407426A/image-size/large/is-moderation-mode/true?v=v2&px=999" role="button" title="Screenshot 2025-11-03 163745.png" alt="Screenshot 2025-11-03 163745.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Screenshot 2025-11-03 164133.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335323iE4A2602E446A8CAA/image-size/large?v=v2&px=999" role="button" title="Screenshot 2025-11-03 164133.png" alt="Screenshot 2025-11-03 164133.png" /></span></P><P>Click on a Email button then open a popup then provide the email id.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_0-1762168588704.png" style="width: 601px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335326iE604C93EC956D43C/image-dimensions/601x482/is-moderation-mode/true?v=v2" width="601" height="482" role="button" title="vinodkumarreddyappannagari_0-1762168588704.png" alt="vinodkumarreddyappannagari_0-1762168588704.png" /></span></P><P>if email id is not provided it's shows the error and incorrect email provided also shows a error message. </P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_1-1762168619343.png" style="width: 546px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335327iC8A7894ADB79C531/image-dimensions/546x602?v=v2" width="546" height="602" role="button" title="vinodkumarreddyappannagari_1-1762168619343.png" alt="vinodkumarreddyappannagari_1-1762168619343.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_2-1762168743938.png" style="width: 648px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335328i1320F1DB9CF73CD0/image-dimensions/648x421/is-moderation-mode/true?v=v2" width="648" height="421" role="button" title="vinodkumarreddyappannagari_2-1762168743938.png" alt="vinodkumarreddyappannagari_2-1762168743938.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_3-1762168756550.png" style="width: 626px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335329i65C00DCD9180C754/image-dimensions/626x633/is-moderation-mode/true?v=v2" width="626" height="633" role="button" title="vinodkumarreddyappannagari_3-1762168756550.png" alt="vinodkumarreddyappannagari_3-1762168756550.png" /></span></P><P> </P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Screenshot 2025-11-03 152748.png" style="width: 569px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350785i02F4C37B2AACD8F8/image-size/large?v=v2&px=999" role="button" title="Screenshot 2025-11-03 152748.png" alt="Screenshot 2025-11-03 152748.png" /></span></P><P>Email sent successful then shows the success message.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_6-1762168821678.png" style="width: 615px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335333i46511C6A6CDD81D5/image-dimensions/615x200/is-moderation-mode/true?v=v2" width="615" height="200" role="button" title="vinodkumarreddyappannagari_6-1762168821678.png" alt="vinodkumarreddyappannagari_6-1762168821678.png" /></span></P><P>Go to SOST t-code we will check the the record.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Screenshot 2025-12-10 184410.png" style="width: 944px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350791i16EC7DBCD3881558/image-size/large?v=v2&px=999" role="button" title="Screenshot 2025-12-10 184410.png" alt="Screenshot 2025-12-10 184410.png" /></span></P><P>Select the record and click on display button</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Screenshot 2025-11-03 165445.png" style="width: 684px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/335338i41F679AE038FF885/image-size/large/is-moderation-mode/true?v=v2&px=999" role="button" title="Screenshot 2025-11-03 165445.png" alt="Screenshot 2025-11-03 165445.png" /></span></P><H2 id="toc-hId-1763871136"><STRONG><FONT size="4">Summary:</FONT> </STRONG></H2><P>In this implementation, a custom action <STRONG>SendEmail</STRONG> is added to a RAP BO to allow users to send an email containing service details directly from the application.</P><H3 id="toc-hId-1696440350"><FONT size="3"><STRONG> 1. Email Validation</STRONG></FONT></H3><P>The action first retrieves the email ID passed through the action parameters.<BR />It performs two validations:</P><UL><LI><P>Checks if the email field is empty</P></LI><LI><P>Checks if the email format is valid using a simple pattern <CODE>*@*.*</CODE><BR />If the validation fails, an error message is returned using RAP messaging.</P></LI></UL><H3 id="toc-hId-1499926845"><FONT size="3"><STRONG>2. Reading Service Data</STRONG></FONT></H3><P>The code reads the selected service record from the root entity (<CODE>zva_header_serv_root</CODE>) using <CODE>READ ENTITIES</CODE>.<BR />The retrieved fields are later used to dynamically build the email content.</P><H3 id="toc-hId-1303413340"><FONT size="3"><STRONG> 3. Building and Sending the Email</STRONG></FONT></H3><P>The email is sent using <STRONG>SAP Business Communication Services (BCS)</STRONG>:</P><UL><LI><P>A persistent send request (<CODE>cl_bcs</CODE>) is created</P></LI><LI><P>An HTML email body is built, including:</P><UL><LI><P>Greeting text</P></LI><LI><P>A formatted HTML table</P></LI><LI><P>Dynamically added service details</P></LI></UL></LI><LI><P>The document is attached to the send request as an HTML email (<CODE>HTM</CODE>)</P></LI><LI><P>Sender is set as the logged-in SAP user</P></LI><LI><P>Recipient is the email address entered by the user</P></LI><LI><P>The email is finally sent using <CODE>send( )</CODE></P></LI></UL><H3 id="toc-hId-1106899835"><FONT size="3"><STRONG>4. Success & Error Handling</STRONG></FONT></H3><P>After sending, the system returns:</P><UL><LI><P>A success message if the email was sent</P></LI><LI><P>An error message if the sending process failed</P></LI></UL><P>These messages are reported back through RAP’s <CODE>reported-</CODE> structure.</P><P><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a> ,</P><P><a href="https://community.sap.com/t5/c-khhcw49343/SAP+Fiori+for+SAP+S%25252F4HANA/pd-p/73555000100800000131" class="lia-product-mention" data-product="623-1">SAP Fiori for SAP S/4HANA</a> ,</P>2025-12-12T08:44:04.273000+01:00https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/abap-platform-in-sap-s-4hana-cloud-private-edition-and-sap-s-4hana-2025/ba-p/14289979ABAP Platform in SAP S/4HANA Cloud Private Edition and SAP S/4HANA 20252025-12-14T23:10:11.122000+01:00OlgaDolinskajahttps://community.sap.com/t5/user/viewprofilepage/user-id/6638<P>SAP S/4HANA Cloud Private Edition and SAP S/4HANA 2025 were released to the SAP customer base on October 8, 2025.</P><P>ABAP Platform 2025 is the technology platform underlying the release 2025 of SAP S/4HANA Cloud Private Edition and SAP S/4HANA and is shipped as part of these products, supporting only SAP HANA database with full exploitation of its advanced capabilities. In addition, ABAP Platform 2025 is part of <A href="https://me.sap.com/notes/3568504/E" target="_self" rel="noopener noreferrer">SAP S/4HANA Foundation 2025</A> for SAP HANA-only Add-Ons.</P><P>ABAP Platform 2025 is not shipped as a standalone product. ABAP Platform 2025 consists of the AS ABAP, the ABAP development tools for Eclipse, and several additional technology components which are required to run SAP S/4HANA Cloud Private Edition and SAP S/4HANA.<BR /><BR />Previous versions of SAP S/4HANA Private Edition and SAP S/4HANA such as 1610, 1709, 1809, 1909, 2020, 2021, 2022 and 2023 can be upgraded directly to the 2025 release, which is based on ABAP Platform 2025 (corresponding to <SPAN><A href="https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/ABENNEWS-81.html" target="_blank" rel="noopener noreferrer">SAP_BASIS 816</A></SPAN>).</P><H2 id="toc-hId-1766649611"><FONT color="#3366FF">Product Highlights</FONT></H2><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="2025_abap_platform_highlights.jpg" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/351817i005DC626988E769A/image-size/large?v=v2&px=999" role="button" title="2025_abap_platform_highlights.jpg" alt="2025_abap_platform_highlights.jpg" /></span></P><H2 id="toc-hId-1570136106"><FONT color="#3366FF">Presentation</FONT></H2><P>This presentation provides the SAP official external slide deck, just click on it to view:</P><P><A title="ABAP Platform 2025 - Overview and Product Highlights" href="https://www.sap.com/documents/2025/12/a43c7800-317f-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="abap_platform_2025.jpg" style="width: 723px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/351818i56128BEDA971EB19/image-dimensions/723x406?v=v2" width="723" height="406" role="button" title="abap_platform_2025.jpg" alt="abap_platform_2025.jpg" /></span></A></P><H2 id="toc-hId-1373622601"><FONT color="#3366FF">Overview</FONT></H2><P>ABAP Platform 2025 delivers innovations for the ABAP stack in different areas.</P><H3 id="toc-hId-1306191815"><FONT color="#666699">Clean core development</FONT></H3><P>In August 2025, SAP enhanced its extensibility guidelines by introducing the new <SPAN><A href="https://www.sap.com/documents/2024/09/20aece06-d87e-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">Clean core extensibility white paper</A></SPAN>. The sustainable and upgrade-safe ABAP extensibility model in SAP S/4HANA Cloud Private Edition and SAP S/4HANA fully relies on SAP clean core guiding principles, aiming to decouple custom extensions from SAP standard whenever possible. The refined SAP guidance for extensibility replaces binary clean core decisions with a more nuanced evaluation of classic ABAP extensions based on the clean core level concept. Evolving from the previous 3-tier model, the new extensibility model categorizes extensions into four levels (A, B, C, and D) and provides rules for ABAP classic extensions to meet the clean core level qualifications. Following this new clean core extensibility guidance the <SPAN><A href="https://www.sap.com/documents/2022/10/52e0cd9b-497e-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">ABAP extensibility guide</A></SPAN> was updated with technical guidelines to support the clean core level concept. The ABAP extensibility model was changed from 3-tier model to ABAP Cloud development (level A) and classic ABAP development (levels B, C and D).</P><P>The overall clean core guidance remained unchanged: always striving for the highest possible level of extensibility. ABAP Cloud is the SAP’s recommended development model for all new custom extensions in SAP S/4HANA private cloud and on-premise systems, whereby the classic ABAP extensibility can still be used to reach clean core, with a focus on upgrade-stability and code quality. This enables SAP customers and partners to transition to a clean core incrementally and at their own speed. SAP provides guidance for ABAP clean core development by offering a recommended list of APIs (so-called “classic APIs”) to be used in classic ABAP development. For governance of ABAP clean core development, the ABAP test cockpit (ATC) now supports the clean core level concept with new ATC checks (see the blog post <SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/abap-test-cockpit-atc-recommendations-for-governance-of-clean-core-abap/ba-p/14186130" target="_blank">ABAP test cockpit (ATC) recommendations for governance of clean core ABAP development</A></SPAN>). For governance of ABAP development for clean core in SAP S/4HANA private cloud or on-premise systems the remote <SPAN><A href="https://www.sap.com/documents/2025/11/38e238f7-2b7f-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">ATC in SAP BTP ABAP environment</A></SPAN> is the SAP recommended approach. </P><H3 id="toc-hId-1109678310"><FONT color="#666699"><STRONG>SAP Joule for Developers, ABAP AI capabilities</STRONG></FONT></H3><P>SAP Joule for Developers, ABAP AI capabilities are now key components and an integral part of AI-assisted ABAP Cloud development, also facilitating custom code transformation from ECC to SAP S/4HANA. The capabilities supporting developer tasks include Joule copilot in ABAP development tools for Eclipse, predictive code completion, code explanation and unit test generation for ABAP and ABAP CDS, app and service generation (including RAP BO generation), predictive business logic for RAP BOs, and OData consumption. The provided ABAP AI SDK, powered by Intelligent Scenario Lifecycle Management (ISLM), can be utilized for the implementation of AI capabilities in custom applications.</P><P>The custom code migration capabilities include docs chat for questions around custom code migration and S/4HANA simplifications, explanation of business purpose and processing logic of legacy code (ABAP reports), explanation of S/4HANA-related ATC findings in custom code, along with resolution recommendations based on S/4HANA simplification items and cookbooks (see the blog post <SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/sap-joule-for-developers-expands-to-private-cloud-accelerating-abap/ba-p/14237958" target="_blank">SAP Joule for Developers Expands to Private Cloud: Accelerating ABAP Innovation and Transformation</A></SPAN>).</P><H3 id="toc-hId-913164805"><FONT color="#666699"><STRONG>ABAP RESTful Application Programming Model (RAP)</STRONG></FONT></H3><P>Another major investment area in the 2025 release is the ABAP RESTful Application Programming Model, which powers modern development in both ABAP Cloud and classic ABAP, enabling the creation of delightful transactional SAP Fiori apps as well as local and web APIs. This release delivers new features to accelerate and enhance the development with RAP, including new generators to boost efficiency, support of CDS table entities as persistence layer, various capabilities for SAP Fiori elements-based UIs, such as collaborative draft, cross-BO scenarios, tree views, and event-driven side effects, as well as end-to-end extensibility options.</P><P>New ABAP Cloud generators for creating OData UI services with RAP BOs (with one or more entities) from scratch, with or without AI assistance, or for generating custom UI service based on RAP BO interface are provided. ABAP CDS table entities can be used as active persistence layer for managed RAP BOs without draft, replacing classic dictionary database tables.</P><P>Enhancements for building of SAP Fiori elements-based apps with RAP include the collaborative draft handling, which allows multiple users to work simultaneously and collaboratively on the same draft instance of an entity without blocking one another. You can now also build SAP Fiori UIs that use multiple RAP BOs interacting with each other. These cross-BO scenarios rely on cross-BO transactional enablement, where the entities of the participating RAP BOs are linked through so-called cross-BO associations. Read-only and editable tree view supports displaying and manipulating hierarchical data in SAP Fiori UIs, with options for drag and drop, cut and paste, reordering, and cascading delete. Event-driven RAP side effects enable asynchronous updates in SAP Fiori UIs. When such a specific RAP business event is raised, the associated side effect is triggered, and the defined targets are reloaded in the UI.</P><P>The privileged context can now be propagated in subsequent Entity Manipulation Language (EML) requests in reading and modifying operation. Further enhancement for the behavior definitions and the behavior pools are provided with this release.</P><H3 id="toc-hId-716651300"><FONT color="#666699"><STRONG>ABAP development tools for Eclipse (ADT)</STRONG></FONT></H3><P>Various enhancements are provided in ABAP development tools for Eclipse for ABAP development, RAP and ABAP CDS related development aspects, testing and troubleshooting, as well as overall IDE and productivity improvements.</P><P>Refactoring support for ABAP classes and interfaces was improved by activation of renaming changes by default, validation of new names and displaying long texts of exceptions. The new where-used dialog enables prefiltering of search results to focus on usages relevant for the concrete use case. There is a new property <EM>abaplv</EM> to filter object searches with the ABAP language version. There are new editors like for example for working with software component relations, Adobe Forms or maintaining intelligent scenarios and intelligent scenarios models which are required to run a solution based on generative AI. It is possible to create and edit CDS table entities and create for them behavior definitions.</P><P>In the area of ABAP unit tests, method calls in test classes can now be highlighted in different colors to distinguish their method contexts. Quick actions allow tests to be launched or templates for test classes to be inserted with a single mouse click. The failed assertions and status of test methods can be displayed directly in the source code editor. The unit tests can be rerun with coverage and coverage results can be cleared in the <EM>ABAP Coverage</EM> view. Additionally, there is a new AMDP Test Double Framework, and the CDS Test Double Framework now supports CDS hierarchy views.</P><P>In the ABAP debugger, it is now possible to display the memory consumption of a debugged ABAP program in the new <EM>ABAP Memory</EM> (Debugger) view. The <EM>ABAP Memory Snapshot</EM> view lists all memory snapshots, which can be opened in the editor to show memory objects ranked by size. These views make it easier to analyze the memory usage of an ABAP application. Internal tables can now be easily compared using the table comparison tool within the ABAP debugger. Beyond this, the ABAP debugger can now consider variables with hidden values (for sensitive data), display variables of type JSON, and show component groups for nested structures in the <EM>Variables</EM> view. Collaborative error analysis is supported by export/import of ABAP Cross Trace results to/from JSON file or export of short dumps as ZIP file in the <EM>ABAP Runtime Error Viewer</EM>.</P><P>Beyond this there are also enhancements in transport management for adding an object to a transport or searching and grouping transport requests.</P><H3 id="toc-hId-520137795"><FONT color="#666699"><STRONG>ABAP Language</STRONG></FONT></H3><P>The modern, declarative, and expression-oriented ABAP language allows writing simple and concise ABAP code through features such as inline declarations and constructor expressions. Advanced operations for internal tables include grouping, filtering, and the CORRESPONDING( ) operator. The cloud-optimized version “<EM>ABAP for Cloud Development</EM>” is used for ABAP Cloud development.</P><P>There are further enhancements for internal tables, including support for arbitrary logical expressions and equality conditions, as well as harmonization of table expressions and READ TABLE statement. <A href="https://community.sap.com/t5/technology-blog-posts-by-sap/random-numbers-and-probability-distributions-in-the-abap-environments-for/ba-p/14173266" target="_blank">New ABAP system classes for probability distributions</A> are provided, enabling the generation of random number and the calculation of quantile, probabilities, and other aspects. These classes support various discrete and continuous distributions. This release also delivers enhancements for expressions and functions, as well as for transformations, such as the new domain XSDGEO for serializing and deserializing spatial data between the Extended Well-Known Binary (EWKB) representation and the GeoJSON format.</P><H3 id="toc-hId-323624290"><FONT color="#666699"><STRONG>SAP HANA-centric optimizations & Data Integration scenarios</STRONG></FONT></H3><P>Modern ABAP development on SAP HANA has been enhanced with several advanced, database-centric features also enriching data integration scenarios. Recent innovations in data integration focus on data exposure, including ABAP-managed database procedures for advanced read scenarios. With CDS updatable view entities it is now possible to wrap existing DDIC database tables (or CDS table entities) and expose a native CDS signature, which can be used with ABAP SQL in combination with DCL-based access control. </P><P>On the consumption side, new write scenarios, the use of static CDS external entities, and the possibility to create ABAP CDS models based on imported CDS models make it easier than ever to integrate external data seamlessly into an ABAP CDS view stack.</P><P>Additional enhancements, such as CDS table entities to define and manage SAP HANA database tables as native CDS repository objects, a CDS generation wizard to simplify and automate the creation of hierarchically structured data in ABAP CDS, and AI-powered CDS Explain to get semantical context information about CDS entities further brighten the ABAP development landscape.</P><H3 id="toc-hId-127110785"><FONT color="#666699"><STRONG>Embedded analytics</STRONG></FONT></H3><P>For embedded analytics scenarios it is now possible to expedite development workflow using ABAP Cloud generator wizards for creation of multidimensional analysis apps, Review Booklet apps, or native CDS hierarchy definitions. With the introduction of reusable measures and filters, the key figures, measures, filters and many more features can now be defined centrally, based on user needs to better manage and align analytical reporting. They can also be utilized in CDS view entities to ensure homogenous definition of complex calculations and unification of coherences of the running business.</P><H3 id="toc-hId--144634089"><FONT color="#666699"><STRONG>Event Enablement & Business Events</STRONG></FONT></H3><P>The event-driven architecture of SAP S/4HANA Cloud Private Edition and SAP S/4HANA is strengthened, and the interoperability across enterprise solutions is improved through seamless integration with SAP Event Mesh Advanced Plan and support of SAP Cloud Application Event Hub to consume events published by SAP Order Management Foundation on SAP BTP.</P><P>The event-driven processing and monitoring was enhanced with new outbound event filtering, enabling selective publishing based on configurable criteria, and dynamic topics in SAP Event Mesh Advanced Plan for more efficient routing. Operational transparency was improved through comprehensive event logging, including local capture and logging of successfully processed events. Events of the same type and object within a session can now be grouped as activities, improving traceability and reducing monitoring noise. Together, these features provide a scalable and well-governed foundation for event-driven architecture.</P><H3 id="toc-hId--341147594"><FONT color="#666699"><STRONG>Process integration</STRONG><STRONG> & Connectivity</STRONG></FONT></H3><P>Key highlights of process integration include a robust OData service consumption model with Swagger UI preview and advanced OData V4 capabilities, such as bulk processing and asynchronous communication integrated with AIF. The API governance and communication management was enhanced by introducing Communication Targets within Communication Arrangements, enabling more granular control over connectivity endpoints. API lifecycle management is improved through API-to-package assignment and the ability to create API packages for better organization across API types. Additionally, OData-based access to Communication Management data increases automation, transparency, and integration with external tools.</P><P>Additional connectivity improvements include outbound communication enablement via HTTP and RFC, support for setting the AIR key as a custom HTTP header in SOAP requests for more secure message handling, direct push-based data exchange between ABAP systems via RFC, and SSE support in the ABAP HTTP client and server for efficient real-time event delivery in distributed scenarios.</P><H3 id="toc-hId--537661099"><FONT color="#666699"><STRONG>Key user extensibility</STRONG></FONT></H3><P>Further improvements are provided for key user extensibility. It is now possible to generate a Fiori elements application for a custom business object with just one click and maintain behavior extensions for SAP-provided RAP business objects using key user extensibility. Moreover, using developer extensibility it is now possible to implement feature control for custom fields that were created via the Custom Fields app. The new extension field wizard provides a better development efficiency by boosting the creation of custom fields via developer extensibility.</P><H3 id="toc-hId--734174604"><FONT color="#666699"><STRONG>Security</STRONG></FONT></H3><P>Key updates include support for OAuth Authorization Code with PKCE (RFC 7636) and JWT-based client authentication (RFC 7523), as well as SAP-managed client certificates for secure integration in S/4HANA Private Cloud (2025 FPS01). TLS 1.3 is now supported across HTTP, WebSocket RFC, and SMTP, with OAuth Client Credential Grant enabled for SMTP outbound scenarios such as Exchange Online.</P><P>Additional enhancements include new OpenID Connect features, improved troubleshooting guidance (SAP Note 3111813), and a new OAuth Client Configuration UI (SOAUTH_CLIENT) with built-in testing and token metadata display. </P><H2 id="toc-hId--637285102"><FONT color="#3366FF">Useful Blog Posts, Community pages and Learnings</FONT></H2><P>ABAP Community Topic Pages:</P><P><SPAN><A href="https://pages.community.sap.com/topics/abap" target="_blank" rel="noopener noreferrer">ABAP Development Community</A></SPAN><BR /><SPAN><A href="https://pages.community.sap.com/topics/abap-testing-analysis" target="_blank" rel="noopener noreferrer">ABAP Testing and Analysis Community </A></SPAN><BR /><SPAN><A href="https://pages.community.sap.com/topics/abap-extensibility" target="_blank" rel="noopener noreferrer">ABAP Extensibility Community</A></SPAN><BR /><SPAN><A href="https://pages.community.sap.com/topics/abap-connectivity" target="_blank" rel="noopener noreferrer">ABAP Connectivity Community</A></SPAN><BR /><SPAN><A href="https://pages.community.sap.com/topics/btp-abap-environment" target="_blank" rel="noopener noreferrer">SAP BTP ABAP Environment Community</A></SPAN><BR /><SPAN><A href="https://pages.community.sap.com/topics/s4hana-cloud-abap-environment" target="_blank" rel="noopener noreferrer">SAP S/4HANA Cloud ABAP Environment Community</A></SPAN></P><P>ABAP at SAP Events:</P><P><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/abap-cloud-sessions-at-sap-teched-in-2025/ba-p/14175995" target="_blank">ABAP Cloud at SAP TechEd in 2025</A></SPAN><BR /><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/abap-cloud-sessions-at-devtoberfest-2025/ba-p/14188138" target="_blank">ABAP Cloud at Devtoberfest in 2025</A></SPAN></P><P>Clean Core</P><P><SPAN><A href="https://www.sap.com/documents/2024/09/20aece06-d87e-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">Clean core extensibility</A></SPAN> white paper<BR /><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/abap-extensibility-guide-clean-core-for-sap-s-4hana-cloud-august-2025/ba-p/14175399" target="_blank">ABAP Extensibility Guide – Clean Core for SAP S/4HANA Cloud - August 2025 Update</A></SPAN><BR /><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/abap-test-cockpit-atc-recommendations-for-governance-of-clean-core-abap/ba-p/14186130" target="_blank">ABAP test cockpit (ATC) recommendations for governance of clean core ABAP development</A></SPAN><BR />ATC on SAP BTP: <SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/usage-of-abap-test-cockpit-atc-in-the-cloud-for-on-premise-developments/ba-p/13576887" target="_blank">blog</A></SPAN> | <SPAN><A href="https://www.sap.com/documents/2025/11/38e238f7-2b7f-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">overview presentation</A></SPAN><BR /><SPAN><A href="https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/certification-of-partner-solutions-following-clean-core/ba-p/13556247" target="_blank">Certification of Partner Solutions following Clean Core</A></SPAN></P><P>SAP Joule for Developers, ABAP AI capabilities</P><P><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/sap-joule-for-developers-expands-to-private-cloud-accelerating-abap/ba-p/14237958" target="_blank">SAP Joule for Developers Expands to Private Cloud: Accelerating ABAP Innovation and Transformation</A></SPAN><BR /><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/abap-ai-revolution-accelerates-the-abap-developer-who-built-enterprise-apps/ba-p/14216073" target="_blank">ABAP AI Revolution Accelerates: The ABAP Developer Who Built Enterprise Apps in Minutes</A></SPAN><BR /><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/from-legacy-to-ai-powered-rise-transformation-revolution-with-joule-for/ba-p/14267448" target="_blank">From Legacy to AI-Powered: RISE Transformation Revolution with Joule for developers</A></SPAN><BR /><SPAN><A href="https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/abap-ai-chapter-2/ba-p/14210568" target="_blank">ABAP AI - Chapter 2</A></SPAN></P><P>ABAP Cloud:</P><P><SPAN><A href="https://www.sap.com/documents/2022/10/52e0cd9b-497e-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">ABAP Exensibility Guide</A></SPAN><BR />Become <SPAN><A href="https://learning.sap.com/certification/sap-certified-associate-back-end-developer-abap-cloud" target="_blank" rel="noopener noreferrer">SAP Certified Associate – Back-End Developer - ABAP Cloud</A></SPAN><BR /><SPAN><A href="https://pages.community.sap.com/topics/abap/abap-cloud-faq" target="_blank" rel="noopener noreferrer">ABAP Cloud FAQ</A></SPAN><BR /><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/sap-build-and-abap-cloud-basic-trial-offering/ba-p/14117116" target="_blank">SAP Build and ABAP Cloud Basic Trial Offering</A></SPAN><BR /><A href="https://help.sap.com/docs/abap-cloud/developer-guide-from-classic-abap-to-abap-cloud/developer-guide-from-classic-abap-to-abap-cloud" target="_self" rel="noopener noreferrer"><SPAN>Developer Guide: From Classic ABAP to ABAP Cloud</SPAN> </A>on SAP Help Portal</P><P>Further blog posts and topic pages:</P><P><SPAN><A href="https://community.sap.com/topics/abap/rap" target="_blank">State-of-the-Art ABAP Development with ABAP RESTful Application Programming Model (RAP)</A></SPAN><BR /><SPAN><A href="https://blogs.sap.com/2023/10/09/abap-tools-for-clean-abap/" target="_blank" rel="noopener noreferrer">ABAP Tools for Clean ABAP</A></SPAN></P><H2 id="toc-hId--833798607"><FONT color="#3366FF">Useful Links</FONT></H2><P><A href="https://help.sap.com/whats-new/5fc51e30e2744f168642e26e0c1d9be1?Product_Line=SAP+S/4HANA+and+SAP+S/4HANA+Cloud+Private+Edition;SAP+S/4HANA+Cloud+Private+Edition&Business_Area=ABAP+Platform" target="_blank" rel="noopener noreferrer">Release Notes for ABAP Platform 2025</A><BR /><A href="https://help.sap.com/docs/ABAP_PLATFORM_NEW/b5670aaaa2364a29935f40b16499972d/48ba073157b85295e10000000a42189b.html" target="_blank" rel="noopener noreferrer">Documentation on SAP Help Portal</A><BR /><A href="https://apps.support.sap.com/sap(bD1lbiZjPTAwMQ==)/support/pam/pam.html#s=SAP%20S%2F4HANA%202020&o=most_viewed%7Cdesc&st=l&rpp=20&ts=5&page=1&pvnr=73554900100900003539&pt=g%7Cd" target="_blank" rel="noopener noreferrer">Product Availability Matrix (PAM)</A><BR /><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/the-abap-platform-strategy/ba-p/13413078" target="_blank">The ABAP Platform Strategy</A><BR /></SPAN><SPAN><A href="https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/abap-platform-releases-and-consumers/ba-p/13438776" target="_blank">ABAP Platform Releases and Consumers</A><BR /></SPAN><SPAN><A href="https://me.sap.com/notes/3612209/E" target="_blank" rel="noopener noreferrer">SAP Note 3612209 – ABAP Platform 2025 – General information</A></SPAN></P><H2 id="toc-hId--1030312112"><FONT color="#3366FF">Previous landing pages</FONT></H2><P><SPAN><A href="https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/abap-platform-for-sap-s-4hana-2023/ba-p/13573791" target="_blank">ABAP Platform for SAP S/4HANA 2023</A><BR /></SPAN><SPAN><A href="https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/abap-platform-for-sap-s-4hana-2022/ba-p/13562774" target="_blank">ABAP Platform for SAP S/4HANA 2022</A><BR /></SPAN><SPAN><A href="https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/abap-platform-for-sap-s-4hana-2021/ba-p/13514539" target="_blank">ABAP Platform for SAP S/4HANA 2021</A><BR /></SPAN><SPAN><A href="https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/abap-platform-for-sap-s-4hana-2020/ba-p/13481357" target="_blank">ABAP Platform for SAP S/4HANA 2020</A><BR /></SPAN><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/abap-platform-for-sap-s-4hana-1909/ba-p/13399472" target="_blank">ABAP Platform for SAP S/4HANA 1909</A><BR /></SPAN><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/abap-platform-for-sap-s-4hana-1809/ba-p/13356978" target="_blank">ABAP Platform for SAP S/4HANA 1809</A><BR /></SPAN><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/sap-netweaver-as-for-abap-7-52-available-now/ba-p/13342473" target="_blank">SAP NetWeaver AS for ABAP 7.52</A><BR /></SPAN><SPAN><A href="https://community.sap.com/t5/technology-blog-posts-by-sap/sap-netweaver-as-for-abap-7-5-one-abap-platform-for-sap-business-suite-and/ba-p/13278977" target="_blank">SAP NetWeaver AS ABAP 7.50</A></SPAN></P><P> </P>2025-12-14T23:10:11.122000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/hide-show-field-in-ui-dynamically-through-virtual-elements-in-rap/ba-p/14271595Hide/Show Field In UI Dynamically Through Virtual Elements In RAP2025-12-15T06:39:16.774000+01:00harsha_reddy24https://community.sap.com/t5/user/viewprofilepage/user-id/2263071<P><BR /><STRONG>Hi RAP Developers, Good Day<BR /><BR />Introduction:</STRONG><BR />In the SAP RAP (RESTful ABAP Programming Model), enhancing UI behavior dynamically is a common requirement, especially when business rules demand that certain fields be shown or hidden based on the underlying data. While RAP provides powerful mechanisms for extending behavior, one of the most flexible techniques for achieving dynamic UI control is through <STRONG>virtual elements</STRONG>.<BR /><BR /><STRONG>Solution Overview:</STRONG></P><P>Virtual elements allow developers to calculate values at runtime without physically storing them in the database. Beyond computed fields, they can also serve as <EM>UI control flags, </EM>for example, determining whether a field should be visible, editable, or hidden in the Fiori Elements UI. In this blog, we explore how to leverage virtual elements to dynamically show or hide UI fields based on data conditions. Using a simple ABAP class implementation, we demonstrate how a virtual field can drive UI visibility logic efficiently within RAP.</P><P><STRONG><BR />Projection View:</STRONG></P><pre class="lia-code-sample language-abap"><code>@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_HIDE_VIRT'
virtual ishide : abap_boolean</code></pre><P><STRONG>Metadata Extension:<BR /></STRONG></P><pre class="lia-code-sample language-abap"><code> " Hide field from Identification section based on virtual element 'ishide'
.identification: [{ position: 40, hidden: #( ishide ) }]
" Display field in Line Item section
.lineItem: [{ position: 30 }]
" Make field available as a Selection Field
.selectionField: [{ position: 30 }]
" Business field – Total Price
TotalPrice;</code></pre><P><STRONG>Implement Virtual Elements:</STRONG></P><pre class="lia-code-sample language-abap"><code>CLASS zcl_hide_virt DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
" SADL Exit Interface
INTERFACES if_sadl_exit .
" Interface for Virtual Element Calculation (Read)
INTERFACES if_sadl_exit_calc_element_read .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_hide_virt IMPLEMENTATION.
METHOD if_sadl_exit_calc_element_read~calculate.
"------------------------------------------------------------------
" Purpose: Populate virtual element 'ishide' based on TotalPrice
" to control field visibility in the UI.
"------------------------------------------------------------------
DATA : lt_virtual TYPE TABLE OF zc_tbjrn.
" Copy original data to local internal table
lt_virtual = CORRESPONDING #( it_original_data ).
" Loop through internal table and set virtual element value
LOOP AT lt_virtual ASSIGNING FIELD-SYMBOL(<fs_travel>).
" Set ishide = abap_true when TotalPrice <= 142, else false
<fs_travel>-ishide = COND abap_boolean(
WHEN <fs_travel>-totalprice LE 142
THEN abap_true
ELSE abap_false ).
ENDLOOP.
" Return updated table with calculated virtual element
ct_calculated_data = CORRESPONDING #( lt_virtual ).
ENDMETHOD.
METHOD if_sadl_exit_calc_element_read~get_calculation_info.
" No additional calculation info required
ENDMETHOD.
ENDCLASS.</code></pre><P><STRONG>Preview:<BR /><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="hide.png" style="width: 527px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/342119iCF395FE5E4C66B36/image-dimensions/527x103/is-moderation-mode/true?v=v2" width="527" height="103" role="button" title="hide.png" alt="hide.png" /></span><BR />Conclusion:</STRONG></P><P>By leveraging virtual elements together with the SADL exit class, we can dynamically control field visibility in RAP applications without modifying the actual database layer. This approach provides a clean separation between data and UI logic, improves performance, and keeps the design fully extensible. With a simple calculation exit, fields like <EM>Hide Indicator</EM> can be determined at runtime based on business rules, allowing the UI to react instantly and display only what is relevant to the user. This method ensures a smarter, more flexible, and more maintainable RAP application.</P><P><STRONG>Thanks For Reading My Blog..</STRONG></P><P><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Connectivity/pd-p/266264953119842772207986043063520" class="lia-product-mention" data-product="313-1">ABAP Connectivity</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/SAP+BTP+ABAP+environment/pd-p/73555000100800001164" class="lia-product-mention" data-product="11-1">SAP BTP ABAP environment</a> </P>2025-12-15T06:39:16.774000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/timestamp-conversion-for-different-user-time-zones-in-abap/ba-p/14286971Timestamp Conversion for Different User Time Zones in ABAP2025-12-15T06:48:28.394000+01:00mubarakbashasyedhttps://community.sap.com/t5/user/viewprofilepage/user-id/2189365<P>Hello Everyone!</P><P>Recently, I worked on a timestamp conversion issue related to <STRONG>user-specific time zones</STRONG> in SAP. The data stored in the SAP level was correct, but when displayed through an ABAP report, the timestamp appeared incorrect for some users.</P><P>After analyzing the issue, I found that the root cause was the <STRONG>conversion routine defined in the domain</STRONG>. This routine automatically converts timestamps based on the user's logon time zone, which caused mismatches during display.</P><P>In this blog, I will show how to resolve this issue by converting all timestamps to <STRONG>UTC</STRONG> before displaying them, ensuring consistent results for every user—regardless of their time zone or domain settings.</P><H2 id="toc-hId-1766560230"><STRONG>Problem Summary</STRONG></H2><UL><LI><P>The timestamp stored in the database table (<CODE>ZDEL_INFO</CODE>) was correct.</P></LI><LI><P>But when displaying the data in a report, the timestamp appeared incorrect for some users.</P></LI><LI><P>This happened because the domain of the timestamp field had a conversion routine (e.g., <CODE>TZNTSTMPS</CODE>).</P></LI><LI><P>As a result, SAP automatically converted timestamps based on each user's time zone.<BR /><BR /></P></LI></UL><P><STRONG>Example:</STRONG></P><P><STRONG>Domain with Conversion Routine:</STRONG><BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="image.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350248i10F02E45DE41FE09/image-size/large?v=v2&px=999" role="button" title="image.png" alt="image.png" /></span><BR /><STRONG>Table:</STRONG><BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="image.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350250iE0C640F7A076221B/image-size/large?v=v2&px=999" role="button" title="image.png" alt="image.png" /></span><BR /><STRONG>Report:</STRONG><BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="image.png" style="width: 712px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350219i7F87989184C7CC10/image-size/large?v=v2&px=999" role="button" title="image.png" alt="image.png" /></span></P><H2 id="toc-hId-1570046725"><STRONG>Solution Approach</STRONG></H2><OL><LI><P>Read timestamp values from the database.</P></LI><LI><P>Convert <STRONG>local timestamp → UTC timestamp</STRONG> using:</P></LI></OL><P>cl_kf_helper=>timestamp_local_zone_2_utc</P><P>3.Populate the final internal table with the corrected timestamp.</P><P>4.Display the data using <STRONG>CL_SALV_TABLE</STRONG>.</P><P>By converting timestamps to UTC, the displayed values remain consistent for all users.</P><pre class="lia-code-sample language-abap"><code>*&---------------------------------------------------------------------*
*& Report ZTIMESTAMPS_USERS
*&---------------------------------------------------------------------*
*& Purpose:
*& This report reads delivery data from table ZDEL_INFO,
*& converts local timestamps into UTC based on the user’s time zone,
*& and displays the results using CL_SALV_TABLE.
*&---------------------------------------------------------------------*
REPORT ztimestamps_users.
TABLES: zdel_info.
TYPES: BEGIN OF ty_del,
deliveryno TYPE zdel_info-deliveryno,
material TYPE zdel_info-material,
deldate TYPE zdel_info-deldate,
END OF ty_del.
DATA: lt_final TYPE TABLE OF ty_del,
ls_final TYPE ty_del.
*START-OF-SELECTION.
START-OF-SELECTION.
SELECT * FROM zdel_info
INTO TABLE (lt_del).
LOOP AT lt_del INTO DATA(ls_del).
ls_final-deliveryno = ls_del-deliveryno.
ls_final-material = ls_del-material.
IF ls_del-deldate IS NOT INITIAL.
CALL METHOD cl_kf_helper=>timestamp_local_zone_2_utc
EXPORTING
i_timestamp_local = ls_del-deldate " Timestamp in user's local time
i_time_zone = sy-zonlo " Current user's time zone
RECEIVING
r_timestamp_utc = DATA(lv_tmstamputc). " Converted UTC timestamp
ls_final-deldate = lv_tmstamputc.
CLEAR lv_tmstamputc.
ENDIF.
APPEND ls_final TO lt_final.
ENDLOOP.
DATA: o_alv TYPE REF TO cl_salv_table.
cl_salv_table=>factory(
IMPORTING
r_salv_table = o_alv
CHANGING
t_table = lt_final ).
* Display the ALV
o_alv->display( ).</code></pre><P><STRONG>Output:</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="image.png" style="width: 747px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350252i568018306611C8B4/image-size/large?v=v2&px=999" role="button" title="image.png" alt="image.png" /></span></P><H2 id="toc-hId-1373533220"><STRONG>Explanation of Key Logic</STRONG></H2><H3 id="toc-hId-1306102434"><STRONG>1. </STRONG><CODE>timestamp_local_zone_2_utc</CODE></H3><P>This method converts a timestamp from the user’s local time zone (based on <CODE>SY-ZONLO</CODE>) to UTC.</P><H3 id="toc-hId-1109588929"><STRONG>2. Why Convert to UTC?</STRONG></H3><P>UTC is a universal reference.<BR />Once converted to UTC, the timestamp remains consistent, regardless of:</P><UL><LI><P>User logon time zone</P></LI><LI><P>System time zone</P></LI><LI><P>Conversion routines in the domain</P></LI></UL><H3 id="toc-hId-913075424"><STRONG>3. Output Using SALV</STRONG></H3><P><CODE>CL_SALV_TABLE</CODE> is used for a simple and clean ALV output without advanced configuration.</P><H2 id="toc-hId-587479200"><STRONG>Conclusion</STRONG></H2><P>Handling timestamps in SAP can be challenging, especially when conversion routines and user time zones come into play.<BR />By converting timestamps to UTC before displaying them, we avoid incorrect values and ensure reliable reporting across all users.<BR /><STRONG>It will have been Very Helpful for Real Time users in Project works<BR />this has a process of just like small solution thank you...<BR /><BR /></STRONG></P><P><BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Connectivity/pd-p/266264953119842772207986043063520" class="lia-product-mention" data-product="313-1">ABAP Connectivity</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Extensibility/pd-p/338571334339306322581424656448659" class="lia-product-mention" data-product="315-1">ABAP Extensibility</a> </P>2025-12-15T06:48:28.394000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/hierarchical-alv-using-factory-method-in-sap-abap/ba-p/14147119Hierarchical ALV Using Factory Method in SAP ABAP2025-12-15T06:50:35.551000+01:00vinodkumarreddyappannagarihttps://community.sap.com/t5/user/viewprofilepage/user-id/2174225<P>In this blog post, we’ll explore how to implement a <STRONG>Hierarchical ALV</STRONG> using the<STRONG> Factory Method </STRONG>of the CL_SALV_HIERSEQ_TABLE class.</P><H2 id="toc-hId-1734258920"><FONT size="4"><STRONG>Introduction</STRONG></FONT></H2><P>In many SAP ERP scenarios, business users frequently work with data that follows a natural master–detail relationship, such as customers and their contacts, vendors and their company-code assignments, or materials and their storage locations. Presenting such related datasets in a clean and intuitive format is critical for efficient decision-making.</P><P>While traditional ALV is highly effective for displaying single-level tables, it becomes less practical when dealing with multi-level or dependent datasets. For these situations, SAP provides <STRONG>Hierarchical ALV</STRONG> through the class <STRONG>CL_SALV_HIERSEQ_TABLE</STRONG>, allowing developers to present complex data relationships in an expandable, easy-to-navigate layout within SAP GUI.</P><P>This blog demonstrates how to create a hierarchical ALV using a vendor master table and its corresponding item details. The objective is to show how straightforward it is to bind two related datasets, define the hierarchy mapping, and display the result using SAP’s SALV framework—all with clean, maintainable ABAP code.</P><H2 id="toc-hId-1537745415"><FONT size="4"><STRONG>Scenario Overview</STRONG></FONT></H2><P>We will work with two custom tables:</P><UL><LI><P><FONT size="3"><STRONG>ZVA_VENDOR_TA</STRONG> </FONT>– Stores vendor master information (header level).</P></LI><LI><P><FONT size="3"><STRONG>ZVA_VENDOR_ITEM</STRONG></FONT> – Stores vendor-specific or company-code-specific details (item level).</P></LI></UL><P>The goal is to display these tables in a hierarchical ALV, where each vendor (header) can be expanded to reveal its associated item entries (detail).</P><P><STRONG>CODE:</STRONG></P><pre class="lia-code-sample language-abap"><code>REPORT ZVA_FACTORY_HIERACY_ALV.
" Declaration of internal tables and work areas for hierarchical ALV binding
DATA: LT_HIERSEQ TYPE SALV_T_HIERSEQ_BINDING,
LS_HIERSEQ TYPE SALV_S_HIERSEQ_BINDING.
" Select vendor master data from custom table ZVA_VENDOR_TA
SELECT VENDERNO, NAME, CITY, POSTALCODE, EMAIL, ACCOUNTGROUP, PROCESSORGROUP, POSTINGBLOCK
FROM ZVA_VENDOR_TA INTO TABLE (LT_VENDOR).
" Check if data is available in the LT_VENDOR table
IF sy-subrc = 0.
" If vendor data exists, select corresponding vendor item details from ZVA_VENDOR_ITEM
SELECT VENDERNO, COMPANYCODE, PERSONNELNUMBER, AUTHORGROUP, NTGEW, GEWEI, EKORG, STATUS
FROM ZVA_VENDOR_ITEM INTO TABLE (LT_VENDOR_ITEM).
ENDIF.
" Define the hierarchy relationship between the master and detail tables
LS_HIERSEQ-MASTER = 'VENDERNO'. " Master key field (header level)
LS_HIERSEQ-SLAVE = 'VENDERNO'. " Corresponding key field in detail (item level)
APPEND LS_HIERSEQ TO LT_HIERSEQ. " Add the mapping to the hierarchy sequence table
" Create and display the hierarchical ALV using CL_SALV_HIERSEQ_TABLE
CALL METHOD CL_SALV_HIERSEQ_TABLE=>FACTORY
EXPORTING
T_BINDING_LEVEL1_LEVEL2 = LT_HIERSEQ " Define the binding between header and item tables
IMPORTING
R_HIERSEQ = DATA(LO_SALV_HIERSEQ) " Get reference to the hierarchical ALV object
CHANGING
T_TABLE_LEVEL1 = LT_VENDOR " Pass header (vendor) data
T_TABLE_LEVEL2 = LT_VENDOR_ITEM. " Pass item (vendor details) data
" Display the hierarchical ALV
LO_SALV_HIERSEQ->DISPLAY( ).</code></pre><P><STRONG>Output :</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="88c198c9-0af1-436e-a69f-a81ceb8902bd.jpg" style="width: 800px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/283957i48820027D15AE42A/image-size/large?v=v2&px=999" role="button" title="88c198c9-0af1-436e-a69f-a81ceb8902bd.jpg" alt="88c198c9-0af1-436e-a69f-a81ceb8902bd.jpg" /></span></P><H1 id="toc-hId-1212149191"><FONT size="4"><STRONG>Conclusion</STRONG></FONT></H1><P>Hierarchical ALV is a powerful tool for presenting master–detail datasets in an organized and interactive format. The class <STRONG>CL_SALV_HIERSEQ_TABLE</STRONG> significantly simplifies the development process by handling the hierarchy logic internally, allowing developers to focus on data retrieval and business requirements rather than UI complexity.</P><P>By implementing this approach, organizations can deliver reports that are not only visually clear but also easier for end users to navigate—especially when dealing with multi-level relational data. This technique remains highly relevant for SAP GUI-based reporting and continues to be an important part of the ABAP developer’s toolkit.</P><P>If needed, this solution can be extended to support additional hierarchy levels, custom toolbar functions, or integration with business logic, making it flexible enough for advanced reporting scenarios.</P><P><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a> </P><P> </P>2025-12-15T06:50:35.551000+01:00https://community.sap.com/t5/abap-blog-posts/building-a-real-rap-application-step-by-step-vlog-series-introduction/ba-p/14290896Building a Real RAP Application Step by Step — Vlog Series Introduction2025-12-15T21:13:47.721000+01:00Kinsbrunnerhttps://community.sap.com/t5/user/viewprofilepage/user-id/124164<H1 id="toc-hId-1638221392">Introduction</H1><P>This vlog series aims to demonstrate how to build a real-life ABAP RAP application, following a practical, incremental, and production-oriented approach.</P><BLOCKQUOTE><P>Disclaimer:</P><P>This series focuses on showcasing how a RAP application can be built incrementally from real functional requirements. The app is intentionally kept practical and educational, rather than exhaustive or fully hardened for production. Some edge cases or potential enhancements are intentionally not covered.</P><P>The purpose of the vlog is to share knowledge, demonstrate real development workflows, and contribute to the SAP community, not to deliver a fully polished commercial-grade application.</P><P>To allow anyone to follow the vlog series, I will be using an SAP BTP Trial. This environment carries several limitations compared to a customer system, but it is perfectly sufficient for demonstrating the concepts and end-to-end implementation</P></BLOCKQUOTE><P>Instead of showing a pre-built demo or isolated RAP examples, the series walks through the development process from scratch, implementing the application one requirement at a time, exactly as it would be done in an actual ABAP Cloud project.</P><P>Each episode focuses on a small, well-defined set of user stories, keeping the learning process smooth and allowing you to see how the application grows after every step. The structure ensures the app is testable from the very beginning, and every enhancement is immediately visible in the UI preview.</P><P>If you want to understand RAP not just in theory but in practice, including determinations, validations, feature control, actions, side effects, completeness checks, semantic keys, and UI configuration, this series is for you.</P><P> </P><H1 id="toc-hId-1441707887">What are we going to build?</H1><P>We’ll be developing an internal equipment request application for a consulting firm.</P><P>Employees can request items kept in internal stock (laptops, monitors, headsets, etc.).</P><P>Each request follows a simple lifecycle:</P><UL><LI>Not Prepared / In Preparation / Delivered / <EM>(later also Cancelled)</EM></LI></UL><P>Each request includes header data (requester, deadline, priority, status) and one or more items referencing products from a customizing table of available materials.</P><P>The scenario is intentionally simple but rich enough to cover the most important RAP concepts: CDS data modeling, RAP behavior definitions in managed scenarios, Semantic keys, Determinations & validations, UI annotations, Feature control, Prechecks, Popup actions, Value helps, Inline editing, Integration with customizing tables, ABAP Cloud–compliant development practices.</P><P> </P><H1 id="toc-hId-1245194382">How the Vlog is structured</H1><P>The application is built based on a list of functional requirements expressed as user stories. These stories are implemented in the same order they would typically be addressed in a real project. The format of each episode is:</P><UL><LI><STRONG>Short and focused</STRONG> (usually covering 1-3 user stories)</LI><LI><STRONG>Incremental</STRONG> (the app evolves visibly every episode)</LI><LI><STRONG>Practical</STRONG> (every change is immediately testable)</LI><LI><STRONG>Aligned with ABAP Cloud guidelines</STRONG></LI><LI><STRONG>Designed for long-term learning and reference</STRONG></LI></UL><P>Whether you're starting with RAP or expanding your expertise, this series aims to provide a clear, realistic, and reusable learning path.</P><P> </P><H1 id="toc-hId-1048680877">Full requirement backlog (User Stories)</H1><P>Below is the collection of user stories implemented throughout the series, listed in almost the exact order used for development:</P><P><STRONG>US-01: Basic request object:</STRONG> As an employee, I want to create internal equipment requests so that I can receive the products I need.</P><P><STRONG>US-02: Search and Filter capabilities:</STRONG> As a user, I want to search requests using structured filters so that I can quickly locate relevant orders. I need to be able to search through the following criteria:</P><UL><LI>free search field,</LI><LI>by Requester (with search help),</LI><LI>by Priority (drop-down )</LI><LI>by Status (drop-down with multiple selections).</LI></UL><P><STRONG>US-03: Sequential External ID and semantic key:</STRONG> As the system, I want to assign each request a sequential external number so that users can reference meaningful IDs.</P><P><STRONG>US-04: Mandatory fields:</STRONG> As a user, I want the system to require Requester Name and Deadline Date so that requests are always complete.</P><P><STRONG>US-05: Deadline validation:</STRONG> As the system, I want to validate that the deadline date is at least one day in the future so that operations can prepare on time.</P><P><STRONG>US-06: Automatic priority determination:</STRONG> As the system, I want priority to be set based on deadline so that urgent requests receive proper attention (High: < 3 days, Medium: <7 days, otherwise, Low).</P><P><STRONG>US-07: Status icons:</STRONG> As a user, I want statuses displayed with colored icons so that I can understand them at a glance.</P><P><STRONG>US-08: Cancel status restrictions:</STRONG> As a user, I want to search for cancelled requests but not manually set status as “Cancelled” so that lifecycle rules are respected.</P><P><STRONG>US-09: Default status:</STRONG> As the system, I want new requests to default to “In Preparation” so that the lifecycle begins correctly.</P><P><STRONG>US-10: Status editability rules:</STRONG> As a user, I want status to be editable only after creation so that inconsistencies are avoided.</P><P><STRONG>US-11: Cancel action:</STRONG> As a user, I want to cancel one or more requests from the list so that I can invalidate unnecessary requests.</P><P><STRONG>US-12: Cancellation popup:</STRONG> As a user, I want to cancel and justify cancellations through a popup so that the system enforces to have reasons registered.</P><P><STRONG>US-13: Cancel reason rules:</STRONG> As a user, I want “Cancellation Reason” to be editable only when status is “Cancelled” so that it appears available only when relevant.</P><P><STRONG>US-13b:</STRONG> changing dynamic field hiding approach from CDS into virtual element.</P><P><STRONG>US-14: No editing after cancellation:</STRONG> As the system, I want cancelled requests to become read-only so that historical data is kept intact.</P><P><STRONG>US-15: Product catalog restriction:</STRONG> As a user, I want to select products only from internal stock so that I request only available items. Internal stock is customized through a customizing table.</P><P><STRONG>US-16: Product value help:</STRONG> As a user, I want a value help showing only available products so that selection is efficient.</P><P><STRONG>US-17: Unique product per request:</STRONG> As a system, I want to prevent duplicate products within a request so that items remain consistent.</P><P><STRONG>US-18: Item creation via popup:</STRONG> As a user, I want to create items in a popup and edit them inline so that maintenance is fast and intuitive.</P><P><STRONG>US-19: Make popup fields mandatory:</STRONG> As a system, I want to ensure that the data entered through the Product popup is complete.</P><P><STRONG>US-20: Make item fields mandatory:</STRONG> As a system, I want to ensure that the data entered through the Product object page is complete.</P><P> </P><H1 id="toc-hId-852167372">Episode Roadmap</H1><P>Each episode implements a specific subset of user stories. Episodes are planned to be released on a <STRONG>weekly basis (approx.)</STRONG>. Episode 1 will be released shortly, before end of year!</P><P> </P><TABLE width="723px"><TBODY><TR><TD width="40px">01</TD><TD width="473.25px">Project introduction + Data model basics</TD><TD width="208.75px">US-01</TD></TR><TR><TD width="40px">02</TD><TD width="473.25px">Service exposure + First UI (read-only) preview</TD><TD width="208.75px">US-01</TD></TR><TR><TD width="40px">03</TD><TD width="473.25px">Basic behavior + Search fields (Part 1): Free text + Requester</TD><TD width="208.75px">US-02 (Requester + Free text)</TD></TR><TR><TD width="40px">04</TD><TD width="473.25px">Search fields (Part 2): Status & Priority</TD><TD width="208.75px">US-02 (Status + Priority)</TD></TR><TR><TD width="40px">05</TD><TD width="473.25px">Semantic key & Sequential numbering</TD><TD width="208.75px">US-03</TD></TR><TR><TD width="40px">06</TD><TD width="473.25px">Mandatory fields + Deadline validation</TD><TD width="208.75px">US-04 + US-05</TD></TR><TR><TD width="40px">07</TD><TD width="473.25px">Automatic Priority determination + Status icons & visual enhancements</TD><TD width="208.75px">US-06 + US-07</TD></TR><TR><TD width="40px">08</TD><TD width="473.25px">Status behavior rules</TD><TD width="208.75px">US-08 + US-09 + US-10</TD></TR><TR><TD width="40px">09</TD><TD width="473.25px">Cancel feature (Part 1)</TD><TD width="208.75px">US-11 + US-12</TD></TR><TR><TD width="40px">10</TD><TD width="473.25px">Cancel feature (Part 2)</TD><TD width="208.75px">US-13 + US-13b + US-14</TD></TR><TR><TD width="40px">11</TD><TD width="473.25px">Item popup creation & inline editing</TD><TD width="208.75px">US-18 + US-19</TD></TR><TR><TD width="40px">12</TD><TD width="473.25px">Product customizing + availability</TD><TD width="208.75px">US-15 + US-16</TD></TR><TR><TD width="40px">13</TD><TD width="473.25px">Item consistency: prevent duplicates</TD><TD width="208.75px">US-17</TD></TR></TBODY></TABLE><P> </P><P><!-- notionvc: 901e9484-b00c-44be-842e-77412ea38c89 --><STRONG>If this introduction was helpful, a like or follow would be appreciated as it helps others in the community find the series.</STRONG></P><P> </P>2025-12-15T21:13:47.721000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/abap-to-export-internal-table-data-and-send-as-email-attachments-txt-csv/ba-p/14274396ABAP to Export Internal Table Data and Send as Email Attachments (TXT, CSV, XLSX)2025-12-16T06:01:11.458000+01:00mubarakbashasyedhttps://community.sap.com/t5/user/viewprofilepage/user-id/2189365<P><STRONG>Introduction:</STRONG></P><P>Hello Everyone!!</P><P>When working on real projects, I often had to export ALV data manually every time someone needed it for an email. It was time-consuming and repetitive. So I created a small ABAP utility that automatically converts the ALV output into a TXT, CSV, or XLSX file and sends it directly by email. This makes the whole process much faster and easier for both users and developers.</P><P>Manually exporting the report every time is both repetitive and error-prone.<BR />So I created a simple yet powerful ABAP program that <STRONG>automates this entire process</STRONG>.</P><P> With one execution, the program:<BR /> ✔ Fetches Sales Order data from <STRONG>VBAK</STRONG><BR /> ✔ Displays the results in a Factory Method (<SPAN>CL_SALV_TABLE</SPAN>)<BR /> ✔ Converts the data into <STRONG>TXT, CSV, or XLSX</STRONG><BR /> ✔ Attaches the file<BR /> ✔ Emails it automatically using <STRONG>CL_BCS</STRONG></P><H2 id="toc-hId-1765571428"><STRONG>How the Program Works</STRONG></H2><OL><LI><P><STRONG>Data Retrieval</STRONG> – Sales order header data (<CODE>VBAK</CODE>) is read based on the input range.</P></LI><LI><P><STRONG>ALV Display</STRONG> – The results are shown using <CODE>CL_SALV_TABLE</CODE>.</P></LI><LI><P><STRONG>File Preparation</STRONG></P><UL><LI><P>TXT: Fixed-width formatting</P></LI><LI><P>CSV: Comma-separated lines</P></LI><LI><P>XLSX: Using SALV → XML export</P></LI></UL></LI><LI><P><STRONG>Binary Conversion</STRONG> – Converts string or XML to <CODE>SOLIX_TAB</CODE> for email attachment.</P></LI><LI><P><STRONG>Email Construction</STRONG> – Creates a BCS email object with subject, body, and attachment.</P></LI><LI><P><STRONG>Sending</STRONG> – Dispatches the email instantly.</P></LI></OL><P>This approach is modular, clean, and easily extendable to other tables, formats, or business requirements.</P><P><STRONG>PROGRAM FLOW </STRONG></P><pre class="lia-code-sample language-abap"><code>+------------------------------------------------------+
| START OF SELECTION |
+-----------------------------+------------------------+
|
v
+------------------------+
| Fetch Data (VBAK) |
+------------------------+
|
v
+------------------------+
| Display ALV Output |
| (CL_SALV_TABLE) |
+------------------------+
|
v
+------------------------------------------------+
| User selects output format (TXT/CSV/XLSX) |
+------------------------------------------------+
|
v
+-------------------------------------------------------------+
| Generate content: |
| - TXT → String formatting |
| - CSV → CSV concatenation |
| - XLSX → ALV->TO_XML (SALV XML Export) |
+-------------------------------------------------------------+
|
v
+-------------------------------------------------------------+
| Convert content to binary attachment: |
| - SCMS_STRING_TO_XSTRING (if TXT/CSV) |
| - SCMS_XSTRING_TO_BINARY (all formats) |
+-------------------------------------------------------------+
|
v
+-------------------------------------------------------------+
| Build Email (BCS Framework): |
| - CREATE_PERSISTENT |
| - CREATE_DOCUMENT |
| - ADD_ATTACHMENT |
| - SET_DOCUMENT |
| - CREATE_SENDER / CREATE_INTERNET_ADDRESS |
| - ADD_RECIPIENT |
+-------------------------------------------------------------+
|
v
+----------------------------+
| SEND EMAIL |
| (LO_SEND->SEND) |
+----------------------------+
|
v
+----------------------------+
| Email Sent Successfully |
+----------------------------+</code></pre><P><FONT size="4"><STRONG>Function Modules & Classes Used in the Program</STRONG></FONT></P><TABLE width="721px"><TBODY><TR><TD width="232.458px"><FONT size="3"><STRONG>Function Module</STRONG></FONT></TD><TD width="487.875px"><FONT size="3"><STRONG>Purpose / Usage</STRONG></FONT></TD></TR><TR><TD width="232.458px"><FONT size="3"><STRONG>SCMS_STRING_TO_XSTRING</STRONG></FONT></TD><TD width="487.875px"><FONT size="3">Converts plain text (string) into XSTRING format. Used for TXT and CSV attachments.</FONT></TD></TR><TR><TD width="232.458px"><FONT size="3"><STRONG>SCMS_XSTRING_TO_BINARY</STRONG></FONT></TD><TD width="487.875px"><FONT size="3">Converts XSTRING into SOLIX_TAB (binary table). Required for sending attachments (TXT, CSV, XLSX).</FONT></TD></TR></TBODY></TABLE><P> </P><TABLE><TBODY><TR><TD><STRONG>Class / Method</STRONG></TD><TD><STRONG>Purpose / Usage</STRONG></TD></TR><TR><TD width="226.865px" height="30px"><STRONG>CL_SALV_TABLE=>FACTORY</STRONG></TD><TD width="442.917px" height="30px">Creates ALV object instance for display.</TD></TR><TR><TD width="226.865px" height="30px"><STRONG>LO_ALV->DISPLAY</STRONG></TD><TD width="442.917px" height="30px">Displays the ALV grid on the screen.</TD></TR><TR><TD><STRONG>LO_ALV->TO_XML</STRONG></TD><TD>Converts ALV data into XML. Used for generating XLSX output.</TD></TR></TBODY></TABLE><P> </P><TABLE><TBODY><TR><TD><STRONG>Class / Method</STRONG></TD><TD><STRONG>Purpose / Usage</STRONG></TD></TR><TR><TD><STRONG>CL_BCS=>CREATE_PERSISTENT</STRONG></TD><TD>Initializes an email send request.</TD></TR><TR><TD><STRONG>CL_DOCUMENT_BCS=>CREATE_DOCUMENT</STRONG></TD><TD>Creates email body and subject.</TD></TR><TR><TD><STRONG>LO_DOCUMENT->ADD_ATTACHMENT</STRONG></TD><TD>Adds attachment (TXT/CSV/XLSX) to email.</TD></TR><TR><TD><STRONG>LO_SEND_REQUEST->SET_DOCUMENT</STRONG></TD><TD>Attaches the document to the send request.</TD></TR><TR><TD><STRONG>CL_SAPUSER_BCS=>CREATE</STRONG></TD><TD>Defines email sender (current SAP user).</TD></TR><TR><TD><STRONG>CL_CAM_ADDRESS_BCS=>CREATE_INTERNET_ADDRESS</STRONG></TD><TD>Creates external email recipient.</TD></TR><TR><TD><STRONG>LO_SEND_REQUEST->ADD_RECIPIENT</STRONG></TD><TD>Adds a recipient to the email request.</TD></TR><TR><TD><STRONG>LO_SEND_REQUEST->SEND</STRONG></TD><TD>Sends the final email.</TD></TR></TBODY></TABLE><P><STRONG>SOURCE CODE FOR REFERENCE :</STRONG></P><pre class="lia-code-sample language-abap"><code>*&---------------------------------------------------------------------*
*& Report ZEMAIL_ATTACH
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zemail_attach.
TABLES:vbak.
*------------Selection screen parameters-------------------------------*
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln.
PARAMETERS: p_txt RADIOBUTTON GROUP rg1 DEFAULT 'X',
p_csv RADIOBUTTON GROUP rg1,
p_xlsx RADIOBUTTON GROUP rg1.
PARAMETERS: p_email TYPE adr6-smtp_addr.
*-------------Start-of-selection---------------------------------------*
START-OF-SELECTION.
*Fetch sales order header data from VBAK
SELECT vbeln,
erdat,
vbtyp,
auart,
vkorg,
kunnr FROM vbak
INTO TABLE (lt_vbak)
WHERE vbeln IN @s_vbeln.
SORT lt_vbak BY vbeln.
*-------------Display ALV----------------------------------------------*
DATA: lo_alv TYPE REF TO cl_salv_table.
TRY.
cl_salv_table=>factory(
IMPORTING
r_salv_table = lo_alv
CHANGING
t_table = lt_vbak ).
lo_alv->display( ).
CATCH cx_salv_msg INTO DATA(lx_msg).
MESSAGE lx_msg->get_text( ) TYPE 'E'.
ENDTRY.
*-------------TXT Format----------------------------------------------*
IF p_txt ='X'.
DATA(lv_txt) = |{ 'VBELN' WIDTH = 12 }| &&
|{ 'ERDAT' WIDTH = 10 }| &&
|{ 'VBTYP' WIDTH = 6 } | &&
|{ 'AUART' WIDTH = 6 } | &&
|{ 'VKORG' WIDTH = 6 } | &&
|{ 'KUNNR' WIDTH = 12 }| &&
cl_abap_char_utilities=>cr_lf.
LOOP AT lt_vbak ASSIGNING FIELD-SYMBOL(<fs_row>).
lv_txt = lv_txt &&
|{ <fs_row>-vbeln WIDTH = 12 } | &&
|{ <fs_row>-erdat WIDTH = 10 } | &&
|{ <fs_row>-vbtyp WIDTH = 6 } | &&
|{ <fs_row>-auart WIDTH = 6 } | &&
|{ <fs_row>-vkorg WIDTH = 6 } | &&
|{ <fs_row>-kunnr WIDTH = 12 } | &&
cl_abap_char_utilities=>cr_lf.
ENDLOOP.
*-------------CSV Format------------------------------------------------*
ENDIF.
IF p_csv = 'X'.
DATA(lv_csv) = |VBELN,ERDAT,VBTYP,AUART,VKORG,KUNNR| &&
cl_abap_char_utilities=>cr_lf.
LOOP AT lt_vbak ASSIGNING <fs_row>.
lv_csv = lv_csv &&
|{ <fs_row>-vbeln },{ <fs_row>-erdat },{ <fs_row>-vbtyp },| &&
|{ <fs_row>-auart },{ <fs_row>-vkorg },{ <fs_row>-kunnr } | &&
cl_abap_char_utilities=>cr_lf.
ENDLOOP.
ENDIF.
*-------------XLSX Format------------------------------------------------*
IF p_xlsx = 'X'.
DATA(lv_xml) = lo_alv->to_xml( xml_type = if_salv_bs_xml=>c_type_xlsx ).
ENDIF.
*-------------Convert content to binary for attachment-------------------*
DATA: lv_xstring TYPE xstring,
lt_bin TYPE solix_tab,
lv_size TYPE i,
lv_filename TYPE so_obj_des.
IF p_txt = 'X'.
lv_filename = 'report.txt'.
CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
EXPORTING
text = lv_txt
IMPORTING
buffer = lv_xstring.
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING
buffer = lv_xstring
TABLES
binary_tab = lt_bin.
ELSEIF p_csv = 'X'.
lv_filename = 'report.csv'.
CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
EXPORTING text = lv_csv
IMPORTING buffer = lv_xstring.
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING buffer = lv_xstring
TABLES binary_tab = lt_bin.
ELSEIF p_xlsx = 'X'.
lv_filename = 'report.xlsx'.
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING
buffer = lv_xml
IMPORTING
output_length = lv_size
TABLES
binary_tab = lt_bin.
ENDIF.
*--------------- Create and send email------------------------------------*
DATA: lo_send_request TYPE REF TO cl_bcs,
lo_document TYPE REF TO cl_document_bcs,
lo_sender TYPE REF TO cl_sapuser_bcs,
lo_recipient TYPE REF TO if_recipient_bcs,
lv_subject TYPE so_obj_des.
*Create send request
lo_send_request = cl_bcs=>create_persistent( ).
*Subject line
lv_subject = 'Sales Order Report'.
*Create email body text
DATA(lt_body) = VALUE soli_tab( ( line = 'Sales Order Report Attached.' ) ).
* Create document with attachment
lo_document = cl_document_bcs=>create_document(
i_type = 'RAW'
i_text = lt_body
i_subject = lv_subject ).
lo_document->add_attachment(
i_attachment_type = 'BIN'
i_attachment_subject = lv_filename
i_attachment_language = sy-langu
i_att_content_hex = lt_bin ).
*Add document to send request
lo_send_request->set_document( lo_document ).
*Set sender
lo_sender = cl_sapuser_bcs=>create( sy-uname ).
lo_send_request->set_sender( lo_sender ).
*Add recipient
lo_recipient = cl_cam_address_bcs=>create_internet_address( p_email ).
lo_send_request->add_recipient(
i_recipient = lo_recipient
i_express = 'X' ).
* Send email
TRY.
lo_send_request->send( i_with_error_screen = 'X' ).
COMMIT WORK.
MESSAGE 'Email sent successfully' TYPE 'S'.
CATCH cx_bcs INTO DATA(lx_bcs).
MESSAGE lx_bcs->get_text( ) TYPE 'E'.
ENDTRY.</code></pre><P>These images will help you better understand how the program behaves during execution.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_0-1763735918651.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/343700iFAD6650D25A334D8/image-size/medium?v=v2&px=400" role="button" title="mubarakbashasyed_0-1763735918651.png" alt="mubarakbashasyed_0-1763735918651.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_1-1763735999468.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/343702iC9C1CAC37B7BD210/image-size/medium?v=v2&px=400" role="button" title="mubarakbashasyed_1-1763735999468.png" alt="mubarakbashasyed_1-1763735999468.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mubarakbashasyed_2-1763736113928.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/343705i26ECBA9C3F05DD0B/image-size/medium?v=v2&px=400" role="button" title="mubarakbashasyed_2-1763736113928.png" alt="mubarakbashasyed_2-1763736113928.png" /></span></P><P>You can check the mail delivery status in transaction <STRONG>SOST</STRONG>.<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="image.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350179i7D6A079900C4E998/image-size/large?v=v2&px=999" role="button" title="image.png" alt="image.png" /></span></P><H3 id="toc-hId-1698140642"><STRONG>Conclusion:</STRONG></H3><P>Automating ALV export and email delivery may seem like a small enhancement, but it brings significant value to daily business operations. Instead of manually downloading and sending files each time a user requests data, this ABAP utility streamlines the entire workflow—fetching data, generating TXT/CSV/XLSX files, and sending them by email in one seamless execution.</P><P><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Connectivity/pd-p/266264953119842772207986043063520" class="lia-product-mention" data-product="313-1">ABAP Connectivity</a> <BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Extensibility/pd-p/338571334339306322581424656448659" class="lia-product-mention" data-product="315-1">ABAP Extensibility</a> </P>2025-12-16T06:01:11.458000+01:00https://community.sap.com/t5/technology-blog-posts-by-members/building-a-custom-stock-requirements-report-in-sap-abap/ba-p/14287594Building a Custom Stock/Requirements Report in SAP ABAP2025-12-16T06:16:16.031000+01:00reddysekharapathipatihttps://community.sap.com/t5/user/viewprofilepage/user-id/2189357<P><!-- StartFragment --></P><P><STRONG><SPAN class="">Introduction</SPAN></STRONG><STRONG><SPAN class=""><BR /></SPAN></STRONG></P><P><!-- StartFragment --></P><P><SPAN class="">In SAP Materials Management, the Stock or Requirements List MD04 is one of the most frequently used transactions for planners and production teams. It provides a real-time view of current stock, incoming receipts, and outgoing requirements for a material at plant level. However, in real project scenarios, users often need a simplified, customized, or report-based version of MD04 that can be enhanced further or adapted to specific business needs.</SPAN></P><P> </P><P><SPAN class="">During one such requirement, I worked on building a custom ABAP report that replicates the core functionality of MD04 while keeping the logic transparent and flexible. This blog explains how a custom Stock/Requirements Report can be built using standard SAP tables and function modules, without modifying standard SAP transactions.</SPAN></P><P><!-- EndFragment --><STRONG>Solution Review :</STRONG></P><P><STRONG><!-- StartFragment --></STRONG></P><P><SPAN class="">The custom report ZSTCOK_912 is designed to display stock and MRP elements for a given Material and Plant, closely mirroring the MD04 output.</SPAN></P><P><STRONG><SPAN class="">1. Selection Screen</SPAN></STRONG></P><UL><LI><SPAN class="">The report starts with a simple and user friendly selection screen:</SPAN></LI><LI><SPAN class="">Material Number MATNR</SPAN></LI><LI><SPAN class="">Plant WERKS</SPAN></LI><LI><SPAN class="">Both parameters are mandatory to ensure accurate stock evaluation.</SPAN></LI></UL><P><STRONG><SPAN class="">2. Material Number Conversion</SPAN></STRONG></P><P><SPAN class="">Since SAP stores material numbers with leading zeros, the report uses:</SPAN></P><OL><LI><SPAN class="">CONVERSION_EXIT_ALPHA_INPUT</SPAN></LI></OL><P><SPAN class="">This ensures the material number is in the correct internal format before database access.</SPAN></P><P><STRONG><SPAN class="">3. Current Stock Determination</SPAN></STRONG></P><P><SPAN class="">To calculate the opening balance:</SPAN></P><OL><LI><SPAN class="">Table MARD is read</SPAN></LI><LI><SPAN class="">All unrestricted stock LABST across storage locations is summed</SPAN></LI><LI><SPAN class="">This provides the current physical stock, which becomes the starting available quantity.</SPAN></LI></OL><P><STRONG><SPAN class="">4. Fetching Stock or Requirements Data</SPAN></STRONG></P><P><SPAN class="">The core of the solution uses the standard SAP function module:</SPAN></P><P><SPAN class="">MD_STOCK_REQUIREMENTS_LIST_API</SPAN></P><UL><LI><SPAN class="">This is the same API used by MD04 and returns:</SPAN></LI><LI><SPAN class="">MRP elements receipts and requirements </SPAN></LI><LI><SPAN class="">Quantities</SPAN></LI><LI><SPAN class="">Planning and control data</SPAN></LI><LI><SPAN class="">The data is stored in internal tables such as MDPSX, MDEZX, and MDSUX.</SPAN></LI></UL><P><STRONG><SPAN class="">5. Display Logic and Running Stock Calculation</SPAN></STRONG></P><UL><LI><SPAN class="">Each MRP element is processed sequentially:</SPAN></LI><LI><SPAN class="">Receipts increase available stock</SPAN></LI><LI><SPAN class="">Requirements reduce available stock</SPAN></LI><LI><SPAN class="">A running available quantity is calculated and displayed line by line, giving users a projected stock position over time.</SPAN></LI></UL><P><STRONG><SPAN class="">6. Output Format</SPAN></STRONG></P><P><SPAN class="">The report displays:</SPAN></P><UL><LI><SPAN class="">Date</SPAN></LI><LI><SPAN class="">MRP element type Receipt, Requirement, Dependent Requirement, etc.</SPAN></LI><LI><SPAN class="">Document number</SPAN></LI><LI><SPAN class="">Receipt quantity</SPAN></LI><LI><SPAN class="">Projected available stock</SPAN></LI><LI><SPAN class="">Additionally, summary information such as total records processed and current stock is displayed at the end.</SPAN></LI></UL><P><STRONG><!-- EndFragment --></STRONG></P><P><SPAN class=""><!-- StartFragment --></SPAN></P><P><!-- StartFragment --></P><P><STRONG><SPAN class="">The Complete Solution Code<BR /></SPAN></STRONG></P><pre class="lia-code-sample language-abap"><code>*&---------------------------------------------------------------------*
*& Report ZSTCOK_912
*&---------------------------------------------------------------------*
*& Custom Stock/Requirements Report
*& Purpose: Display stock and requirements similar to MD04 transaction
*&---------------------------------------------------------------------*
REPORT ZSTCOK_912.
*&---------------------------------------------------------------------*
*& DATA DECLARATIONS
*&---------------------------------------------------------------------*
" Reference to standard SAP tables for material master data
TABLES: mara, " General Material Data
marc. " Plant Data for Material
*&---------------------------------------------------------------------*
*& SELECTION SCREEN
*&---------------------------------------------------------------------*
" Input parameters for the report - both are mandatory
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
PARAMETERS: p_matnr TYPE matnr OBLIGATORY, " Material Number
p_werks TYPE werks_d OBLIGATORY. " Plant
SELECTION-SCREEN END OF BLOCK b1.
*&---------------------------------------------------------------------*
*& INTERNAL TABLES AND WORK AREAS
*&---------------------------------------------------------------------*
" Internal tables to store data returned by the function module
DATA: gt_mdpsx TYPE TABLE OF mdps, " MRP element data (dates, doc numbers)
gs_mdpsx TYPE mdps, " Work area for MDPSX
gt_mdezx TYPE TABLE OF mdez, " MRP element quantities
gs_mdezx TYPE mdez, " Work area for MDEZX
gt_mdsux TYPE TABLE OF mdsu, " Summary data
gs_mdsux TYPE mdsu. " Work area for MDSUX
" Structures for exporting parameters from function module
DATA: gs_mt61d TYPE mt61d, " Material requirements planning data
gs_mdkp TYPE mdkp, " MRP controller and configuration
gs_cm61m TYPE cm61m, " MRP list control data
gs_mdsta TYPE mdsta, " MRP statistics
gv_ergbz TYPE ergbz. " Result indicator
" Variables for processing and display
DATA: gv_labst TYPE labst, " Unrestricted stock quantity
gv_available TYPE labst, " Available quantity (opening stock)
lv_running_stock TYPE mng01, " Running available stock
lv_matnr TYPE matnr, " Material number with leading zeros
lv_txt TYPE char30, " Text for MRP element description
lv_count TYPE i. " Counter for total records
*&---------------------------------------------------------------------*
*& START-OF-SELECTION
*&---------------------------------------------------------------------*
START-OF-SELECTION.
"*------------------------------------------------------------------*
"* Step 1: Convert Material Number with Leading Zeros
"*------------------------------------------------------------------*
" SAP stores material numbers with leading zeros in database
" This conversion ensures proper format for database queries
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = p_matnr
IMPORTING
output = lv_matnr.
"*------------------------------------------------------------------*
"* Step 2: Get Current Stock from MARD Table
"*------------------------------------------------------------------*
" MARD contains storage location data for materials
" We sum all unrestricted stock (LABST) across storage locations
SELECT SINGLE SUM( labst )
INTO gv_labst
FROM mard
WHERE matnr = lv_matnr
AND werks = p_werks.
" Initialize available quantity based on query result
IF sy-subrc = 0.
gv_available = gv_labst. " Stock found
ELSE.
gv_available = 0. " No stock found
ENDIF.
"*------------------------------------------------------------------*
"* Step 3: Call Function Module to Get Stock Requirements List
"*------------------------------------------------------------------*
" MD_STOCK_REQUIREMENTS_LIST_API is SAP standard FM used by MD04
" It returns all MRP elements (receipts and requirements)
CALL FUNCTION 'MD_STOCK_REQUIREMENTS_LIST_API'
EXPORTING
matnr = lv_matnr " Material number
werks = p_werks " Plant
IMPORTING
e_mt61d = gs_mt61d " Planning data
e_mdkp = gs_mdkp " MRP configuration
e_cm61m = gs_cm61m " Control data
e_mdsta = gs_mdsta " Statistics
e_ergbz = gv_ergbz " Result indicator
TABLES
mdpsx = gt_mdpsx " MRP element master data
mdezx = gt_mdezx " MRP element quantities
mdsux = gt_mdsux " Summary data
EXCEPTIONS
material_plant_not_found = 1 " Material doesn't exist
plant_not_found = 2 " Plant doesn't exist
OTHERS = 3. " Other errors
" Error handling for function module call
IF sy-subrc <> 0.
WRITE: / 'Error getting stock requirements data'.
WRITE: / 'Return Code:', sy-subrc.
EXIT.
ENDIF.
" Check if any data was returned
IF gt_mdpsx IS INITIAL AND gt_mdezx IS INITIAL.
WRITE: / 'No stock requirements data found for Material:', p_matnr,
'Plant:', p_werks.
EXIT.
ENDIF.
"*------------------------------------------------------------------*
"* Step 4: Display Report Header Information
"*------------------------------------------------------------------*
WRITE: / 'Stock/Requirements List as of', sy-datum, sy-uzeit.
WRITE: / sy-uline(155).
WRITE: / 'Material:', p_matnr, ' Plant:', p_werks.
WRITE: / sy-uline(155).
SKIP 1.
" Display MRP configuration details if available
IF gs_mdkp IS NOT INITIAL.
WRITE: / 'MRP Controller:', gs_mdkp-dispo. " Person responsible
WRITE: / 'MRP Type:', gs_mdkp-dismm. " Planning strategy
WRITE: / 'Lot Size:', gs_mdkp-disls. " Lot sizing procedure
SKIP 1.
ENDIF.
"*------------------------------------------------------------------*
"* Step 5: Display Column Headers
"*------------------------------------------------------------------*
" Column positions are carefully aligned for readability
WRITE: / 'Date', " Date of MRP element
15 'MRP Element data', " Type of element (receipt/requirement)
45 'Doc Number', " Document number reference
70 'Receipt Qty', " Quantity of receipt
90 'Available Qty'. " Running available stock
WRITE: / sy-uline(155).
" Initialize running stock with opening balance
lv_running_stock = gv_available.
"*------------------------------------------------------------------*
"* Step 6: Display Opening Stock
"*------------------------------------------------------------------*
" Show current available stock as starting point
WRITE: / sy-datum USING EDIT MASK '__/______', " Today's date formatted
90 gv_available. " Opening stock quantity
WRITE: / sy-uline(155).
"*------------------------------------------------------------------*
"* Step 7: Process and Display MRP Elements
"*------------------------------------------------------------------*
" Loop through all MRP elements (receipts and requirements)
LOOP AT gt_mdpsx INTO gs_mdpsx.
" Get corresponding quantity data for this MRP element
" Match by date (dat00) and planning number (plumi)
READ TABLE gt_mdezx INTO gs_mdezx
WITH KEY dat00 = gs_mdpsx-dat00
plumi = gs_mdpsx-plumi.
IF sy-subrc = 0.
"*----------------------------------------------------------------*
"* Determine MRP Element Type Description
"*----------------------------------------------------------------*
" DELKZ field indicates whether element is receipt or requirement
CASE gs_mdpsx-delkz.
WHEN 'V'.
lv_txt = 'Receipt'. " Incoming material
WHEN 'B'.
lv_txt = 'Requirement'. " Outgoing material demand
WHEN 'L'.
lv_txt = 'Delivery Schedule'. " Scheduled delivery
WHEN 'A'.
lv_txt = 'Dependent Reqmt'. " From BOM explosion
WHEN 'U'.
lv_txt = 'Stock Transfer'. " Between storage locations
WHEN OTHERS.
lv_txt = gs_mdpsx-delkz. " Display code if unknown
ENDCASE.
"*----------------------------------------------------------------*
"* Calculate Running Available Stock
"*----------------------------------------------------------------*
" Receipts (+) increase stock, Requirements (-) decrease stock
IF gs_mdpsx-delkz = 'V'.
" Receipt: Add to available stock
lv_running_stock = lv_running_stock + gs_mdezx-mng03.
ELSE.
" Requirement: Subtract from available stock
lv_running_stock = lv_running_stock - gs_mdezx-mng02.
ENDIF.
"*----------------------------------------------------------------*
"* Display MRP Element Line
"*----------------------------------------------------------------*
" Show each element with aligned columns
WRITE: / gs_mdpsx-dat00 USING EDIT MASK '__/______', " Date formatted
15 lv_txt, " Element type description
45 gs_mdpsx-delnr, " Document number
70 gs_mdezx-mng03, " Receipt quantity
90 lv_running_stock. " Projected available stock
" Increment record counter
lv_count = lv_count + 1.
ENDIF.
ENDLOOP.
"*------------------------------------------------------------------*
"* Step 8: Display Summary Information
"*------------------------------------------------------------------*
WRITE: / sy-uline(155).
SKIP 1.
" Show total number of MRP elements processed
WRITE: / 'Total Records:', lv_count.
" Show current physical stock
WRITE: / 'Current Stock:', gv_labst.
" Display summary data count if available
IF gt_mdsux IS NOT INITIAL.
SKIP 2.
WRITE: / 'Summary Data Available - Total Entries:', lines( gt_mdsux ).
ENDIF.
*&---------------------------------------------------------------------*
*& END OF REPORT
*&---------------------------------------------------------------------*</code></pre><P><!-- StartFragment --></P><P><STRONG><SPAN class="">Output for standard MD04 real stock view:</SPAN></STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="reddysekharapathipati_0-1765352645154.png" style="width: 727px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350599iF2BBED715F2C3DDB/image-dimensions/727x308?v=v2" width="727" height="308" role="button" title="reddysekharapathipati_0-1765352645154.png" alt="reddysekharapathipati_0-1765352645154.png" /></span></P><P><STRONG>Output for custom Report output:</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="reddysekharapathipati_1-1765352723809.png" style="width: 725px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350600i81D0676745289928/image-dimensions/725x243?v=v2" width="725" height="243" role="button" title="reddysekharapathipati_1-1765352723809.png" alt="reddysekharapathipati_1-1765352723809.png" /></span></P><P> </P><P><STRONG><SPAN class="">Conclusion :</SPAN></STRONG></P><P><SPAN class=""><!-- StartFragment --></SPAN></P><P><SPAN class="">This custom ABAP report demonstrates how standard SAP functionality like MD04 can be replicated and customized using clean ABAP logic and standard APIs. By leveraging MD_STOCK_REQUIREMENTS_LIST_API and combining it with stock data from MARD, the report provides a clear and reliable view of stock movements and future requirements.</SPAN></P><P><SPAN class="">From my experience, building such custom reports not only helps meet specific business requirements but also improves understanding of SAP’s internal MRP data flow. This approach offers flexibility for further enhancements such as ALV output, additional filters, or integration with planning dashboards, making it a practical alternative to standard transactions when customization is required.</SPAN><SPAN class=""><!-- EndFragment --><!-- StartFragment --></SPAN></P><P><STRONG><SPAN class="">Thanks for Reading My Blog..</SPAN></STRONG></P><P><SPAN class=""><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Connectivity/pd-p/266264953119842772207986043063520" class="lia-product-mention" data-product="313-1">ABAP Connectivity</a> </SPAN></P><P><SPAN class=""><a href="https://community.sap.com/t5/c-khhcw49343/SAP+BTP+ABAP+environment/pd-p/73555000100800001164" class="lia-product-mention" data-product="11-1">SAP BTP ABAP environment</a> .</SPAN></P><P> </P><P> </P><P><SPAN class=""><!-- EndFragment --><BR /></SPAN></P><P><SPAN class=""><!-- EndFragment --><BR /></SPAN></P><P><SPAN class=""><!-- EndFragment --></SPAN></P><P><STRONG><SPAN class=""><!-- EndFragment --></SPAN></STRONG></P><P><!-- EndFragment --></P><P><STRONG><SPAN class=""> </SPAN></STRONG></P><P><!-- EndFragment --></P><P class=""><SPAN class=""><!-- EndFragment --><BR /><BR /></SPAN></P><P class=""> </P><P><SPAN class=""><!-- EndFragment --><BR /></SPAN></P><P><!-- EndFragment --></P>2025-12-16T06:16:16.031000+01:00https://community.sap.com/t5/abap-blog-posts/a-journey-from-netweaver-7-50-to-s-4hana-part-4-custom-code-conversion/ba-p/14277883A journey from Netweaver 7.50 to S/4HANA - Part 4: Custom Code Conversion Conundrums2025-12-16T14:50:29.981000+01:00BaerbelWinklerhttps://community.sap.com/t5/user/viewprofilepage/user-id/439<P>After the preliminary steps for our custom code conversion described in <A href="https://community.sap.com/t5/application-development-and-automation-blog-posts/a-journey-from-netweaver-7-50-to-s-4hana-part-1-setting-the-stage/ba-p/13965761" target="_blank">part 1</A>, <A href="https://community.sap.com/t5/abap-blog-posts/a-journey-from-netweaver-7-50-to-s-4hana-part-2-what-s-cooking/ba-p/14068398" target="_blank">part 2</A> and <A href="https://community.sap.com/t5/abap-blog-posts/a-journey-from-netweaver-7-50-to-s-4hana-part-3-hitting-some-snags/ba-p/14122127" target="_blank">part 3</A> of this blog series, we finally started the actual coding activity over the summer.</P><P>To begin with, about 120 objects needed to be tackled which had been classified as high priority by the functional and business teams, many of which would most likely be needed for process testing in the first of eventual four sandbox systems. Once done with those, a big list with about 2,500 objects needed to be processed by our development team. For this blog post I picked three issues we encountered and briefly describe how we tackled them.</P><H3 id="toc-hId-1894748291">What to do with customer master creation or updates via XD01 and XD02?</H3><P>We have several programs which create new customers or update existing customers via batch input (or call transaction) logic based on transaction XD01/02 and targeting the "old" tables KNA1, KNB1, KNVV, etc. While the tables still exist in S/4HANA, the transactions are no longer functional because customers now have to be created and maintained as business partners via transaction BP and the business partner tables are in the "lead". The old tables are then filled from the BP, so are still available but only for read access.</P><P>Some of our logic creates customers in bulk based on file uploads and we needed an alternative route for that because many users are relying on that logic. Other programs call XD02 in order to update some fields in the customer master. Searching for alternatives, we happened upon class CL_MD_BP_MAINTAIN and method MAINTAIN, which - based on <A class="" title="Follow link" href="https://me.sap.com/notes/2484299/E" target="_blank" rel="noopener noreferrer">OSS Note 2484299 - BAPI list for BP</A> - is the recommended "tool" in S/4HANA for these kind of tasks (the BAPIs (FMs) listed in the note are intended for an ECC-system).</P><P>At first glance, using this class and method looked straight-forward enough, given that it only requires one import parameter:</P><pre class="lia-code-sample language-abap"><code>cl_md_bp_maintain=>maintain(
EXPORTING
i_data = l_data
IMPORTING
e_return = l_return ).</code></pre><P>The "fun" really started once we realised what this parameter "i_data" really is ... very deeply nested structure CVIS_EI_EXTERN! The "complex" in the description doesn't really do it justice - at the very least, I would have added an "extremely" before "complex"!</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="High level definition of deeply nested structure CVIS_EI_EXTERN" style="width: 716px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/348937iE98BCD22F78A2EED/image-dimensions/716x232/is-moderation-mode/true?v=v2" width="716" height="232" role="button" title="BaerbelWinkler_0-1764935655506.png" alt="High level definition of deeply nested structure CVIS_EI_EXTERN" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">High level definition of deeply nested structure CVIS_EI_EXTERN</span></span></P><P>To get a better handle on what I was looking at, I extended all the structures and all of their sub-structures until reaching the lowest nesting level for each of them. I then downloaded everything into a spreadsheet which ended up having 18(!) nested levels in columns A to R and over 32,000(!!!) rows. Here is a small snippet taken from the spreadsheet:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Green rows are for fields, blue lines indicate a (sub)structure and yellow rows tabletypes." style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/348956i01CC7BBDF69BDA9A/image-size/large/is-moderation-mode/true?v=v2&px=999" role="button" title="BaerbelWinkler_1-1764936645778.png" alt="Green rows are for fields, blue lines indicate a (sub)structure and yellow rows tabletypes." /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Green rows are for fields, blue lines indicate a (sub)structure and yellow rows tabletypes.</span></span></P><P>Based on a code example found in a helpful <A href="https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-members/how-to-create-business-partner-and-assign-multiple-customer-roles-by-using/ba-p/13471108" target="_blank">blog post here in SAP Community</A>, we started to piece together the code needed to fill this gigantic structure in order to create a new customer in our system. By now, we do have some working code but are still working out some details for specific cases where only some fields need to be updated instead a new customer created.</P><H3 id="toc-hId-1698234786">Syntax error while testing logic for Australia but due to a vanished table related to Taiwan</H3><P>As most of you will already know, SAP calls the OSS-notes related to a conversion to S/4HANA "Simplification Items" because SAP simplified the underlying database by eliminating tables and table fields and - to state the obvious - this makes the switch to S/4HANA anything but simple, at least if you have a large custom code base like we do! </P><P>While our development team has been working through the custom code conversion, other teams are already testing processes in sandbox systems. These were created based on productive systems which - even though the code is sourced from the same development system - differ in the data they contain. One is for example a small system for only one company code, while another one is used in Asian-Pacific countries, so is much larger than the first sandbox to be converted and also covers many more test cases. Testing processes related to webshop orders for Australia came to a stop when the logic ran into a syntax error because a table and its structure needed for e-documents in Taiwan was found missing.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Dump due to a syntax error" style="width: 605px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350212iB12F3FE73F303905/image-dimensions/605x427?v=v2" width="605" height="427" role="button" title="JourneyNW-to-S4HANA-Part4-03.jpg" alt="Dump due to a syntax error" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Dump due to a syntax error</span></span></P><P>The table KNA1_TW_EXT contains just a handful of fields but they are legal requirements in Taiwan for invoices. A simplification item exists for the table but it's only the rather generic one mentioning objects no longer available in S/4HANA and it doesn't go into anything specific: <A href="https://me.sap.com/notes/2296016/E" target="_blank" rel="noopener noreferrer">2296016 - SAP S/4HANA custom code adaptation - removal of orphaned objects</A>. So, we were wondering what happens to the data stored in the productive system in ECC during system conversion?</P><P>Digging around a bit more, I found OSS-Note <A href="https://me.sap.com/notes/3166424/E" target="_blank" rel="noopener noreferrer">3166424 - eDocument Taiwan: Migrate Extension Fields for Electronic Documents for Taiwan</A> directly related to table KNA1_TW_EXT. In it, the conversion steps are explained and - guess what? - they involve manually downloading the data from table KNA1_TW_EXT while still on ECC and then - again manually - running SAP-provided program <SPAN>EDOC_TW_CUST_MIGRATE</SPAN> to add the fields' content to their "new" location which is funnily enough table KNA1! Unfortunately, we didn't have the upload program in our system and the OSS-Note wasn't applicable to our version of the S/4HANA-system anyway. </P><P>So, the next step was to create an SAP incident to ask about the note's applicability in our system and to get some confirmation that these manual steps are actually necessary. We got both quickly and could then run through these motions in the sandbox system. And these steps will need to be added to the big check list for needed manual activities when the actual productive system gets converted sometime next year. </P><H3 id="toc-hId-1501721281">The need for and fun with Retrofit</H3><P>Given the long-running nature of our custom code conversion and process testing in sandbox systems, we obviously couldn't impose a freeze on the productive landscape still on Netweaver 750 EHP8 (ECC). We therefore needed a means to keep our new S/4HANA landscape up to date with new developments and applied changes in the corresponding ECC-system. With help from SAP, a Retrofit system based on Solution Manager was established and can now be used to "merge" changes applied in the ECC-system with the code in S/4HANA.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Simplified system landscape" style="width: 697px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350215iBDA85B9E5423971B/image-dimensions/697x299?v=v2" width="697" height="299" role="button" title="JourneyNW-to-S4HANA-Part4-02.jpg" alt="Simplified system landscape" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Simplified system landscape</span></span></P><P>Once transports hit our ECC productive systems, they become relevant for Retrofit in S/4HANA. The transports are automatically checked and the ones without conflicts - new objects, changed objects for which no S/4HANA code conversion has happened and which don't have S/4HANA Readiness findings - are directly imported into the S/4HANA development system. Other transports are held back for manual inspections.</P><P>While the Retrofit framework handles report programs and includes just fine by displaying differences in the two code versions side by side, it has its limitations when it comes to Adobe forms and enhancements. For these objects the side by side comparison doesn't work and it would need to be done manually via version compare which can not just be tedious but also rather error prone. Because of that, we are now asking our colleagues who applied changes in these objects in ECC to re-apply the same changes - adapted to the S/4HANA needs - in the S/4HANA development system. </P><P>Generally and speaking from a Retrofit perspective, any change not applied in the ECC system is a good change. Even with the tools available in Retrofit, the effort increases with frequent changes in ECC to objects already converted to S/4. And with each new change, the complexity and chances for errors increases.</P><HR /><P>This concludes part 4 of our journey from SAP Netweaver to S/4HANA - I'm sure that 2026 will throw some more curve balls our way!</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Cartoon generated with Gemini" style="width: 599px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/350218iCB726C0EBB999422/image-dimensions/599x327/is-moderation-mode/true?v=v2" width="599" height="327" role="button" title="JourneyNW-to-S4HANA-Part4-01.jpg" alt="Cartoon generated with Gemini" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Cartoon generated with Gemini</span></span></P>2025-12-16T14:50:29.981000+01:00