Quantcast
Channel: ABAP Development
Viewing all 948 articles
Browse latest View live

Problem in sales order creation using BAPI_SALESORDER_CREATEFROMDAT2 for BOM (Bill of Material) and Solution

$
0
0

Generally when we create sales order using BAPI_SALESORDER_CREATEFROMDAT2, there we pass item number externally into the tables parameter - ORDER_ITEMS_IN like 10, 20, 30 format.

 

Problem:

When there is BOM (bill of material) for any material that will explode when creating the sales order with those materials. Sometime it can be happen that the material has more than 9 sub items (bill of material). In this case if we pass the item number as 10, 20, 30, 40 format externally into the BAPI, then the item (which have more than 9 sub item) will over write on the next item and there will be problem in sales order creation.

 

Solution:

Pass the parameter INT_NUMBER_ASSIGNMENT with value ‘X’ into the BAPI. It will internally generates and assign the next suitable item number and avoid the overwriting of items.

 

Example:

Lets say there is two materials used to create a sales order,

MAT1

MAT2

 

And sub items (bill of material) of the materials are like,

MAT1 – BOM1, BOM2, BOM3, BOM4, BOM5, BOM5, BOM7, BOM8, BOM9, BOM10, BOM11.

MAT2 – BOM1A, BOM2A, BOM3A.

 

When we will try to create sales order using BAPI (BAPI_SALESORDER_CREATEFROMDAT2) providing the line item numbering externally (from our custom code) as 10, 20 … then we would face the same problem.

 

If we pass the parameter INT_NUMBER_ASSIGNMENT as ‘X’, then the standard code within BAPI will generate the next item assignment number and create the sales order successfully.

 

In the created sales order the line items will look like –

10 – MAT1

11 – sub item (BOM1)

12 – sub item (BOM2)

13 – sub item (BOM3)

.

.

21 – sub item (BOM11)

 

30 – MAT2

32 – sub item (BOM1A)

33 – sub item (BOM2A)

34 – sub item (BOM3A).

 

Here, instead of 20 the next item (MAT2) will start from 30.

 

This is a very simple technique and might help someone when troubling with such king of BOM issue.


Transport Tracking Made Easier in SAP

$
0
0

This blog will help in understanding the concept of transport request attributes and how it will help in transport management. This will help in achieving good governance of transport requests in big SAP implementation projects.

 

Pre-requisite:Basic knowledge of SAP transport request.

 

  • Introduction                                                         

Transport requests are used to transfer the changes done to existing objects or new objects created in the development system to quality and then finally to production system.

screen1.jpg

Production system has real and confidential data, hence while importing transports to production system transport requests needs to be verified correctly. Any mistakes in transport list can hamper existing functionality which intern will cause in change backout and development failure.

 

The order in which transports should be imported to production needs to be same as per the sequence they were moved in Quality/Acceptance system.

 

In big SAP implementation projects which are having more than 100 transport requests created by developer / functional, there will be more chance of missing transport request in final list of production. If any transport is missed in the production list, there are several possible risks involved.

Other factors involved are number of developers working on the same project, developers working on the same objects , transports which are being moved in case of production bug fixes and multiple projects being run in single environment.

 

  • Possible risks if transport is missed in the production list:

1.  Wrong object versions can go to production: If there are multiple transport requests for one object and one of the transport requests is missed during production move, then this will lead to incorrect version of the object.

 

For e.g. for report program ‘ZTEST’ one transport request ‘AB123’ was created and moved from DEV system to Acceptance system. Later on there was a defect detected in Acceptance testing.

Then to fix this defect again new transport request ‘AB456’ was created and moved to Acceptance box. Now while preparing the production transport list for program ‘ZTEST’, latest transport request for defect fix ‘AB456’ was missed. Then incorrect version of program ‘ZTEST’ will go to production system and same defect which was already fixed in acceptance testing will remain unfixed as it is.

 

2.  Possibility of RC8 Error during transport movement to production:  If any transport of dependent object is missed in the final list of production movement then transport movement will result in RC8 Error.

 

E.g. there are 2 transport requests one is for table and another is for data element which is used in table. Both table and data element are new objects and does not exist in production before transport movement.

Object Type

Object Name

Transport Request

Data Element

ZDTELE

AB1234

Table

ZTABLE

AB5678

 

Now while preparing final transport list for production movement if transport ‘AB1234’ for Data Element ‘ZDTELE’ is missed then while moving transport request ‘AB5678’ (i.e. for table) RC8 error will occur.

 

Hence transport movement will end up with error and intern will need analysis on transport  failure. Again for missing transport request separate change management process will be required to move transport to production.

 

Above mentioned are major risks during production transport movement and may cause HUGE BUSINESS IMPACT.

 

To avoid such issues because of simple mistakes, good transport management and tracking is needed in projects.

 

  • Steps for better transport management and tracking:

o Create custom transport attribute.

Maintain custom transport attribute for each new transport request for specific development before releasing it. Hence the entire transport list  related to development will have attribute maintained.

Fetch the list of transports from E070A table where attribute name = custom attribute name.

This result will give complete list of transport requests for which custom attribute was maintained.

This will avoid human error of missing any transport request in production transport list.

Transport attribute maintenance check can be enforced for specific projects. E.g. In development environment multiple projects are being run and if we want to make transport attribute maintenance mandatory only for our project then this check can be performed specific to project ID by implementing method ‘CHECK_BEFORE_RELEASE’ of BADI “CTS_REQUEST_CHECK”.

Once this check is implemented developer/functional will not be able to release transport request without maintaining transport attribute.

Hence at the time of production move list of transports for specific development can be fetched from E070A table where transport attribute value =’XXXXXX’.

 

  • Scenario for how attribute maintenance will help in better management of transports:

In single project there are multiple developments going in parallel. Each development will have separate requirement specification document with unique number of requirement document.

 

Below is example:

Project Name:    Project1

Now under project1 there are multiple developments executed,

Development Name

Requirement Spec. Document number

DEV1

R1111

DEV2

R2222

DEV3

R3333

 

Now if we create a custom transport attribute ‘ZREQ_DOCNO’ for maintaining requirement specification document number.

Then while creating transport requests for development (i.e. DEV1), maintain transport attribute ZREQ_DOCNO = R1111’ (which is req. spec. doc. Number for DEV1).

Now if there are total 40 transport requests were created for DEV1 then list of transports can be fetched from “E070A” table where TRANSPORT ATTRIBUTE =’ ZREQ_DOCNO’ and ATTRIBUTE VALUE = ‘R1111’.

This data fetch from E070A table will give complete list of transports created for DEV1 and there will not be any miss in transport list.

Also this transport request maintenance can be made mandatory based on project ID by implementing BADI.

Transport attributes creation and BADI implementation is explained in detail further.

 

  • How to create Transport Attribute?  We can create custom transport Attributes (Z-attribute) for easier project level transport tracking.  This custom transport attribute can be maintained, so that we can find specific development transports according to custom Transport Attribute values. You can use attributes to define change requests. Also using these Attribute values, we can perform transport analysis.

 

  • Steps for creation of TP Attribute:

      1. Go to transaction SE03 (Transport Organizer Tools).Select Display/Change Request Attributes option.

 

   screen2.jpg

 

2.          2. Click on ‘Create’. New pop-up window will appear.                    screen3.jpg

      3.  Now enter the respective values for new custom Attribute:

 

      Attribute:              Enter the Attribute name for i.e. “ZREQ_DOCNO”

      Short Description: Enter Short description “Project1 Transport Attribute”.

 

There are 3 options which need to be selected according to purpose of this attribute:

1.      Attribute Value Obligatory: This specifies whether the attribute can only be assigned with a value. If it is essential that value should be specified for the attribute, then select attribute value obligatory.

2.      Attribute Assigned Externally: If this field is selected, the attribute is assigned using external interfaces only. You can then no longer add this attribute to a request, or delete it from a request. Mostly this option will not be used as we need to track transport requests in SAP.

3.      Attribute can only be assigned once for Each Request: If this field is selected then you can only assign this attribute once for each transport request.

 

We can also make these attributes mandatory to specific development client by mentioning client specific settings.

 

So here we will select option 1 & 3 to create custom attribute: then SAVE.

  screen4.jpg

Now new attribute “ZREQ_DOCNO” will be available for maintenance through SE01.

 

  • How to maintain transport attribute?

1.      Go to SE01. Display transport request.

2.      Go to properties tab of transport and enable change mode.

3.      Attribute “ZREQ_DOCNO” will be available for maintenance in attribute list.

4.      Select the attribute and enter the value for the attribute e.g. If we are creating transport request for DEV1 and requirement document number

          for DEV1 is “R1111” then we can maintain attribute having same value.

            screen5.jpg

We can define Attribute value such as some unique number for each Development for e.g. Design Document number will be different for each development. If we maintain transport attribute value “R1111” (i.e. Requirement Doc. Number) for all transport requests specific to one of the development i.e. DEV1, then it will be easier to track all the transport requests related to DEV1 for production movement.

 

So there will not be any chance of missing any transport request during production movement of the development.

 

                We can find out the list of transport requests having specific attribute value From E070A table:

                 

   screen6.jpg

 

This selection will give list of transports for which Attribute “ZREQ_DOCNO” is maintained with value “R1111” e.g. if there were three transport requests created for DEV1 so this selection will give all the three transports in output.

 

  screen7.jpg

This way we can identify all the transports for specific project or development. Risk for missing transports in the list during production movement will be minimized to great extent.

But there can be a miss, if somebody forgets to maintain attribute for transport request before releasing the request, then what will happen?

Still we will not be able to track that specific transport request for which attribute was not maintained.We can make this Transport Attribute Check mandatory based on few conditions.

 

  • How to make transport attribute maintenance mandatory according to transport description or naming?

Many projects use intelligent naming conventions for Transports. For example Project ID is mentioned in Transport request description or Design Document number is mentioned in Transport description.

 

Now if we make Transport Attribute maintenance mandatory, it will be mandatory check for all projects in specific development box. We can make this check obligatory project-ID specific.

 

  • How to automate the process of Transport Attribute maintenance?

The transport attribute maintenance can be made mandatory project specific by implementing BADI “CTS_REQUEST_CHECK”.

 

CTS_REQUEST_CHECK:  This BADI has multiple methods through which various checks can be implemented for transport requests. Method ‘CHECK_BEFORE_RELEASE’ is called before a transport request is released transport request through SE01 transaction.

By using this method we can implement our own check related to transport request:

1.      1. Check attributes and short text of transport request.

2.      2. Objects included in transport request.

 

      screen8.jpg

         

BADI implementation steps:

Transport request attribute check can be implemented specific to project or according to the short text of transport request. E.g. In development environment , if currently multiple projects are run i.e. Project1,Project2,Project3……Project(n) and we want to make transport attribute maintenance mandatory only for our project (i.e. Project1) which will help in better transport tracking.

In such scenario, we can make TP attribute mandatory for specific project by implementing BADI check.

Many projects use intelligent transport naming conventions (transport request short text). E.g. Transport request description contains PROJECT IDand based on which we can make this attribute check mandatory.

          E.g.        TR1234 (Transport Request) -> DEV: Project1:SE38_ZTESTPROGRAM (Short text)

Now while releasing the transport request TR1234, we can check if transport request short text/description contains our project ID i.e. Project1 in this case. If yes, then check if transports attribute “ZREQ_DOCNO” is maintained for TR1234. If NO, then throw error ‘Please maintain required attribute’, while releasing the request through SE01.

 

We can maintain configuration for which project ID which transport attribute should be maintained, so check can be made dynamic.

1.      1. Create custom table ‘ZATTRICHECK ‘having 2 fields Project ID and Transport Request Attribute.

 

      screen9.jpg

 

2.      2. Maintain ‘ZATTRICHECK ‘table with Project ID (i.e. project which will be present in Transport Request short text) and Transport attribute which 

            needs to  be checked for particular project ID.

   

So for below example, if Transport short text contains “Project1”, then by implementing BADI check can be performed to see whether “ZREQ_DOCNO” attribute is maintained or not while releasing the transport request.

             

      screen10.jpg

3. BADI Implementation Steps:

 

  • Go to transaction SE19 and create BADI implementation for classic BADI “CTS_REQUEST_CHECK”.

     screen11.jpg

  • Implement method CHECK_BEFORE_RELEASE.
  • Source code implementation:

                        1.First check if transport request is “Higher-Level Request”, if transport is Higher-Level then only Attribute check should be performed.This check can be performed by querying E070 table.

                        2.If transport is higher level, then fetch Project ID and Transport Attribute from custom table ‘ZATTRICHECK ‘into internal table.

                        3.Fetch transport attributes maintained for the current transport request from E070A table.

                        4.Check if transport request short text for Project ID in custom table ‘ZATTRICHECK ‘. If short text contains Project ID which is in custom table,then perform further check for transport attribute.

                        5. Check if custom table TP attribute present in Attributes fetched from E070A table for this transport request.

                        6. If transport attribute is not present then populate the error “Please maintain required attribute”.

 

 

  • Implementation Source Code:

*$*$**********************************************************************************************************

*$*$    PROGRAM ID    : ZCTS_REQUEST_CHECK                                                              *   

*$*$    TITLE                : BADI Impl.to check Transport Attribute                                             *     

*$*$    AUTHOR           : SANJANA LINGRAS                                                                       *

*$*$    DESCRIPTION   : BADI implementation to check if required                                          *     

*$*$                               transport attribute is maintained before                                             *   

*$*$                               release of TP.                                                                                 *

*$*$------------------------------------------------------------------------------------------------------------------------------------* 

METHOD if_ex_cts_request_check~check_before_release.

  TYPES:  BEGIN OF y_tpchk,
            zprojid  TYPE zattricheck-zprojid,
            ztpattri TYPE zattricheck-ztpattri,
          END OF y_tpchk,

          BEGIN OF y_attri,
            ztkorr TYPE e070a-trkorr,
            zattri TYPE e070a-attribute,
          END OF y_attri.

  DATA  : t_tpchk TYPE STANDARD TABLE OF y_tpchk,
          t_attri TYPE STANDARD TABLE OF y_attri.

  DATA : w_request    TYPE e070-strkorr,
         w_result_tab TYPE match_result_tab,
         w_flag       TYPE string.

  CLEAR w_request.

  FIELD-SYMBOLS : <fs_tpchk> TYPE y_tpchk,
                  <fs_attri> TYPE y_attri.

  FREE : t_tpchk,
         t_attri.

    SELECT SINGLE          “Check whether TP is higher level request
           strkorr
      INTO w_request
      FROM e070
     WHERE trkorr EQ request.

    IF  sy-subrc  EQ 0
    AND w_request IS INITIAL.

      SELECT zprojid        “Fetch proj.ID and attribute from custom table
             ztpattri
        FROM zattricheck
        INTO TABLE t_tpchk.

      IF sy-subrc EQ 0.

        SORT t_tpchk
          BY zprojid.

      ENDIF.

      IF t_tpchk IS NOT INITIAL.

        SELECT trkorr      “Fetch Attribute for current transport request
               attribute
          INTO TABLE t_attri
          FROM e070a
           FOR ALL ENTRIES IN t_tpchk
         WHERE attribute EQ t_tpchk-ztpattri
           AND trkorr    EQ request.

        IF sy-subrc  EQ 0.

          SORT t_attri
            BY ztkorr
               zattri.

        ENDIF.

      ENDIF.

      UNASSIGN <fs_tpchk>.

      LOOP AT t_tpchk
        ASSIGNING <fs_tpchk>.

        FREE w_result_tab.

 

“Check if transport short text contains project ID which is maintained in custom table.

 

        FIND ALL OCCURRENCES OF SUBSTRING <fs_tpchk>-zprojid IN text
          RESULTS w_result_tab.

        IF  sy-subrc     EQ 0
        AND w_result_tab IS NOT INITIAL.

          READ TABLE t_attri
            ASSIGNING <fs_attri>
            WITH KEY zattri = <fs_tpchk>-ztpattri
            BINARY SEARCH.

      IF  sy-subrc   NE 0  “If attribute is not maintained then throw error
      AND <fs_attri> IS NOT ASSIGNED.

            “Populate error message with Attribute Name
              (WITH <fs_tpchk>-ztpattri)

      ENDIF.

      ENDIF.

    ENDLOOP.

   ENDIF.
  ENDIF.

ENDMETHOD.

 

4.      4. BADI Implementation Result: If developer or functional tries to release transport request without maintaining required transport attribute error will be thrown. User will not be able to release request without maintaining attribute for our specific project.

 

                        screen12.jpg

 

This way we can eliminate the risk of missing the transport in final transport list for production.

 

 

  • Benefits of Transport Tracking:

1. Eliminate the risks:  Proper transport tracking will reduce potential human errors in preparing final transport lists.

2. Save efforts of change management:  If transports are managed properly within the project then it will reduce the burden of change  management which is required for missing transports movement.

3. Cost benefits:  It will reduce the cost which is required for extra change management efforts and rework on transports.

4. Less Rework: Production transport movement will be smoother and no rework will be needed for analysis of issues or errors.

 

Before moving transport list to production it is always a good idea to recheck the list.

 

Preventing transport movement issues and risks before production move is always better than solving them after production move.

 

Keeping the transport list clean and simple will prevent lot of issues arise later on

Understanding Widening Cast in ABAP Objects

$
0
0

There are many discussions about Widening cast in SCN. some say, it is Up casting while other say it is Down casting. I remember in a way as depicted below and still following the same.

 

Let's take a simple inheritance tree.

          inh_tree.jpg

 

Narrowing Cast:

2.jpg

 

Assigning/copying the instance of sub class to super class instance is called Narrowing Cast.

As shown in the figure, assigning sub class to super class is going up wards. From sub class(es) to super class while moving Up the path becomes narrow as shown in the left image. So I simply remember this. Narrowing cast = Up cast .

 

 

 

 

 

 

 

 

Widening Cast:

3.jpg

 

Assigning/coping the instance of super class to the sub class instance is called Widening Cast.

This is the reverse of Narrowing cast. As shown in the figure, assigning super class to sub class is going down wards. From super class to sub class while moving Down the path becomes wider as shown in the left image. So I simply remember this - Widening cast = Down cast.

 

 

 

 

 

 

 

 

I will still remember the above inheritance tree while referring casting and refer Widening cast as Down casting ( though is is referred as up casting from release 7.0).

 

Coming to the topic, I use Widening cast in this blog (instead of up/down casting ) .

 

To understand the Widening cast, I will just explain with the simple program.

 

Simple Inheritance Report
REPORT zkk_widening_cast_demo.

CLASS lcl_parent DEFINITION.
   PUBLIC SECTION.
     METHODS parent_method.

ENDCLASS.                    "lcl_parent DEFINITION

  CLASS lcl_child DEFINITION INHERITING FROM lcl_parent.
   PUBLIC SECTION.
     METHODS parent_method REDEFINITION.
     METHODS child_method.

ENDCLASS.                    "lcl_child DEFINITION

  CLASS lcl_parent IMPLEMENTATION.

   METHOD parent_method.
     WRITE / 'Called -> parent method in Parent Class!'.
   ENDMETHOD.                    "parent_method
ENDCLASS.                    "lcl_parent IMPLEMENTATION


CLASS lcl_child IMPLEMENTATION.

   METHOD parent_method.
     WRITE / 'Called -> parent redifinition method in Child Class!'.
   ENDMETHOD.                    "parent_method
   METHOD child_method.
     WRITE / 'Called -> child method in Child Class!'.
   ENDMETHOD.                    "child_method

ENDCLASS.                    "lcl_child IMPLEMENTATION

  START-OF-SELECTION.

   DATA: lr_parent TYPE REF TO lcl_parent,
         lr_child  TYPE REF TO lcl_child.

   CREATE OBJECT: lr_parent,lr_child.

   lr_parent->parent_method( ).
   lr_child->parent_method( ).
   lr_child->child_method( ).

 

Now after executing this I got the below output:

4.jpg

 

Now I am interested in child(sub) class method in my parent(super) class. Which mean when I call the 'parent_method' of parent class in the above report then it should call the 'parent_method' of child class( Redefined method call instead of original method call). So I do a Narrowing cast.

 

continuing the above report.

 

CREATE OBJECT: lr_parent,lr_child.   WRITE / 'Before Narrowing Cast:'.   lr_parent->parent_method( ).   lr_child->parent_method( ).   lr_child->child_method( ).
 *  Narrowing cast   lr_parent = lr_child.   WRITE / 'After Narrowing Cast:'.   lr_parent->parent_method( ).   lr_child->parent_method( ).   lr_child->child_method( ).

 

Now when I execute the above report, I get the below output, which is as expected.

5.jpg

 

Now I am interested in parent(super) class method in my child(sub) class. Which mean when I call the 'parent_method' of child class in the above report then it should call the 'parent_method' of super class( Super class method call instead of redefined sub class method call). So I do a Widening cast.

 

CREATE OBJECT: lr_parent,lr_child.   WRITE / 'Before Widening Cast:'.   lr_parent->parent_method( ).   lr_child->parent_method( ).   lr_child->child_method( ).   TRY .
 *   Widening Cast     lr_child ?= lr_parent.          WRITE / 'After Widening Cast:'.     lr_parent->parent_method( ).     lr_child->parent_method( ).     lr_child->child_method( ).   CATCH cx_sy_move_cast_error.     WRITE / 'Widening Cast Failed!'.   ENDTRY.

 

The output is as below:

6.jpg

After seeing the above output, we remember that " It is always not possible to do Widening cast as the sub class will have more functionality compared to super class" .

 

So, I removed the method definition 'child_method' in the child class and tried Widening cast. I got the same output!

 

I created an empty class definitions and tried widening cast to see the widening cast success message .

 CLASS lcl_parent DEFINITION.
 ENDCLASS.                    "lcl_parent DEFINITION
 CLASS lcl_child DEFINITION INHERITING FROM lcl_parent.
 ENDCLASS.                    "lcl_child DEFINITION
 CLASS lcl_parent IMPLEMENTATION.
 ENDCLASS.                    "lcl_parent IMPLEMENTATION
 CLASS lcl_child IMPLEMENTATION.
 ENDCLASS.                    "lcl_child IMPLEMENTATION
 START-OF-SELECTION.   DATA: lr_parent TYPE REF TO lcl_parent,         lr_child  TYPE REF TO lcl_child.   CREATE OBJECT: lr_parent,lr_child.   TRY .
 *   Widening Cast     lr_child ?= lr_parent.     WRITE / 'Widening Cast Success!'.   CATCH cx_sy_move_cast_error.     WRITE / 'Widening Cast Failed!'.   ENDTRY.

 

Now we will see the output which we are all waiting for!

10.jpg

 

disappointed? 

 

The above example was taken from one of the tweets of  Uwe Fetzer and is the motivation for writing this blog.

 

7.jpg

 

The Widening cast will always fail unless the assigning instance has the same type of instance to which we are assigning.

 

So people used to tell do Narrowing cast before Widening Cast!, to have the assigning instance same reference.

 

I will take the main report and do a narrowing cast before widening cast.

 

REPORT zkk_widening_cast_demo.
 CLASS lcl_parent DEFINITION.   PUBLIC SECTION.     METHODS parent_method.
 ENDCLASS.                    "lcl_parent DEFINITION
 CLASS lcl_child DEFINITION INHERITING FROM lcl_parent.   PUBLIC SECTION.     METHODS parent_method REDEFINITION.     METHODS child_method.
 ENDCLASS.                    "lcl_child DEFINITION
 CLASS lcl_parent IMPLEMENTATION.   METHOD parent_method.     WRITE / 'Called -> parent method in Parent Class!'.   ENDMETHOD.                    "parent_method
 ENDCLASS.                    "lcl_parent IMPLEMENTATION
 CLASS lcl_child IMPLEMENTATION.   METHOD parent_method.     WRITE / 'Called -> parent redifinition method in Child Class!'.   ENDMETHOD.                    "parent_method   METHOD child_method.     WRITE / 'Called -> child method in Child Class!'.   ENDMETHOD.                    "child_method
 ENDCLASS.                    "lcl_child IMPLEMENTATION
 START-OF-SELECTION.   DATA: lr_parent TYPE REF TO lcl_parent,         lr_child  TYPE REF TO lcl_child.   CREATE OBJECT: lr_parent,lr_child.   WRITE / 'Before Widening Cast:'.   lr_parent->parent_method( ).   lr_child->parent_method( ).   lr_child->child_method( ).   lr_parent = lr_child. " Narrowing cast   TRY .
 *   Widening Cast     lr_child ?= lr_parent.     WRITE / 'After Widening Cast:'.     lr_parent->parent_method( ).     lr_child->parent_method( ).     lr_child->child_method( ).   CATCH cx_sy_move_cast_error.     WRITE / 'Widening Cast Failed!'.   ENDTRY.

 

Now lr_parent has same type of lr_child as we did Narrowing cast. We will see the output:

8.jpg

Wow! widening cast is successful this time. But we can see that this output is same as the output of Narrowing cast shown above (which is not what we required).

 

Because, we have copied the lr_child instance to lr_parent ( lr_parent = lr_child " Narrow cast) before widening cast. Now lr_parent has same type of lr_child and we assign lr_child ?= lr_parent which is noting but copying child class instance to child class instance!

 

So, when this Widening cast is actually useful?

 

To explain this, I will take a simple example using interfaces:

 

REPORT zkk_widening_cast_demo.
 INTERFACE lif_test.   METHODS interface_method.
 ENDINTERFACE.                    "lif_test
 CLASS lcl_myclass DEFINITION.   PUBLIC SECTION.     INTERFACES lif_test.
 ENDCLASS.                    "lcl_class1 DEFINITION
 CLASS lcl_myclass IMPLEMENTATION.   METHOD lif_test~interface_method.     WRITE / 'Interface method call in My Class'.   ENDMETHOD.                    "lif_test~interface_method
 ENDCLASS.                    "lcl_class1 IMPLEMENTATION
 START-OF-SELECTION.   DATA: lr_intf TYPE REF TO lif_test,         lr_mine TYPE REF TO lcl_myclass.   CREATE OBJECT lr_intf TYPE lcl_myclass.   TRY .
 *   Widening Cast       lr_mine ?= lr_intf.       WRITE /'Widening Cast Successful!'.     CATCH cx_sy_move_cast_error.       WRITE / 'Widening Cast Failed!'.   ENDTRY.

 

Output:

9.jpg

Since we cannot directly assign the interface reference to class reference,

 

As using, lr_mine = lr_intf   " will give syntax error because lr_intf is not the same type of lr_mine.

 

So we do a Widening cast, lr_mine ?= lr_intf , which won't give syntax check and at run time if lr_intf contains the same reference of lr_mine, the reference will be copied else the exception will be thrown.

 

Now lets take one more class to understand better.

REPORT zkk_widening_cast_demo.
 INTERFACE lif_test.   METHODS interface_method.
 ENDINTERFACE.                    "lif_test
 CLASS lcl_myclass DEFINITION.   PUBLIC SECTION.     INTERFACES lif_test.
 ENDCLASS.                    "lcl_class1 DEFINITION
 CLASS lcl_yourclass DEFINITION.   PUBLIC SECTION.     INTERFACES lif_test.
 ENDCLASS.                    "lcl_class2 DEFINITION
 CLASS lcl_myclass IMPLEMENTATION.   METHOD lif_test~interface_method.     WRITE / 'Interface method call in My Class'.   ENDMETHOD.                    "lif_test~interface_method
 ENDCLASS.                    "lcl_class1 IMPLEMENTATION
 CLASS lcl_yourclass IMPLEMENTATION.   METHOD lif_test~interface_method.     WRITE / 'Interface method call in Your class'.   ENDMETHOD.                    "lif_test~interface_method
 ENDCLASS.                    "lcl_class2 IMPLEMENTATION
 START-OF-SELECTION.   DATA: lr_intf TYPE REF TO lif_test,         lr_mine TYPE REF TO lcl_myclass,         lr_your TYPE REF TO lcl_yourclass.
 *  CREATE OBJECT lr_intf TYPE lcl_myclass.   CREATE OBJECT lr_intf TYPE lcl_yourclass.    TRY .
 *      Widening Cast        lr_mine ?= lr_intf.        WRITE /'Widening Cast Successful!'.      CATCH cx_sy_move_cast_error.        WRITE / 'Widening Cast Failed!'.    ENDTRY.

 

In this case the widening cast will be failed since lr_intf is not of same type as lr_mine.

 

We use widening cast mainly while dealing with interfaces and in case of dynamic programming.

 

Now, If we look at the below statement

 

CREATE OBJECT lr_intf TYPE lcl_yourclass.    TRY .
 *      Widening Cast        lr_mine ?= lr_intf.        WRITE /'Widening Cast Successful!'.      CATCH cx_sy_move_cast_error.        WRITE / 'Widening Cast Failed!'.    ENDTRY.

 

is nothing but Narrowing cast before widening cast,

DATA lr_mine1 TYPE REF TO lcl_myclass.   CREATE OBJECT lr_mine1.   lr_intf = lr_mine1.  " Narrowing Cast   TRY .
 *      Widening Cast       lr_mine ?= lr_intf.       WRITE /'Widening Cast Successful!'.     CATCH cx_sy_move_cast_error.       WRITE / 'Widening Cast Failed!'.   ENDTRY.

 

So in this context, "Do Narrowing cast before Widening cast"  makes sense without confusion!

 

Hope I tried to explain Widening cast to some extent!.  Comments are welcome

Background jobs with users for authorization - report

$
0
0

Recently I had an issue to make an report for background jobs that are planned to run from dialog user. All informations I needed was in transaction sm37, but for every job I had to double click on it and go to 'step' options to check background user name. I made an ABAP program which make this report for me. Some of those jobs have more than one step, my report takes them into account. Here you have my program code, to make it working you have to create screen with container for alv list, gui status, and structures in se11: zbackground_jobs and zbackground_jobs_3f. Screenshots with structures and gui are attached.

 

Background jobs report

REPORT Z_BGJ_REPORT.

data: container_r type ref to cl_gui_custom_container,

       grid_r type ref to cl_gui_alv_grid.

 

data: it_bgj type table of zbackground_jobs,

       it_bgjt type table of zbackground_jobs_3f,

       wa_bgj type zbackground_jobs,

       wa_usr02 type usr02,

       wa_tbtcpv type tbtcpv.

 

select JOBNAME JOBCOUNT STATUS from TBTCO into corresponding fields of table it_bgjt where status = 'S'.

 

Loop at it_bgjt into wa_bgj.

   select * from tbtcpv into wa_tbtcpv where JOBCOUNT = wa_bgj-JOBCOUNT and JOBNAME = wa_bgj-JOBNAME.

     wa_bgj-AUTHCKNAM = wa_tbtcpv-AUTHCKNAM.

   select single * from usr02 into wa_usr02 where bname = wa_bgj-authcknam.

     wa_bgj-ustyp = wa_usr02-ustyp.

   append wa_bgj to it_bgj.

   endselect.

endloop.

 

call screen 321.

 

*&---------------------------------------------------------------------*

*&      Module  alv_pbo_876  OUTPUT

*&---------------------------------------------------------------------*

*       text

*----------------------------------------------------------------------*

MODULE STATUS_0321 OUTPUT.

   SET PF-STATUS 'LIST_STATUS'.

   if container_r is initial.

CREATE OBJECT CONTAINER_R

   EXPORTING

*    PARENT                      =

     CONTAINER_NAME              = 'ALV_CONTAINER'

*    STYLE                       =

*    LIFETIME                    = lifetime_default

*    REPID                       =

*    DYNNR                       =

*    NO_AUTODEF_PROGID_DYNNR     =

*  EXCEPTIONS

*    CNTL_ERROR                  = 1

*    CNTL_SYSTEM_ERROR           = 2

*    CREATE_ERROR                = 3

*    LIFETIME_ERROR              = 4

*    LIFETIME_DYNPRO_DYNPRO_LINK = 5

*    others                      = 6

     .

IF SY-SUBRC <> 0.

* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO

*            WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.

ENDIF.

 

CREATE OBJECT GRID_R

   EXPORTING

*    I_SHELLSTYLE      = 0

*    I_LIFETIME        =

     I_PARENT          = container_r

*    I_APPL_EVENTS     = space

*    I_PARENTDBG       =

*    I_APPLOGPARENT    =

*    I_GRAPHICSPARENT  =

*    I_NAME            =

*    I_FCAT_COMPLETE   = SPACE

*  EXCEPTIONS

*    ERROR_CNTL_CREATE = 1

*    ERROR_CNTL_INIT   = 2

*    ERROR_CNTL_LINK   = 3

*    ERROR_DP_CREATE   = 4

*    others            = 5

     .

IF SY-SUBRC <> 0.

* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO

*            WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.

ENDIF.

 

   CALL METHOD GRID_R->SET_TABLE_FOR_FIRST_DISPLAY

     EXPORTING

*      I_BUFFER_ACTIVE               =

*      I_BYPASSING_BUFFER            =

*      I_CONSISTENCY_CHECK           =

       I_STRUCTURE_NAME              = 'zbackground_jobs'

*      IS_VARIANT                    =

*      I_SAVE                        =

*      I_DEFAULT                     = 'X'

*      IS_LAYOUT                     =

*      IS_PRINT                      =

*      IT_SPECIAL_GROUPS             =

*      IT_TOOLBAR_EXCLUDING          =

*      IT_HYPERLINK                  =

*      IT_ALV_GRAPHICS               =

*      IT_EXCEPT_QINFO               =

*      IR_SALV_ADAPTER               =

     CHANGING

       IT_OUTTAB                     = IT_BGJ

*      IT_FIELDCATALOG               =

*      IT_SORT                       =

*      IT_FILTER                     =

*    EXCEPTIONS

*      INVALID_PARAMETER_COMBINATION = 1

*      PROGRAM_ERROR                 = 2

*      TOO_MANY_LINES                = 3

*      others                        = 4

           .

   IF SY-SUBRC <> 0.

*   Implement suitable error handling here

   ENDIF.

   endif.

 

ENDMODULE.                 " alv_pbo_321  OUTPUT

*&---------------------------------------------------------------------*

*&      Module  USER_COMMAND_0321  INPUT

*&---------------------------------------------------------------------*

*       text

*----------------------------------------------------------------------*

MODULE USER_COMMAND_0321 INPUT.

case sy-ucomm.

     when 'E'.

       leave to screen 0.

     when 'B'.

       leave program.

     when 'C'.

       leave program.

   endcase.

ENDMODULE.                 " USER_COMMAND_0321  INPUT


 

If you have problem to run this code - just look what tables I am using and make a report on your own or just review the tables.

Good luck!

 

Regards

Gabriel

Survey Bachelor Thesis - Security Risks in the SAP Environment

$
0
0

Dear SAP Community,


My name is Rick Trojahn and I study Business Informatics. I am currently working on my bachelor thesis. Therefore I created a survey on security risks in the SAP environment. I am having problems to find SAP programmers who would like to participate in my survey therefore any help will be highly appreciated!!!


 

A tutorial on how to use the survey can be found here: www.ricktrojahn.com/survey-tutorial.pdf

 

The survey itself can be found here: www.ricktrojahn.com/survey.xls

 


 

It would be nice of you to return the completed survey via email (see my account)

 

 

Thank you so much for your participation! If you have any questions feel free to contact me.

 

 

Kind Regards

Rick Trojahn

MS-Office change Layout using Open XML for SAP

$
0
0

Hello.

Often when we create documents Templates we are

wasting a lot of time and effort on visualize these documents.

In the screen cast below there is an example of how easy it

could be with using Open XML for SAP, to change some

Visual attributes of the Template.

 

 

This just one demonstration of a lot of Visual Attributes

we can have in using MS-Office with SAP.

In the blogs to come

I will try to give some more examples.

 

   Ronen Almog

Use of Standard SAP function modules in custom development

$
0
0

Hello,

 

I work on SAP Product Support. There are several incidents opened by customers related to the use of Standard SAP function modules (FM) in custom development. Basically they use a standard FM in their custom code and it does not work as they expected, then they open an OSS message asking why it does not work as they wish. My goal with this post is to share some information about FM not released for customer's use, since there are several customers that are not aware of this restriction.

 

When considering to use standard SAP FM in custom development, firstly it is advisable to check if it is released (or not) for customer' use. It is possible to check check it in tab "Attributes" when displaying the function module in transaction SE37, as shown below:

notreleased1.PNG

 

In the sample above, function module RS_VARIANT_DISPLAY is not released for customer use, hence not supported. When a function module is flagged as "Not released", SAP recommends that customers avoid using this object in their custom code. However, it is not forbidden. You can use this function as it is a global function. However, it will not be supported by SAP if it does not work as you expected. Besides, SAP might change, remove or rename this object at anytime by an upgrade or support package.

 

So it is kind of useless to open an OSS message in such cases. However, there are some alternatives:

  1. Look for a standard functionality that can be used instead;
  2. Develop the desired functionality on your own by a custom development;
  3. Create a copy of standard function and use it. Then you can adjust it as you need.

 

Further information can be found on the following notes:

SAP Note 109533 - Use of SAP function modules

SAP KBA 1909989 - Standard SAP function modules do not work as expected in custom development

 

Best regards,

Maurício Grisa.

Shortcuts that can make an ABAP'er life easier

$
0
0

Introduction

 

ABAP is quite different from many contemporary programming languages in several ways. Some aspects of ABAP would make us wonder why is it made this complex while some aspects are so awesome and more comfortable for a programmer than any other language can provide.

 

Two of those things that I find so cool are:

  • Its ingenuous IDE (ABAP Editor) and
  • Its cool Debugger

 

Eventhough the SAP IDE does not support some of the features which more prominent IDE's like Eclipse etc have, I find it so comfortable to code in ABAP Editor compared to others. The reason is because of the below shortcuts and customizations available with it. I am listing the few which I use constantly and without which I cannot think of coding ABAP.

 

Most of the programmers even with a little bit of ABAP experience would have come accross the details listed here. If you have, please ignore and if you haven't then the stage is yours..

 

Shortcut

What it does

Ctrl + D

Duplicate any line.

eg. i_vbap TYPE STANDARD TABLE OF vbap + Ctrl-D = i_vbap TYPE STANDARD TABLE OF vbap
i_vbap TYPE STANDARD TABLE OF vbap

Ctrl + /

Jump to the "command field" where we enter t-codes. This comes really handy and saves a jump from keyboard to mouse and back to keyboard just to click on the box.

Ctrl + J

Convert to Proper case where the first letter of every word becomes a capital letter. This is pretty useful when writing comments.

eg.  * this is a comment which will give absolutely no useful information will be changed to
* This Is A Comment Which Will Give Absolutely No Useful Information

Ctrl + I  &
Ctrl + Shift + I

Incremental search. This is a little improved 'Find' (Ctrl + F) function which searches as soon as you type. Useful for impatient people. Add shift to search backwards.

Ctrl + K

Toggle between Upper case and Lower Case.

Alt + Selection

This is useful in situation where you need to select only the field names of a particular table.

eg.

caufv-aufnr,

caufv-werks,

caufv-objnr,

caufv-plnbez,

caufv-gamng,

caufv-gasmg,

caufv-gmein,

caufv-plnnr,

caufv-plnal,

caufv-dispo,

caufv-fevor,

caufv-cy_seqnr ,

caufv-aufpl,

caufv-gstrp,

caufv-gltrp,

caufv-gstrs,

caufv-gltrs,

caufv-gstri,

caufv-gltri,

 

In these values, u can select only the field names by pressing Alt key and get the clipboard filled like this.

 

aufnr,

werks,

objnr,

plnbez,

gamng,

gasmg,

gmein,

plnnr,

plnal,

dispo,

fevor,

cy_seqnr ,

aufpl,

gstrp,

gltrp,

gstrs,

gltrs,

gstri,

gltri,

Tab & Shift tab

Increase and Decrease Intend

Ctrl + O

Goto a particular line in the program

Ctrl + Shift + S

Save your program in Desktop in .abap format. I came know about .abap only after learning this short cut.

Ctrl + Selection

When you do a selection with **** + -> or <- hold on to Ctrl to jump every word in that direction.

Ctrl + . & Ctrl + ,

Comment and Un-Comment selected lines.

Ctrl+Alt+T

Swaps current line with the Upper Line.
eg. INCLUDE ZTEST_ABAP_HTTP_CLIENT_TOP.
     INCLUDE ZTEST_ABAP_HTTP_CLIENT_C01. becomes


INCLUDE ZTEST_ABAP_HTTP_CLIENT_C01.
INCLUDE ZTEST_ABAP_HTTP_CLIENT_TOP.

Ctrl+Shift+L/XDeletes the whole line

 

More Editor Tools:

 

Apart from this, there are a few other things that can be set in Editor options

 

 

like,

 

Code Templates

 


 

 

Here I use a template for the text. This could be a text that is used for marking modifications or Defenition and implementation of local classes etc.


  * Begin of Insertion <SID>K12345 <username>
* End of Insertion   <SID>K12345  <username>

 

i.e when I press i* in the editor, it will prompt for code completion..

 


 

When I press Tab for completion, it pops up for TR Number…

 

 

The TR number that we give will be added in the comment.


Variable Name Suggestions

This is just a small setting but it will save you from Copy pasting or re-typing small words.

 

When you check this box, it will suggest even for variable names like…

 

Particularly useful for longer variable names.

 

 

Conclusion

 

Apart from the editor and debugger functions, the navigation and where used-list  are other funtionalities which we use more often. Especially the code maintenance and support activities are comparitively less hectic just because these features.

 

Another cool way to extend its core editor functionality for customizations could be by providing API's even for the application programmers to code and customize the editor features. It will also add to the creativity aspect on SAP side since any third programmer could come with an awesome idea as an editor extension.

 

As far as I have explored, I havent found any BADI or classes which can be used to perform editor functions. May be I have to look more or wait...



Survey Bachelor Thesis - Security Risks in the SAP Environment

$
0
0

Dear SAP Community,


My name is Rick and I study Business Informatics. I am currently working on my bachelor thesis. Therefore I created a survey on security risks in the ABAP Code. I am having problems to find SAP programmers who would like to participate in my survey therefore any help will be highly appreciated!!!

 


 

A tutorial on how to use the survey can be found here: www.ricktrojahn.com/survey-tutorial.pdf

 

The full survey itself can be found here (20 minutes): www.ricktrojahn.com/survey.xls

 

The short version survey can be found here (5 - 10 minutes):https://docs.google.com/forms/d/1y_hqb0QIcmuFs_IVE2BdRSrHDBYp_HPzs2dSMgnh0wk/viewform


 

It would be nice of you to return the completed full survey via email (see my account)

 

 

Thank you so much for your participation! If you have any questions feel free to contact me.

 

 

Kind Regards

Rick

Create flexible database tables for your applications.

$
0
0

Most of us today, working on SAP solutions have to create custom applications. These applications may be simple program to as complex as designed across multiple SAP / Non-SAP systems. One of the most important design requirements to tackle for these custom applications is the application configuration. If it is custom, 90% of the cases require custom configurations on which the application runs. These configurations also validate the underlying assumptions on which the application is designed.

 

Sometimes these configurations might be so small that they end up as constants or hard coded values. Sometimes they might end up as tables. The main problem is to understand how to define these configurations so that the code consuming it can remain generic to support reuse, scalability and flexibility objectives.

 

In my early days as a developer I was responsible for developing configuration and logic, which would for the first time be consumed by one application but over the years the same would be used by multiple similar applications. I was lucky to have a seasoned SAP developer who was collaborating with me on this development. He told me that from his experience for the first and may be even second time when we are designing these models it is very difficult to make them generic and I second that thought since it is very difficult for the application teams to have that long a vision about the applications as well as the availability of time to accomplish the same.

 

Also most of the teams across the world are switching onto Agile Development methodologies (which most of them abuse) in which the requirements and design evolve over a period of time, it is more than necessary to make the foundation (configuration) flexible enough to reduce the impact of continuous
change.

 

So here I used several learning’s from the past and came out with a concept which is flexible enough to work in any application that you create and is complimented by similar code support in other development languages like JAVA.

 

 

The case with which I want to explain this concept is that of a website. I have to create a website which will be used to sell my products in multiple subsidiaries. Each subsidiary will have its specific pricing, promotions, quota logic, order types and a lot more. For simplicity sake I will take examples of Switzerland and Germany. Apart from business logic, I want to reuse the code that I am developing for my site like the UI rendering language and other things. I also have web services to integrate my SAP backend with the site (another blog would come up soon to talk about creating just one web service to cater to all logic).

 

So how do I define my application configuration:-

 

 

  • Create a database table with some key fields ( I would use just one string or char field to store values like SWISS_UI, SWISS_PRICING, SWISS_QUOTA, SWISS_ORG, GERMAN_ORG etc) which can help you create unique config types.

 

  • Have a string define which will store all the attributes as an XML string.

 

  • Create a XSLT transformation to encode and decode the XML string.

 

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>

<xsl:template match="/">

<xsl:copy-of select="."/>

</xsl:template>

</xsl:transform>

 

  • Have a mapping structure which is a universal set of all relevant attributes related to a config type.

 

  • Create a setter ( an FM, Report, Class Method – Most preffered ) which will generate the record for the table

   
data
: tab1 type ref to data,
vbak_tab
type table of vbak,
vbak_wa
type vbak.

create data tab1 type table of vbak.

field-symbols : <tab1> type any table.

assign tab1->* to <tab1> .

select * from vbak into table <tab1> up to 1 rows.

call TRANSFORMATION transformation
SOURCE record_data
= <tab1>
result xml xml_string
.

 

 

  • Create a getter that will read the config record and reverse transform into my mapping structure which can be consumed in relevant areas of my application.

 

Call TRANSFORMATION transformation
source xml xml_string
result record_data
= <tab1>.

 

  • To map you can also use CL_ABAP_TYPEDESCR class to create another layer of generic code.

 

So this is a just a concept which you can use in your applications. You can also use it to create custom log tables, staging tables just anything where you are working with an evolving data model. Do comment if you have used any other similar approach for creating applications.

How to log any changes in MM01/MM02 customer subscreen and table

$
0
0

Sometimes clients need to log any changes made by user on customer created screen and Z table in MM01/MM02.

 

You can do it by activate user-exit at save (for example):

at user-exit insert your code:

            CALL FUNCTION 'ZMM_ZMMLABEL_CREATE_LOG'
            EXPORTING
              i_matnr     = rmmg1-matnr
              i_werks     = rmmg1-werks
              i_change_id = ('I' for insert new record, 'D' when you delete record, 'U' for update)

              i_zmmlabel  = l_zmmlabel.

 

and you must create FM:

   FUNCTION zmm_zmmlabel_create_log .
*"----------------------------------------------------------------------
*"*"Update Function Module:
*"
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(I_MATNR) LIKE  RMMG1-MATNR
*"     VALUE(I_WERKS) TYPE  RMMG1-WERKS
*"     VALUE(I_CHANGE_ID) TYPE  CDHDR-CHANGE_IND
*"     VALUE(I_ZMMLABEL) TYPE  ZMMLABEL
*"----------------------------------------------------------------------
  DATA: lt_zmmlabel   LIKE TABLE OF zmmlabel,
        zmmlabel_old  LIKE zmmlabel,
        objectid      LIKE cdhdr-objectid,
        objectclass   LIKE cdhdr-objectclas,
        tablename     LIKE cdpos-tabname,
        change_id     LIKE cdhdr-change_ind.


*  MOVE-CORRESPONDING i_zmmlabel TO zmmlabel.

  tablename   = 'ZMMLABEL'.
  objectid    = i_matnr.
  objectclass = 'MATERIAL'.

* Manage change document
  IF i_change_id = 'D'.
    CLEAR i_zmmlabel.

    SELECT * FROM zmmlabel INTO TABLE lt_zmmlabel
     WHERE matnr   = i_matnr
       AND werks   = i_werks.

    IF sy-subrc = 0.
      LOOP AT lt_zmmlabel INTO zmmlabel_old.

        CALL FUNCTION 'YMM_CREATE_CHANGE_DOCUMENT'
          EXPORTING
            objectclass      = objectclass
            objectid         = objectid
            tablename        = tablename
            workarea_new     = i_zmmlabel
            workarea_old     = zmmlabel_old
*            change_indicator = i_change_id
            change_indicator = 'U'. " if you need log all changes, please use U mode
        COMMIT WORK.

        CLEAR zmmlabel_old.
      ENDLOOP.

      DELETE zmmlabel FROM TABLE lt_zmmlabel.

      COMMIT WORK.
*      COMMIT WORK AND WAIT.
    ENDIF.

  ELSEIF i_change_id = 'U'.

    SELECT SINGLE * FROM zmmlabel INTO zmmlabel_old
     WHERE matnr   = i_matnr
       AND werks   = i_werks
       AND counter = zmmlabel-counter.

    CALL FUNCTION 'YMM_CREATE_CHANGE_DOCUMENT'
      EXPORTING
        objectclass      = objectclass
        objectid         = objectid
        tablename        = tablename
        workarea_new     = i_zmmlabel
        workarea_old     = zmmlabel_old
        change_indicator = i_change_id.

    COMMIT WORK.

    MODIFY zmmlabel FROM i_zmmlabel.

    COMMIT WORK.

*    COMMIT WORK AND WAIT.

  ELSEIF i_change_id = 'I'.
    CLEAR zmmlabel_old.

    CALL FUNCTION 'YMM_CREATE_CHANGE_DOCUMENT'
      EXPORTING
        objectclass      = objectclass
        objectid         = objectid
        tablename        = tablename
        workarea_new     = i_zmmlabel
        workarea_old     = zmmlabel_old
*            change_indicator = i_change_id
        change_indicator = 'U'. " if you need log all changes, please use U mode

    COMMIT WORK.

    MODIFY zmmlabel FROM i_zmmlabel.

    COMMIT WORK.

*    COMMIT WORK AND WAIT.

  ENDIF.
ENDFUNCTION.

 

   FUNCTION YMM_CREATE_CHANGE_DOCUMENT.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(OBJECTCLASS) LIKE  CDHDR-OBJECTCLAS
*"     VALUE(OBJECTID) LIKE  CDHDR-OBJECTID
*"     VALUE(TABLENAME) LIKE  CDPOS-TABNAME
*"     VALUE(WORKAREA_NEW) DEFAULT SPACE
*"     VALUE(WORKAREA_OLD) DEFAULT SPACE
*"     VALUE(CHANGE_INDICATOR) DEFAULT 'U'
*"----------------------------------------------------------------------

  call function 'CHANGEDOCUMENT_OPEN'
       exporting
            objectclass      = objectclass
            objectid         = objectid
       exceptions
            sequence_invalid = 1
            others           = 2.
  call function 'CHANGEDOCUMENT_SINGLE_CASE'
       exporting
            tablename              = tablename
            workarea_old           = workarea_old
            workarea_new           = workarea_new
            change_indicator       = change_indicator
       exceptions
            nametab_error          = 1
            open_missing           = 2
            position_insert_failed = 3
            others                 = 4.
  case sy-subrc.
    when 1. message a850(m3) with 'NAMETAB-ERROR'.
    when 2. message a850(m3) with 'OPEN MISSING'.
    when 3. message a850(m3) with 'INSERT ERROR'.
    when 4. message a850(m3) with 'SINGLE ERROR'.
    when others.
  endcase.
*
  udate = sy-datum.
  utime = sy-uzeit.
  tcode = sy-tcode.
  username = sy-uname.
*
  call function 'CHANGEDOCUMENT_CLOSE'
       exporting
            objectclass             = objectclass
            objectid                = objectid
            date_of_change          = udate
            time_of_change          = utime
            tcode                   = tcode
            username                = username
            object_change_indicator = change_indicator
       exceptions
            header_insert_failed    = 1
            object_invalid          = 2
            open_missing            = 3
            no_position_inserted    = 4
            others                  = 5.

  case sy-subrc.
    when 1. message a850(m3) with 'INSERT HEADER FAILED'.
    when 2. message a850(m3) with 'OBJECT INVALID'.
    when 3. message a850(m3) with 'OPEN MISSING'.
    when 5. message a850(m3) with 'CLOSE ERROR'.
    when others.
  endcase.

ENDFUNCTION.

How to Implement Function Module Exits using BADI

$
0
0

Hi Developers ,

 

Consider a scenario in which you are going to create BADI definition as well for a customer exit.

Here are the steps:

 

a ) Find out the correct customer exit for your requirement from the functional team.


      1.png

 

b ) Create enhancement in CMOD and activate the components. (See below screens)

 

     2.png

       3.png

 

         4.png

 

c)   Go to SE18 and create a BADI definition.

       5.png

d)  Create an instance method (public) for the BADI with parameters (if needed).

        

       6.png

          7.png

 

e)  Create implementation for the BSDI.

 

                8.png

 

                    

                     9.png

 

f)     Here, see the method (public) created in definition is already assigned to your implementation (EXIT_SAPLFMR4_002).

 

               10.png

               

g )  Apply the validation in the public method and business logic in private method. Call the private method in the public method after validation.

         

               11.png

 

                 12.png


Now, next step is how to call the BADI from the customer exit.

                         

                       

a)  Go to your customer exit program.

                      

                     13.png

 

b)  Create an instance of your BADI interface and call the public method (e.g. EXIT_SAPLFMR4_002).

      

                     14.png

                       15.png

 

c) The BADI (ZBADI_ZXFMCU08) is multiple uses BADI. In future if there requirements for the same customer exit, create a new implementation and a private method to apply logic in the BADI.

 


Hope this blog will prove helpful ,Pls feel free to reach out for anything !

 

 

 

Thanks and Regards,

Praveen Srivastava

Get RFC Destination Dynamically in SAP ABAP

$
0
0

Function module to get RFC destinations.

 

In CRM system FM CRM_AV_CHECK_R3_GET_DESTIN  can be used to get destination as follows,

 

  Data: lv_dest     type rfcdest.

  call function 'CRM_AV_CHECK_R3_GET_DESTIN'
      importing
        ev_destination  = lv_dest
      exceptions
        invalid_release = 1
        others          = 2.


  Another way in CRM side,

 

  DATA: lt_erpsites  TYPE STANDARD TABLE OF  smof_erpsh,
        ls_erpsites  TYPE    smof_erpsh, 
        lv_dest  TYPE   rfcdest. 
   
* * Read ERP destination
  CALL FUNCTION 'SMOF_READ_SMOFERPSH'
    EXPORTING
      i_sitetypeid = 'SMOF_ERPSITE'
      i_mandt      = sy-mandt
    TABLES
      t_erpsites   = lt_erpsites.
 
  READ TABLE lt_erpsites INTO ls_erpsites INDEX 1.
  lv_dest = ls_erpsites-rfcdest.

 

 

In ECC system FM CRM0_READ_RFC_DEST  can be used to get destination as follows,

 

  Data: lt_dest   type table of CRMRFCPAR.

  CALL FUNCTION 'CRM0_READ_RFC_DEST'
    EXPORTING
      I_CONSUMER             = 'CRM'
      i_download_type          = ' '
      i_objname                   = ' '
    tables
      t_crmrfcpar           = lt_dest.

 

From the lt_dest internal table we have to pick the rfcdest value.

 

A Dream for SE80 - Github Integration

$
0
0

When I heard Code Exchange was closing, I was bummed.  I read that a new code exchange 2.0 is being developed, but as I write this it is still under construction.  As many people have pointed out, however, that doesn't need to stop SAP developers from sharing code with one another.

 

For us ABAPers, we have few choices on how to share code and it's not easy to share non-code development objects.  I can copy-paste a simple program from any forum, but what if that program has a dozen custom data elements and a few custom global classes?  Well, thanks to the fantastic SAPLink project (with which I am not affiliated), that's gotten a lot easier.  It's as easy as downloading a .nugg file and importing it, or so I hear.

 

I want to take the idea behind SAPLink one step further.  Instead of searching the web via browser (and by the web, I mean Google Code and Github) for a .nugg file, downloading it to a file directory, and importing it via SAPGUI, can't we do this all from SAPGUI?  We're trying to share code, so why not search the web in the place where we work on the code, i.e. SE80?  If you're thinking, "That's not where I work on the code!  I use Eclipse!" well, good for you.  I hope to join your smug ranks soon, but most of what I'm proposing is probably applicable to Eclipse development too.

 

So rather than spending 5 minutes explaining it, I spent half an hour stumbling through MS Paint, drawing what I had in mind.

 

Github Mockup SCN.png

 

Seriously, how cool would this be?

 

From what I can tell, although it's not possible to add tools to SE80 like this, it would still be very helpful to copy the general UI into another transaction.  It could have two or three pushbuttons on the left like SE80, but they would be along the lines of Github Repositories, Search Github, and Package Browser.  From github repositories, you could view your own repos.  Search Github would return a results list of repos, from which you could view the contents, readme, and import as an SAP development package.  Package Browser would allow a user to select and push his or her development packages to github.

 

Right now I'm thinking a 1-to-1 ratio of packages to repositories would work best for code management and sharing.  If I download/clone a repository, it becomes a package, and if I push a package to github, it becomes a repository, and any subpackages do not - they are just part of the .nugg file.

 

There are a few problems that need answers if this will get developed, such as how to handle the github readme files, but boy howdy, this would be a dream come true.

 

If this were developed, would you use it?  What other features would you like to see?

Do Quality Processes really matters ?

$
0
0

"Do the Quality processes in SAP projects really matters ? ",this is  a basic question which strike to my mind,while I was sitting in the Quarterly Audit for my project."You have to update the object tracker regularly and also the defect tracker with all the efforts and if missed that will amount to Non-conformance of the quality process;The WBS of the project should be evident ;where are you putting all the efforts for TS review ? " , screamed the Auditor.

   These questions appeared to me as volleys, from which I have to safeguard my head;otherwise it would definitely strike the Head ! 

 

But do we really follow Quality processes in our projects and fill the documents in timely manner ? Or, is it simply a Historical and manipulated Data ?

And what benefit, it will provide to the project in continuous improvement ?

 

Now-a-days,in the SAP Projects - whether Implementation or Support - the environment is very challenging and more and more stressful.Every now and then there are rapid changes in the requirements and sometimes, it is seen that after the long development period of 3 months, finally the object is scrapped and it is no more required.Or otherwise, it is found that although the development is correct but the old version of the object was better;so switch to the older version  and comment the latest one ! So how you define the SDLC for this ? Within the Quality perspective,first you have to develop a technical specification or a technical design for the object and then jump to coding.But, if the requirements keeps on changing and no test data is given ? then , what should be the approach ?

 

The most favorite Question that is asked in the Audit is - "what is your delivery process ?" ."How do you deliver the object to the end customer ?" . The real problem arises when the customer do not follow any specific process and your Quality Department is adamant on following s set of processes. "We are a CMMI Level 5 company and we cannot compromise with any non-conformance of the Quality Process ", adds the QA of the project. So, how to strike a balance between the two flippers - Client and the Quality Deptt. ? Finally, what is the solution ? Is it right that you feel always overburdened with the lot of Work and always face the dilemma of managing the start date and end date of a object and its representation in the object tracker ! 

 

The purpose of the quality system of a company - I feel - is to facilitate the smooth delivery to the client and definitely of High Quality.To ensure this, there must be - what we call it as adaptation- just like in Agile Development.The Quality processes should not be blindly followed,but,rather be adapted to the client requirements and delivery processes.It must not be the case of too many processes or no process.In this way,only, the QMS may  achieve its basic organisational  goal of 'High Quality Delivery" . Till this thought is put into consideration,our Team Leads and Manager will surely have a hard time with QA !

 

 

I still feel that the debate is still not over for this moot point and would certainly like to hear the voices of fellow members and their thoughts.Please feel free to share your expression on  this.


SAPLink plugin for Workflow objects

$
0
0

Recently I found myself as a SAPLink user- a client of mine was not offering a remote access and at the same time they were expecting some pilot solution ASAP. So I had to do developments in a comercially accessible IDES system and then tranport it to the client's. And as Workflow was involved I had to trasnport not only conventional ABAP code but also a number of Workflow objects. Unfortunately I did not find a plugin for Workflow objects and so I had to develop one.

Those who need it feel free to download attached XML file which is actually a NUGGET containing 4 classes for export/import Workflow objects: Standard Tasks (object PDTS), Agent determination rules (object PDAC), and Workflow templates (object PDWS).

This all is just out of the oven, so let's say it's in "alpha".

Tested on NW 7.02.

Creation of Custom Collective Search help

$
0
0

Creation of the Blog post  :


I want to share you some points regarding Creation of Custom Collective Search help :

 

Actual Requirement :

 

My requirement is to develop a Custom Module pool screen where I need to attach Collective Search help for a field in a Table Control, where the user may select Material/Asset from the F4 option(where Material and Asset have no relation ship maintained).

 

Procedure :

 

1) Initially I have tried to create two elementary search helps for Material & Asset .

    

    You can look into the below URL to create Elementary Search help.

 

http://help.sap.com/saphelp_nw04/helpdata/en/cf/21ee5f446011d189700000e8322d00/content.htm

 

2) I have attached these Elementary Search helps for a Collective Search help.

 

Here I want to share you some useful points which may help us

 

DEFINITION & INCLUDE SEARCH HELPS plays a vital role in Creation of Collective Search help.

 

 

DEFINITION (Steps to follow in Definition Tab) ::::

 

 

I need to get both the material/asset on a single field where the data elements of material & asset are different.

 

->  Then Declare a Standard or Custom data type which can hold the different data elements.

 

For Example : Material has Data type CHAR & Size 18

                                  Asset         has Data type CHAR & Size 10.

 

So I have taken a Standard data element /BCV/SIN_CHAR018 which can hold both the data elements .

CAP1.JPG

->Give a TEXT in Search help parameter

->Tick Importing & Exporting

->Provide the relevant data element

 

    

INCLUDE SEARCH HELPS (Steps to follow in Include Search help Tab) ::::

 

-> Provide our Elementary Search helps as shown in below screen

 

CAP2.JPG

 

Select single Search help and click on Param.assignment as shown above.

Then you will get these below screen shots.

CAP3.JPGCAP4.JPG

 

 

And Click on OK and SAVE & ACTIVATE.

 

Finally activate all the Inactive objects and EXECUTE.


 

 

CAP5.JPG

 

CAP6.JPG

 

 

By this you can achieve the Collective Search help for different data elements where there are no relation ship between the two .

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

mockA repuplished

$
0
0

Disruption

As you might have noticed, I removed the mockA repository at Github. I did this as as a precation to avoid licensing issues.

As these questions are clarified now, mockA is available again at https://github.com/uweku/mockA.

 

What is mockA?

mockA is a free Mocking Framework for ABAP published under Apache License v2

For tutorials and further information please see

mockA tutorial – How to create fakes
mockA tutorial - How to create mocks

 

I'm sorry for the disruption, but it looks like all open questions are adressed and clarified now. So mockA will remain at the public Github site and can be downloaded and extended by everyone.

 

Enjoy!

IoC implemented

$
0
0

Challenge

Yesterday we had an interesting discussion about the following requirement: There is an application which consists of a webdynpro UI and a backend model. The backend model is described by an interface ZIF_SOME_BACKEND_MODEL which is implemented by some specific classes ZCL_BACKEND_MODEL_A and ZCL_BACKEND_MODEL_B. Backend A and Backend B are performing their tasks quite differently, however, the UI does not really care about this fact, as it uses only the interface ZIF_SOME_BACKEND_MODEL.

IoC implemented - Initial situation.PNG

Model A and B may be switched depending on some constraints which can be defined by the user but which we are not discussing here.

In case the application uses that backend model A in the backend, everything is okay and the application does what it is expected to do.

But: In case ZCL_BACKEND_MODEL_B does its work, an output stating e.g. that the backend data is derived by an external system should be shown as an info message in webdynpro.

This simple requirement led to two approaches.

 

 

 

Approach #1

The first approach is to apply specific methods which allow the UI to get some kind of a message from the backend.

IoC implemented - Approach 01.PNG

 

 

This means, method GET_INFO_MESSAGE ( ) needs to be called by the UI and depending on wether or not some message has been specified, the message has to be displayed.

 

This is a quite simple approach.

 

 

Disadvantage of approach #1

 

 

But there is also a disadvantage to this approach: By extended the interface with the GET_INFO_MESSAGE-method, we introduce a new concern to the application, which is completely useless for backend model A. Only backend model B will ever provide some messages to its caller (which is, the UI).

 

Even worse: Every implementer of ZIF_SOME_BACKEND_MODEL will have to implement at least an empty implementation of that method to avoid runtime exceptions when a not implemented method is called.

 

 

Approach #2

The second approach makes use of the Inversion of Control principle. Instead of asking the backend something, the UI tells it to tell its message manager what it thinks is newsworthy to tell.

 

How does it work? The most crucial difference is the existence of a new interface ZIF_I_AM_COMMUNICATIVE.
It is implemented only by Backend Model B.

IoC implemented - Approach 02.PNG

What happens in the application? The UI tries to downcast the backend model to an instance of type ZIF_I_AM_COMMUNICATIVE. If backend model A is currently used in the application, the downcast will fail and the exception CX_SY_MOVE_CAST_ERROR may be catched silently.

In case the downcast succeeds, the webdynpro message manager of the UI component will be transferred to the backend model.

This gives backend model B the opportunity to show a warning / info message to the UI informing the user that backend model B is active. This could happen at a time point of time which can be controlled by the backend, not by the UI.

 

Disadvantage of approach #2

But also approach #2 has its disadvantages. By introducing a webdnypro interface to the backend, we have not only a dependency of the UI to the backend, but also bring in a dependency in reverse. At least as far it concerns ZCL_BACKEND_MODEL_B.

Usually you should avoid having such kind of dependencies as they might imply problems when working with dependency tracking techniques such as IoC Containers.

Also, the coupling between backend model B and the webdynpro  runtime is increased by introducing the interface IF_WD_MESSAGE_MANAGER to the backend class.

To avoid these issues you might consider to wrap IF_WD_MESSAGE_MANAGER inside another, more abstract class, e.g. a generic message manager interface whose implementers may work also with classic dynpro screens. Instead of the webdynpro message manager, this wrapper class instance would then be injected to the backend. However such an approach might be kind of over-engineering in the first step.

 

What to do?

We decided to go for approach #2 as it was the least invasive and the most flexible one. We might consider implementing the refactoring mentioned in the disadvantages section of approach #2 in the future. However, the approach works like a charm right now.

A real example: how to leverage ABAP breakpoint with type "Exception"

$
0
0

Hi friends,

 

     most of the time when your application does not work as you expected and you want to debug to find root cause. Unfortunately there is no hint in your application which can guide you to the right way of trouble shooting( if there is some error message poped up in ui, then you can quickly locate the exact location of the code which raises that error message using the approaches explained in my blog ). My personal opinion about the reason why we don't see any error messages in UI but the application still does not work is because that, at least in CRM web client ui development area, there are indeed some exception raised in the backend, however they are caught by the framework without any error handling ( at least the framework does not raise the error into UI or notifies developer with whatever ways ).

In this situation it is difficult for developers to find the entry point of debugging. If just starting to debug into framework, we may get lost in the horrible callstacks of framework code.

 

     I will use a real example in my project to demonstrate how to leverage ABAP exception breakpoint to make our debug easier.

 

    I developed a table using BSP in CRM. The content of each column is filled in the runtime by the getter method of the context node which is bound to a BOL node.

 

clipboard1.png

 

During my testing, I found the column "Associated Object" in the first row is empty. Hmmm, my first assumption is there must be something wrong with my implementation in its getter method GET_ASSOC_OBJ_DEF_ATTRIB.

 

clipboard2.png

 

So I set a breakpoint on that method and start debugging. To my surprise, I found the breakpoint is not triggered for the first row, but triggered as my expected for the left rows two, three, four.... Why the framework does not call the getter method for my first row? Then I planned to debug the BSP framework to understand how the getter method is called for my second row. After sometime's struggle against the framwork code, I changed my mind since I find it is not an effective way to debug the complex framework code.

 

clipboard3.png

 

I do believe there is some exception occured in the backend, but caught by framework. I set a breakpoint in search button implementation, since for sure the exception only occurs after search is executed.

 

I create a new exception dynamically. Since I don't know the exact name of exception, I can only create a breakpoint based on CX_ROOT, which is super class of all class based exceptions.

 

clipboard4.png

 

then all that I can do is just F8, F8 and F8... Soon ( ten seconds later) I found one exception raised in a suspicious method GET_TABLE_CONTENT.

 

clipboard5.png

 

Then I click "Display Trigger Location", the debuger displays the method GET_P_ASSOC_OBJ_DEF_ATTRIB which leads to the exception CX_SY_NO_HANDLER.

 

clipboard6.png

 

Wait.. isn't this trouble-maker method developed by myself?

 

clipboard7.png

 

After going through BSP framework code I learnt that BSP framework will first try to determine the cell type by calling our property getter method ( PREFIX GET_P_XXX). Only the successful determination of field type can trigger the successive call of content getter method ( PREFIX GET_XXXX) to retrieve the cell content.

 

By the way, if the method which trigger the exception is not owned by you, you need to know which class that method belongs to.

 

You can achieve it by using SE80->Repository Information System

 

clipboard8.png

 

clipboard9.png

Viewing all 948 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>