1 6 7 8 9 10 48 Previous Next

ABAP Development

707 Posts

When I talk with people about ABAP quality, the way they think of dumps always amazes me.

 

Most people believe dumps are their worst enemy. Actually they are not. Actually you're lucky if your software dumps.

 

How is that?

 

In order to understand this, we need to talk about why software dumps in the first place. Software dumps because it runs into a corrupt state it can no longer process, something virtually breaks and further processing is impossible. This results in a dump. Operation ends. Users swears.

 

While this is not good, it provides one important benefit: you now know you have a problem.

 

Ask yourself the following question: "What if my business application runs into a corrupt state and doesn't dump (right away) ?"

 

In this case your program may continue to operate for an unknown time span, potentially corrupting your persistent business data. If this happens, you won't find out for some time. If you find out, you may have a very hard time to recover from this data corruption and to trace it back to the actual programming defect that caused it.

 

Finding a problem that shows no (visible) symptoms can be extremely difficult. And its effects can be devastating once you discover them.

 

How would you - for example -  cure a disease that shows no (visible) symptoms? You couldn't. Because you don't know it's there. Until it may be too late. But if you see the symptoms, you can treat that disease and even take action to improve your health in general.

 

Under that aspect, you're lucky if your program dumps. It's like a problem that waves at you with a white flag: "Hey, here I am. Fix me!".

 

Now if you're a Padawan, you'll find the bug and you'll fix it.

 

If you're a Jedi, you'll think about a process to avoid robustness issues in the future.

 

And if you're a Jedi Master, you'll learn from every future mistake and adapt/improve your processes as new bugs come along.

 

I encourage you to see dumps as a chance, not an enemy. A chance to improve the development process. A chance to avoid similar mistakes in the future. And a reminder that robust programming matters for your business.

 

If you like to know more about avoiding robustness issues, I'd love to point you to another of my blog posts. Unfortunetaly SCN would see this as a "grounds for rejection". That's why I removed the link.

 

Dumps are not your only friend. Google is, too.

Every day you create or change ABAP class in class builder. When you activate your change, have you noticed a series of objects with several "=" in the middle part of each?

clipboard1.png

Technically speaking, an ABAP class consists of several parts. In order to figure them out, I just create a simple class with the following source code:

 

 

CLASS zcl_abap_class DEFINITION

  PUBLIC FINAL CREATE PUBLIC .

  PUBLIC SECTION.

    DATA public_attribure TYPE i .

    TYPES:BEGIN OF ty_global,

            name  TYPE string,

            score TYPE i,

          END OF ty_global.

    METHODS public .

protected section.

  data PROTECTED_ATTRIBUTE type I .

  methods PROTECTED .

  PRIVATE SECTION.

    DATA private_attribute TYPE i .

    METHODS private .

ENDCLASS.

CLASS ZCL_ABAP_CLASS IMPLEMENTATION.

  METHOD private.

  ENDMETHOD.

  method PROTECTED.

  endmethod.

  METHOD public.

  ENDMETHOD.

ENDCLASS.

I have also generated a local test class for it via SE80. After activation, look into corresponding entry in TRDIR.

clipboard2.png

The object name under column NAME could be opened via SE38. Take CCAU for example:

clipboard3.png

So CCAU contains the source code of local test class implementation:

clipboard4.png

Here below is the list of each part and its meaning:

 

Part NamePart meaning
CCAUcontains the source code of local test class implementation
CCDEFClass-Relevant Local Definitions, contains the definitions of local classes inside the public class
CCIMPIt contains the implementation for those local classes which definitions are stored in the Definitions-Include
CCMACcontains the macros of the public class
CIsource code of private section
COsource code of protected section
CUsource code of public section
CPopen it in SE38, it will automatically navigate to class builder
CTopen it in SE38, it will automatically navigate to class builder
CMXXXsource code of each method


The constant of part name is defined in type group SEOP:

clipboard7.png

If you need to get the part name of a given class via ABAP code, you can use utility class CL_OO_CLASSNAME_SERVICE. There are corresponding getter method for each kind of part defined.

 

For example, if you need to get the part name of all methods of class CL_CRM_BOL_CORE, just set breakpoint in method CL_OO_CLASSNAME_SERVICE =>GET_ALL_METHOD_INCLUDES, and open the class CL_CRM_BOL_CORE in SE24, and click "Source Code-Based" button:

clipboard8.png

Here you can find the name class part for each method are populated with one incremental step in hexadecimal.

Task essence:

My task was to set Block ID and Text automatically while end-user created purchase requisition in ME51N.

Why do it? Because, it should be approved in another SAP module (PSM-FM) and only after this it can be converted to PO.

1.jpg

                             

My solution:

First of all, look at SE11, structure MEREQ_ITEM_S_CUST_ALLOWED. There are no such fields (block id and text) there.

Create append structure.

1.jpg

Then, implement BADI ME_PROCESS_REQ_CUST, create 1 attribute and write code of 2 methods:


G_TRTYP Instance Attribute Private Type TRTYP

 

  METHOD if_ex_me_process_req_cust~open.
     me
->g_trtyp = im_trtyp .
 
ENDMETHOD.

 

  METHOD if_ex_me_process_req_cust~process_item.
   
CHECK  me->g_trtyp  = 'H' . " creatingmode
   
CHECK im_count = .

   
DATA  reqdata   TYPE mereq_item .
   
CLEAR: reqdata .
    reqdata
= im_item->get_data( ) .

    reqdata-blckd  
= '1' .
    reqdata-blckt  
= 'need to approve' .
    im_item
->set_data( reqdata ) .

   
DATA: ls_datax TYPE mereq_itemx.
   
MOVE: 'X' TO ls_datax-blckd,
         
'X' TO ls_datax-blckt.

   
im_item->set_datax( ls_datax ) .
ENDMETHOD.

 

That's all. Have a nice day

 

 

 

IMHO one purpose to write IF 1 = 0 code is to enable the cross reference of message raised in application code.

 

 

I have written several blogs to discuss the tip how to find the source code where the error message in UI is raised.

 

clipboard1.png

Most of the time you have to debug. ( Of course you can use source code scann approach to search the source code with keyword CRM_MDG_CORE 034 , the trouble is how you specify the package to be scanned, especially you are not familar with the application and you know nothing about package name at all )

 

 

The where used List on message could only identify those occurrence where the MESSAGE keyword appears in code.

clipboard2.png

clipboard3.png


For the use case in line 24 and 25 below, the where used list does not work. That is when IF 1 = 0 plays a part.

clipboard4.png

Recently in our code review meeting there are some arguments about this usage. The pros like this approach since it enable the cross reference on message raising by method call and ease the maintenance. The opposition consider that it is "unreached code" and should not appear in production code.

 

 

I just check in the system and find there are plenty of such usage in SAP standard code, also I tested that currently no ATC or extended check profile will complain about this "unreached code". Would you please kindly share your opinion of using IF 1 = 0 this way? Or do you have any concern about it?

Rainer Hübenthal

Multipart Emails

Posted by Rainer Hübenthal Mar 11, 2014

One of our customers requested data from SAP sent to him via Email. The data was a table and the customer complained that the presentation wasn't a in tabular form. Well, that is how plain text emails are working, you are sending text and the client software decides about the presentation. You do not have control over the used font and only with a monospaced font the table will be readable. A proportional font will distort the whole layout. The next try was to use tabs (0x09) but again you do not have control about the width of a tab. The result was a distorted table again.

 

Attachments like excel or PDF files were out of the question, too. So i had the idea of sending HTML emails, but they should have a fall back or at least a hint if the client software is unable to show HTML mails or was configured to only show text mails. In that case the body of the email appears empty. So i looked around and was sure to find something about multipart Emails containing a plain text part as well as a HTML part. But what a surprise, i was only able to find some fragments even in SCN and some postings on how to do it in PI with JAVA.

 

My intention was to use to the BCS classes as we have a central class wrapping all the necessary stuff in own methods. I will show the solution as own report which works fine in our environment, it's up to you to build a method for reusing the functionality

 

At least you need two tables containing the plain text and the html code. Both must be of type SOLI_TAB. That might be double work if you want to a have a fall back when only the plain text is displayed. At least there should be a hint that the main content is only visible in HTML mode. Those two tables needs to combined to a multipart/alternative document which can be achieved by the class CL_GBL_MULTIRELATED_SERVICE calling the methods set_main_text and set_main_html.

 

Instead of binding the text to the email with create_document from CL_DOCUMENT_BCS you just call the method create_from_multirelated.

 

The rest is now business as usual using the BCS classes to compose an email and send it to the recipients.

 

It was really easier as in my first thoughts and if i miss someones blog i apologize, but i really have bad search skills

 

As the source is really short i just past it here.

 

 

 

*&---------------------------------------------------------------------*
*& Report  Z_TEST_EMAIL
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT  z_test_email.
DATA:
  subject               TYPE so_obj_des,
  it_body_text         TYPE soli_tab,
  it_body_html         TYPE soli_tab,
  from                 TYPE ad_smtpadr,
  to                   TYPE ad_smtpadr.
DATA:
  document             TYPE REF TO cl_document_bcs,
  request              TYPE REF TO cl_bcs,
  mime_helper          TYPE REF TO cl_gbt_multirelated_service,
  sender               TYPE REF TO if_sender_bcs,
  recipient            TYPE REF TO if_recipient_bcs.
to      = 'receiver@example.org'.
from    = 'sender@example.org'.
subject = 'Tabular data'.
APPEND 'Hello World'           TO it_body_text.
APPEND 'Column 1     Column 2' TO it_body_text.
APPEND 'a            b'        TO it_body_text.
APPEND 'xyz          test'     TO it_body_text.
APPEND '4711         0815'     TO it_body_text.
APPEND '<html>'                      TO it_body_html.
APPEND '<head>'                      TO it_body_html.
APPEND '<title>MY HTML part</title>' TO it_body_html.
APPEND '</head>'                     TO it_body_html.
APPEND '<body>'                      TO it_body_html.
APPEND '<h1>Hello World!</h1>'       TO it_body_html.
APPEND '<table border="1">'          TO it_body_html.
APPEND '<tr><td>Column 1</td><td>Column 2</td></tr>' TO it_body_html.
APPEND '<tr><td>a</td><td>b</td></tr>'               TO it_body_html.
APPEND '<tr><td>xyz</td><td>test</td></tr>'          TO it_body_html.
APPEND '<tr><td>4711</td><td>0815</td></tr>'         TO it_body_html.
APPEND '</table>' TO it_body_html.
APPEND '</body>'  TO it_body_html.
APPEND '</html>'  TO it_body_html.
CREATE OBJECT mime_helper.
mime_helper->set_main_text( content = it_body_text ).
mime_helper->set_main_html( content = it_body_html ).
document = cl_document_bcs=>create_from_multirelated(
  i_subject          = subject
  i_multirel_service = mime_helper ).
request = cl_bcs=>create_persistent( ).
request->set_document( document ).
IF from IS NOT INITIAL.
  sender = cl_cam_address_bcs=>create_internet_address( from ).
ELSE.
  sender = cl_sapuser_bcs=>create( sy-uname ).
ENDIF.
request->set_sender( sender ).
recipient = cl_cam_address_bcs=>create_internet_address( to ).
request->add_recipient( EXPORTING i_recipient = recipient ).
request->set_send_immediately( 'X' ).
IF request->send( i_with_error_screen = 'X' ) = 'X'.
  WRITE:/ 'Email sent succesfully'.
ELSE.
  WRITE:/ ' Error sending email'.
ENDIF.
COMMIT WORK.

I was searching for reports which can give up a report of Vendor classification used in vendore master.This blog is about getting the report for vendor classification in the Vendor master data. Also you can use this in many places to build your own logic.

 

There are 2 ways to do this .

1. We can use a standard BAPI and then call it in a loop by extracting data from KSSK.

     So as step 1 get the list of Vendors who are having valid vendor characteristics from table KSSK.

     Now loop thourhg thie table and then pass value to the BAPI 'BAPI_OBJCL_GETDETAIL'.

 

 

BAPI.JPG

Pass the values like above.

Object Key is your vendor number

Object Table will be LFA1.

CLASSNUM -. pass from KSSK.

Class type also from KSSK or mostly this will be 010 only.

 

You will get the result as below.

bapiresult.JPG

 

2. Build report using the below tables.

Table:

KSSK - Pass vendor number in Object (add preceding Zeros)  and class type '010'.

KLAH - This will give the class

KSML - give give more detals of vendor classification

AUSP - Here pass the vendor number as the Object and the Internal char. from the previus table KSML and you will get the details.

 

 

Regards,

Vijay V

the idea comes from Sougata Chatterjee's anwser in this thread:


Suppose I need to add the maintenance view COMV_PARTNER_FCT to my favorite list. I expect once the entry in the favorite list is double clicked, it will automatically navigate to the view detail like below ( the initial screen of SM30 is not expected )


clipboard1.png

Create a new transaction code and maintain SM30 as default value for transaction:

clipboard2.png

Just maintain the maintenance view name as the default value for screen field VIEWNAME:

clipboard3.png

You can find the screen name by put the focus on input field for view name in SM30, and click F1,

clipboard4.png

then click "Technical Information" icon,

clipboard5.png

then you get the screenfield name:

clipboard6.png

The last step is adding the new transaction code to my favorite. Unfortunately when I test it, it fails to work and raised the following error message.

The initial screen still remains without any automatic navigation to detail of view COMV_PARTNER_FCT.

clipboard7.png


we can find the location where this error message is raised by this tip and know the error is caused since we didn't specify any action like UPDATE, SHOW or TRANSPORT.

clipboard8.png

Then go back to SE93 and add another entry with SHOW = X and after that issue is resolved.

clipboard10.png

Before you read this: I’ve spent some time debugging the things I describe here, I thoroughly searched SCN, I used my brain and although it can sound like one big low-brainer what I describe here, I still think it is worth writing about it. I don’t think I am a beginner with ALV, be it grid ALV or tree ALV and this was driving me nuts for two hours. And it is un-debug-able.

In case the lesson learnt is not clear after reading the blog I rather put it right here upfront. Most (if not all) cryptic ALV dumps are caused by your program errors rather than SAP GUI problems, patch levels etc. The ALV classes are not so “smart” (or “tolerant”) as I would build them.


Dump 1: class CL_ALV_TREE_BASE method QUEUE_APPEND_NODES

Symptom: My code building a CL_GUI_ALV_TREE finished without any errors. I was catching and handling all SY-SUBRC problems returned by the CL_GUI_ALV_TREE methods so the problem could not be coming from there. I mean it couldn’t be a missing exception not handled correctly. Also no SY-SUBRC problem ever happened in the coding. The UI was drawing the ALV tree correctly too.

The problem was only hitting the program when I wanted to expand one of the nodes. No nodes were created expanded, but the nodes that were direct children of the VIRTUAL_ROOT were visible of course (in other words my tree does not have one root node only, it has a list of “root” nodes). When I clicked on the expander of these nodes, I got the dump below.

 

Analysis: I checked SDN. Three posts (I probably took the wrong keywords… I tried multiple combinations though). Two were duplicates (one thread about the same problem without any answer and one hijacked post by the person who posted the first one) and the third one was irrelevant. Some less relevant posts were suggesting that it is “definitely” a patch level or a SAP GUI problem. But I also saw some wise men and women saying that it can be a coding problem.

 

Solution: Eureka moment stroke and I tried to add CALL METHOD me->tree->frontend_update. That fixed the problem. So at the end of my PBO method the front-end update was needed. Without it the UI got created but dumped afterwards. Maybe this is a low-brainer. But maybe this spares other people some time when the search (it should also spare the SCN some questions about it too).

 

Keywords if anyone searches about the problem in the future:

"RAISE_EXCEPTION" " "

"CL_ALV_TREE_BASE==============CP" or "CL_ALV_TREE_BASE==============CM014"

"QUEUE_APPEND_NODES"

 

queue.png

 

Dump 2: class CL_GUI_CFW method FLUSH

Symptom: No problems happen when the tree ALV hierarchy is being built but when it comes to flushing the UI so the user can have some fun too, you hit this dump.

 

Analysis: I was experimenting a bit, so I knew what could be causing the problem. Lesson learnt: Don’t try to be too smart. What I wanted to achieve was I wanted to expand all nodes in my tree with one simple command (without collecting the first level nodes, which are “roots” -> this is crazy for someone who knows that a tree has one root only, otherwise it is a forest, isn’t it). So what I tried was the following:

me->tree->expand_node( i_node_key = me->tree->c_virtual_root_node i_expand_subtree = 'X' ).


Unfortunately SAP was not "nice" enough to support such an option. That also explains the number of SCN posts asking about how to expand the whole tree at once and no post I found proposed a simple solution for this. Some suggested creating an explicit “artificial” root so that you have a root that you can expand that one with one simple command (EXPAND_NODE with the correct I_NODE_KEY), others suggested collecting the nodes you want to expand into a list and calling EXPAND_NODES instead. Take your pick.

If I may have a wish, could someone in the ALV development team at SAP consider supporting this? I mean the C_VIRTUAL_ROOT_NODE constant as a special case? If not, I would be interested to know why not (what is preventing it, why it is a good idea or why it is not needed -> so that I don’t have to create a mess in my program by collecting nodes I need to expand).

Bad idea number 2: I want to expand my whole ALV tree using the following:

  CLEAR lt_keys[].
LOOP AT me->mapping ASSIGNING <fs_map>.
APPEND <fs_map>-nkey TO lt_keys.
ENDLOOP.

CALL METHOD me->tree->frontend_update.

me
->tree->expand_nodes( it_node_key = lt_keys ).

CALL METHOD me->tree->frontend_update.

BOOM! The same dump again. So maybe we have too many front-end updates here. So we remove the first one and… BOOM! The previous dump (QUEUE_APPEND_NODES) comes again. So the following does not work either.

me->tree->expand_nodes( it_node_key = lt_keys ).

CALL METHOD me->tree->frontend_update.

 

Maybe we could swtch the two commands like this…?

  CALL METHOD me->tree->frontend_update.

me
->tree->expand_nodes( it_node_key = lt_keys ).

 

BOOM! The FLUSH dump again.

Last idea around the topic: Maybe the problem is that EXPAND_NODES calls front-end update too? Then EXPAND_NODES only (without any front-end updates) could work? Nope. QUEUE_APPEND_NODES dump strikes again.

Completely different idea: Maybe the tree control is not so smart and when I add a node I want expanded which has no children (no point in expanding), then it dumps. So I check that in my coding and let’s see what happens. The code now looks like this:

  CLEAR lt_keys[].
LOOP AT me->mapping ASSIGNING <fs_map>.
CALL METHOD me->tree->get_first_child
EXPORTING
i_node_key      
= <fs_map>-nkey
IMPORTING
e_child_node_key
= lv_dummy.
IF NOT lv_dummy IS INITIAL.
APPEND <fs_map>-nkey TO lt_keys.
ENDIF.
ENDLOOP.

CALL METHOD me->tree->frontend_update.

me
->tree->expand_nodes( it_node_key = lt_keys ).

 

…and drumrolls… it works now

 

Keywords if anyone searches about the problem in the future:

"MESSAGE_TYPE_X" " "

"CL_GUI_CFW====================CP" or "CL_GUI_CFW====================CM002"

"FLUSH"

 

CALL FUNCTION 'AC_FLUSH_CALL'

     EXPORTING

SYSTEM_FLUSH = ' '

     IMPORTING

MESSAGE_NR   = rc

MESSAGE_TEXT = msgli.

 

    WHEN 2.

* method_call_error

      MESSAGE ID 'CNDP' TYPE 'X' NUMBER 006 RAISING CNTL_ERROR.

 

flush.png

 

Dump 3: Surprise! Surprise! No more dumps…

Last but not least: Some fun with dumps (sounds like "Fun with flags", right?). This is a real one, not a joke.

 

no_dumps.png

Sometimes the task is not to create order through Bapi, because in this case it will be saved,
if not error occured. If you need to go into a standard transaction, passing
with some header information and items. Here are fragments of programs that
make it easy to do this:

 

1) Purchase Order.

  Imagine, you have
an ALV report with output table gt_outtab and columns banfn and bnfpo -
purchase requisition no and item. no.

 

  DATA : header                        LIKE mepoheader,
       mepo_doc       
TYPE mepo_document,
       requisitions   
TYPE  mereq_t_eban_mem,
       wa_requisitions
LIKE LINE OF requisitions,
       items          
LIKE  mepoitem OCCURS 0 WITH HEADER LINE .
DATAlr_selections   TYPE REF TO cl_salv_selections,
       lt_rows        
TYPE salv_t_row,
       ls_row         
LIKE LINE OF  lt_rows.


  lr_selections
= gr_table->get_selections( ).
  lt_rows
= lr_selections->get_selected_rows( ).
 
IF lt_rows IS INITIAL .
   
MESSAGE s001 WITH 'select any line' .
   
EXIT .
 
ENDIF.
 
CLEAR : items , items[]  .
 
LOOP AT lt_rows INTO l_row.
   
READ TABLE gt_outtab INDEX l_row .
   
CHECK gt_outtab-ebeln IS INITIAL .
   
ADD 10 TO items-ebelp .
    items
-banfn = gt_outtab-banfn .
    items
-bnfpo = gt_outtab-bnfpo .
   
APPEND items.
 
ENDLOOP .

* call me21n
 
CALL FUNCTION 'WB2_PO_PROCESS_START'
   
EXPORTING
      im_ekko              
= header
      im_aktyp             
= 'H'
   
IMPORTING
      ch_requisitions      
= requisitions
   
TABLES
      cht_items            
= items
   
CHANGING
      ch_document          
= mepo_doc
   
EXCEPTIONS
      invalid_call         
= 1
      invalid_activity_type
= 2
      done                 
= 3
      error                
= 4
     
OTHERS                = 5.

 
IF sy-subrc <> 0.
* Implement suitable error handling here
 
ENDIF.

 

2)Sales order basis on previous sales document. Vbeln - number of previous sales document.

  SELECT SINGLE * FROM vbak INTO wa_vbak
        
WHERE vbeln = vbeln.

 

CALL FUNCTION 'Z_MAP_VBAKKOM_2_HDRIN' " code of FM below
   
EXPORTING
      i_vbakkom      
= vbakkom
   
IMPORTING
      order_header_in
= sales_header_in.

  CLEAR : sales_partners , sales_partners[].

 
DATA t_vbpa     LIKE vbpa OCCURS 0 WITH HEADER LINE  .
 
SELECT * FROM vbpa INTO TABLE t_vbpa WHERE vbeln = wa_vbak-vbeln .
 
LOOP AT t_vbpa .
    sales_partners
-partn_role = t_vbpa-parvw.
   
IF NOT t_vbpa-kunnr IS INITIAL   .
      sales_partners
-partn_numb = t_vbpa-kunnr.
   
ELSEIF NOT t_vbpa-pernr IS INITIAL   .
      sales_partners
-partn_numb = t_vbpa-pernr .
   
ENDIF .
    sales_partners
-itm_number = t_vbpa-posnr .
   
APPEND sales_partners.
 
ENDLOOP.

 

* items
 
CLEAR : sales_items_in[] ,      sales_items_in,
          sales_schedules_in[]
sales_schedules_in,
          sales_conditions_in[]
, sales_conditions_in,
          tab_root_instances[]
root_instances.

   
SELECT * FROM vbap INTO wa_vbap WHERE vbeln = vbeln.

     sales_items_in-itm_number     = wa_vbap-posnr .
    sales_items_in
-material       = wa_vbap-matnr .
    sales_items_in
-reason_rej     = wa_vbap-abgru .
    sales_items_in
-ref_doc        = wa_vbap-vbeln .
    sales_items_in
-ref_doc_it     = wa_vbap-posnr .
    sales_items_in
-ref_doc_ca     = wa_vbak-vbtyp .
    sales_items_in
-plant          = wa_vbap-werks .
    sales_items_in
-store_loc      = wa_vbap-lgort .
    sales_items_in
-po_itm_no      = sales_items_in-itm_number .
   
IF vbtyp_v = 'B'. " next doc is contract
      sales_items_in
-target_qty     wa_vbap-orfmng  .
   
ELSE .
      sales_schedules_in
-itm_number     = sales_items_in-itm_number .
      sales_schedules_in
-sched_line     = 1 .
      sales_schedules_in
-req_qty        = wa_vbap-orfmng   .
     
APPEND sales_schedules_in .
   
ENDIF .
   
APPEND sales_items_in.

* conditions
   
DATA amount_external LIKE  bapicurr-bapicurr .
   
SELECT        * FROM  konv INTO wa_konv
                   
WHERE  knumv  = wa_vbak-knumv
                     
AND  kposn  = wa_vbap-posnr
                     
AND  kherk  = 'C'.    " manual conditions
     
IF wa_konv-krech = 'A' .  
        wa_konv
-kbetr = wa_konv-kbetr / 10 .
     
ENDIF .
     
MOVE-CORRESPONDING wa_konv TO komv.
     
CALL FUNCTION 'MAP2E_KOMV_TO_BAPISDCOND'
       
EXPORTING
          komv      
= komv
       
CHANGING
          bapisdcond
= bapisdcond.

     
MOVE-CORRESPONDING bapisdcond TO sales_conditions_in .
     
IF bapisdcond-currency IS NOT INITIAL .
       
CALL FUNCTION 'BAPI_CURRENCY_CONV_TO_EXTERNAL'
         
EXPORTING
           
currency        = bapisdcond-currency
            amount_internal
= bapisdcond-cond_value
         
IMPORTING
            amount_external
= amount_external.
        sales_conditions_in
-cond_value = amount_external.
     
ENDIF .

      sales_conditions_in
-itm_number = sales_items_in-itm_number .
     
APPEND sales_conditions_in .
   
ENDSELECT.

   
IF tc = 'X'  .   " configuration if vehicle, variable tc is flag - material is vehicle

       root_instances-instance_no = wa_vbap-cuobj .
      root_instances
-posex  = sales_items_in-po_itm_no  .   
     
APPEND  root_instances TO tab_root_instances .
   
ENDIF .

 
ENDSELECT .

 

   IF tc = 'X'  .   " read configuration of previous doc. if it is vehicle
   
CALL FUNCTION 'CUXI_GET_MULTI_CONFIGURATION'
     
EXPORTING
        i_tab_root_instances        
= tab_root_instances
     
TABLES
        e_tab_cfg_headers           
= e_tab_cfg_headers
        e_tab_instances             
= e_tab_instances
        e_tab_part_of               
= e_tab_part_of
        e_tab_values                
= e_tab_values
        e_tab_var_keys              
= e_tab_var_keys
     
EXCEPTIONS
        invalid_instance            
= 1
        instance_is_a_classification
= 2
        no_root_instance            
= 3
        internal_error              
= 4
        invalid_data                
= 5
       
OTHERS                       = 6.


** clear some fields
   
LOOP AT e_tab_cfg_headers INTO  cfg_headers .
     
CLEAR :   cfg_headers-sce ,
                cfg_headers
-kbname,
                cfg_headers
-kbversion,
                cfg_headers
-complete,
                cfg_headers
-consistent,
                cfg_headers
-cfginfo,
                cfg_headers
-kbprofile,
                cfg_headers
-kblanguage,
                cfg_headers
-cbase_id,
                cfg_headers
-cbase_id_type .
     
MODIFY e_tab_cfg_headers  FROM cfg_headers.
   
ENDLOOP .

   
LOOP AT e_tab_instances INTO  instances .
     
CLEAR : instances-obj_txt ,
              instances
-quantity ,
              instances
-author ,
              instances
-quantity_unit ,
              instances
-complete ,
              instances
-consistent ,
              instances
-object_guid ,
              instances
-persist_id ,
              instances
-persist_id_type .
     
MODIFY e_tab_instances FROM instances .
   
ENDLOOP .

   
LOOP AT e_tab_values INTO values.
     
CLEAR  values-valcode .
     
MODIFY e_tab_values FROM  values .
   
ENDLOOP.
 
ENDIF .

 

 

* header conditions
 
SELECT        * FROM  konv INTO wa_konv
                 
WHERE  knumv  = wa_vbak-knumv
                   
AND  kposn  = '000000'
                   
AND  kherk  = 'C'.    " manual
   
IF wa_konv-krech = 'A' .        

      wa_konv-kbetr = wa_konv-kbetr / 10 .
   
ENDIF .
   
MOVE-CORRESPONDING wa_konv TO komv.
   
CALL FUNCTION 'MAP2E_KOMV_TO_BAPISDCOND'
     
EXPORTING
        komv      
= komv
     
CHANGING
        bapisdcond
= bapisdcond.

   
MOVE-CORRESPONDING bapisdcond TO sales_conditions_in .
    sales_conditions_in
-itm_number = '000000' .
   
APPEND sales_conditions_in .
 
ENDSELECT.

 

 

CALL FUNCTION 'BAPI_SALESDOCU_CREATEWITHDIA'
 
EXPORTING
    sales_header_in              
= sales_header_in

   synchronous                   = 'X'

   IMPORTING
   salesdocument_ex             
= vbeln_so
TABLES
  
return                        = return
   sales_items_in               
= sales_items_in

    sales_partners                = sales_partners
   sales_schedules_in           
= sales_schedules_in
   sales_conditions_in          
= sales_conditions_in
   sales_cfgs_ref               
= e_tab_cfg_headers
   sales_cfgs_inst              
= e_tab_instances
   sales_cfgs_value             
= e_tab_values .

 

 

  FUNCTION Z_MAP_VBAKKOM_2_HDRIN.
*"----------------------------------------------------------------------
*"*"Локальный интерфейс:
*"  IMPORTING
*"     REFERENCE(I_VBAKKOM) TYPE  VBAKKOM
*"  EXPORTING
*"     REFERENCE(ORDER_HEADER_IN) TYPE  BAPISDHEAD1
*"----------------------------------------------------------------------
 
MOVE i_vbakkom-auart TO order_header_in-doc_type        .
 
MOVE i_vbakkom-submi TO order_header_in-collect_no      .
 
MOVE i_vbakkom-vkorg TO order_header_in-sales_org       .
 
MOVE i_vbakkom-vtweg TO order_header_in-distr_chan      .
 
MOVE i_vbakkom-spart TO order_header_in-division        .
 
MOVE i_vbakkom-vkgrp TO order_header_in-sales_grp       .
 
MOVE i_vbakkom-vkbur TO order_header_in-sales_off       .
 
MOVE i_vbakkom-vdatu TO order_header_in-req_date_h      .
 
MOVE i_vbakkom-vprgr TO order_header_in-date_type       .
 
MOVE i_vbakkom-bsark TO order_header_in-po_method       .
 
MOVE i_vbakkom-bstdk TO order_header_in-purch_date      .
 
MOVE i_vbakkom-bstzd TO order_header_in-po_supplem      .
 
MOVE i_vbakkom-ihrez TO order_header_in-ref_1           .
 
MOVE i_vbakkom-bname TO order_header_in-name            .
 
MOVE i_vbakkom-telf1 TO order_header_in-telephone       .
 
MOVE i_vbakkom-konda TO order_header_in-price_grp       .
 
MOVE i_vbakkom-kdgrp TO order_header_in-cust_group      .
 
MOVE i_vbakkom-bzirk TO order_header_in-sales_dist      .
 
MOVE i_vbakkom-pltyp TO order_header_in-price_list      .
 
MOVE i_vbakkom-inco1 TO order_header_in-incoterms1      .
 
MOVE i_vbakkom-inco2 TO order_header_in-incoterms2      .
 
MOVE i_vbakkom-zterm TO order_header_in-pmnttrms        .
 
MOVE i_vbakkom-lifsk TO order_header_in-dlv_block       .
 
MOVE i_vbakkom-faksk TO order_header_in-bill_block      .
 
MOVE i_vbakkom-augru TO order_header_in-ord_reason      .
 
MOVE i_vbakkom-autlf TO order_header_in-compl_dlv       .
 
MOVE i_vbakkom-prsdt TO order_header_in-price_date      .
 
MOVE i_vbakkom-angdt TO order_header_in-qt_valid_f      .
 
MOVE i_vbakkom-bnddt TO order_header_in-qt_valid_t      .
 
MOVE i_vbakkom-guebg TO order_header_in-ct_valid_f      .
 
MOVE i_vbakkom-gueen TO order_header_in-ct_valid_t      .
 
MOVE i_vbakkom-kvgr1 TO order_header_in-cust_grp1       .
 
MOVE i_vbakkom-kvgr2 TO order_header_in-cust_grp2       .
 
MOVE i_vbakkom-kvgr3 TO order_header_in-cust_grp3       .
 
MOVE i_vbakkom-kvgr4 TO order_header_in-cust_grp4       .
 
MOVE i_vbakkom-kvgr5 TO order_header_in-cust_grp5       .
 
MOVE i_vbakkom-bstkd TO order_header_in-purch_no_c      .
 
MOVE i_vbakkom-bstkd_e TO order_header_in-purch_no_s      .
 
MOVE i_vbakkom-bstdk_e TO order_header_in-po_dat_s        .
 
MOVE i_vbakkom-bsark_e TO order_header_in-po_meth_s       .
 
MOVE i_vbakkom-ihrez_e TO order_header_in-ref_1_s         .
 
MOVE i_vbakkom-audat TO order_header_in-doc_date        .
 
MOVE i_vbakkom-gwldt TO order_header_in-war_date        .
 
MOVE i_vbakkom-vsbed TO order_header_in-ship_cond       .
 
MOVE i_vbakkom-ktext TO order_header_in-pp_search       .
 
MOVE i_vbakkom-mahza TO order_header_in-dun_count       .
 
MOVE i_vbakkom-mahdt TO order_header_in-dun_date        .
 
MOVE i_vbakkom-abrvw TO order_header_in-dlvscheduse     .
 
MOVE i_vbakkom-abdis TO order_header_in-plan_dlv_schtype.
 
MOVE i_vbakkom-vgbel TO order_header_in-ref_doc         .
 
MOVE i_vbakkom-bukrs_vf TO order_header_in-comp_code_b     .
 
MOVE i_vbakkom-taxk1 TO order_header_in-alt_tax_class   .
 
MOVE i_vbakkom-taxk2 TO order_header_in-tax_class2      .
 
MOVE i_vbakkom-taxk3 TO order_header_in-tax_class3      .
 
MOVE i_vbakkom-taxk4 TO order_header_in-tax_class4      .
 
MOVE i_vbakkom-taxk5 TO order_header_in-tax_class5      .
 
MOVE i_vbakkom-taxk6 TO order_header_in-tax_class6      .
 
MOVE i_vbakkom-taxk7 TO order_header_in-tax_class7      .
 
MOVE i_vbakkom-taxk8 TO order_header_in-tax_class8      .
 
MOVE i_vbakkom-taxk9 TO order_header_in-tax_class9      .
 
MOVE i_vbakkom-xblnr TO order_header_in-ref_doc_l       .
 
MOVE i_vbakkom-zuonr TO order_header_in-***_number      .
 
MOVE i_vbakkom-vgtyp TO order_header_in-ref_doc_cat     .
 
MOVE i_vbakkom-kzazu TO order_header_in-ord_comb_in     .
 
MOVE i_vbakkom-perfk TO order_header_in-bill_sched      .
 
MOVE i_vbakkom-perrl TO order_header_in-invo_sched      .
 
MOVE i_vbakkom-mrnkz TO order_header_in-mn_invoice      .
 
MOVE i_vbakkom-kurrf TO order_header_in-exch_rate_fi    .
 
MOVE i_vbakkom-valtg TO order_header_in-add_val_dy      .
 
MOVE i_vbakkom-valdt TO order_header_in-fix_val_dy      .
 
MOVE i_vbakkom-zlsch TO order_header_in-pymt_meth       .
 
MOVE i_vbakkom-ktgrd TO order_header_in-accnt_asgn      .
 
MOVE i_vbakkom-kursk TO order_header_in-exchg_rate      .
 
MOVE i_vbakkom-fkdat TO order_header_in-bill_date       .
 
MOVE i_vbakkom-fbuda TO order_header_in-serv_date       .
 
MOVE i_vbakkom-mschl TO order_header_in-dunn_key        .
 
MOVE i_vbakkom-mansp TO order_header_in-dunn_block      .
 
MOVE i_vbakkom-abssc TO order_header_in-pymt_gar_proc   .
 
MOVE i_vbakkom-abtnr TO order_header_in-department_no   .
 
MOVE i_vbakkom-empst TO order_header_in-rec_point       .
 
MOVE i_vbakkom-lcnum TO order_header_in-doc_num_fi      .
 
MOVE i_vbakkom-kdkg1 TO order_header_in-cust_cond_grp1  .
 
MOVE i_vbakkom-kdkg2 TO order_header_in-cust_cond_grp2  .
 
MOVE i_vbakkom-kdkg3 TO order_header_in-cust_cond_grp3  .
 
MOVE i_vbakkom-kdkg4 TO order_header_in-cust_cond_grp4  .
 
MOVE i_vbakkom-kdkg5 TO order_header_in-cust_cond_grp5  .
 
MOVE i_vbakkom-delco TO order_header_in-dlv_time        .
 
MOVE i_vbakkom-waerk TO order_header_in-CURRENCY        .
 
MOVE i_vbakkom-ernam TO order_header_in-created_by      .
 
MOVE i_vbakkom-landtx TO order_header_in-tax_depart_cty  .
 
MOVE i_vbakkom-stceg_l TO order_header_in-tax_dest_cty    .
 
MOVE i_vbakkom-xegdr TO order_header_in-eu_triang_deal  .
 
MOVE i_vbakkom-vbeln_grp TO order_header_in-master_contr    .
 
MOVE i_vbakkom-scheme_grp TO order_header_in-ref_proc        .
 
MOVE i_vbakkom-abruf_part TO order_header_in-check_partn_auth.
 
MOVE i_vbakkom-dat_fzau TO order_header_in-cml_qty_date    .
 
MOVE i_vbakkom-vsnmr_v TO order_header_in-version         .
 
MOVE i_vbakkom-qmnum TO order_header_in-notif_no        .
 
MOVE i_vbakkom-vkont TO order_header_in-fkk_conacct     .

ENDFUNCTION.

Hi SCN,

 

I'm currently working on SAP integration with Excel and want to share my developments with the SCN Community.
In this first part of the integration project I'll share my development to export the data in any SAP table to an Excel spreadsheet.

 

I have also plans on working out a second and a third part:

  • Part 2: Automatic daily backup/export data from multiple SAP tables to Excel
  • Part 3: Insert/update data from Excel to an SAP table.

 

I don't claim that this is the best/fastest way to export data to Excel, but it's a working program which can make dynamic exports of table data.

If you have any questions/remarks about this blog post, feel free to contact me .

 

Program output:


Upon running the program, the user gets to see the following startscreen:

1.JPG

In this screen the user can enter a table or press F4 to look for a table with the search help.

After choosing a table, the path input field can be accessed:

2.JPG

A valid path and table need to be entered, else the user will get an error message.

 

You can press F4 in the Path field to specify a path.

The name of the file will be automatically generated to "name of table + export_to_excel + date" (can be changed).

3.JPG

After saving the path and executing the program the file will be created in the specified location.
4.JPG

Result of the exported data in Excel:

5.JPG

 

Let's dig into the coding:


Data declarations:

DATA: v_default_file_name TYPE string,

      v_filename          TYPE string,

      v_file_path         TYPE string,

      wa_table            TYPE dd02l,

      check_path          TYPE string,

      v_select            TYPE string,

      t_fieldcat          TYPE lvc_t_fcat,

      v_xml_version       TYPE string,

      v_xml_flavour       TYPE string,

      v_xstring           TYPE xstring,

      v_size              TYPE i,

      gt_bintab           TYPE solix_tab.

 

DATA: r_data        TYPE REF TO data,

      r_structdescr TYPE REF TO cl_abap_structdescr,

      r_table       TYPE REF TO cl_salv_table,

      r_columns     TYPE REF TO cl_salv_columns_table,

      r_aggreg      TYPE REF TO cl_salv_aggregations,

      r_result_data TYPE REF TO cl_salv_ex_result_data_table.

 

FIELD-SYMBOLS: <table> TYPE ANY TABLE,

               <fs_component> TYPE abap_compdescr.

 

PARAMETERS: p_table TYPE dd02l-tabname .

PARAMETERS: p_path  TYPE string        OBLIGATORY.

Initialization:

If the table parameter is not specified, no path may be specified:

INITIALIZATION.

  LOOP AT SCREEN.

    IF screen-name = 'P_PATH'.

      screen-input = '0'.

      MODIFY SCREEN.

      EXIT.

    ENDIF.

  ENDLOOP.

When F4 is pressed in path to select a path:

Generates a pop-up window that generates a default name.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_path.

 

  CONCATENATE p_table '_EXPORT_TO_EXCEL_' sy-datum INTO v_default_file_name.

 

  cl_gui_frontend_services=>file_save_dialog(

    EXPORTING

      window_title        = 'Navigate to location and enter file name'

      default_extension   = 'XLS'

      default_file_name   = v_default_file_name

      initial_directory   = 'Desktop'

      prompt_on_overwrite = 'X'

    CHANGING

      filename            = v_filename

      path                = v_file_path

      fullpath            = p_path

    EXCEPTIONS

      cntl_error          = 1

      error_no_gui        = 2

      not_supported_by_gui = 3

      OTHERS              = 4

         ).

  IF sy-subrc <> 0.

*   TODO: Error Handling

  ENDIF.

When the program gets executed:

The input parameters gets checked to see if an existing table name and a correct file path are entered.

If this is the case, data of the table will be selected, the excel output data will be build and the excel file will be exported to the path.

START-OF-SELECTION.

 

  TRANSLATE v_file_path TO UPPER CASE.

  CONCATENATE v_file_path v_default_file_name '.XLS' INTO check_path.

 

  SELECT SINGLE tabname INTO wa_table FROM dd02l

        WHERE tabname   EQ p_table

          AND tabclass  EQ 'TRANSP'.

 

  IF sy-subrc NE 0.

    MESSAGE i000(your message class here). "If table does not exist

    EXIT.

  ENDIF.

 

  IF p_path EQ check_path.

 

*   Select all data

    PERFORM get_table_data.

*   Build excel output data

    PERFORM build_excel_data.

*   Export excel file

    PERFORM export_excel.

 

  ELSE.

    MESSAGE i001(your message class here). "Invalid path

    EXIT.

  ENDIF.

Form get_table_data: will get all the data of the table specified as parameter (dynamically)

FORM get_table_data.

 

  CREATE DATA r_data TYPE STANDARD TABLE OF (p_table).

  ASSIGN r_data->* TO <table>.

 

* Get all columns for select

  r_structdescr ?= cl_abap_structdescr=>describe_by_name( p_table ).

  IF r_structdescr IS BOUND.

    LOOP AT r_structdescr->components[] ASSIGNING <fs_component>.

      CONCATENATE v_select <fs_component>-name INTO v_select SEPARATED BY space.

    ENDLOOP.

  ENDIF.

 

* Select all data

  SELECT (v_select) FROM (p_table) INTO TABLE <table>.

 

ENDFORM.                    "get_table_data

Form build_excel_data:

In this form, the SAP data will be converted to XML (xstring) which is needed for the export.

FORM build_excel_data.

 

  TRY.

      cl_salv_table=>factory(

      EXPORTING

        list_display = abap_false

      IMPORTING

        r_salv_table = r_table

      CHANGING

        t_table     = <table> ).

    CATCH cx_salv_msg.

  ENDTRY.

 

* Get columns and aggregation to create fieldcatalog

  r_columns  = r_table->get_columns( ).

  r_aggreg   = r_table->get_aggregations( ).

  t_fieldcat = cl_salv_controller_metadata=>get_lvc_fieldcatalog(

                                r_columns     = r_columns

                                r_aggregations = r_aggreg ).

 

* Create result data table

  IF cl_salv_bs_a_xml_base=>get_version( ) EQ if_salv_bs_xml=>version_25 OR

     cl_salv_bs_a_xml_base=>get_version( ) EQ if_salv_bs_xml=>version_26.

 

    r_result_data = cl_salv_ex_util=>factory_result_data_table(

        r_data                     = r_data

        t_fieldcatalog             = t_fieldcat

    ).

 

* Get XML version

    CASE cl_salv_bs_a_xml_base=>get_version( ).

      WHEN if_salv_bs_xml=>version_25.

        v_xml_version = if_salv_bs_xml=>version_25.

      WHEN if_salv_bs_xml=>version_26.

        v_xml_version = if_salv_bs_xml=>version_26.

    ENDCASE.

 

* Get XML flavour

    v_xml_flavour = if_salv_bs_c_tt=>c_tt_xml_flavour_export.

 

* Create excel data

    CALL METHOD cl_salv_bs_tt_util=>if_salv_bs_tt_util~transform

      EXPORTING

        xml_type     = if_salv_bs_xml=>c_type_mhtml

        xml_version  = v_xml_version

        r_result_data = r_result_data

        xml_flavour  = v_xml_flavour

        gui_type     = if_salv_bs_xml=>c_gui_type_gui

      IMPORTING

        xml          = v_xstring.

  ENDIF.

ENDFORM.                    "build_excel_data

Form export_excel:

Last but not least, this form will use the XML data (xstring) to create a binary file (Excel) in the specified path.

FORM export_excel.

 

  IF v_xstring IS NOT INITIAL.

    CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'

      EXPORTING

        buffer       = v_xstring

      IMPORTING

        output_length = v_size

      TABLES

        binary_tab   = gt_bintab.

 

    CALL METHOD cl_gui_frontend_services=>gui_download

      EXPORTING

        bin_filesize           = v_size

        filename               = p_path

        filetype               = 'BIN'

      CHANGING

        data_tab               = gt_bintab

      EXCEPTIONS

        file_write_error       = 1

        no_batch               = 2

        gui_refuse_filetransfer = 3

        invalid_type           = 4

        no_authority           = 5

        unknown_error          = 6

        header_not_allowed     = 7

        separator_not_allowed  = 8

        filesize_not_allowed   = 9

        header_too_long        = 10

        dp_error_create        = 11

        dp_error_send          = 12

        dp_error_write         = 13

        unknown_dp_error       = 14

        access_denied          = 15

        dp_out_of_memory       = 16

        disk_full              = 17

        dp_timeout             = 18

        file_not_found         = 19

        dataprovider_exception = 20

        control_flush_error    = 21

        not_supported_by_gui   = 22

        error_no_gui           = 23

        OTHERS                 = 24.

    IF sy-subrc <> 0.

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

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

    ENDIF.

  ENDIF.

 

ENDFORM.                    "export_excel

 

I hope that this blog was useful for some of you and feel free to contact me with suggestions, questions or remarks.

I will post an update here when the second part of the SAP & Excel Integration has been posted.

 

Have a nice day.

Kind regards,

 

Niels

With mockA it is quite easy to mock interfaces for unit tests. But it is also capable of creating mock objects that are not based only on interfaces, but specific classes. This blog post shows how it works and what needs to be considered.

Basics

Creating such an instance is quite the same as the creation of mock objects based on interfaces. The only restriction that applies is the fact that the class which is to be mocked may not be final class. This is necessary because mockA couldn’t create a subclass to override method outputs.

The classes in the following examples can be found in the mockA package provided at Github.


DATA lo_mocker TYPE REF TO zif_mocka_mocker.
DATA lo_mocker_method TYPE REF TO zif_mocka_mocker_method.
DATA lo_flight_observer TYPE REF TO zcl_mocka_flight_observer.
lo_mocker = zcl_mocka_mocker=>zif_mocka_mocker~mock( zcl_mocka_flight_observer=>gc_name ).
lo_mocker_method = lo_mocker->method( 'observe_flight' ).
lo_mocker_method->with( i_p1 = 'NA' i_p2 = 007 i_p3 = sy-datlo ).
lo_mocker_method->returns( abap_true ). 
lo_flight_observer ?= lo_mocker->generate_mockup( ).


Constructor parameters

However, this little example will still fail, as ZCL_MOCKA_FLIGHT_OBSERVER’s constructor expects non-optional IMPORTING parameters. This is an issue which is not existent for interfaces. As you mock already existing implementations, you also need to take care of that.

But that is also no problem at all. Consider the following example that passes some earlier created instances to the constructor. It can be achieved by calling the method PASS_TO_SUPER_CONSTRUCTOR of the mocker instance.


DATA lo_is_in_time_info TYPE REF TO zif_mocka_is_in_time_info.
DATA lo_flight_alert_process TYPE REF TO zif_mocka_flight_alert_process.
*create lo_is_in_time_info and lo_flight_alert_process... (not shown here)
DATA lo_mocker TYPE REF TO zif_mocka_mocker.
DATA lo_mocker_method TYPE REF TO zif_mocka_mocker_method.
DATA lo_flight_observer TYPE REF TO zcl_mocka_flight_observer.
lo_mocker = zcl_mocka_mocker=>zif_mocka_mocker~mock( zcl_mocka_flight_observer=>gc_name ).
lo_mocker->pass_to_super_constructor( 
  i_p1 = lo_flight_alert_process i_p2 = lo_is_in_time_info ).
*mock some method output (not shown here)
lo_flight_observer ?= lo_mocker->generate_mockup( ).

The example s are also in the mockA package.

Take a look at the unit test report ZTEST_CL_MOCKA_MOCKER and the test methods mock_class_with_construc_param, mock_class_with_method_output and mock_intf_with_construc_param.

We can do any number of modification to the fieldcatalog and layout of ALV grid even after it has been displayed on the screen, we can hide certain columns , change the column text, change the column position etc. We can achieve all this simply by using the following methods of the class CL_GUI_ALV_GRID:

 

For fieldcatalog modification:


get_frontend_fieldcatalog

set_frontend_fieldcatalog

 

For layout modification:

get_frontend_layout

set_frontend_layout

 

Steps to change the fieldcatalog after first display:

  1. Trigger the PAI using pushbutton or some other manner.
  2. Now for this triggered function code get the existing fieldcatalog using the method get_frontend_fieldcatalog.
  3. Make the required modification to the fieldcatlog.
  4. Now in order to reflect these changes to the ALV grid make use of the method set_frontend_fieldcatalog.
  5. Call the method refresh_table_display of class CL_GUI_ALV_GRID to refresh the ALV display so as to show the modifications done to the ALV grid.

The ALV layout can be changed in a similar manner using the get and set methods meant for layout.


Example:


This is the initial display of ALV gird.

5.png

On clicking the button Technical Name the existing column headings will be replaced by their equivalent technical name.


6.png


On clicking the Layout 1 button the existing layout will be changed to Zebra layout.


7.png


Similarly you can present multiple layout and display options to the user using this technique.



Jerry Wang

A handy RTTC tool

Posted by Jerry Wang Feb 28, 2014

in one of my project the data type of the variable to hold service consumption result is not known in design time so I have to generate the data type dynamically via code, using ABAP RTTC( runtime type creation ). For detail of RTTC and dynamic programming, please refer to sap help.


This blog will introduce a handy RTTC tool to generate any kind of complex data type in the runtime and demonstrate how to access the variable with that data type dynamically using field symbol.

 

one example: I need to define a variable with the following data type. The structure of the data type is only known in the runtime:

clipboard1.png

       Figure1: an example of data type definition which needs to be generate in the runtime


The variable could have the component named "PRODUCTS" which is a table type, the table line type is a structure with five fields: PROD_ID, PROD_TXT, VALID_FROM, VALID_TO and COMPONENTS. The last field COMPONENTS is again a table type, with the table line type consisting of four fields COMP_ID, COMP_TXT, OPERATOR and again a table type for last field NOTES.

 

The row in the picture above marked with green seems a little strange and not necessary at a first glance, but it really makes sense. Consider the setting for table type in ABAP Dictionary.

clipboard2.png

How to use the RTTC tool

 

I write a simple report to create the data type and define a variable with that type using the RTTC tool zcl_rttc_tool( source code in attachment ).

 

To use the tool, you just need to put into the definition of the data type to be generated, and the exporting parameter er_ref contains the reference pointing to the variable with the very data type.

clipboard3.png

To facilitate the filling of importing it_des_tab, I create three simple macro in report:

 

DEFINE define_table_type.
APPEND INITIAL LINE TO lt_definition ASSIGNING <type>.
  <type> = VALUE #( level = &1 field = &2 kind = ZCL_RTTC_TOOL=>c_table parent = &3 ).
END-OF-DEFINITION.
DEFINE define_tab_line_type.
  APPEND INITIAL LINE TO lt_definition ASSIGNING <type>.
 <type> = VALUE #( level = &1 kind = ZCL_RTTC_TOOL=>c_structure parent = &2 ).
END-OF-DEFINITION.
DEFINE define_element.
APPEND INITIAL LINE TO lt_definition ASSIGNING <type>.
  <type> = VALUE #( level = &1 field = &2 kind = ZCL_RTTC_TOOL=>c_element type = &3 parent = &4 ).
END-OF-DEFINITION.

clipboard4.png

How to access the variable created by RTTC tool

 

We get the variable from tool which is a reference points to a structure which has a transient technical type. The type is only valid withing current session.

clipboard5.png


Although you can find the component PRODUCTS in debugger, you cannot use lr_data->products to access it in your code, since the structure is not known by compiler in design time.

clipboard6.png

Instead, you have to access it via so called dynamic programming via field symbol:

 

FIELD-SYMBOLS: <data>     TYPE any,
               <prod_tab> TYPE STANDARD TABLE,
               <comp_tab> TYPE STANDARD TABLE,
               <note_tab> TYPE STANDARD TABLE.
ASSIGN lr_data->* TO <data>.
CHECK sy-subrc = 0.
ASSIGN COMPONENT 'PRODUCTS' OF STRUCTURE <data> TO <prod_tab>.
CHECK sy-subrc = 0.
" create a new empty line to component PRODUCTS
APPEND INITIAL LINE TO <prod_tab> ASSIGNING FIELD-SYMBOL(<prod_line>).
CHECK sy-subrc = 0.
"fill the field PROD_ID for the first table line
ASSIGN COMPONENT 'PROD_ID' OF STRUCTURE <prod_line> TO FIELD-SYMBOL(<prod_id>).
CHECK sy-subrc = 0.
<prod_id> = 'MCF-0001'.
ASSIGN COMPONENT 'COMPONENTS' OF STRUCTURE <prod_line> TO <comp_tab>.
CHECK sy-subrc = 0.
" create a new empty line to component COMPONENTS
APPEND INITIAL LINE TO <comp_tab> ASSIGNING FIELD-SYMBOL(<comp_line>).
CHECK sy-subrc = 0.
" fill COMP_ID for the first table line
ASSIGN COMPONENT 'COMP_ID' OF STRUCTURE <comp_line> TO FIELD-SYMBOL(<comp_id>).
CHECK sy-subrc = 0.
<comp_id> = 'COMP_0001'.
ASSIGN COMPONENT 'NOTES' OF STRUCTURE <comp_line> TO <note_tab>.
CHECK sy-subrc = 0.
" create a new empty line to component NOTES 
APPEND INITIAL LINE TO <note_tab> ASSIGNING FIELD-SYMBOL(<note_line>).
CHECK sy-subrc = 0.
" fill NOTE_ID for the first table line 
ASSIGN COMPONENT 'NOTE_ID' OF STRUCTURE <note_line> TO FIELD-SYMBOL(<note_id>).
CHECK sy-subrc = 0.
<note_id> = 'NOTE_0001'.

the filled data is displayed in the debugger as below, let's compare it with figure1:

clipboard7.png

clipboard8.png

In ALV report , when we click on Microsoft Excel
button(CTRL+SHIFT+F7) as shown below, the excel sheet does not display data.

 

Image1.JPG
 
 
  image 2.JPG
   
For data to appear here do the following :

 

 

1. Open Excel

 

 

2. Click on  Office Button at the top and click  > Excel Options

 

    Click onTrust Center as shown below:

 

image 3.png

  
  

3.Click on Trust Center Settings

 

 

image 4.jpg

4. Click on Macro Settings and Enable Trust Access

 

image 5.jpg

 

5. Then data will appear in the Excel:

 

image 6.jpg

Scheduling Periodic Job has one limitation , We can not schedule the job for a particular time frame .

 

Lets Say if you want to schedule the job every one minute for one week only .In order to achieve this , we have to schedule the periodic job which will run every one minute and then after one week we need to manually delete the job.

 

So In order to overcome this limitation i have written simple report which will schedule the periodic job for a given time frame.

 

This report will schedule two jobs , one to run the report periodically and other job to delete the first job after the given time frame.


Start Date and Start Time( Low)  implies the start time for the first job ,similarly Start Date and Start Time( High) implies the start time for the second job which will delete the first job.You can also specify the Day on which job should be scheduled.

SELECTION SCREEN.PNG

 

You can also specify the Job Prefix name , first job will be created with the name of the Prefix followed by '_JOB' followed by the timestamp and second job will have '_DEL'  and the timestamp.

 

Period in Mnts is for the first job to specify how often it should be run.

job.PNG

 

Attached Document has the source code for the report.

Actions

Filter Blog

By author:
By date:
By tag: