Technology Blog Posts by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
34,786

Updates

    • 29.04.2020 - added picture and scenario description, list of applicable releases
    • 30.09.2023 - added clarification that this is a workaround that must be used SAP S/4HANA .
    • 28.11.2023 - changed the how to guide section. Now describe the use of the new service consumption model 2.0.
    • 25.03.2024 - added a second version of the report zaf_r_create_mpc_from_scm20 which is valid for SAP S/4 HANA 2023 systems since the signature of the class /iwbep/cl_cp_registry_config has changed in SAP S/4HANA 2023
    • 25.04.2025 - added additional replacement strings that are required for more complex service consumption models 



Introduction


If you want to consume an OData service in your ABAP coding there is a nice feature available which is called OData Client Proxy that allows to develop ABAP code that consumes a (remote) OData service.

The OData Client itself is already available in SAP S/4HANA 1709 and thus also in later releases of SAP S/4HANA.

The tricky thing in using this useful feature in SAP S/4HANA so far is, that it requires you to build an appopriate OData V4 model provider class that fits to the OData service that you want to consume.

OData Client Proxy User Guide | SAP Help Portal

In SAP BTP, ABAP Environment your life as a developer is easier since here it is possible to generate a Service Consumption Model by importing the EDMX file of an OData V2 service. An OData Proxy Client can easily be instantiated based on such a Service Consumption Model.


If you want to call an Odata Service from within the SAP BTP, ABAP Environment you can check out the following tutorial.

 


Recently my colleague bernhard.grusie published a very detailed blog post about the new Service Consumption Model 2.0.

Service Consumption Model 2 for OData Client Proxy | SAP Blogs

where he mentioned that it is planned to make the Service Consumption Model 2.0 for future on premise releases as well.

Since the service consumption model 2.0 is thus not yet available for SAP S/4HANA on premise systems, I would like to describe in this blog post how you can make use of the new Service Consumption Model 2.0 already in older releases if you have access to an SAP BTP ABAP Environment System.

For the workaround I describe in the following you can also leverage the SAP BTP trial systems.


Workaround for on premise / private cloud SAP S/4HANA systems


As mentioned above, the problem when using the OData Client Proxy is, that it requires an OData V4 model which is conveniently created for you in SAP Cloud Platform, ABAP Environment when you create a Service Consumption Model.


Since creating an OData V4 model manually just from analyzing the $metadata document of the OData V2 service that you want to consume is a tedious and error-prone task I thought whether there are workarounds that can be used.

With the advent of the Service Consumption Model 2.0 a model class is being generated which is very similar to an OData V4 model provider class of the SAP Gateway framework.

With a few manual steps that I will describe in the remaining part of this blog post it is possible to create an OData V4 model provider class from the generated source code of an Service Consumption Model 2.0.

The way how to create an odata client proxy model which I will describe in this blog post is meant as a workaround that can be used by customers that are using an on premise or private cloud version of SAP S/4HANA where the Service Consumption Model 2.0 is not yet availble.

The steps you have to follow are the following:

    1. Create a service consumption model 2.0 in a SAP BTP, ABAP Environment system (e.g. a trial system).

 

    1. Copy the source code of the generated Service Consumption Model 2.0 class into a class with the same name in your on premise SAP S/4HANA System

 

    1. Adapt the code so that it becomes a valid OData V4 model provider class using the report zaf_r_create_mpc_from_scm20

 

    1. Register an OData Proxy CLient



Use case


The use case is the integration of any OData service punlished by other SAP systems that run on premise or in the cloud or other OData services.


In this blog I will describe how to call the OData service GWSAMPLE_BASIC that can reside either in another SAP S/4 HANA system or on the same system.

Applicable releases


The scenario described can be implemented in any recent SAP S/4HANA on premise release and also older SAP S/4HANA releases since the SAP Gateway Framework has been down ported as described in SAP Note 2512479 - SAP Gateway Foundation Support Package Stack Definition

 

How to section

 

Step 1 - Create a service consumption model


You have to create a service consumption model and a model class as described in the blog post of my colleague Bernhard Gruise.

In this case we will create a service consumption model to consume the demo OData service GWSAMPLE_BASIC.

 

Step 2 - Create a class in SAP S/4HANA


Create a class with the same name as the class that has been generated when creating the service consumption model 2.0 in step 1.

Copy the source code from the service consumption model class to the class in SAP S/4HANA.

As shown in the following screen shot  you will notice an error message that the class /iwbep/cl_v4_abs_pm_model_prov is not known.


 

Step 3 - Run the report zaf_r_create_mpc_from_scm20


In order to create a valid OData V4 model provider class out of the generated source code of our service consumption model 2.0 we have to perform several replacements.

Since performing all this replacements is a tedious and errorprone task I have created a report zaf_r_create_mpc_from_scm20 that reads the source code of the inactive class and provides you with the fixed source code.

The source code of this report can be found at the end of this blog post. The list of replacements is stored in the internal table replacement_list.

 

    1. Start report zaf_r_create_mpc_from_scm20 

 

    1. Select inactive class

 

    1. Execute report



The report performs the following actions for you

 

    1. It replaces code snippets so that the service consumption model 2.0 class becomes a valid OData V4 model provider class

 

    1. It activates the modified class

 

    1. It registers the model provider class as an OData Proxy Client



The result of this process can be checked using ADT and using transaction /o/IWBEP/CP_ADMIN.

Report result

 

 

Changed source code

 



Transaction /IWBEP/CP_ADMIN

 



Step 9 Test the OData Proxy Client locally


We can now test the OData Proxy Client locally in our SAP S/4HANA System since the service GWSAMPLE_BASIC is available in such systems.

 

 

CLASS zcl_my_odata_proxy DEFINITION

  PUBLIC

  FINAL

  CREATE PUBLIC .



  PUBLIC SECTION.

    INTERFACES if_oo_adt_classrun.

  PROTECTED SECTION.

  PRIVATE SECTION.

ENDCLASS.







CLASS zcl_my_odata_proxy IMPLEMENTATION.

  METHOD if_oo_adt_classrun~main.

    DATA: lt_salesorder    TYPE zaf_sc_gwsample_basic_20=>tyt_sales_order,

          lo_client_proxy  TYPE REF TO /iwbep/if_cp_client_proxy,

          lo_read_request  TYPE REF TO /iwbep/if_cp_request_read_list,

          lo_read_response TYPE REF TO /iwbep/if_cp_response_read_lst.



    DATA lv_relative_service_root TYPE string.



    lv_relative_service_root = '/sap/opu/odata/IWBEP/GWSAMPLE_BASIC/'.



    TRY.

        "throws an exception if service document cannot be read



        " Using SM59 destination for HTTP client object

*        cl_http_client=>create_by_destination(

*          EXPORTING

*            destination = 'LOCAL_HTTP_AF'

*          IMPORTING

*            client      = DATA(lo_http_client)

*          EXCEPTIONS

*            OTHERS      = 0 ).



        cl_http_client=>create_internal(

         IMPORTING

           client      = DATA(lo_http_client)

         ).

        IF sy-subrc <> 0.

          out->write( 'error create by http destination').

          EXIT.

        ENDIF.



        lo_client_proxy = /iwbep/cl_cp_client_proxy_fact=>create_v2_remote_proxy(

           io_http_client = lo_http_client

           is_proxy_model_key = VALUE #( repository_id = /iwbep/if_cp_registry_types=>gcs_repository_id-default

           proxy_model_id = to_upper( 'zaf_sc_gwsample_basic_20' )

           proxy_model_version = 0001 )

           iv_relative_service_root = lv_relative_service_root ).



        " 'SALESORDER' is the ABAP internal name of the entityset of the V4 model



        lo_read_request = lo_client_proxy->create_resource_for_entity_set( zaf_sc_gwsample_basic_20=>gcs_entity_set-sales_order_set )->create_request_for_read( ).

        lo_read_request->set_top( iv_top = 5 ).



        lo_read_response = lo_read_request->execute( ).



        " Retrieve the business data

        lo_read_response->get_business_data( IMPORTING et_business_data = lt_salesorder ).



        LOOP AT lt_salesorder INTO DATA(ls_salesorder).

          out->write( ls_salesorder ).

        ENDLOOP.



      CATCH /iwbep/cx_cp_remote INTO DATA(lx_cp_remote).

        " Error handling

        out->write( lx_cp_remote->get_longtext(  ) ).

      CATCH /iwbep/cx_gateway INTO DATA(lx_gateway).

        " Error Handling

        out->write( lx_gateway->get_longtext(  ) ).

    ENDTRY.



  ENDMETHOD.



ENDCLASS.

 

 


 

This will show the following result:

 


 

Source code of  zaf_r_create_mpc_from_scm20

Please note that you have the signature of class /iwbep/cl_cp_registry_config has changed from 2022 to 2023. As a result you will have to use one of the following listings depending on the release of your SAP S/4HANA system.

SAP S/4HANA 2023

 

 

*&---------------------------------------------------------------------*
*& Report zaf_r_create_mpc_from_scm20
*&---------------------------------------------------------------------*
*& Valid for SAP S/4HANA 2023
*&---------------------------------------------------------------------*

REPORT zaf_r_create_mpc_from_scm20.

PARAMETERS: cls_name LIKE seoclass-clsname.

DATA result TYPE i.

DATA search_for TYPE string.
DATA replace_by TYPE string.
FIELD-SYMBOLS <source_code_line> TYPE string.


TYPES: BEGIN OF replacement,
         search_for TYPE string,
         replace_by TYPE string,
       END OF replacement.

DATA replacement_list TYPE STANDARD TABLE OF replacement.

CONSTANTS scm20_super_class TYPE string VALUE '/iwbep/cl_v4_abs_pm_model_prov'.



replacement_list = VALUE #(
                       "change inheritance being used and method names
                       ( search_for = |INHERITING FROM /iwbep/cl_v4_abs_pm_model_prov|
                         replace_by = |INHERITING FROM /iwbep/cl_v4_abs_model_prov|   )
                       ( search_for = |METHODS /iwbep/if_v4_mp_basic_pm~define REDEFINITION|
                         replace_by = |METHODS /iwbep/if_v4_mp_basic~define REDEFINITION|   )
                       ( search_for = |METHOD /iwbep/if_v4_mp_basic_pm~define|
                         replace_by = |METHOD /iwbep/if_v4_mp_basic~define|   )
                       ( search_for = |/iwbep/if_v4_pm_|
                         replace_by = |/iwbep/if_v4_med_|   )
                       ( search_for = |/iwbep/if_v4_med_types=>ty_internal_name|
                         replace_by = |/iwbep/if_v4_med_types=>ty_e_med_internal_name|   )
                       ( search_for = |/iwbep/if_v4_med_types=>gcs_nav_multiplicity-|
                         replace_by = |/iwbep/if_v4_med_element=>gcs_med_nav_multiplicity-|   )
                       " removed dot at the end from search and replace string
                       " since generated code now contains a space in front of the dot
                       ( search_for = |lo_primitive_property->set_edm_type_v2( 'DateTime' )|
                         replace_by = |cast /iwbep/if_v4_med_prim_type_cp( lo_primitive_property )->set_v2_edm_type( 'DateTime' )|   )
                       "new 'Time'
                       ( search_for = |lo_primitive_property->set_edm_type_v2( 'Time' )|
                         replace_by = |cast /iwbep/if_v4_med_prim_type_cp( lo_primitive_property )->set_v2_edm_type( 'Time' )|   )
                       "new lo_primitive_type
                       ( search_for = |lo_primitive_type->set_edm_type_v2( 'DateTime' )|
                         replace_by = |cast /iwbep/if_v4_med_prim_type_cp( lo_primitive_type )->set_v2_edm_type( 'DateTime' )|   )
                       ( search_for = |lo_primitive_type->set_edm_type_v2( 'Time' )|
                         replace_by = |cast /iwbep/if_v4_med_prim_type_cp( lo_primitive_type )->set_v2_edm_type( 'Time' )|   )


                       ( search_for = |lo_primitive_property->set_scale_floating( )|
                         replace_by = |"lo_primitive_property->set_scale_floating( )|   )
                       ( search_for = |iv_do_gen_prim_props|
                         replace_by = |iv_gen_prim_props|   )
                       ( search_for = |iv_do_gen_prim_prop_colls|
                         replace_by = |iv_gen_prim_prop_colls|   )
                       ( search_for = |iv_do_add_conv_to_prim_props|
                         replace_by = |iv_add_conv_to_prim_props|   )
                       ( search_for = |lo_parameter->set_is_nullable( )|
                         replace_by = |"lo_parameter->set_is_nullable( )| )
                       ( search_for = |lo_function->/iwbep/if_v4_med_fu_advanced|
                         replace_by = |"lo_function->/iwbep/if_v4_med_fu_advanced|   )
                       ( search_for = |lo_action->/iwbep/if_v4_med_ac_advanced|
                         replace_by = |"lo_action->/iwbep/if_v4_med_ac_advanced|   )

                       ( search_for = |lo_function_import->/iwbep/if_v4_med_func_imp_v2~set_http_method|
                         replace_by = |"lo_function_import->/iwbep/if_v4_med_func_imp_v2~set_http_method| )

*lo_function TYPE REF TO /iwbep/if_v4_pm_function,
*lo_function_import TYPE REF TO /iwbep/if_v4_pm_func_imp,
*lo_parameter TYPE REF TO /iwbep/if_v4_pm_func_param,
*lo_return TYPE REF TO /iwbep/if_v4_pm_func_return.

*                       ( search_for = | |
*                         replace_by = | |   )
                       ).




cls_name = to_upper( cls_name ).

SELECT SINGLE  * FROM i_abapobjectdirectoryentry INTO @DATA(obj_entry)
                           WHERE abapobject = @CLS_name
                           .

DATA(package) = obj_entry-abappackage.

IF package IS INITIAL.
  WRITE : / |Class { cls_name } not found|.
  EXIT.
ENDIF.

DATA : proxy_model_id      TYPE /iwbep/if_cp_registry_types=>ty_proxy_model_id,
       proxy_model_version TYPE /iwbep/if_cp_registry_types=>ty_proxy_model_version.

proxy_model_id = cls_name.
proxy_model_version = 1.

DATA register_cp  TYPE REF TO /iwbep/cl_cp_registry_config.
register_cp = /iwbep/cl_cp_registry_config=>create( ).

TRY.
    IF register_cp->is_proxy_model_registered(
        iv_proxy_model_id      = proxy_model_id
        iv_proxy_model_version = proxy_model_version ).
      WRITE : / |Proxy model { proxy_model_id } version { proxy_model_version } is already registered|.
      EXIT.
    ENDIF.
  CATCH /iwbep/cx_gateway INTO DATA(lx_gateway).
    WRITE : / |Error checking { proxy_model_id } : { lx_gateway->get_text( ) } |.
    EXIT.
ENDTRY.


DATA(ref) = cl_oo_factory=>create_instance( )->create_clif_source( to_upper( cls_name ) ).
ref->get_source( IMPORTING source = DATA(source_code) ).

LOOP AT source_code INTO DATA(source_code_line).
  result = find( val = source_code_line sub  = replacement_list[ 1 ]-search_for case = abap_false ).
  IF result <> -1.
    EXIT.
  ENDIF.
ENDLOOP.

IF result = -1.
  WRITE : / | { cls_name } does not inherit from { scm20_super_class } |.
  EXIT.
ENDIF.

LOOP AT replacement_list INTO DATA(replacement).
  search_for = replacement-search_for.
  replace_by = replacement-replace_by.
  LOOP AT source_code ASSIGNING <source_code_line> .
    result = find( val = <source_code_line> sub  = search_for case = abap_false ).
    IF result <> -1.
      <source_code_line> = replace( val = <source_code_line>
                                    sub = search_for
                                    with = replace_by ).
    ENDIF.
  ENDLOOP.
ENDLOOP.
"output

TRY.
    ref->lock( ).
    ref->set_source( source = source_code ).
    ref->save( ).
    ref->unlock( ).
  CATCH  cx_oo_access_permission  INTO DATA(access_permission_exc).
    WRITE : / |error occured: { access_permission_exc->get_text(  ) }|.
    EXIT.
ENDTRY.

DATA objects TYPE STANDARD TABLE OF dwinactiv .

objects =  VALUE #( ( object = 'CLAS' obj_name = cls_name uname = sy-uname )
                       ).

CALL FUNCTION 'RS_WORKING_OBJECTS_ACTIVATE'
  TABLES
    objects                = objects
  EXCEPTIONS
    excecution_error       = 1
    cancelled              = 2
    insert_into_corr_error = 3
    OTHERS                 = 4.

IF sy-subrc <> 0.
  WRITE : / |error occured when activating class { cls_name }. SY-SUBRC = { sy-subrc } |.
  EXIT.
ENDIF.



TRY.
    register_cp->create_proxy_model(
      EXPORTING
        iv_proxy_model_id      = proxy_model_id
        iv_proxy_model_version = proxy_model_version
        iv_mpc_name            = cls_name
        iv_proxy_model_descr         = |Proxy model { proxy_model_id } |
        iv_package             = package
        iv_suppress_dialog     = abap_false ).

  CATCH /iwbep/cx_gateway INTO lx_gateway.
    WRITE : / |Error registering { proxy_model_id } : { lx_gateway->get_text( ) } |.
    EXIT.
ENDTRY.

WRITE : / |{ cls_name } registered as OData Proxy Client. |.

WRITE : / |run transaction /o/IWBEP/CP_ADMIN to check the result.|.

 

 

SAP S/HANA 2022 and earlier

 

 

 

*&---------------------------------------------------------------------*

*& Report zaf_r_create_mpc_from_scm20

*&---------------------------------------------------------------------*

*& Valid for SAP S/4HANA 2022 and earlier

*&---------------------------------------------------------------------*

REPORT zaf_r_create_mpc_from_scm20.



PARAMETERS: cls_name LIKE seoclass-clsname.



DATA result TYPE i.



DATA search_for TYPE string.

DATA replace_by TYPE string.

FIELD-SYMBOLS <source_code_line> TYPE string.





TYPES: BEGIN OF replacement,

         search_for TYPE string,

         replace_by TYPE string,

       END OF replacement.



DATA replacement_list TYPE STANDARD TABLE OF replacement.



CONSTANTS scm20_super_class TYPE string VALUE '/iwbep/cl_v4_abs_pm_model_prov'.


replacement_list = VALUE #(
                       "change inheritance being used and method names
                       ( search_for = |INHERITING FROM /iwbep/cl_v4_abs_pm_model_prov|
                         replace_by = |INHERITING FROM /iwbep/cl_v4_abs_model_prov|   )
                       ( search_for = |METHODS /iwbep/if_v4_mp_basic_pm~define REDEFINITION|
                         replace_by = |METHODS /iwbep/if_v4_mp_basic~define REDEFINITION|   )
                       ( search_for = |METHOD /iwbep/if_v4_mp_basic_pm~define|
                         replace_by = |METHOD /iwbep/if_v4_mp_basic~define|   )
                       ( search_for = |/iwbep/if_v4_pm_|
                         replace_by = |/iwbep/if_v4_med_|   )
                       ( search_for = |/iwbep/if_v4_med_types=>ty_internal_name|
                         replace_by = |/iwbep/if_v4_med_types=>ty_e_med_internal_name|   )
                       ( search_for = |/iwbep/if_v4_med_types=>gcs_nav_multiplicity-|
                         replace_by = |/iwbep/if_v4_med_element=>gcs_med_nav_multiplicity-|   )
                       " removed dot at the end from search and replace string
                       " since generated code now contains a space in front of the dot
                       ( search_for = |lo_primitive_property->set_edm_type_v2( 'DateTime' )|
                         replace_by = |cast /iwbep/if_v4_med_prim_type_cp( lo_primitive_property )->set_v2_edm_type( 'DateTime' )|   )
                       "new 'Time'
                       ( search_for = |lo_primitive_property->set_edm_type_v2( 'Time' )|
                         replace_by = |cast /iwbep/if_v4_med_prim_type_cp( lo_primitive_property )->set_v2_edm_type( 'Time' )|   )
                       "new lo_primitive_type
                       ( search_for = |lo_primitive_type->set_edm_type_v2( 'DateTime' )|
                         replace_by = |cast /iwbep/if_v4_med_prim_type_cp( lo_primitive_type )->set_v2_edm_type( 'DateTime' )|   )
                       ( search_for = |lo_primitive_type->set_edm_type_v2( 'Time' )|
                         replace_by = |cast /iwbep/if_v4_med_prim_type_cp( lo_primitive_type )->set_v2_edm_type( 'Time' )|   )


                       ( search_for = |lo_primitive_property->set_scale_floating( )|
                         replace_by = |"lo_primitive_property->set_scale_floating( )|   )
                       ( search_for = |iv_do_gen_prim_props|
                         replace_by = |iv_gen_prim_props|   )
                       ( search_for = |iv_do_gen_prim_prop_colls|
                         replace_by = |iv_gen_prim_prop_colls|   )
                       ( search_for = |iv_do_add_conv_to_prim_props|
                         replace_by = |iv_add_conv_to_prim_props|   )
                       ( search_for = |lo_parameter->set_is_nullable( )|
                         replace_by = |"lo_parameter->set_is_nullable( )| )
                       ( search_for = |lo_function->/iwbep/if_v4_med_fu_advanced|
                         replace_by = |"lo_function->/iwbep/if_v4_med_fu_advanced|   )
                       ( search_for = |lo_action->/iwbep/if_v4_med_ac_advanced|
                         replace_by = |"lo_action->/iwbep/if_v4_med_ac_advanced|   )

                       ( search_for = |lo_function_import->/iwbep/if_v4_med_func_imp_v2~set_http_method|
                         replace_by = |"lo_function_import->/iwbep/if_v4_med_func_imp_v2~set_http_method| )

*lo_function TYPE REF TO /iwbep/if_v4_pm_function,
*lo_function_import TYPE REF TO /iwbep/if_v4_pm_func_imp,
*lo_parameter TYPE REF TO /iwbep/if_v4_pm_func_param,
*lo_return TYPE REF TO /iwbep/if_v4_pm_func_return.

*                       ( search_for = | |
*                         replace_by = | |   )
                       ).









cls_name = to_upper( cls_name ).



SELECT SINGLE  * FROM I_ABAPObjectDirectoryEntry INTO (obj_entry)

                           WHERE ABAPObject = _name

                           .



DATA(package) = obj_entry-ABAPPackage.



IF package IS INITIAL.

  WRITE : / |Class { cls_name } not found|.

  EXIT.

ENDIF.



DATA : proxy_model_id      TYPE /iwbep/if_cp_registry_types=>ty_proxy_model_id,

       proxy_model_version TYPE /iwbep/if_cp_registry_types=>ty_proxy_model_version.



proxy_model_id = cls_name.

proxy_model_version = 1.



TRY.

    IF /iwbep/cl_cp_registry_config=>is_proxy_model_registered(

        iv_proxy_model_id      = proxy_model_id

        iv_proxy_model_version = proxy_model_version ).

      WRITE : / |Proxy model { proxy_model_id } version { proxy_model_version } is already registered|.

      EXIT.

    ENDIF.

  CATCH /iwbep/cx_gateway INTO DATA(lx_gateway).

    WRITE : / |Error checking { proxy_model_id } : { lx_gateway->get_text( ) } |.

    EXIT.

ENDTRY.





DATA(ref) = cl_oo_factory=>create_instance( )->create_clif_source( to_upper( cls_name ) ).

ref->get_source( IMPORTING source = DATA(source_code) ).



LOOP AT source_code INTO DATA(source_code_line).

  result = find( val = source_code_line sub  = replacement_list[ 1 ]-search_for case = abap_false ).

  IF result <> -1.

    EXIT.

  ENDIF.

ENDLOOP.



IF result = -1.

  WRITE : / | { cls_name } does not inherit from { scm20_super_class } |.

  EXIT.

ENDIF.



LOOP AT replacement_list INTO DATA(replacement).

  search_for = replacement-search_for.

  replace_by = replacement-replace_by.

  LOOP AT source_code ASSIGNING <source_code_line> .

    result = find( val = <source_code_line> sub  = search_for case = abap_false ).

    IF result <> -1.

      <source_code_line> = replace( val = <source_code_line>

                                    sub = search_for

                                    with = replace_by ).

    ENDIF.

  ENDLOOP.

ENDLOOP.

"output



TRY.

    ref->lock( ).

    ref->set_source( source = source_code ).

    ref->save( ).

    ref->unlock( ).

  CATCH  cx_oo_access_permission  INTO DATA(access_permission_exc).

    WRITE : / |error occured: { access_permission_exc->get_text(  ) }|.

    EXIT.

ENDTRY.



DATA objects TYPE STANDARD TABLE OF dwinactiv .



objects =  VALUE #( ( object = 'CLAS' obj_name = cls_name uname = sy-uname )

                       ).



CALL FUNCTION 'RS_WORKING_OBJECTS_ACTIVATE'

  TABLES

    objects                = objects

  EXCEPTIONS

    excecution_error       = 1

    cancelled              = 2

    insert_into_corr_error = 3

    OTHERS                 = 4.



IF sy-subrc <> 0.

  WRITE : / |error occured when activating class { cls_name }. SY-SUBRC = { sy-subrc } |.

  EXIT.

ENDIF.



TRY.

    /iwbep/cl_cp_registry_config=>create_proxy_model(

      EXPORTING

        iv_proxy_model_id      = proxy_model_id

        iv_proxy_model_version = proxy_model_version

        iv_mpc_name            = cls_name

        iv_proxy_model_descr         = |Proxy model { proxy_model_id } |

        iv_package             = package

        iv_suppress_dialog     = abap_false ).



  CATCH /iwbep/cx_gateway INTO lx_gateway.

    WRITE : / |Error registering { proxy_model_id } : { lx_gateway->get_text( ) } |.

    EXIT.

ENDTRY.



WRITE : / |{ cls_name } registered as OData Proxy Client. |.



WRITE : / |run transaction /o/IWBEP/CP_ADMIN to check the result.|.

 

 


 

30 Comments
former_member184867
Active Contributor
0 Kudos
Nice Feature from Gateway and a nice blog 🙂
AbhijeetK
Active Participant
0 Kudos
Hi Andre,

Nice trick to use existing segw framework and use.

For consuming odata service in abap there is already "Odata Services Consumption and Integration(OSCI).

Is iOSCI different from Service Consumption Model and do we expect in upcoming release on sap on-premises will come with odata V4 in both inbound and outbound.

 

Regards,

Abhijeet Kankani
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
Hi Abhijeet,

I know that OSCI is available but I would not recommend to use it anymore if you can use the OData Client Proxy as an alternative.

The Client Proxy is much more powerful and lets you call an OData service from within your ABAP code.

OSCI just creates another OData service based on a $metadata file. So no use for you if you want to integrate with an Odata service programmatically. In addition OSCI has lots of technical restrictions.

OData V4 is available on premise already, inbound and outbound. But you have to create your services and OData client proxies manually.

Only in an upcoming version the ABAP RESTful programming model will support OData V4.

This is planned for 2021.

Regards,

Andre

 

 
AbhijeetK
Active Participant
0 Kudos
Thanks Andre,

 

Thanks for the update, I only meant using abap restful programming  model for odata v4.

 

As doing code based implementation for odata V4 is tedious and error prone which you already mentioned in your v4 blog, we cant use cds as RDS there for v4.

Regards

Abhijeet kankani

 
former_member192895
Participant
0 Kudos
Hi Andre,

Can we create dynamic entity set using V4?

Do we have any mechanism to read the input parameter before creating an entity set?

Please help me to understand whether it is doable via Odata v2 or V4.

Thanks

Pooja

 
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos
In the following blog post a community member described how to develop a dynamic entity set.

https://blogs.sap.com/2018/02/11/create-dynamic-entity-model-in-sap-gateway/

But you have to be aware that the metadata is cached and you would have to make sure that it would be generated newly with each call which is not a nice thing from a performance perspective.
former_member192895
Participant
0 Kudos
Hi Andre,

Thanks!

I have been through the blog but the way the implementation of dynamic entity has been done is not what I am looking for.

My requirement is to read the parameter value from the URL & based on which a dynamic entity will get created.

 

Thanks

Pooja
adel_adel
Participant
Very Useful Tutorial!!

I get an authentication error when calling the statement :
lo_client_proxy = /iwbep/cl_cp_client_proxy_fact=>create_v2_remote_proxy(
io_http_client = lo_http_client
is_proxy_model_key = VALUE #( repository_id = /iwbep/if_cp_registry_types=>gcs_repository_id-default
proxy_model_id = 'ZSC_EDMX_IMPORT'
proxy_model_version = 0001 )
iv_relative_service_root = lv_relative_service_root ).

 

Is a solution to use a system user on the used destination when creating the http client object?? we do't use single sign on.
" Using SM59 destination for HTTP client object
cl_http_client=>create_by_destination(
EXPORTING
destination = 'LOCAL_HTTP_AF'
IMPORTING
client = DATA(lo_http_client)
EXCEPTIONS
OTHERS = 0 ).

 

Thanks in advance

Kind Regards
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos
Yes, this is an option.

Best regards

Andre
former_member719109
Discoverer
0 Kudos
What are the other options ?
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos
Anything that works in SM59
0 Kudos
Hi, Andre,

I want to try out the OData Client Proxy to test the service,

I have successfully get the result list for the EntitySet and single Entity, but couldn't get the $expand item data.

Could you guide how to achive with url ?$expand=To_Item ?
peter_walcz79
Explorer
Hi Andre,

 

is it already / will it be possible to create dynamic entity sets in ABAP Environment (Steampunk)?

 

Best Regards,

Peter
timo_stuemper87
Explorer
0 Kudos

Any updates regarding the possibility to create dynamic models in ABAP Environment?
It's possible to create OData Proxy via cl_web_odata_client_factory and / or /iwbep/cl_cp_factory_remote. The abstract model provider class iwbep/cl_v4_abs_pm_model_prov is also released, but i couldn't find a way to dynamically create and register a service consumption model or a proxy model.

 

Thanks in advance!

Best Regards,

Timo

Frank1
Participant
0 Kudos
Hi Andre,

 

Thank you for sharing. In the S/4HANA system, If want to fetch data from other S/4HANA or NON-SAP systems, using the OData Client Proxy is an absolutely good approach.

I am not sure if there are some limitations with this approach, such as the return data records having a max limitation, can only retrieve 5000 lines in one call? If has this limitation,  If want to get all the data in one call, how to handle it? Thank you.
Andre_Fischer
Product and Topic Expert
Product and Topic Expert

Hi Frank,

here we have to distinguish between the two cases OData V2 and OData V4.

When consuming an OData V4 service you can use the OData Client V4 remote Proxy and you will be able to retrieve the so called NextLink which contains the OData Query Option $skiptoken.

OData Request: Including a Nextlink | SAP Help Portal

However OData Clients have to treat the URL of the next link as opaque OData Version 4.01. Part 1: Protocol (oasis-open.org). That means they shall not add any OData query options and shall take the link as it has provided by the server.

When using OData V2 there is unfortunately no support to retrieve the nextlink from the OData payload.

Here you would have to work recursively with providing $top and $skip as long there is data in the response.

Kind regards,

Andre

 

Frank1
Participant
0 Kudos
Hi Andre,

Good to know that, thanks a lot for your valuable response.

Best regards,

Frank
pranamr
Explorer
0 Kudos

Hi Andre

We have a requirement to call SAP standard service “Sales Contract (A2X)” service from custom RAP API.

Sales Contract (A2X) is built on ODATA V2

Link to API documentation – Overview | Sales Contract (A2X) | SAP Business Accelerator Hub

We are currently on S/4 HANA 2023 on-premise and we are trying to follow your blog to create Service Consumption model for Sales Contract service (A2X) Which is build on ODATA V2.

But we don’t see ODATA option in the drop down list of Remote Consumption model. Screen shot attached below. Can you help us ?

pranamr_0-1719855075103.png

Note – We do not have SAP BTP ABAP Environment.

Is the Service Consumption model for ODATA services supported in S/4HANA 2023 on-premise? If not, please suggest how to consume SAP standard ODATA services in a custom RAP API

MatthiasH
Explorer
0 Kudos

Hi @Andre_Fischer ,

 Thanks for the tutorial.

Unfortunatelly I´m facing an issue with my first test at calling API_WHSE_PHYSSTOCKPROD (OData V4 https://api.sap.com/api/OP_WHSEPHYSICALSTOCKPRODUCTS_0001/overview). We are running S/4 HANA 2022 onPremise and the API is called in the same system.
In my test class it throws the exception (CATCH /iwbep/cx_gateway) message "Entity list could not be deserialized." With both http_client variants.

Could you help me to solve this?

Place in SAP, where exception is happening 

MatthiasH_0-1723207345296.png

 

My Testcoding

Spoiler

 

    DATA: lt_physical_stock TYPE zcl_sc_api_whse_physstockprod=>tyt_whse_physical_stock_produc,
          lo_client_proxy   TYPE REF TO /iwbep/if_cp_client_proxy,
          lo_read_request   TYPE REF TO /iwbep/if_cp_request_read_list,
          lo_read_response  TYPE REF TO /iwbep/if_cp_response_read_lst.
    DATA lv_relative_service_root TYPE string.


    lv_relative_service_root = '/sap/opu/odata4/sap/api_whse_physstockprod/srvd_a2x/sap/whsephysicalstockproducts/0001/'.

    TRY.
*        cl_http_client=>create_internal(
*          IMPORTING
*            client = DATA(lo_http_client)
*        ).

        cl_http_client=>create_by_destination(
          EXPORTING
            destination = 'FIORI_CLASSICUI_HTTPS'
          IMPORTING
            client      = DATA(lo_http_client)
          EXCEPTIONS
            OTHERS      = 0 ).
        IF sy-subrc <> 0.
          out->write( 'error create by http destination' ).
          EXIT.
        ENDIF.

        lo_client_proxy = /iwbep/cl_cp_client_proxy_fact=>create_v2_remote_proxy(
           io_http_client = lo_http_client
           is_proxy_model_key = VALUE #( repository_id = /iwbep/if_cp_registry_types=>gcs_repository_id-default
           proxy_model_id = to_upper( 'zcl_sc_api_whse_physstockprod' )
           proxy_model_version = 0001 )
           iv_relative_service_root = lv_relative_service_root ).

        lo_read_request = lo_client_proxy->create_resource_for_entity_set( zcl_sc_api_whse_physstockprod=>gcs_entity_set-whse_phys_stock_prod_seria )->create_request_for_read( ).
        lo_read_request->set_top( iv_top = 5 ).

        lo_read_response = lo_read_request->execute( ).

        " Retrieve the business data
        lo_read_response->get_business_data( IMPORTING et_business_data = lt_physical_stock ).

        LOOP AT lt_physical_stock INTO DATA(ls_salesorder).
          out->write( ls_salesorder ).
        ENDLOOP.

      CATCH /iwbep/cx_cp_remote INTO DATA(lx_cp_remote).
        " Error handling
        out->write( lx_cp_remote->get_longtext( ) ).

      CATCH /iwbep/cx_gateway INTO DATA(lx_gateway).
        " Error Handling
        out->write( lx_gateway->get_longtext( ) ).
    ENDTRY.

 

My Service Consumption Class

Spoiler
"! <p class="shorttext synchronized">I2O Service Consumption API_WHSE_PHYSSTOCKPROD</p>
"! This class has been generated based on the metadata with namespace
"! <em>com.sap.gateway.srvd_a2x.api_whse_physstockprod.v0001</em>
CLASS zcl_sc_api_whse_physstockprod DEFINITION
  PUBLIC
  INHERITING FROM /iwbep/cl_v4_abs_model_prov
  CREATE PUBLIC.

  PUBLIC SECTION.

    TYPES:
      "! <p class="shorttext synchronized">Value Control Structure of WHSE_PHYSICAL_STOCK_PRODUC</p>
      BEGIN OF tys_value_controls_1,
        "! EWMGOODS_RECEIPT_DATE_TIME
        ewmgoods_receipt_date_time TYPE /iwbep/v4_value_control,
        "! SHELF_LIFE_EXPIRATION_DATE
        shelf_life_expiration_date TYPE /iwbep/v4_value_control,
        "! SERIAL_NUMBER
        serial_number              TYPE /iwbep/v4_value_control,
      END OF tys_value_controls_1.

    TYPES:
      "! <p class="shorttext synchronized">WhsePhysicalStockProducts_Type</p>
      BEGIN OF tys_whse_physical_stock_produc,
        "! <em>Value Control Structure</em>
        value_controls             TYPE tys_value_controls_1,
        "! <em>Key property</em> ParentHandlingUnitUUID
        parent_handling_unit_uuid  TYPE sysuuid_x16,
        "! <em>Key property</em> StockItemUUID
        stock_item_uuid            TYPE sysuuid_x16,
        "! EWMWarehouse
        ewmwarehouse               TYPE c LENGTH 4,
        "! Product
        product                    TYPE c LENGTH 18,
        "! EWMStockType
        ewmstock_type              TYPE c LENGTH 2,
        "! EWMStockOwner
        ewmstock_owner             TYPE c LENGTH 10,
        "! EntitledToDisposeParty
        entitled_to_dispose_party  TYPE c LENGTH 10,
        "! EWMStockUsage
        ewmstock_usage             TYPE c LENGTH 1,
        "! Batch
        batch                      TYPE c LENGTH 10,
        "! StockDocumentCategory
        stock_document_category    TYPE c LENGTH 3,
        "! StockDocumentNumber
        stock_document_number      TYPE c LENGTH 35,
        "! ExternalStockDocumentNumber
        external_stock_document_nu TYPE c LENGTH 35,
        "! StockItemNumber
        stock_item_number          TYPE c LENGTH 10,
        "! EWMWorkInProcess
        ewmwork_in_process         TYPE c LENGTH 128,
        "! EWMStockReferenceDocCategory
        ewmstock_reference_doc_cat TYPE c LENGTH 3,
        "! EWMStockReferenceDocument
        ewmstock_reference_documen TYPE c LENGTH 35,
        "! EWMStockReferenceDocumentItem
        ewmstock_reference_docum_2 TYPE c LENGTH 10,
        "! StockIdentificationNumber
        stock_identification_numbe TYPE c LENGTH 20,
        "! WhseQualityInspectionType
        whse_quality_inspection_ty TYPE c LENGTH 1,
        "! QualityInspectionDocument
        quality_inspection_documen TYPE c LENGTH 35,
        "! EWMHghstLvlHandlingUnitNumber
        ewmhghst_lvl_handling_unit TYPE c LENGTH 20,
        "! HandlingUnitNumber
        handling_unit_number       TYPE c LENGTH 20,
        "! EWMStorageBin
        ewmstorage_bin             TYPE c LENGTH 18,
        "! EWMStockQuantityInBaseUnit
        ewmstock_quantity_in_base  TYPE p LENGTH 16 DECIMALS 14,
        "! EWMStockQuantityBaseUnit
        ewmstock_quantity_base_uni TYPE c LENGTH 3,
        "! EWMStockQtyBaseUnitISOCode
        ewmstock_qty_base_unit_iso TYPE c LENGTH 3,
        "! EWMStockQtyBaseUnitSAPCode
        ewmstock_qty_base_unit_sap TYPE c LENGTH 3,
        "! EWMStockQuantityAltvUnit
        ewmstock_quantity_altv_uni TYPE c LENGTH 3,
        "! EWMStockQtyAltvUnitISOCode
        ewmstock_qty_altv_unit_iso TYPE c LENGTH 3,
        "! EWMStockQtyAltvUnitSAPCode
        ewmstock_qty_altv_unit_sap TYPE c LENGTH 3,
        "! EWMLoadingOrNetWeight
        ewmloading_or_net_weight   TYPE p LENGTH 8 DECIMALS 3,
        "! EWMLoadingOrNetWeightUnit
        ewmloading_or_net_weight_u TYPE c LENGTH 3,
        "! EWMLoadgOrNetWgtUntISOCode
        ewmloadg_or_net_wgt_unt_is TYPE c LENGTH 3,
        "! EWMLoadgOrNetWgtUntSAPCode
        ewmloadg_or_net_wgt_unt_sa TYPE c LENGTH 3,
        "! EWMLoadingOrNetVolume
        ewmloading_or_net_volume   TYPE p LENGTH 8 DECIMALS 3,
        "! EWMLoadingOrNetVolumeUnit
        ewmloading_or_net_volume_u TYPE c LENGTH 3,
        "! EWMLoadgOrNetVolUntISOCode
        ewmloadg_or_net_vol_unt_is TYPE c LENGTH 3,
        "! EWMLoadgOrNetVolUntSAPCode
        ewmloadg_or_net_vol_unt_sa TYPE c LENGTH 3,
        "! EWMStorageBinCapConsumptionVal
        ewmstorage_bin_cap_consump TYPE p LENGTH 8 DECIMALS 3,
        "! EWMGoodsReceiptDateTime
        ewmgoods_receipt_date_time TYPE timestamp,
        "! WarehouseTimeZone
        warehouse_time_zone        TYPE c LENGTH 6,
        "! ShelfLifeExpirationDate
        shelf_life_expiration_date TYPE datn,
        "! CountryOfOrigin
        country_of_origin          TYPE c LENGTH 3,
        "! EWMBatchIsInRestrictedUseStock
        ewmbatch_is_in_restricted  TYPE abap_bool,
        "! InspectionPartialLot
        inspection_partial_lot     TYPE c LENGTH 6,
        "! EWMValuationQuantity
        ewmvaluation_quantity      TYPE p LENGTH 16 DECIMALS 14,
        "! EWMValuationQuantityUnit
        ewmvaluation_quantity_unit TYPE c LENGTH 3,
        "! EWMValuationQtyUnitISOCode
        ewmvaluation_qty_unit_isoc TYPE c LENGTH 3,
        "! EWMValuationQtyUnitSAPCode
        ewmvaluation_qty_unit_sapc TYPE c LENGTH 3,
        "! EWMValuationQuantityStatus
        ewmvaluation_quantity_stat TYPE c LENGTH 1,
        "! EWMStockIsBlockedForInventory
        ewmstock_is_blocked_for_in TYPE abap_bool,
        "! EWMConsolidationGroup
        ewmconsolidation_group     TYPE c LENGTH 10,
        "! SerialNumberRequiredLevel
        serial_number_required_lev TYPE c LENGTH 1,
        "! EWMStorBinIsBlockedForPutaway
        ewmstor_bin_is_blocked_for TYPE abap_bool,
        "! EWMStorBinIsBlockedForRemoval
        ewmstor_bin_is_blocked_f_2 TYPE abap_bool,
        "! EWMStorBinIsBlockedDueToPInv
        ewmstor_bin_is_blocked_due TYPE abap_bool,
        "! EWMStorageType
        ewmstorage_type            TYPE c LENGTH 4,
        "! EWMStorageSection
        ewmstorage_section         TYPE c LENGTH 4,
        "! EWMPhysStkMigrtnStsCode
        ewmphys_stk_migrtn_sts_cod TYPE c LENGTH 1,
        "! odata.etag
        etag                       TYPE string,
      END OF tys_whse_physical_stock_produc,
      "! <p class="shorttext synchronized">List of WhsePhysicalStockProducts_Type</p>
      tyt_whse_physical_stock_produc TYPE STANDARD TABLE OF tys_whse_physical_stock_produc WITH DEFAULT KEY.

    TYPES:
      "! <p class="shorttext synchronized">WhsePhysStockProdSerialNmbr_Type</p>
      BEGIN OF tys_whse_phys_stock_prod_ser_2,
        "! <em>Key property</em> ParentHandlingUnitUUID
        parent_handling_unit_uuid TYPE sysuuid_x16,
        "! <em>Key property</em> StockItemUUID
        stock_item_uuid           TYPE sysuuid_x16,
        "! <em>Key property</em> EWMSerialNumber
        ewmserial_number          TYPE c LENGTH 30,
        "! EWMWarehouse
        ewmwarehouse              TYPE c LENGTH 4,
        "! odata.etag
        etag                      TYPE string,
      END OF tys_whse_phys_stock_prod_ser_2,
      "! <p class="shorttext synchronized">List of WhsePhysStockProdSerialNmbr_Type</p>
      tyt_whse_phys_stock_prod_ser_2 TYPE STANDARD TABLE OF tys_whse_phys_stock_prod_ser_2 WITH DEFAULT KEY.


    CONSTANTS:
      "! <p class="shorttext synchronized">Internal Names of the entity sets</p>
      BEGIN OF gcs_entity_set,
        "! WarehousePhysicalStockProducts
        "! <br/> Collection of type 'WhsePhysicalStockProducts_Type'
        warehouse_physical_stock_p TYPE /iwbep/if_cp_runtime_types=>ty_entity_set_name VALUE 'WAREHOUSE_PHYSICAL_STOCK_P',
        "! WhsePhysStockProdSerialNumber
        "! <br/> Collection of type 'WhsePhysStockProdSerialNmbr_Type'
        whse_phys_stock_prod_seria TYPE /iwbep/if_cp_runtime_types=>ty_entity_set_name VALUE 'WHSE_PHYS_STOCK_PROD_SERIA',
      END OF gcs_entity_set .

    CONSTANTS:
      "! <p class="shorttext synchronized">Internal names for complex types</p>
      BEGIN OF gcs_complex_type,
         "! Dummy field - Structure must not be empty
         dummy TYPE int1 VALUE 0,
      END OF gcs_complex_type.

    CONSTANTS:
      "! <p class="shorttext synchronized">Internal names for entity types</p>
      BEGIN OF gcs_entity_type,
        "! <p class="shorttext synchronized">Internal names for WhsePhysicalStockProducts_Type</p>
        "! See also structure type {@link ..tys_whse_physical_stock_produc}
        BEGIN OF whse_physical_stock_produc,
          "! <p class="shorttext synchronized">Navigation properties</p>
          BEGIN OF navigation,
            "! _SerialNumber
            serial_number TYPE /iwbep/if_v4_med_types=>ty_e_med_internal_name VALUE 'SERIAL_NUMBER',
          END OF navigation,
        END OF whse_physical_stock_produc,
        "! <p class="shorttext synchronized">Internal names for WhsePhysStockProdSerialNmbr_Type</p>
        "! See also structure type {@link ..tys_whse_phys_stock_prod_ser_2}
        BEGIN OF whse_phys_stock_prod_ser_2,
          "! <p class="shorttext synchronized">Navigation properties</p>
          BEGIN OF navigation,
            "! _PhysStock
            phys_stock TYPE /iwbep/if_v4_med_types=>ty_e_med_internal_name VALUE 'PHYS_STOCK',
          END OF navigation,
        END OF whse_phys_stock_prod_ser_2,
      END OF gcs_entity_type.


    METHODS /iwbep/if_v4_mp_basic~define REDEFINITION.


  PRIVATE SECTION.

    "! <p class="shorttext synchronized">Model</p>
    DATA mo_model TYPE REF TO /iwbep/if_v4_med_model.


    "! <p class="shorttext synchronized">Define WhsePhysicalStockProducts_Type</p>
    "! @raising /iwbep/cx_gateway | <p class="shorttext synchronized">Gateway Exception</p>
    METHODS def_whse_physical_stock_produc RAISING /iwbep/cx_gateway.

    "! <p class="shorttext synchronized">Define WhsePhysStockProdSerialNmbr_Type</p>
    "! @raising /iwbep/cx_gateway | <p class="shorttext synchronized">Gateway Exception</p>
    METHODS def_whse_phys_stock_prod_ser_2 RAISING /iwbep/cx_gateway.

ENDCLASS.



CLASS ZCL_SC_API_WHSE_PHYSSTOCKPROD IMPLEMENTATION.


  METHOD /iwbep/if_v4_mp_basic~define.

    mo_model = io_model.
    mo_model->set_schema_namespace( 'com.sap.gateway.srvd_a2x.api_whse_physstockprod.v0001' ) ##NO_TEXT.

    def_whse_physical_stock_produc( ).
    def_whse_phys_stock_prod_ser_2( ).

  ENDMETHOD.


  METHOD def_whse_physical_stock_produc.

    DATA:
      lo_complex_property    TYPE REF TO /iwbep/if_v4_med_cplx_prop,
      lo_entity_type         TYPE REF TO /iwbep/if_v4_med_entity_type,
      lo_entity_set          TYPE REF TO /iwbep/if_v4_med_entity_set,
      lo_navigation_property TYPE REF TO /iwbep/if_v4_med_nav_prop,
      lo_primitive_property  TYPE REF TO /iwbep/if_v4_med_prim_prop.


    lo_entity_type = mo_model->create_entity_type_by_struct(
                                    iv_entity_type_name       = 'WHSE_PHYSICAL_STOCK_PRODUC'
                                    is_structure              = VALUE tys_whse_physical_stock_produc( )
                                    iv_gen_prim_props         = abap_true
                                    iv_gen_prim_prop_colls    = abap_true
                                    iv_add_conv_to_prim_props = abap_true ).

    lo_entity_type->set_edm_name( 'WhsePhysicalStockProducts_Type' ) ##NO_TEXT.
    lo_entity_type->create_complex_prop_for_vcs( 'VALUE_CONTROLS' ).


    lo_entity_set = lo_entity_type->create_entity_set( 'WAREHOUSE_PHYSICAL_STOCK_P' ).
    lo_entity_set->set_edm_name( 'WarehousePhysicalStockProducts' ) ##NO_TEXT.


    lo_primitive_property = lo_entity_type->get_primitive_property( 'PARENT_HANDLING_UNIT_UUID' ).
    lo_primitive_property->set_edm_name( 'ParentHandlingUnitUUID' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Guid' ) ##NO_TEXT.
    lo_primitive_property->set_is_key( ).

    lo_primitive_property = lo_entity_type->get_primitive_property( 'STOCK_ITEM_UUID' ).
    lo_primitive_property->set_edm_name( 'StockItemUUID' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Guid' ) ##NO_TEXT.
    lo_primitive_property->set_is_key( ).

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMWAREHOUSE' ).
    lo_primitive_property->set_edm_name( 'EWMWarehouse' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 4 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'PRODUCT' ).
    lo_primitive_property->set_edm_name( 'Product' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 18 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_TYPE' ).
    lo_primitive_property->set_edm_name( 'EWMStockType' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 2 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_OWNER' ).
    lo_primitive_property->set_edm_name( 'EWMStockOwner' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 10 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'ENTITLED_TO_DISPOSE_PARTY' ).
    lo_primitive_property->set_edm_name( 'EntitledToDisposeParty' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 10 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_USAGE' ).
    lo_primitive_property->set_edm_name( 'EWMStockUsage' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 1 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'BATCH' ).
    lo_primitive_property->set_edm_name( 'Batch' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 10 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'STOCK_DOCUMENT_CATEGORY' ).
    lo_primitive_property->set_edm_name( 'StockDocumentCategory' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'STOCK_DOCUMENT_NUMBER' ).
    lo_primitive_property->set_edm_name( 'StockDocumentNumber' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 35 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EXTERNAL_STOCK_DOCUMENT_NU' ).
    lo_primitive_property->set_edm_name( 'ExternalStockDocumentNumber' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 35 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'STOCK_ITEM_NUMBER' ).
    lo_primitive_property->set_edm_name( 'StockItemNumber' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 10 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMWORK_IN_PROCESS' ).
    lo_primitive_property->set_edm_name( 'EWMWorkInProcess' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 128 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_REFERENCE_DOC_CAT' ).
    lo_primitive_property->set_edm_name( 'EWMStockReferenceDocCategory' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_REFERENCE_DOCUMEN' ).
    lo_primitive_property->set_edm_name( 'EWMStockReferenceDocument' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 35 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_REFERENCE_DOCUM_2' ).
    lo_primitive_property->set_edm_name( 'EWMStockReferenceDocumentItem' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 10 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'STOCK_IDENTIFICATION_NUMBE' ).
    lo_primitive_property->set_edm_name( 'StockIdentificationNumber' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 20 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'WHSE_QUALITY_INSPECTION_TY' ).
    lo_primitive_property->set_edm_name( 'WhseQualityInspectionType' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 1 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'QUALITY_INSPECTION_DOCUMEN' ).
    lo_primitive_property->set_edm_name( 'QualityInspectionDocument' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 35 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMHGHST_LVL_HANDLING_UNIT' ).
    lo_primitive_property->set_edm_name( 'EWMHghstLvlHandlingUnitNumber' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 20 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'HANDLING_UNIT_NUMBER' ).
    lo_primitive_property->set_edm_name( 'HandlingUnitNumber' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 20 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTORAGE_BIN' ).
    lo_primitive_property->set_edm_name( 'EWMStorageBin' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 18 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_QUANTITY_IN_BASE' ).
    lo_primitive_property->set_edm_name( 'EWMStockQuantityInBaseUnit' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Decimal' ) ##NO_TEXT.
    lo_primitive_property->set_precision( 31 ) ##NUMBER_OK.
    lo_primitive_property->set_scale( 14 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_QUANTITY_BASE_UNI' ).
    lo_primitive_property->set_edm_name( 'EWMStockQuantityBaseUnit' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_QTY_BASE_UNIT_ISO' ).
    lo_primitive_property->set_edm_name( 'EWMStockQtyBaseUnitISOCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_QTY_BASE_UNIT_SAP' ).
    lo_primitive_property->set_edm_name( 'EWMStockQtyBaseUnitSAPCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_QUANTITY_ALTV_UNI' ).
    lo_primitive_property->set_edm_name( 'EWMStockQuantityAltvUnit' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_QTY_ALTV_UNIT_ISO' ).
    lo_primitive_property->set_edm_name( 'EWMStockQtyAltvUnitISOCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_QTY_ALTV_UNIT_SAP' ).
    lo_primitive_property->set_edm_name( 'EWMStockQtyAltvUnitSAPCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMLOADING_OR_NET_WEIGHT' ).
    lo_primitive_property->set_edm_name( 'EWMLoadingOrNetWeight' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Decimal' ) ##NO_TEXT.
    lo_primitive_property->set_precision( 15 ) ##NUMBER_OK.
    lo_primitive_property->set_scale( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMLOADING_OR_NET_WEIGHT_U' ).
    lo_primitive_property->set_edm_name( 'EWMLoadingOrNetWeightUnit' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMLOADG_OR_NET_WGT_UNT_IS' ).
    lo_primitive_property->set_edm_name( 'EWMLoadgOrNetWgtUntISOCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMLOADG_OR_NET_WGT_UNT_SA' ).
    lo_primitive_property->set_edm_name( 'EWMLoadgOrNetWgtUntSAPCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMLOADING_OR_NET_VOLUME' ).
    lo_primitive_property->set_edm_name( 'EWMLoadingOrNetVolume' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Decimal' ) ##NO_TEXT.
    lo_primitive_property->set_precision( 15 ) ##NUMBER_OK.
    lo_primitive_property->set_scale( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMLOADING_OR_NET_VOLUME_U' ).
    lo_primitive_property->set_edm_name( 'EWMLoadingOrNetVolumeUnit' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMLOADG_OR_NET_VOL_UNT_IS' ).
    lo_primitive_property->set_edm_name( 'EWMLoadgOrNetVolUntISOCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMLOADG_OR_NET_VOL_UNT_SA' ).
    lo_primitive_property->set_edm_name( 'EWMLoadgOrNetVolUntSAPCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTORAGE_BIN_CAP_CONSUMP' ).
    lo_primitive_property->set_edm_name( 'EWMStorageBinCapConsumptionVal' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Decimal' ) ##NO_TEXT.
    lo_primitive_property->set_precision( 15 ) ##NUMBER_OK.
    lo_primitive_property->set_scale( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMGOODS_RECEIPT_DATE_TIME' ).
    lo_primitive_property->set_edm_name( 'EWMGoodsReceiptDateTime' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'DateTimeOffset' ) ##NO_TEXT.
    lo_primitive_property->set_is_nullable( ).
    lo_primitive_property->create_vcs_value_control( ).

    lo_primitive_property = lo_entity_type->get_primitive_property( 'WAREHOUSE_TIME_ZONE' ).
    lo_primitive_property->set_edm_name( 'WarehouseTimeZone' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 6 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'SHELF_LIFE_EXPIRATION_DATE' ).
    lo_primitive_property->set_edm_name( 'ShelfLifeExpirationDate' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Date' ) ##NO_TEXT.
    lo_primitive_property->set_is_nullable( ).
    lo_primitive_property->create_vcs_value_control( ).

    lo_primitive_property = lo_entity_type->get_primitive_property( 'COUNTRY_OF_ORIGIN' ).
    lo_primitive_property->set_edm_name( 'CountryOfOrigin' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMBATCH_IS_IN_RESTRICTED' ).
    lo_primitive_property->set_edm_name( 'EWMBatchIsInRestrictedUseStock' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Boolean' ) ##NO_TEXT.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'INSPECTION_PARTIAL_LOT' ).
    lo_primitive_property->set_edm_name( 'InspectionPartialLot' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 6 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMVALUATION_QUANTITY' ).
    lo_primitive_property->set_edm_name( 'EWMValuationQuantity' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Decimal' ) ##NO_TEXT.
    lo_primitive_property->set_precision( 31 ) ##NUMBER_OK.
    lo_primitive_property->set_scale( 14 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMVALUATION_QUANTITY_UNIT' ).
    lo_primitive_property->set_edm_name( 'EWMValuationQuantityUnit' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMVALUATION_QTY_UNIT_ISOC' ).
    lo_primitive_property->set_edm_name( 'EWMValuationQtyUnitISOCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMVALUATION_QTY_UNIT_SAPC' ).
    lo_primitive_property->set_edm_name( 'EWMValuationQtyUnitSAPCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 3 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMVALUATION_QUANTITY_STAT' ).
    lo_primitive_property->set_edm_name( 'EWMValuationQuantityStatus' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 1 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOCK_IS_BLOCKED_FOR_IN' ).
    lo_primitive_property->set_edm_name( 'EWMStockIsBlockedForInventory' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Boolean' ) ##NO_TEXT.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMCONSOLIDATION_GROUP' ).
    lo_primitive_property->set_edm_name( 'EWMConsolidationGroup' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 10 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'SERIAL_NUMBER_REQUIRED_LEV' ).
    lo_primitive_property->set_edm_name( 'SerialNumberRequiredLevel' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 1 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOR_BIN_IS_BLOCKED_FOR' ).
    lo_primitive_property->set_edm_name( 'EWMStorBinIsBlockedForPutaway' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Boolean' ) ##NO_TEXT.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOR_BIN_IS_BLOCKED_F_2' ).
    lo_primitive_property->set_edm_name( 'EWMStorBinIsBlockedForRemoval' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Boolean' ) ##NO_TEXT.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTOR_BIN_IS_BLOCKED_DUE' ).
    lo_primitive_property->set_edm_name( 'EWMStorBinIsBlockedDueToPInv' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Boolean' ) ##NO_TEXT.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTORAGE_TYPE' ).
    lo_primitive_property->set_edm_name( 'EWMStorageType' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 4 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSTORAGE_SECTION' ).
    lo_primitive_property->set_edm_name( 'EWMStorageSection' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 4 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMPHYS_STK_MIGRTN_STS_COD' ).
    lo_primitive_property->set_edm_name( 'EWMPhysStkMigrtnStsCode' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 1 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'ETAG' ).
    lo_primitive_property->set_edm_name( 'ETAG' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->use_as_etag( ).
    lo_primitive_property->set_is_technical( ).

    lo_navigation_property = lo_entity_type->create_navigation_property( 'SERIAL_NUMBER' ).
    lo_navigation_property->set_edm_name( '_SerialNumber' ) ##NO_TEXT.
    lo_navigation_property->set_target_entity_type_name( 'WHSE_PHYS_STOCK_PROD_SER_2' ).
    lo_navigation_property->set_target_multiplicity( /iwbep/if_v4_med_element=>gcs_med_nav_multiplicity-to_many_optional ).
    lo_navigation_property->create_vcs_value_control( ).

  ENDMETHOD.


  METHOD def_whse_phys_stock_prod_ser_2.

    DATA:
      lo_complex_property    TYPE REF TO /iwbep/if_v4_med_cplx_prop,
      lo_entity_type         TYPE REF TO /iwbep/if_v4_med_entity_type,
      lo_entity_set          TYPE REF TO /iwbep/if_v4_med_entity_set,
      lo_navigation_property TYPE REF TO /iwbep/if_v4_med_nav_prop,
      lo_primitive_property  TYPE REF TO /iwbep/if_v4_med_prim_prop.


    lo_entity_type = mo_model->create_entity_type_by_struct(
                                    iv_entity_type_name       = 'WHSE_PHYS_STOCK_PROD_SER_2'
                                    is_structure              = VALUE tys_whse_phys_stock_prod_ser_2( )
                                    iv_gen_prim_props         = abap_true
                                    iv_gen_prim_prop_colls    = abap_true
                                    iv_add_conv_to_prim_props = abap_true ).

    lo_entity_type->set_edm_name( 'WhsePhysStockProdSerialNmbr_Type' ) ##NO_TEXT.


    lo_entity_set = lo_entity_type->create_entity_set( 'WHSE_PHYS_STOCK_PROD_SERIA' ).
    lo_entity_set->set_edm_name( 'WhsePhysStockProdSerialNumber' ) ##NO_TEXT.


    lo_primitive_property = lo_entity_type->get_primitive_property( 'PARENT_HANDLING_UNIT_UUID' ).
    lo_primitive_property->set_edm_name( 'ParentHandlingUnitUUID' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Guid' ) ##NO_TEXT.
    lo_primitive_property->set_is_key( ).

    lo_primitive_property = lo_entity_type->get_primitive_property( 'STOCK_ITEM_UUID' ).
    lo_primitive_property->set_edm_name( 'StockItemUUID' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'Guid' ) ##NO_TEXT.
    lo_primitive_property->set_is_key( ).

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMSERIAL_NUMBER' ).
    lo_primitive_property->set_edm_name( 'EWMSerialNumber' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 30 ) ##NUMBER_OK.
    lo_primitive_property->set_is_key( ).

    lo_primitive_property = lo_entity_type->get_primitive_property( 'EWMWAREHOUSE' ).
    lo_primitive_property->set_edm_name( 'EWMWarehouse' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->set_max_length( 4 ) ##NUMBER_OK.

    lo_primitive_property = lo_entity_type->get_primitive_property( 'ETAG' ).
    lo_primitive_property->set_edm_name( 'ETAG' ) ##NO_TEXT.
    lo_primitive_property->set_edm_type( 'String' ) ##NO_TEXT.
    lo_primitive_property->use_as_etag( ).
    lo_primitive_property->set_is_technical( ).

    lo_navigation_property = lo_entity_type->create_navigation_property( 'PHYS_STOCK' ).
    lo_navigation_property->set_edm_name( '_PhysStock' ) ##NO_TEXT.
    lo_navigation_property->set_target_entity_type_name( 'WHSE_PHYSICAL_STOCK_PRODUC' ).
    lo_navigation_property->set_target_multiplicity( /iwbep/if_v4_med_element=>gcs_med_nav_multiplicity-to_one ).

  ENDMETHOD.
ENDCLASS.

Kind regards, Matthias

 

 

 

Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos

@pranamr This blog post is exactly for your problem that there is currently not OData option to create a service consumption model in SAP S/4HANA .

You can get a user for the shared trial of Steampunk.

There you can generate the Service Consumption Class

Andre_Fischer
Product and Topic Expert
Product and Topic Expert

@MatthiasH 
I assume that the error stems from the fact that you are trying to consume an OData V4 service using the remote OData V2 proxy client.

The  service URL of the service that you consume 

lv_relative_service_root = '/sap/opu/odata4/sap/api_whse_physstockprod/srvd_a2x/sap/whsephysicalstockproducts/0001/'.

contains the information that this is an OData V4 service.

/sap/opu/odata4/sap/

 

 

NKN
Explorer
0 Kudos

Hi Andre, 

 

thanks a lot for this great Blog. I generated a Proxy in our DEV System which worked great, however now I am wondering how I can transport it to QA. By default the proxy seems to be in service group /IWBEP/ALL however this is only for DEV and QA as per documentation: Service Registration (sap.com). Do i need to create a new service group for the service and if so how do I register the proxy as a service in that group? Or is there another way to go about this?

 

Best Regards,

Niklas

Marçal_Oliveras
Active Contributor
0 Kudos

@Andre_Fischer, I don't understand why the latest version of S/4 still doesn't have the OData option generating the "Remote Consumption Mode" for the service...

This workaround using the BTP ABAP Environment to generate is nice but it feels like a too much risk. It creates a dependency on the BTP service compromising future changes/maintenance.

Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Marcal,

unfortunately it is not possible to perform a downport of this functionality.   

I agree that it is a little bit cumbersome. But it is not a risk. The code that you have created once can be maintained manually. So changing it only requires ADT. And the BTP ABAP Environment will be there in the future as well or you have the option to upgrade your on prem or private cloud systems to a release of SAP S/4HANA 2025 or later later this year.

Kind regards,

Andre

 

rammel_sapdev
Participant
0 Kudos

Hi @Andre_Fischer,

I noticed that not all oData v2 services are supported when creating the service consumption model. I tried creating it in BTP ABAP trial for Sales order and it gave me this error.

rammel_sapdev_0-1733946930714.png

I am using the EDMX file from this link: https://api.sap.com/api/OP_API_SALES_ORDER_SRV_0001/overview

However, when I tried to create the model for Business Partner and Pricing Condition records, I didn't encounter this issue.

link for business partner: https://api.sap.com/api/OP_API_BUSINESS_PARTNER_SRV/overview

link for pricing condition: https://api.sap.com/api/OP_API_SLSPRCGCONDITIONRECORD_SRV_0001/overview

Could you have a look and it from your end? Thanks!

 

rammel_sapdev
Participant
0 Kudos

Hi @Andre_Fischer,

Thank you for creating the utility program! I noticed the custom program for converting the model provider class to be v4 compatible still have some missing replace components like below:

( search_for = |lo_primitive_property->set_edm_type_v2( 'Time' ).|
replace_by = |cast /iwbep/if_v4_med_prim_type_cp( lo_primitive_property )->set_v2_edm_type( 'Time' ).| )

Just wondering, in case in the future we encounter some errors due to some incompatible EDM types, do you know which documentation should we refer to so that we can manually adapt the code from the MPC class?

And also, the generated code from BTP has some extra texts like the ##NO_TEXT. Because of this, the custom utlitiy program is not able to find and replace the corresponding code section. Just a note for future developers who want to use it.

rammel_sapdev_0-1734015106241.png

Other than that, so far I managed to make it work for some of the odata v2 services.

rammel_sapdev
Participant
0 Kudos

Hi Andre,

Is it also possible to call this odata service from a RAP BO (e.g., custom action or in the SAVE_MODIFIED method for unmanaged save?)

I tried consuming the service using the same exact code I had in my console app and I got some errors which I did not get when I was testing it via the console in ADT.

rammel_sapdev_0-1734038358991.png

My code:

  METHOD read.
    DATA: lt_bp            TYPE STANDARD TABLE OF zscm_businesspartner=>tys_a_address_email_address_ty,
          lo_client_proxy  TYPE REF TO /iwbep/if_cp_client_proxy,
          lo_read_request  TYPE REF TO /iwbep/if_cp_request_read_list,
          lo_read_response TYPE REF TO /iwbep/if_cp_response_read_lst.
    DATA lv_relative_service_root TYPE string.

    TRY.


        cl_http_client=>create_internal(
          IMPORTING
            client = DATA(lo_http_client)
        ).
        IF sy-subrc <> 0.
          out->write( 'error create by http destination' ).
          EXIT.
        ENDIF.
        lv_relative_service_root = '/sap/opu/odata/sap/API_BUSINESS_PARTNER/'.
        "oData v4 remote proxy
        lo_client_proxy = /iwbep/cl_cp_client_proxy_fact=>create_v2_remote_proxy(
           io_http_client = lo_http_client
           is_proxy_model_key = VALUE #( repository_id       = /iwbep/if_cp_registry_types=>gcs_repository_id-default
                                         proxy_model_id      = to_upper( 'ZSCM_BUSINESSPARTNER' )
                                         proxy_model_version = 0001 )
           iv_relative_service_root = lv_relative_service_root ).

        lo_read_request = lo_client_proxy->create_resource_for_entity_set( 'A_ADDRESS_EMAIL_ADDRESS' )->create_request_for_read( ).
        lo_read_request->set_top( iv_top = 10 ).
        lo_read_response = lo_read_request->execute( ).

        "Retrieve the business data
        lo_read_response->get_business_data( IMPORTING et_business_data = lt_bp ).

        LOOP AT lt_bp INTO DATA(ls_bp).
          out->write( ls_bp ).
        ENDLOOP.
      CATCH /iwbep/cx_cp_remote INTO DATA(lx_cp_remote).
        " Error handling
        out->write( lx_cp_remote->get_longtext( ) ).
      CATCH /iwbep/cx_gateway INTO DATA(lx_gateway).
        " Error Handling
        out->write( lx_gateway->get_longtext( ) ).
    ENDTRY.
  ENDMETHOD.

Do we need to code it differently or do we need to set something before we can consume it from a custom RAP BO?

rammel_sapdev
Participant
0 Kudos

As a workaround, I managed to call the odata v2 service using a local proxy instead.

However, for odata v4, I am still getting the same error as before.

rammel_sapdev_0-1734120962133.pngrammel_sapdev_1-1734120974496.png

 

Frank1
Participant
0 Kudos

Great blog. Thank you for sharing.

AustinKloske
Explorer
0 Kudos

I followed this approach to generate the Outbound Delivery (A2X) consumption model in a BTP ABAP system and load the class into the newest available on-premise system - S/4 HANA 2023 FSP02 SAP Cal. I attempted using both version 2.0.0 & 2.1.0.

Both results contained syntax errors for missing interfaces that do not exist in on-premise S/4 HANA 2023 FSP02. Corrections to these missing interfaces are not addressed in the workaround replacement program zaf_r_create_mpc_from_scm20.

  • Class "/IWBEP/IF_V4_PM_FUNC_IMP" does not contain an interface "/IWBEP/IF_V4_PM_FUNC_IMP_V2".
  • Class "/IWBEP/IF_V4_PM_FUNCTION" does not contain an interface "/IWBEP/IF_V4_PM_FU_ADVANCED".

How should Business Accelerator Hub APIs such as Outbound Delivery (A2X) be used from ABAP on-premise client?

Screenshot 2025-01-08 at 11.04.37 AM.png

 

__PRESENT

__PRESENT