Friday 5 May 2023

Learning new syntax ABAP 7.4 with a volte-face scenario

Recently, I encountered a unique challenge while working with a client with an old SAP system.

I had code ( ABAP 7.4 ) ready to deploy to client system but I could not use it due to lower ECC version. So, I downgraded my code syntactically as many of the operators are not supported by EHP 6.0

I am sharing few of my learnings while doing so. I hope the same can be useful for changing the code to and/or learning ABAP 7.4 as well.

This blog will cover Inline declaration of variables and field symbols, inline usage of structure, and operators such as Filter and group by.

1. LOOP-AT Statement: Inline declaration of Variable or Reference.


Inline Declaration.

LOOP AT GT_DATA  ASSIGNING FIELD-SYMBOL(<LS_DATA>).
* Code
ENDLOOP.

LOOP AT GT_DATA INTO DATA(LS_DATA).
* Code
ENDLOOP.

First of all, if you find DATA(*) OR FIELD-SYMBOL(*) in code, it means it is inline declaration. This is not supported by old syntax. So, I declared the field symbol and as it is a LOOP-AT, type of field symbol has to be a line of the table.


Old syntax equivalent is as below.

FIELD-SYMBOLS: <LS_DATA> LIKE LINE OF GT_DATA .

LOOP AT GT_DATA  ASSIGNING <LS_DATA>.
* Code 
ENDLOOP.

* ORR
data: LS_DATA LIKE LINE OF GT_DATA .

LOOP AT GT_DATA INTO LS_DATA.
* Code 
ENDLOOP.

Same holds true for inline declaration of Data(*) in LOOP-AT statement.

2. Inline usage of Structure | NO-DECLRATION

 
IF <LS_DATA>-NUM IS NOT INITIAL.
  APPEND VALUE #( BUKRS = <LS_DATA>-BUK
                  BELNR = <LS_DATA>-BEL
                  GJAHR = <LS_DATA>-YR ) TO GT_DOC.
ENDIF.

Here, no structure/ work area is declare to hold values. Instead, direct assignment and then append happens.

First of all, declare a work area of type GT_DOC.

DATA: LS_DOC LIKE LINE OF GT_DOC.

Then assign 3 variables from <ls_data> to new work area and append to the table.

IF <LS_DATA>-NUM IS NOT INITIAL.
  LS_DOC-BUKRS = <LS_DATA>-BUK.
  LS_DOC-BELNR = <LS_DATA>-BEL.
  LS_DOC-GJAHR = <LS_DATA>-YR.
  APPEND LS_DOC TO GT_DOC.
ENDIF.
 

3. Filter Operator : an Equivalent of Conditional Move-corresponding.


New syntax looks like below. As the name suggests, Usage of Filter operator is to transfer records , for which the condition holds true, from one table to another

DATA(LT_DATA) = FILTER #( GT_DATA WHERE BUKRS = CONV #( CS_DATA-BUK )       
                                    AND BELNR = CONV #( CS_DATA-BEL )                                                                                                                       
                                    AND GJAHR = CONV #( CS_DATA-YR ) ).

Initially, I suspected that it is move-corresponding operator for work area. But, I later found out that result is a subset table of GT_Data and “where” condition filters the result set.

So, Equivalent code would look like below.

DATA: LT_DATA LIKE GT_DATA.
DATA: LS_DATA LIKE LINE OF GT_DATA.

DATA:LS_BUKRS TYPE BUKRS,
     LS_BELNR TYPE BELNR,
     LS_GJAHR TYPE GJAHR.

LS_BUKRS = CS_DATA-BUK.
LS_BELNR = CS_DATA-BEL.
LS_GJAHR = CS_DATA-YR.


LOOP AT GT_DATA INTO LS_DATA WHERE BUKRS =  LS_BUKRS
                               AND BELNR =  LS_BELNR
                               AND GJAHR =  LS_GJAHR.
  APPEND LS_DATA TO LT_DATA.
ENDLOOP.

4. Reduce Operator : Loop-At statement with Aggregation


Usage of Reduce operator is to aggregate value of a particular column of an internal table.

in other words, it reduces a table to single variable by aggregating.

GS_DATA-TAX = REDUCE #( INIT LV_TAX TYPE BSET-HWSTE
                           FOR LS_DATA IN LT_DATA  
                                NEXT LV_TAX = LV_TAX + COND # 
                                  ( 
                                    WHEN LS_DATA-SHKZG = CS_DATA-DEBIT THEN LS_DATA-HWSTE      
                                    WHEN LS_DATA-SHKZG = CS_DATA-CREDIT THEN ( LS_DATA-HWSTE * -1 )    
                                   ) 
).

In above scenario, Reduce operator loops over LT_DATA and cumulatively adds HWSTE value into LV_TAX and finally assigns to GS_DATA-TAX.

For this to work in old ABAP, it would require looping over an internal table, storing record in a work area and writing an IF-ELSE ladder.

DATA: LV_TAX TYPE BSET-HWSTE.
DATA: LS_DATA LIKE LINE OF LT_DATA.

LOOP AT LT_DATA INTO LS_DATA.
  IF LS_DATA-SHKZG = CS_DATA-DEBIT.
    LV_TAX = LV_TAX + LS_DATA-HWSTE.
  ELSEIF LS_DATA-SHKZG = CS_DATA-CREDIT.
    LV_TAX = LV_TAX + ( LS_DATA-HWSTE * -1 ).
  ENDIF.
ENDLOOP.

GS_DATA-TAX = LV_TAX.
 

5. GROUP BY on an Internal Table


New Syntax supports group by operator on an internal table while looping over it.

This makes code way easier when dealing with single internal table containing both Header and Item level data.

Group-by table <LT_GRP>, which is reference to original table GT_TABLE, contains item level data of a particular header. ( Grouped by 3 parameters in below example )

LOOP AT GT_DATA INTO LS_DATA WHERE VAR1 = ABAP_TRUE
                               AND VAR2 IS NOT INITIAL
                                           GROUP BY (  BUKRS   = LS_DATA-BUKRS
                                                       BELNR   = LS_DATA-BELNR   
                                                       GJHAR   = LS_DATA-GJHAR       
                                                       INDEX   = GROUP INDEX )
                                            ASCENDING
                                                ASSIGNING FIELD-SYMBOL(<LT_GRP>).   
* Code

LOOP AT GROUP <LT_GRP> ASSIGNING FIELD-SYMBOL(<LS_GRP_DATA>).
Code
ENDLOOP.

* Code   
ENDLOOP.

I found this one really complex to solve.

Old syntax does not support Group-by on an internal table. So I had to find a solution for GROUP-BY.

Create a copy-table of the given table and use it is header table, while GT_TABLE would work as Item table.

I used field symbol for looping over item table, so I would be able to make changes in the GT_TABLE itself.

FIELD-SYMBOL: <LS_GRP_DATA> LIKE LINE OF GT_DATA.
DATA: GT_HEADER_DATA LIKE GT_DATA. 

GT_HEADER_DATA[] = GT_DATA[].

SORT GT_HEADER_DATA BY BUKRS 
                       BELNR 
                       GJHAR.
DELETE ADJECENT DUPLICATES FROM GT_HEADER_DATA COMPARING BUKRS                     
                                                         BELNR 
                                                         GJHAR. 

LOOP AT GT_HEADER_DATA INTO LS_DATA WHERE VAR1 = ABAP_TRUE
                                    AND VAR2 IS NOT INITIAL.
* Code
LOOP AT GT_DATA ASSIGNING <LS_GRP_DATA> WHERE VAR1 = ABAP_TRUE
          AND VAR2 IS NOT INITIAL
          AND BUKRS = LS_DATA-BUKRS
          AND BELNR = LS_DATA-BELNR
          AND GJHAR = LS_DATA-GJHAR.   
* Code
ENDLOOP.

* Code   
 ENDLOOP.

No comments:

Post a Comment