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

How to reduce run-time of batch program?

$
0
0

Most of the programs, especially reports which are generated during year-end or reports run once in every month, every quarter etc. takes lot of time.These reports will be run in background because it takes long time or sometimes automatic execution of these reports happens by Job scheduling.

There are various ways of improving the performance or rather reducing the time taken for execution, so that the report output is available ahead of time or at least within some timelines which the user or customer desires.

 

Here are some of the different ways on how to reduce the run-time of batch program, which I have come across, worked on and which would be helpful to all of you in some way or the other. This can be applied not only to the existing programs which takes lot of time, but also can be applied before creating such kind of report programs. There are two kinds of reports: standard and custom created report programs.

 

1. Standard programs:

 

When talking about the run-time of standard batch programs,  we don't have many things to control over it. As an ABAPer or developer, what can be done is to go and check for SAP notes available for the program which takes long time, as SAP would have released some notes if the program is generally run as batch program and many customers would have raised message to SAP. Implementing the SAP notes, would mostly resolve the issue or would reduce the run-time.

Sometimes, it would need some memory parameter setting or system setting in addition to the note implementation.

 

In case, if the SAP note not available, then we can raise a message to SAP after checking for the other parameters which can be configured such as memory, system parameters,etc.

 

Apart from setting or configuring of the parameters for the job, there are some things which needs to be taken care mostly related to the program logic i.e.performance of the program/job, in standard program - to check if there is any customer exit coding or BADI coding available which might need fine tuning.

 

2. Custom programs:

 

In case of custom programs, there are lot of things which as a ABAPer we can plan out before creating a report program or for tuning the existing program to reduce the run-time. Some existing programs can even be changed to run in foreground( if needed) from background if most of the below things are taken care.

There are two ways in which run-time can be reduced: one is the memory, system settings for the job/program and second is the coding part.

We have to concentrate more on the coding part, to improve the performance or reduce the run-time of the program. The report program has to be coded considering all the performance tuning techniques. Each and every performance technique plays a vital role in reducing the run-time of the program. For example, populating the internal table as below :

 

                         itab[] = itab1[].  ~ would be faster

 

                         LOOP AT itab.               ~ will take time when comparing above statement.

                          APPEND itab TO itab1.

                         ENDLOOP.

 

This will reduce some seconds depending on the total records in ITAB[]. However, writing code like this, as a whole makes a big difference and will reduce run-time of the program. Also,clearing the memory space used by the internal table at end of the perform if the data of that internal table is not needed later, will increase the memory space thereby indirectly helping in performance.

 

When it comes to performance tuning in coding, there are three things, .i.e. ABAP statements, Database statement or queries and system. Out of which ABAP and database statements can be controlled.

 

ABAP statements:

Each and every ABAP statement has a specific execution time. Thus, when coding, not only think of statement which suits requirement but we also need to analyse best statement which can be used i.e. as in my above example for populating internal table data if data type for both are same.

ABAP statements sometimes takes more time when compared to database statement when written without analysis or without knowing the impact. It is better to analyze even while writing a simple ABAP statement in a program.

 

For understanding on what is time taken for execution by different ABAP statements, login to SAP, execute program RSHOWTIM, alternatively we can use the path to navigate there, i.e. In menu bar->Environment->Examples->Performance Examples. This will be useful.

 

There are lot of artifacts, documents already available in SDN wiki, forums which might be useful to you for performance tuning.

http://wiki.sdn.sap.com/wiki/display/ABAP/ABAP+Performance+and+Tuning

 

Database statements:

 

Most of the time, when we do a run-time analysis, the percentage of  time consumed by the database hit or when pulling data from database table or updating/deleting/inserting data to the table is more. Hence proper analysis has to be done when coding queries. It is better to understand the requirements on what the program is going to do, how frequently it will run, how many records, how many tables, what kind of tables, whether the program be enhanced later etc. (Most of the programs are initially created without knowing it will be enhanced later or not).

We can take more time in analyzing on which type of query should be coded, whether going for joins like INNER JOIN,OUTER JOIN or FOR ALL ENTRIES, depending on the tables which are used, i.e. especially when using Cluster tables and views.

Sometimes FOR ALL ENTRIES takes less time when compared to using INNER JOIN, hence depending on the tables, use the proper query. Use the primary keys in where clause and in the same order it is there in table, while picking up data from tables.

Try to use standard FMs if available in place of SELECT queries, as it will not only reduce the execution time, but will also have error handling and query written in a better way.

 

There is also an option to configure the setting for every job/batch program with different parameters like priority or job class which will control the run-time of the program. This can be done for both custom and standard batch programs.

 

Existing custom programs:

For existing custom programs, if we want to reduce the run-time, then we can go for below approaches.

Do the run-time analysis in SE30 transaction, and check execution time for ABAP, database or system.After that, then we will get know which one we need to fine tune, either ABAP or database statements or anything needs to be done for system settings.Also go for performance analysis in ST05, activate trace and execute program and analyze how much time each select query of the program has taken.

 

The above approaches will also be applicable to Function modules, Class methods or Module pools.

 

Any additional information to this blog are welcome.


Stories about Repositories and Number Ranges

$
0
0

Introduction

This week, I faced a situation where I needed to implement a new business object for one of our applications. As business objects usually need persistence, I created a new repository for it to handle the database access. This repository covered the standard database functions like Create, Update, Read and Delete (CRUD).

While implementing the repository, the question of what should happen to new business objects during the Create-operation came up, specifically who should create a new document number. I decided to request new number ranges for new business objects while in the SAVE-Method of the repository and then the trouble started to grow…

 

Bad design

The first design was a mess:

v1.PNG

In this fictitious example, ZCL_BOOKING represents an entity, a booking record, which will be saved to the database.

ZCL_BOOKING_REPOSITORY takes care of saving this entity correctly, with some more functions like retrieving those entities back from database or delete them from the DB.

The SAVE-Method looked like this:

 

CLASS ZCL_BOOKINGS_REPOSITORY IMPLEMENTATION.
...
METHOD ZIF_BOOKING_REPOSITORY~save.  DATA lv_bookid TYPE S_BOOK_ID.  DATA ls_header TYPE bookings.  lv_bookid = io_booking->get_bookid( ).  ls_header = io_booking->get_booking( ).  IF lv_bookid IS INITIAL.    CALL FUNCTION 'NUMBER_GET_NEXT'      EXPORTING
 nr_range_nr             = 'ZFL_BOOKID'
 object                  = '01'      IMPORTING
 number                  = rv_bookid      EXCEPTIONS
 interval_not_found      = 1
 number_range_not_intern = 2
 object_not_found        = 3
 quantity_is_0           = 4
 quantity_is_not_1       = 5
 interval_overflow       = 6
 buffer_overflow         = 7
 OTHERS                  = 8.
*   implement proper error handling here...
 io_booking->set_bookid( lv_bookid ).    CALL FUNCTION 'Z_FM_INSERT_BOOKINGS' IN UPDATE TASK      EXPORTING
 iv_bookid                                 = lv_bookid
 is_header             = ls_header.  ELSE.    CALL FUNCTION 'Z_FM_UPDATE_BOOKINGS' IN UPDATE TASK      EXPORTING
 iv_bookid                                 = lv_bookid
 is_header             = ls_header.  ENDIF.
ENDMETHOD.
...
ENDCLASS.

Running out of time? I’M RUNNING OUT OF NUMBERS!!!

Everything went well, until I started to write a unit test for the SAVE-method.

I started to write a test which created a new instance of type ZCL_BOOKING without any BOOKID. I expected the instance to be inserted to the database. This worked pretty well, but when I tried to implement the TEARDOWN method I had some issues. As Unit tests need to be processed as often as you need, and should leave the system in the same state from where you started from. This means, the inserted record needed to be deleted.

As the SAVE-method requests a new number for each object that has not yet an ID, I don’t really know which ID has just been inserted.

I could have asked the instance of type ZCL_BOOKING which ID has been set for it. This would solve at least the issue that I need to clean up the database after the test-insert.

But, more severe, the current number in the number range interval has increased by one with each unit test. This was not acceptable.

So the unit test revealed the bad design: In fact, the repository had a dependency on a number range object. Actually, it should not care about it.

 

Refactored design

This step introduces a new class to the design, which is called ZCL_NUMBER_RANGE_REQUEST. It implements an interface ZIF_NUMBER_RANGE_REQUEST which is now used by ZCL_BOOKING_REPOSITORY to handle its number range requests.

  The number range object is created before ZCL_BOOKING_REPOSITORY is getting created in order to hand it over to the constructor of the repository.

v2.PNG

The result is: Instead of creating new document numbers by its own, the repository asks another object for it.

This has a huge benefit: As the number range object is specified by an interface, we can fake this interface in a unit test and pass it to the repository’s constructor. The fake object of course does not request a real number from a real number range but returns “1” all the time.

Unit Test Setup.png

 

So that’s what the new implementation of the classes looks like:

 

CLASS ZCL_BOOKING_REPOSITORY IMPLEMENTATION.
...
METHOD ZIF_BOOKING_REPOSITORY~save.  DATA lv_bookid TYPE S_BOOK_ID.  DATA ls_header TYPE bookings.  lv_bookid = io_booking->get_bookid( ).  ls_header = io_booking->get_booking( ).  IF lv_bookid IS INITIAL.    lv_bookid = mo_number_range->get_next_number( ).    io_booking->set_bookid( lv_bookid ).    CALL FUNCTION 'Z_FM_INSERT_BOOKINGS' IN UPDATE TASK      EXPORTING
 iv_bookid                                 = lv_bookid
 is_header       = ls_header.  ELSE.    CALL FUNCTION 'Z_FM_UPDATE_BOOKINGS' IN UPDATE TASK      EXPORTING
 iv_bookid                                 = lv_bookid
 is_header       = ls_header.  ENDIF.
ENDMETHOD.
METHOD constructor.
 mo_number_range = io_number_range.
ENDMETHOD.
ENDCLASS.

 

The implementation of the number range object requests the current number by using the standard function module. The input paramaters for this function module have been provided in the CONSTRUCTOR of the object.

 

CLASS ZCL_NUMBER_RANGE_REQUEST IMPLEMENTATION.
...
method GET_NEXT_NUMBER.    CALL FUNCTION 'NUMBER_GET_NEXT'      EXPORTING
 nr_range_nr             = mv_nrobj
 object                  = mv_nrnr      IMPORTING
 number                  = rv_number      EXCEPTIONS
 interval_not_found      = 1
 number_range_not_intern = 2
 object_not_found        = 3
 quantity_is_0           = 4
 quantity_is_not_1       = 5
 interval_overflow       = 6
 buffer_overflow         = 7
 OTHERS                  = 8.
*   implement proper error handling here...
endmethod.
ENDCLASS.

 

How can I really get a fake?

Fake objects can be created using local classes in the unit test. As an alternative, mocking Frameworks can help to automate this task by providing a declarative API.

In the real life use case I created the fake object using a mocking framework with this call:

 

    mo_number_range_request ?= /leos/cl_mocker=>/leos/if_mocker~mock( ‘/leosb/if_number_range_request’)->method( 'GET_NEXT_NUMBER' )->returns( 1 )->generate_mockup( ).

 

I hate puzzles

This kind of architecture eventually leads to tons of classes, each having their own responsibility. In a real life application you would need to set up the repository instances and their dependencies at least in some specific method at startup:

 

CREATE OBJECT lo_number_range TYPE ZCL_NUMBER_RANGE_REQUEST
CREATE OBJECT lo_repository TYPE ZCL_BOOKING_REPOSITORY EXPORTING io_number_range = lo_number_range.

 

IoC Containers help you in managing these dependencies by allowing you to register specific classes for each interface in customizing. Their purpose is to resolve all dependencies for a root object, when a root object like a repository is requested by the application. The container creates this root object and hands it back to the caller with just one single line of code.

 

Related links

http://scn.sap.com/community/abap/application-development/objects/blog/2012/11/16/unit-tests-in-abap-using-a-mocking-framework

http://scn.sap.com/community/abap/application-development/objects/blog/2012/11/20/ioc-container-in-abap-part-i

http://scn.sap.com/community/abap/application-development/objects/blog/2012/11/28/ioc-container-in-abap-part-ii

How to display table data in message long-text

$
0
0
You want to display table data in the long-text of a message so that the user can decide based on this information. It's very easy but can be tricky   if you do not know how to use this FM : RKE_POPUP_TEXT_DECIDE_VARTEXT. Here is a demo program for this purpose
DATA: lt_mara TYPE TABLE OF mara,

      ls_mara TYPE mara,

      ls_text LIKE tline,

      lt_text TYPE TABLE OF tline.

* fetch 10 rows for display

SELECT * FROM mara INTO TABLE lt_mara

         UP TO 10 ROWS  WHERE matnr NE space.

IF sy-subrc EQ 0.

  ls_text-tdformat = 'AS'.

  LOOP AT lt_mara INTO ls_mara.

    ls_text-tdline = ls_mara-matnr.

    CONDENSE ls_text-tdline.

    APPEND ls_text TO lt_text.

    ls_text-tdformat = '/'.

  ENDLOOP.


  CALL FUNCTION 'RKE_POPUP_TEXT_DECIDE_VARTEXT'

    EXPORTING

*   OPTIONS              = '' "You can add push-buttons also

      object_id            = 'NA'

      object               = 'ZTEST000'

     na_shorttext         = 'X'

     titel                = 'Example to show table'

* IMPORTING

*   ANSWER               = "User decision can be captured here

   TABLES

*   T_PARAMS             =

     t_texttab            = lt_text

   EXCEPTIONS

     docu_not_found       = 1

     OTHERS               = 2  .

  IF sy-subrc <> 0.

    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno

            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

  ENDIF.

ELSE.

  MESSAGE i001(00) WITH 'Nothing to dispaly'. EXIT.

ENDIF.
The table can be passed as a variable in the message short text like : Select material number & and in the long text you have to insert a "Command" with type &TABLES& or simply &T&.
The output is a message with 10 rows from MARA as an additional info.
Table in message.PNG

One case I met: SAPLSLVC_FULLSCREEN was modified, so ALV output is not in full screen

$
0
0

Share one case here I met: Someone modified the standard program SAPLSLVC_FULLSCREEN, so ALV output is not in full screen.

 

I found the screen 500 of the program SAPLSLVC_FULLSCREEN was modified, this can be seen in transaction SE80 -> Program -> SAPLSLVC_FULLSCREEN -> Screen -> 500 -> Layout:

 

Screen No.           0500 Modified/Active

 

the Attributes was change to:

Type      Custom Control
Name    GRID1
Line       1    Column    1     Lngth 110      Height  19

 

so the ALV list will have length 110 and height 19. This can be changed it to the default value to length 240 and height 200 and then it will work.
But of cause you need the Access key as the program is a standard SAP program.

 

In case you met this knid of case. This will help then.

Simple OO ALV report in full screen mode example

$
0
0

REPORT zmmr_perf_eval_vend.


"Types Declaration
TYPES:BEGIN OFt_disp,
   lifnr
TYPElifnr,
   name1
TYPEname1_gp,
   bedat
TYPEbedat,
   rfq 
TYPE I,
   quot
TYPE I,
   po  
TYPE I,
   cont
TYPE I,
   sch 
TYPE I,
END OFt_disp,
BEGIN OFt_temp,
   lifnr
TYPElifnr,
 
CNT   TYPE I,
END OFt_temp,
BEGIN OFt_lfa1,
   lifnr
TYPElifnr,
   name1
TYPEname1_gp,
END OFt_lfa1.

"For ALV {
DATA:"it_layout   TYPE lvc_s_layo,
       gr_table
TYPE REF TOcl_salv_table,
       gr_functions
TYPE REF TOcl_salv_functions,
       gr_columns
TYPE REF TOcl_salv_columns_table,
       gr_column
TYPE REF TOcl_salv_column_table,
       gr_display
TYPE REF TOcl_salv_display_settings,
       lr_grid
TYPE REF TOcl_salv_form_layout_grid,
       lr_gridx
TYPE REF TOcl_salv_form_layout_grid,
       lr_logo
TYPE REF TOcl_salv_form_layout_logo,
       lr_label
TYPE REF TOcl_salv_form_label,
       lr_text
TYPE REF TOcl_salv_form_text,
       lr_footer
TYPE REF TOcl_salv_form_layout_grid,
       ls_color
TYPElvc_s_colo
     
.
" For ALV }

DATA:it_dispTYPE TABLE OFt_disp,
       wa_disp
LIKE LINE OFit_disp,
       it_temp
TYPE TABLE OFt_temp,
       wa_temp
LIKE LINE OFit_temp,
       it_lfa1
TYPE TABLE OFt_lfa1,
       wa_lfa1
LIKE LINE OFit_lfa1.

SELECTION-SCREEN BEGIN OF BLOCKb1WITH FRAME TITLE TEXT-001.
 
SELECT-OPTIONS: s_lifnrFORwa_disp-lifnr,
   s_bedat
FORwa_disp-bedat.
SELECTION-SCREEN END OF BLOCKb1.

*----------------------------------------------------------------------*
*       CLASS lcl_Perf_Eval DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASSlcl_perf_evalDEFINITION.
 
PUBLIC SECTION.
 
METHODS: constructor,
   fill_disp
.
 
METHODSbuild_fc.
 
METHODSdisp_alv.
 
METHODSset_tol.
 
METHODSend_of_page.

ENDCLASS.                   "lcl_perf_eval DEFINITION


*----------------------------------------------------------------------*
*       CLASS lcl_perf_eval IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASSlcl_perf_evalIMPLEMENTATION.
 
METHODconstructor.
   
TRY.
       cl_salv_table
=>factory(IMPORTINGr_salv_table=gr_tableCHANGINGt_table=it_disp)."Calling Factory Obj of Cl_ALV_TABLE
   
CATCHcx_salv_msg.
   
ENDTRY.

   
IFgr_tableIS INITIAL.
     
MESSAGE TEXT-002TYPE'I'DISPLAYLIKE'E'.
     
EXIT.
   
ENDIF.
 
ENDMETHOD.                   "constructor

 
METHODfill_disp.
   
"RFQ
   
SELECTa~lifnrCOUNT( DISTINCTa~ebeln)ASrfqFROMekkoASa
   
JOINekpoASbONa~ebeln=b~ebeln
   
INTOCORRESPONDINGFIELDS OF TABLEit_disp
   
WHEREa~lifnrINs_lifnrANDbedatINs_bedat
   
ANDb~loekzNE'X'
   
ANDa~bstyp='A'
   
GROUP BYa~lifnr.

   
"WRITE sy-dbcnt.
   
"Quot
   
SELECTlifnrCOUNT(DISTINCTebeln)AS CNT FROMekko
   
APPENDINGCORRESPONDINGFIELDS OF TABLEit_temp
   
WHERElifnrINs_lifnrANDbedatINs_bedat
   
ANDloekzEQspace
   
AND(bstyp='A'ANDstatu='A')
   
GROUP BYlifnr.

   
LOOP ATit_tempINTOwa_temp.
       wa_disp
-lifnr=wa_temp-lifnr.
       wa_disp
-quot=wa_temp-CNT.
     
MODIFYit_dispFROMwa_dispTRANSPORTINGlifnr quotWHERElifnr=wa_temp-lifnr.
     
CLEAR:wa_disp,wa_temp.
   
ENDLOOP.

   
" PO
   
REFRESHit_temp.
   
SELECTlifnrCOUNT(DISTINCTa~ebeln)AS CNT FROMekkoASaJOINekpoASbONa~ebeln=b~ebeln
   
APPENDINGCORRESPONDINGFIELDS OF TABLEit_temp
   
WHERElifnrINs_lifnrANDbedatINs_bedat
   
ANDb~loekzEQspace
   
ANDbsartNE'UB'
   
AND(a~bstyp='F')
   
GROUP BYlifnr.

   
LOOP ATit_tempINTOwa_temp.
       wa_disp
-lifnr=wa_temp-lifnr.
       wa_disp
-po=wa_temp-CNT.
     
MODIFYit_dispFROMwa_dispTRANSPORTINGlifnr poWHERElifnr=wa_temp-lifnr.
     
IFsy-subrcNE0.
       
APPENDwa_dispTOit_disp.
     
ENDIF.
     
CLEAR:wa_disp,wa_temp.
   
ENDLOOP.

   
"Cont. Created
   
REFRESHit_temp.
   
SELECTlifnrCOUNT(DISTINCTa~ebeln)AS CNT FROMekkoASaJOINekpoASbONa~ebeln=b~ebeln
   
APPENDINGCORRESPONDINGFIELDS OF TABLEit_temp
   
WHERElifnrINs_lifnrANDbedatINs_bedat
   
ANDb~loekzEQspace
   
AND(a~bstyp='K')
   
GROUP BYlifnr.

   
LOOP ATit_tempINTOwa_temp.
       wa_disp
-lifnr=wa_temp-lifnr.
       wa_disp
-cont=wa_temp-CNT.
     
MODIFYit_dispFROMwa_dispTRANSPORTINGlifnr contWHERElifnr=wa_temp-lifnr.
     
IFsy-subrcNE0.
       
APPENDwa_dispTOit_disp.
     
ENDIF.
     
CLEAR:wa_disp,wa_temp.
   
ENDLOOP.

   
"Sch Aggre
   
REFRESHit_temp.
   
SELECTlifnrCOUNT(DISTINCTa~ebeln)AS CNT FROMekkoASaJOINekpoASbONa~ebeln=b~ebeln
   
APPENDINGCORRESPONDINGFIELDS OF TABLEit_temp
   
WHERElifnrINs_lifnrANDbedatINs_bedat
   
ANDb~loekzEQspace
   
AND(a~bstyp='L')
   
GROUP BYlifnr.

   
LOOP ATit_tempINTOwa_temp.
       wa_disp
-lifnr=wa_temp-lifnr.
       wa_disp
-sch=wa_temp-CNT.
     
MODIFYit_dispFROMwa_dispTRANSPORTINGlifnr schWHERElifnr=wa_temp-lifnr.
     
IFsy-subrcNE0.
       
APPENDwa_dispTOit_disp.
     
ENDIF.
     
CLEAR:wa_disp,wa_temp.
   
ENDLOOP.

   
SELECTlifnr name1FROMlfa1
   
INTOCORRESPONDINGFIELDS OF TABLEit_lfa1
   
FOR ALLENTRIESINit_disp
   
WHERElifnr=it_disp-lifnr.

   
LOOP ATit_dispINTOwa_disp.
     
READ TABLEit_lfa1INTOwa_lfa1WITH KEYlifnr=wa_disp-lifnr.
     
IFsy-subrcEQ0.
         wa_disp
-name1=wa_lfa1-name1.
       
MODIFYit_dispFROMwa_dispTRANSPORTINGlifnr name1WHERElifnr=wa_disp-lifnr.
     
ENDIF.
   
ENDLOOP.


   
SORTit_dispBYlifnr.

 
ENDMETHOD.                   "fill_disp
 
METHODbuild_fc.

   
INCLUDE<color>.
   
TRY.
       gr_columns
=gr_table->get_columns( ).
       gr_columns
->set_optimize(abap_true).
       gr_column ?= gr_columns
->get_column('LIFNR').
       ls_color
-col=3.
       gr_column
->set_color(ls_color).

   
CATCHcx_salv_not_found.
   
ENDTRY.

   
TRY.
       gr_column ?= gr_columns
->get_column('NAME1').
       gr_column
->set_long_text('Vendor Name').
       gr_column
->set_short_text('V.Name').
       gr_column
->set_medium_text('Vendor Name').
       ls_color
-col=3.
       gr_column
->set_color(ls_color).
   
CATCHcx_salv_not_found.
   
ENDTRY.

   
TRY.
       gr_column ?= gr_columns
->get_column('BEDAT').
       gr_column
->set_visible(abap_false).
       gr_column
->set_technical(VALUE=if_salv_c_bool_sap=>true).
   
CATCHcx_salv_not_found.
   
ENDTRY.

   
TRY.
       gr_column ?= gr_columns
->get_column('RFQ').
       gr_column
->set_short_text('RFQ').
       gr_column
->set_medium_text('RFQ Created').
   
CATCHcx_salv_not_found.
   
ENDTRY.

   
TRY.
       gr_column ?= gr_columns
->get_column('QUOT').
       gr_column
->set_short_text('Quot.').
       gr_column
->set_medium_text('Quotation Maintained').
   
CATCHcx_salv_not_found.
   
ENDTRY.
   
TRY.
       gr_column ?= gr_columns
->get_column('PO').
       gr_column
->set_short_text('PO Created').
   
CATCHcx_salv_not_found.
   
ENDTRY.

   
TRY.
       gr_column ?= gr_columns
->get_column('CONT').
       gr_column
->set_short_text('Cont.').
       gr_column
->set_medium_text('Contract Created').
   
CATCHcx_salv_not_found.
   
ENDTRY.
   
TRY.
       gr_column ?= gr_columns
->get_column('SCH').
       gr_column
->set_short_text('Sch. Crea.').
       gr_column
->set_medium_text('Sch. Agr. Created').
       gr_column
->set_long_text('Schedule Agreement Created').
   
CATCHcx_salv_not_found.
   
ENDTRY.

 
ENDMETHOD.                   "build_fc

 
METHODdisp_alv.

     set_tol
( ).
     build_fc
( ).
     end_of_page
( ).

     gr_functions
=gr_table->get_functions( ).
     gr_functions
->set_all(abap_true).
     gr_table
->set_top_of_list(lr_logo).
     gr_table
->set_end_of_list(lr_footer).
     gr_display
=gr_table->get_display_settings( ).
     gr_display
->set_striped_pattern(cl_salv_display_settings=>true).


     gr_table
->display( ).

 
ENDMETHOD.                   "disp_alv
 
METHODset_tol.
   
DATA:lv_text(30)TYPE C,
           lv_date
TYPE CLENGTH10.

   
CREATEOBJECT lr_grid.

     lr_grid
->create_header_information(row=1 column=1
   
TEXT='MM: Vendor Evaluation'
     tooltip
='MM: Vendor Evaluation').

     lr_gridx
=lr_grid->create_grid(row=2 column=1 ).
     lr_label
=lr_gridx->create_label(row=2column=1
   
TEXT='Vendor No # :'tooltip='Vendor #.').

   
IFs_lifnrIS NOT INITIAL.
       lv_text
=s_lifnr-low.
     
IFs_lifnr-highIS NOT INITIAL.
       
CONCATENATElv_text' to 's_lifnr-highINTOlv_textSEPARATED BYspace.
     
ENDIF.
   
ELSE.
       lv_text
='Not Provided'.
   
ENDIF.
     lr_text
=lr_gridx->create_text( row=2column=2
   
TEXT=lv_text tooltip=lv_text).
   
"Vendor
     lr_label
=lr_gridx->create_label(row=3column=1
   
TEXT='Posting Date:'tooltip='Posting Date').
   
IFs_bedatIS NOT INITIAL.
     
WRITEs_bedat-low DD/MM/YYYYTOlv_text .
     
IFs_bedat-highIS NOT INITIAL.
       
WRITEs_bedat-high DD/MM/YYYYTOlv_date.
       
CONCATENATElv_text' to 'lv_dateINTOlv_textSEPARATED BYspace.
     
ENDIF.
   
ELSE.
       lv_text
='Not Provided'.
   
ENDIF.

     lr_text
=lr_gridx->create_text( row=3column=2
   
TEXT=lv_text  tooltip=lv_text).

     lr_label
=lr_gridx->create_label(row=4column=1
   
TEXT='Run Date:'tooltip='Run Date').
     lr_text
=lr_gridx->create_text( row=4column=2
   
TEXT=sy-datum tooltip=sy-datum).

     lr_label
=lr_gridx->create_label(row=5column=1).
     lr_label
=lr_gridx->create_label(row=6column=1).
     lr_label
=lr_gridx->create_label(row=7column=1).
     lr_label
=lr_gridx->create_label(row=8column=1).


* Create logo layout, set grid content on left and logo image on right
   
CREATEOBJECT lr_logo.
     lr_logo
->set_left_content(lr_grid).
     lr_logo
->set_right_logo('ZCHEM_N_LOGO_SMALL')." Image From OAER T.code

 
ENDMETHOD.                   "set_Tol

 
METHODend_of_page.

   
DATA:lf_linesTYPEsy-tfill.

   
DATA:"lr_label TYPE REF TO cl_salv_form_label,
           lf_flow
TYPE REF TOcl_salv_form_layout_flow.

   
CREATEOBJECT lr_footer.
*--get total lines in internal table
     lf_lines
=LINES(it_disp).
     lr_label
=lr_footer->create_label(row=1column=1).
     lr_label
->set_text('Information:').
     lf_flow
=lr_footer->create_flow(row=2 column=1).
     lf_flow
->create_text(TEXT='Total Number of Entries').
     lf_flow
=lr_footer->create_flow(row=2 column=2).
     lf_flow
->create_text(TEXT=lf_lines).

 
ENDMETHOD.                   "end_of_page

ENDCLASS.                   "lcl_perf_eval IMPLEMENTATION


START-OF-SELECTION.
DATA:obj_repTYPE REF TOlcl_perf_eval." Declaring Object for Class

CREATEOBJECT:obj_rep." Creating Object

obj_rep
->fill_disp( )." Calling class Methods
obj_rep
->disp_alv( ).

ASUG Webcast on 'Custom ABAP Development on SAP HANA'

$
0
0

Session Abstract:

 

With SAP Business Suite and SAP NetWeaver Business Warehouse, two major SAP standard applications have been optimized for leveraging SAP HANA as primary persistence. This webinar gives an overview on how to benefit from SAP HANA in existing and new custom development based on SAP NetWeaver AS ABAP 7.0x and 7.4.

 

Speaker - Eric Westenberger, SAP

 

Start : May 1, 2013 1:00 PM (CT), 2:00 PM (ET), 12:00 PM (MT), 11:00 AM (PT)

End:   May 1, 2013 2:00 PM (CT), 3:00 PM (ET), 1:00 PM (MT), 12:00 PM (PT)

 

Registration Link

 

http://www.asug.com/events/detail/Custom-ADAP-Development-on-SAP-HANA

 

or Click Here

 

Please register soon. This is the first of our webcast series on SAP Development Technologies.

 

Be sure not to miss! Note that this session is for ASUG Members only.

 

Thanks,

Srini

 

Srini Tanikella,

ASUG BITI/ Development Technologies SIG Chair

ST01 RFC TRACE: Debugging ABAP RFC via JAVA Webdynpro Screen.

$
0
0

   This Blog will be helpful to find the ABAP RFCs which get called from the Java webdynpro screen

   on applying any action on it. Most of the time in many projects client prefer any other technology screen

   or JAVA screen as Frontend but for Backend they use  ABAP code. If any problem appear on the

   Java screen due to ABAP code execution, then the ABAP code should be  debugged with the help of debugger .

   To search the name of RFC or the problematic code we can use

   SAP transaction ST01 ->RFC Trace.

 

   Procedure in short :

   Step 1) Go to ST01 and switch ON the trace

   Step2) Do the required actions on Java webdynpro screen such as   (Press any Button: Save/update/Delete)

   Step3) Go to ST01 and switch OFF the trace and Press analysis to see the required RFCs

   Step4) Go to SE37 and find the RFC name.  on the external debugging , put the break point

   Step5) Do the required actions on Java webdynpro screen as done in step 2 and find that the debugger is on.

 

   Procedure in brief:

1)      1) Go to ST01 and switch ON the trace: Tick the RFC Calls check box and Clicked on Trace on button.

                  2.JPG

   2)  Here we can see the below Java Webdynpro screen , Fill in it the required fields and 

        Press GEM button to update the date in Backend (SAP Database tables).

 

1.JPG

   3)  The data is updated, we can see a record on Java webdynpro screen. This updation has

        happened in SAP database using ABAP code.

             3.JPG

  4)  Again go to transaction ST01 to OFF the trace  by pressing  TRACE OFF button

       And see analysis report by pressing ANALYSIS button.

          4.JPG

   5) Put the SAP user name , proper date / time fields value and press execute .

           5.JPG

  6)  After Execute below screen will appear. In the Object Column you can see all the RFCs are listed which were hit

      by the action applied on java webdynpro screen. The RFC name may be not fully displayed due to limited length

      of OBJECT column in the report.

         6.JPG

   7)  Go to transaction SE37 to find the full name of RFC

         put the name got from above screen Z_HR_RFC_UDLAAN_* in function module field

         press F4 to get its full name, here I got it Z_HR_RFC_UDLAAN_CREATE.

           7.JPG

    8) Now put the break point in the found RFC Z_HR_RFC_UDLAAN_CREATE .

          8.JPG

9)  And using menu entry UTILITIES -> SETTINGS  set the external debugging on9.JPG

   10) Now go to Java webdynpro screen and do the same actions  hown above you will find the debugger is activated

     and normally an ABAPer can start debugging.  

           10.JPG

 

       

 

 

 

2

STMS: facing errors when importing transport requests? It's your fault!

$
0
0

Without any doubt: your fault it is... and not only because obviously you didn't pay enough attention to objects' dependencies when you released your transport requests, but mainly because you didn't take 3 seconds to start transaction SE38 and run report ZCEX_TRDA_START to let the system check those dependencies for you.

 

Remark: if you do not find this report in your system, that's probably because you missed this blog post:

How-to check dependencies between transport requests

 

What's new with code exchange project "TRDA - Transport request dependencies analyzer" then?

First of all, the first versions had been developed on SAP Netweaver 7.02 Developer edition which made its use limited to the happy few customers running one of the last versions of SAP Netweaver... Well, I believe this period is over as it has now been backported to SAP NetWeaver 7.0 Trial version:

  • Two missing classes have been copied from 702 into customer namespace.
  • Some statements have been adapted: for example every "&&" character has been replaced by the corresponding "CONCATENATE" statement.
  • ABAP Unit tests have been reviewed.
  • Etc.

 

Speaking of which, those ABAP Unit tests have been enhanced to make sure TRDA finds the following dependencies:

 

PredecessorFollower
DomainData element based on Domain
Data elementStructure with one component based on Data element
StructureTable type based on Structure
Table typeFunction group with one function module using Table type as importing parameter
Function groupClass implementing a method where a function module from Function group is called
InterfaceClass implementing Interface
ClassProgram using objects of type Class
Enhancement spotFunction module where Enhancement spot is implemented
Enhancement spotEnhancement spot implementation of Enhancement spot
Function module

Enhancement spot implementation in Function module

Enhancement spot implementationComposite enhancement implementation containing Enhancement spot implementation
Database tableEnqueue object for Database table
Database tableSearch help based on Database table
Database tableMaintenance view for Database table
Search helpDatabase table where one component is using Search help
Table maintenance viewGenerated function group for Table maintenance view

 

But that's not the only new feature you'll find on TRDA Code exchange project page: this program can now be installed very easily via SAPlink too (provided you follow the corresponding How-to guide available). Note however that this version released as a nugget file doesn't include any ABAP Unit test class to simplify the installation process (but of course all ABAP Unit tests have been passed before creating the nugget).

 

And even more new features can be found in the Release notes document:

  • Parameters to influence the scope of the dependency analysis.
  • Ability to check dependencies that have been added manually in transport request attributes.
  • New columns to display transport request status in TMS queues.
  • Ability to exclude successfully imported request.
  • Ability to start dependency analysis in background.
  • Etc.

 

So if you're interested do not hesitate to join the project and give it a try: even if SAP is working on a similar program at the moment, we don't know yet when it's released, and for which SAP Netweaver versions it will be delivered... hence TRDA may still have some fine days ahead of it!


What about the good old Dynpro?

$
0
0

Call me conservative, call me old-fashioned, call me unprogressive - but I still don't get it! I'm talking about SAPs User Interface Roadmap and/or Strategy - especially regarding development in and for SAP ERP - the system environment I am most familiar with, so with this disclaimer let's start with some thoughts on UIs, business processes and custom development.

 

A couple of years ago, the SAP world for its customers and users was so simple! There was the SAP GUI with its now "outdated", proprietary programming model Dynpro for creation of user interfaces. It undoubtedly had an has some major drawbacks - mainly the various limits regarding user interaction and experience, which had mainly been overcome with the introduction of the enjoy controls. Together with the control framework, SAP GUI had again become a environment for efficient, rich, highly integrated user interface development with high performance.

 

  • Efficient development: If you take the different use cases for UIs in a ERP system into consideration - reporting via selection screen and list output, creating, editing and displaying business objects and their relations - old UI techniques like selection screens together with its variants in combination with modern controls like ALV, Tree, Split Screen a.s.o. provide a very effective way for the user to handle his or her business data. Simple reports, data maintainence views, complex business transactions (either single screen or multi-step) - everything built with proven, stable technology and high developer efficiency. And - not to forget - if you need/needed a developer or consultant, you always get/got one - try the same for SAP UI5, WDA with FPM or the unspeakable Java-based technologies.
  • Rich user experience: Okay, I admit that SAP GUI as a frontend is not what the standard iPad user would call fancy or user friendly. But has it to be fancy and is it really not user friendly? SAP GUI was always and is still meant for daily business processes - from mass data processing to handling single business objects. No app experience needed here as far as I can see. Icons and pictures where necessary, colors where needed - e. g. for status display. Right click, double click, Link click, Drag & Drop, menus, context menus - everything available but a colorful UI itself with everything floating, moving, blinking. Does such a fancy UI really add business value to the software-support of a business process? I highly doubt it.
  • High integration: The main ERP processes are - and as far as I can see will always be - implemented as SAP GUI transactions, from HCM over Financials and Project System to Material Management and Sales. So in case you want to adapt a SAP delivered GUI program you always have the largest variety of enhancement techniques  - from the UI itself to the possibilities for user interaction and the ABAP-based functionalities. Create a custom program and provide access to SAP programs? No problem. Call a custom program from a SAP program. The same. Try this with WDA and SAP GUI for HTML and enjoy the experience!
  • High performance: You don't expect me to compare DIAG with HTTP, do you?

 

So, the question for me is the following:

 

Why does SAP push itself and its customers to use Web-based technologies like WDA, FPM, CRM Web UI, SAP UI5, Web Dynpro Java, Guided Procedures, JSF, Adobe Interactive Forms - and what was this SAP Portal-based code generator called again - with more than the half of these programming models called obsolete just some months after the first painful customer implementations set productive?

 

Why not continue development of core technologies like Dynpro and Control Framework, for which customers have spent lots of money in consulting, development, in- and outsourcing know how and in which they now have to maintain a large code base?

 

Just my 2 cents!

 

PS: In case you didn't guess it yet - I just finished my first big project with WDA!

Parallel Cursor : Performance for Nested Loops

$
0
0

In a lot of scenarios we come across where nesting loops is the only option we have to achieve what we want.

 

They can be hazardous if not tuned properly and can result in time out dumps and heavy processing time.

 

The solution : PARALLEL Cursor.

 

Lets assume a scenario where we are having 3 internal tables one with following structure.

 

KNA1

     Kunnr

     Name1 SORTED TABLE by KUNNR

 

VBRK

    Vbeln

     Kunag [Sold to will be equal to kunnr].

 

VBRP

     vbeln

     posnr

     matnr

     netwr [SORTED TABLE by VBELN]

 

Now it becomes tricky as we want to link KNA1 to VBRK and VBRK to VBRP.

 

Note : This is just to explain a three level nested loop if exact case is considered a read on KNA1 will be better.

 

Some thumb rules for Parallel Cursor

1. SORTING should be on the field which will part of where clause if you are not using.

     Like in this case KNA1 will be on KUNNR

     VBRK will be on KUNAG

     and VBRP will be on VBELN.

2. Recommended : use of variables to store tabix of the loop process.

 

Now the solution :

 

DATA : lv_vbrk_tabix  TYPE sy-tabix,

       lv_vbrp_tabix  TYPE sy-tabix.

 

SORT it_vbrk BY kunag.

 

lv_vbrk_tabix = 1.

 

LOOP AT it_kna1 INTO wa_kna1.

 

     WRITE:/5 'Name : ' , wa_kna1-name1 , ' | ' , wa_kna1-kunnr.

     ULINE.


     LOOP AT it_vbrk INTO wa_vbrk FROM lv_vbrk_tabix.

 

          IF wa_kna1-kunnr GT wa_vbrk-kunag.

            lv_vbrk_tabix = sy-tabix.

            EXIT. 

          ENDIF.

 

          CHECK wa_kna1-kunnr = wa_vbrk-kunag.

 

          WRITE:/10 wa_vbrk-vbeln , wa_vbrk-fkdat.

 

          READ TABLE it_vbrp WITH TABLE KEY vbeln = wa_vbrk-vbeln

                             TRANSPORTING NO FIELDS.

 

* AS IT_VBRP is a sorted table on VBELN default BINARY SEATCH will be used.         

 

          IF sy-subrc IS INITIAL.

            lv_vbrp_tabix = sy-tabix.

          ELSE.

            CONTINUE.

          ENDIF.

 

          LOOP AT it_vbrp INTO wa_vbrp FROM lv_vbrp_tabix.

 

            IF wa_vbrk-vbeln NE wa_vbrp-vbeln.

              EXIT. 

            ENDIF.

 

            WRITE:/15 wa_vbrp-matnr , 50 wa_vbrp-netwr.

 

          ENDLOOP.

 

     ENDLOOP.

 

ENDLOOP.

 

These are the 2 possible ways of parallel cursor.

 

Do comment if any issues or there is a better way...

 

BINARY SEARCH Removed and SORTED TABLE added Thanks for the input "Mathew Sir"

Frustrating!

$
0
0

Why do SAP Support take so long to provide the simplest of fixes?

 

Back in January I debugged an issue for a client involving the transfer of delivery documents from R/3 to GTS.  After an hour or so I found the issue and told the client that 1 additional line of code was needed.  They decided to log the issue with SAP and included my detailed description of the problem and fix to help speed up the correction.

 

Fast forward three months and SAP have finally provided a solution and guess what, it's exactly the same solution I provided 3 months earlier.

 

Very frustrating!

Screen cast of Open XML documents Generation

$
0
0

  Hello.

  this  is  a screen cast of how to  generate

  Word  Ooxml  documents directly from SAP WAS

  without any Office Installation!

  


 

http://youtu.be/DPg2AYORNjU

 

 

 

Enjoy!

 

  Ronen Almog

Important concepts for all SAP Techies

$
0
0

Hello

 

This is my first SCN blog and i would like to share some of the important concepts used by most of the technical consultants in SAP.

Some of them may be project specific but i thought it would be good to collect them all at one place.

 

 

ConceptTransactions

Data dictionary objects SE11
Reports                                               SE80 or SE38
Module pool programming                                  SE80 or SE51
BDC                                                      SE80 or SM35
Scripts                                                 SE71
Smart forms
SMARTFORMS
ClassesSE24
Function modules                                   SE37
Bapi                                                     BAPI
Lsmw                                                   LSMW
Customer exits                                 CMOD
Badi SE19
Implicit and Explicit enhancements SE80 or SE19
BTE FIBF
Validations OB28
Substitutions OBBH
Custom infotypes PM01
WorkflowSWDD
Adobe formsSFP
QuerySQ01

 

 

These are just some common concepts and relevant transactions used by me or most of us,

i would like to know if you do use some other tools or concepts for development.

 

Note: I tried to collect only concepts which needs to be developed, hence didn't mention other concepts like

performance tools (ST05 or SE30), transport mechanism (SE09 or SE03) etc ...

 

Any suggestions are always welcome. 

 

 

 

Thanks and Regards,

Gautham Vangaveti.

Finding Actual function module for a Function Exit

$
0
0

It is common to find customer exits in SAP’s code and Function modules, to accommodate customer specific business rules in SAP provided applications. These exits sometimes are in the form:

 

Call Customer-Function ‘xxx’, where ‘xxx’ is usually a number. So, how do we know what the actual function module is, where we should put our custom code?

 

Here is a screen shot of a function module with customer exit:

 

Customer_Function_exit.png

 

To find out the actual function module, we will need to know what the main program name is. You can go to the main program using the menu item GO TO –> Main Program

 

Customer_Function_exit_menu.png

 

Now, our customer exit name would be:

EXIT_<Progam Name>_<XXX>,

Where    
<Program_Name> is the main program name     
<XXX>                  is the number next to “Customer-Function”

 

In this example function module, the main program was : SAPLHRBEN00GENERAL.

Hence, our customer exit will be  
EXIT_SAPLHRBEN00GENERAL_022

Create new batch characteristics with values checked and suggested by a function module

$
0
0

In this example I'll try to show you how to create new characteristics for a material batch. This will include the following steps:

  1. Creation of a function module to check characteristics value (optional)
  2. Creation of a function module to suggest characteristics value - search help (optional)
  3. Creation of new characteristics (CT04)
  4. Creation/modification of a class (CL02)
  5. Object/Class assignment to a class (CL24N or CL20N)
  6. Batch modification with our new characteristics (MCS2N)

1. Creation of a function module to check characteristics value

In the following code you can see very basic check which can of course be much more complex for your specific scenario.

FUNCTION Z_CHECK_050.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(CHARACT_NO) TYPE  CABN-ATINN
*"     REFERENCE(CHARACT) TYPE  CABN-ATNAM
*"     REFERENCE(VALUE) TYPE  CAWN-ATWRT
*"  EXCEPTIONS
*"      NOT_FOUND
*"----------------------------------------------------------------------

" Allow empty value
  check value is NOT INITIAL.

" Just for demonstration purposes we check for fixed values
  if value <> 1 and      value <> 2 and     value <> 3.    RAISE NOT_FOUND.  endif.
ENDFUNCTION.

2. Creation of a function module to suggest characteristics value

In the following code I'll create my own field catalog for selection grid to be displayed. We will need a checkbox column (called CHK) which will inform about which values (multiple allowed) are selected

FUNCTION z_check_050_f4.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(CHARACT_NO) TYPE  CABN-ATINN
*"     REFERENCE(CHARACT) TYPE  CABN-ATNAM
*"     REFERENCE(DISPLAY)
*"     REFERENCE(ADDITIONAL_VALUES) TYPE  CABN-ATSON
*"     REFERENCE(MULTIPLE_VALUES) TYPE  RCTMV-ATLIS
*"     REFERENCE(LANGUAGE) TYPE  SY-LANGU
*"     REFERENCE(DISPLAY_WITH_LANGUAGE)
*"  TABLES
*"      VALUES STRUCTURE  RCTVALUES
*"----------------------------------------------------------------------  TYPE-POOLS : slis.  CONSTANTS:      c_werks(50) TYPE c VALUE '(SAPLCHRG)DFBATCH-WERKS'.  types:    BEGIN OF ty_data,      chk(1) type c,      value type c,          END OF ty_data.  DATA:    lt_values type TABLE OF ty_data,    l_werks TYPE  dfbatch-werks,    lt_fieldcat TYPE slis_t_fieldcat_alv.  FIELD-SYMBOLS:    <fs_value> type ty_data,    <fs_werks>,    <fs_rctvalue> TYPE rctvalues,    <fs_fcat> type slis_fieldcat_alv.  ASSIGN (c_werks) TO <fs_werks>.  IF sy-subrc EQ 0.    l_werks  = <fs_werks>.  ENDIF.  CHECK l_werks IS NOT INITIAL.  APPEND INITIAL LINE TO lt_values ASSIGNING <fs_value>.  <fs_value>-value = '1'.  APPEND INITIAL LINE TO lt_values ASSIGNING <fs_value>.  <fs_value>-value = '2'.  APPEND INITIAL LINE TO lt_values ASSIGNING <fs_value>.  <fs_value>-value = '3'.        APPEND INITIAL LINE TO lt_fieldcat ASSIGNING <fs_fcat>.  <fs_fcat>-fieldname  = 'CHK'.  <fs_fcat>-seltext_m  = ''.  <fs_fcat>-ddictxt(1) = 'M'.  APPEND INITIAL LINE TO lt_fieldcat ASSIGNING <fs_fcat>.  <fs_fcat>-fieldname  = 'VALUE'.  <fs_fcat>-seltext_m  = 'Value'.  <fs_fcat>-outputlen  = 10.  <fs_fcat>-ddictxt(1) = 'M'.  loop at lt_values ASSIGNING <fs_value>.    READ TABLE values with KEY value = <fs_value>-value TRANSPORTING NO FIELDS.    if sy-subrc = 0.      <fs_value>-chk = 'X'.    ENDIF.  ENDLOOP.  CALL FUNCTION 'REUSE_ALV_POPUP_TO_SELECT'    EXPORTING      i_title       = 'Allowed values'      i_selection   = 'X'      i_zebra       = 'X'      i_checkbox_fieldname = 'CHK'      i_tabname     = 'LT_VALUES'      it_fieldcat   = lt_fieldcat    TABLES      t_outtab      = lt_values    EXCEPTIONS      program_error = 1      OTHERS        = 2.  LOOP AT lt_values ASSIGNING <fs_value> where chk = 'X'.    READ TABLE values with KEY value = <fs_value>-value TRANSPORTING NO FIELDS.    if sy-subrc = 0.
*     selected value had already been assigned - no action needed    else.
*     new value selected -> add it to the list      APPEND INITIAL LINE TO values ASSIGNING <fs_rctvalue>.      <fs_rctvalue>-value = <fs_value>-value.      <fs_rctvalue>-status = 'I'.    ENDIF.  endloop.  LOOP AT values ASSIGNING <fs_rctvalue> where status <> 'I'.    READ TABLE lt_values with KEY      value = <fs_rctvalue>-value      chk      = 'X'      TRANSPORTING NO FIELDS.    if sy-subrc <> 0.
*     value was de-selected - we have to delete it      <fs_rctvalue>-status = 'D'.    endif.  ENDLOOP.

ENDFUNCTION.

3. Creation of new characteristics

Run Transaction CT04, enter name of new batch and press CREATE icon

Enter description of the characteristics, set Status to Released, in Format section select your desired format (we'll create multiple values, character type of length 15)

Now we need to assign our check function module to the characteristics - Go to tab Values, click on Other Value Check and select radio with label Funct. module

When prompted, enter name of our check FM - Z_CHECK_050.

Note: The search help function module Z_CHECK_050_F4 is assigned automatically

4. Creation/modification of a class

Run TCode CL02 and create new or edit existing class for class type 022 (Batch). Enter some description (for new class), go to tab Char. and assign our new characteristics ZBM_0050 to class.

5. Object/Class assignment to a class

Run TCode CL24N select class you used in previous step (B0001), class type 022

  • for new class without existing assignments click on button Only new assignments and select Material

  • for class with existing assignments just press enter

6. Batch modification with our new characteristics

Run TCode MSC2N and change a batch for given material. You can see that our new characteristics is available

Try to enter some value different from 1,2 or 3 (values defined in our check FM) and press enter

Press F4 and select some values

Press F4 again and check that your previously selected values are already checked.

Now you can just save your batch - we are DONE


Posting a Goods Movement Document in IS-OIL

$
0
0

This blog illustrates the method to post goods movement in IS-OIL.

 

Almost every one of us have used “BAPI_GOODSMVT_CREATE” to post a material goods movement in SAP. But when we are working in IS-Oil material this BAPI does not work and we end up trying different ways to do the same.

 

Well SAP has another BAPI for this and I will try to post a 311 movement with the same. I hope this helps in other postings as well.

 

The BAPI is BAPI_GOODSMVT_CREATE_OIL.

 

Data Declaration :

 

     DATA : lw_item       TYPE bapioil2017_gm_itm_crte_01,
        lw_item_param
TYPE bapioil2017_gm_itm_crte_param,
        lw_header    
TYPE bapioil2017_gm_head_create,
        lw_doc_no    
TYPE mkpf-mblnr,
        lt_item      
TYPE TABLE OF bapioil2017_gm_itm_crte_01,
        lt_item_param
TYPE TABLE OF bapioil2017_gm_itm_crte_param,
        lt_return    
TYPE TABLE OF bapiret2.

 

Passing the Data.

 

Now most data passing will be similar to our standard way.

 

Material Document Header.

 

    lw_header-pstng_date = sy-datum.
    lw_header
-doc_date   = sy-datum.

 

Material Document Item.

 

  lw_item-material      = lw_g_odet-matnr.
        lw_item
-move_mat      = lw_g_odet-matnr.
        lw_item
-plant         = lw_tankm-plant.
        lw_item
-stge_loc      = lw_tankm-sloc.
        lw_item
-batch         = lw_oijnomi-charg_o.
        lw_item
-val_type      = lc_vatyp.
        lw_item
-move_plant    = lw_tankm-plant.
        lw_item
-move_stloc    = lc_vsloc.
        lw_item
-move_batch    = lw_oijnomi-charg_o.
        lw_item
-move_val_type = lc_vatyp.
        lw_item
-move_type     = '311'.

  lw_item-entry_qnt     = lw_tankm-tag_value.
        lw_item
-entry_uom     = lw_tankm-tag_uom.

 

Posting the Additional Quantities

 

Now this is the major difference between normal goods movement and IS-Oil goods movement.

 

In the declared lt_item_param there are two control parameters for posting items with additional quantities:

§  CALCULATEMISSING

§  USEDEFAULTPARAMETERS

 

There are QCI [Quantity Conversion Interface] parameters which are default specified in configuration if you want to use them you put the USEDEFAULTPARAMETERS parameter value as ‘X’.

 

Extract from SAP FM Documentation for understanding.

 

If the value you enter for the CALCULATEMISSING parameter differs from the default value, the system determines all all necessary units of measure for this posting item and calculates the missing quantities. Otherwise you must ensure that the system can access all quantities in all required units of measure through the interface.

 

We are going to provide values.

 

For some materials the Air Buoyancy indicator is also a parameter for conversion that can be received from MARC.

 

        SELECT SINGLE umrsl abfac FROM marc
                             
INTO (lw_item_param-conversiongroup,
                                   lw_item_param
-airbuoyancyconstant )
                           
WHERE matnr = lw_g_odet-matnr
                              
AND werks = lw_tankm-werks.

       
IF sy-subrc IS INITIAL.
         
IF lw_item_param-airbuoyancyconstant IS NOT INITIAL.
            lw_item_param
-airbuoyancyindicator = 'X'.
         
ENDIF.
       
ENDIF.

        lw_item_param
-calculatemissing        = 'X'.
        lw_item_param
-testtemperature_density = '15.00'.
        lw_item_param
-testtemp_density_uom    = 'CEL'.

 

        lw_item_param-basedensity             = lw_tankm-tag_value.
        lw_item_param
-basedensityuom          = lw_tankm-tag_uom.
        lw_item_param
-testdensity             = lw_tankm-tag_value.
        lw_item_param
-testdensity_uom         = lw_tankm-tag_uom.

        lw_item_param-materialtemperature     = lw_tankm-tag_value.
        lw_item_param
-materialtemperature_uom = lw_tankm-tag_uom.

  

 

 

Another important point

 

 

There is a mapping between the item and item_param that is line_id they should be same for the item for which the parameter is passed.

 

        ADD 1 TO lw_item_count.
    lw_item
-line_id = lw_item_param-line_id = lw_item_count.

 

        APPEND lw_item       TO lt_item.
   
APPEND lw_item_param TO lt_item_param.

 

        CLEAR : lw_item,
           lw_item_param
.


 

 

Calling the BAPI

 

Finally we will call the BAPI to post the Document.

 

CALL FUNCTION 'BAPI_GOODSMVT_CREATE_OIL'
     
EXPORTING
        goodsmvt_header    
= lw_header
        goodsmvt_code      
= '04'
     
IMPORTING
        materialdocument   
= lw_doc_no
     
TABLES
        goodsmvt_item_01   
= lt_item
        goodsmvt_item_param
= lt_item_param
       
return              = lt_return.

   
IF lt_return IS INITIAL
  
AND lw_doc_no IS NOT INITIAL.
     
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' .
     
MESSAGE s110 WITH lw_doc_no.
   
ELSE.

     
CALL FUNCTION 'POPUP_WITH_TABLE_DISPLAY_OK'
       
EXPORTING
          endpos_col  
= 150
          endpos_row  
= 15
          startpos_col
= 5
          startpos_row
= 5
          titletext   
= text-002
       
TABLES
          valuetab    
= lt_return.

   
ENDIF.

Screen cast of Open XML documents Contents read

$
0
0

Hello.

This  is a screen-cast showing

Reading Contents of MS-Word documents ( Open XML documents )

form outside the SAP

into SAP content.

 

 

 

http://www.youtube.com/watch?v=Ratcsce-8qE

 

 

 

Open XML documents are manipulated on the SAP server

without using  MS-Word application.

 

this is done by ABAP objects using Open XML specification.

 

 

   Ronen Almog

MACROS in ABAP

$
0
0

Well, it is a very old methodology but still useful in some cases..... for those who are not aware....

 

Macro is just like Sub-routine BUT.... it has some differences.

 

MACROS needs to be declared before usage, Sub-routines can be called and defined later below in the program.

 

A macro can be used when we want to use the same set of statement multiple times.

 

A macro is either local and can be defined as :

 

DEFINE macro_name.

   statements

END-OF-DEFINITION.

 

The maximum number of parameters that can be passed in a macro are 9.

 

One of the possible example I could think is easy to understand is field catalog.

 

DEFINITION.

 

DEFINE Build_FCat.

    itfieldcat-fieldname  = &1.

    itfieldcat-col_pos     = &2.

    itfieldcat-seltext_l    = &3.

    itfieldcat-emphasize = &4.

    itfieldcat-outputlen   = &5.

    append itfieldcat to itfieldcat.

    clear itfieldcat.

END-OF-DEFINITION.

 

USAGE.

 

  Build_FCat 'EBELN'   '01'  'PO Number'   'X' 10.

  Build_FCat 'EBELP'   '02'  'PO Item'        ' ' 05.

  Build_FCat 'MAKTX'    '03' 'Description'    ' ' 25.

 

A macro can be GLOBAL and the best example is the BREAK statement of ABAP.

 

Global macros are defined in table TRMAC in SAP and can be used as you use the BREAK statement.

 

macro SM30.png

 

 

Now,

 

Macros don't belong to the definition part of the program. So you cannot debug them and they don't appear also in the debugger.

 

The best use would be to put logic that are complex calculations that you don't want to be disturbed in debug mode

 

Some checks which you want to over ride etc.

 

But in generalized way if used can save you lot of stuffs like using in QCI calculations for OIL material quantities to group it and get the table directly

 

Note : SAP recommends to use MACROS only in EXCEPTIONAL cases.

Global Data in ABAP OO Programs

$
0
0

I decided to spend a bit of time looking at some of the blogs being published out on SCN as I found myself with a bit of time.  Unfortunately I found a lot of examples of poor quality coding, obsolete techniques and non-nonsensical use of OO programming. 

 

As many people are pushing to learn the latest technologies, unfortunately there are many who have not yet grasped many of the fundamental principles of good quality coding.  More often than not I have found that having a solid understanding of the syntax and the basic design principles outlined by the good old gang of four has helped me to quickly get up to speed with new advances in technology.  There is no point trying to run, before you can  walk and eventually it shows in the work you deliver.  Testament to this is the WebDynpro developers that embed business logic in the Views of their WebDynpro components or the OO Developers that use classes in the same way they used to use function modules or subroutines. 

 

If you think you are in the above category, then I urge you to go back and learn the basics.  There is nothing to be ashamed of.  I recently did it myself.  Having been persecuted for so many years for trying to use OO techniques that I learnt at university (as it was not fair to other developers who could not code in OO) , I brushed off my old books and gemmed up. 

 

One of the key principles in programming is called the "Separation of Concerns".  So one of the first things that breaks this principle is the use of global data.  I'm sure you have come across a piece of code in a massive program in a huge subroutine and had a mental breakdown deciphering what the impact of your change is going to be.  Well if you modularise your code, preferably in OO, you have a lot less to worry about. 

 

The time for using global program variables (yes and even in report writing) can and should pretty much come to an end.  Below is a little sample report, which I think exemplifies the usage of passing references and minimal use of the global reference.  

 

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

*& Report  ZKP_TEMPLATE_REPORT

*&

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

*& A very simple MVC template for creating reports.

*& Note the distinct lack of global variables in the main program and

*& even in my classes. It is far better to pass references into methods,

*& then keep track of everything globally.

*&

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

 

REPORT  zkp_template_report.

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

*       CLASS zcl_report_model DEFINITION

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

* This is a really simplistic model but you could work with your own

* model objects and better incorporate inheritance if required,

* to better encapsulate your business logic

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

CLASS zcl_report_model DEFINITION.

   PUBLIC SECTION.

     " Shared type elements that are reused globally in my application

     " are placed here in the model

     TYPES: ty_carrid   TYPE RANGE OF s_carr_id,

            ty_currcode TYPE RANGE OF s_currcode,

            tty_scarr   TYPE STANDARD TABLE OF scarr WITH KEY carrid.

 

     METHODS: get_data IMPORTING im_carrid       TYPE zcl_report_model=>ty_carrid

                                 im_currcode     TYPE zcl_report_model=>ty_currcode

                       RETURNING value(re_scarr) TYPE tty_scarr.

 

   PRIVATE SECTION.

     " This is the only piece of global data I use in my application

     " it exists only as long as I have a reference to an instance of

     " this class in my program

     DATA: gt_scarr TYPE tty_scarr.

 

ENDCLASS.                    "zcl_report_model DEFINITION

 

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

*       CLASS zcl_report_view DEFINITION

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

* Your view is really how you intend to present the information. This

* class is abstract and so is the method implying you need to redefine

* it.  (Hence no implementation required)

* You may want to render your view in different ways ALV, FILE, EMAIL

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

CLASS zcl_report_view DEFINITION ABSTRACT.

   PUBLIC SECTION.

     METHODS: display_data ABSTRACT IMPORTING im_scarr TYPE zcl_report_model=>tty_scarr.

ENDCLASS.                    "zcl_report_view DEFINITION

 

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

*       CLASS zcl_report_view_alv DEFINITION

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

* So here is my new class that will implement the display method

* using an ALV.  You can do a lot here with the SALV class for

* displaying data, but this will be very simple.

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

CLASS zcl_report_view_alv DEFINITION FINAL INHERITING FROM zcl_report_view.

   PUBLIC SECTION.

     METHODS: display_data REDEFINITION.

ENDCLASS.                    "zcl_report_v

 

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

*       CLASS zcl_report_controller DEFINITION

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

* This class will be used to handle the flow of the program. Passing

* information from the views and requesting data from the model.

* No business logic should be placed here

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

CLASS zcl_report_controller DEFINITION ABSTRACT FINAL.

   PUBLIC SECTION.

     " Import all the report selection variables into the controller method

     " for executing the report

     CLASS-METHODS: execute_report

                      IMPORTING im_carrid   TYPE zcl_report_model=>ty_carrid

                                im_currcode TYPE zcl_report_model=>ty_currcode.

 

ENDCLASS.                    "zcl_report_controller DEFINITION

 

" I need a global data statement for my selection option

" I could create a generic select-option by adding the

" name in brackets, however I lose the benefits from the data dictionary

" Search helps etc in my selection screen

" Beyond this I will not use this reference again.

" It's not ideal but reporting was never going to be 100% OO

DATA: gt_scarr TYPE scarr.

 

" Replace these with your report variables

SELECT-OPTIONS: s_carrid FOR gt_scarr-carrid,

                 s_curcod FOR gt_scarr-currcode.

 

START-OF-SELECTION.

   " Now kick off the report logic

   zcl_report_controller=>execute_report( im_carrid   = s_carrid[]

                                          im_currcode = s_curcod[] ).

 

 

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

*       CLASS zcl_report_controller IMPLEMENTATION

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

*

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

CLASS zcl_report_controller IMPLEMENTATION.

   METHOD execute_report.

     DATA: lo_model    TYPE REF TO zcl_report_model,

           lt_scarr    TYPE zcl_report_model=>tty_scarr,

           lo_disp     TYPE REF TO zcl_report_view,

           lo_disp_alv TYPE REF TO zcl_report_view_alv.

 

     CREATE OBJECT lo_model.

 

" Execute the model method to retrieve the data I need for my report

     lt_scarr = lo_model->get_data( im_carrid   = im_carrid

                                    im_currcode = im_currcode ).

 

     CREATE OBJECT lo_disp_alv.

" Now output the data via the view

" The reason I have assigned the specialised ALV class reference to the

" generalised view class reference is purely overkill in this example.

" However I can very quickly create a new view class and assign this

" perhaps using a case statement to determine which view to output.

     lo_disp = lo_disp_alv.

     lo_disp->display_data( im_scarr = lt_scarr ).

   ENDMETHOD.                    "execute_report

ENDCLASS.                    "zcl_report_controller IMPLEMENTATION

 

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

*       CLASS zcl_report_view IMPLEMENTATION

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

*

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

CLASS zcl_report_view_alv IMPLEMENTATION.

   METHOD display_data.

     DATA: lo_salv_tab TYPE REF TO cl_salv_table,

           lx_salv_msg TYPE REF TO cx_salv_msg,

           lt_scarr    TYPE zcl_report_model=>tty_scarr.

 

     lt_scarr = im_scarr.

 

     TRY.

" The SALV classes are excellent for quickly generating output for display

" The factory method here generates a new instance based on my input data.

" I could manipulate the output further prior to display if I need

         cl_salv_table=>factory( IMPORTING r_salv_table = lo_salv_tab

                                 CHANGING  t_table      = lt_scarr ).

 

         lo_salv_tab->display( ).

       CATCH cx_salv_msg INTO lx_salv_msg.

         " You should use better exception handling here.  Possibly raise it up

         " to the controller class and deal with an appropriate action there

         MESSAGE e000(zkp) WITH 'An error occurred rendering the results'(001)

                                'as an ALV'(002).

     ENDTRY.

   ENDMETHOD.                    "display_data

ENDCLASS.                    "zcl_report_view IMPLEMENTATION

 

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

*       CLASS zcl_report_model IMPLEMENTATION

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

*

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

CLASS zcl_report_model IMPLEMENTATION.

   METHOD get_data.

     DATA: lt_scarr TYPE tty_scarr.

 

     IF gt_scarr IS NOT INITIAL.

       re_scarr = gt_scarr.

     ENDIF.

 

     SELECT *

       FROM scarr

       INTO TABLE lt_scarr

       WHERE carrid   IN im_carrid

       AND   currcode IN im_currcode.

 

     IF sy-subrc = 0.

       re_scarr = gt_scarr = lt_scarr.

     ENDIF.

   ENDMETHOD.                    "get_data

ENDCLASS.                    "zcl_report_model IMPLEMENTATION

 

 

At this point I won't be mentioning singleton classes in the context of global data, but they do have their place.  And there is a pretty good blog out there discussing this in ABAP.

Adding custom fields to the Purchase Order transaction ME21N HEADER & ITEM LEVEL.

$
0
0

I  searched for Enhancements for ME21N to add custom fields  . I found lot of examples unfortunately i didn't come across complete Step by Step Process.So i decided to give a elaborate document.

 

Enhancement used for ME21N , ME22N , ME23N is MM06E005.

 

1) If we know the Enhancement name we can directly use it or  we can search it in SMOD Transaction.

 


 

2) T code to implement Enhancement Project is CMOD.

 


 

Give Project name and click CREATE push button.

 

 

Give short text  and select COMPONENTS push button.

 

 

  In this screen we can find Function Exit, Screen Exit and Include tables.

For HEADER LEVEL - For adding Custom Tabs, Custom fields in Header level .

 

  EXIT_SAPMM06E_006 - Export Data to Customer Sub screen for Purchasing Document Header (PBO)

                                       This Function Exit is PBO (Process before output). We can add custom logic in this Exit.

 

   Process : Double click on EXIT_SAPMM06E_006 Go to SOURCE CODE tab and you will find INCLUDE file . double click the INCLUDE file and add your

   custom code.     

 

                                        INCLUDE ZXM06U36 .

 

 

 

  EXIT_SAPMM06E_007 - Export Data to Customer Sub screen for Purchasing Document Header (PAI)

                                       This Function Exit is PBO (Process before output). We can add custom logic in this Exit.

 

 

Process : Double click on EXIT_SAPMM06E_007 Go to SOURCE CODE tab and you will find INCLUDE file . double click the INCLUDE file and add your

   custom code.     

 

                                        INCLUDE ZXM06U38 .

 

For ITEM LEVEL - For adding Custom Tabs, Custom fields in Item level .

 


EXIT_SAPMM06E_016 : Export Data to Customer Sub screen for Purchasing Document Item (PBO).

 

EXIT_SAPMM06E_018 : Import Data from Customer Sub screen for Purchasing Document Item

 

 

Before Creating Screen.


Create STRUCTURE with Required Fields in custom  includes CI_EKKODB and CI_EKPODB

 


CI_EKKODB - Header Data.


 

 

CI_EKPODB-Item Data.

 


 

 

---> Now in Screen Exit Section.

 

use SAPMM06E this is Program Name.

 

     Go to SE38-- Create Program by giving name SAPMM06E.

     Go to SE51-- Create Sub-Screen with Screen Number 0111 ( Check Sub-Screen Box) .

 


 



----Now Adding Required Code----

 

Function Exit :
EXIT_SAPMM06E_016    - PBO

 

Include File:
INCLUDE ZXM06U41 .

 

 

 

Function Exit :

EXIT_SAPMM06E_018  - PAI

 

Include File:
INCLUDE ZXM06U40 .

 

This code is to Update Data Base Table EKPO.


 

Now Coding Part is Completed.

 

Go to ME21N  - In ITEM LEVEL You will find CUSTOMER DATA Tab. In that Tab you will find COST CENTER Field.

 

 

EKPO TABLE : CHECK THE DATA.

 


 

 

Same Steps you can follow for adding FIELDS in HEADER LEVEL .

Viewing all 948 articles
Browse latest View live


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