Skip to end of metadata
Go to start of metadata

CLASS zcl_eppm_ruum_proxy DEFINITION
   PUBLIC
   FINAL
   CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES if_dpr_obl_proxy .
    INTERFACES if_dpr_obl_proxy_url .
    INTERFACES if_dpr_appl_bootstrap_member .
    INTERFACES if_dpr_appl_plug_in_subsystem .

    TYPES:
      tt_query_ruum_results TYPE STANDARD TABLE OF zeppm_ruum .

    METHODS constructor .
    CLASS-METHODS create_ruum
      IMPORTING
        !iv_object_type  TYPE dpr_tv_obl_type
        !iv_external_id  TYPE string
      EXPORTING
        !ev_system_error TYPE string
        !ev_ruumid       TYPE string .
    METHODS on_dpr_common_changed
          FOR EVENT changed OF if_dpr_common
      IMPORTING
          !sender .
    METHODS on_dpr_common_created
          FOR EVENT created OF if_dpr_common
      IMPORTING
          !sender .
    METHODS on_dpr_common_deleted
          FOR EVENT deleted OF if_dpr_common
      IMPORTING
          !sender .
    CLASS-METHODS query_ruum_task_kpis
      IMPORTING
        !iv_object_type TYPE dpr_tv_obl_type
      CHANGING
        !cv_ruum        TYPE zeppm_ruum .
    CLASS-METHODS query_ruum
      IMPORTING
        !iv_object_type  TYPE dpr_tv_obl_type
      EXPORTING
        !ev_error_string TYPE string
        !et_query_result TYPE tt_query_ruum_results .
  PROTECTED SECTION.

    METHODS on_change
      IMPORTING
        !sender     TYPE REF TO if_dpr_common
        !changemode TYPE .
  PRIVATE SECTION.

    TYPES:
      BEGIN OF ty_query_ruum_tasks,
        ruumid           TYPE zeppm_ruum_id,
        taskid           TYPE string,
        startdate_year   TYPE string,
        startdate_month  TYPE string,
        startdate_day    TYPE string,
        startdate        TYPE sydatum,
        finishdate_year  TYPE string,
        finishdate_month TYPE string,
        finishdate_day   TYPE string,
        finishdate       TYPE sydatum,
        status           TYPE string,
      END OF ty_query_ruum_tasks .
    TYPES:
      tt_query_ruum_tasks TYPE TABLE OF ty_query_ruum_tasks .
    types:
      BEGIN OF ty_query_ruum_task_custom,
          ruumid     TYPE zeppm_ruum_id,
          taskid     TYPE string,
          parentId   TYPE string,
          sectionId  TYPE zeppm_ruum_id,
          order      type string,
          " sectionOrder type string,
          startdate  TYPE sydatum,
          finishdate TYPE sydatum,
          status     TYPE string,
          name       TYPE string,
          effort     TYPE string,
          remaining  TYPE string,
          completion TYPE string,
        END OF ty_query_ruum_task_custom .
    types:
      tt_query_ruum_task_custom TYPE STANDARD TABLE OF ty_query_ruum_task_custom .
    TYPES:
      BEGIN OF ty_instance,
        obj_link_guid TYPE dpr_tv_guid,
        root_guid     TYPE dpr_tv_guid,
        task_guid     TYPE dpr_tv_guid,
        common        TYPE REF TO if_dpr_common,
        native_object TYPE REF TO object,
        project_id    TYPE dpr_tv_project_id,
        projectname   TYPE cgpl_text1,
        task_id       TYPE dpr_tv_task_id,
        taskname      TYPE cgpl_text1,
        mode(1)       TYPE c,
      END OF ty_instance .
    TYPES:
      tt_instance TYPE SORTED TABLE OF ty_instance WITH UNIQUE KEY obj_link_guid .

    CLASS-DATA sv_query_timestamp TYPE .
    CLASS-DATA st_query_ruum_result TYPE tt_query_ruum_results .
    CLASS-DATA mt_linkref TYPE tt_instance .
    class-data ST_QUERY_RUUM_TASK_CUSTOM type TT_QUERY_RUUM_TASK_CUSTOM .
    CLASS-DATA mr_instance TYPE REF TO if_dpr_appl_plug_in_subsystem .
    CONSTANTS mc_oauth2_profile TYPE oa2c_profile VALUE 'ZRUUM'.

    class-methods GET_RUUM_TASKS
      importing
        !IV_OBJECT_TYPE type DPR_TV_OBL_TYPE .
    CLASS-METHODS get_service_url
      IMPORTING
        !iv_object_type       TYPE dpr_tv_obl_type
      RETURNING
        VALUE(rv_service_urlTYPE string .
    CLASS-METHODS get_service_url_parameter
      IMPORTING
        !iv_object_type               TYPE dpr_tv_obl_type
        VALUE(iv_url_parameter)       TYPE olr3_tv_pname
      RETURNING
        VALUE(rv_url_parameter_valueTYPE string .
    CLASS-METHODS get_user_email
      RETURNING
        VALUE(rv_mailaddressTYPE string .
    CLASS-METHODS has_link
      IMPORTING
        !iv_object_key     TYPE string
        !iv_object_type    TYPE dpr_tv_obl_type
      RETURNING
        VALUE(rv_has_linkTYPE abap_bool .
    CLASS-METHODS get_string_fragment
      IMPORTING
        !iv_part         TYPE i
        !iv_string       TYPE string
      RETURNING
        VALUE(rv_stringTYPE string .
    CLASS-METHODS string_cut_trailing_spaces
      IMPORTING
        !iv_string       TYPE string
      RETURNING
        VALUE(rv_stringTYPE string .
    CLASS-METHODS send_url
      IMPORTING
        !io_http_client TYPE REF TO if_http_client .
ENDCLASS.



CLASS ZCL_EPPM_RUUM_PROXY IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD constructor.

    SET HANDLER on_dpr_common_changed FOR ALL INSTANCES.
    SET HANDLER on_dpr_common_created FOR ALL INSTANCES.
    SET HANDLER on_dpr_common_deleted FOR ALL INSTANCES.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>CREATE_RUUM
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_EXTERNAL_ID                 TYPE        STRING
* | [<---] EV_SYSTEM_ERROR                TYPE        STRING
* | [<---] EV_RUUMID                      TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD create_ruum.

    DATA:
      lv_service_url TYPE string,
      lv_csrf_token  TYPE string,
      lv_timestamp   TYPE i,
      lv_body        TYPE string,
      lt_result      TYPE TABLE OF zeppm_ruum.

    TRY.
        DATA(lo_http_clientlcl_rest_client=>get_client(
          EXPORTING
            iv_obl_type       iv_object_type
            iv_oauth2_profile mc_oauth2_profile
          IMPORTING
            ev_xsrf_token    lv_csrf_token
         ).
      CATCH lcx_rest_nocust INTO DATA(lx_odata_client).
        ev_system_error lx_odata_client->get_text).
        RETURN.
      CATCH lcx_oauth_grant_required INTO DATA(lx_oac_grant).
        ev_system_error lx_oac_grant->get_text).
        MESSAGE ID 'ZRUUM' TYPE 'E' NUMBER '001' WITH
          get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
          get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
          get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
          get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
          INTO ev_system_error.
        RETURN.
    ENDTRY.

    " prepare service url
    lv_service_url get_service_urliv_object_type ).
    " switch to new API
    " CONCATENATE lv_service_url 'ruums' INTO lv_service_url.
    CONCATENATE lv_service_url 'OData/Ruum.svc/CreateProjectWithParameters' INTO lv_service_url.

    "lv_body = '{' && cl_abap_char_utilities=>cr_lf &&
    "          '"name": "' && string_cut_trailing_spaces( iv_external_id ) && '",' && cl_abap_char_utilities=>cr_lf &&
    "          '"fromTemplateId": "' && get_service_url_parameter( iv_object_type = iv_object_type iv_url_parameter = 'ZTEMPLATE' ) && '",' && cl_abap_char_utilities=>cr_lf &&
    "          '"participants": [' && cl_abap_char_utilities=>cr_lf &&
    "          '"  ' && get_user_email( ) && '"' && cl_abap_char_utilities=>cr_lf &&
    "          '],' && cl_abap_char_utilities=>cr_lf &&
    "          '"variables": [{' && cl_abap_char_utilities=>cr_lf &&
    "          '  "id": "EPPM Project",' && cl_abap_char_utilities=>cr_lf &&
    "          '  "dataType": "URL",' && cl_abap_char_utilities=>cr_lf &&
    "          '  "value": "https://*:*/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html#EnterpriseProject-showOverviewPage"' && cl_abap_char_utilities=>cr_lf &&
    "          '}] }' && cl_abap_char_utilities=>cr_lf.

    lv_body '{' && cl_abap_char_utilities=>cr_lf &&
              '  "templateId": "' && get_service_url_parameteriv_object_type iv_object_type iv_url_parameter 'ZTEMPLATE' && '",' && cl_abap_char_utilities=>cr_lf &&
              '  "ignoreTaskDates": false,' && cl_abap_char_utilities=>cr_lf &&
              '  "relativeStartDate": "' && sy-datlo(4&& '-' && sy-datlo+4(2&& '-' && sy-datlo+6(2&& '",' && cl_abap_char_utilities=>cr_lf &&
              '  "project": {'  && cl_abap_char_utilities=>cr_lf &&
              '    "name": "' && string_cut_trailing_spacesiv_external_id && '",' && cl_abap_char_utilities=>cr_lf &&
              '    "participants": [' && cl_abap_char_utilities=>cr_lf &&
              '      {' && cl_abap_char_utilities=>cr_lf &&
              '        "email": "' && get_user_email&& '"' && cl_abap_char_utilities=>cr_lf &&
              '      }' && cl_abap_char_utilities=>cr_lf.
    if get_service_url_parameteriv_object_type iv_object_type iv_url_parameter 'ZWORKSPACE'is initial.
      lv_body lv_body &&
              '    ]' && cl_abap_char_utilities=>cr_lf.
    else.
      lv_body lv_body &&
              '    ],' && cl_abap_char_utilities=>cr_lf &&
              '    "workspaceId": "' && get_service_url_parameteriv_object_type iv_object_type iv_url_parameter 'ZWORKSPACE' && '"' && cl_abap_char_utilities=>cr_lf.
    endif.
    lv_body lv_body &&

              '  }' && cl_abap_char_utilities=>cr_lf &&
              '}' && cl_abap_char_utilities=>cr_lf.

    DATA lv_body_xstr TYPE xstring.
    CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
      EXPORTING
        text   lv_body
      IMPORTING
        buffer lv_body_xstr.

    " read data
    lo_http_client->request->set_methodif_http_request=>co_request_method_post ).
    lo_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri        value lv_service_url ).
    lo_http_client->request->set_content_typecontent_type 'application/json' ).
    lo_http_client->request->set_datalv_body_xstr ).
    send_urllo_http_client ).
    lo_http_client->response->get_statusIMPORTING code DATA(lv_status_code).

    IF lv_status_code <> 200.
      ev_system_error lo_http_client->response->get_cdata).
      EXIT.
    ENDIF.

    "make sure that buffer is invalidated - we simply do this by clearing the timestamp of last read access
    CLEAR sv_query_timestamp.
    "set return data
    ev_ruumid lcl_json_parser=>get_property_from_jsoniv_json lo_http_client->response->get_cdataiv_property 'projectId' ).

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_RUUM_TASKS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD GET_RUUM_TASKS.

    DATA:
      lv_service_url TYPE string,
      lv_service     TYPE string,
      lv_csrf_token  TYPE string,
      lv_timestamp   TYPE i,
      lt_result      TYPE tt_query_ruum_tasks.

    " get client
    TRY.
        DATA(lo_http_clientlcl_rest_client=>get_client(
          EXPORTING
            iv_obl_type       iv_object_type
            iv_oauth2_profile mc_oauth2_profile
          IMPORTING
            ev_xsrf_token    lv_csrf_token
         ).
      CATCH lcx_rest.
        " Silent exit. All relevant errors will have been sent already
        RETURN.
    ENDTRY.

    " get service url
    CALL METHOD cl_dpr_obl_repository=>get_object_capabilities
      EXPORTING
        iv_object_type iv_object_type
      IMPORTING
        es_obl_obtyp   DATA(ls_obtype)
      EXCEPTIONS
        OTHERS         0.

    cl_dpr_olr3_repository=>get_url_webserver_par(
       EXPORTING
         iv_web_server     =                  ls_obtype-web_server
       IMPORTING
         ev_web_server_url =                  DATA(lv_ws_url)
       EXCEPTIONS
         OTHERS            ).
    lv_service lv_ws_url.
    TRANSLATE lv_service TO LOWER CASE.

    DO TIMES.

      IF sy-index 1.
        CONCATENATE lv_service 'OData/Reporting.svc/Tasks?$top=1000' INTO lv_service_url.
      ELSE.
        CONCATENATE lv_service 'OData/Reporting.svc/Tasks?$skip=1000&$top=1000' INTO lv_service_url.
      ENDIF.


      " read data
      lo_http_client->request->set_methodif_http_request=>co_request_method_get ).
      lo_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri        value lv_service_url ).

      send_urllo_http_client ).

      lo_http_client->response->get_statusIMPORTING code DATA(lv_status_code).

      DATA(lv_responselo_http_client->response->get_cdata).

      " parse data
      DATA(lt_ruum_jsonslcl_json_parser=>get_enumeration_from_jsonEXPORTING iv_json lv_response iv_property 'value' ).

      LOOP AT lt_ruum_jsons ASSIGNING FIELD-SYMBOL(<ls_ruum_json>).
        APPEND INITIAL LINE TO st_query_ruum_task_custom ASSIGNING FIELD-SYMBOL(<ls_task>).
        <ls_task>-ruumid lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'projectId' ).
        <ls_task>-sectionid lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'sectionId' ).
        <ls_task>-status lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'status' ).
        DATA lv_date TYPE string.
        lv_date lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'startDate' ).
        REPLACE ALL OCCURRENCES OF '-' IN lv_date WITH ''.
        IF lv_date <> 'null'.
          <ls_task>-startdate lv_date.
        ENDIF.
        lv_date lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'dueDate' ).
        REPLACE ALL OCCURRENCES OF '-' IN lv_date WITH ''.
        IF lv_date <> 'null'.
          <ls_task>-finishdate lv_date.
        ENDIF.
        <ls_task>-taskid     lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json> iv_property 'taskId' ).
        <ls_task>-parentid   lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json> iv_property 'parentId' ).
        <ls_task>-order      lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json> iv_property 'order' ).
        <ls_task>-name       lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json> iv_property 'description' ).

        " If you use workspaces to maintain custom fields: Here some examples how toread them into the internal tables :)

        " <ls_task>-effort     = lcl_json_parser=>get_property_from_json( iv_json = <ls_ruum_json> iv_property = 'custom_field_1580*********_r*******' ).
        " IF <ls_task>-effort = 'null'.
        "   <ls_task>-effort = '0'.
        " ENDIF.
        " <ls_task>-remaining  = lcl_json_parser=>get_property_from_json( iv_json = <ls_ruum_json> iv_property = 'custom_field_1580*********_w*******' ).
        " IF <ls_task>-remaining = 'null'.
        "   <ls_task>-remaining = '0'.
        " ENDIF.
        " <ls_task>-completion = lcl_json_parser=>get_property_from_json( iv_json = <ls_ruum_json> iv_property = 'custom_field_1581*********_s*******' ).
        " IF <ls_task>-completion = 'null'.
        "   <ls_task>-completion = '0'.
        " ENDIF.

      ENDLOOP.

    ENDDO.

    SORT st_query_ruum_task_custom BY ruumid.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_SERVICE_URL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<-()] RV_SERVICE_URL                 TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_service_url.

    " get service url
    CALL METHOD cl_dpr_obl_repository=>get_object_capabilities
      EXPORTING
        iv_object_type iv_object_type
      IMPORTING
        es_obl_obtyp   DATA(ls_obtype)
      EXCEPTIONS
        OTHERS         0.

    cl_dpr_olr3_repository=>get_url_webserver_par(
       EXPORTING
         iv_web_server     =                  ls_obtype-web_server
       IMPORTING
         ev_web_server_url =                  DATA(lv_ws_url)
       EXCEPTIONS
         OTHERS            ).
    rv_service_url lv_ws_url.
    TRANSLATE rv_service_url TO LOWER CASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_SERVICE_URL_PARAMETER
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_URL_PARAMETER               TYPE        OLR3_TV_PNAME
* | [<-()] RV_URL_PARAMETER_VALUE         TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_service_url_parameter.

    " get service url
    CALL METHOD cl_dpr_obl_repository=>get_object_capabilities
      EXPORTING
        iv_object_type iv_object_type
      IMPORTING
        es_obl_obtyp   DATA(ls_obtype)
      EXCEPTIONS
        OTHERS         0.

    cl_dpr_olr3_repository=>get_url_webserver_par(
       EXPORTING
         iv_web_server     =                  ls_obtype-web_server
       IMPORTING
         et_parameter      DATA(lt_parameter)
       EXCEPTIONS
         OTHERS            ).

    READ TABLE lt_parameter ASSIGNING FIELD-SYMBOL(<ls_parameter>WITH KEY name iv_url_parameter.
    IF sy-subrc 0.
      rv_url_parameter_value <ls_parameter>-value.
    ENDIF.

    TRANSLATE rv_url_parameter_value TO LOWER CASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_STRING_FRAGMENT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_PART                        TYPE        I
* | [--->] IV_STRING                      TYPE        STRING
* | [<-()] RV_STRING                      TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_string_fragment.

    DATA:
      lv_tmp(50TYPE c,
      lv_len     TYPE i.

    lv_len strleniv_string ).

    CASE iv_part.
      WHEN 1.
        rv_string iv_string.
      WHEN 2.
        IF lv_len > 50.
          rv_string iv_string+50.
        ENDIF.
      WHEN 3.
        IF lv_len > 100.
          rv_string iv_string+100.
        ENDIF.
      WHEN 4.
        IF lv_len > 150.
          rv_string iv_string+150.
        ENDIF.
    ENDCASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_USER_EMAIL
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_MAILADDRESS                 TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_user_email.

    DATA:
      lv_persnumber TYPE ad_persnum,
      lv_addrnumber TYPE ad_addrnum,
      lt_adsmtp     TYPE TABLE OF adsmtp.

    rv_mailaddress sy-uname && '@ruumapp.com'.
    TRANSLATE rv_mailaddress TO LOWER CASE.

    CALL FUNCTION 'SUSR_USER_ADDRESSKEY_GET'
      EXPORTING
        bname             sy-uname
      IMPORTING
        persnumber        lv_persnumber
        addrnumber        lv_addrnumber
      EXCEPTIONS
        address_not_found 1
        OTHERS            2.
    CHECK sy-subrc IS INITIAL.

    " Get address details
    CALL FUNCTION 'ADDR_PERS_COMP_COMM_GET'
      EXPORTING
        address_number    lv_addrnumber
        person_number     lv_persnumber
        table_type        'ADSMTP'
      TABLES
        comm_table        lt_adsmtp
      EXCEPTIONS
        parameter_error   1
        address_not_exist 2
        person_not_exist  3
        internal_error    4
        OTHERS            5.
    CHECK sy-subrc IS INITIAL.

    READ TABLE lt_adsmtp ASSIGNING FIELD-SYMBOL(<ls_adsmtp>WITH KEY flgdefault abap_true.
    IF sy-subrc IS INITIAL.
      rv_mailaddress <ls_adsmtp>-smtp_addr.
    ENDIF.
    TRANSLATE rv_mailaddress TO LOWER CASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>HAS_LINK
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_KEY                  TYPE        STRING
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<-()] RV_HAS_LINK                    TYPE        ABAP_BOOL
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD has_link.

    query_ruum(
      EXPORTING
        iv_object_type  iv_object_type
      IMPORTING
        et_query_result DATA(lt_result)  ).

    READ TABLE lt_result TRANSPORTING NO FIELDS WITH KEY ruumid iv_object_key.
    IF sy-subrc IS INITIAL.
      rv_has_link abap_true.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_APPL_BOOTSTRAP_MEMBER~GET_SEQUENCE_PLACE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_SEQUENCE_PLACE              TYPE        I
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_bootstrap_member~get_sequence_place.
    rv_sequence_place -1.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_APPL_BOOTSTRAP_MEMBER~LOAD
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_bootstrap_member~load.
    RETURN.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~FREE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~free.

    SET HANDLER on_dpr_common_changed        FOR ALL INSTANCES ACTIVATION cl_dpr_co=>sc_false.
    SET HANDLER on_dpr_common_created        FOR ALL INSTANCES ACTIVATION cl_dpr_co=>sc_false.
    SET HANDLER on_dpr_common_deleted        FOR ALL INSTANCES ACTIVATION cl_dpr_co=>sc_false.

    CLEARmt_linkref.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_APPL_PLUG_IN_SUBSYSTEM~GET_INSTANCE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RR_INSTANCE                    TYPE REF TO IF_DPR_APPL_PLUG_IN_SUBSYSTEM
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~get_instance.

    IF mr_instance IS INITIAL.

      CREATE OBJECT mr_instance TYPE zcl_eppm_ruum_proxy.

    ENDIF.

    rr_instance mr_instance.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~HAS_CHANGES
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_HAS_CHANGES                 TYPE        BOOLE_D
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~has_changes.

    DESCRIBE TABLE mt_linkref.
    IF sy-tfill > 0.
      rv_has_changes abap_true.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~INITIALIZE_AFTER_SAVE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~initialize_after_save.

    CLEAR:
      mt_linkref,
      sv_query_timestamp,
      st_query_ruum_result.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~PREPARE_TO_SAVE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_RC                          TYPE        I
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~prepare_to_save.
    rv_rc 0.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~SAVE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_RC                          TYPE        I
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~save.

    DATA:
      lr_objectlink   TYPE REF TO cl_dpr_obl_assignment,
      lo_http_client  TYPE REF TO if_http_client,
      lv_csrf_token   TYPE string,
      ls_oblink_data  TYPE dpr_objlink,
      lv_body         TYPE string,
      lv_service_url  TYPE string,
      lv_guid_as_char TYPE string,
      lv_path         TYPE string,
      lv_what_i_am    TYPE string VALUE 'PPM 6.1 or similar'.

    IF mt_linkref IS NOT INITIAL.

      LOOP AT mt_linkref ASSIGNING FIELD-SYMBOL(<ls_linkref>WHERE mode CA 'CD'.

        " Get object link attributes
        TRY.
            lr_objectlink ?= <ls_linkref>-native_object.
          CATCH cx_sy_move_cast_error.
            " Not an object link: Shame on you but I won't tell anybody if you don't
            CONTINUE.
        ENDTRY.
        lr_objectlink->get_attributesIMPORTING es_attributes ls_oblink_data ).

        " Ruum links only
        IF NOT ls_oblink_data-object_type CS 'RUUM'.
          CONTINUE.
        ENDIF.

        TRY.
            lo_http_client lcl_rest_client=>get_client(
              EXPORTING
                iv_obl_type       ls_oblink_data-object_type
                iv_oauth2_profile mc_oauth2_profile
              IMPORTING
                ev_xsrf_token    lv_csrf_token
             ).
          CATCH lcx_rest.
            " If something goes wrong here, it went wrong earlier. We don't have to react on this again.
            CONTINUE.
        ENDTRY.

        lv_service_url get_service_urlls_oblink_data-object_type ).
        " We only do ruum updates here. As we don't know which object link to take, we check the url
        IF NOT lv_service_url CS 'api.ruumapp.com'.
          CONTINUE.
        ENDIF.

        " Create Service URL here
        CONCATENATE lv_service_url 'OData/Ruum.svc/Projects(''' ls_oblink_data-object_key ''')/customFields' INTO lv_service_url.

        " get client and set it up
        lo_http_client lcl_rest_client=>get_clientls_oblink_data-object_type ).

        CASE <ls_linkref>-mode.
            " Create mode: add new remote link to ruum
          WHEN 'C'.
            lo_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri  value lv_service_url ).
            lo_http_client->request->set_header_fieldname  if_http_header_fields=>content_type value 'application/json' ).
            lo_http_client->request->set_method'PATCH' ).
            DATA lv_self TYPE string.
            TRY.
                cl_gdt_conversion=>guid_outboundEXPORTING im_guid_x ls_oblink_data-project_guid IMPORTING ex_value  lv_self ).
              CATCH cx_gdt_conversion" Error During Global Data Types Conversion
            ENDTRY.
            DATA lv_projectref TYPE string.
            IF <ls_linkref>-taskname IS NOT INITIAL AND <ls_linkref>-taskname <> <ls_linkref>-projectname.
              lv_projectref <ls_linkref>-projectname && ' - ' && <ls_linkref>-taskname.
            ELSE.
              lv_projectref <ls_linkref>-projectname.
            ENDIF.

            DATAlv_localurl  TYPE string,  lv_localport TYPE string.
            CALL FUNCTION 'TH_GET_VIRT_HOST_DATA'
              EXPORTING
                protocol       2
                virt_idx       0
              IMPORTING
                hostname       lv_localurl
                port           lv_localport
              EXCEPTIONS
                not_found      1
                internal_error 2
                OTHERS         3.
            IF sy-subrc <> 0.
              CONTINUE.
            ENDIF.

            CASE lv_what_i_am.
              WHEN 'SolutionManager'.
                "---------------------------------------------------------------------------------
                " use this link format when using this code for a Solution Manager based scenario
                "---------------------------------------------------------------------------------
                lv_self 'https://' && lv_localurl && ':' && lv_localport
                       && '/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html#Action-projectManagementPMO&/detail/'
                       && to_upperlv_self ).
              WHEN 'S/4HANA CE'.
                lv_self 'https://' && lv_localurl && ':' && lv_localport
                       && '/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html#EnterpriseProject-showProjectBrief&//C_PPM_ProjectBriefTP(ProjectUUID=guid'''
                       && lv_self
                       && ''',IsActiveEntity=true)'.
              WHEN 'PPM 6.1 or similar'.
                "---------------------------------------------------------------------------------
                " Link format for connecting with WD ABAP based PPM 6.1-like UI
                "---------------------------------------------------------------------------------
                lv_self ls_oblink_data-project_guid.
                lv_self 'https://' && lv_localurl && ':' && lv_localport
                       && '/nwbc/~canvas;window=app/wda/cprojects_fpm/?sap-client='
                       && sy-mandt
                       &&'&STARTVIEW=Projects&OBJ_EVENT=DPO'
                       && lv_self
                       && lv_self
                       && 'DPO&DetailView=DPO&sap-wd-configid=CPROJECTS_FPM&EDITMODE=display&sap-language=EN'.
            ENDCASE.

            " To store a back reference to the S/4HANA Project, you need to introduce a custom
            " for your workspace. Here you can then hardcode the techncal custom field definition
            " by replacing the field name 'custom_field_123123123123' in the code by the real value.
            lv_body '{' && cl_abap_char_utilities=>cr_lf
                   && '   "custom_field_123123123123": "' && lv_self && '"' && cl_abap_char_utilities=>cr_lf
                   && '}'.
            DATA lv_body_xstr TYPE xstring.
            CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
              EXPORTING
                text   lv_body
              IMPORTING
                buffer lv_body_xstr.

            " To get the link maintainmed in a custom field, un-coment the next four lines:
            " lo_http_client->request->set_data( lv_body_xstr ).
            " send_url( lo_http_client ).
            " lo_http_client->response->get_status( IMPORTING code = DATA(lv_status_code) ).
            " DATA(lv_result) = lo_http_client->response->get_cdata( ).

          WHEN 'D'.
            " No deletion yet. Is it possible to delete a variable here?
        ENDCASE.
      ENDLOOP.

    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY_URL~GET_APPLICATION_URLS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_SERVICE                     TYPE        OLR3_TV_SERVICE(optional)
* | [--->] IV_OBJECT_KEY                  TYPE        STRING(optional)
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_EXTERNAL_KEY                TYPE        OLR3_TV_STRING(optional)
* | [<---] ET_APPLICATION_URL             TYPE        OLR3_TT_URL
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy_url~get_application_urls.

    DATAls_odata TYPE olr3_ts_url,
          ls_ui    TYPE olr3_ts_url.

    CLEAR et_application_url.

    " get all services
    cl_dpr_olr3_repository=>get_url_def(
      EXPORTING
        iv_object_type =  iv_object_type
       IMPORTING
         et_services    DATA(lt_services)
      EXCEPTIONS
        OTHERS         ).
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    " get url service
    LOOP AT lt_services ASSIGNING FIELD-SYMBOL(<ls_services>).

      cl_dpr_olr3_repository=>get_url_webserver_par(
        EXPORTING
          iv_web_server     =                  <ls_services>-web_server
        IMPORTING
          ev_web_server_url =                  DATA(lv_url)
          et_parameter      =                  DATA(lt_parameter)
        EXCEPTIONS
          OTHERS            ).

      " Get text
      cl_dpr_olr3_repository=>get_url_service(
        EXPORTING
          iv_service   =                  <ls_services>-service
        IMPORTING
          ev_text      =                  DATA(lv_service_text)  ).

      APPEND INITIAL LINE TO et_application_url ASSIGNING FIELD-SYMBOL(<ls_application_url>).
      <ls_application_url>-service_url lv_url.
      <ls_application_url>-pos <ls_services>-pos.
      <ls_application_url>-description lv_service_text.
      <ls_application_url>-tcode <ls_services>-service.

    ENDLOOP.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY~CHECK_EXISTENCE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<---] EV_DESCRIPTION                 TYPE        STRING
* | [<---] EV_SYSTEM_ERROR                TYPE        STRING
* | [<-->] CV_EXTERNAL_ID                 TYPE        STRING
* | [<-->] CV_OBJECT_KEY                  TYPE        STRING
* | [EXC!] NOT_FOUND
* | [EXC!] NOT_ACCESSIBLE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy~check_existence.

    DATA:
      ltr_name  TYPE RANGE OF zeppm_ruum_name.

    query_ruum(
      EXPORTING
        iv_object_type  iv_object_type
      IMPORTING
        ev_error_string ev_system_error
        et_query_result DATA(lt_result)  ).

    CHECK ev_system_error IS INITIAL.

    IF cv_object_key IS NOT INITIAL.
      READ TABLE lt_result ASSIGNING FIELD-SYMBOL(<ls_result>WITH KEY ruumid cv_object_key.
      IF sy-subrc IS NOT INITIAL.
        RAISE not_accessible.
      ELSE.
        cv_external_id ev_description <ls_result>-name.
      ENDIF.
    ELSE.
      READ TABLE lt_result ASSIGNING <ls_result> WITH KEY name cv_external_id.
      IF sy-subrc IS NOT INITIAL.
        create_ruum(
          EXPORTING
            iv_object_type iv_object_type iv_external_id cv_external_id
          IMPORTING
            ev_system_error ev_system_error
            ev_ruumid       cv_object_key  ).
        IF ev_system_error IS NOT INITIAL.
          RAISE not_found.
        ENDIF.
        ev_description cv_external_id.
      ELSE.
        cv_object_key <ls_result>-ruumid.
        ev_description cv_external_id.
      ENDIF.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY~GET_APPLICATION_URL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_KEY                  TYPE        STRING
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<---] EV_APPLICATION_URL             TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy~get_application_url.

    DATA  lv_ui_endpoint      TYPE string.
    DATAlt_url              TYPE olr3_tt_url.

    CLEAR ev_application_url.

    CHECK iv_object_key > ' '.

    CHECK has_linkiv_object_key iv_object_key iv_object_type iv_object_type abap_true.

** get IPD endpoint (= URL base) for UI
    CALL METHOD if_dpr_obl_proxy_url~get_application_urls
      EXPORTING
        iv_object_key      iv_object_key
        iv_object_type     iv_object_type
      IMPORTING
        et_application_url lt_url.

    READ TABLE lt_url ASSIGNING FIELD-SYMBOL(<ls_url>WITH KEY tcode 'ZRUUM_FO'.
    IF NOT <ls_url> IS ASSIGNED.
      RETURN.
    ENDIF.

    lv_ui_endpoint <ls_url>-service_url.
    TRANSLATE lv_ui_endpoint TO LOWER CASE.

    " add ruum id
    IF NOT iv_object_key IS INITIAL.
      CONCATENATE lv_ui_endpoint iv_object_key INTO ev_application_url.
    ENDIF.   " IF iv_object_key IS INITIAL.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY~GET_DATA
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_KEY                  TYPE        STRING
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_CONTEXT                     TYPE        STRING(optional)
* | [<---] EV_OBJECT_DATA                 TYPE        XSTRING
* | [<---] EV_SYSTEM_ERROR                TYPE        STRING
* | [EXC!] NOT_FOUND
* | [EXC!] NOT_ACCESSIBLE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy~get_data.

    DATA:
      lt_data      TYPE olr3_tt_tab_data,
      lt_dfies_tab TYPE TABLE OF dfies,
      lt_xmltab    TYPE olr3_tt_xmlattrib,
      lv_tabname   TYPE olr3_tv_ddic_table.
    FIELD-SYMBOLS:
      <lv_content>       TYPE any.

    " Get ruum data
    query_ruum(
       EXPORTING
         iv_object_type iv_object_type
       IMPORTING
        ev_error_string ev_system_error
        et_query_result =  DATA(lt_result).
    IF ev_system_error IS NOT INITIAL.
      RETURN.
    ENDIF.

    READ TABLE lt_result ASSIGNING FIELD-SYMBOL(<ls_result>WITH KEY ruumid iv_object_key.
    IF sy-subrc IS NOT INITIAL.
      RAISE not_accessible.
    ENDIF.

    " Enhance ruum data with kpi like characteristics from existing tasks
    query_ruum_task_kpisEXPORTING iv_object_type iv_object_type CHANGING cv_ruum <ls_result> ).

    " We need the table definition to dynamically define the structure to receive data
    CALL METHOD cl_dpr_olr3_repository=>get_tabledef
      EXPORTING
        iv_object_type    iv_object_type
        iv_method         '04'
      IMPORTING
        ev_table_viewname lv_tabname
      EXCEPTIONS
        not_found         1.
    IF sy-subrc IS NOT INITIAL.
      CONCATENATE iv_object_key TEXT-004 INTO ev_system_error.
      RETURN.
    ENDIF.

    " Get the field names that are required
    CALL METHOD cl_dpr_olr3_repository=>get_fields
      EXPORTING
        iv_object_type iv_object_type
      IMPORTING
        et_data        lt_data
      EXCEPTIONS
        not_found      1.
    IF sy-subrc IS NOT INITIAL.
      " No fields defined as well: no XML string is possible
      CLEAR ev_object_data.
      EXIT.
    ENDIF.

    " Get labels via DDIC
    CALL FUNCTION 'DDIF_FIELDINFO_GET'
      EXPORTING
        tabname   lv_tabname
      TABLES
        dfies_tab lt_dfies_tab
      EXCEPTIONS
        OTHERS    1.
    IF sy-subrc IS NOT INITIAL.
      CONCATENATE iv_object_key TEXT-004 INTO ev_system_error SEPARATED BY space.
      RETURN.
    ENDIF.
    SORT lt_dfies_tab BY fieldname ASCENDING.

    " Prepare result for XML transformation
    LOOP AT lt_data ASSIGNING FIELD-SYMBOL(<ls_data>).
      READ TABLE lt_dfies_tab ASSIGNING  FIELD-SYMBOL(<ls_dfies>WITH KEY fieldname <ls_data>-olr3_tab_field.
      IF sy-subrc 0.
        <ls_data>-olr3_tab_label <ls_dfies>-scrtext_m.
      ENDIF.
      ASSIGN COMPONENT <ls_data>-olr3_tab_field OF STRUCTURE <ls_result> TO <lv_content>.
      IF sy-subrc IS INITIAL.
        WRITE <lv_content> TO <ls_data>-olr3_tab_value.
      ENDIF.
    ENDLOOP.

    " Use the data from OData call and the frame info to build a work table
    CALL METHOD cl_dpr_olr3_work=>built_tab_from_data
      EXPORTING
        iv_object_type iv_object_type
        iv_context     space
        iv_frame       space
        it_data        lt_data
      IMPORTING
        et_xmltab      lt_xmltab.

    " Tweak attribute names to have evaluation w/o Badi implementation
    LOOP AT lt_xmltab ASSIGNING FIELD-SYMBOL(<ls_xmltab>).
      READ TABLE lt_data ASSIGNING <ls_data> WITH KEY olr3_tab_key <ls_xmltab>-id.
      IF sy-subrc IS INITIAL.
        IF <ls_data>-olr3_tab_key_eval > ' '.
          <ls_xmltab>-id <ls_data>-olr3_tab_key_eval.
        ELSE.
          <ls_xmltab>-id <ls_data>-olr3_tab_field.
        ENDIF.
      ENDIF.
    ENDLOOP.

    " Conversion of contents of LT_XMLTAB into an XML string
    CALL METHOD cl_dpr_olr3_work=>convert_tab_to_xml
      EXPORTING
        it_xmltab      lt_xmltab
      IMPORTING
        ev_object_data ev_object_data.


  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY~SEARCH_OBJECTS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_SEARCH_CRITERIA             TYPE        DPR_TT_OBL_SEARCH_CRITERIA
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_MAX_NO_OF_HITS              TYPE        NUMC4(optional)
* | [<---] EV_ERROR_STRING                TYPE        STRING
* | [<---] ET_SEARCH_RESULT               TYPE        DPR_TT_OBL_SEARCH_RESULTS
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy~search_objects.

    DATA:
      lt_result TYPE TABLE OF zeppm_ruum,
      ltr_name  TYPE RANGE OF zeppm_ruum_name.

    query_ruum(
      EXPORTING
        iv_object_type  iv_object_type
      IMPORTING
        ev_error_string ev_error_string
        et_query_result lt_result
    ).

    CHECK ev_error_string IS INITIAL.

    LOOP AT it_search_criteria ASSIGNING FIELD-SYMBOL(<ls_search_criteria>WHERE fieldname 'NAME'.
      APPEND INITIAL LINE TO ltr_name ASSIGNING FIELD-SYMBOL(<ls_range>).
      IF <ls_search_criteria>-value CS '*'.
        <ls_range> VALUE #sign 'I' option 'CP' low <ls_search_criteria>-value ).
      ELSE.
        <ls_range> VALUE #sign 'I' option 'EQ' low <ls_search_criteria>-value ).
      ENDIF.
    ENDLOOP.

    LOOP AT lt_result ASSIGNING FIELD-SYMBOL(<ls_result>WHERE name IN ltr_name.
      APPEND INITIAL LINE TO et_search_result ASSIGNING FIELD-SYMBOL(<ls_search_result>).
      "      <ls_search_result>-object_key = <ls_result>-ruumid.
      "      CONCATENATE <ls_result>-name '                                                  .' INTO  <ls_search_result>-external_id.
      "      <ls_search_result>-external_id = <ls_search_result>-external_id(50).
      <ls_search_result>-external_id <ls_result>-name.
      <ls_search_result>-object_key  <ls_result>-ruumid.
      "      <ls_search_result>-description = <ls_search_result>-external_id.
    ENDLOOP.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_EPPM_RUUM_PROXY->ON_CHANGE
* +-------------------------------------------------------------------------------------------------+
* | [--->] SENDER                         TYPE REF TO IF_DPR_COMMON
* | [--->] CHANGEMODE                     TYPE        C
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD on_change.

    DATA:
      lr_common             TYPE REF TO if_dpr_common,
      lr_common_root        TYPE REF TO if_dpr_common,
      lr_common_parent      TYPE REF TO if_dpr_common,

      lv_object_type        TYPE cgpl_object_type,
      lr_native_object      TYPE REF TO object,
      ls_linkref            TYPE ty_instance,
      lv_object_is_relevant TYPE boole_d.

    TRY.
        lr_common ?= sender.
        lv_object_type lr_common->get_object_type).
      CATCH cx_dpr_object_composite_error.
        RETURN.
      CATCH cx_sy_move_cast_error.
        RETURN.
    ENDTRY.

    TRY.
        lr_native_object  sender->get_native_object).
      CATCH cx_dpr_object_composite_error.
        RETURN.
      CATCH cx_sy_move_cast_error.
        RETURN.
    ENDTRY.

    ls_linkref-obj_link_guid lr_common->get_guid).
    ls_linkref-root_guid     lr_common->get_root)->get_guid).
    ls_linkref-projectname   lr_common->get_root)->get_description).
    ls_linkref-mode          changemode.
    TRY.
        ls_linkref-task_guid     lr_common->get_parent)->get_guid).
        ls_linkref-taskname      lr_common->get_parent)->get_description).
      CATCH cx_sy_ref_is_initial.
        "
    ENDTRY.

    CASE lv_object_type.
      WHEN cl_dpr_co=>sc_ot_object_link.
        READ TABLE mt_linkref ASSIGNING FIELD-SYMBOL(<ls_linkref>WITH KEY obj_link_guid ls_linkref-obj_link_guid.
        IF sy-subrc 0.
          <ls_linkref>-common lr_common.
          <ls_linkref>-native_object lr_native_object.
          IF changemode 'D' AND <ls_linkref>-mode 'U'.
            <ls_linkref>-mode changemode.
          ELSEIF changemode 'C' AND <ls_linkref>-mode 'D'.
            <ls_linkref>-mode 'R'.
          ELSE.
            "keep original change mode.
          ENDIF.
        ELSE.
          ls_linkref-common lr_common.
          ls_linkref-native_object lr_native_object.
          INSERT ls_linkref INTO TABLE mt_linkref.
        ENDIF.
    ENDCASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->ON_DPR_COMMON_CHANGED
* +-------------------------------------------------------------------------------------------------+
* | [--->] SENDER                         LIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD on_dpr_common_changed.

    me->on_changesender sender changemode 'U' ).

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->ON_DPR_COMMON_CREATED
* +-------------------------------------------------------------------------------------------------+
* | [--->] SENDER                         LIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD on_dpr_common_created.
    me->on_changesender sender changemode 'C' ).
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->ON_DPR_COMMON_DELETED
* +-------------------------------------------------------------------------------------------------+
* | [--->] SENDER                         LIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD on_dpr_common_deleted.

    me->on_changesender sender changemode 'D' ).

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>QUERY_RUUM
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<---] EV_ERROR_STRING                TYPE        STRING
* | [<---] ET_QUERY_RESULT                TYPE        TT_QUERY_RUUM_RESULTS
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD query_ruum.

    DATA:
      lv_service_url TYPE string,
      lv_csrf_token  TYPE string,
      lv_timestamp   TYPE i,
      lt_result      TYPE TABLE OF zeppm_ruum.

    CLEAR ev_error_string.

    " Fresh results are read every second at most.
    GET RUN TIME FIELD lv_timestamp.
    IF lv_timestamp sv_query_timestamp 5000000 AND sv_query_timestamp IS NOT INITIAL )
    OR sv_query_timestamp IS INITIAL.

      " get client
      TRY.
          DATA(lo_http_clientlcl_rest_client=>get_client(
            EXPORTING
              iv_obl_type       iv_object_type
              iv_oauth2_profile mc_oauth2_profile
            IMPORTING
              ev_xsrf_token    lv_csrf_token
           ).
        CATCH lcx_rest_noauth lcx_rest_nocust INTO DATA(lx_oac_at).
          ev_error_string lx_oac_at->get_text).
          RETURN.
        CATCH lcx_oauth_grant_required INTO DATA(lx_oac_grant).
          ev_error_string lx_oac_grant->get_text).
          MESSAGE ID 'ZRUUM' TYPE 'E' NUMBER '001' WITH
            get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
            get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
            get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
            get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
            INTO ev_error_string.
          RETURN.
      ENDTRY.

      " get service url
      CALL METHOD cl_dpr_obl_repository=>get_object_capabilities
        EXPORTING
          iv_object_type iv_object_type
        IMPORTING
          es_obl_obtyp   DATA(ls_obtype)
        EXCEPTIONS
          OTHERS         0.

      cl_dpr_olr3_repository=>get_url_webserver_par(
         EXPORTING
           iv_web_server     =                  ls_obtype-web_server
         IMPORTING
           ev_web_server_url =                  DATA(lv_ws_url)
         EXCEPTIONS
           OTHERS            ).
      lv_service_url lv_ws_url.
      TRANSLATE lv_service_url TO LOWER CASE.

      "---------------------
      " New variant with OData V4 API
      "---------------------

      CONCATENATE lv_service_url 'OData/Reporting.svc/projects?$top=1000' INTO lv_service_url.

      " read data
      lo_http_client->request->set_methodif_http_request=>co_request_method_get ).
      lo_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri        value lv_service_url ).

      send_urllo_http_client ).

      lo_http_client->response->get_statusIMPORTING code DATA(lv_status_code).

      IF lv_status_code <> 200.
        ev_error_string lo_http_client->response->get_cdata).
        EXIT.
      ENDIF.

      DATA(lv_responselo_http_client->response->get_cdata).

      " parse data
      DATA(lt_ruum_jsonslcl_json_parser=>get_enumeration_from_jsonEXPORTING iv_json lv_response iv_property 'value' ).

      LOOP AT lt_ruum_jsons ASSIGNING FIELD-SYMBOL(<ls_ruum_json>).
        APPEND INITIAL LINE TO lt_result ASSIGNING FIELD-SYMBOL(<ls_result>).
        <ls_result>-ruumid          lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'projectId' ).
*        <ls_result>-workspaceid     = lcl_json_parser=>get_property_from_json( iv_json = <ls_ruum_json>  iv_property = 'workspaceId' ).
        <ls_result>-name        lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'name' ).
        DATA lv_str TYPE string.
        lv_str lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'createdAt' ).
        REPLACE ALL OCCURRENCES OF '-' IN lv_str WITH ''.
        <ls_result>-createdat lv_str.
        lv_str lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'changedAt' ).
        REPLACE ALL OCCURRENCES OF '-' IN lv_str WITH ''.
        <ls_result>-changedat lv_str.
        <ls_result>-status lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'status' ).
      ENDLOOP.

      GET RUN TIME FIELD sv_query_timestamp.
      st_query_ruum_result lt_result.
    ENDIF.

    et_query_result st_query_ruum_result.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>QUERY_RUUM_TASK_KPIS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<-->] CV_RUUM                        TYPE        ZEPPM_RUUM
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD query_ruum_task_kpis.

    DATA:
      lv_service_url TYPE string,
      lv_service     TYPE string,
      lv_csrf_token  TYPE string,
      lv_timestamp   TYPE i,
      lt_result      TYPE tt_query_ruum_tasks.

    IF st_query_ruum_task_custom IS INITIAL.
      get_ruum_tasksEXPORTING iv_object_type iv_object_type ).
    ENDIF.

    READ TABLE st_query_ruum_result ASSIGNING FIELD-SYMBOL(<ls_ruum>WITH KEY ruumid cv_ruum-ruumid.
    CHECK sy-subrc 0.

    LOOP AT st_query_ruum_task_custom ASSIGNING field-symbol(<ls_task>WHERE ruumid <ls_ruum>-ruumid.

      IF <ls_task>-finishdate IS NOT INITIAL AND <ls_task>-finishdate < sy-datum AND <ls_task>-status <> 'DONE'.
        ADD TO <ls_ruum>-tasks_overdue.
      ENDIF.
      IF <ls_task>-status <> 'DONE'.
        ADD TO <ls_ruum>-tasks_open.
      ENDIF.
      IF <ls_task>-status 'DONE'.
        ADD TO <ls_ruum>-tasks_completed.
      ENDIF.

    ENDLOOP.

    IF <ls_ruum>-tasks_completed AND <ls_ruum>-tasks_open 0.
      CLEAR <ls_ruum>-poc.
    ELSEIF <ls_ruum>-tasks_completed > AND <ls_ruum>-tasks_open 0.
      <ls_ruum>-poc 100.
    ELSE.
      DATA(lv_poc100 * <ls_ruum>-tasks_completed / <ls_ruum>-tasks_completed + <ls_ruum>-tasks_open ).
      <ls_ruum>-poc lv_poc.
    ENDIF.
    cv_ruum <ls_ruum>.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>SEND_URL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_HTTP_CLIENT                 TYPE REF TO IF_HTTP_CLIENT
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD send_url.

    DATA:
      lv_url      TYPE string,
      lv_host     TYPE string,
      lv_firsttry TYPE string,
      lv_retry    TYPE string.

    " No absolute path possible here: tweak necessary
    lv_url  io_http_client->request->get_header_field(  name  if_http_header_fields_sap=>request_uri ).
    lv_host io_http_client->request->get_header_field(  name  'host' ).
    IF lv_host IS NOT INITIAL AND lv_url CS lv_host.
      SPLIT lv_url AT lv_host INTO DATA(lv_dummylv_url.
      io_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri value lv_url ).
    ENDIF.

    io_http_client->send).
    io_http_client->receiveEXCEPTIONS http_communication_failure ).
    io_http_client->response->get_statusIMPORTING code DATA(lv_status_code).

    "If Ruum is a bit under the weather or assumes a DoS attack falsely, just re-try.
    IF lv_status_code 500.
      io_http_client->send).
      io_http_client->receiveEXCEPTIONS http_communication_failure ).
      io_http_client->response->get_statusIMPORTING code lv_status_code ).
    ENDIF.

    IF lv_status_code 401 OR lv_status_code 403 OR lv_status_code 404.
      DATA(lv_responseio_http_client->response->get_cdata).
      " We're obviously not successful. If it's an expired token: try to trigger the refresh flow
      IF lcl_rest_client=>refresh_successfulabap_true.
        io_http_client->send).
        io_http_client->receiveEXCEPTIONS http_communication_failure ).
      ENDIF.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>STRING_CUT_TRAILING_SPACES
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_STRING                      TYPE        STRING
* | [<-()] RV_STRING                      TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD string_cut_trailing_spaces.

    "---------------------------------------------------------------------------------------------------
    " Makes sure that a filter string doesn't contain any trailing spaces without losing leading spaces
    "---------------------------------------------------------------------------------------------------

    DATAlv_pos          TYPE VALUE 0,
          lv_char255(255TYPE c,
          lv_space        TYPE VALUE ' '.

    CHECK iv_string IS NOT INITIAL.

    rv_string lv_char255 iv_string.
    " count leading spaces
    DO.
      IF lv_char255+lv_pos(1lv_space.
        ADD TO lv_pos.
        IF lv_pos 255.
          EXIT.
        ENDIF.
      ELSE.
        EXIT.
      ENDIF.
    ENDDO.

    " Remove all spacs
    SHIFT rv_string RIGHT DELETING TRAILING space.
    SHIFT rv_string LEFT DELETING LEADING space.
    " Restore leading spaces
    SHIFT rv_string RIGHT BY lv_pos PLACES.

  ENDMETHOD.
ENDCLASS.
CLASS zcl_eppm_ruum_proxy DEFINITION
   PUBLIC
   FINAL
   CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES if_dpr_obl_proxy .
    INTERFACES if_dpr_obl_proxy_url .
    INTERFACES if_dpr_appl_bootstrap_member .
    INTERFACES if_dpr_appl_plug_in_subsystem .

    TYPES:
      tt_query_ruum_results TYPE STANDARD TABLE OF zeppm_ruum .

    METHODS constructor .
    CLASS-METHODS create_ruum
      IMPORTING
        !iv_object_type  TYPE dpr_tv_obl_type
        !iv_external_id  TYPE string
      EXPORTING
        !ev_system_error TYPE string
        !ev_ruumid       TYPE string .
    METHODS on_dpr_common_changed
          FOR EVENT changed OF if_dpr_common
      IMPORTING
          !sender .
    METHODS on_dpr_common_created
          FOR EVENT created OF if_dpr_common
      IMPORTING
          !sender .
    METHODS on_dpr_common_deleted
          FOR EVENT deleted OF if_dpr_common
      IMPORTING
          !sender .
    CLASS-METHODS query_ruum_task_kpis
      IMPORTING
        !iv_object_type TYPE dpr_tv_obl_type
      CHANGING
        !cv_ruum        TYPE zeppm_ruum .
    CLASS-METHODS query_ruum
      IMPORTING
        !iv_object_type  TYPE dpr_tv_obl_type
      EXPORTING
        !ev_error_string TYPE string
        !et_query_result TYPE tt_query_ruum_results .
  PROTECTED SECTION.

    METHODS on_change
      IMPORTING
        !sender     TYPE REF TO if_dpr_common
        !changemode TYPE .
  PRIVATE SECTION.

    TYPES:
      BEGIN OF ty_query_ruum_tasks,
        ruumid           TYPE zeppm_ruum_id,
        taskid           TYPE string,
        startdate_year   TYPE string,
        startdate_month  TYPE string,
        startdate_day    TYPE string,
        startdate        TYPE sydatum,
        finishdate_year  TYPE string,
        finishdate_month TYPE string,
        finishdate_day   TYPE string,
        finishdate       TYPE sydatum,
        status           TYPE string,
      END OF ty_query_ruum_tasks .
    TYPES:
      tt_query_ruum_tasks TYPE TABLE OF ty_query_ruum_tasks .
    types:
      BEGIN OF ty_query_ruum_task_custom,
          ruumid     TYPE zeppm_ruum_id,
          taskid     TYPE string,
          parentId   TYPE string,
          sectionId  TYPE zeppm_ruum_id,
          order      type string,
          " sectionOrder type string,
          startdate  TYPE sydatum,
          finishdate TYPE sydatum,
          status     TYPE string,
          name       TYPE string,
          effort     TYPE string,
          remaining  TYPE string,
          completion TYPE string,
        END OF ty_query_ruum_task_custom .
    types:
      tt_query_ruum_task_custom TYPE STANDARD TABLE OF ty_query_ruum_task_custom .
    TYPES:
      BEGIN OF ty_instance,
        obj_link_guid TYPE dpr_tv_guid,
        root_guid     TYPE dpr_tv_guid,
        task_guid     TYPE dpr_tv_guid,
        common        TYPE REF TO if_dpr_common,
        native_object TYPE REF TO object,
        project_id    TYPE dpr_tv_project_id,
        projectname   TYPE cgpl_text1,
        task_id       TYPE dpr_tv_task_id,
        taskname      TYPE cgpl_text1,
        mode(1)       TYPE c,
      END OF ty_instance .
    TYPES:
      tt_instance TYPE SORTED TABLE OF ty_instance WITH UNIQUE KEY obj_link_guid .

    CLASS-DATA sv_query_timestamp TYPE .
    CLASS-DATA st_query_ruum_result TYPE tt_query_ruum_results .
    CLASS-DATA mt_linkref TYPE tt_instance .
    class-data ST_QUERY_RUUM_TASK_CUSTOM type TT_QUERY_RUUM_TASK_CUSTOM .
    CLASS-DATA mr_instance TYPE REF TO if_dpr_appl_plug_in_subsystem .
    CONSTANTS mc_oauth2_profile TYPE oa2c_profile VALUE 'ZSAP_RUUM'.

    class-methods GET_RUUM_TASKS
      importing
        !IV_OBJECT_TYPE type DPR_TV_OBL_TYPE .
    CLASS-METHODS get_service_url
      IMPORTING
        !iv_object_type       TYPE dpr_tv_obl_type
      RETURNING
        VALUE(rv_service_urlTYPE string .
    CLASS-METHODS get_service_url_parameter
      IMPORTING
        !iv_object_type               TYPE dpr_tv_obl_type
        VALUE(iv_url_parameter)       TYPE olr3_tv_pname
      RETURNING
        VALUE(rv_url_parameter_valueTYPE string .
    CLASS-METHODS get_user_email
      RETURNING
        VALUE(rv_mailaddressTYPE string .
    CLASS-METHODS has_link
      IMPORTING
        !iv_object_key     TYPE string
        !iv_object_type    TYPE dpr_tv_obl_type
      RETURNING
        VALUE(rv_has_linkTYPE abap_bool .
    CLASS-METHODS get_string_fragment
      IMPORTING
        !iv_part         TYPE i
        !iv_string       TYPE string
      RETURNING
        VALUE(rv_stringTYPE string .
    CLASS-METHODS string_cut_trailing_spaces
      IMPORTING
        !iv_string       TYPE string
      RETURNING
        VALUE(rv_stringTYPE string .
    CLASS-METHODS send_url
      IMPORTING
        !io_http_client TYPE REF TO if_http_client .
ENDCLASS.



CLASS ZCL_EPPM_RUUM_PROXY IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD constructor.

    SET HANDLER on_dpr_common_changed FOR ALL INSTANCES.
    SET HANDLER on_dpr_common_created FOR ALL INSTANCES.
    SET HANDLER on_dpr_common_deleted FOR ALL INSTANCES.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>CREATE_RUUM
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_EXTERNAL_ID                 TYPE        STRING
* | [<---] EV_SYSTEM_ERROR                TYPE        STRING
* | [<---] EV_RUUMID                      TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD create_ruum.

    DATA:
      lv_service_url TYPE string,
      lv_csrf_token  TYPE string,
      lv_timestamp   TYPE i,
      lv_body        TYPE string,
      lt_result      TYPE TABLE OF zeppm_ruum.

    TRY.
        DATA(lo_http_clientlcl_rest_client=>get_client(
          EXPORTING
            iv_obl_type       iv_object_type
            iv_oauth2_profile mc_oauth2_profile
          IMPORTING
            ev_xsrf_token    lv_csrf_token
         ).
      CATCH lcx_rest_nocust INTO DATA(lx_odata_client).
        ev_system_error lx_odata_client->get_text).
        RETURN.
      CATCH lcx_oauth_grant_required INTO DATA(lx_oac_grant).
        ev_system_error lx_oac_grant->get_text).
        MESSAGE ID 'ZRUUM' TYPE 'E' NUMBER '001' WITH
          get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
          get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
          get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
          get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
          INTO ev_system_error.
        RETURN.
    ENDTRY.

    " prepare service url
    lv_service_url get_service_urliv_object_type ).
    " switch to new API
    " CONCATENATE lv_service_url 'ruums' INTO lv_service_url.
    CONCATENATE lv_service_url 'OData/Ruum.svc/CreateProjectWithParameters' INTO lv_service_url.

    "lv_body = '{' && cl_abap_char_utilities=>cr_lf &&
    "          '"name": "' && string_cut_trailing_spaces( iv_external_id ) && '",' && cl_abap_char_utilities=>cr_lf &&
    "          '"fromTemplateId": "' && get_service_url_parameter( iv_object_type = iv_object_type iv_url_parameter = 'ZTEMPLATE' ) && '",' && cl_abap_char_utilities=>cr_lf &&
    "          '"participants": [' && cl_abap_char_utilities=>cr_lf &&
    "          '"  ' && get_user_email( ) && '"' && cl_abap_char_utilities=>cr_lf &&
    "          '],' && cl_abap_char_utilities=>cr_lf &&
    "          '"variables": [{' && cl_abap_char_utilities=>cr_lf &&
    "          '  "id": "EPPM Project",' && cl_abap_char_utilities=>cr_lf &&
    "          '  "dataType": "URL",' && cl_abap_char_utilities=>cr_lf &&
    "          '  "value": "https://vhcals4hci.dummy.nodomain:50001/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html#EnterpriseProject-showOverviewPage"' && cl_abap_char_utilities=>cr_lf &&
    "          '}] }' && cl_abap_char_utilities=>cr_lf.

    lv_body '{' && cl_abap_char_utilities=>cr_lf &&
              '  "templateId": "' && get_service_url_parameteriv_object_type iv_object_type iv_url_parameter 'ZTEMPLATE' && '",' && cl_abap_char_utilities=>cr_lf &&
              '  "ignoreTaskDates": false,' && cl_abap_char_utilities=>cr_lf &&
              '  "relativeStartDate": "' && sy-datlo(4&& '-' && sy-datlo+4(2&& '-' && sy-datlo+6(2&& '",' && cl_abap_char_utilities=>cr_lf &&
              '  "project": {'  && cl_abap_char_utilities=>cr_lf &&
              '    "name": "' && string_cut_trailing_spacesiv_external_id && '",' && cl_abap_char_utilities=>cr_lf &&
              '    "participants": [' && cl_abap_char_utilities=>cr_lf &&
              '      {' && cl_abap_char_utilities=>cr_lf &&
              '        "email": "' && get_user_email&& '"' && cl_abap_char_utilities=>cr_lf &&
              '      }' && cl_abap_char_utilities=>cr_lf.
    if get_service_url_parameteriv_object_type iv_object_type iv_url_parameter 'ZWORKSPACE'is initial.
      lv_body lv_body &&
              '    ]' && cl_abap_char_utilities=>cr_lf.
    else.
      lv_body lv_body &&
              '    ],' && cl_abap_char_utilities=>cr_lf &&
              '    "workspaceId": "' && get_service_url_parameteriv_object_type iv_object_type iv_url_parameter 'ZWORKSPACE' && '"' && cl_abap_char_utilities=>cr_lf &&
              '  }' && cl_abap_char_utilities=>cr_lf.
    endif.
    lv_body lv_body &&
              '}' && cl_abap_char_utilities=>cr_lf.

    DATA lv_body_xstr TYPE xstring.
    CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
      EXPORTING
        text   lv_body
      IMPORTING
        buffer lv_body_xstr.

    " read data
    lo_http_client->request->set_methodif_http_request=>co_request_method_post ).
    lo_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri        value lv_service_url ).
    lo_http_client->request->set_content_typecontent_type 'application/json' ).
    lo_http_client->request->set_datalv_body_xstr ).
    send_urllo_http_client ).
    lo_http_client->response->get_statusIMPORTING code DATA(lv_status_code).

    IF lv_status_code <> 200.
      ev_system_error lo_http_client->response->get_cdata).
      EXIT.
    ENDIF.

    "make sure that buffer is invalidated - we simply do this by clearing the timestamp of last read access
    CLEAR sv_query_timestamp.
    "set return data
    ev_ruumid lcl_json_parser=>get_property_from_jsoniv_json lo_http_client->response->get_cdataiv_property 'projectId' ).

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_RUUM_TASKS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD GET_RUUM_TASKS.

    DATA:
      lv_service_url TYPE string,
      lv_service     TYPE string,
      lv_csrf_token  TYPE string,
      lv_timestamp   TYPE i,
      lt_result      TYPE tt_query_ruum_tasks.

    " get client
    TRY.
        DATA(lo_http_clientlcl_rest_client=>get_client(
          EXPORTING
            iv_obl_type       iv_object_type
            iv_oauth2_profile mc_oauth2_profile
          IMPORTING
            ev_xsrf_token    lv_csrf_token
         ).
      CATCH lcx_rest.
        " Silent exit. All relevant errors will have been sent already
        RETURN.
    ENDTRY.

    " get service url
    CALL METHOD cl_dpr_obl_repository=>get_object_capabilities
      EXPORTING
        iv_object_type iv_object_type
      IMPORTING
        es_obl_obtyp   DATA(ls_obtype)
      EXCEPTIONS
        OTHERS         0.

    cl_dpr_olr3_repository=>get_url_webserver_par(
       EXPORTING
         iv_web_server     =                  ls_obtype-web_server
       IMPORTING
         ev_web_server_url =                  DATA(lv_ws_url)
       EXCEPTIONS
         OTHERS            ).
    lv_service lv_ws_url.
    TRANSLATE lv_service TO LOWER CASE.

    DO TIMES.

      IF sy-index 1.
        CONCATENATE lv_service 'OData/Reporting.svc/Tasks?$top=1000' INTO lv_service_url.
      ELSE.
        CONCATENATE lv_service 'OData/Reporting.svc/Tasks?$skip=1000&$top=1000' INTO lv_service_url.
      ENDIF.


      " read data
      lo_http_client->request->set_methodif_http_request=>co_request_method_get ).
      lo_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri        value lv_service_url ).

      send_urllo_http_client ).

      lo_http_client->response->get_statusIMPORTING code DATA(lv_status_code).

      DATA(lv_responselo_http_client->response->get_cdata).

      " parse data
      DATA(lt_ruum_jsonslcl_json_parser=>get_enumeration_from_jsonEXPORTING iv_json lv_response iv_property 'value' ).

      LOOP AT lt_ruum_jsons ASSIGNING FIELD-SYMBOL(<ls_ruum_json>).
        APPEND INITIAL LINE TO st_query_ruum_task_custom ASSIGNING FIELD-SYMBOL(<ls_task>).
        <ls_task>-ruumid lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'projectId' ).
        <ls_task>-sectionid lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'sectionId' ).
        <ls_task>-status lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'status' ).
        DATA lv_date TYPE string.
        lv_date lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'startDate' ).
        REPLACE ALL OCCURRENCES OF '-' IN lv_date WITH ''.
        IF lv_date <> 'null'.
          <ls_task>-startdate lv_date.
        ENDIF.
        lv_date lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'dueDate' ).
        REPLACE ALL OCCURRENCES OF '-' IN lv_date WITH ''.
        IF lv_date <> 'null'.
          <ls_task>-finishdate lv_date.
        ENDIF.
        <ls_task>-taskid     lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json> iv_property 'taskId' ).
        <ls_task>-parentid   lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json> iv_property 'parentId' ).
        <ls_task>-order      lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json> iv_property 'order' ).
        <ls_task>-name       lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json> iv_property 'description' ).

        " If you use workspaces to maintain custom fields: Here some examples how toread them into the internal tables :)

        " <ls_task>-effort     = lcl_json_parser=>get_property_from_json( iv_json = <ls_ruum_json> iv_property = 'custom_field_1580*********_r*******' ).
        " IF <ls_task>-effort = 'null'.
        "   <ls_task>-effort = '0'.
        " ENDIF.
        " <ls_task>-remaining  = lcl_json_parser=>get_property_from_json( iv_json = <ls_ruum_json> iv_property = 'custom_field_1580*********_w*******' ).
        " IF <ls_task>-remaining = 'null'.
        "   <ls_task>-remaining = '0'.
        " ENDIF.
        " <ls_task>-completion = lcl_json_parser=>get_property_from_json( iv_json = <ls_ruum_json> iv_property = 'custom_field_1581*********_s*******' ).
        " IF <ls_task>-completion = 'null'.
        "   <ls_task>-completion = '0'.
        " ENDIF.

      ENDLOOP.

    ENDDO.

    SORT st_query_ruum_task_custom BY ruumid.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_SERVICE_URL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<-()] RV_SERVICE_URL                 TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_service_url.

    " get service url
    CALL METHOD cl_dpr_obl_repository=>get_object_capabilities
      EXPORTING
        iv_object_type iv_object_type
      IMPORTING
        es_obl_obtyp   DATA(ls_obtype)
      EXCEPTIONS
        OTHERS         0.

    cl_dpr_olr3_repository=>get_url_webserver_par(
       EXPORTING
         iv_web_server     =                  ls_obtype-web_server
       IMPORTING
         ev_web_server_url =                  DATA(lv_ws_url)
       EXCEPTIONS
         OTHERS            ).
    rv_service_url lv_ws_url.
    TRANSLATE rv_service_url TO LOWER CASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_SERVICE_URL_PARAMETER
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_URL_PARAMETER               TYPE        OLR3_TV_PNAME
* | [<-()] RV_URL_PARAMETER_VALUE         TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_service_url_parameter.

    " get service url
    CALL METHOD cl_dpr_obl_repository=>get_object_capabilities
      EXPORTING
        iv_object_type iv_object_type
      IMPORTING
        es_obl_obtyp   DATA(ls_obtype)
      EXCEPTIONS
        OTHERS         0.

    cl_dpr_olr3_repository=>get_url_webserver_par(
       EXPORTING
         iv_web_server     =                  ls_obtype-web_server
       IMPORTING
         et_parameter      DATA(lt_parameter)
       EXCEPTIONS
         OTHERS            ).

    READ TABLE lt_parameter ASSIGNING FIELD-SYMBOL(<ls_parameter>WITH KEY name iv_url_parameter.
    IF sy-subrc 0.
      rv_url_parameter_value <ls_parameter>-value.
    ENDIF.

    TRANSLATE rv_url_parameter_value TO LOWER CASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_STRING_FRAGMENT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_PART                        TYPE        I
* | [--->] IV_STRING                      TYPE        STRING
* | [<-()] RV_STRING                      TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_string_fragment.

    DATA:
      lv_tmp(50TYPE c,
      lv_len     TYPE i.

    lv_len strleniv_string ).

    CASE iv_part.
      WHEN 1.
        rv_string iv_string.
      WHEN 2.
        IF lv_len > 50.
          rv_string iv_string+50.
        ENDIF.
      WHEN 3.
        IF lv_len > 100.
          rv_string iv_string+100.
        ENDIF.
      WHEN 4.
        IF lv_len > 150.
          rv_string iv_string+150.
        ENDIF.
    ENDCASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>GET_USER_EMAIL
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_MAILADDRESS                 TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_user_email.

    DATA:
      lv_persnumber TYPE ad_persnum,
      lv_addrnumber TYPE ad_addrnum,
      lt_adsmtp     TYPE TABLE OF adsmtp.

    rv_mailaddress sy-uname && '@ruumapp.com'.
    TRANSLATE rv_mailaddress TO LOWER CASE.

    CALL FUNCTION 'SUSR_USER_ADDRESSKEY_GET'
      EXPORTING
        bname             sy-uname
      IMPORTING
        persnumber        lv_persnumber
        addrnumber        lv_addrnumber
      EXCEPTIONS
        address_not_found 1
        OTHERS            2.
    CHECK sy-subrc IS INITIAL.

    " Get address details
    CALL FUNCTION 'ADDR_PERS_COMP_COMM_GET'
      EXPORTING
        address_number    lv_addrnumber
        person_number     lv_persnumber
        table_type        'ADSMTP'
      TABLES
        comm_table        lt_adsmtp
      EXCEPTIONS
        parameter_error   1
        address_not_exist 2
        person_not_exist  3
        internal_error    4
        OTHERS            5.
    CHECK sy-subrc IS INITIAL.

    READ TABLE lt_adsmtp ASSIGNING FIELD-SYMBOL(<ls_adsmtp>WITH KEY flgdefault abap_true.
    IF sy-subrc IS INITIAL.
      rv_mailaddress <ls_adsmtp>-smtp_addr.
    ENDIF.
    TRANSLATE rv_mailaddress TO LOWER CASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>HAS_LINK
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_KEY                  TYPE        STRING
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<-()] RV_HAS_LINK                    TYPE        ABAP_BOOL
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD has_link.

    query_ruum(
      EXPORTING
        iv_object_type  iv_object_type
      IMPORTING
        et_query_result DATA(lt_result)  ).

    READ TABLE lt_result TRANSPORTING NO FIELDS WITH KEY ruumid iv_object_key.
    IF sy-subrc IS INITIAL.
      rv_has_link abap_true.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_APPL_BOOTSTRAP_MEMBER~GET_SEQUENCE_PLACE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_SEQUENCE_PLACE              TYPE        I
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_bootstrap_member~get_sequence_place.
    rv_sequence_place -1.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_APPL_BOOTSTRAP_MEMBER~LOAD
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_bootstrap_member~load.
    RETURN.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~FREE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~free.

    SET HANDLER on_dpr_common_changed        FOR ALL INSTANCES ACTIVATION cl_dpr_co=>sc_false.
    SET HANDLER on_dpr_common_created        FOR ALL INSTANCES ACTIVATION cl_dpr_co=>sc_false.
    SET HANDLER on_dpr_common_deleted        FOR ALL INSTANCES ACTIVATION cl_dpr_co=>sc_false.

    CLEARmt_linkref.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_APPL_PLUG_IN_SUBSYSTEM~GET_INSTANCE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RR_INSTANCE                    TYPE REF TO IF_DPR_APPL_PLUG_IN_SUBSYSTEM
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~get_instance.

    IF mr_instance IS INITIAL.

      CREATE OBJECT mr_instance TYPE zcl_eppm_ruum_proxy.

    ENDIF.

    rr_instance mr_instance.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~HAS_CHANGES
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_HAS_CHANGES                 TYPE        BOOLE_D
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~has_changes.

    DESCRIBE TABLE mt_linkref.
    IF sy-tfill > 0.
      rv_has_changes abap_true.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~INITIALIZE_AFTER_SAVE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~initialize_after_save.

    CLEAR:
      mt_linkref,
      sv_query_timestamp,
      st_query_ruum_result.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~PREPARE_TO_SAVE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_RC                          TYPE        I
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~prepare_to_save.
    rv_rc 0.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->IF_DPR_APPL_PLUG_IN_SUBSYSTEM~SAVE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_RC                          TYPE        I
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_appl_plug_in_subsystem~save.

    DATA:
      lr_objectlink   TYPE REF TO cl_dpr_obl_assignment,
      lo_http_client  TYPE REF TO if_http_client,
      lv_csrf_token   TYPE string,
      ls_oblink_data  TYPE dpr_objlink,
      lv_body         TYPE string,
      lv_service_url  TYPE string,
      lv_guid_as_char TYPE string,
      lv_path         TYPE string,
      lv_what_i_am    TYPE string VALUE 'PPM 6.1 or similar'.

    IF mt_linkref IS NOT INITIAL.

      LOOP AT mt_linkref ASSIGNING FIELD-SYMBOL(<ls_linkref>WHERE mode CA 'CD'.

        " Get object link attributes
        TRY.
            lr_objectlink ?= <ls_linkref>-native_object.
          CATCH cx_sy_move_cast_error.
            " Not an object link: Shame on you but I won't tell anybody if you don't
            CONTINUE.
        ENDTRY.
        lr_objectlink->get_attributesIMPORTING es_attributes ls_oblink_data ).

        " Ruum links only
        IF NOT ls_oblink_data-object_type CS 'RUUM'.
          CONTINUE.
        ENDIF.

        TRY.
            lo_http_client lcl_rest_client=>get_client(
              EXPORTING
                iv_obl_type       ls_oblink_data-object_type
                iv_oauth2_profile mc_oauth2_profile
              IMPORTING
                ev_xsrf_token    lv_csrf_token
             ).
          CATCH lcx_rest.
            " If something goes wrong here, it went wrong earlier. We don't have to react on this again.
            CONTINUE.
        ENDTRY.

        lv_service_url get_service_urlls_oblink_data-object_type ).
        " We only do ruum updates here. As we don't know which object link to take, we check the url
        IF NOT lv_service_url CS 'api.ruumapp.com'.
          CONTINUE.
        ENDIF.

        " Create Service URL here
        CONCATENATE lv_service_url 'OData/Ruum.svc/Projects(''' ls_oblink_data-object_key ''')/customFields' INTO lv_service_url.

        " get client and set it up
        lo_http_client lcl_rest_client=>get_clientls_oblink_data-object_type ).

        CASE <ls_linkref>-mode.
            " Create mode: add new remote link to ruum
          WHEN 'C'.
            lo_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri  value lv_service_url ).
            lo_http_client->request->set_header_fieldname  if_http_header_fields=>content_type value 'application/json' ).
            lo_http_client->request->set_method'PATCH' ).
            DATA lv_self TYPE string.
            TRY.
                cl_gdt_conversion=>guid_outboundEXPORTING im_guid_x ls_oblink_data-project_guid IMPORTING ex_value  lv_self ).
              CATCH cx_gdt_conversion" Error During Global Data Types Conversion
            ENDTRY.
            DATA lv_projectref TYPE string.
            IF <ls_linkref>-taskname IS NOT INITIAL AND <ls_linkref>-taskname <> <ls_linkref>-projectname.
              lv_projectref <ls_linkref>-projectname && ' - ' && <ls_linkref>-taskname.
            ELSE.
              lv_projectref <ls_linkref>-projectname.
            ENDIF.

            DATAlv_localurl  TYPE string,  lv_localport TYPE string.
            CALL FUNCTION 'TH_GET_VIRT_HOST_DATA'
              EXPORTING
                protocol       2
                virt_idx       0
              IMPORTING
                hostname       lv_localurl
                port           lv_localport
              EXCEPTIONS
                not_found      1
                internal_error 2
                OTHERS         3.
            IF sy-subrc <> 0.
              CONTINUE.
            ENDIF.

            CASE lv_what_i_am.
              WHEN 'SolutionManager'.
                "---------------------------------------------------------------------------------
                " use this link format when using this code for a Solution Manager based scenario
                "---------------------------------------------------------------------------------
                lv_self 'https://' && lv_localurl && ':' && lv_localport
                       && '/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html#Action-projectManagementPMO&/detail/'
                       && to_upperlv_self ).
              WHEN 'S/4HANA CE'.
                lv_self 'https://' && lv_localurl && ':' && lv_localport
                       && '/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html#EnterpriseProject-showProjectBrief&//C_PPM_ProjectBriefTP(ProjectUUID=guid'''
                       && lv_self
                       && ''',IsActiveEntity=true)'.
              WHEN 'PPM 6.1 or similar'.
                "---------------------------------------------------------------------------------
                " Link format for connecting with WD ABAP based PPM 6.1-like UI
                "---------------------------------------------------------------------------------
                lv_self ls_oblink_data-project_guid.
                lv_self 'https://' && lv_localurl && ':' && lv_localport
                       && '/nwbc/~canvas;window=app/wda/cprojects_fpm/?sap-client='
                       && sy-mandt
                       &&'&STARTVIEW=Projects&OBJ_EVENT=DPO'
                       && lv_self
                       && lv_self
                       && 'DPO&DetailView=DPO&sap-wd-configid=CPROJECTS_FPM&EDITMODE=display&sap-language=EN'.
            ENDCASE.

            " To store a back reference to the S/4HANA Project, you need to introduce a custom
            " for your workspace. Here you can then hardcode the techncal custom field definition
            " by replacing the field name 'custom_field_123123123123' in the code by the real value.
            lv_body '{' && cl_abap_char_utilities=>cr_lf
                   && '   "custom_field_123123123123": "' && lv_self && '"' && cl_abap_char_utilities=>cr_lf
                   && '}'.
            DATA lv_body_xstr TYPE xstring.
            CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
              EXPORTING
                text   lv_body
              IMPORTING
                buffer lv_body_xstr.

            " To get the link maintainmed in a custom field, un-coment the next four lines:
            " lo_http_client->request->set_data( lv_body_xstr ).
            " send_url( lo_http_client ).
            " lo_http_client->response->get_status( IMPORTING code = DATA(lv_status_code) ).
            " DATA(lv_result) = lo_http_client->response->get_cdata( ).

          WHEN 'D'.
            " No deletion yet. Is it possible to delete a variable here?
        ENDCASE.
      ENDLOOP.

    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY_URL~GET_APPLICATION_URLS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_SERVICE                     TYPE        OLR3_TV_SERVICE(optional)
* | [--->] IV_OBJECT_KEY                  TYPE        STRING(optional)
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_EXTERNAL_KEY                TYPE        OLR3_TV_STRING(optional)
* | [<---] ET_APPLICATION_URL             TYPE        OLR3_TT_URL
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy_url~get_application_urls.

    DATAls_odata TYPE olr3_ts_url,
          ls_ui    TYPE olr3_ts_url.

    CLEAR et_application_url.

    " get all services
    cl_dpr_olr3_repository=>get_url_def(
      EXPORTING
        iv_object_type =  iv_object_type
       IMPORTING
         et_services    DATA(lt_services)
      EXCEPTIONS
        OTHERS         ).
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    " get url service
    LOOP AT lt_services ASSIGNING FIELD-SYMBOL(<ls_services>).

      cl_dpr_olr3_repository=>get_url_webserver_par(
        EXPORTING
          iv_web_server     =                  <ls_services>-web_server
        IMPORTING
          ev_web_server_url =                  DATA(lv_url)
          et_parameter      =                  DATA(lt_parameter)
        EXCEPTIONS
          OTHERS            ).

      " Get text
      cl_dpr_olr3_repository=>get_url_service(
        EXPORTING
          iv_service   =                  <ls_services>-service
        IMPORTING
          ev_text      =                  DATA(lv_service_text)  ).

      APPEND INITIAL LINE TO et_application_url ASSIGNING FIELD-SYMBOL(<ls_application_url>).
      <ls_application_url>-service_url lv_url.
      <ls_application_url>-pos <ls_services>-pos.
      <ls_application_url>-description lv_service_text.
      <ls_application_url>-tcode <ls_services>-service.

    ENDLOOP.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY~CHECK_EXISTENCE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<---] EV_DESCRIPTION                 TYPE        STRING
* | [<---] EV_SYSTEM_ERROR                TYPE        STRING
* | [<-->] CV_EXTERNAL_ID                 TYPE        STRING
* | [<-->] CV_OBJECT_KEY                  TYPE        STRING
* | [EXC!] NOT_FOUND
* | [EXC!] NOT_ACCESSIBLE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy~check_existence.

    DATA:
      ltr_name  TYPE RANGE OF zeppm_ruum_name.

    query_ruum(
      EXPORTING
        iv_object_type  iv_object_type
      IMPORTING
        ev_error_string ev_system_error
        et_query_result DATA(lt_result)  ).

    CHECK ev_system_error IS INITIAL.

    IF cv_object_key IS NOT INITIAL.
      READ TABLE lt_result ASSIGNING FIELD-SYMBOL(<ls_result>WITH KEY ruumid cv_object_key.
      IF sy-subrc IS NOT INITIAL.
        RAISE not_accessible.
      ELSE.
        cv_external_id ev_description <ls_result>-name.
      ENDIF.
    ELSE.
      READ TABLE lt_result ASSIGNING <ls_result> WITH KEY name cv_external_id.
      IF sy-subrc IS NOT INITIAL.
        create_ruum(
          EXPORTING
            iv_object_type iv_object_type iv_external_id cv_external_id
          IMPORTING
            ev_system_error ev_system_error
            ev_ruumid       cv_object_key  ).
        IF ev_system_error IS NOT INITIAL.
          RAISE not_found.
        ENDIF.
        ev_description cv_external_id.
      ELSE.
        cv_object_key <ls_result>-ruumid.
        ev_description cv_external_id.
      ENDIF.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY~GET_APPLICATION_URL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_KEY                  TYPE        STRING
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<---] EV_APPLICATION_URL             TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy~get_application_url.

    DATA  lv_ui_endpoint      TYPE string.
    DATAlt_url              TYPE olr3_tt_url.

    CLEAR ev_application_url.

    CHECK iv_object_key > ' '.

    CHECK has_linkiv_object_key iv_object_key iv_object_type iv_object_type abap_true.

** get IPD endpoint (= URL base) for UI
    CALL METHOD if_dpr_obl_proxy_url~get_application_urls
      EXPORTING
        iv_object_key      iv_object_key
        iv_object_type     iv_object_type
      IMPORTING
        et_application_url lt_url.

    READ TABLE lt_url ASSIGNING FIELD-SYMBOL(<ls_url>WITH KEY tcode 'ZRUUM_FO'.
    IF NOT <ls_url> IS ASSIGNED.
      RETURN.
    ENDIF.

    lv_ui_endpoint <ls_url>-service_url.
    TRANSLATE lv_ui_endpoint TO LOWER CASE.

    " add ruum id
    IF NOT iv_object_key IS INITIAL.
      CONCATENATE lv_ui_endpoint iv_object_key INTO ev_application_url.
    ENDIF.   " IF iv_object_key IS INITIAL.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY~GET_DATA
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_KEY                  TYPE        STRING
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_CONTEXT                     TYPE        STRING(optional)
* | [<---] EV_OBJECT_DATA                 TYPE        XSTRING
* | [<---] EV_SYSTEM_ERROR                TYPE        STRING
* | [EXC!] NOT_FOUND
* | [EXC!] NOT_ACCESSIBLE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy~get_data.

    DATA:
      lt_data      TYPE olr3_tt_tab_data,
      lt_dfies_tab TYPE TABLE OF dfies,
      lt_xmltab    TYPE olr3_tt_xmlattrib,
      lv_tabname   TYPE olr3_tv_ddic_table.
    FIELD-SYMBOLS:
      <lv_content>       TYPE any.

    " Get ruum data
    query_ruum(
       EXPORTING
         iv_object_type iv_object_type
       IMPORTING
        ev_error_string ev_system_error
        et_query_result =  DATA(lt_result).
    IF ev_system_error IS NOT INITIAL.
      RETURN.
    ENDIF.

    READ TABLE lt_result ASSIGNING FIELD-SYMBOL(<ls_result>WITH KEY ruumid iv_object_key.
    IF sy-subrc IS NOT INITIAL.
      RAISE not_accessible.
    ENDIF.

    " Enhance ruum data with kpi like characteristics from existing tasks
    query_ruum_task_kpisEXPORTING iv_object_type iv_object_type CHANGING cv_ruum <ls_result> ).

    " We need the table definition to dynamically define the structure to receive data
    CALL METHOD cl_dpr_olr3_repository=>get_tabledef
      EXPORTING
        iv_object_type    iv_object_type
        iv_method         '04'
      IMPORTING
        ev_table_viewname lv_tabname
      EXCEPTIONS
        not_found         1.
    IF sy-subrc IS NOT INITIAL.
      CONCATENATE iv_object_key TEXT-004 INTO ev_system_error.
      RETURN.
    ENDIF.

    " Get the field names that are required
    CALL METHOD cl_dpr_olr3_repository=>get_fields
      EXPORTING
        iv_object_type iv_object_type
      IMPORTING
        et_data        lt_data
      EXCEPTIONS
        not_found      1.
    IF sy-subrc IS NOT INITIAL.
      " No fields defined as well: no XML string is possible
      CLEAR ev_object_data.
      EXIT.
    ENDIF.

    " Get labels via DDIC
    CALL FUNCTION 'DDIF_FIELDINFO_GET'
      EXPORTING
        tabname   lv_tabname
      TABLES
        dfies_tab lt_dfies_tab
      EXCEPTIONS
        OTHERS    1.
    IF sy-subrc IS NOT INITIAL.
      CONCATENATE iv_object_key TEXT-004 INTO ev_system_error SEPARATED BY space.
      RETURN.
    ENDIF.
    SORT lt_dfies_tab BY fieldname ASCENDING.

    " Prepare result for XML transformation
    LOOP AT lt_data ASSIGNING FIELD-SYMBOL(<ls_data>).
      READ TABLE lt_dfies_tab ASSIGNING  FIELD-SYMBOL(<ls_dfies>WITH KEY fieldname <ls_data>-olr3_tab_field.
      IF sy-subrc 0.
        <ls_data>-olr3_tab_label <ls_dfies>-scrtext_m.
      ENDIF.
      ASSIGN COMPONENT <ls_data>-olr3_tab_field OF STRUCTURE <ls_result> TO <lv_content>.
      IF sy-subrc IS INITIAL.
        WRITE <lv_content> TO <ls_data>-olr3_tab_value.
      ENDIF.
    ENDLOOP.

    " Use the data from OData call and the frame info to build a work table
    CALL METHOD cl_dpr_olr3_work=>built_tab_from_data
      EXPORTING
        iv_object_type iv_object_type
        iv_context     space
        iv_frame       space
        it_data        lt_data
      IMPORTING
        et_xmltab      lt_xmltab.

    " Tweak attribute names to have evaluation w/o Badi implementation
    LOOP AT lt_xmltab ASSIGNING FIELD-SYMBOL(<ls_xmltab>).
      READ TABLE lt_data ASSIGNING <ls_data> WITH KEY olr3_tab_key <ls_xmltab>-id.
      IF sy-subrc IS INITIAL.
        IF <ls_data>-olr3_tab_key_eval > ' '.
          <ls_xmltab>-id <ls_data>-olr3_tab_key_eval.
        ELSE.
          <ls_xmltab>-id <ls_data>-olr3_tab_field.
        ENDIF.
      ENDIF.
    ENDLOOP.

    " Conversion of contents of LT_XMLTAB into an XML string
    CALL METHOD cl_dpr_olr3_work=>convert_tab_to_xml
      EXPORTING
        it_xmltab      lt_xmltab
      IMPORTING
        ev_object_data ev_object_data.


  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>IF_DPR_OBL_PROXY~SEARCH_OBJECTS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_SEARCH_CRITERIA             TYPE        DPR_TT_OBL_SEARCH_CRITERIA
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [--->] IV_MAX_NO_OF_HITS              TYPE        NUMC4(optional)
* | [<---] EV_ERROR_STRING                TYPE        STRING
* | [<---] ET_SEARCH_RESULT               TYPE        DPR_TT_OBL_SEARCH_RESULTS
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_dpr_obl_proxy~search_objects.

    DATA:
      lt_result TYPE TABLE OF zeppm_ruum,
      ltr_name  TYPE RANGE OF zeppm_ruum_name.

    query_ruum(
      EXPORTING
        iv_object_type  iv_object_type
      IMPORTING
        ev_error_string ev_error_string
        et_query_result lt_result
    ).

    CHECK ev_error_string IS INITIAL.

    LOOP AT it_search_criteria ASSIGNING FIELD-SYMBOL(<ls_search_criteria>WHERE fieldname 'NAME'.
      APPEND INITIAL LINE TO ltr_name ASSIGNING FIELD-SYMBOL(<ls_range>).
      IF <ls_search_criteria>-value CS '*'.
        <ls_range> VALUE #sign 'I' option 'CP' low <ls_search_criteria>-value ).
      ELSE.
        <ls_range> VALUE #sign 'I' option 'EQ' low <ls_search_criteria>-value ).
      ENDIF.
    ENDLOOP.

    LOOP AT lt_result ASSIGNING FIELD-SYMBOL(<ls_result>WHERE name IN ltr_name.
      APPEND INITIAL LINE TO et_search_result ASSIGNING FIELD-SYMBOL(<ls_search_result>).
      "      <ls_search_result>-object_key = <ls_result>-ruumid.
      "      CONCATENATE <ls_result>-name '                                                  .' INTO  <ls_search_result>-external_id.
      "      <ls_search_result>-external_id = <ls_search_result>-external_id(50).
      <ls_search_result>-external_id <ls_result>-name.
      <ls_search_result>-object_key  <ls_result>-ruumid.
      "      <ls_search_result>-description = <ls_search_result>-external_id.
    ENDLOOP.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_EPPM_RUUM_PROXY->ON_CHANGE
* +-------------------------------------------------------------------------------------------------+
* | [--->] SENDER                         TYPE REF TO IF_DPR_COMMON
* | [--->] CHANGEMODE                     TYPE        C
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD on_change.

    DATA:
      lr_common             TYPE REF TO if_dpr_common,
      lr_common_root        TYPE REF TO if_dpr_common,
      lr_common_parent      TYPE REF TO if_dpr_common,

      lv_object_type        TYPE cgpl_object_type,
      lr_native_object      TYPE REF TO object,
      ls_linkref            TYPE ty_instance,
      lv_object_is_relevant TYPE boole_d.

    TRY.
        lr_common ?= sender.
        lv_object_type lr_common->get_object_type).
      CATCH cx_dpr_object_composite_error.
        RETURN.
      CATCH cx_sy_move_cast_error.
        RETURN.
    ENDTRY.

    TRY.
        lr_native_object  sender->get_native_object).
      CATCH cx_dpr_object_composite_error.
        RETURN.
      CATCH cx_sy_move_cast_error.
        RETURN.
    ENDTRY.

    ls_linkref-obj_link_guid lr_common->get_guid).
    ls_linkref-root_guid     lr_common->get_root)->get_guid).
    ls_linkref-projectname   lr_common->get_root)->get_description).
    ls_linkref-mode          changemode.
    TRY.
        ls_linkref-task_guid     lr_common->get_parent)->get_guid).
        ls_linkref-taskname      lr_common->get_parent)->get_description).
      CATCH cx_sy_ref_is_initial.
        "
    ENDTRY.

    CASE lv_object_type.
      WHEN cl_dpr_co=>sc_ot_object_link.
        READ TABLE mt_linkref ASSIGNING FIELD-SYMBOL(<ls_linkref>WITH KEY obj_link_guid ls_linkref-obj_link_guid.
        IF sy-subrc 0.
          <ls_linkref>-common lr_common.
          <ls_linkref>-native_object lr_native_object.
          IF changemode 'D' AND <ls_linkref>-mode 'U'.
            <ls_linkref>-mode changemode.
          ELSEIF changemode 'C' AND <ls_linkref>-mode 'D'.
            <ls_linkref>-mode 'R'.
          ELSE.
            "keep original change mode.
          ENDIF.
        ELSE.
          ls_linkref-common lr_common.
          ls_linkref-native_object lr_native_object.
          INSERT ls_linkref INTO TABLE mt_linkref.
        ENDIF.
    ENDCASE.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->ON_DPR_COMMON_CHANGED
* +-------------------------------------------------------------------------------------------------+
* | [--->] SENDER                         LIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD on_dpr_common_changed.

    me->on_changesender sender changemode 'U' ).

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->ON_DPR_COMMON_CREATED
* +-------------------------------------------------------------------------------------------------+
* | [--->] SENDER                         LIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD on_dpr_common_created.
    me->on_changesender sender changemode 'C' ).
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_EPPM_RUUM_PROXY->ON_DPR_COMMON_DELETED
* +-------------------------------------------------------------------------------------------------+
* | [--->] SENDER                         LIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD on_dpr_common_deleted.

    me->on_changesender sender changemode 'D' ).

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>QUERY_RUUM
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<---] EV_ERROR_STRING                TYPE        STRING
* | [<---] ET_QUERY_RESULT                TYPE        TT_QUERY_RUUM_RESULTS
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD query_ruum.

    DATA:
      lv_service_url TYPE string,
      lv_csrf_token  TYPE string,
      lv_timestamp   TYPE i,
      lt_result      TYPE TABLE OF zeppm_ruum.

    CLEAR ev_error_string.

    " Fresh results are read every second at most.
    GET RUN TIME FIELD lv_timestamp.
    IF lv_timestamp sv_query_timestamp 5000000 AND sv_query_timestamp IS NOT INITIAL )
    OR sv_query_timestamp IS INITIAL.

      " get client
      TRY.
          DATA(lo_http_clientlcl_rest_client=>get_client(
            EXPORTING
              iv_obl_type       iv_object_type
              iv_oauth2_profile mc_oauth2_profile
            IMPORTING
              ev_xsrf_token    lv_csrf_token
           ).
        CATCH lcx_rest_noauth lcx_rest_nocust INTO DATA(lx_oac_at).
          ev_error_string lx_oac_at->get_text).
          RETURN.
        CATCH lcx_oauth_grant_required INTO DATA(lx_oac_grant).
          ev_error_string lx_oac_grant->get_text).
          MESSAGE ID 'ZRUUM' TYPE 'E' NUMBER '001' WITH
            get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
            get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
            get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
            get_string_fragmentiv_part iv_string =  lx_oac_grant->get_text)
            INTO ev_error_string.
          RETURN.
      ENDTRY.

      " get service url
      CALL METHOD cl_dpr_obl_repository=>get_object_capabilities
        EXPORTING
          iv_object_type iv_object_type
        IMPORTING
          es_obl_obtyp   DATA(ls_obtype)
        EXCEPTIONS
          OTHERS         0.

      cl_dpr_olr3_repository=>get_url_webserver_par(
         EXPORTING
           iv_web_server     =                  ls_obtype-web_server
         IMPORTING
           ev_web_server_url =                  DATA(lv_ws_url)
         EXCEPTIONS
           OTHERS            ).
      lv_service_url lv_ws_url.
      TRANSLATE lv_service_url TO LOWER CASE.

      "---------------------
      " New variant with OData V4 API
      "---------------------

      CONCATENATE lv_service_url 'OData/Reporting.svc/projects?$top=1000' INTO lv_service_url.

      " read data
      lo_http_client->request->set_methodif_http_request=>co_request_method_get ).
      lo_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri        value lv_service_url ).

      send_urllo_http_client ).

      lo_http_client->response->get_statusIMPORTING code DATA(lv_status_code).

      IF lv_status_code <> 200.
        ev_error_string lo_http_client->response->get_cdata).
        EXIT.
      ENDIF.

      DATA(lv_responselo_http_client->response->get_cdata).

      " parse data
      DATA(lt_ruum_jsonslcl_json_parser=>get_enumeration_from_jsonEXPORTING iv_json lv_response iv_property 'value' ).

      LOOP AT lt_ruum_jsons ASSIGNING FIELD-SYMBOL(<ls_ruum_json>).
        APPEND INITIAL LINE TO lt_result ASSIGNING FIELD-SYMBOL(<ls_result>).
        <ls_result>-ruumid          lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'projectId' ).
*        <ls_result>-workspaceid     = lcl_json_parser=>get_property_from_json( iv_json = <ls_ruum_json>  iv_property = 'workspaceId' ).
        <ls_result>-name        lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'name' ).
        DATA lv_str TYPE string.
        lv_str lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'createdAt' ).
        REPLACE ALL OCCURRENCES OF '-' IN lv_str WITH ''.
        <ls_result>-createdat lv_str.
        lv_str lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'changedAt' ).
        REPLACE ALL OCCURRENCES OF '-' IN lv_str WITH ''.
        <ls_result>-changedat lv_str.
        <ls_result>-status lcl_json_parser=>get_property_from_jsoniv_json <ls_ruum_json>  iv_property 'status' ).
      ENDLOOP.

      GET RUN TIME FIELD sv_query_timestamp.
      st_query_ruum_result lt_result.
    ENDIF.

    et_query_result st_query_ruum_result.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_EPPM_RUUM_PROXY=>QUERY_RUUM_TASK_KPIS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_OBJECT_TYPE                 TYPE        DPR_TV_OBL_TYPE
* | [<-->] CV_RUUM                        TYPE        ZEPPM_RUUM
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD query_ruum_task_kpis.

    DATA:
      lv_service_url TYPE string,
      lv_service     TYPE string,
      lv_csrf_token  TYPE string,
      lv_timestamp   TYPE i,
      lt_result      TYPE tt_query_ruum_tasks.

    IF st_query_ruum_task_custom IS INITIAL.
      get_ruum_tasksEXPORTING iv_object_type iv_object_type ).
    ENDIF.

    READ TABLE st_query_ruum_result ASSIGNING FIELD-SYMBOL(<ls_ruum>WITH KEY ruumid cv_ruum-ruumid.
    CHECK sy-subrc 0.

    LOOP AT st_query_ruum_task_custom ASSIGNING field-symbol(<ls_task>WHERE ruumid <ls_ruum>-ruumid.

      IF <ls_task>-finishdate IS NOT INITIAL AND <ls_task>-finishdate < sy-datum AND <ls_task>-status <> 'DONE'.
        ADD TO <ls_ruum>-tasks_overdue.
      ENDIF.
      IF <ls_task>-status <> 'DONE'.
        ADD TO <ls_ruum>-tasks_open.
      ENDIF.
      IF <ls_task>-status 'DONE'.
        ADD TO <ls_ruum>-tasks_completed.
      ENDIF.

    ENDLOOP.

    IF <ls_ruum>-tasks_completed AND <ls_ruum>-tasks_open 0.
      CLEAR <ls_ruum>-poc.
    ELSEIF <ls_ruum>-tasks_completed > AND <ls_ruum>-tasks_open 0.
      <ls_ruum>-poc 100.
    ELSE.
      DATA(lv_poc100 * <ls_ruum>-tasks_completed / <ls_ruum>-tasks_completed + <ls_ruum>-tasks_open ).
      <ls_ruum>-poc lv_poc.
    ENDIF.
    cv_ruum <ls_ruum>.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>SEND_URL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_HTTP_CLIENT                 TYPE REF TO IF_HTTP_CLIENT
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD send_url.

    DATA:
      lv_url      TYPE string,
      lv_host     TYPE string,
      lv_firsttry TYPE string,
      lv_retry    TYPE string.

    " No absolute path possible here: tweak necessary
    lv_url  io_http_client->request->get_header_field(  name  if_http_header_fields_sap=>request_uri ).
    lv_host io_http_client->request->get_header_field(  name  'host' ).
    IF lv_host IS NOT INITIAL AND lv_url CS lv_host.
      SPLIT lv_url AT lv_host INTO DATA(lv_dummylv_url.
      io_http_client->request->set_header_fieldname  if_http_header_fields_sap=>request_uri value lv_url ).
    ENDIF.

    io_http_client->send).
    io_http_client->receiveEXCEPTIONS http_communication_failure ).
    io_http_client->response->get_statusIMPORTING code DATA(lv_status_code).

    "If Ruum is a bit under the weather or assumes a DoS attack falsely, just re-try.
    IF lv_status_code 500.
      io_http_client->send).
      io_http_client->receiveEXCEPTIONS http_communication_failure ).
      io_http_client->response->get_statusIMPORTING code lv_status_code ).
    ENDIF.

    IF lv_status_code 401 OR lv_status_code 403 OR lv_status_code 404.
      DATA(lv_responseio_http_client->response->get_cdata).
      " We're obviously not successful. If it's an expired token: try to trigger the refresh flow
      IF lcl_rest_client=>refresh_successfulabap_true.
        io_http_client->send).
        io_http_client->receiveEXCEPTIONS http_communication_failure ).
      ENDIF.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_EPPM_RUUM_PROXY=>STRING_CUT_TRAILING_SPACES
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_STRING                      TYPE        STRING
* | [<-()] RV_STRING                      TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD string_cut_trailing_spaces.

    "---------------------------------------------------------------------------------------------------
    " Makes sure that a filter string doesn't contain any trailing spaces without losing leading spaces
    "---------------------------------------------------------------------------------------------------

    DATAlv_pos          TYPE VALUE 0,
          lv_char255(255TYPE c,
          lv_space        TYPE VALUE ' '.

    CHECK iv_string IS NOT INITIAL.

    rv_string lv_char255 iv_string.
    " count leading spaces
    DO.
      IF lv_char255+lv_pos(1lv_space.
        ADD TO lv_pos.
        IF lv_pos 255.
          EXIT.
        ENDIF.
      ELSE.
        EXIT.
      ENDIF.
    ENDDO.

    " Remove all spacs
    SHIFT rv_string RIGHT DELETING TRAILING space.
    SHIFT rv_string LEFT DELETING LEADING space.
    " Restore leading spaces
    SHIFT rv_string RIGHT BY lv_pos PLACES.

  ENDMETHOD.
ENDCLASS.


  • No labels