Skip to Content
Author's profile photo François Henrotte

Reading price conditions dynamically from condition tables

It is not easy to get price conditions as they can be stored into different condition tables based on the needs of each customer. The condition tables are generated and the fields used inside the tables are not always the same.

Here is a solution to get the price linked to a condition LV_KSCHL. We assume that the usage and application (keys from table T685) are fixed into constants – respectively ‘A’ and ‘V’ for Sales.

Step 1 : get access sequence

This is needed in order to retrieve the list of condition tables linked to the condition type.

    SELECT SINGLE * FROM t685
                    INTO @gs_t685
                   WHERE kvewe EQ @gc_kvewe
                     AND kappl EQ @gc_kappl
                     AND kschl EQ @lv_kschl.
    IF sy-subrc EQ 0.
      lv_kozgf = gs_t685-kozgf.
    ENDIF.

Step 2 : get the list of condition tables linked to the access sequence

    DATA: lt_t682ia TYPE TABLE OF t682ia.


    CLEAR: gt_t681.

    CALL FUNCTION 'COND_READ_ACCESSES'
      EXPORTING
        i_kvewe    = gc_kvewe
        i_kappl    = gc_kappl
        i_kozgf    = lv_kozgf
      TABLES
        t682ia_tab = lt_t682ia
      EXCEPTIONS
        OTHERS     = 1.

    SELECT * FROM t681
             INTO TABLE gt_t681
              FOR ALL ENTRIES IN lt_t682ia
            WHERE kvewe   EQ gc_kvewe
              AND kotabnr EQ lt_t682ia-kotabnr.

Step 3 : for each condition table, get the data of the condition type

We follow the access sequence, and if some data is found, then we exit the loop. We could also collect all the data from the different condition tables, if needed. The date PRSDT can be also defined externally to some other value than the current date.

LOOP AT gt_t681 INTO DATA(ls_t681).
  "Retrieve data from condition tables
  get_data_from_condition_table( is_t681  = ls_t681
                                 iv_prsdt = sy-datum ).
  IF gt_data IS NOT INITIAL.
    EXIT.
  ENDIF.
ENDLOOP.

Now let’s look at the dynamical reading of the data. As we have the structures T685 and T681, we have almost all information needed to do so. The only missing part is about the fields to be used for the selection of the table. This will be easily retrieved using function module WCB_GET_CONDITION_TABLE_KEYS. So the coding to retrieve the data will be like this :

  METHOD GET_DATA_FROM_CONDITION_TABLE.
    DATA: lt_t682z TYPE wcb_t682z_tab.

    DATA: lv_datum TYPE datum,
          ls_where TYPE string.

    DATA: ls_data TYPE ty_data.

    DATA: ob_rec TYPE REF TO data.

    FIELD-SYMBOLS: <lt_rec>   TYPE STANDARD TABLE,
                   <lv_field> TYPE any,
                   <lv_knumh> TYPE knumh.


    CREATE DATA ob_rec TYPE STANDARD TABLE OF (is_t681-kotab) WITH NON-UNIQUE DEFAULT KEY.
    ASSIGN ob_rec->* TO <lt_rec>.

*   Pay attention to this:
*   Method GET_ACCESS_SEQUENCE should be called first in order to fill structure GS_T685
    CALL FUNCTION 'WCB_GET_CONDITION_TABLE_KEYS'
      EXPORTING
        i_use            = gc_kvewe
        i_application    = gc_kappl
        i_condition_type = gs_t685-kschl
        i_con_tab        = is_t681-kotabnr
        i_access         = gs_t685-kozgf
      IMPORTING
        et_t682z         = lt_t682z
      EXCEPTIONS
        OTHERS           = 1.
    IF sy-subrc NE 0.
      RETURN.
    ENDIF.

    LOOP AT lt_t682z INTO DATA(ls_t682z).
      ASSIGN COMPONENT ls_t682z-zifna OF STRUCTURE gs_komg TO <lv_field>.
      IF sy-subrc EQ 0.
        IF ls_where IS INITIAL.
          ls_where = |{ ls_t682z-zifna } EQ '{ <lv_field> }'|.
        ELSE.
          ls_where = ls_where && | AND { ls_t682z-zifna } EQ '{ <lv_field> }'|.
        ENDIF.
      ENDIF.
    ENDLOOP.

    IF is_t681-ksdat IS INITIAL.
      SELECT * INTO TABLE <lt_rec>
               FROM (is_t681-kotab)
              WHERE kappl EQ gc_kappl
                AND kschl EQ gs_t685-kschl
                AND (ls_where).
    ELSE.
      IF iv_prsdt IS INITIAL.
        lv_datum = sy-datum.
      ELSE.
        lv_datum = iv_prsdt.
      ENDIF.
      SELECT * INTO TABLE <lt_rec>
               FROM (is_t681-kotab)
              WHERE kappl EQ gc_kappl
                AND kschl EQ gs_t685-kschl
                AND datbi GE lv_datum
                AND datab LE lv_datum
                AND (ls_where).
    ENDIF.

    LOOP AT <lt_rec> ASSIGNING FIELD-SYMBOL(<ls_line>).
      ASSIGN COMPONENT 'KNUMH' OF STRUCTURE <ls_line> TO <lv_knumh>.
      SELECT konp~knumh
             konp~kbetr AS kbetr_1
             konp~konwa
             konp~kpein
             konp~kmein
             konm~kstbm
             konp~konms
             konm~kbetr AS kbetr_2
        INTO ls_data
        FROM konp
        LEFT OUTER JOIN konm ON konm~knumh = konp~knumh
       WHERE konp~knumh    EQ <lv_knumh>
         AND konp~loevm_ko EQ ' '.

        IF ls_data-konwa CA '%'.
          ls_data-kbetr_1 = ls_data-kbetr_1 / 10 .
          ls_data-kbetr_2 = ls_data-kbetr_2 / 10 .              "BGO01
        ENDIF.
        APPEND ls_data TO gt_data.

      ENDSELECT.
    ENDLOOP.

    SORT gt_data BY knumh kstbm.

  ENDMETHOD.

Notes:

  1. the parameters are trivial : IS_T681 TYPE T681 and IV_PRSDT TYPE PRSDT.
  2. the field T681-KSDAT indicates if the condition table is time-dependent.
  3. depending on your needs you define the table GT_DATA to contain data from tables KONP / KONM
  4. those two tables are always read with the key KNUMH coming from the condition tables

Prerequisite :

Now you should have noticed that we compare the values of the condition tables with the values from segment GS_KOMG. This one is of type KOMG and contains all the possible fields to be used in the key fields of condition tables. Of course you have to fill this segment before starting to read the condition tables. Here is some sample code to do it quite easily for a Billing document.

    CALL FUNCTION 'RV_INVOICE_PRICING_PREPARE'
      EXPORTING
        vbrk_i = ls_vbrk
        vbrp_i = ls_vbrp
      IMPORTING
        komk_e = ls_komk
        komp_e = ls_komp
      TABLES
        xkomfk = lt_komfk
        xvbfs  = lt_vbfs
        xvbpa  = lt_xvbpa
        xvbrk  = lt_xvbrk
        xvbrp  = lt_xvbrp
      EXCEPTIONS
        OTHERS = 1.

    "Fill source fields for condition tables
    MOVE-CORRESPONDING ls_komk TO gs_komg.
    MOVE-CORRESPONDING ls_komp TO gs_komg.

 

As you probably noticed, this was extracted from a class that I made to read the condition tables dynamically. I extracted the important parts of the code and removed the Z tables and such things that are not generic so that you can see how this works from a global point of view.

Assigned Tags

      9 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Jesús Antonio Santos Giraldo
      Jesús Antonio Santos Giraldo

      Nice !

      Author's profile photo Roberto Forti dos Santos
      Roberto Forti dos Santos

      Thanks for sharing it! Regards

       

      Author's profile photo Shai Sinai
      Shai Sinai

      Thanks for sharing.

      In case you are interested just in the condition value (and not in complete analysis), you may use standard FM CONDITION_RECORD_READ.

      FM CONDITION_RECORD_READ (and it seems that also your code) doesn't handle scale based conditions, For this you'll have to further process parameter pe_t_scale according to KOMP-KSTBS.

      Author's profile photo François Henrotte
      François Henrotte
      Blog Post Author

      Thank you for your input !

      The coding I proposed is a basis that you can adapt in order to meet specific needs.

      Based on KONP you can retrieve the scales using the function module CONDITION_SCALES_READ. This one is used also in CONDITION_RECORD_READ which leads me to think that it is well handling such conditions.

       

      Author's profile photo akira jain
      akira jain

      Thanks for sharing.

      The ABAP language was originally used by developers to develop the SAP R/3 platform. It was also intended to be used by SAP customers to enhance SAP applications – customers can develop custom reports and interfaces with ABAP programming.

      Author's profile photo Matthew Billingham
      Matthew Billingham

      Spammer, reported.

      Author's profile photo Akash Kanade
      Akash Kanade

      Thanks for sharing..! Helpful..!

      Author's profile photo Matthew Billingham
      Matthew Billingham

      You need to make an edit

          CALL FUNCTION 'COND_READ_ACCESSES'
            EXPORTING
              i_kvewe    = gc_kvewe
              i_kappl    = gc_kappl
              i_kozgf    = lv_kozgf
            TABLES
              t682ia_tab = lt_t682ia
            EXCEPTIONS
              OTHERS     = 1.
      
          IF lt_t682ia IS NOT INITIAL.
            SELECT * FROM t681
                     INTO TABLE gt_t681
                      FOR ALL ENTRIES IN lt_t682ia
                    WHERE kvewe   EQ gc_kvewe
                      AND kotabnr EQ lt_t682ia-kotabnr.
          ENDIF.

      If you don't have that check and lt_t682ia is empty, then you'll get everything in T681. Which you probably don't want.

      Author's profile photo François Henrotte
      François Henrotte
      Blog Post Author

      True, it is always needed to check if the table is empty before you use it in a FOR ALL ENTRIES statement. Thank you for your remark !