Hello,
Below is a attempt to show , how to build a RAP based application. If you are coming with core ABAP experience and want to learn how to build your first RAP application , you can follow along the blog.
The best way is to create , your own small version of every step. No need to copy the code in this blog rather create your own objects and follow the steps.
This will give you idea of how to go for RAP based applications including any custom API to call backend.
Below things are covered in this:
- How to fetch data via CDS view
- How to create provider view - alternative to MDE(Meta Data extension)
- How to create Behavior definition class and write validation in it.
- Add a custom button "Bulk Upload"
This is how it will look like at the end:
Let's start..
- 1. As a first step, we will be fetching records from table, So calling it root view(RV).
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Root view for Mapping table'
define root view entity ZR2R_E_073_RV_MAPPING_TAB as
select from zr2r_e_073_t_map as mapping
left outer join makt as mtext on mtext.matnr = mapping.service_material
and mtext.spras = $session.system_language
left outer join but000 as CustomerMaster on CustomerMaster.partner = mapping.third_party_cust
left outer join cskt as TechReceiverCCText on TechReceiverCCText.kostl = mapping.tech_receiver_cc
and TechReceiverCCText.spras = $session.system_language
and TechReceiverCCText.datbi >= $session.system_date
left outer join cskt as SenderCCText on SenderCCText.kostl = mapping.sending_cc
and SenderCCText.spras = $session.system_language
and SenderCCText.datbi >= $session.system_date
left outer join cskt as Techsendccenter on Techsendccenter.kostl = mapping.tech_sender_cc
and Techsendccenter.spras = $session.system_language
and Techsendccenter.datbi >= $session.system_date
left outer join zr2r_e_073_t_pri as pid on pid.lauf_id = mapping.lauf_id
{
key mapping.service_material as ServiceMaterial,
key mapping.sending_cc as SendingCC,
key mapping.lauf_id as LaufID,
key mapping.tech_receiver_cc as TechReceiverCC,
TechReceiverCCText.ktext as TechReceiverCCDesc,
SenderCCText.ktext as SenderCCDesc,
Techsendccenter.ktext as Techsendccdesc,
mtext.maktx as MaterialDescription,
CustomerMaster.name_org1 as CustomerName,
pid.lauf_id_description as lid_desc,
mapping.tech_sender_cc as TechSenderCC,
mapping.third_party_cust as ThirdPartyCust,
mapping.asset_class as AssetClass,
mapping.created_on as CreatedOn,
mapping.created_by as CreatedBy,
mapping.changed_on as ChangedOn,
mapping.changed_by as ChangedBy
}
- As a 2nd step, Let's create provider view, Provider view(PV) is basically a substitute of Meta data extension. We will provide annotations to make sure application look the way we want it to be. It includes any F4 help, sequence of fields etc...
- So you can see here we are giving reference of our Root view here while creating provider view and all annotations are used to display records.
@EndUserText.label: 'Provider Contract view of Mapping table'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.ignorePropagatedAnnotations: true
@UI: {
headerInfo: {
typeName: 'Mapping',
typeNamePlural: 'Mappings',
title: { type: #STANDARD, value: 'ServiceMaterial' }
}
}
define root view entity ZR2R_E_073_PV_CDS_MAPPING_TAB
provider contract transactional_query
as projection on ZR2R_E_073_RV_MAPPING_TAB
{
@UI.facet: [
{
id: 'Mapping',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Mapping',
position: 10
}
]
@UI: {
lineItem: [{ position: 10, label: 'Service Material' }],
identification: [{ position: 10 }],
selectionField: [{ position: 10 }]
}
@Consumption.valueHelpDefinition: [{entity: {name: 'I_Productvh', element: 'Product' }}]
@EndUserText.label: 'Service Material'
key ServiceMaterial,
@UI:{
lineItem: [{ position: 30, label: 'Sending Cost Center' }],
identification: [{ position: 30 }],
selectionField: [{ position: 20 }]
}
@Consumption.valueHelpDefinition: [{entity: {name: 'I_CostCenterVH', element: 'CostCenter' }}]
@EndUserText.label: 'Sending Cost Center'
key SendingCC,
@UI:{
lineItem: [{ position: 50, label: 'Process ID' }],
identification: [{ position: 50 }],
selectionField: [{ position: 30 }]
}
@Consumption.valueHelpDefinition: [{entity: {name: 'ZR2R_E_073_VH_LAUF_ID', element: 'Lauf_ID' }}]
@EndUserText.label: 'Process ID'
key LaufID,
@UI:{
lineItem: [{ position: 110, label: 'Technical Receiving Cost Center' }],
identification: [{ position: 110 }]
}
@Consumption.valueHelpDefinition: [{entity: {name: 'I_CostCenterVH', element: 'CostCenter' }}]
@EndUserText.label: 'Technical Receiving Cost Center'
key TechReceiverCC,
@UI:{
lineItem: [{ position: 20, label: 'Material Description' }],
identification: [{ position: 20, label: 'Material Description' }]
}
MaterialDescription,
@UI:{
lineItem: [{ position: 40, label: 'Sending cost center Desc' }],
identification: [{ position: 40, label: 'Sending cost center Description' }]
}
SenderCCDesc,
@UI:{
lineItem: [{ position: 120, label: 'Technical rec. cost center Description' }],
identification: [{ position: 120, label: 'Tech. rec. cost center Description' }]
}
TechReceiverCCDesc,
@UI:{
lineItem: [{ position: 60, label: 'Process id Desc' }],
identification: [{ position: 60, label: 'Process id description' }]
}
lid_desc,
@UI:{
lineItem: [{ position: 70, label: 'Technical Sending Cost Center' }],
identification: [{ position: 70, label: 'Technical Sending Cost Center' }]
}
@Consumption.valueHelpDefinition: [{entity: {name: 'I_CostCenterVH', element: 'CostCenter' }}]
@EndUserText.label: 'Technical Sending Cost Center'
TechSenderCC,
@UI:{
lineItem: [{ position: 80, label: 'Tech. Sending cost center Description' }],
identification: [{ position: 80, label: 'Tech. Sending cost center Description' }]
}
Techsendccdesc,
@UI:{
lineItem: [{ position: 90, label: 'Customer' }],
identification: [{ position: 90 }]
}
@Consumption.valueHelpDefinition: [{entity: {name: 'I_Customer', element: 'Customer' }}]
@EndUserText.label: 'Customer'
ThirdPartyCust,
@UI:{
lineItem: [{ position: 100, label: 'Customer Name' }],
identification: [{ position: 100, label: 'Customer Name' }]
}
CustomerName,
@UI:{
lineItem: [{ position: 130, label: 'Assset Class' }],
identification: [{ position: 130 }]
}
@Consumption.valueHelpDefinition: [{entity: {name: 'I_AssetClass', element: 'AssetClass' }}]
@EndUserText.label: 'Asset Class'
AssetClass,
@UI.hidden: true
@Semantics.systemDateTime.createdAt: true
CreatedOn as CreatedOn,
@UI.hidden: true
@Semantics.user.createdBy: true
CreatedBy as CreatedBy,
@UI.hidden: true
@Semantics.systemDateTime.lastChangedAt: true
ChangedOn as ChangedOn,
@UI.hidden: true
@Semantics.user.lastChangedBy: true
ChangedBy as ChangedBy
}
- As a 3rd step, right click on your root view and choose "New Behavior definition" as shown below:
- In 4th step, we will write below code for validation, making fields mandatory etc..
managed implementation in class zbp_r2r_e_073_rv_mapping_tab unique;
strict;
define behavior for ZR2R_E_073_RV_MAPPING_TAB //alias <alias_name>
persistent table zr2r_e_073_t_map
lock master
authorization master ( instance )
etag master ChangedOn
{
create;
update;
delete;
field ( mandatory : create ) ServiceMaterial, SendingCC, LaufID;
field ( readonly : update ) ServiceMaterial, SendingCC, LaufID,TechReceiverCC;
field ( readonly ) CreatedBy, CreatedOn, ChangedBy, ChangedOn,TechReceiverCCDesc,SenderCCDesc,
Techsendccdesc,MaterialDescription,CustomerName,lid_desc;
// static action Bulk_up result [1] $self;
determination setAdministrativeData on modify
{ field ServiceMaterial,
SendingCC, TechSenderCC, LaufID, ThirdPartyCust, TechReceiverCC; }
// Validations
validation validateServiceMaterial on save { create; update; }
validation validateSendingCC on save { create; update; }
validation validateTechSenderCC on save { create; update; }
validation validateLaufID on save { create; update; }
validation validateThirdPartyCust on save { create; update; }
validation validateTechReceiverCC on save { create; update; }
validation validassetclass on save { create; update; }
mapping for ZR2R_E_073_T_MAP
{
ServiceMaterial = service_material;
SendingCC = sending_cc;
TechSenderCC = tech_sender_cc;
LaufID = lauf_id;
ThirdPartyCust = third_party_cust;
TechReceiverCC = tech_receiver_cc;
AssetClass = asset_class;
CreatedOn = created_on;
CreatedBy = created_by;
ChangedBy = changed_by;
ChangedOn = changed_on;
}
}
- As a next step, you need to create the class and validation methods in Behavior definition class as shown below:
CLASS lhc_zr2r_e_073_rv_mapping_tab DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR zr2r_e_073_rv_mapping_tab RESULT result.
* METHODS bulk_up FOR MODIFY
* IMPORTING keys FOR ACTION zr2r_e_073_rv_mapping_tab~bulk_up RESULT result.
METHODS validatelaufid FOR VALIDATE ON SAVE
IMPORTING keys FOR zr2r_e_073_rv_mapping_tab~validatelaufid.
METHODS validatesendingcc FOR VALIDATE ON SAVE
IMPORTING keys FOR zr2r_e_073_rv_mapping_tab~validatesendingcc.
METHODS validateservicematerial FOR VALIDATE ON SAVE
IMPORTING keys FOR zr2r_e_073_rv_mapping_tab~validateservicematerial.
METHODS validatetechreceivercc FOR VALIDATE ON SAVE
IMPORTING keys FOR zr2r_e_073_rv_mapping_tab~validatetechreceivercc.
METHODS validatetechsendercc FOR VALIDATE ON SAVE
IMPORTING keys FOR zr2r_e_073_rv_mapping_tab~validatetechsendercc.
METHODS validatethirdpartycust FOR VALIDATE ON SAVE
IMPORTING keys FOR zr2r_e_073_rv_mapping_tab~validatethirdpartycust.
METHODS setadministrativedata FOR DETERMINE ON MODIFY
IMPORTING keys FOR zr2r_e_073_rv_mapping_tab~setadministrativedata.
METHODS validassetclass FOR VALIDATE ON SAVE
IMPORTING keys FOR zr2r_e_073_rv_mapping_tab~validassetclass.
ENDCLASS.
CLASS lhc_zr2r_e_073_rv_mapping_tab IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.
METHOD validatelaufid.
"Variable declaration
DATA: lt_lauf TYPE STANDARD TABLE OF zr2r_e_073_t_pri.
"logic to validate lauf id
READ ENTITIES OF zr2r_e_073_rv_mapping_tab IN LOCAL MODE
ENTITY zr2r_e_073_rv_mapping_tab
FIELDS ( laufid )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_mapping).
lt_lauf = CORRESPONDING #( lt_mapping MAPPING lauf_id = laufid ).
DELETE lt_lauf WHERE lauf_id IS INITIAL.
READ TABLE lt_lauf ASSIGNING FIELD-SYMBOL(<fs_mapping>) INDEX 1.
IF sy-subrc IS INITIAL.
SELECT SINGLE @abap_true
FROM zr2r_e_073_t_pri
WHERE lauf_id = @<fs_mapping>-lauf_id
INTO @DATA(lv_exists).
IF sy-subrc IS NOT INITIAL.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky ) TO failed-zr2r_e_073_rv_mapping_tab.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky
%msg = new_message( id = 'ZR2R_E_073_MESSAGE_C'
number = '018'
severity = if_abap_behv_message=>severity-error
v1 = <fs_mapping>-lauf_id )
%element-laufid = if_abap_behv=>mk-on ) TO reported-zr2r_e_073_rv_mapping_tab.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD validatesendingcc.
DATA: lt_csks TYPE STANDARD TABLE OF csks.
DATA: lv_exists TYPE abap_bool.
READ ENTITIES OF zr2r_e_073_rv_mapping_tab IN LOCAL MODE
ENTITY zr2r_e_073_rv_mapping_tab
FIELDS ( sendingcc )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_mapping).
lt_csks = CORRESPONDING #( lt_mapping MAPPING kostl = sendingcc ).
DELETE lt_csks WHERE kostl IS INITIAL.
READ TABLE lt_csks ASSIGNING FIELD-SYMBOL(<fs_mapping>) INDEX 1.
IF sy-subrc IS INITIAL.
SELECT SINGLE @abap_true
FROM csks
WHERE kostl = @<fs_mapping>-kostl
AND kokrs = 'BMG1'
AND datab <= @sy-datum " Start date is less than or equal to current date
AND datbi >= @sy-datum
INTO @lv_exists.
IF sy-subrc IS NOT INITIAL.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky ) TO failed-zr2r_e_073_rv_mapping_tab.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky
%msg = new_message( id = 'ZR2R_E_073_MESSAGE_C'
number = '002'
severity = if_abap_behv_message=>severity-error
v1 = <fs_mapping>-kostl )
%element-sendingcc = if_abap_behv=>mk-on ) TO reported-zr2r_e_073_rv_mapping_tab.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD validateservicematerial.
READ ENTITIES OF zr2r_e_073_rv_mapping_tab IN LOCAL MODE
ENTITY zr2r_e_073_rv_mapping_tab
FIELDS ( servicematerial )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_mapping).
DATA: lt_mara TYPE STANDARD TABLE OF mara.
DATA: lv_exists TYPE abap_bool.
lt_mara = CORRESPONDING #( lt_mapping MAPPING matnr = servicematerial ).
DELETE lt_mara WHERE matnr IS INITIAL.
READ TABLE lt_mara ASSIGNING FIELD-SYMBOL(<fs_mapping>) INDEX 1.
IF sy-subrc IS INITIAL.
SELECT SINGLE @abap_true
FROM mara
WHERE matnr = @<fs_mapping>-matnr
INTO @lv_exists.
IF sy-subrc IS NOT INITIAL.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky ) TO failed-zr2r_e_073_rv_mapping_tab.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky
%msg = new_message( id = 'ZR2R_E_073_MESSAGE_C'
number = '001'
severity = if_abap_behv_message=>severity-error
v1 = <fs_mapping>-matnr )
%element-servicematerial = if_abap_behv=>mk-on ) TO reported-zr2r_e_073_rv_mapping_tab.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD validatetechreceivercc.
READ ENTITIES OF zr2r_e_073_rv_mapping_tab IN LOCAL MODE
ENTITY zr2r_e_073_rv_mapping_tab
FIELDS ( techreceivercc )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_mapping).
DATA: lt_csks TYPE STANDARD TABLE OF csks.
DATA: lv_exists TYPE abap_bool.
lt_csks = CORRESPONDING #( lt_mapping MAPPING kostl = techreceivercc ).
DELETE lt_csks WHERE kostl IS INITIAL.
READ TABLE lt_csks ASSIGNING FIELD-SYMBOL(<fs_mapping>) INDEX 1.
IF sy-subrc IS INITIAL.
DATA(lv_kostl_no_zeros) = <fs_mapping>-kostl.
" Remove leading zeros
SHIFT lv_kostl_no_zeros LEFT DELETING LEADING '0'.
"validation only if it's less then 10 chars
IF strlen( lv_kostl_no_zeros ) = 10.
SELECT SINGLE @abap_true
FROM csks
WHERE kostl = @<fs_mapping>-kostl
AND kokrs = 'BMG1'
INTO @lv_exists.
IF sy-subrc IS NOT INITIAL.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky ) TO failed-zr2r_e_073_rv_mapping_tab.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky
%msg = new_message( id = 'ZR2R_E_073_MESSAGE_C'
number = '002'
severity = if_abap_behv_message=>severity-error
v1 = <fs_mapping>-kostl )
%element-techreceivercc = if_abap_behv=>mk-on ) TO reported-zr2r_e_073_rv_mapping_tab.
ENDIF.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD validatetechsendercc.
READ ENTITIES OF zr2r_e_073_rv_mapping_tab IN LOCAL MODE
ENTITY zr2r_e_073_rv_mapping_tab
FIELDS ( techsendercc )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_mapping).
DATA: lt_csks TYPE STANDARD TABLE OF csks.
DATA: lv_exists TYPE abap_bool.
lt_csks = CORRESPONDING #( lt_mapping MAPPING kostl = techsendercc ).
DELETE lt_csks WHERE kostl IS INITIAL.
READ TABLE lt_csks ASSIGNING FIELD-SYMBOL(<fs_mapping>) INDEX 1.
IF sy-subrc IS INITIAL.
SELECT SINGLE @abap_true
FROM csks
WHERE kostl = @<fs_mapping>-kostl
AND kokrs = 'BMG1'
AND datab <= @sy-datum " Start date is less than or equal to current date
AND datbi >= @sy-datum
INTO @lv_exists.
IF sy-subrc IS NOT INITIAL.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky ) TO failed-zr2r_e_073_rv_mapping_tab.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky
%msg = new_message( id = 'ZR2R_E_073_MESSAGE_C'
number = '002'
severity = if_abap_behv_message=>severity-error
v1 = <fs_mapping>-kostl )
%element-techsendercc = if_abap_behv=>mk-on ) TO reported-zr2r_e_073_rv_mapping_tab.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD validatethirdpartycust.
READ ENTITIES OF zr2r_e_073_rv_mapping_tab IN LOCAL MODE
ENTITY zr2r_e_073_rv_mapping_tab
FIELDS ( thirdpartycust )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_mapping).
DATA: lt_kna1 TYPE STANDARD TABLE OF kna1.
DATA: lv_exists TYPE abap_bool.
lt_kna1 = CORRESPONDING #( lt_mapping MAPPING kunnr = thirdpartycust ).
DELETE lt_kna1 WHERE kunnr IS INITIAL.
READ TABLE lt_kna1 ASSIGNING FIELD-SYMBOL(<fs_mapping>) INDEX 1.
IF sy-subrc IS INITIAL.
SELECT SINGLE @abap_true
FROM kna1
WHERE kunnr = @<fs_mapping>-kunnr
INTO @lv_exists.
IF sy-subrc IS NOT INITIAL.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky ) TO failed-zr2r_e_073_rv_mapping_tab.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky
%msg = new_message( id = 'ZR2R_E_073_MESSAGE_C'
number = '003'
severity = if_abap_behv_message=>severity-error
v1 = <fs_mapping>-kunnr )
%element-thirdpartycust = if_abap_behv=>mk-on ) TO reported-zr2r_e_073_rv_mapping_tab.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD setadministrativedata.
DATA:
current_user TYPE syuname.
DATA(current_date) = sy-datum.
current_user = cl_abap_context_info=>get_user_technical_name( ).
" Read the entities
READ ENTITIES OF zr2r_e_073_rv_mapping_tab IN LOCAL MODE
ENTITY zr2r_e_073_rv_mapping_tab
FIELDS ( servicematerial sendingcc createdon createdby changedon changedby )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_entities).
" Prepare modifications
DATA: lt_update TYPE TABLE FOR UPDATE zr2r_e_073_rv_mapping_tab.
LOOP AT lt_entities ASSIGNING FIELD-SYMBOL(<entity>).
" Check if this is a new entity (create operation)
IF <entity>-createdon IS INITIAL.
APPEND VALUE #(
%tky = <entity>-%tky
createdon = current_date
createdby = current_user
changedon = current_date
changedby = current_user
) TO lt_update.
ELSE.
" This is an update operation
APPEND VALUE #(
%tky = <entity>-%tky
changedon = current_date
changedby = current_user
) TO lt_update.
ENDIF.
ENDLOOP.
" Modify the entities
IF lt_update IS NOT INITIAL.
MODIFY ENTITIES OF zr2r_e_073_rv_mapping_tab IN LOCAL MODE
ENTITY zr2r_e_073_rv_mapping_tab
UPDATE FIELDS ( createdon createdby changedon changedby )
WITH lt_update.
ENDIF.
ENDMETHOD.
METHOD validassetclass.
TYPES : BEGIN OF ty_asset,
assetclass TYPE anlkl,
laufid TYPE zde_lauf_id,
END OF ty_asset.
DATA : lt_asset TYPE STANDARD TABLE OF ty_asset,
lv_exists TYPE abap_bool.
READ ENTITIES OF zr2r_e_073_rv_mapping_tab IN LOCAL MODE
ENTITY zr2r_e_073_rv_mapping_tab
FIELDS ( AssetClass LaufID )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_asset_class).
lt_asset = CORRESPONDING #( lt_asset_class MAPPING assetclass = AssetClass laufid = LaufID ).
READ TABLE lt_asset ASSIGNING FIELD-SYMBOL(<fs_asset>) INDEX 1.
IF sy-subrc IS INITIAL.
IF <fs_asset>-laufid CA 'Dep' AND <fs_asset>-assetclass IS INITIAL.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky ) TO failed-zr2r_e_073_rv_mapping_tab.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky
%msg = new_message( id = 'ZR2R_E_073_MESSAGE_C'
number = '030'
severity = if_abap_behv_message=>severity-error
v1 = <fs_asset>-laufid )
%element-assetclass = if_abap_behv=>mk-on ) TO reported-zr2r_e_073_rv_mapping_tab.
ENDIF.
IF <fs_asset>-assetclass IS NOT INITIAL.
SELECT SINGLE @abap_true
FROM anla
WHERE anlkl = @<fs_asset>-assetclass
INTO @lv_exists.
IF sy-subrc IS NOT INITIAL.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky ) TO failed-zr2r_e_073_rv_mapping_tab.
APPEND VALUE #( %tky = keys[ sy-tabix ]-%tky
%msg = new_message( id = 'ZR2R_E_073_MESSAGE_C'
number = '031'
severity = if_abap_behv_message=>severity-error
v1 = <fs_asset>-assetclass )
%element-assetclass = if_abap_behv=>mk-on ) TO reported-zr2r_e_073_rv_mapping_tab.
ENDIF.
ENDIF.
ENDIF.
ENDMETHOD.
ENDCLASS.
- As a last step, we will add custom button to bulk upload the data via excel sheet. So in this there are 2 things:
- Front-end changes
- Back-end API creation
Front-end changes will be done by fiori team e.g. addition of button and calling API with GET method.
As a 2nd step , we will be creating API , So we will be creating custom entity as shown below:
//@AbapCatalog.viewEnhancementCategory: [#NONE]
//@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Validation & Post for SO ready table'
@ObjectModel.query.implementedBy: 'ABAP:ZR2R_E_073_CL_VAL_POST'
//@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define custom entity ZR2R_E_073_CE_VALIDATION_POST
{
key zid : abap.string;
zvalue : abap.string;
}
In above , you can see that we have ZID and ZVALUE as parameters where front-end team will be converting all records into BASE64 and sending it in parameter ZVALUE and ZID is indicator that this record is coming via bulk upload, so indicator you can keep anything.
And below annotation is used to mention the class where we will be implementing the code.
@ObjectModel.query.implementedBy: 'ABAP:ZR2R_E_073_CL_VAL_POST'
This class will be called automatically as and when front-end team calls the API with Get method.
Below is the code for class:
CLASS zr2r_e_073_cl_val_post DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_rap_query_provider .
INTERFACES if_rap_query_request .
.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zr2r_e_073_cl_val_post IMPLEMENTATION.
METHOD if_rap_query_request~get_aggregation.
ENDMETHOD.
METHOD if_rap_query_request~get_entity_id.
ENDMETHOD.
METHOD if_rap_query_request~get_filter.
ENDMETHOD.
METHOD if_rap_query_request~get_paging.
ENDMETHOD.
METHOD if_rap_query_request~get_parameters.
ENDMETHOD.
METHOD if_rap_query_request~get_requested_elements.
ENDMETHOD.
METHOD if_rap_query_request~get_search_expression.
ENDMETHOD.
METHOD if_rap_query_request~get_sort_elements.
ENDMETHOD.
METHOD if_rap_query_request~is_data_requested.
ENDMETHOD.
METHOD if_rap_query_request~is_total_numb_of_rec_requested.
ENDMETHOD.
METHOD if_rap_query_provider~select.
DATA : lv_base64 TYPE string,
lt_file TYPE STANDARD TABLE OF ty_file,
lv_process TYPE string,
lv_period TYPE string,
lv_year TYPE string,
lv_zid TYPE string,
lt_resp TYPE STANDARD TABLE OF ty_result,
lt_final TYPE STANDARD TABLE OF ty_result,
ls_final TYPE ty_result,
"Get details from request
TRY.
DATA(dyn_clause) = io_request->get_filter( )->get_as_sql_string( ).
" Split the string into individual conditions
SPLIT dyn_clause AT 'AND' INTO TABLE DATA(lt_conditions).
" Process each condition
LOOP AT lt_conditions INTO DATA(lv_condition).
" Remove leading/trailing spaces
CONDENSE lv_condition.
" Extract values based on field names
IF lv_condition CS 'ZPROCESS ='.
SPLIT lv_condition AT '=' INTO DATA(lv_field) lv_process.
REPLACE ALL OCCURRENCES OF `'` IN lv_process WITH space.
CONDENSE lv_process.
ELSEIF lv_condition CS 'ZPERIOD ='.
SPLIT lv_condition AT '=' INTO lv_field lv_period.
REPLACE ALL OCCURRENCES OF `'` IN lv_period WITH space.
CONDENSE lv_period.
ELSEIF lv_condition CS 'ZYEAR ='.
SPLIT lv_condition AT '=' INTO lv_field lv_year.
REPLACE ALL OCCURRENCES OF `'` IN lv_year WITH space.
CONDENSE lv_year.
ELSEIF lv_condition CS 'ZVALUE ='.
SPLIT lv_condition AT '=' INTO lv_field lv_base64.
REPLACE ALL OCCURRENCES OF `'` IN lv_base64 WITH space.
CONDENSE lv_base64.
ELSEIF lv_condition CS 'ZID ='.
SPLIT lv_condition AT '=' INTO lv_field lv_zid.
REPLACE ALL OCCURRENCES OF `'` IN lv_zid WITH space.
CONDENSE lv_zid.
ENDIF.
ENDLOOP.
"Encoding
DATA(lo_object) = NEW cl_http_utility( ).
DATA(lv_json_data) = lo_object->decode_base64( encoded = lv_base64 ).
/ui2/cl_json=>deserialize(
EXPORTING
json = lv_json_data " JSON string
pretty_name = /ui2/cl_json=>pretty_mode-camel_case " Pretty Print property names
CHANGING
data = lt_file " Data to serialize
).
"Clear variables
CLEAR: lt_resp,lt_sor,
lt_resp, gv_counter,gv_string.
"Validation & Post
CASE lv_zid.
WHEN 'UPL_VAL'. "Validation while uploading of excel sheet
The above code is not complete code but enough to understand the logic.
In above code , you need to implement 2 interfaces mentioned above and you will get Select method which will be called when GET is done from front-end(on button click).
In above you can see , we are getting the data and then looping on the records to fetch the relevant fields from excel and processing it further.
ZVALUE which is in base64 needs to be decoded, So a method to convert from BASE64 is used. Just make sure that technical field names should be same in front-end and back-end while decoding because otherwise your data will not be fetched correctly. So create a type(in this case lt_file ) and give the technical names to front-end which you have kept in backend.
So this way you can try to create your own small application.
Let me know if there's any question and something missing .
Thanks,
Vimal
Top comments (0)