1 2 3 48 Previous Next

ABAP Development

707 Posts

"REPORT HAS BEEN DEACTIVATED". You may find statement saying that within ABAP code like reports. One may wonder what does it actually mean. Usually the case is that the code is obsolete and it should not be longer used.

What makes SAP code obsolete? These are cases I’m thinking of:

  • Particular function implemented in the code was rewritten (refactored) and an old one is not needed any more and is obsolete.


  • Functionality implementation error. Some part of functionality was intended to be present but later it was decided to do not implement it but some initial code remains. Thus the remaining code is obsolete.


  • Implementation errors in security area. There is potential security risk or vulnerable patterns with the code. These can be following - just to name few: hardcoded users or passwords, performing certain code without logging it or without checking authorization objects, direct access to critical DB tables, injections issues (ABAP, SQL), RFC execution, directory traversing, using of wait commands, etc. These errors were not detected during security checks of development cycle and were rolled out to customer’s systems. These kind of errors make parts of the code obsolete.


As soon as the refactored code is delivered or implementation type of errors were explored a corrections are prepared (mostly in form of SAP Notes). These corrections mark the code as obsolete and prevent execution of it.


That’s basically what happened in case if we see e.g. REPORT HAS BEEN DEACTIVATED in the ABAP code.

To enforce that particular ABAP code will not be used it is even commented out. The code needs to be comment out instead of simply removing whole objects in order to prevent unnecessary ABAP dump. By this user informed about obsolescence:


Other point of view (as suggested in the comment that introduces deactivation of the function) is software archaeology (see 1st screenshot). Even seems it is practice in SAP that after few more releases particular code is not only commented but also removed it is very nice to see a track of software archaeology :-)



PS: This blog is cross published on my personal blog site.


Recently there were some questions about transport information functions.

The program attached Y_R_EITAN_TEST_26_02 is my attempt of using some of the transport functions .





The program goes through table E070 based on user selection .

For each E070 row the program call function TR_READ_GLOBAL_INFO_OF_REQUEST , The output from the function is used to create the final output table.

The final output table is presented using cl_salv_table .

Transport Logs and Action log is availble by hotspot .















Hi Guys,


while working with own database tables (Z* tables) the SAP offers us a simple tool to add data or edit these tables. I am talking about the table maintenance views, that you can call via the transaction SM30. The problem is that only one user can edit such a table at once. For my application this was unsatisfying because several users worldwide couldn't consider waiting until one has finished his changings. I sersched the SCN and found serveral threads handling this issue. After implementing it myself i wanted to share my knowledge with you and carry the information together.

So at first you need the database table and you have to generate a table maintenance view.  While Generating this View choose two step maintenance type, because we want a list where several entries are not editable. In the overview screen no entry is editable in general, in detail screen it gets editable when opened with changing.


When you enter the table maintenance view via SM30 a table level lock is set. This lock has to be removed. The most easiest way to do that is a report that deletes the lock and calls the maintenance view. In detail this is done by reading all system locks. After that we have to delete the relevant lock by calling the function module  ENQUE_DELETE. Now you can call the table maintenance view via the function module   VIEW_MAINTENANCE_CALL.  It is recommendable to add a transaction to this report because it has to be processed to delete the locks. Otherwise if someone opens table maintenance view via SM30 this will not work any more and the lock is set again.


Code Example:


REPORT ztest.



BEGIN OF seltab OCCURS 1.        


        INCLUDE STRUCTURE vimsellist.

DATA: END OF seltab,


BEGIN OF excl_cua_funct OCCURS 1.  


        INCLUDE STRUCTURE vimexclfun.

DATA: END OF excl_cua_funct.


DATA: lt_enq_del       TYPE STANDARD TABLE OF seqg3,

          lt_enq_read      TYPE STANDARD TABLE OF seqg7,

          lw_enq_read     TYPE seqg7,

          lw_enq_del       TYPE seqg3,

          lv_subrc           TYPE sy-subrc.


*Read all locks in system




    gclient = sy-mandt

    gname = ' '

    guname = '*'


    enq = lt_enq_read.


*We will search entry for table level lock for our table

LOOP AT lt_enq_read INTO lw_enq_read WHERE gname EQ 'RSTABLE'



  MOVE-CORRESPONDING lw_enq_read TO lw_enq_del.

  APPEND lw_enq_del TO lt_enq_del.



*Delete lock entry for our table



    check_upd_requests = 1


    subrc              = lv_subrc


    enq                = lt_enq_del.




    action                               = 'U'

*   CORR_NUMBER                          = '          '


*   SHOW_SELECTION_POPUP                 = ' '

    view_name                            =  'Z_OURTABLE'.



Now every entry we are editing has to be locked for other user. To achieve that we need a lock object configured for our table Z_OURTABLE. Everytime we enter the detail screen we check if this entry locked and if so, we set all fields not editable. For that the Screen logic of the dynpro has to be modified. You can add a module that calls the function module created by your locking object. Be careful , if you change your database table, the screens have to be generated new and also the PBO Module has to be added again.


Code example:


MODULE change_locking OUTPUT.







      kunnr = zourtable-kunnr


      foreign_lock   = 1

      system_failure = 2

      OTHERS         = 3.

  IF sy-subrc <> 0.

message 'Data locked by another user!' type 'S'.

* row is locked..


      screen-input = 0.






Everytime a user opens a single record this is locked by the locking object. If any user tries to open the same record all fields are enhanced grey.



I hope this is useful to someone.


kind regards Tobias

Hi all,


Today's blog is about something I’m thinking quite a while how to create it.


We, as ABAP-Developer , didn't have such a problem or better, not in the same way a lot of others programmers had to face it.


What I want to say, is when you have a look at a SAP-Transaction everybody of us know normally how to navigate. There are the well known Navigationbar, Execute and all the Standard-Buttons above an ALV.

I think, you know what I’m talking about. So what is this blog for? I recognize that developing in ABAP make a huge change at the moment (ok, it is more a process and yes it's more a general thing). That’s why we face problems, we didn't know before and one is the Design-Styleguide.


I just want to collect some facts why all of us should have a Design-styleguide as an additional document to the coding-guidelines.


Everybody of us know the Coding-Guidelines and I’m pretty sure, I will not find one person around here saying it is not necessary to have a document like this. Of course, some are a bit over the top, but all in all it is a great instrument to lead all people into the same direction.


Now, when I would say that a Design-Styleguide is also necessary a lot people saying to me, that it’s not important.


Why do I get this reaction? I mean, of course years before, when just the dynpro was developed by SAP you just could choose between a hand full controls and a predefined icons to create your screen. That was awesome, because all of the programs had the same look and feel. I think that was one of the success-factors of SAP. Keep it simple and similar might be the thinking behind.


But developing has changed and of course the elements we can use today are a lot more. I don't know where here on SCN I have read the sentence “A 23 year old employee don't want to use a 20 year old software” and that is so true. Additional to that, I would say that also the rules of developing has changed and so today also we, the SAP developers may need more than just a coding-guidelines.


Now, how to start…what to do? This is how I want to start and hey, miss the counting in my blog? Me too


1st point Use existing style guides


This is a very important point. Before to start with the own one work through other styleguides. All the companies out there especially in the mobile sector have one and I’m pretty sure SAP also got one, so if anybody knows where it is located, I would love to have a link in the comments


2nd point Keep it short and simple


I read a lot of different blogs about this topic and I decided for me, that a good styleguide should not have more than 4 to 6 pages. In my opinion I’m pretty sure, that a lot of people saying that it is not necessary (as mentioned in the beginning) and out of that I’m pretty sure that it is a absolutely success factor that the guide is as simple as possible. Don't add tons of links, keep it simple, we all are creative people and I if something is not clear, make it easy to ask.


3rd point Example-package


Provide a package of examples that leads through the different designs. That’s a way you can make similar feeling and by the way after investing some money you can save it afterwards with a multiplier





4th point Easier to test (or 3.1)


What?  A styleguide should make my programs easier to test? Yes, it does. People will feel comfortable with the handling and so it will be easier to hand over some testing to another. Also keep in mind that the other worlds (UI5 / River / POWL) swap on our desk and it is not just a trend. It’s the future.


5th point Easier to develop and to prepare (or 3.2)


A styleguide also helps the responsible persons to prepare the documents for developing. All people in the chain got a similar expectation of the program from the first sentence in the whole process. This will take time in the beginning, but I’m pretty sure in the end it will result in lower bugs and lower maintenance cost on each side.


6th point Shared vocabulary (or 3.3)


This is a point, I humble sometimes over. I see 3 different programs with similar (custom)data in it and there are also three different data-elements used. I know, this won't be fixed in summary by an styleguide as well, but I’m pretty sure, that a active styleguide in an company leads to more sensitive searching before creating new elements.


7th point Invest time


That isn't just a phrase here. I’m pretty sure that it will take more than two meetings to complete the process. I think it needs a lot of time to walk through the company and ask a lot of people how they define it and collect just facts. Afterwards pin all facts at a whiteboard and go on to point number eight. Of course, it also will take a lot of time to create the sample packages (Webdynpro, BSP, UI5), but this is also a nice doing to get in touch with all the things.


8th point Onboard young employees

This document should be created by the young employees. They may add their points without having the company glasses on. No need to argue, but I think the “older” employees should have the second check on the document, so everybody has the chance to add something but in this case all voices are at the same level and if there are arguments, it will be early enough to add these to the document.


9th point Catch the feedback


In my opinion I think it need a period to have an “beta-test” on the document. After the examples (or during) are created it should have a group of people to try the handling, if possible people without any experience of programming. They will deliver clear voices if they think all the different examples give the feeling to be always on the same highway. I think you know what I mean.


10th point Love it or leave it



If you have worked through the other 9 points and ended here I just have to add, that I do not know anything other to add.  I know that this will end in a lot of discussions and it might not be easy to deliver such document. So I think you have to love the idea behind and see the necessity. And I hope I delivered that point with this blog





Have a look around in your company and I’m pretty sure there are always people trying to put things in a row, let documents look the same and try to publish the brand in the same way. So this is exact the same what a styleguide tries. All we have to learn is that a styleguide today is normal and when I talk to people with other software in the back, it is usually a must have, except if I talk to SAP-guys.


I think it is time to leave the leaf or do I see things wrong and most of you got one available?


(Comic comes from here: xkcd: Donald Knuth http://xkcd.com/163/)


Thank you for reading to the end. Feel free to add something I missed or just to leave a comment.




This article probably isn't required, as most of us here are already ABAP developers, but, I thought it would be good experience to share my thoughts what it actually felt like to switch to ABAP.


Unlike Java or C++ , ABAP isn't a language for development of applications on Windows or any other operating system for that matter. The purpose it actually serves  is to cater to the needs of Industries who are using SAP. So the major difference between working  ABAP and Java/C++ is you have to utilize most of your talents to study the functions already provided by SAP team, as generally it optimizes the program whereas it generally is vice-versa on other language as it increases dependency on Platform.


ABAP can be considered a more specific language in terms of application. By this I mean that while in other languages you have freedom to present end result of your program but in ABAP you have to optimally utilize SAP GUI to present results.


When working on Java I was really sick of long syntax's . To be honest it really felt more like article writing rather than coding(and by now u might  have  figured out how good I'm in article writing ). I would clearly like to state here I am not judging the capabilities of any programming language, it's just my perspective on things. When I switched from Java to ABAP , firstly I thought why do companies even require ABAP coders at first place(though I clearly understand now 'why').

The simplicity it offered at the beginning made me feel like as if they had designed a function for each and everything you wanted to do, thus rendering you useless again.


So it can be concluded that if you are good in any other Programming language , don't get scared to switch to ABAP. It simply is the simplest language you can find. So far, while working on ABAP , I felt like as if ABAP was designed to comfort the Developers (I really mean that). Coding on ABAP really is a piece of cake(some may disagree). You just have to understand the business scenarios a bit better than your fellow counterparts working on other technologies.

I am really glad that I made the switch to ABAP when I had chance.

I had an interesting last week and what looked easy at the outset did my head in for quite a while. I tried various methods and the below approach was able to give me a satisfactory solution.


Let's have a look at the high level requirement.



- Copy a standard SAP transaction and customise it . Below picture describes the requirement

Screen Shot 2014-08-16 at 7.28.17 pm.png


The transaction is started with only few fields of the complete selection screen as the selection screen has too many fields and may confuse the users.





The users need to navigate back and forth between different modes of output screen. At the first display of output screen ( let's call them as levels - so the output screen is at level 0 when initially displayed and if called again goes to level 1 and so on . Similarly when the user comes back from a higher level of screen, the level will decrease : from 1 to 0 ). And of course when the program navigates back from level 0 of selection screen, it should display the selection screen.



I prototyped using a simple program using flight model.



- Selection Screen : Contains all fields.

All fields.PNG


However, the transaction is always run with a variant which hides the last field.


Selection Screen.PNG


- Let's test with some data.



Selection Test.PNG


We get the level 0 output screen.


Level 0.PNG


Now click on filter ( search icon on top right )




and we get level 1 screen.


Level 1.PNG


Looks good so far. Now, let's try going back - going back to level 0 gives the screen as anticipated. However, when we go back and see that the selection screen parameters have gone back. The selection screen has gone blank !


Selection Screen.PNG



Let's see what's going on.


As we need to keep track of different levels of screen, if the level of screen is greater than 0.


ELSEIF sy-ucomm = 'EXIT'.

    IF gv_list_level > 0.

      gv_list_level = gv_list_level - 1.

      gt_flight[] = gt_master_flight[].

      CALL SCREEN 100.




When we want to go back to selection screen from screen at level 0, we use below:


SUBMIT zsubmit_flight

            WITH report EQ 'ZTESTFLIGHT'

            WITH variant = 'ZFLIGHT_VAR'

            WITH SELECTION-TABLE gt_seltab .

zsubmit_flight is a standard SAP report used by the report and can't be changed by us.



                    VIA SELECTION-SCREEN



1) Store selected values by call of RS_REFRESH_FROM_SELECTOPTIONS 


2) Export the selection table before doing a program restart.

EXPORT gt_seltab TO MEMORY ID gc_sel_mem.


3)  Retrieve the selection table AT SELECTION-SCREEN OUTPUT.


RS_VARIANT_CONTENTS gives the parameters and select-options actually visible in the variant.


IMPORT gt_seltab FROM MEMORY ID gc_sel_mem.


  IF NOT gt_seltab[] IS INITIAL.




        report              = 'ZTESTFLIGHT'

        variant              = 'ZFLIGHT_VAR'


        l_params            = lt_params

        l_selop              = lt_selops

        valutab              = lt_value


        variant_non_existent = 1

        variant_obsolete    = 2

        OTHERS              = 3.

    IF sy-subrc <> 0.

clear: lt_value,





* Update parameters values


    LOOP AT lt_params INTO lw_param.

      READ TABLE gt_seltab REFERENCE INTO lo_values WITH KEY selname = lw_param-name.

      IF sy-subrc = 0.

        lv_attr = lo_values->selname.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_val>.

        <fs_attr_val> = lo_values->low.




* Update select-option values


    LOOP AT lt_selops INTO lw_param.

      READ TABLE gt_seltab REFERENCE INTO lo_values WITH KEY selname = lw_param-name.

      IF sy-subrc = 0.


        CONCATENATE lo_values->selname 'SIGN' INTO lv_attr SEPARATED BY '-'.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_sign>.

        <fs_attr_sign> = lo_values->sign.



        CONCATENATE lo_values->selname 'OPTION' INTO lv_attr SEPARATED BY '-'.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_option>.

        <fs_attr_option> = lo_values->option.


        CONCATENATE lo_values->selname 'LOW' INTO lv_attr SEPARATED BY '-'.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_low>.

        <fs_attr_low> = lo_values->low.


        CONCATENATE lo_values->selname 'HIGH' INTO lv_attr SEPARATED BY '-'.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_high>.

        <fs_attr_high> = lo_values->high.


        lv_attr = lo_values->selname.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_main>.


        CONCATENATE lv_attr '[]' INTO lv_attr_tab.

        ASSIGN (lv_attr_tab) TO <fs_attr_tab>.


        IF lo_values->low IS NOT INITIAL OR lo_values->high IS NOT INITIAL.

          REFRESH <fs_attr_tab>.

          APPEND <fs_attr_main> TO <fs_attr_tab>.







REFRESH gt_seltab.

   EXPORT gt_seltab TO MEMORY ID gc_sel_mem.


- Create a transaction 'ZFLIGHT' with program ZTESTFLIGHT , variant ZFLIGHT_VAR.



The code can be referred here:





Program ZTESTFLIGHT with issues:



Program  ZTESTFLIGHT with corrections:

ABAP_Demo/ZTESTFLIGHT_2 at master · viksingh/ABAP_Demo · GitHub


The key here is function module RS_VARIANT_CONTENTS and the dynamic update of selection screen after restart of a transaction.

As with most OO related discussion (i.eWhy object oriented? Import parameters), the arguments get interesting really quick. In that blog, a fellow SCN user described her dislike for OO, and how it relates to procedural, as the following:

The funny thing is that this aspect I dislike most about FM's is their greatest parallel to OO concepts. Basically you can say that a function group is something similar to an object, with the FM's being its methods. Fortunately, most of the time the FM's are independent and provide a well-defined functionality that only depends on the parameters you are providing at run-time.

The point the user is making is that class attributes are a lot like global variables, which are more annoying to debug since it's harder to find out where they were actually set. I really get where he is coming from. As always, it's a matter of design and following OOP guidelines.


What you should do:

  • Public atributes should be set in the constructor;
  • Private attributes should be set in specific getter/setter methods (or the constructor).


What you shouldn't do:

  • Change an attribute directly outside of the constructor and getter/setter methods.
  • Create attributes for temporary variables that are not related to the object itself;
  • Create attributes with obscure naming like WERKS, use Plant instead. Use _ if you have to, the attribute name should always be self descriptive.


The rule of thumb is: If the attribute is not worthy of public or a getter/setter then it is temporary method variable and shouldn't be an attribute at all.

This explains why they aren't so bad if used well, but doesn't explain why you should use them. I think the most immediate way to summarize their power (in the context of SAP WM, and TO confirmation) is this:

lo_to->confirm( ).

Why is this powerful? Because import parameters are messy, and the more "the merrier" (joking). Translation, the more parameters, the more mistakes you can make and the more information you need to use them correctly.

This is the exact opposite of the FM with zero state, where all information must be provided by IMPORTING parameters. Lets picture the scenario where you need to confirm a TO (from SAP WM) without using OO attributes. SAP provides a FM for that:

    call function 'L_TO_CONFIRM'
        i_lgnum                        = lv_lgnum
        i_tanum                        = lv_tanum
        i_squit                           = lv_squit
        i_komim                        = lv_komim
        i_tbeli                            = lv_tbeli
        i_update_task                  = 'X'
        t_ltap_conf                    = lt_ltap_conf[]
        t_ltap_conf_hu              = lt_ltap_hu[]


This is not an extreme example there are way more complicated FM interfaces. There are two main problems with this:

  • Filling lt_ltap_conf and lt_ltap_hu is far from trivial;
  • The FM call is completely coupled to the calling program (more on that in an instant).


I've used this function in RF programs which are a pain (if you ever touched one, you will know it...), and have persistency requirements: a warehouse worker can't lose his work if Wi-Fi goes down, so every item picked gets saved to the database. Now let's assume that an error is thrown at TO confirmation, and you need to find out why.


If you used the traditional procedural way, you would need to run the calling RF program, get to the place where you make the TO confirmation and debug (with the extra annoyance that RF is system-guided, so getting that specific TO means superuser specific code). Either that, or you could SE37 the FM and fill by hand all the parameters of the FM (remember the counterexample is a FM with not state).


With OO, it's as simple as SE24, create instance, insert number of TO (and warehouse number), and then press "CONFIRM". Two parameters and you are ready to debug. I cannot stress how important this decoupling becomes when you are debugging errors or making unit tests, this separation between caller and callee means you can focus on particular behaviors.


This is a specific situation with persistence where OO gives you a really advantage. I've found over the years that dealing with persistence is one of the greater advantages of OO since most of the data is already available. In a more general situation the CONFIRM call would be preceded by calls to ADD_ITEM, but even that is simpler than manually filling the lt_ltap_conf with absolutely no rules (check Why object oriented? Import parameters for my argumentation on that subject).


All this could be made using Function Groups, since this blog more about Object Oriented Programming then Classes/Methods.

HI mates!


Actually this is my first blog in my 5+ years SAP career so don't judge me strictly.


So I have chosen really intersting topic: probably something that everyone thought about. I'm sure someone even tried to implement this feature by own efforts.


This is a proposal search feature. This is so obvious that if we type the beginning of the search term or even mask we want to see the results instantly. But not in SAP GUI. All the times we had to press F4 or at least click at search button by mouse.


But this morning while creating a new search help I suddenly noticed an  interesting new block in SE11 transaction.




According to F4 search help I found the following note:




The requirements for that feature is quite high: These functions are available as of SAP NetWeaver for ABAP 7.4 SP03 and SAP GUI for Windows 7.30 patch level 5 or higher. But happily we have SP04 so I decided to go further and to try it.


I have selected search helps from DD30L table by AUTOSUGGEST = 'X' field. Hopefully there were results and I have chosen SDSH_SPFLI as an example to try.

From the where-used list of the following search help i found SDSH_S_SPFLI structure and created a tiny program following the instructions from the mentioned above note:


report ztest_autosuggest.
  p_carrid TYPE SDSH_S_SPFLI-carrier_id.
at selection-screen output.
  loop at screen.
    if screen-input eq 1.
          fields    = value #( ( |{ screen-name }| ) )
          overwrite = abap_false ).

The result on the screen made me really enjoyed. Now we have it as a standard feature:




As I understood only since SP06 this feature is going to be activated automatically. So this cl_dsh_dynpro_properties should be called manually in lower versions.


Also I would mention that it's possible only search by code. The full text fuzzy search is available only for special databases like SAP HANA as well,

But in anyway that's something interesting!


So thanks for reading!



Just would like to share with you how I struggle with a bug recently. These days I am supporting a customer project which would go live very soon. We find a severe performance problem in a scenario. After fighting it for sometime, we locate the possible cause into the FM call below.


This is a RFC call from CRM to ERP system with expectation that at maximum 15 records are returned.


Much to our surprise, far more than 15 records are returned, finally leads to the performance issue.


Then I go to the responsible colleague for FM SLS_LORD_GET_VALUES_SAREA saying "Hey man, there is something wrong with the max entry filtering logic in your FM. Customer will go live soon and could you please help as soon as possible". My colleague soon replied to me "just checked from my side, this FM works pretty good".


Then I have to look into this issue once again. When debugging inside this FM, I found the importing parameter is not 15, but becomes a big number 3473457, so the max record filter logic absolutely does not work in such case.


I checked the signature of this FM, and found out we should pass into it with a integer, not a char ( '15' in this example ) .


Where does this magic number '3473457' come from


I write a small report to explore it. I deliberately pass char value ( from 1 to 15 ) to an importing parameter with INT type. 


DATA: lv_num_c TYPE char2.



  lv_num_c = sy-index.




         iv_in_rfc = abap_false

         iv_num = lv_num_c.

  CATCH cx_root INTO DATA(cx_root).

     WRITE: / cx_root->get_text( ).





  lv_num_c = sy-index.



        iv_in_rfc = abap_true

        iv_num = lv_num_c.


The FM ZTEST just insert what has passed in to a DB table:




ls_rfc-in_rfc = iv_in_rfc.

ls_rfc-num = iv_num.

INSERT zrfc_Test FROM ls_rfc.




Execute result:


The first normal FM call failed with exception:


The function call of ZTEST failed; a field may have been assigned to the parameter IV_NUM whose type is not compatible with this parameter


The second round RFC call does succeed, and check what has been written into the DB:


why we passed a '1' into the FM and it has been interpreted as 2097201??


in our report, we have passed '1' ( an variable with type CHAR2 ), whose Hex value is 31002000. And when it is passed into this remote-enabled FM, since the importing parameter is defined as INT in signature, the framework tries to interpret this Hex value back to an Integer, which is 2097201, since this Integer has the very Hex value 31002000.


This operation could simply be simulated to the lines below:





In normal function call, the ABAP runtime environment could help us identify some misuse on FM call, for example the non-compatible parameter type just as the first example in this blog. However when dealing with remote function call, such misuse would not lead to runtime exception, the application could keep running but not in accordance with what we expect, and sometimes it is difficult to identify in which step the deviation occurs. So we must strictly adhere to the development guideline to avoid such implicit conversion.

Jörg Wulf

Do you know your SE16N?

Posted by Jörg Wulf Aug 8, 2014

Probably, this does not exactly belong here, but i found no better place for it.


Several people i know(me included) like to use TA SE16N for a quick glance at table data or as a means of preselection e.g.  for personnel data.

Something like a query but without the hassle of building one.


It's really great, as long as you only need data from a single table AND all selection criteria are AND related. (Or so I thought)


One problem, I frequently ran into, is when you want to evaluate  a "nested" table. That is a table that has multiple  fields in its structure, basically for the same data, representing a limited table in maintenance view.


For example infotype tables in HR are often built like that and the problem is always, that you do not know, in which field (nnnn01, nnnn02, …) to look for a certain value.


Now quite I recently figured out, that SE16N can do that and I found it worth sharing.


Let's assume, you  need to know all employee, that have a certain date type (say 18) in infotype 41, in a specific time interval, but you have no idea, in which date type column (DAR01, DAR02,…)  it is to be found.


In the past, I would have run several selections, each one with a different DARxx targeted to my date type and then would have assembled the results in Excel.


This is how to do it now



  1. Call TA Se16N with table PA0041
  2. Fill in the first set of selection criteria (DAR01 / DAT01)
  3. Change to Technical View On (SHIFT+F11 or right-click for context menu)Technical View ON.png
  4. Select Multiple entry (Cntrl+F9 or right-click for context menu or More button in the top)
    Multiple Entry.png
    Youwill be rewarded with an additional, empty selection screen
  5. Fill in your selection criteria and then press Next Entry (F5 Or Right Arrow in the bottom)More First.png
    You get a new empty selection screen. Note the number shown in the top line, it will increase as you circle through your  value sets.More Second.png
  6. Repeat
  7. When you're through with typing in your values in every possible column, press F8 to get back to your starting selection.
    The only hint, that there are additional select criteria, is the more button in the top, now showing the filled Icon.

SE16n Final.png


The difference is  in the result. After executing  your selection, you will now receive all entries, that match either of your value sets. They are each linked by OR-relation.

Of course, the use of this feature is in no way limited to HR Infotype tables. It's just the most common use for me.

Wherever you need OR-related  sets of values for a SE16N Selection , this feature comes in handy.


Hope you'll enjoy it.



Recently there was a question about sending a chart by mail from pavan kumar Mallipeddi


CL_GUI_CHART_ENGINE Graph As Email in Background


Using a hint from Jānis B I was able to generate a chart and to add it in the body of the message and also as attachment .


Program Y_R_EITAN_TEST_10_06 attached use cl_document_bcs and cl_igs_chart_engine .


cl_igs_chart_engine recieve XML documents as input so cl_ixml used .


In order to display the image in the body of the message cl_gbt_multirelated_service is used this allow the use of <img src="cid:<image name>"> tag .


FORM do_igs_chart is reponsible to return the image as xstring .


The program is also send a smart form as attachment. (A bonus.....)














2014/08/28 Increase the picture size to 600X800


attachment chart.PNG

When I joined SAP Labs India in 2007 , this book was gifted to me ( as well as every ABAP developer) in the team by the manager. Initially we thought what we would do with the book ( use it as weight for exercising was also an option given the volume of the book). So it found a corner space in the book shelf and rested their comfortably. But as I moved into typical developments,  I realized the importance of the book. The book is pretty expansive in content and would touch upon mostly everything if not in detailed. The emphasis of the book as the name suggests is on ABAP Objects and the authors have done a wonderful work in that regards. Before I go into details of the book please understand This is not a book its a bible. You have to read it every day to soak in the learning.

The book has following thirteen topics

  • Introduction
  • A practical introduction to ABAP
  • Basic Principles to ABAP
  • Classes and Objects
  • Basic ABAP Language Elements
  • Advanced Concepts in ABAP Objects
  • Classic ABAP- Events and Procedures
  • Error Handling
  • GUI Programming with ABAP
  • Working with Persistent Data
  • Dynamic Programming
  • External Interfaces
  • Testing and Analysis Tools

So if you see the content, you would agree with my previous statement that the content is expansive. If you are new to ABAP objects this book is a treatise on everything on ABAP objects and explains every concept in detail with examples. I have gone back and read this stuff so many times that some of the examples are always in my mind. Since I was into developing frameworks there were some topics such as Events in ABAP , Dynamic Programming  ( Field Symbols and Dynamic Method calls) , Testing and Analysis Tools , Shared Memory and XML were very beneficial to me. This book also has a very robust section on Error Handling which is often ignored by consultants. It is imperative that exceptions are caught in the UI and they should be raised in the frameworks and the context information be provided in exception objects.

Most of the us have learned ABAP through on job learning and in that case we know the practical usage but the theoretical knowledge of concepts is lagging. This book exposes us to those smaller things. Also sometimes in the project when we have to deal with topics such as RFCs and External Interfaces of which we have no clue. A formal knowledge on the subject would not prepare to do things on previous mentioned topics but give us a logical edge to think in the right direction.


If you are into any sort of ABAP development especially ABAP Objects , this book is a must have.

In the end I would summarize - this book has been my companion for more than 7 years and now when I flip the pages to read a topic which I don't use in my daily life , I am still amazed at the depth of knowledge of authors Horst Keller & Sascha Krüger and that spurs me to raise my standards.

Hi everybody, this is about how i got an SM30 maintenance tableview, to accept changes from multiple users at the same time.

It's my first ever blog, so don't expect too much.


Maybe I should start with the admittance that DDIC related development is not my field of experience – but nevertheless, I'd like to share the following, because a reasonably thorough search on SCN didn't bring any satisfying result.


Tableview V_T001B_COFI is a maintenace view that allows users, to assign timeslots for accepting posts, depending on various key values. The view features a subset of the table entries of table T001B.


V_T001B_COFI_Change View _Posting Periods_ Specify Time Intervals__ Overview.png



When the request was brought to me, that the maintenance of posting periods in tableview V_T001B_COFI should be enabled for multiple users at the same time, I started to search SCN for similar threads. That's where I came across this one.


The outcome however, was not satisfactory, since any number of users could have made concurrent changes, leaving the lastone to press 'SAVE'  as the winner.


So I started to reanalyse the problem.


I would need to create key specified locks.


My first impulse was, to create a new maintenance dialog, complete with an enqueueing object, specifically taylored to my needs – that is, locking entries keyspecific.

The maintenance dialog would then have to ensure, that no two users could maintain the same entries. Thatwas the easy part, as far as the maintenance in my own dialog would go.


In addition it was necessary, that any maintenance started by using the standard view (V_T001B_COFI) would still prevent any other user from editing any entry - whilst on the other hand, the key specific  lock would have to prevent the standard maintenance as well.


I knew that I could achieve that, by cleverly combining the use of the FMs to be generated by the enqueueing object, together with FM 'ENQUE_READ'. But still it felt clumsy.


So I started to reanalyse the problem.


I didn't need to have control over every single tableline to be locked seperately – a subset, in this case by tablefield BUKRS would be completely sufficient.


And there it was – the keyword subset. I remembered coming across in DDIC, when building a maintenance tableview.


So my new aproach started by copying tableview V_T001B_COFI to Z_T001B_COFI, with the only difference , setting the maintenance attribut (RDONLY) for viewfield BUKRS to 'S'.


Z_T001B_COFI_Dictionary_ Display View.png

Following that, I created a maintenance dialog without any fancy stuff.


When I started the tableview Z_T001B_COFI, a popup dialog prompted me to provide the variant(BUKRS) and the next thing was a maintenance screen with only those entries, matching the variant.

Z_T001B_COFI Change View _Posting Periods_ Specify Time Intervals__ Overview.png

A quick glance on the enqueued object showed the difference. Where the standard View had produced an entry, specified only by tablename, client and record type, there was now the variant as additional discriminator.


A little bit of testing revealed, that all my preliminary enqueueing requirements where fully met. Without any additional enqueueing object or  modification, the request was fullfilled.

  Mission accomplished


Sometimes, it pays to think twice before starting to code and for me, it signalled that I should get myself a bit more into DDIC.

Quite a while ago I read Uncle Bob's Clean Code: A Handbook of Agile Software Craftsmanship and learned a little bit about FitNesse.


"It's a Collaboration Tool"

"It's a Test Tool"

"It's Open"


I'm not going to go in to why you should use FitNesse. You can read a bit about it at www.fitnesse.org. What I am going to talk about today is the work I've done on ABAPSlim and how you can go about setting up your own FitNesse wiki to run tests against SAP.


If you want to jump straight to the code you can head over to the ABAPSlim GitHub page.


Slim is the protocol that FitNesse uses to talk to your SUT (System Under Test). So far I'd say ABAPSlim is about 1/3rd done. It's easy to see this since I've copied FitNesse's standard set of tests for Slim and adapted them slightly for my implementation of ABAPSlim. When the following tests are all green then we will be able to use all the features of FitNesse.


Working tests.PNG


Right now, only the basic functionality is working. You can instantiate a class (zcl_fixture_division), you can call setter methods to set up data in your test fixture (numerator and denominator) and you can call getter methods and make assertions based on the result (quotient?). It's not shown here, but you can also pass in arguments to the constructor by adding columns in the first line where the class name is...

a test.PNG


The class zcl_fixture_division is included in the Saplink Nugget file on the ABAPSlim github page but here's what it looks like in case you're curious. Note that the columns without question marks (numerator, denominator) are setters so in the fixture class they need to be called setnumerator and setdenominator. The method with the question mark (quotient?) doesn't need the set in front of it but it does need to have a returning parameter.

CLASS zcl_fixture_division DEFINITION






   METHODS: setnumerator IMPORTING num TYPE S_PRICE,

                        setdenominator IMPORTING den TYPE S_PRICE,

                        quotient RETURNING VALUE(quotient) TYPE S_PRICE.




   DATA: _numerator TYPE S_PRICE,

                  _denominator TYPE S_PRICE.




  method QUOTIENT.

      quotient = _numerator / _denominator.




      me->_denominator = den.




      me->_numerator = num.




So how can you get this set up and play with it yourself?


1. Head over to the ABAPSlim GitHub page and download everything.

2. Install the NUGG_ZSLIM.nugg Nugget using Saplink

3. Extract the Fitnesse folder to your C: drive

4. Edit the file NSP.jcoDestination and put in your own SAP system details and credentials

5. Rename the file NSP.jcoDestination and replace NSP with your SAP instance SID

6. Run fitnesse-standalone.jar (you can run it from a command line with "java -jar fitnesse-standalone.jar")

7. Browse to http://localhost and you should see the following:




8. The last step will be to go to the AbapSlim test suite (http://localhost/AbapSlim) and modify the Slim parameters:


Click edit on the AbapSlim Page and edit the variables defined so they point to wherever you put the FitNesse folder and replace NSP at the end of the COMMAND_PATTERN with your SAP instance SID. Now you can run the test suite by clicking the Suite button.


When you create your own test suite you'll need to include the same variables in the suite page so that it knows to use ABAPSlim instead of the default Java Slim implementation:

!define TEST_SYSTEM {slim}

!define TEST_RUNNER {C:\Fitnesse\ABAPSlim.jar}

!path C:\Fitnesse\

!define COMMAND_PATTERN {java -Djava.library.path=C:\Fitnesse\ABAPSlim_lib\ -jar C:\Fitnesse\ABAPSlim.jar -sap NSP}


Thanks for reading and I hope you find this useful!


Lucas Tétreault





If you're not using Windows on x64 64bit then you'll need to download the SAP JCO 3.0 for your OS + architecture from Service Marketplace and put the files in C:\Fitnesse\ABAPSlim_lib

The idea behind this trivial solution is the possibility to export text data from an SAP system into PowerPoint format using a given template. In my experience, multinational companies usually have a default PowerPoint template for presentations, which includes: the big company logo, strict rules for what should the header and the footer include, and so on. These are particularly important for status update presentations in different areas.

Although I had this requirement in the PPM sector, that is, Portfolio and Project Management, I chose to post this in ABAP development as it might be used in other areas as well.


As a prerequisite, this solution only works beginning with Office 2007 as it requires Office Open XML. Therefore, the iXML Library must be available on the SAP Application Server.


The following steps need to be performed in order to achieve a first test:

1. Create a demo template.

It is mandatory to set a custom property for each of the slides in the presentation, with:

name = "&&slide*&&"

type = "text"

value = "slide*"

(where * represents the slide number)

Advanced Properties.png

2. Create an ABAP/4 class with the following source-code or use the one attached bellow:


class ZCL_PPTX definition
  create public .

public section.
*"* public components of class ZCL_PPTX
*"* do not include other source files here!!!

  constants MC_SCHEMA type STRING value 'http://schemas.openxmlformats.org/drawingml/2006/main'. "#EC NOTEXT

      ZCX_PPTX .
  methods GENERATE
      value(RE_V_FILE) type XSTRING .
protected section.
*"* protected components of class ZCL_PPTX
*"* do not include other source files here!!!

  data MO_ZIP type ref to CL_ABAP_ZIP .
  data MO_IXML type ref to IF_IXML .

  methods GET_FILE
      value(RE_O_DOCUMENT) type ref to IF_IXML_DOCUMENT .
  methods UPDATE_FILE
      !IM_O_DOCUMENT type ref to IF_IXML_DOCUMENT .
  methods ADD_FILE
      !IM_O_DOCUMENT type ref to IF_IXML_DOCUMENT .
  methods UPDATE_TEXTS
      !IM_O_IXML_NODE type ref to IF_IXML_NODE .
private section.
*"* private components of class ZCL_PPTX
*"* do not include other source files here!!!


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->ADD_FILE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_V_FILEPATH                  TYPE        STRING
* | [--->] IM_O_DOCUMENT                  TYPE REF TO IF_IXML_DOCUMENT
* +--------------------------------------------------------------------------------------</SIGNATURE>

  DATA :
    lo_ostream  TYPE REF TO if_ixml_ostream,
    lv_content  TYPE xstring.

* create output stream
  lo_ostream = mo_ixml->create_stream_factory( )->create_ostream_xstring( string = lv_content ).

* set encoding to UTF-8 (Unicode Transformation Format)
* 8-bit variable-width encoding maximizes compatibility with ASCII
  lo_ostream->set_encoding( encoding = mo_ixml->create_encoding( character_set = 'UTF-8' byte_order = 0 ) ).

* Set Pretty Print
  lo_ostream->set_pretty_print( abap_true ).

* render document
  mo_ixml->create_renderer( ostream = lo_ostream document = im_o_document )->render( ).

* add file
  mo_zip->add( name = im_v_filepath content = lv_content ).


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_PPTX->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_V_CONTENT                  TYPE        XSTRING
* | [!CX!] ZCX_PPTX
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD constructor.

  IF im_v_content IS INITIAL.
      RAISE EXCEPTION TYPE zcx_pptx.

* get iXML library instance
  mo_ixml = cl_ixml=>create( ).

* load OpenXML document
      zip            = im_v_content
      zip_parse_error = 1
      OTHERS          = 2 ).

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

  mo_ixml_docprops_custom = get_file( im_v_filepath = 'docProps/custom.xml' ).


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_PPTX->GENERATE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_T_TEXTS                    TYPE        ZXFILE_T_NAME_VALUE_PAIR
* | [<-()] RE_V_FILE                      TYPE        XSTRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD generate.

  CLEAR : re_v_file.

  DATA :
    lo_ixml_document      TYPE REF TO if_ixml_document,
    lo_ixml_document_rels TYPE REF TO if_ixml_document,
    lt_indicators        TYPE zxfile_t_name_value_pair,
    lt_files              TYPE cl_abap_zip=>t_files,
    lv_dummy              TYPE string,                      "#EC NEEDED
    lv_slide              TYPE string,
    lv_value              TYPE string,
    lv_filename          TYPE string,
    lv_filename_rels      TYPE string.

  lt_indicators[] = get_indicators( ).
  lt_files[]      = mo_zip->files[].

  FIELD-SYMBOLS : <fs_file> TYPE cl_abap_zip=>t_file.
  LOOP AT lt_files[] ASSIGNING <fs_file>
                    WHERE name CP 'ppt/slides/slide*.xml'.

    SPLIT <fs_file>-name AT 'ppt/slides/' INTO lv_dummy lv_slide.
    SPLIT lv_slide      AT '.'          INTO lv_value lv_dummy.

    FIELD-SYMBOLS : <fs_indicator> TYPE zxfile_s_name_value_pair.
    READ TABLE lt_indicators[] ASSIGNING <fs_indicator>
                              WITH KEY value = lv_value.
    IF NOT sy-subrc IS INITIAL.
*    file not relevant, process next

*  get .xml file
    lo_ixml_document = get_file( im_v_filepath = <fs_file>-name ).

*  get .rels file
    CONCATENATE 'ppt/slides/_rels/' lv_value '.xml.rels' INTO lv_filename_rels.
    lo_ixml_document_rels = get_file( im_v_filepath = lv_filename_rels ).

*  check indicators
    IF NOT <fs_indicator>-name IS INITIAL.
      update_texts( EXPORTING im_t_texts    = im_t_texts[]
                              im_o_ixml_node = lo_ixml_document ).


*  trigger update
    lv_filename = <fs_file>-name.
    update_file( im_v_filepath = lv_filename      im_o_document = lo_ixml_document ).
    update_file( im_v_filepath = lv_filename_rels im_o_document = lo_ixml_document_rels ).

  re_v_file = mo_zip->save( ).


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->GET_FILE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_V_FILEPATH                  TYPE        STRING
* | [<-()] RE_O_DOCUMENT                  TYPE REF TO IF_IXML_DOCUMENT
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_file.

  DATA :
    lo_stream_factory TYPE REF TO if_ixml_stream_factory,
    lo_istream        TYPE REF TO if_ixml_istream,
    lv_content        TYPE xstring.

  mo_zip->get( EXPORTING  name                    = im_v_filepath
              IMPORTING  content                = lv_content
              EXCEPTIONS zip_index_error        = 1
                          zip_decompression_error = 2
                          OTHERS                  = 3 ).

  IF NOT sy-subrc IS INITIAL.

* create the document
  re_o_document = mo_ixml->create_document( ).

* create the stream factory
  lo_stream_factory = mo_ixml->create_stream_factory( ).

* create the input stream
  lo_istream = lo_stream_factory->create_istream_xstring( lv_content ).

* parse document
  IF NOT mo_ixml->create_parser( document      = re_o_document
                                istream        = lo_istream
                                stream_factory = lo_stream_factory )->parse( ) is INITIAL.
    CLEAR : re_o_document.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->GET_INDICATORS
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RE_T_INDICATORS                TYPE        ZXFILE_T_NAME_VALUE_PAIR
* +--------------------------------------------------------------------------------------</SIGNATURE>

  REFRESH : re_t_indicators[].

  DATA :
    lo_ixml_iterator  TYPE REF TO if_ixml_node_iterator,
    lo_ixml_element    TYPE REF TO if_ixml_element,
    ls_indicator      TYPE zxfile_s_name_value_pair.

* get the corresponding entries in the custom .xml to control the generation
  lo_ixml_iterator  = mo_ixml_docprops_custom->get_elements_by_tag_name( name = 'property' )->create_iterator( ).

* get the first element
  lo_ixml_element ?= lo_ixml_iterator->get_next( ).
  WHILE lo_ixml_element IS BOUND.
    CLEAR ls_indicator.
*  get name
    ls_indicator-name = condense( lo_ixml_element->get_attribute( name = 'name' ) ).

    IF ls_indicator-name CP '&&*&&'.
*    get value
      lo_ixml_element    = lo_ixml_element->find_from_name( name = 'lpwstr' namespace = 'vt' ).
      ls_indicator-value = condense( val = lo_ixml_element->get_value( ) ).

*    insert indicator
      INSERT ls_indicator INTO TABLE re_t_indicators[].

*  get next element
    lo_ixml_element ?= lo_ixml_iterator->get_next( ).


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->UPDATE_FILE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_V_FILEPATH                  TYPE        STRING
* | [--->] IM_O_DOCUMENT                  TYPE REF TO IF_IXML_DOCUMENT
* +--------------------------------------------------------------------------------------</SIGNATURE>

  mo_zip->delete( EXPORTING  name            = im_v_filepath
                  EXCEPTIONS zip_index_error = 1
                            OTHERS          = 2 ).

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

  IF im_o_document IS BOUND.
    add_file( im_v_filepath = im_v_filepath im_o_document = im_o_document ).


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->UPDATE_TEXTS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_T_TEXTS                    TYPE        ZXFILE_T_NAME_VALUE_PAIR
* | [--->] IM_O_IXML_NODE                TYPE REF TO IF_IXML_NODE
* +--------------------------------------------------------------------------------------</SIGNATURE>

  DATA :
    lo_classdescr    TYPE REF TO cl_abap_classdescr,
    lo_exception    TYPE REF TO cx_sy_ref_is_initial,
    lo_ixml_texts    TYPE REF TO if_ixml_node_collection,
    lo_ixml_iterator TYPE REF TO if_ixml_node_iterator,
    lo_ixml_document TYPE REF TO if_ixml_document,
    lo_ixml_element  TYPE REF TO if_ixml_element,
    lo_ixml_node    TYPE REF TO if_ixml_node,
    lv_message      TYPE string,
    lv_text          TYPE string,
    lv_result        TYPE string.

*    determine all texts of the corresponding node
      lo_classdescr ?= cl_abap_classdescr=>describe_by_object_ref( im_o_ixml_node ).
      READ TABLE lo_classdescr->interfaces WITH KEY name = 'IF_IXML_DOCUMENT'
                                          TRANSPORTING NO FIELDS.
      IF sy-subrc IS INITIAL.
*      document
        lo_ixml_document ?= im_o_ixml_node.
        lo_ixml_texts    = lo_ixml_document->get_elements_by_tag_name_ns(
                              name = 't'
                              uri  = mc_schema ).

        READ TABLE lo_classdescr->interfaces WITH KEY name = 'IF_IXML_ELEMENT'
                                            TRANSPORTING NO FIELDS.
        IF sy-subrc IS INITIAL.
*        element
          lo_ixml_element ?= im_o_ixml_node.
          lo_ixml_texts    = lo_ixml_element->get_elements_by_tag_name_ns(
                              name = 't'
                              uri  = mc_schema ).
*        current object not supported

*    get iterator
      lo_ixml_iterator = lo_ixml_texts->create_iterator( ).

*    get first node
      lo_ixml_node = lo_ixml_iterator->get_next( ).

      WHILE lo_ixml_node IS BOUND.
*      update slide
        lv_text = lo_ixml_node->get_value( ).

*      replace the corresponding text
        FIELD-SYMBOLS : <fs_text> TYPE zxfile_s_name_value_pair.
        LOOP AT im_t_texts[] ASSIGNING <fs_text>.
*        update component
          CONCATENATE '&&' <fs_text>-name '&&' INTO lv_result.
          REPLACE lv_result IN lv_text WITH <fs_text>-value.

*      set updated text
        lo_ixml_node->set_value( lv_text ).

*      get next node
        lo_ixml_node = lo_ixml_iterator->get_next( ).
    CATCH cx_sy_ref_is_initial INTO lo_exception.
      IF lo_exception->is_resumable EQ abap_false.
        lv_message = lo_exception->get_text( ).
        MESSAGE lv_message TYPE 'X'.



3. Create a demo report with the following source-code or use the one attached bellow:


REPORT zdemo_pptx.

  gv_data TYPE xstring.

  p_file TYPE localfile.

  PERFORM open.

  PERFORM upload.
  PERFORM generate.
  PERFORM download.

FORM upload.
  DATA :
    lt_file      TYPE solix_tab,
    lv_filename  TYPE string,
    lv_filelength TYPE i.

  lv_filename = p_file.

  CALL METHOD cl_gui_frontend_services=>gui_upload
      filename                = lv_filename
      filetype                = 'BIN'
      filelength              = lv_filelength
      data_tab                = lt_file
      file_open_error        = 1
      file_read_error        = 2
      no_batch                = 3
      gui_refuse_filetransfer = 4
      invalid_type            = 5
      no_authority            = 6
      unknown_error          = 7
      bad_data_format        = 8
      header_not_allowed      = 9
      separator_not_allowed  = 10
      header_too_long        = 11
      unknown_dp_error        = 12
      access_denied          = 13
      dp_out_of_memory        = 14
      disk_full              = 15
      dp_timeout              = 16
      not_supported_by_gui    = 17
      error_no_gui            = 18
      OTHERS                  = 19.

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

      input_length = lv_filelength
      buffer      = gv_data
      binary_tab  = lt_file
      failed      = 1
      OTHERS      = 2.

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

FORM generate.
  DATA :
    lo_pptx  TYPE REF TO zcl_pptx,
    lt_texts TYPE zxfile_t_name_value_pair,
    ls_text  TYPE zxfile_s_name_value_pair.

      CREATE OBJECT lo_pptx
          im_v_content = gv_data.
    CATCH zcx_pptx.
      MESSAGE text-001 TYPE 'E'.

  ls_text-name  = 'TITLE'.
  ls_text-value = 'Automatically generated
  APPEND ls_text TO lt_texts. CLEAR ls_text.

  ls_text-name  = '
  ls_text-value = '
using very little coding'.
  APPEND ls_text TO lt_texts. CLEAR ls_text.

  ls_text-name  = 'NAME'.
  ls_text-value = '
Your name (Ex. John Dr. Smith)'.
  APPEND ls_text TO lt_texts. CLEAR ls_text.

  ls_text-name  = 'DEPARTMENT'.
  ls_text-value = '
Your department name or abbreviation'.
  APPEND ls_text TO lt_texts. CLEAR ls_text.

  ls_text-name  = 'DATE'.
  ls_text-value =
  APPEND ls_text TO lt_texts. CLEAR ls_text.

  CLEAR gv_data.
  gv_data = lo_pptx->generate( lt_texts ).

FORM download.
  DATA :
    lt_file      TYPE solix_tab,
    lv_filelength TYPE i,
    lv_filename  TYPE string,
    lv_fullpath  TYPE string,
    lv_path      TYPE string.

      buffer        = gv_data
      output_length = lv_filelength
      binary_tab    = lt_file.

  CALL METHOD cl_gui_frontend_services=>file_save_dialog
      filename                  = lv_filename
      path                      = lv_path
      fullpath                  = lv_fullpath
      cntl_error                = 1
      error_no_gui              = 2
      not_supported_by_gui      = 3
      invalid_default_file_name = 4
      OTHERS                    = 5.

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

  IF lv_fullpath NS '.PPTX'.
    CONCATENATE lv_fullpath '.PPTX' INTO lv_fullpath.

  CALL METHOD cl_gui_frontend_services=>gui_download
      bin_filesize            = lv_filelength
      filename                = lv_fullpath
      filetype                = 'BIN'
      data_tab                = lt_file
      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 NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

FORM open.
      program_name  = syst-cprog
      dynpro_number = syst-dynnr
      field_name    = space
      file_name    = p_file.

In the future, based on new requirements, I plan to extend this class to also include tables, new slides, and images. But if you get ahead of me, please feel free to add your code on SCN and give me a hint!




Filter Blog

By author:
By date:
By tag: