Application Development and Automation Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
Vivek_Sahu_21
Explorer
960

Value Help with Additional Binding in RAP – Filtering Storage Locations by Plant in Material Stock Management 

Introduction:

In this blog, I will demonstrate how to implement Value Help with Additional Binding in a RAP (RESTful ABAP Programming) application for the MM module. The scenario involves managing Material Stock Information by providing value help for Plant (WERKS) and Storage Location (LGORT). The key feature is filtering the storage location list dynamically based on the selected plant, enhancing the user experience. 

When the user selects a Plant, the system automatically filters the Storage Location (LGORT) list to show only the storage locations related to the selected plant. 

The requirement is to build a Fiori-based RAP application that enables users to: 

  • Select a Plant from the dropdown. 
  • Dynamically filter the Storage Locations based on the selected Plant. 
  • Display and manage material stock details such as material number, plant, storage location, stock quantity, and unit of measure. 

 Procedure: 

Key Tables Involved 

1. I have created three custom tables, where Storage and plant table have records: 

  • zvs_dt_storage_l → Storage Locations table with data
@EndUserText.label : 'Table for storage location'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zvs_dt_storage_l {
  key client : abap.clnt not null;
  key lgort  : lgort_d not null;
  key lgobe  : abap.char(16) not null;
  werks      : werks_d;
}

Table Data:

Vivek_Sahu_21_0-1743766832846.png

  • zvs_dt_plant_dt → Plant Data
@EndUserText.label : 'Table for plant data'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zvs_dt_plant_dt {
  key client : abap.clnt not null;
  key werks  : werks_d not null;
  name1      : abap.char(30);
}

Table Data:

Vivek_Sahu_21_1-1743767225404.png

  • zvs_dt_mat_stockMaterial Stock Data 
@EndUserText.label : 'table to store the material stock data.'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zvs_dt_mat_stock {
  key client : abap.clnt not null;
  key matnr  : matnr not null;
  werks      : werks_d;
  lgort      : lgort_d;
  @Semantics.quantity.unitOfMeasure : 'zvs_dt_mat_stock.meins'
  labst      : abap.quan(13,3);
  meins      : meins;
}

 

2.1 Now create one interface view ‘ZVS_I_PLANT_DT’ on top of DB table 'ZVS_DT_PLANT_DT': - 

This view provides the value help for Plant (WERKS). 

I have used the annotation "@ObjectModel.resultSet.sizeCategory: #XS which makes the value help appear as a dropdown. 

@AbapCatalog.sqlViewName: 'ZVS_PLANT_DT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'interface view for plant data'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.resultSet.sizeCategory: #XS
define view zvs_i_plant_dt as select from zvs_dt_plant_dt
{
    key werks as Werks,
    name1 as Name1
}

2.2 Now create interface view ‘ZVS_I_STORAGE_LC’ on top of DB table 'ZVS_DT_STORAGE_L': - 

This view filters Storage Locations by Plant using additional binding. 

  • This view selects Storage Location, Description, and Plant. 
  • The Plant field acts as the filter when the user selects a Plant. 
@AbapCatalog.sqlViewName: 'ZVS_STORAGE_LC'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'interface view for storage location'
@Metadata.ignorePropagatedAnnotations: true
define view zvs_i_storage_lc as select from zvs_dt_storage_l
{
    key lgort as StorageLocation,
    lgobe as StorageLocDesc,
    werks as Plant
}

2.3 Now create interface view ‘ZVS_I_MAT_STOCK’ on top of DB table 'ZVS_DT_MAT_STOCK': - 

An Interface View (zvs_i_mat_stock) for fetching material stock data with associations to plant and storage location details. 

  • This view maps to the custom table zvs_dt_mat_stock. 
  • It includes fields for Material Number, Plant, Storage Location, Stock Quantity, and Unit of Measure 
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'interface view for material stock'
@Metadata.ignorePropagatedAnnotations: true

define root view entity zvs_i_mat_stock as select from zvs_dt_mat_stock
association[0..*] to zvs_i_plant_dt  as _plant on $projection.Werks = _plant.Werks
association[0..*] to zvs_i_storage_lc as _storage on $projection.Lgort = _storage.StorageLocation
{
    key matnr as Matnr,
    werks as Werks,
    lgort as Lgort,
    @Semantics.quantity.unitOfMeasure: 'meins'
    labst as Labst,
    meins as Meins,
    _plant,
    _storage.StorageLocDesc // Expose description from Storage association
}

3. Now create one consumption view ‘ZVS_C_MAT_STOCK’ on top of Interface view 'ZVS_I_MAT_STOCK': - 

The consumption view zvs_c_mat_stock projects the data from the interface view zvs_i_mat_stock. This view is intended to expose the data for transactional operations, such as create, update, and delete. The consumption view allows clients to interact with the data, but the actual persistence and behavior are managed through the behavior definition

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'consumption view for material stock'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@ObjectModel.usageType:{
    serviceQuality: #X,
    sizeCategory: #S,
    dataClass: #MIXED
}
define root view entity zvs_c_mat_stock provider contract transactional_query 
as projection on zvs_i_mat_stock
{
    key Matnr,
    Werks,
    Lgort,
    @Semantics.quantity.unitOfMeasure: 'meins'
    Labst,
    Meins,
    /* Associations */
    _plant,
    StorageLocDesc
}

 4. Define Metadata Extension 

Add Value Help with Additional Binding to your RAP Business Object. 

Vivek_Sahu_21_1-1744106066804.png

Here: 

  • This “@Consumption.valueHelpDefinition: [{ entity : { element: 'Werks' , name: 'zvs_i_plant_dt' } }]” Annotation to get the dropdown for WERKS(Plant) Field. 
  • This “@Consumption.valueHelpDefinition: [{ entity : { element: 'StorageLocation' , name: 'zvs_i_storage_lc' }, additionalBinding: [{ element: 'Plant' ,localElement: 'Werks' }] }]” Annotation here, for additional binding. So based on selected plant it will dynamically filter the storage location.  

The @Consumption.valueHelpDefinition annotation is used to define value help (similar to F4 help in SAP GUI) for a field. It allows you to provide dropdown-style suggestions or search help for users when they enter data into specific fields. 

  • entity: 
    1. Specifies the data source for the value help. 
    2. element: 'StorageLocation': The field in the current CDS view where the value help is applied. 
    3. name: 'zvs_i_storage_lc': The CDS view providing the value help data. 
  • additionalBinding: 
    1. Defines additional filtering criteria. 
    2. element: 'Plant': The field in the value help entity used for filtering. 
    3. localElement: 'Werks': The field in the current view that is used as the filtering key. 
     

Metadata Extension Code for your reference:

@Metadata.layer: #CORE
annotate entity zvs_c_mat_stock with
{
  .facet: [{
     id: 'MaterialStock',
     purpose: #STANDARD,
     type: #IDENTIFICATION_REFERENCE,
     label: 'Material ID',
     position: 10
   }]

  : { lineItem: [{ position: 10, label: 'Material no.' }],
         identification: [{ position: 10, label: 'Material no.' }] }
  Matnr;

  : { lineItem: [{ position: 20, label: 'Plant' }],
     identification: [{ position: 20, label: 'Plant' }] }
  @Consumption.valueHelpDefinition: [{ entity : { element: 'Werks' , name: 'zvs_i_plant_dt' } }]
  Werks;

  : { lineItem: [{ position: 30, label: 'Storage location' }],
       identification: [{ position: 30, label: 'Storage location' }] }
  @Consumption.valueHelpDefinition: [{ entity : { element: 'StorageLocation' , name: 'zvs_i_storage_lc'  }
  ,additionalBinding: [{ element: 'Plant' ,localElement: 'Werks' }]
  }]
  Lgort;

  : { lineItem: [{ position: 40, label: 'Stock quantity' }],
       identification: [{ position: 40, label: 'Stock quantity' }] }
  Labst;

  : { lineItem: [{ position: 60, label: 'Storage location Description' }],
       identification: [{ position: 60, label: 'Storage location Description' }] }
  StorageLocDesc;
}

5. Define Behavior Definition

  • The labst (Stock Quantity) and meins (Unit of Measure) fields are read-only. 
  • The behavior definition supports CRUD operations. 

Now create a behavior definition on top of interface view 'ZVS_I_MAT_STOCK': 

managed implementation in class zbp_vs_i_mat_stock unique;
strict ( 2 );

define behavior for zvs_i_mat_stock //alias <alias_name>
persistent table zvs_dt_mat_stock
lock master
authorization master ( instance )
//etag master <field_name>
early numbering
{
  create;
  update;
  delete;
  field ( readonly ) Matnr, StorageLocDesc;

  mapping for zvs_dt_mat_stock{
    Matnr = matnr;
    Werks = werks;
    Lgort = lgort;
    Labst = labst;
    Meins = meins;
  }
}

Now create a behavior definition on top of consumption view 'ZVS_C_MAT_STOCK': 

projection;
strict ( 2 );

define behavior for zvs_c_mat_stock //alias <alias_name>
{
  use create;
  use update;
  use delete;
}

Go to front-end:

Here I will create one new record: 

Vivek_Sahu_21_0-1744109346370.png

You can see here, all the storage location are coming if we didn’t provide plant: 

Vivek_Sahu_21_1-1744109346370.png

So we'll select plant 1000 from dropdown: 

Vivek_Sahu_21_2-1744109346371.png

You can see here storage location got filtered based on the selected plant: 

Vivek_Sahu_21_3-1744109346372.png

If I select plant 1400, so based on that we are getting 0006 storage location: 

Vivek_Sahu_21_4-1744109346372.png

After saving record you can see the result: 

Vivek_Sahu_21_5-1744109346373.png

Vivek_Sahu_21_6-1744109346373.png

Conclusion:

This blog showed how to create a RAP-based Fiori app with value help that filters storage locations based on the selected plant. Using CDS views, associations, and annotations, the app becomes user-friendly, efficient, and easy to maintain.

 

2 Comments
Krishna_karale
Explorer
0 Kudos

Useful information, Thanks for sharing

 

Khan-Muskan
Explorer
0 Kudos

Thank you for sharing the blog, it was useful.

Labels in this area