Supply Chain Management Blog Posts by SAP
Expand your SAP SCM knowledge and stay informed about supply chain management technology and solutions with blog posts by SAP. Follow and stay connected.
cancel
Showing results for 
Search instead for 
Did you mean: 
Rohit_Mahajan
Product and Topic Expert
Product and Topic Expert
1,868

After the previous Blog on DDD code

https://community.sap.com/t5/supply-chain-management-blogs-by-sap/premium-hub-coe-dsc-sap-tm-code-fo...

Request was for Geocode calculation code.

SAP Transportation Management provides standard way of Geocode Calculation of Locations based on Region or Pin code.

First we have to define Geocoding Levels.

Rohit_Mahajan_0-1719145823802.png

 

Rohit_Mahajan_1-1719145823804.png

 

These are standard Strategy provided by SAP TM.

Rohit_Mahajan_2-1719145823805.png

 

But we get requirements from customer to calculate Geocode based on Exact Address.

At Transaction /SCMTMS/LOC3, you will find following section at location

 

Rohit_Mahajan_3-1719145823808.png

 

 

SAP HANA Spatial Service is recommended approach and you do not have to do any code for same, Details are mentioned in the below link.

Premium Hub CoE – DSC Knowledge Bits – “A simple setup guide to integrate SAP TM with Hana Spatial S...

When customer does not want to use HANA Spatial Service and have HERE or any other api's for Geo Code calculation. 

These are the configuration steps you can use and also added the code which you copy and use it.

This Customizing activity contains general information about setting up the process controller for use with geocoding.

The process controller is a framework that allows you to define your own services, strategies, and methods for a specific application process. For example, if you want to use a strategy to determine geocoordinates different from the standard we deliver, you can define your own strategy using the process controller and assign it to a specific service.

Activities

You can make settings for the process controller in the following Customizing activities:

 

Assign the Strategy to GC level and GIS Zone

 

Rohit_Mahajan_4-1719145823811.png

 

Go to Sm59 and create a connection to GIS provider

 

Rohit_Mahajan_5-1719145823815.png

 

Create a Class ZCL_GEOCODE_CONNECTOR

 

class ZCL_GEOCODE_CONNECTOR definition

  public

  final

  create public .

 

public section.

 

  types TY_REQUEST_REF type ref to /SCMB/S_GEOCODING_REQUEST_INT .

  types:

    ty_t_requests  TYPE STANDARD TABLE OF ty_request_ref

                                 WITH KEY table_line .

  types:

    BEGIN OF ty_s_request_mapping,

          request_id TYPE guid_16,

          adrc_new   TYPE adrc_struc,

          adrc_old   TYPE adrc_struc,

          latitude   TYPE geolat,

          longitude  TYPE geolon,

          altitude   TYPE geoalt,

          geoprec    TYPE geoprecis,

          geosrcid   TYPE geosrcid,

          tzone      TYPE timezone,

          adrc_corr  TYPE adrc_struc,

          messages   TYPE bapiret2_t,

          requests   TYPE ty_t_requests,

        END OF ty_s_request_mapping .

  types:

    ty_t_request_mapping TYPE SORTED TABLE OF ty_s_request_mapping

                                 WITH UNIQUE KEY adrc_new

                                 WITH UNIQUE HASHED KEY request_id COMPONENTS request_id .

 

  constants C_GEOPREC_INITIAL_OKAY type GEOPRECIS value '9999' ##NO_TEXT.

 

  methods GET_STANDARD_COORDINATES

    importing

      !IO_METHPAR type ref to /SCTM/CL_METH_PARAMETER

      !IT_REQUEST type /SCTM/TT_REQUEST .

  class-methods CAST_REQUEST

    importing

      !IO_REQUEST type ref to /SCTM/CL_REQUEST

    returning

      value(RO_REQUEST) type ref to /SCMB/CL_GEOCODING_REQUEST .

  methods EXECUTE_REQUESTS

    importing

      !IV_DIALOG type BOOLE_D

    changing

      !CT_REQUESTS type TY_T_REQUEST_MAPPING .

 

  METHOD get_standard_coordinates.

*It can be assumed that only a single request is passed to this method containing all

*relevant requests: No comprehensive request handling required

    TYPES:

      BEGIN OF ty_s_request,

        adrc    TYPE adrc_struc,

        request TYPE REF TO /scmb/s_geocoding_request_int,

      END OF ty_s_request,

      ty_t_requests TYPE STANDARD TABLE OF ty_s_request.

 

    DATA: lt_requests TYPE ty_t_requests,

          ls_request  TYPE ty_s_request.

 

    DATA: lo_request           TYPE REF TO /sctm/cl_request,

          lo_geocoding_request TYPE REF TO /scmb/cl_geocoding_request.

 

    DATA: lt_request_mapping TYPE ty_t_request_mapping,

          ls_request_mapping TYPE ty_s_request_mapping.

 

    DATA: ls_adrc_previous TYPE adrc_struc.

 

    DATA: lv_num_igs TYPE int4,

          lv_num_ori TYPE int4.

 

    FIELD-SYMBOLS: <fs_request> TYPE ty_s_request.

 

*Map given request structure to optimized Geocoding Structure

*- combine all requests with the same address -> avoid duplicate determinations

    LOOP AT it_request INTO lo_request.

      lo_geocoding_request = cast_request( lo_request ).

      CHECK lo_geocoding_request IS NOT INITIAL.

 

      CLEAR lt_request_mapping.

 

*Sort requests according to address specification to avoid read by address

      LOOP AT lo_geocoding_request->mt_requests REFERENCE INTO ls_request-request.

        CHECK ls_request-request->return_code <> /scmb/if_dist_dur_det=>gc_lddd_return_success.

 

        IF ls_request-adrc IS INITIAL.

          MOVE-CORRESPONDING ls_request-request->addr_new TO ls_request-adrc. "#EC ENHOK

        ENDIF.

 

        CHECK ls_request-adrc IS NOT INITIAL.

        APPEND ls_request TO lt_requests.

      ENDLOOP.

 

      SORT lt_requests BY adrc.

 

      LOOP AT lt_requests ASSIGNING <fs_request>.

*Be pessimistic -> only a successful geo-coding resets this status

        <fs_request>-request->return_code = /scmb/if_dist_dur_det=>gc_lddd_return_failed.

        <fs_request>-request->geo_precision = c_geoprec_initial_okay.

 

        lv_num_ori = lv_num_ori + 1.

        IF <fs_request>-adrc <> ls_adrc_previous.

*New unique address

          IF ls_request_mapping-requests IS NOT INITIAL.

            ls_request_mapping-request_id = /sctm/cl_guid_convert=>get_guid_x16( ).

            INSERT ls_request_mapping INTO TABLE lt_request_mapping.

            CLEAR ls_request_mapping-requests.

          ENDIF.

 

          ls_request_mapping-adrc_new = <fs_request>-adrc.

          MOVE-CORRESPONDING <fs_request>-request->addr_old TO ls_request_mapping-adrc_old. "#EC ENHOK

          ls_adrc_previous = ls_request_mapping-adrc_new.

        ENDIF.

        INSERT <fs_request>-request INTO TABLE ls_request_mapping-requests.

      ENDLOOP.

 

* Take over last request

      IF ls_request_mapping IS NOT INITIAL.

        ls_request_mapping-request_id = /sctm/cl_guid_convert=>get_guid_x16( ).

        INSERT ls_request_mapping INTO TABLE lt_request_mapping.

      ENDIF.

 

      execute_requests( EXPORTING iv_dialog   = lo_geocoding_request->mv_dialog

                        CHANGING  ct_requests = lt_request_mapping ).

 

      CHECK lo_geocoding_request->mo_message_handler->mv_detail_messages = abap_true.

 

      lv_num_igs = lines( lt_request_mapping ).

      MESSAGE s083(/scmb/lddd) WITH lv_num_igs lv_num_ori

        INTO lo_geocoding_request->mo_message_handler->mv_message.

      lo_geocoding_request->mo_message_handler->add_msg_from_sys( ).

    ENDLOOP.

  ENDMETHOD.

  METHOD cast_request.

    TRY.

        ro_request ?= io_request.

      CATCH cx_sy_move_cast_error.

        CLEAR ro_request.

    ENDTRY.

  ENDMETHOD

  METHOD execute_requests.

 

    DATA: lv_api         TYPE string,

          lv_bahne       TYPE string,

          lv_bahns       TYPE string,

          lv_latitude    TYPE geolat,

          lv_longitude   TYPE geolon,

          et_data        TYPE REF TO data,

          lv_destination TYPE c VALUE 'HERE_GEOCODE' LENGTH 15,

          lr_data        TYPE REF TO data,

          lr_request     TYPE ty_request_ref.

 

    FIELD-SYMBOLS: <data>        TYPE data,

                   <items>       TYPE any,

                   <position>    TYPE any,

                   <structure>   TYPE any,

                   <table>       TYPE ANY TABLE,

                   <field>       TYPE any,

                   <field_value> TYPE data

                   .

    "qq=street=Main%20Street;city=Jeddah;postalCode=22334;state=15;country=SA

 

    TRY.

 

 

*Map Train Station and Express Station as Geo code to location.

        LOOP AT ct_requests ASSIGNING FIELD-SYMBOL(<s_request_current>).

          CHECK <s_request_current>-adrc_new IS NOT INITIAL.

          LOOP AT <s_request_current>-requests INTO lr_request.

           

              SELECT SINGLE bezei FROM t005u WHERE spras = @SY-langu

                              AND land1 = @<s_request_current>-adrc_new-country

                               AND bland = @<s_request_current>-adrc_new-region

                               INTO @DATA(lv_region).

 

              IF <s_request_current>-adrc_new-street IS NOT INITIAL.

                CONCATENATE 'street=' <s_request_current>-adrc_new-street INTO lv_api.

              ENDIF.

              IF lv_api IS INITIAL.

                IF <s_request_current>-adrc_new-city1 IS NOT INITIAL.

                  CONCATENATE 'city=' <s_request_current>-adrc_new-city1 INTO lv_api.

                ENDIF.

              ELSEIF <s_request_current>-adrc_new-city1 IS NOT INITIAL.

                CONCATENATE lv_api ';city=' <s_request_current>-adrc_new-city1 INTO lv_api.

              ENDIF.

 

              IF lv_api IS INITIAL.

                IF <s_request_current>-adrc_new-post_code1 IS NOT INITIAL.

                  CONCATENATE 'postalCode=' <s_request_current>-adrc_new-post_code1 INTO lv_api.

                ENDIF.

              ELSEIF <s_request_current>-adrc_new-post_code1 IS NOT INITIAL.

                CONCATENATE lv_api ';postalCode=' <s_request_current>-adrc_new-post_code1 INTO lv_api.

              ENDIF.

 

              IF lv_api IS INITIAL.

                IF lv_region IS NOT INITIAL.

                  CONCATENATE 'state=' lv_region INTO lv_api.

                ENDIF.

              ELSEIF lv_region IS NOT INITIAL.

                CONCATENATE lv_api ';state=' lv_region INTO lv_api.

              ENDIF.

              IF lv_api IS INITIAL.

                IF <s_request_current>-adrc_new-country IS NOT INITIAL.

                  CONCATENATE 'country=' <s_request_current>-adrc_new-country INTO lv_api.

                ENDIF.

              ELSEIF <s_request_current>-adrc_new-country IS NOT INITIAL.

                CONCATENATE lv_api ';country=' <s_request_current>-adrc_new-country INTO lv_api.

              ENDIF.

              CONCATENATE '?qq=' lv_api

                                 INTO lv_api.

 

 

              CALL FUNCTION 'Z_FM_HERE_MAP_REST_API'

                EXPORTING

                  im_destination = lv_destination

                  im_api         = lv_api

                IMPORTING

                  et_data        = et_data.

 

              CHECK et_data IS BOUND.

 

*Fetch Items

              ASSIGN et_data->* TO <data>.

              ASSIGN COMPONENT 'ITEMS' OF STRUCTURE <data> TO <items>.

              ASSIGN <items>->* TO <table>.

 

 

              LOOP AT <table> ASSIGNING <structure>.

 

*Fetch Sections

                ASSIGN <structure>->* TO <data>.

                ASSIGN COMPONENT 'POSITION' OF STRUCTURE <data> TO <position>.

                ASSIGN <position>->* TO FIELD-SYMBOL(<ls_position>).

 

*    if <ls_position> is ASSIGNED.

                ASSIGN COMPONENT 'LAT' OF STRUCTURE <ls_position> TO <field>.

                IF <field> IS ASSIGNED.

                  lr_data = <field>.

                  ASSIGN lr_data->* TO <field_value>.

                  <s_request_current>-latitude = <field_value>.

                ENDIF.

                UNASSIGN: <field>, <field_value>.

 

                ASSIGN COMPONENT 'LNG' OF STRUCTURE <ls_position> TO <field>.

                IF <field> IS ASSIGNED.

                  lr_data = <field>.

                  ASSIGN lr_data->* TO <field_value>.

                  <s_request_current>-longitude = <field_value>.

                ENDIF.

                UNASSIGN: <field>, <field_value>.

                <s_request_current>-geoprec = '0900'.   " Street

*Transfer result to original request(s) in case coordinates could be determined

                LOOP AT <s_request_current>-requests INTO lr_request.

                  CHECK <s_request_current>-longitude IS NOT INITIAL

                     OR <s_request_current>-latitude  IS NOT INITIAL.

                  lr_request->return_code    = /scmb/if_dist_dur_det=>gc_lddd_return_success.

                  lr_request->xpos           = <s_request_current>-longitude.

                  lr_request->ypos           = <s_request_current>-latitude.

                  lr_request->geo_precision  = <s_request_current>-geoprec.

                ENDLOOP.

 

              ENDLOOP.

            CLEAR lr_request.

          ENDLOOP.

        ENDLOOP.

 

      CATCH cx_sy_arithmetic_error cx_sy_conversion_error INTO exc.

 

    ENDTRY.

  ENDMETHOD.

Create a Function Module

 

FUNCTION z_fm_here_map_rest_api.

*"----------------------------------------------------------------------

*"*"Local Interface:

*"  IMPORTING

*"     REFERENCE(IM_DESTINATION) TYPE  CHAR15

*"     VALUE(IM_API) TYPE  STRING

*"  EXPORTING

*"     REFERENCE(ET_DATA) TYPE REF TO  DATA

*"----------------------------------------------------------------------

 

*HTTP Client Abstraction

  DATA: lo_client      TYPE REF TO if_http_client,

        lo_rest_client TYPE REF TO cl_rest_http_client,

        lo_response    TYPE REF TO     if_rest_entity,

*        lv_apikey      TYPE string VALUE 'M-AGoC0QrkXBQqmFSnfpbsf14BFVrpmr9UNEKTVFAUQ'." Rohit on 28-08-2022

 

 

  CHECK im_api IS NOT INITIAL.

 

*Concatenate api key and app id for authentication

*  CONCATENATE im_api '&app_id=' lv_app_id '&apiKey=' lv_apikey INTO im_api.

  CONCATENATE im_api '&apiKey=' lv_apikey INTO im_api.

 

*consume service from RFC Destination

  cl_http_client=>create_by_destination(

   EXPORTING

     destination              = im_destination    " Logical destination (specified in function call)

   IMPORTING

     client                   = lo_client    " HTTP Client Abstraction

   EXCEPTIONS

     argument_not_found       = 1

     destination_not_found    = 2

     destination_no_authority = 3

     plugin_not_active        = 4

     internal_error           = 5

     OTHERS                   = 6 ).

 

  CHECK lo_client IS BOUND.

 

  CREATE OBJECT lo_rest_client

    EXPORTING

      io_http_client = lo_client.

 

*Get data in JSON

  CALL METHOD lo_client->request->set_header_field

    EXPORTING

      name  = 'Accept'

      value = 'application/json'.

 

*Pass API

  cl_http_utility=>set_request_uri(

      EXPORTING

        request = lo_client->request    " HTTP Framework (iHTTP) HTTP Request

        uri     = im_api                   " URI String (in the Form of /path?query-string)

    ).

 

*Pass method as GET

  lo_rest_client->if_rest_client~get( ).

 

  CHECK lo_rest_client IS BOUND.

 

* HTTP response

  lo_response = lo_rest_client->if_rest_client~get_response_entity( ).

 

  CHECK lo_response IS BOUND.

 

* HTTP return status

  DATA(http_status)   = lo_response->get_header_field( '~status_code' ).

 

*Status code should be success

  CHECK http_status = '200' OR http_status = '201'.

 

* HTTP JSON return string

  DATA(json_response) = lo_response->get_string_data( ).

 

  CHECK json_response IS NOT INITIAL.

 

*Convert JSON into Internal table

  CALL METHOD /ui2/cl_json=>deserialize

    EXPORTING

      json         = json_response

      pretty_name  = /ui2/cl_json=>pretty_mode-user

      assoc_arrays = abap_true

    CHANGING

      data         = et_data.

 

ENDFUNCTION.

 

Discover further insights into SAP Premium Engagement and explore how an international team of specialists can assist you in maximizing the value of your SAP solutions.

If you already are a Premium Engagement customer, contact your Technical Quality Manager (TQM) to discuss how Premium Engagement Service can help you with a custom-tailored and efficient service portfolio to make your project a success!

1 Comment