Skip to Content

While setting up Gateway using the Service Builder I came across an issue which, once I managed to resolve it, I thought would be helpful to share.
It seems that some OData calls which use filters do not populate the table IT_FILTER_SELECT_OPTIONS. This has to be done manually in the backend by converting IV_FILTER_STRING.

Scenario
Search for an order which is an Opportunity (ProcessType eq ‘ZBOP’) and where the Sales Cycle Closing Date is between two dates (ScCdate ge datetime’2012-12-01T00:00:00′ and ScCdate le datetime’2012-12-09T00:00:00′)

The OData call looks like this:
…/sap/opu/odata/sap/PROJECT_NAME/Orders?$filter=ProcessType eq ‘ZBOP’ and ScCdate ge datetime’2012-12-01T00:00:00′ and ScCdate le datetime’2012-12-09T00:00:00′

When you make this call IV_FILTER_SELECT_OPTIONS, which would usually contain all the filter options, is empty.

IV_FILTER_STRING is populated (as it always is when a filter is used) with the string :
( ( ( ProcessType eq ‘ZBOP’ ) and ( ScCdate le ‘20121231’ ) ) and ( ScCdate ge ‘20121101’ ) )
As you can see from this string, the two dates are not being grouped together, which I believe is the reason for IT_FILTER_SELECT_OPTIONS not being generated.

I found that this is always the case when you try to look between two dates and filter by another option as well. If you’re just filtering between two dates then there seems to be no issue, but it’s a good idea to implement the appropriate code to deal with this situation should it occur unexpectedly. When making OData calls it shouldn’t be the responsibilty of the calling program to order the filters in the correct way, it should be managed in the backened after the call is sent.

I resolved this problem with the following code, which converts IV_FILTER_STRING into a table like IT_FILTER_SELECT_OPTIONS.

The important thing to note is that where there are two properties with the same name these need to be combined into one line in the IV_FILTER_SELECT_OPTIONS with the high and low values. The last part of my code shows how I did this.

*******METHOD CALL FOR CODE TO FIX FILTER_SELECT_OPTIONS********

if it_filter_select_options is initial.
me->set_filter_str(
          exporting
             iv_filter_string = iv_filter_string
          importing
             it_filter_select_options = lt_filter_select_options  ).
endif.

*******METHOD SET_FILTER_STR********

method set_filter_str.

  data:
     lt_filter_string type table of string,
     lt_key_value type /iwbep/t_mgw_name_value_pair,
     ls_filter_string type string,
     lv_input type string,
     lv_name type string,
     lv_value type string,
     lv_sign type string,

     lt_filter_select_options type table of /iwbep/s_mgw_select_option,
     ls_filter_select_options type /iwbep/s_mgw_select_option,
     lt_select_options type /iwbep/t_cod_select_options,
     ls_select_options type /iwbep/s_cod_select_option,
     lt_filter_select_options2 type /iwbep/t_mgw_select_option,
     ls_filter_select_options2 type /iwbep/s_mgw_select_option.

  field-symbols:
    <fs_range_tab> like line of lt_filter_select_options ,
    <fs_select_option> type /iwbep/s_cod_select_option,
    <fs_key_value> like line of lt_key_value.

*******************************************************************************
  if iv_filter_string is not initial.
    lv_input = iv_filter_string.

* *— get rid of )( & ‘ and make AND’s uppercase
    replace all occurrences of ‘)’ in lv_input with ”.
    replace all occurrences of ‘(‘ in lv_input with ”.
    replace all occurrences of `’` in lv_input with ”.
    replace all occurrences of ‘ and ‘ in lv_input with ‘ AND ‘.
    replace all occurrences of ‘ eq ‘ in lv_input with ‘ EQ ‘.
    split lv_input at ‘AND’ into table lt_filter_string.

* *— build a table of key value pairs based on filter string
    loop at lt_filter_string into ls_filter_string.
      clear: ls_select_options, ls_filter_select_options, lt_select_options.
      append initial line to lt_key_value assigning <fs_key_value>.

      condense ls_filter_string.
*       Split at space, then split into 3 parts
      split ls_filter_string at ‘ ‘ into lv_name lv_sign lv_value.
      translate lv_sign to upper case.
      ls_select_options-sign = ‘I’.
      ls_select_options-option = lv_sign.
      ls_select_options-low = lv_value.
      append ls_select_options to lt_select_options.
      ls_filter_select_options-property = lv_name.
      ls_filter_select_options-select_options = lt_select_options.

      append ls_filter_select_options to lt_filter_select_options.
      clear: ls_filter_select_options.
    endloop.
    clear: ls_select_options, ls_filter_select_options, lt_select_options.
  endif.

*  Loop through the select options, look for two with the same property name, if it exisits, copy into one!
  sort lt_filter_select_options ascending by property.
  data: count type i value 1,
        countplus type i,
        ls_temp like ls_filter_select_options,
        lt_temp_op like lt_select_options,
        ls_temp_op like ls_select_options,
        lt_sel_op like lt_select_options,
        ls_sel_op like ls_select_options,
        ls_results like ls_filter_select_options,
        lt_results like lt_filter_select_options.

  read table lt_filter_select_options into ls_filter_select_options index count.
  while sy-tabix <> 0.
    ls_temp = ls_filter_select_options.
    countplus = count + 1.
    read table lt_filter_select_options into ls_filter_select_options index countplus.
    if sy-tabix <> 0.
      if ls_temp-property = ls_filter_select_options-property.
        ls_sel_op-sign = ‘I’.
        ls_sel_op-option = ‘EQ’.
        lt_temp_op = ls_temp-select_options.
        lt_select_options = ls_filter_select_options-select_options.
        read table lt_temp_op into ls_temp_op index 1.
        if ls_temp_op-option = ‘GE’ or ls_temp_op-option = ‘GT’.
          ls_sel_op-low = ls_temp_op-low.
          read table lt_select_options into ls_select_options index 1.
          ls_sel_op-high = ls_select_options-low.
        else.
          ls_sel_op-high = ls_temp_op-low.
          read table lt_select_options into ls_select_options index 1.
          ls_sel_op-low = ls_select_options-low.
        endif.
        append ls_sel_op to lt_sel_op.

        ls_results-property = ls_temp-property.
        ls_results-select_options = lt_sel_op.
        append ls_results to lt_results.
        count = count + 2.
      else.
        append ls_temp to lt_results.
        count = count + 1.
      endif.
    else.
      append ls_temp to lt_results.
      exit.
    endif.

    clear: ls_temp, lt_temp_op[], ls_temp_op, lt_sel_op[], ls_sel_op, ls_results, ls_filter_select_options.
    read table lt_filter_select_options into ls_filter_select_options index count.
  endwhile.

  it_filter_select_options = lt_results.

endmethod.

To report this post you need to login first.

7 Comments

You must be Logged on to comment or reply to a post.

      1. Former Member Post author

        John (and Glen) that looks really good, I guess I should have checked the OSS notes first!

        Although through doing this exercise I think I gained some valuable experience, even if there does seem to be a better way to do it.

        Next time though I will be sure to check OSS Notes, thank you for your comment, any advice/tips/feedback are very welcome and appreciated ๐Ÿ™‚

        (0) 
  1. Thomas Knobloch

    Hi Lindsay, thanks for sharing this with us. But I’d like also to know in which method to put this coding? I have the same problem like you but under different circumstances and I think this will not help me.

    If you generate a service for a CDS Analytical Query view and you use that service to display a SmartChart or SmartTable, the same problem with filter occurs when you set filters on UI. Error comes because IT_FILTER_OPTIONS can’t be filled because of complicated IV_FILTER_STRING which contains logic like (TYPE=’1′ and SIZE=’10’) or (TYPE=’1′ and SIZE=’12’).

    Best regards,

    Thomas

    (0) 

Leave a Reply