1 6 7 8 9 10 58 Previous Next

ABAP Development

861 Posts

*** If you just want to skip to the good stuff here's the github project with a saplink nugget: lucastetreault/zPhabricator · GitHub



Phabricator is a collection of open source web applications that help software companies build better software. It is developed and maintained by Facebook and largely based on their own internal tools.

hero.png

 

The major components of Phabricator are:

  • Differential - a code review tool
  • Diffusion - a repository browser
  • Maniphest - a bug tracker
  • Phriction - a wiki

 

My company has a very mature Java Development team and they have been using Phabricator's Differential for their code review process for quite some time. Our ABAP team has experimented with various processes for enabling and enforcing code reviews and I recently hacked together some integration so that we can use Phabricator for our ABAP code as well. Once I've cleaned up the code and made it easy to configure without having to change a bunch of code I'll set up a project on github with everything you need to get up and running!

 

Basically the goal is to get a nice side by side comparison so that we can quickly and easily see what was changed and to be able to control the release of transport tasks by checking the status of the review. You will not be able to release tasks until the review has been accepted.

diff.PNG

 

***Since a couple days ago when I first put this blog up I have spent a couple late nights working on this and have managed to have the whole process inside of SAP. I'll leave the "old new" process at the bottom of this blog so you can see where I started...

 

Here is what our NEW process looks like:

 

You are done coding in a transport task and you are ready to have it reviewed and moved up to the test tier.

transport.PNG

 

Go to transaction ZPHAB and enter the details required to create a code review:

zphab.PNG

 

Run the program and a revision will be created:

zphab result.PNG

 

Browse to the link it gives you and you can view the revision:

 

review.PNG

 

If you make more changes to the transport task (ie: if your reviewer requested changes) you can use ZPHAB again and it will update the revision with the latest changes.

 

If you forgot to submit a task for review you will get the following error when you try to release it:

7.png


If you submitted the task for review but it hasn’t been approved you will get the following message including the URL of the revision in Phabricator so you can send it off to someone to follow up if needed.

8.png

 

 

 

 

 

 

 

**** This is the "old new" process before I did a bunch of work to have the whole process in SAP.

Here is what our (old)new process looks like:


You are done coding in a transport task and you are ready to have it reviewed and moved up to the test tier.

1.png

 

Open a command prompt and navigate to C:\Phabricator. When you get there, run the command sapdiff <task number>

2.png


You’ll get a popup of notepad++ and you’ll need to enter a few details:

3.png


<<Replace this line with your Revision Title>> -- This needs to be set to the task number that you are submitting for review

Reviewers – Enter the phabricator user name of the person (or people) you want to review this

4.png


Save the file, then close notepad++. The differences have now been pushed to Phabricator. You will receive an email confirming that a ‘revision’ has been opened and the reviewers will receive an email asking them to review your code.



If you forgot to submit a task for review you will get the following error when you try to release it:

7.png


If you submitted the task for review but it hasn’t been approved you will get the following message including the URL of the revision in Phabricator so you can send it off to someone to follow up if needed.

8.png


I'm pretty excited about this! It's a HUGE improvement over our old process. Hope you like it!


- Lucas


What is real-time in ABAP and why ABAP Channels?


The new technologies like Cloud, Mobility, and In-Memory open new opportunities and lead the industries to the real-time business. Become real-time business means react immediately to the market changes, provide higher responsiveness, accelerate business processes, adjust responses in real-time based on changed business conditions, deliver fast and personalized service for customers, or exploit new business chances not possible before.

 

But what does real-time mean for the running business? From the business user point of view, one of the most important definitions is low latency, meaning how fast the application responds to a click or other user interaction (independent on a computer or a mobile device). Ideally users expect that the input data is processed within milliseconds and they receive immediate responses.

 

Real-time means also always having the latest up-to-date information about application data and state (e.g. the current stock market prices, airline seat availability, latest deadlines for delivery, accurate information on inventory – value, status, receipt, location and disposition), and react in real-time to incoming events. The events can be of various nature and span from the simple notification (e.g. the vacation request was approved in the system), broadcasting (e.g. new repurchase prices are available and must be distributed to the users), process control information (e.g. delivery of sales orders took place, the billing process for customers can start) to events, which require immediate reaction (e.g. illegal trade pattern is detected). Another aspect of real-time is best support for collaborative scenarios (e.g. business users work on the same data records, collaboration platforms, interaction centers).

 

All in all developing real-time applications in ABAP is about the fast, event-driven, highly interactive and collaborative scenarios, which must be supported in ABAP applications.

 

How is it implemented in ABAP? ABAP development for SAP HANA enables real-time processing for huge amounts of business data by exploiting the strengths of In-Memory technology. Using SAPUI5/SAP Fiori on top of AS ABAP offers real-time UI experience and simplified business interactions by means of intuitive highly-responsive consistent UIs across multiple devices. The ABAP channels complete this real-time offering by supporting interactive and collaborative scenarios based on event-driven paradigm independent of database (yes, not only on HANA!) and UI (yes, it works also 'as prototype' for Dynpros!). ABAP Channels infrastructure is general available with SAP NetWeaver AS ABAP 7.40 Support Package 5 (SP05).

 

 


Real-time UI access to ABAP data with ABAP Push Channel (APC)

 

As described above, one of the important real-time characteristics is immediate access of users to the frequently changing business information and data in ABAP backend, which will support timely business insights, decision making and productivity.

 

The examples for this can be for instance bringing the irregularly and often changing product information and sale conditions to browser UI (SAPUI5, Web Dynpro ABAP, BSP) as soon as data change takes place in the ABAP backend, pushing short-lived financial data relevant for trades to the browser UI, statistics, process information (sales figures in different areas, financial statistics, manufacturing process status). In all these cases the data presentation on UI (charts, diagrams, text and numbers) must be updated immediately accordingly to the modified data in the ABAP backend.

 

In such situations in order to present the latest up-to-date information from the ABAP backend in real-time on the browser based UI most ABAP applications used polling techniques with multi-seconds intervals or refresh button periodically to get newest updates to UI. These approaches are quite resource consuming result in insufficient performance and poor user experience. The availability of real-time data in ABAP backend is unpredictable and it is unnecessary effort to make requests and open and close HTTP connections.

 

The ABAP Push Channel (APC) technology replaces such inefficient polling approach through WebSockets. ABAP Push Channel is bi-directional message based communication channel representing the WebSocket integration in ABAP, allowing e.g.to push notification to the UI as soon as data change in ABAP backend happens. This is a sign for a user to request the changed data from ABAP backend and update UI.

 

Picture2.png

 

More details about ABAP Push Channel and step-by-step guidance how to implement it in ABAP in Masoud’s Blog:

ABAPChannels Part 1: WebSocket Communication Using ABAP Push Channels.

 

 

Real-time communication between ABAP sessions with ABAP Messaging Channel (AMC)

 

Other aspect of the real-time behavior is reacting immediately to the events. Event-driven communication between ABAP sessions across the boundaries of ABAP application servers will streamline the business process workflow, speed up performance and reduce the rate of consumption of database resources. An ABAP application might need to identify and react to certain events in the other ABAP session as soon as they occur. Moreover an ABAP application might involve data processing in order to provide some output to be delivered to another application, running in another ABAP session and therefore has to send notification. Traditionally to realize such real-time event-driven behavior ABAP applications often poll periodically for the state information on the database. Bottleneck problems on the database may occur with numerous active polling from many ABAP applications simultaneously.

 

One of the examples of such real life situations can be long running calculations (sales statistics, loan calculations). A user may initiate a loan calculation (via asynchronous RFC) and it is running so long, that he is not any more interested in the status of calculations and the results and may want to proceed with another actions. In such case the running session (initiated e.g. by RFC) only consumes resources and the calculation must be stopped. In current implementations the ABAP application polls for the status of the calculation on the database. Another example is long running batch jobs (mass data changes, create deliveries from open sales orders, create invoices) which process data gradually. To simulate the real-time behavior, the calling ABAP session polls in short time intervals on the database for the status in order to request already processed data or get updated information.

 

Another example is the business workflow e.g. the manufacturing process, which consists of several productions steps (e.g. manufacturing of components), which are initiated in parallel by the central process (e.g. assembling) on different application servers and must report back their status as soon as they get accomplished. The central process would need to poll on the database periodically in order to get the status of the productions steps. All these situations result either in heavily loaded database by batch jobs, bottlenecks, or by resource- and time-intensive applications reducing database performance.

 

Instead of using periodically polling technique, a publish/subscribe mechanism can be used for prompt notification which can eliminate unnecessary database load. The ABAP Messaging Channel (AMC) infrastructure replaces the polling through publish/subscribe mechanism and acts as a broker for the messages exchange between different ABAP sessions, which can reside on different ABAP application servers. After ABAP sessions act as publisher and subscribers respectively, as soon as an ABAP session publishes notification to AMC, all subscriber ABAP sessions get notified.

 

Picture1.png

Picture3.png

 

More details about AMC and step-by-step guidance how to implement it in ABAP in Masoud’s Blog:

ABAP Channels Part 2: Publish/Subscribe Messaging Using ABAP Messaging Channels


Real-time collaboration with ABAP Push Channel (APC) and ABAP Messaging Channel (AMC)

 

Another essential element of the real-time business are real-time collaboration scenarios, which allow multiple users in different locations in internet to communicate instantly or work on the same business objects simultaneously sharing the same backend resources and even allowing collaborative real-time editing. Applying this to ABAP would mean for example SAPUI5 users in different ABAP sessions which reside on different ABAP application servers can communicate (send messages) and work together on the same ABAP business data records.

 

One of the business scenarios would be broadcasting and distributing of the irregularly and frequently changing business data in ABAP backend to the browser UIs of multiple users across the boundaries of the ABAP application servers (see APC use examples above)

 

Another real-time scenario would be collecting the data from any kind of hardware device (e.g. traffic control tool, medical equipment, RFID scanner, vehicle tracking control, multimedia system, etc.) in the ABAP system and display them on the UI, or react to event (robot reached its destination in the warehouse,

telephone call/chat arrived in the interaction center) in ABAP system with subsequent UI update with latest data without having to poll for the data changes.

 

In situations when multiple users work with the same data (e.g. customers or suppliers information) in the browser UI, and one user changes several data records, they must be updated immediately on all other user UIs.

 

If one goes a step further there are also scenarios of collaborative real-time editing of business object data in which multiple browser UI users have to edit jointly the data of the same ABAP object and modified data should be displayed on UI of other users in the real-time without having to lock the whole object.

 

For all these scenarios the collaboration of ABAP Push and Messaging Channels is the best choice. The publish/subscribe infrastructure of the ABAP Messaging Channels can be used with ABAP Push Channel to enable WebSocket UI clients to act as subscriber. This allows WebSocket UI clients either to receive notifications about data changes or to publish notifications requesting WebSocket UI clients to reload the data from source.

 

new_Picture1.png

 

More details about using AMC/APC for collaboration and step-by-step guidance how to implement it in ABAP in Masoud’s Blog:

ABAP Channels Part 3: Collaboration Scenario Using ABAP Messaging and ABAP Push Channels.

Do you also have the requirement to provide data from your ABAP-System to an Excel workbook? Then, I hope you heard about the fantastic abap2xlsx-library by Ivan Femia. If not, you should immediately head over to their project website. For our project, it saved a tremendous amount of effort and time. Let me briefly explain why and how it’s even more easy to provide beautiful Excel download from your ABAP system.


Starting point

During the specialization of our application some years back, users and consultants together defined complex Excel files they wanted the system to be generated. As we’re using a FPM-based Webdynpro user interface, we could not rely on using the GUI frontend services, but hat to use the OLE-based APIs. They are not only slow, but also quite clumsy to handle and need a lot of code. In  our sample, we had used more than 5.000 lines of code in order to produce a file which was at least almost matching the requested format.


ABAP2XLSX

Searching for alternative manipulation of Excel from ABAP, I came across abap2xlsx which has a beautiful API for creation and modification of Excel files. Particularly binding tabular data into a table-entity of the workbook is incredibly efficient. After having clarified the licensing questions, we communicated how much cheaper development would be if only we could rely on our customer using Excel 2007 (or at least Excel 2003 and the compatibility pack). Talking about savings, convincing them was not too difficult.


Templating

With all the facilities given by ABAP2XLSX, it still was quite some effort to define those rich files which may comprise  more than 100 fields and some tables: For each field, you as a developer have to define a label, format the cells, rows and columns and bind the data. Also for minor graphical changes (e. g. formating) or to the texts, a developer is needed. How beautiful would it be if the business expert could just provide a new version of a template? It would not even be required that the template layout remains if named cells would be used for filling the  template. We therefore decided to split up the provisioning of a the initial Excel as a view and the controller logic to fill it (which is in general a good idea).

template.png

Some sample template designed by a "business user" observer the beautiful formatting...


The MIME Repository as template store

Having got a prepared template by a business user, one important question remained: How to store, access and manage the lifecycle of a template? Of course, you could simply put the file into the filesystem of your application server, but there’s a much better option: The MIME Repository is a tool integrated into the ABAP workbench for managing storage of binary data. You can simply create an own folder for your application and upload your template-files to it. This give you

  • A transportable object which integrates into the deployment (transportation) of your ABAP-application
  • Authorization mechanism in order to limit who’s allowed to access and update which template
  • A nice separation of the presentation and the logic (though of course you might have to bridge some shortages with respect to i18n, depending on your customer)

MIME_rep_se80.png

The MIME-repository UI in SE80 - and the uploaded template


There’s an ABAP-API in order to load the binary content from which you create the ZEXCEL-object. You could for example use a factory:

METHOD create_from_mime_repository.  

  DATA lv_mime_file TYPE xstring. 
  DATA lo_excel_reader TYPE REF TO zif_excel_reader.  
  DATA lx_excel TYPE REF TO zcx_excel.

    cl_mime_repository_api=>get_api( )->get( 
          EXPORTING        i_url                  =  iv_mime_path           
          IMPORTING        e_content              = lv_mime_file           
          EXCEPTIONS OTHERS = 8 ). 

    IF sy-subrc <> 0.   
     RAISE EXCEPTION TYPE zcx_excel
          EXPORTING error = |File could not be found in MIME repositoy at { iv_mime_path }|. 
    ENDIF.  

    CREATE OBJECT lo_excel_reader TYPE zcl_excel_reader_2007.   

     TRY.        "Instantiate the Excel object on the basis of the binary date from the MIME-Repository
         ro_excel = lo_excel_reader->load( i_excel2007 = lv_mime_file ).   
    CATCH zcx_excel INTO lx_excel.    "excel loading error      
      RAISE EXCEPTION TYPE zcx_excel          
               EXPORTING error = |File at { iv_mime_path } could not be interpreted as Excel file|.
    ENDTRY.

ENDMETHOD.

Having done this very small coding, you’ll see your efficiency tremendously improved: You basically need one line of code per cell into which you’d like to populate data. Not for tables though: you need at least four lines of code – for the complete table.

"Load file from MIME-path

go_excel = zcl_excel_factory=>get_instance( )->create_from_mime_repository( '/SAP/PUBLIC/excel_templates/Template_Sample.xlsx' ).

 

"Fill some elementary data into a predefined format

go_excel->get_active_worksheet( )->set_cell(    
     ip_column    = 2       
     ip_row       = 1       
     ip_value     = 'Fruits'      ).

 

"Add tabular data

go_excel->get_active_worksheet( )->bind_table(     
     ip_table = gt_item
     is_table_settings = VALUE #( top_left_column = 'A' top_left_row = 4 )  
).

filled.png


Can you do this any easier?


Feedback appreciated!

Oliver


Excel Creation Methods :

Today there are a number of methods to create a formated Excel file like Standard FMs, IXML Interface, OLE, Using XML syntax , Using HTML syntax and few  more Interfaces ( available over Code Share Pages )..!!


Flexibility and Ease of Use :

Well, taking about  Ease of use, I would always prefer Standard FMs.


But the problem with Mr. FM is, there stiffness. I mean they are not really flexible enough to fulfill my business needs. My Business Team always thinks, creating an Excel thru SAP is equivalent to creating an Excel thru MS Office..!! ;(

Basically FMs creates Excel, which are more sort of fixed format file..!!


Next comes IXML interfaces, they are obviously flexible but I find them a bit bulky interms of Memory ComPlexity..!! Probalby, because you need to instnciate a Class and then set its attribute before using just a simPle Style, font or a new color../!! My business asks for a highly decorated Excel..!! Seems tough this way..!!


OLE ,, really tough stuff to deal with, once OLE starts to create Excel,, I usually move out of my desk, m sure, it will take a handsome amount of time..!!

Yes, Mr. OLE is really laZy, just like me. Takes too much of time for Excel creation..!!


So, I will oPt for XML or HTML Syntax out of all the available candidates..!!


Hmmm, I didnt talked about the other interfaces, actually I could not dare to PeeP inside,, My SAP has emPowered me with some beautiful tools.

No need to look at something else..!!


The HTML Way :

Create all you want using HTML Tags and Syntax, download it in a XLS file format and Now its ready to use..!!

As simPle, as a two minute noodle,, well.. Yes it is..!! lol

 

You can create a Table, Paint it easily, with the color, your near and dear wants..!!

<TABLE>

<td colspan =4>

<div><font size =5>Test Excel</font></div>

</TD>

</TR>

<tr>

<td colspan =9>

<font size =5>Excel Details</font>

</TD>

</TR>

 

 

HTML Tutorial will tell in detail about the HTML Syntax..

 

 

Create the Excel using your tags, keep them in an internal table or better in a String..!!

 

Use ,,

 

cl_bcs_convert=>string_to_solix with code page 4103..!!

 

Create the Doc Object using

 

cl_document_bcs=>create_document with tye 'RAW'..

 

Add the Excel attachment using document->add_attachment, with tye 'xls'..

 

Now, set_document,, add recipient  and then send document

 

For Mail sending area, Object report BCS_EXAMPLE_7 is also helpful..!!

 

Comments and Rectification :

Kindly put your comments, which can help me to further add values to blogs..!!

My mentors and guides over SDN, kindly rectify me if I am wrong somewhere..!!


Thanking You All..!!

related page 1
related page 2
related page 3


NOTE: Before beginning, the XLSX Workbench functionality must be available in the your system.

 

Let's use standard demo report BCALV_GRID_DEMO is available in the every system (the report demonstrates how to use ALV-Grid control). We will export an output table to the Excel based form.

 

1 PREPARE A PRINTING PROGRAM.

 

1.1 Copy standard demo report BCALV_GRID_DEMO to the customer namespace, for example Z_BCALV_GRID_DEMO :

IMAGE_4.PNG

 

1.2 In the copied report, add new button to GUI-status 'MAIN100':

IMAGE_5.PNG

 

1.3 In the report line number 40, insert next code to processing the new OK-code :

IMAGE_7.PNG

 

1.4 Activate objects:

IMAGE_8.PNG

 

2 PREPARE A FORM.

 

2.1 Launch XLSX Workbench, and in the popup window specify a form name TEST_GRID , and then press the button «Process»:

IMAGE_9.PNG

Empty form will be displayed:

444_19_1.png

2.2 Push button444_19_2.PNGto save the form.

 

 

2.3 Assign context FLIGHTTAB to the form:

IMAGE_12.PNG

 

Herewith, you will be prompted to create a form's structure automatically (based on context):

 


We will create form structrure manually,

therefore we should press the button

 

 

 

 

2.4 Add a Pattern (HEADER LINE) to the Sheet:

IMAGE_26.PNG

 

 

2.5 Add a Loop to the Sheet:

IMAGE_29.PNG

 

2.6 Set context binding for created Loop:

IMAGE_23_.PNG

 

 

2.7 Add a Pattern (POSITION) to the Loop:

IMAGE_32.PNG

 

2.8 Add a Values to the Pattern (POSITION):

IMAGE_37.PNG

 

2.9 Make markup in the Excel template:

IMAGE_38.PNG

 

2.10 Set template binding for Pattern (HEADER LINE). To do it, you have to perform next steps successivery:
  • Select node PATTERN_HEADERLINE in the tree of the form structure;
  • Select cells range A1:I1 in the Excel template;
  • Press a button IMAGE_39.PNG located in the item «Area in the template» of the Properties tab.

IMAGE_42.PNG

 

 

2.11 Set template binding for Pattern (POSITION). To do it, you have to perform next steps successivery:
  • Select node PATTERN_POSITION in the tree of the form structure;
  • Select cells range A2:I2 in the Excel template;
  • Press a button IMAGE_39.PNG located in the item «Area in the template» of the Properties tab.
IMAGE_43.PNG

 

2.12 Set template binding for Values. To do it, you have to perform steps, described in the previous item. Mapping is figured below:
  • CORRID           (cell: A2)
  • CONNID           (cell: B2)
  • FLDATE            (cell: C2)
  • PRICE              (cell: D2)
  • CURRENCY     (cell: E2)
  • PLINETYPE      (cell: F2)
  • SEATSMAX      (cell: G2)
  • SEATSOCC      (cell: H2)
  • PAYMENTSUM (cell: I2)


2.13 Finally, you have to set template binding as figured below:

IMAGE_47.PNG

 

2.14 Activate form by pressing button444_30.PNG.

 

 

 

3 EXECUTION.


Run your report Z_BCALV_GRID_DEMO; ALV-grid will be displayed :

IMAGE_48.PNG


Press button444_43.PNGto export Grid to Excel form :

IMAGE_49.PNG


Hi community!

 

I have come across the need to have a vendor contact created (you know, those contacts you find in XK01/2/3), and, to my disbelief, really the only possible way to do this programatically, is with a batch input!!

 

Well, not anymore. I have created a class that allows you to create and edit vendor contacts (deleting might be easy as well, but I haven't looked into it yet). Also, it should be fairly easy to extend this to create customer contacts as well. If that's what you need, go ahead and try to do it Ideally, there should be a generic "contact" class, and a subclass for vendor and customer contacts.

 

The most basic way to create a vendor contact is to use static method CREATE_CONTACT and populate vendor number (LIFNR) and last name (NAME1) in structure IM_HEADER_CONTACT_DATA. After that, it's up to you to figure out how to use it

 

You will find the nugget for the class under folder PURCHASE_TO_PAY/VENDOR_CONTACT of project object, here.

 

If you have any questions, feel free to ask, but don't expect 24/7 technical support, that doesn't come for free

 

Best regards,

Bruno

 

DISCLAIMER

 

This is not, by any means, a finished "commercial product". It still definitely needs a lot of work to be a final stable solution. However, it should be a great starting point to whatever you need. If you do some work on it and feel like sharing an improved version of this, please let me know.

 

Thanks.

I recently worked on a project which entailed enhancing vendor master, updating CREMAS04 Idoc with a new segment for custom records and finally being able to generate IDOCS with new segment when these custom fields of (added to )vendor master are updated. In this 3 part blog I will try to cover the development effort required to achieve the aforementioned functionality in detail.

 

The entire development effort can be classified into three sections as follows:

1) Extending the vendor master

2) Enhancing method VMD_EI_API->MAINTAIN( ) method to programmatically update vendor master tables (LFA1, LFB1, LFM1, LFM2 .. ) - part2.

3) Enhancing the CREAMS04 basis type to include the new segment. - part3

 

 

  1. Extending the vendor master.

        Extending vendor master involves enhancing the vendor master database table and vendor master screen. For the purpose of this blog I am going        to enhance LFA1 (vendor master general - header level ) table with custom fields.

    • Step 1: Carry out steps listed under step ‘Adoption of Customer’s Own Master Data Fields’. Follow this configuration path to reach this step.

     SAP IMG->Financial Accounting->Accounts Receivable and Accounts Payable->Vendor Accounts->Master Data->Preparations for Creating Vendor Master Data->Adoption of Customer's Own Master Data Fields.

SPRO_patch_to_modification_free_enhancement.png

    • Step 2:Execute step 'Prepare Modification-Free Enhancement in Vendor Master Record' step.

In this step you specify the screen group and screen number associated with the new vendor master fields.

Screengroup for venodr master.pngScreenNumber_for_vendor_master.png

    • Step 3:Execute step "Business Add-In: Process of Master Data Enhancements'.

             This steps allows user to create a implementation for BADI - VENDOR_ADD_DATA. In my example I am just activating the custom screen group

              Add on , However this BADI provides other methods to query data for add on fields, save data to table other then vendor master, initialize add-              on append structure ( discussed later ) and much more.

              BADI_VENDOR_ADD_DATA.png

                Implement badi venodor add data.png

    • Step 4:Execute the Business Add-In: customer subscreen step next.

                This steps allows for creation of implementation of BADI- VENDOR_ADD_DATA_CS. This badi provides methods to manipulate the screen elements of subscreen which are all associated with the screen-group declared in previous group. It also provides methods to set values to and read values from the screen fields on the subscreens.

                A filer with the screen group has to be specified before methods of this BADI can implemented.

               BADI_VENDOR_ADD_CS_FILTER.png

               BADI_VENDOR_ADD_CS_IMPLEMENTATION.png

    • Step 5:Next, LFA1 has to be enhanced with append structure consisting of custom fields which will show up on the new subscreen (9030 in this case).

               To do this, go to SE11 and open definition of table LFA1. Click on 'Append Structure..' option and then click on 'Create' to create new                append structure. Since for this demo IDOCS have to be created for any change in values stored in these custom fields. Make sure that the 'Change document' option is turned on at the data element level .

               Save all changes and active.

 

                Create a new append structure.png

                   Append structure with change documents.png

    • Step 6:The Next Step involves adding the fields from append structure to the custom subscreen (accessible via XK** transaction ).

               Execute transaction SE51 and create a new subscreen for program and screen number specified above ( step 4 and step2 respectively: program: SAPMZMSW_VEND_EPA, Screen: 9030 ).

               Create subscreen for new vendor fields.png

                  Click on the 'Dictionary/Program fields window' button to select the append structure fields from LFA1 table structure.

                  Select custom fields from append structure.png

                    Arrange the fields on the layout screen and save all changes.

                  Arrange screen layout for subscreen.png

    • Step 7: In this example the above added screen fields are all display only fields, hence no  PBO is necessary. However to populate these fields for display, LFA1 needs to be declared as a global variable (TABLES) in the dynpro program. Standard processing routing will automatically populate the LFA1 structure with value in the database. Since the screen elements created above all refer to the LFA1 structure they values will automatically be passed to the screen fields and display.

               LFA1 declaration in dynpro program.png

    • Step 8: Finally if all the steps are correctly followed you should be able to view a vendor in XK03 and see the subscreen that was added in the above step. However since all the fields on this subscreen are newly added fields they will all be empty. In the next part of this series, I will go over the steps required to  update the LFA1 structure from an external source.

                XK03_screen1.png

                XK03_screen2.png

You may have been in a situation where you have to process multiple objects. When you do this sequentially, it'll take some time before that processing finishes. One solution could be to schedule your program in background, and just let it run there.

But what if you don't have the luxury to schedule your report in background, or what if the sheer amount of objects is so large that it would take a day to process all of them, with the risk of overrunning your nightly timeframe and impacting the daily work.

 

Multi Threading

It would be better if you could actually just launch multiple processing blocks at the same time. Each block could then process a single object and when it finishes off, release the slot so the next block can be launched.

That could mean that you could have multiple objects updated at the same time. Imagine 10 objects being processed at once rather than just one object sequentially. You could reduce your runtime to only 10% of the original report.

 

It's actually not that hard. If you create a remote enabled function module, containing the processing logic for one object, with the necessary parameters, you can simply launch them in a new task. That creates a new process (you can monitor it in transaction SM50) which will end as soon as your object is processed.

 

Newtask.png

 

Here's a piece of pseudo-code to realise this principle.

data: lt_object type whatever. "big *** table full of objects to update

 

 

 

while lt_object[] is not initial.

     loop at lt_object assigning <line>.

 

          call function ZUPDATE starting new task

               exporting <line>

               exceptions other = 9      

 

          if sy-subrc = 0.

               delete lt_object.

          endif.

     endloop.

endwhile.


Something like that.

Notice how there's a loop in a loop, to make sure that we keep trying until every object has been launched to a process. Once an object has been successfully launched, remove it from the list.

 

Queue clog

But there's a catch with that approach. As long as the processing of an individual object doesn't take up too much time, and you have enough DIAlog processes available, things will work fine. As soon as a process ends, it's freed up to take on a new task.

 

But what if your processes are called upon faster than they finish off? That means that within a blink of an eye, all your processes will be taken up, and new tasks will be queued. That also means that no-one can still work on your system, because all dialog processes are being hogged by your program.

queue clog.png

* notice how the queue is still launching processes, even after your main report has already ended.

 

You do not want that to happen.

 

First time that happened to me was on my very first assignment, where I had to migrate 200K Maintenance Notifications. I brought the development system to its knees on multiple occasions.

The solution back then was double the amount of Dialog processes. One notification process finished fast enough before the main report could schedule 19 new tasks, so the system never got overloaded.

 

Controlled Threading

So what you want, is to control the number of threads that can be launched at any given time. You want to be able to say that only 5 processes may be used, leaving 5 more for any other operations. (That means you could even launch these mass programs during the day!)

But how do you do that?

 

Well, you'll have to receive the result of each task, so you can keep a counter of active threads and prevent more from being spawned as long as you don't want them to.

 

caller:

data: lt_object type whatever. "big *** table full of objects to update

 

 

 

while lt_object[] is not initial.

     loop at lt_object assigning <line>.

          call function ZUPDATE starting new task

               calling receive on end of task

               exporting <line>

               exceptions other = 9      

      

          if sy-subrc = 0.

               delete lt_object.

               add 1 to me->processes

          endif.

     endloop.

endwhile.

receiver

RECEIVE RESULTS FROM FUNCTION 'ZUPDATE'.

substract 1 from me->processes

 

This still just launches all processes as fat as possible with no throtling. It just keeps the counter, but we still have to do something with that counter.

And here's the trick. There's a wait statement you can use to check if the number of used processes is less than whatever you specify.

But this number is not updated after a receive, unless you logical unit of work is updated. And that is only done after a commit, or a wait statement.

But wait, we already have a wait statement, won't that update it?

Why yes, it will, but than it's updated after you waited, which is pretty daft, cause then you're still not quite sure whether it worked.

 

so here's a trick to get around that.

caller:

data: lt_object type whatever. "big *** table full of objects to update

 

 

while lt_object[] is not initial.

     loop at lt_object assigning <line>.

 

 

          while me->processes <= 5.

               wait until me->processes < 5.

          endwhile.

 

 

          call function ZUPDATE starting new task

               calling receive on end of task

               exporting <line>

               exceptions other = 9      

 

 

          if sy-subrc = 0.

               delete lt_object.

               add 1 to me->processes

          endif.

     endloop.

endwhile.

 

That'll keep the number of threads under control and still allow you to achieve massive performance improvements on mass processes!

 

Alternatives

Thanks to Robin Vleeschhouwer for pointing out the Destination groups. Starting your RFC in a specific destination group, your system administrators can control the number of processes in that group. The downside is that it's not as flexible as using a parameter on your mass-processing report, and you have to run everything past your sysadmins.

 

Another sweet addition came from Shai Sinai under the form of bgRFC. I have to admit that I actually never even heard of that, so there's not much I can say at this point in time. Except, skimming through the doco, it looks like something pretty nifty.

Welcome back to another ABAP Trapdoors article. It’s been a while – I’ve posted my last article in 2011. In the meantime, I’ve collected a number of interesting topics. If you’re interested in the older articles, you can find the links at the end of this article.

 

A few weeks ago, I had to code some seemingly simple task: From a SAP Business Workflow running in system ABC, a sub-workflow with several steps had to be started in another system, or even a number of other systems. Since a BPM engine was not available, I decided to use simple RFC-enabled function modules to raise workflow events in the target system. The sub-workflows can then be started via simple object type linkage entries. While this approach works quite well for my simple scenario, I ran into an altogether unexpected issue that took me quite a while to figure out.

 

There are two function modules to raise the workflow events: SAP_WAPI_CREATE_EVENT and SAP_WAPI_CREATE_EVENT_EXTENDED. In my case, I used the extended function module because I was working with class-based events. So the call basically was

 

  CALL FUNCTION 'SAP_WAPI_CREATE_EVENT_EXTENDED' DESTINATION l_rfcdest
    EXPORTING
      catid             = 'CL'
      typeid            = 'ZCL_MY_CLASS'
      instid            = l_instid
      event             = 'MY_EVENT'
    ... 

To my surprise, it did not work - the system kept telling me that the event M does not exist. After spending a considerable time debugging and scratching my head, I finally identified the issue. Since it can be tricky to reproduce this particular issue, here is a very simple function module to demonstrate the actual problem:

 

FUNCTION ztest_rfc_echo.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*"  IMPORTING
*"     VALUE(I_INPUT_VALUE) TYPE  STRING
*"  EXPORTING
*"     VALUE(E_OUTPUT_VALUE) TYPE  STRING
*"----------------------------------------------------------------------

  e_output_value = i_input_value.

ENDFUNCTION.

(If you want to try this for yourself, make sure that the function module is RFC-enabled.)

This is no more than a simple value assignment – Text goes in, text comes out, right? Let’s see. Here is a demo program to check it out:

 

REPORT ztest_rfc_conversion.

DATA: g_value TYPE string.

START-OF-SELECTION.

  CALL FUNCTION 'ZTEST_RFC_ECHO'
    EXPORTING
      i_input_value  = 'This is a C literal'
    IMPORTING
      e_output_value = g_value.
  WRITE: / '1:', g_value.

  CALL FUNCTION 'ZTEST_RFC_ECHO'
    EXPORTING
      i_input_value  = `This is a STRING literal`
    IMPORTING
      e_output_value = g_value.
  WRITE: / '2:', g_value.

  CALL FUNCTION 'ZTEST_RFC_ECHO' DESTINATION 'NONE'
    EXPORTING
      i_input_value  = 'This is a C literal'
    IMPORTING
      e_output_value = g_value.
  WRITE: / '3:', g_value.

  CALL FUNCTION 'ZTEST_RFC_ECHO' DESTINATION 'NONE'
    EXPORTING
      i_input_value  = `This is a STRING literal`
    IMPORTING
      e_output_value = g_value.
  WRITE: / '4:', g_value.

 

In this program, the function module is called twice within the same session and twice starting a new session, using both a character literal and a string literal (note the difference between 'X' and `X`!). And the output is:

 

output.png

 

As you can easily see, the character literal is chopped off after the first character, but only if the function module is called via RFC. The same thing happened in my original program since the parameter EVENT of the function module SAP_WAPI_CREATE_EVENT_EXTENDED is of type STRING.

 

I considered this a bug, especially since neither SLIN nor the code inspector warned about this issue. As a good SAP citizen, I created a SAPnet ticket. After a lengthy discussion, I was told

There is no "implicit conversion" in RFC, therefore application need to adjust(or choose) a proper data types for calling/receiving RFMs.

In the end, this problem is very similar to the one explained by Jerry Wang in his blog a few weeks ago – another trapdoor in the development environment you constantly have to keep in mind when doing RFC programming if you want to avoid being reduced to a single character with a lot of trouble…

 

Older ABAP Trapdoors articles

Who should read this?

First and foremost, if you don't know what a design pattern is, then this blog is most certainly targeted at you.

 

Secondly those who don't really understand the Model View Controller (MVC) design pattern should also keep on reading.

 

What is the MVC?

My intention was never to write a blog on what it is or how to implement it.  There is heaps of content on the internet and also on SCN.  A simple search and you can find tons of stuff out there.  It's been around for ages, in fact it's older than me, so it's pretty old.

 

Here are some of my favourites:

http://blog.codinghorror.com/understanding-model-view-controller/

http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

 

Where are you going wrong?

I've worked at quite a few clients over the years and it never ceases to amaze me at the number of developers unaware of MVC & it's importance to SAP frameworks.  Even more horrifying is the number of developments/extensions I have seen that break this pretty straight forward design pattern. 


The most classic example of this is those who code business logic within the UI (a view). This results in two very frustrating outcomes

  • Data input via other views (i.e. via middleware) will not have the same business validation logic and as result the application data may be corrupted
  • Validation logic has been duplicated in multiple views. Maintainance requires double the effort and if not managed could result in inconsistencies.

.

 

Why should I learn it?

It's the same pattern that keeps cropping up again and again and it does not appear to be going away any time soon...

 

FrameworkMVC Links
BSPModel View Controller (MVC) - Business Server Pages - SAP Library
ABAP WebDynproWeb Dynpro and the Model View Controller Design - SAP NetWeaver Composition Environment Library - SAP Library
OpenUI5OpenUI5 SDK - Demo Kit
Introduction to UI5 - MVC 1 - YouTube
Introduction to UI5 - MVC 2 - YouTube

 

So if you don't know MVC, you really can't say you know these frameworks and even worse are potentially using them incorrectly.

 

Many non SAP programming languages incorporate frameworks built on this concept and the sooner you spot it the easier it will be for you to adopt a particular framework and the less likely you are to fall into one of the pitfalls described in previous section.

 

Cleaner Code

The ability to have a clean separation of code, that promotes code reuse is fantastic.  So much so that I find myself using this priniciple even when writing ABAP reports.  The ability to plug in different views makes it quick to extend the logic to expose the report data as an e-mail, alv, file download, etc.  And is abundantly clear to anyone maintaining it on where to make changes.

 

One final note

Please, please, please.  If you don't understand it and before you attempt to create or extend any more content, take some time out to learn this pattern.  Your collleagues, your employers and everyone who works with your code will forever appreciate it.

Hi All,

recently i got a scenario to biuld a Multilevel Employee Hierarchy report, i posted it on SCN because i was not getting how could i achieve it through custom program (There are some function modules available for the same purpose e.g. RH_STRUC_GET, but alone it was not fulfilling my requirements). Although it is something like as in standard transaction PPOME, but what i was expecting  is something different from what you can see in PPOME transaction. After posted the query on SCN , i was not able to get a single reply (strange for me , i don't know why). Then i decided to create a Custom Program to show Multilevel Hierarchy Report for Employees, in which you can see all those employee under any level along with its designation , Name, its id, and so on. I have hided the name of Concerned person in this screenshot, and anyone can edit this program to make a good use of Custom Multilevel Hierarchy report.

Although i have searched for the same on SCN, but i got all the answer which was related to the Hierarchy of one person. And it was not my requirement. So, here i am posting this whole code alongwith the screenshot of Output, so that it will benifit all those members or new persons who wants to create a Multilevel Hierarchy Report.

(There may be some correction in this program, which might help in creating a more benificial list, i will appreciate all those suggestions which will come to me to add within my custom code.)

 

Step By Step Process i have implemented in getting this List.

 

 

Let us assume that i have to show all the concerned person under CMD, let us assume that will have many GM, HR head, Purchase Head, Sales Head like persons who are directly reporting to the CMD, again for each department head we will have persons with different positions, and this hierarchy will be from Top - To - Bottom and can be spreaded upto any level. Now the problem is through RH_STRUC_GET we can get all the concerned person details which has a immediate reporting structure.

A user needs to see the hierarchy details at any level, means he could see either starting for a GM , or for a Executive.

 

Checking for initial entry, if a avalid person has been entered or not.

 

AT SELECTION-SCREEN.

 

   IF p_pernr IS NOT INITIAL.

 

    SELECT SINGLE pernr

       FROM pa0001

       INTO lv_pernr

       WHERE pernr EQ p_pernr

       AND   endda EQ '99991231'.

 

     IF sy-subrc IS NOT INITIAL.

       MESSAGE 'Please enter a valid Employee Code'  TYPE 'E'.

     ENDIF.

   ENDIF.

 

 

Now with the use of RH_STRUC_GET i get all the employees that are directly or indirectly reporting to the concerned person for which i need to see the hierarchy, in tables parameters we will have three tables namely

 

it_result_tab   -> which shows the result of all objid which are directly or indirectly related to a concerned person

 

it_result_object -> which shows the designation of all employee with other details

 

it_result_struc   -> contains the level of each employee with other details

 

Now getting all the employees details through RH_STRUC_GET

 

FORM get_data .

 

   CLEAR lv_objid.

   SELECT SINGLE plans

     INTO lv_objid

     FROM pa0001

     WHERE pernr = p_pernr

     AND endda = '99991231'.

 

   CALL FUNCTION 'RH_STRUC_GET'

     EXPORTING

       act_otype      = 'S'

       act_objid      = lv_objid

       act_wegid      = 'B002'

       act_plvar      = '01'

       act_begda      = pm_datuv

       act_endda      = pm_datuv

     TABLES

       result_tab     = it_result_tab

       result_objec   = it_result_objec

       result_struc   = it_result_struc

     EXCEPTIONS

       no_plvar_found = 1

       no_entry_found = 2

       OTHERS         = 3.

 

ENDFORM.  

 

Now as we will have a table it_result_struc having levels of all employee, so getting the related details of employees.

 

FORM preapare_final_table .

 

   LOOP AT  it_result_struc INTO wa_result_struc .

     MOVE-CORRESPONDING wa_result_struc TO it_struct.

 

     SELECT SINGLE pernr

                   ename

                   bukrs

                   werks

                   btrtl

                   persk

                   kostl

       FROM pa0001

       INTO (it_struct-pernr ,

             it_struct-ename,

             it_struct-bukrs,

             it_struct-werks,

             it_struct-btrtl,

             it_struct-persk,

             it_struct-kostl )

       WHERE endda = '99991231'

       AND plans = it_struct-objid.

 

 

 

     SELECT SINGLE ptext

       FROM t503t

       INTO it_struct-ptext

       WHERE persk = it_struct-persk.

 

     SELECT SINGLE btext

       FROM t001p

       INTO it_struct-btext

       WHERE werks = it_struct-werks

         AND btrtl = it_struct-btrtl.

 

 

     SELECT SINGLE ltext

       FROM cskt

       INTO  it_struct-ltext

       WHERE spras  = 'E'

       AND kostl = it_struct-kostl.

 

     SELECT SINGLE plstx

       FROM t528t

       INTO it_struct-plstx

       WHERE sprsl = 'E'

         AND plans = it_struct-objid.

 

     APPEND it_struct.

     CLEAR it_struct.

 

   ENDLOOP.

 

   IF so_bukrs[] IS NOT INITIAL.

     DELETE it_struct WHERE bukrs NOT IN so_bukrs.

   ENDIF.

 

   IF so_werks[] IS NOT INITIAL.

     DELETE it_struct WHERE werks NOT IN so_werks.

   ENDIF.

 

   IF so_btrtl[] IS NOT INITIAL.

     DELETE it_struct WHERE btrtl NOT IN so_btrtl.

  ENDIF.

 

   IF so_persk[] IS NOT INITIAL.

     DELETE it_struct WHERE persk NOT IN so_persk.

  ENDIF.

 

   IF so_kostl[] IS NOT INITIAL.

     DELETE it_struct WHERE kostl NOT IN so_kostl.

  ENDIF.

 

   DELETE it_struct WHERE pernr IS INITIAL.

 

 

  READ TABLE it_struct WITH KEY pernr = p_pernr.

   IF sy-subrc IS NOT INITIAL.

    SELECT SINGLE pernr

                   ename

                   bukrs

                   werks

                   btrtl

                   persk

                   kostl

                   plans

       FROM pa0001

       INTO (it_struct-pernr,

             it_struct-ename,

             it_struct-bukrs,

             it_struct-werks,

             it_struct-btrtl,

             it_struct-persk,

             it_struct-kostl,

             it_struct-objid )

       WHERE endda = '99991231'

         AND plans = lv_objid.

 

     SELECT SINGLE ptext

       FROM t503t

       INTO it_struct-ptext

       WHERE persk = it_struct-persk.

 

     SELECT SINGLE btext

       FROM t001p

       INTO it_struct-btext

       WHERE werks = it_struct-werks

         AND btrtl = it_struct-btrtl.

 

     SELECT SINGLE ltext

       FROM cskt

       INTO  it_struct-ltext

       WHERE spras  = 'E'

       AND kostl = it_struct-kostl.

 

     SELECT SINGLE plstx

       FROM t528t

       INTO it_struct-plstx

       WHERE sprsl = 'E'

         AND plans = it_struct-objid.

 

     it_struct-level = 0.

 

     INSERT it_struct INDEX 1.

 

     DELETE ADJACENT DUPLICATES FROM it_struct COMPARING pernr.

  ENDIF.

 

ENDFORM.                   

 

 

Now we have all the data in our internal table it_struct, including level of each employee , here level refers to the hierarchy level of each employee w.r.t. to higher person for which we want to see the reporting hierarchy.

 

So, we have to go for each level separately and see haow many are reporting them directly, and the same will be checked for each entry.

 

FORM prepare_relationship .

 

 

   LOOP AT it_struct INTO wa_struct.

     lv_index = sy-tabix - 1.

     IF sy-tabix EQ 1.

       MOVE wa_struct-pernr TO ts1_pernr-pernr.

       APPEND ts1_pernr TO gt_pernr.

       CONTINUE.

     ELSE.

       PERFORM get_heir USING  wa_struct

                        CHANGING lv_index

                          gt_pernr.

    ENDIF.

   ENDLOOP.


LOOP AT gt_pernr INTO wa_person.

     CLEAR lv_counter.

     lv_index1 = sy-tabix + 1 .

     LOOP AT gt_pernr INTO wa_person1 FROM lv_index1.

       IF wa_person1-level GT wa_person-level .

         lv_counter = lv_counter + 1.

       ELSEIF  wa_person1-level EQ wa_person-level .

         EXIT.

       ENDIF.

     ENDLOOP.

     MOVE wa_person-pernr TO gt_pernr3-pernr.

 

     IF lv_counter IS INITIAL.

       lv_counter 1.

    ENDIF.

 

     MOVE  lv_counter TO gt_pernr3-count.

     APPEND gt_pernr3.

   ENDLOOP.

 

 

   gt_pernr2[] = gt_pernr[].

 

   SORT gt_pernr2 BY f_pernr.

   LOOP AT gt_pernr2.

     MOVE gt_pernr2-f_pernr TO it_pernr-pernr.

     MOVE 1 TO it_pernr-count.

     COLLECT it_pernr.

   ENDLOOP.

 

ENDFORM.   

 

 

FORM get_heir   USING    wa_struct  TYPE ty_pernr

                CHANGING lv_index  TYPE sy-tabix

                         gt_pernr    TYPE tt_bom.

 

   READ TABLE it_struct INTO wa_struct1 INDEX lv_index.

 

   IF sy-subrc IS INITIAL.

     IF wa_struct-level > wa_struct1-level.

       MOVE: wa_struct-pernr TO ts1_pernr-pernr,

             wa_struct1-pernr TO ts1_pernr-f_pernr,

             wa_struct-level TO ts1_pernr-level.

       APPEND  ts1_pernr TO gt_pernr.

    ELSE.

 

       IF lv_index > 1.

         lv_index = sy-tabix - 1.

         PERFORM get_heir USING  wa_struct

                         CHANGING lv_index

                                  gt_pernr .

       ELSE.

         MOVE: wa_struct-pernr TO ts1_pernr-pernr,

               wa_struct1-pernr TO ts1_pernr-f_pernr,

               wa_struct-level TO ts1_pernr-level.

         APPEND  ts1_pernr TO gt_pernr.

       ENDIF.

     ENDIF.

   ENDIF.

ENDFORM.        

 

 

To create the ALV Tree, we have to create a method, below code has been created for displaying the ALV Tree.

 

FORM display_alv_tree .

 

   LOOP AT gt_pernr ASSIGNING <fs_pernr>.

 

 

     READ TABLE it_struct INTO wa_struct

     WITH KEY pernr = <fs_pernr>-pernr.

 

 

 

     IF <fs_pernr>-f_pernr = ''.

 

       READ TABLE gt_pernr3 WITH KEY pernr = wa_struct-pernr.

       IF sy-subrc IS INITIAL.

         MOVE gt_pernr3-count TO lv_str.

         CONCATENATE wa_struct-ptext '( count' lv_str ')'INTO  l_node_text SEPARATED BY space.

       ELSE.

         l_node_text wa_struct-ename.

       ENDIF.

 

       READ TABLE it_pernr WITH KEY pernr = wa_struct-pernr.

       IF sy-subrc  IS INITIAL.

         MOVE it_pernr-count TO wa_struct-count.

       ELSE.

         MOVE 1 TO wa_struct-count.

       ENDIF.

 

       CLEAR l_node_key.

 

       CALL METHOD g_alv_tree->add_node

         EXPORTING

           i_relat_node_key = l_node_key

           i_relationship   = cl_gui_column_tree=>relat_last_child

           i_node_text      = l_node_text

           is_outtab_line   = wa_struct

         IMPORTING

           e_new_node_key   = l_node_key.

 

     ELSE.

 

       READ TABLE gt_pernr INTO w_pernr

       WITH KEY pernr = <fs_pernr>-f_pernr.

 

       READ TABLE gt_pernr3 WITH KEY pernr = wa_struct-pernr.

       IF sy-subrc IS INITIAL.

         MOVE gt_pernr3-count TO lv_str.

         CONCATENATE wa_struct-ptext '( count' lv_str ')'INTO  l_node_text SEPARATED BY space.

       ELSE.

         l_node_text wa_struct-ename.

       ENDIF.

 

       READ TABLE it_pernr WITH KEY pernr = wa_struct-pernr.

       IF sy-subrc  IS INITIAL.

         MOVE it_pernr-count TO wa_struct-count.

       ELSE.

         MOVE 1 TO wa_struct-count.

       ENDIF.

 

       lv_key =   w_pernr-key.

 

       CALL METHOD g_alv_tree->add_node

         EXPORTING

           i_relat_node_key = lv_key

           i_relationship   = cl_gui_column_tree=>relat_last_child

           i_node_text      = l_node_text

           is_outtab_line   = wa_struct

         IMPORTING

           e_new_node_key   = l_node_key.

    ENDIF.

 

 

     <fs_pernr>-key = l_node_key.

     lv_key = <fs_pernr>-key.

 

  ENDLOOP.

 

ENDFORM.                    " DISPLAY_ALV_

 

 

MODULE status_0100 OUTPUT.

   SET PF-STATUS 'MAIN11'.

   SET TITLEBAR 'MAINTITLE1'.

   IF g_alv_tree IS INITIAL.

     PERFORM init_tree.

 

     CALL METHOD cl_gui_cfw=>flush

       EXCEPTIONS

         cntl_system_error = 1

         cntl_error        = 2.

     IF sy-subrc NE 0.

       CALL FUNCTION 'POPUP_TO_INFORM'

         EXPORTING

           titel = 'Automation Queue failure'(801)

           txt1  = 'Internal error:'(802)

           txt2  = 'A method in the automation queue'(803)

           txt3  = 'caused a failure.'(804).

     ENDIF.

   ENDIF.

ENDMODULE.  



Now creating the container for holding the node containing the details


FORM init_tree .

   DATA: l_tree_container_name(30) TYPE c.

 

   l_tree_container_name = 'CCONTAINER1'.

 

   CREATE OBJECT g_custom_container

     EXPORTING

       container_name              = l_tree_container_name

     EXCEPTIONS

       cntl_error                  = 1

       cntl_system_error           = 2

       create_error                = 3

       lifetime_error              = 4

       lifetime_dynpro_dynpro_link = 5.

   IF sy-subrc <> 0.

     MESSAGE x208(00) WITH 'ERROR'(100).

   ENDIF.

 

* create tree control

   CREATE OBJECT g_alv_tree

     EXPORTING

       parent                      = g_custom_container

       node_selection_mode         = cl_gui_column_tree=>node_sel_mode_single

       item_selection              = 'X'

       no_html_header              = 'X'

       no_toolbar                  = ''

     EXCEPTIONS

       cntl_error                  = 1

       cntl_system_error           = 2

       create_error                = 3

       lifetime_error              = 4

       illegal_node_selection_mode = 5

       failed                      = 6

       illegal_column_name         = 7.

   IF sy-subrc <> 0.

     MESSAGE x208(00) WITH 'ERROR'.                          "#EC NOTEXT

   ENDIF.

 

   DATA l_hierarchy_header TYPE treev_hhdr.

   PERFORM build_hierarchy_header CHANGING l_hierarchy_header.

 

  CALL METHOD g_alv_tree->set_table_for_first_display

     EXPORTING

       i_structure_name    = 'ZHR_EMP'

       is_hierarchy_header = l_hierarchy_header

     CHANGING

       it_outtab           = gt_pernr1. "table must be empty !

 

   PERFORM get_data.

   PERFORM preapare_final_table.

   PERFORM prepare_relationship.

   PERFORM display_alv_tree.

 

   CALL METHOD g_alv_tree->frontend_update.

 

ENDFORM.   


When you will execute the report , you will get a result like this


 

Capture1.PNG

 

 

 

 


On opening its successive nodes, you will get the various level of hierarchy.



PS.: Editing still is in Process.

 

 

Employee Hierarchy.PNG

 

 

In the above screenshot i have shown that how many peoples are there under each level, The Source Code can be optimised for any data related to this Hierarchy (Means you can add your needy data to show here.).

 

 

Regards

Sanjeev kumar.

Quite recently I've been impressed by a blog post by Eric Petersen, describing a better logging solution for ABAP OO. However, while this approach definitely addresses quantitative part of the problem, in terms of squashing the code a bit, I could not help thinking that this is something like buying a better porcelain in a diarrhea case. It will simply not cure the illness, no matter how hard you try.

 

So, what's the cure then?

The first and most important question is, when writing an application, any application - are we really interested in logging? Yes, logging is something we must take care of at some point, just like authorization checks, possibly also tracing and lots of other stuff, but is this really supposed to be a concern of mine as an application author? Does the log handling really need to clutter my shiny application code?

 

The keyword is Concern

...Or, more precisely, separation of concerns. After all, logging presents such a brilliant example of a cross-cutting concern which bubbles all around the place. In fact, we can never be sure that we're not going to need logging at any specific point in code later, some time in the future. Neither can we predict that we might need to log some more stuff in certain cases while some places we have decided earlier in the project to do the logging are not really needed any more and could be cleaned up.

So what do we do? Refactor and refactor to death? Well, I don't know how about you but I hate such menial manual jobs, not to speak of the likelihood to do something wrong and be forced to come back to the same place in the code again and again. That's no fun.

 

C'mon, show me the solution!

Enough small talk. Besides, the RIGHT logging solution is not rocket science and only requires a tiny bit of AOP:

screenshot031.png

Yes? That ABAP does not support AOP? Maybe it does not, maybe it does... It depends mostly if you have Vesna Framework installed in your NetWeaver system (which needs to be at least 7.02 or higher).

You can download the demo source code attached to this blog post and see how you can get rid of logging code from your application altogether and yet, log anything you want, anywhere you want. Moreover, your decisions do not have to be final, neither you are bound to any specific implementation of the logger. Does it sound like a fairly tale? A good one, possibly? But you may wake up. Really. Vesna AOP does give you all this, and much more.

 

Download & Install

Don't just read. Try it. If you see the code in action and feel it, you will immediately embrace the power of an AOP programming model and it will give you wings.

The installation of the demo report is actually a breeze. I presume you'll be using SE80 rather than ADT. If you use ADT, you'll find it no problem to adapt the instruction below.

  1. Download all files attached to this blog post.
  2. Install them as follows:
ActionImage
Create a local class ZLOGGER. This will be our emulation of the logger wrapper implementation. In your productive application you'd use something more functional, like e.g. a BAL log wrapper proposed by Eric Petersen in his blog. Just accept default options and save it in $TMP.screenshot023.png
Switch to source-code based edytor.screenshot024.png
Copy-paste the source code from the appropriate section of the CLASSES.txt attachment to this blog and activate the class.screenshot025.png
Repeat the same operations for the class ZLOG_ASPECTscreenshot026.png
...and for the class ZDEMO_APPLICATIONscreenshot027.png
Finally, create report ZVESNA_AOP_LOGscreenshot028.png
Default options will do just fine. Confirm and save in $TMP.screenshot029.png
Copy-paste the contents of the ZVESNA_AOP_LOG.txt source code file and activate the report.screenshot030.png

 

All right, so what am I looking at?

What you have in front of you at this point is a simple AOP application, a small tribute to Mr. Masataka Taketsuru, the creator of Yoichi whisky brand, since 1940 known as Nikka. Personally, I'm not particularly fond of modern trends to die as virgin as you can, therefore I greatly appreciate the efforts of great masters of humanity to bring some colour to life. The small AOP app in front of you allows you to evaluate approximate distance in days between a chosen brand of whisky and reference brand which has been set to Yoichi, 1934 (it's just my personal taste, no philosophy behind it).

Btw: the appreciation for Japanese whisky appears seems to grow with time: Hochprozentige Rangliste: Der beste Whisky der Welt - Aus aller Welt - Panorama - Handelsblatt.

But we're here to see some nice and good logging, right? So let's get down to it.

As soon as you run the application you will see an output similar to this:

Application returned:
Yamazaki is 4018 days older than reference brand Yoichi.

 

Log output:
20.10.2014 21:30:11,5160000: Starting whisky age evaluation app...
20.10.2014 21:30:11,7510000: About to evaluate Yamazaki dated 01.01.1923.
20.10.2014 21:30:11,7510000: Evaluation result for Yamazaki: Yamazaki is 4018 days older than reference brand Yoichi.
20.10.2014 21:30:11,7510000: Whisky evaluation app finished.

Now, what's so special about it?

 

Logging AOP style

If you take a look at the actual application code of the class ZDEMO_APPLICATION you'll see no trace of logging. Nowehere. There are no traces of any logger bindings. So how come that we do have some logger entries (marked green in the listing above) somewhere right in the middle of the application?

 

The answer is AOP configuration

In the upper part of the demo app screen, when you run it, you'll see Vesna config for the application. Please take a closer look at the part marked blue:

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.vesnaframework.org" xmlns:aop="http://www.vesnaframework.org/schema/aop">

  <bean id="application" class="ZDEMO_APPLICATION">

    <!-- Date established: -->

    <constructor-arg name="REFERENCE_DATE" value="1934-01-01" />

    <!-- Reference whisky brand: -->

    <constructor-arg name="REFERENCE_NAME" value="Yoichi" />

  </bean>

  <bean id="logAspect" class="ZLOG_ASPECT" >

    <constructor-arg name="LOGGER" ref="logger" />

  </bean>

  <aop:config autoproxy-mode="default">

    <aop:aspect ref="logAspect">

      <aop:around pointcut="execution(*)" method="PROCESS"/>

    </aop:aspect>

  </aop:config>

</beans>

What you're looking at is aspect weaving configuration, instructing our tiny Vesna app that it needs an around advice for every method call since pointcut expression is set to wildcard (*). Also, it tells Vesna framework that the advice is implemented by the method PROCESS of the bean referenced to as logAspect. If you're unfamiliar with AO terms, please consult the documentation for any aspect-enabled language. Java Spring documentation will do for that purpose.

 

How does it work?

Well, really simple, in fact. Vesna Framework uses advanced proxying mechanism that allows for runtime aspect weaving, based upon defined pointcuts. This mechanism is very similar to what is being used in other AOP-enabled evironments.

 

Ultimate separation of concerns

I might have resisted from this boisterous heading for this paragraph but it was too tempting, really... Since AOP really does give you exactly what you'd wish for your application: being able to inject the logging anywhere you'd want, without changing a single line of your code.

The logging functionality itself is encapsulated in the class ZLOG_ASPECT. Needless to say, you can use more aspects calling specialized logs for various functional contexts in your application. Logging aspect uses logger bean, encapsulating actual log wrapper of some kind.

Since our aspect is of an around kind, its signature of the logging method PROCESS must contain at least the reference to the join point of type ref to /ARCONA1/PROCEEDING_JOIN_POINT. The parameter name is meaningless. This parameter allows the aspect to make a decision to pass the call further down the call chain, by the means of using the PROCEED( ) method, or not. In our logging case we don't want to interfere with application logic itself so we'll call that.

Apart from that, the signature of the ZLOG_ASPECT->PROCESS( ) method may contain also same parameters as captured method. In our case these are: DATE, NAME and RESULT. In such a way we can easily use original paremetr values of the method call at runtime, e.g. to do better logging.

 

There's more than just logging to AOP

I hope I got you interested... In Japan's whisky heritage!

But - as regards AOP - the logging is just the beginning. Do you think that changing the parameters of a method's call on-the-fly could be fun? Then stay tuned to the next part of the Vesna blog!


The small print

Needless to say, all whisky brand names used in this blog belong to their proprietary holders. The author of this blog is in no way associated with any of them. However, let the mastery of Japanese whisky creators never be forgotten, howgh.

related page 1
related page 2
related page 3


NOTE: Before beginning, the XLSX Workbench functionality must be available in the your system.

 

Let's use standard demo report BCALV_TREE_02 is available in the every system (the report demonstrates how to use ALV-Tree control). We export this ALV-tree to the Excel based form.

 

1 PREPARE A PRINTING PROGRAM.

 

1.1 Copy standard demo report BCALV_TREE_02 to the customer namespace, for example Z_BCALV_TREE_02 :

444_5.PNG

 

 

1.2 In the copied report, add new button to GUI-status 'MAIN100':

444_14.PNG

 

 

1.3 In the report line number 29, write CL_HRPAYNA_GUI_ALV_TREE instead CL_GUI_ALV_TREE :

444_8.PNG

 

 

1.4 In the report line number 125, insert next code to processing the new OK-code :

444_112.PNG

 

1.5 Activate objects:

444_15.PNG

 

 

 

2 PREPARE A FORM.

 

2.1 Launch XLSX Workbench, and in the popup window specify a form name TEST_ALV_TREE , and then press the button «Process»:

444_19.PNG

Empty form will be displayed:

444_19_1.png

2.2 Push button444_19_2.PNGto save the form.

 

 

2.3 Assign context CL_HRPAYNA_GUI_ALV_TREE to the form:

444_19_55.PNG

 

Herewith, you will be prompted to create a form's structure automatically (based on context):

00_6_3.PNG

We will create form structrure manually,

therefore we should press the button

 

2.4 Add a Tree to the Sheet:

444_201.PNG

 

2.5 Assign created Tree to the context:

444_23.PNG

 

2.6 Make markup in the Excel template (read more here):

444_24.PNG

 

2.7 Assign Tree to the marked area (cells range A1:B5) in the Excel template.

To do that, select cells range A1:B5 in the Excel template, and then, press button with "pencil" in the item "Area in the template" of the Properties tab:

444_28.PNG

2.8 Activate form by pressing button444_30.PNG.

 

 

 

3 EXECUTION.


Run your report Z_BCALV_TREE_02; ALV-tree will be displayed :

444_41.PNG


Press button444_43.PNGto export ALV-Tree to Excel form :

444_42.PNG

Employees Provident Fund Organisation, India (EPFO) has launched a Universal Account Number (UAN) to provide a number of facilities to its members through a single window. In SAP a new subtype 08 ( Universal Account Number ) has been created for Infotype 185 to store Universal Account number.

 

Basically we design payslip through HR form editor ( Tcode PE51 ) and we add tables, fields to HR Form classes (PE51_Checktab).

Once the table and fields are added, this will bring the value into the payslip but in this case UAN number is stored in 0185 as ICNUM and is classified by subtype 8 so we cannot directly put the fields in PE51_Checktab to fetch the UAN Number on Indian Payslip. We have to make a Z enhancement (Implicit Enhancement) to incorporate UAN number on Payslip.

 

The standard program HINCEDT0 will be called while generating indian payslips through Tcodes PC00_MXX_CALC and PC00_MXX_CEDT. If you want to this display this UAN number on Indian Payslip, we need to enhance this program.


Open HINCEDTO in SE38 and enhance include RPCEDDZ9 for data definitions and also enhance Include RPCEDSZ9 to write our own code ( in this case to fetch UAN number based on subtype).


29.jpg

26.jpg

27.jpg

 

Finally we will add additional structure TUAN and their respective fields ICNUM and SUBTY which we added by enhancing RPCEDDZ9, to form Class ( PE51_CHECKTAB) so they become available in HR Form Editor (PE51) for payslip designing.

 

25.jpg

23.bmp

 

Useful Links :

 

**************** - Payslip through PE51 – adding custom fields from infotypes

 

EPFO Launched Universal Account Number

 

*****************************************************************************************************************************************************************************************

Your feedback is highly appreciated, Thank you,

 

PRADEEP K

 

*****************************************************************************************************************************************************************************************

Release 7.40, SP08 of Application ABAP in SAP Netweaver is another bundled release that comes with a new kernel. While 7.40, SP02 was delivered with kernel release 740 and  7.40, SP05 with kernel release 741, 7.40, SP08 is based on kernel 742. When upgrading your 740 application server to 7.40, SP08 you have to use kernel 742 and by this you will get the following enhancements of the ABAP language in a fully downward compatible way.

 

Expressions

  • Predicative method call IF meth( ) and a new boolean function xsdbool for logical expressions
  • Iterative expressions FOR ... UNTIL|WHILE in constructor expressions, new constructor expression REDUCE especially for FOR
  • Addition BASE for start values of constructor expressions

 

 

Internal Tables

 

Database Access

  • Inline declarations, enhanced SQL expressions and new position of INTO clause in Open SQL
  • Parameter views, new built-in functions and view extensions in  ABAP CDS
  • Tabular changing parameters, class based exceptions and specialized BAdIs in AMDP

 

 

Furthermore, you can make interface methods optional now. As always, you find all ABAP News in the ABAP Keyword Documentation, that was updated in the SAP Help Portal. The updated version contains a new reference documentation for the ABAP Dictionary. The next bundled release with new ABAP features (I know some niceties already)  will be 7.40, SP12 presumably.

Actions

Filter Blog

By author:
By date:
By tag: