A frequent business requirement involves enabling mass changes to business objects via Excel uploads executed through a custom action popup. Historically, achieving this functionality has necessitated various workarounds, often involving UI5 extensions, third-party solutions, or Object Page manipulations, all of which present specific implementation challenges.
The existing workaround approaches present several drawbacks:
Custom UI Extensions: Require specialized UI5 development expertise.
Third-Party Solutions: Introduce risks related to licensing compliance and potential security vulnerabilities.
Object Page Manipulations: Involve complex, multi-step processes, such as creating a dummy object page, facilitating file upload, temporarily storing the file data in a table field, and requiring a final user action (a button press) to initiate processing. This temporary data storage is often unnecessary, complicating the data model.
However, SAP has recently introduced ABAP / CAP annotations that offer a cloud-ready solution, potentially eliminating approximately 95% of the development effort typically associated with integrating an Excel upload into the backend. This innovation allows developers to prioritize implementing core business logic over developing reusable technical artifacts.
I will now detail the implementation steps.
A business requirement to manage mass processing listings for a library was selected to demonstrate this use case. The implementation requires several steps, with steps 3 through 6 being the special or additional configurations needed, while all others are considered routine.
This feature is currently functional on the BTP ABAP Environment. However, an issue appears to exist with metadata generation on S/4HANA 2023 On-Premise deployments, even though the objects are syntactically correct. It is anticipated that this constraint will be addressed in the S/4HANA 2025 release, making the full feature set available on the S/4HANA On-Premise version following a brief waiting period.
Id, Title, Type, and Author.@EndUserText.label : 'Library Listings'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrk_lib_listings {
key client : abap.clnt not null;
key listing_uuid : sysuuid_x16 not null;
id : abap.numc(10);
title : abap.char(40);
type : abap.char(5);
author : abap.char(40);
publisher_studio : abap.char(40);
isbn_ean : abap.char(40);
language_code : abap.lang;
publication_year : abap.numc(4);
description : abap.char(40);
totalcopies : abap.int2;
available_copies : abap.int2;
location_shelf_id : abap.char(40);
lending_duration_days : abap.int2;
status : abap.char(40);
cover_image_url : abap.char(100);
local_created_by : abp_creation_user;
local_created_at : abp_creation_tstmpl;
local_last_changed_by : abp_locinst_lastchange_user;
local_last_changed_at : abp_locinst_lastchange_tstmpl;
last_changed_at : abp_lastchange_tstmpl;
}2. A RAP Business Object (BO) is generated, followed by the requisite UI artifacts. The specific RAP BO scenario (Managed, Unmanaged, Draft, or Non-Draft) is noted as not influencing the core Excel upload use case. The RAP Generator is used to simplify the demonstration.
3. A root abstract entity is created for the file to be uploaded. (This entity is highly reusable and can be applied across different RAP BOs).
@EndUserText.label: 'Abs. Entity For Attachment'
define root abstract entity ZRK_D_FILE_STREAM
{
@Semantics.largeObject.mimeType: 'MimeType'
@Semantics.largeObject.fileName: 'FileName'
@Semantics.largeObject.contentDispositionPreference: #INLINE
@EndUserText.label: 'Select Excel file'
StreamProperty : abap.rawstring(0);
.hidden: true
MimeType : abap.char(128);
.hidden: true
FileName : abap.char(128);
}4. The abstract behavior definition for the file entity is implemented.
abstract;
strict(2);
with hierarchy;
define behavior for ZRK_D_FILE_STREAM {
}5. A second abstract entity is created to serve as an action parameter. This entity includes an association to the file abstract entity (from Step 3).
@EndUserText.label: 'Action Param for Uploading Excel'
define root abstract entity ZRK_D_UPLOAD_EXCEL
{
// Dummy is a dummy field
@UI.hidden: true
dummy : abap_boolean;
_StreamProperties : association [1] to ZRK_D_FILE_STREAM on 1 = 1;
}6. The abstract behavior definition for the action parameter is implemented, including the association to the earlier entity.
abstract;
strict ( 2 );
with hierarchy;
define behavior for ZRK_D_UPLOAD_EXCEL //alias <alias_name>
{
association _StreamProperties with hierarchy;
}7. An action is defined on the RAP BO Behavior definition, with the parameter specified in Step 5.
static action ExcelUpload deep parameter ZRK_D_UPLOAD_EXCEL ;managed implementation in class ZRK_BP_R_LIB_LISTINGS unique;
strict ( 2 );
with draft;
extensible;
define behavior for ZRK_R_LIB_LISTINGS alias Listings
persistent table ZRK_LIB_LISTINGS
extensible
draft table ZRK_LIB_LSTNGS_D
etag master LocalLastChangedAt
lock master total etag LastChangedAt
authorization master( global )
{
field ( readonly )
ListingUUID,
LocalCreatedBy,
LocalCreatedAt,
LocalLastChangedBy,
LocalLastChangedAt,
LastChangedAt;
field ( numbering : managed )
ListingUUID;
create;
update;
delete;
draft action Activate optimized;
draft action Discard;
draft action Edit;
draft action Resume;
draft determine action Prepare;
static action ExcelUpload deep parameter ZRK_D_UPLOAD_EXCEL ;
mapping for ZRK_LIB_LISTINGS corresponding extensible
{
ListingUUID = listing_uuid;
ID = id;
Title = title;
Type = type;
Author = author;
PublisherStudio = publisher_studio;
IsbnEan = isbn_ean;
LanguageCode = language_code;
PublicationYear = publication_year;
Description = description;
Totalcopies = totalcopies;
AvailableCopies = available_copies;
LocationShelfID = location_shelf_id;
LendingDurationDays = lending_duration_days;
Status = status;
CoverImageUrl = cover_image_url;
LocalCreatedBy = local_created_by;
LocalCreatedAt = local_created_at;
LocalLastChangedBy = local_last_changed_by;
LocalLastChangedAt = local_last_changed_at;
LastChangedAt = last_changed_at;
}
}8. The business logic is implemented to read the Excel content. A released API, XCO_CP_XLSX , is used for this demonstration.
METHOD ExcelUpload.
TYPES : BEGIN OF ty_sheet_data,
id TYPE zrk_r_lib_listings-id,
title TYPE zrk_r_lib_listings-title,
type TYPE zrk_r_lib_listings-Type,
author TYPE zrk_r_lib_listings-author,
PublisherStudio TYPE zrk_r_lib_listings-PublisherStudio,
IsbnEan TYPE zrk_r_lib_listings-IsbnEan,
LanguageCode TYPE zrk_r_lib_listings-LanguageCode,
PublicationYear TYPE zrk_r_lib_listings-PublicationYear,
description TYPE zrk_r_lib_listings-Description,
Totalcopies TYPE zrk_r_lib_listings-Totalcopies,
AvailableCopies TYPE zrk_r_lib_listings-AvailableCopies,
LocationShelfID TYPE zrk_r_lib_listings-LocationShelfID,
LendingDurationDays TYPE zrk_r_lib_listings-LendingDurationDays,
status TYPE zrk_r_lib_listings-Status,
END OF ty_sheet_data.
DATA lv_file_content TYPE xstring.
DATA lt_sheet_data TYPE STANDARD TABLE OF ty_sheet_data.
DATA lt_listing_create TYPE TABLE FOR CREATE zrk_r_lib_listings.
lv_file_content = VALUE #( keys[ 1 ]-%param-_streamproperties-StreamProperty OPTIONAL ).
" Error handling in case file content is initial
DATA(lo_document) = xco_cp_xlsx=>document->for_file_content( lv_file_content )->read_access( ).
DATA(lo_worksheet) = lo_document->get_workbook( )->worksheet->at_position( 1 ).
DATA(o_sel_pattern) = xco_cp_xlsx_selection=>pattern_builder->simple_from_to(
)->from_column( xco_cp_xlsx=>coordinate->for_alphabetic_value( 'A' ) " Start reading from Column A
)->to_column( xco_cp_xlsx=>coordinate->for_alphabetic_value( 'N' ) " End reading at Column N
)->from_row( xco_cp_xlsx=>coordinate->for_numeric_value( 2 ) " *** Start reading from ROW 2 to skip the header ***
)->get_pattern( ).
lo_worksheet->select( o_sel_pattern
)->row_stream(
)->operation->write_to( REF #( lt_sheet_data )
)->set_value_transformation(
xco_cp_xlsx_read_access=>value_transformation->string_value
)->execute( ).
lt_listing_create = CORRESPONDING #( lt_sheet_data ).
MODIFY ENTITIES OF zrk_r_lib_listings IN LOCAL MODE
ENTITY Listings
CREATE AUTO FILL CID FIELDS ( Id Title Type author PublisherStudio IsbnEan LanguageCode PublicationYear description Totalcopies AvailableCopies LocationShelfID LendingDurationDays status )
WITH lt_listing_create
" TODO: variable is assigned but never used (ABAP cleaner)
MAPPED DATA(lt_mapped)
" TODO: variable is assigned but never used (ABAP cleaner)
REPORTED DATA(lt_reported)
" TODO: variable is assigned but never used (ABAP cleaner)
FAILED DATA(lt_failed).
" Communicate the messages to UI - not in scope of this demo
IF lt_failed IS INITIAL.
APPEND VALUE #( %msg = new_message_with_text( severity = if_abap_behv_message=>severity-success
text = 'Listings have been uploaded - please refresh the list!!' ) )
TO reported-listings.
ENDIF.
ENDMETHOD.9. The action is utilized on the projection behavior and subsequently exposed in the metadata extension.
use action ExcelUpload;projection implementation in class ZRK_BP_C_LIB_LISTINGS unique;
strict ( 2 );
extensible;
use draft;
use side effects;
define behavior for ZRK_C_LIB_LISTINGS alias Listings
extensible
use etag
{
use create;
use update;
use delete;
use action Edit;
use action Activate;
use action Discard;
use action Resume;
use action Prepare;
use action ExcelUpload;
}.lineItem: [{ type:#FOR_ACTION , dataAction: 'ExcelUpload' , label: 'Upload Excel' }]10. The service binding is published, and the application is then ready for execution.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 15 | |
| 9 | |
| 7 | |
| 6 | |
| 6 | |
| 6 | |
| 5 | |
| 5 | |
| 4 | |
| 4 |