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

The case for other tools

$
0
0

Although this post is not directly about ABAP development, I think its relevant to most ABAPers. For people in the ABAP world, it’s unusual stray far from SAP's suite of Development tools. However having additional skills can add a lot of value, especially with SAP's pivot towards using more open standards and tools (think UI5, D3.js). The embedded developer tools within a browser are one such set of tools, as we will see below:

 

 

After a recent upgrade to SAP CRM, we had issues with the SAP CIC. Attempts at launching the CIC would result in a service not reached error. These are usually an easy fix because the inactive service is displayed on the error page. Once in a while though, someone gets an error which looks like this (fig. 1, click to enlarge), for which even the mighty Google doesn't have a solution.

 

HTTP://host:port/sap<!DOCTYPE html PUBLIC"-//W3C//DTD HTML 4.01Transitional//EN"><html><head><title>Logon Error Message</title>….


Fig 1.png

 

As many of us have experienced, these never-seen-before issues tend to get discovered during the critical stage of the project, which also happens to be a Friday evening of a long week. It being a critical phase, It was  important to analyze and fix the issue right away so I began the analysis immediately with the usual set of tools: ABAP Debugger, ICM, ICF, Logs etc. After spending considerable time  with these to and not making much progress, it seemed worthwhile to start the analysis afresh and from a different perspective. This time I decided to begin the analysis at the opposite end of the problem i.e. instead of starting the analysis at the server (SAP), starting the analysis at the client (browser) using the embedded developer tools.


For those who have made this far, the obvious question is how does one go about doing this? Firstly, To launch the developer tools, look under the browser tools menu or use the shortcut key Ctrl/Cmd + Shift + I (works under many browsers) . Once launched, they will automatically start collecting and displaying the relevant data. Under the developer tools, there are tabs focussing on a specific function such as network analysis, DOM inspection, Stylesheets, Debugger etc. The names of these tabs can be different on different browsers.The next step would be to launch the CIC (or the relevant webpage). Since the issue I was facing was an unreachable service, it made sense to start with the network analysis tool. It’s a good default tool to start with as it will give an idea to the order of calls and the services called. An example of its output can be seen below (fig 2):

 

Fig 2.png

 

Here you can see the HTTP requests made by the browser to the server and the corresponding responses. From the 'Path' column (first column), it’s easy to determine the resource requested. The 'Initiator' column also holds important information, usually a hyperlink to the source of the request (when available). Double clicking on the request will provide additional details on the request and its response plus other details.

 

 

For my issue, it was relatively easy to find the HTTP request that called the non reachable service (in red). Usually the CIC will keep sending polling requests so it may a good idea to stop recording the traffic once the page loads what we need. Just by looking at the error URL (fig. 1 & 2), it was evident that the browser was trying to reach a service that would not exist in SAP. The next step was to figure out how this requested URL was formed.  The bad URL could either be formed using a string delivered by SAP, or it could be the result of JavaScript(js) that did some unexpected manipulation in the browser. For the HTTP request we found above, the initiator was a js function, which was conveniently linked to in the Initiator column. This would serve as the starting point for our next step, by taking us to the Sources(debugger) tab to display the js triggering the HTTP request.

 

A little more about the Sources tab before we proceed further: all js loaded for a webpage can be seen under the Sources tab. The tab, along with displaying the js, can also be used to debug any js that executes in the browser. The debugger is very similar to the ABAP debugger with the ability to traverse the stack, lookup values of global and local variables, set breakpoints and watchpoints etc. Having found the code that made the HTTP request, it was time to work backwards to the source of the bad URL. Using the same approach used to debug ABAP code, we setup relevant breakpoints in the call stack plus watchpoints as desired to start debugging.

 

During debugging, I was able to find the function where the bad URL is actually formed (fig. 4, click to expand). The function is mergeManglingURL in the file crmuifServer.js, under the BSP crm_ui_start. The function performs its job perfectly well, serving us a URL that led nowhere because the parameter mangling has a long and incorrect string value. On a side note, the contents of the parameter ‘mangling’ seemed to be a well formed HTML page by itself, so I saved the contents of mangling to a separate file for examination later. At this stage, the cause was the incorrect value in the mangling parameter. I followed the trail down the rabbit hole further to determine what put the incorrect value in the parameter but reached a dead end.


Fig 4.png


At this stage, instead of debugging further, I wanted to examine the contents of mangling that I had saved separately. It had looked like valid HTML and I believed/hoped that it might hold clues to the root cause of this issue. After verifying the consistency of the HTML, I was able to open it up in a browser. The HTML was successfully rendered as shown below, finally displaying the service name that was actually inactive(fig. 5):

 

Fig 5.png

 

Upon activating the service uif_callback, I had the CIC up and running immediately. This is where I stopped the investigation which may seem a little anticlimactic, but the job was done and Friday evening was close to turning into Saturday morning .

 

A little more analysis on Monday revealed we had missed steps from note 1115493, which is in addition to note 1295006. (LINK).

 

To conclude, I hope I convinced you to play around with the developer tools inside your browser if you haven't already and also demonstrated an unconventional approach to solving the issue of an inactive service, where the service name in the error page looks like HTML markup.


How to implement and use ABAP Channels - Video Tutorials

$
0
0

The ABAP Channels infrastructure offers best support for native event-driven interactive and collaborative scenarios in ABAP and is generally available with ABAP 7.40 Support Package 5 (SP05). The ABAP 7.40 Support Package 8 (SP08) contains various enhancements including API refactoring to support WebSocket subprotocols.and message exchange with SAP Push Channel Protocol (PCP).

 

Take your time to watch these YouTube video tutorials to learn how to implement and use ABAP Channels.

 

How to implement ABAP Push Channel (APC)


ABAP Push Channel enables bi-directional communication via WebSockets in ABAP. This video gives you step-by-step introduction on how to implement and use ABAP Push Channel.

 

 

 

How to implement ABAP Messaging Channel (AMC)


ABAP Messaging Channel enables event-driven communication based on publish/subscribe mechanism for message exchange between different ABAP sessions which can reside on different ABAP Servers. Any ABAP session can subscribe to channels and any ABAP session can publish messages to channels. This video gives you step-by-step introduction on how to implement and use ABAP Messaging Channel.

 

 

How to implement collaboration using ABAP Push Channel (APC) and ABAP Messaging Channel (AMC)

 

The collaboration scenario provides the possibility on the basis of publish/subscribe mechanism of ABAP Messaging Channels and WebSocket implementation of ABAP Push Channel to exchange messages between different WebSocket Clients.This video gives you step-by-step introduction on how to implement collaboration scenario using ABAP Messaging Channel and ABAP Push Channel.

 

5 major differences between an R/3 project and S/4 HANA project

$
0
0

I have preferred to post this blog here in ABAP space, because I believe I can easily find here, SAP dinosaurs like me

 

 

1. Google is not used in an R/3 project:

Because Google was not established yet .  We need to wait 6 years that Larry Page and Sergey Brin to establish Google in 4th of September in 1998. We often use our notes on papers, pals, debug  or self trials to explore any information.

 

 

2. 3,5” floppy disks or commonly diskettes are used in R/3 projects:

There were no SD cards, cloud spaces or memory sticks. We have only 720 kb or1,44 MB of floopies to store any piece of data. To be honest we did not have any fancy data at all

 

 

3. Lotus 1-2-3 or Quattro Pro is used in an R/3 Project:

Excel was not so popular before year 1995, so Lotus 1-2-3 and quattro pro were the key spreadsheet solutions those days.

 

 

4. Remote connection or job is not acceptable in R/3 project:

Since there were no public remote connection facility in early 1990’s. So we need to work long long days in offices during go-live preparation and cut-over phases.

 

 

5. Help.sap.com is not used in an R/3 projects:

Because it was not established yet. We have Help documentation CD’s provided by SAP software, which were also come with CDs. This documentation should be installed on network to search for help J

 

There are many differences, but these are my favorites, please share yours:)

 

Cheers,

 

SarhanPolatates

Selecting One Row From a Database Table

$
0
0

This one might be trivial, but interestingly there are quiet some discussions about it. Therefore, let's wrap it up.

 

Selecting a Fully Specified Row

 

For selecting a fully specified row with Open SQL SELECT, you specify the full table key in equals conditions combined by AND.

 

The natural result set of an SQL statement is tabular. And so, the natural way of writing a SELECT statement also in Open SQL is:

 

SELECT *
       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS' AND
             msgnr = '050'
       INTO TABLE @DATA(result).

 

cl_demo_output=>display( result ).

 

This is independent from the number of rows expected. Of course, by specifying the full key, the result set contains only one row. Assigning the result set to internal table result of course gives an internal table with one line.

 

So far so good. In languages dealing with tables only, as.e.g. SAP HANA's SQLScript, this is also the only way and you always receive a result table with one line. But in ABAP, we additionally have structures. Structures are even older than internal tables. So you can write the result of a single row selection also into a structure:

 

SELECT *
       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS' AND
             msgnr = '050'
       INTO  @DATA(result).
ENDSELECT.

 

cl_demo_output=>display( result ).

 

Without specifying TABLE, result is a structure and a SELECT loop is opened that must be closed with ENDSELECT. That is an ABAP speciality of course. Now you might ask why should I open a loop, if I know that I want to read only one row into a structure. And that's exactly what the ABAP speciality SELECT SINGLE is made for. Nothing more and nothing less.

 

SELECT SINGLE *
       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS' AND
             msgnr = '050'
       INTO  @DATA(result).

 

cl_demo_output=>display( result ).

 

Same result as above. The native SQL generated from that syntax and passed to the database is also the same. There is a very small performance improvement with SELECT SINGLE, because no loop has to be opened, but normally that can be neclected. SELECT SINGLE has shorter syntax and  documents the semantics: You know, that you want to read a fully specified row into a structure and you use SELECT SINGLE for that purpose. The syntax documents the semantics of your statement in the program and the extended program check warns you, if you do not specify the full key.

 

Selecting a Partly Specified Row

 

If you do not specify the full key, the result set delivered by the database nornally contains multiple rows:

 

SELECT *
       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS'
       INTO TABLE @DATA(result).


cl_demo_output=>display( result ).

 

The internal table result contains mulitple lines now. How can I get one line instead? You know the answer:

 

SELECT *
       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS'
       INTO TABLE @DATA(result)
       UP TO 1 ROWS.

 

cl_demo_output=>display( result ).

 

With UP TO 1 ROWS you tell the database to pass only one row in its tabular result set and the internal table contains only one line. But be aware, that the returned row is not defined. It can be any of those specified by the partial key. In order to get a defined row in respect to the sort order, you can add an ORDER BY clause.

 

SELECT *
       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS'
       ORDER BY PRIMARY KEY
       INTO TABLE @DATA(result)
       UP TO 1 ROWS.

 

cl_demo_output=>display( result ).

 

Of course, you can also select into a structure:

 

SELECT *
       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS'
       ORDER BY PRIMARY KEY
       INTO @DATA(result)
       UP TO 1 ROWS.
ENDSELECT.

 

cl_demo_output=>display( result ).

 

Since UP TO always creates a tabular result set, you must use ENDSELECT.

 

What about SELECT SINGLE? Yeah, you can use that too:

 

SELECT SINGLE *
       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS'
       INTO @DATA(result).

 

cl_demo_output=>display( result ).

 

Again a single row in a structure. But this can be seen as a misuse of  SELECT SINGLE. Especially, you cannot use ORDER BY in connection with SINGLE. Simply, because SELECT SINGLE is not made for this. Therefore, the returned row is always undefined. If you are interested in the contents of the single row, SELECT SINGLE should not be used with partial key specifications.

 

Checking the Existence of a Row

 

A widely discussed question is, how to check the existence of a row or rows in a database table. Especially, if you specify a partial key or even non key fields only, you want to restrict the number of lines transferred from the database to the application server as much as possible. Before 7.40, SP05, the minimal numbers of rows to be selected was 1. You can use either SELECT SINGLE or UP TO 1 ROWS in order to restrict the number of rows to that minimum. Since you only check sy-subrc and you are not interested in the contents of the returned row, you don't have to care about ORDER BY. So both forms can be used:

 

SELECT SINGLE sprsl
       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS'
       INTO @DATA(result).
IF sy-subrc = 0.
  ...
ENDIF.

 

SELECT sprsl      

       FROM t100
       WHERE sprsl = @sy-langu AND
             arbgb = 'SABAPDEMOS'
       INTO @DATA(result)
       UP TO 1 ROWS.
ENDSELECT.
IF sy-subrc = 0.
  ...
ENDIF.

 

The syntax of SELECT SINGLE is shorter. And performance? On the database both variants take the same time because the same native code is executed there. All in all SELECT SINGLE is even a little bit faster than UP TO 1 ROWS (no loop opened), but that is negligible. Therefore, no problem in "misusing" SELECT SINGLE for merely checking the existence of rows. In that case, you know what you do and you can hide the warning of the extended program check with pragma ##WARN_OK.

 

With 7.40, SP05, you can use the following syntax:

 

SELECT SINGLE @abap_true

       FROM t100

       WHERE sprsl = @sy-langu AND

             arbgb = 'SABAPDEMOSi'

       INTO @DATA(result).

IF sy-subrc = 0.

...

ENDIF.

 

The constant abap_true is used as a minimal SQL expression. Now, not even a single row must be transported from the database to the application server. You can also check IF result = abap_true.

Comments about comments

$
0
0

When I started to work as a junior developer ten months ago, my first tasks were mostly related to maintenance. As far as I know this is the usual way for newcomers to get familiar with software engineering processes in real customer projects. The most important thing I learnt during the maintenance tasks was that I learnt to value code readability. Code with high readability made my job easier and also helped me to focus on completing the tasks. I became quite passionate about code readability and I even did my bachelor’s thesis about refactoring.

 

I have studied computer science for three years. Every programming course I have attended highlighted the importance of properly commenting the code. More was better. However if we had a visiting lecturer from a software engineering company, he or she recommended to write our programs in such way that the comments would not be needed. My opinions are closer to the latter.

 

In my opinion there are few (too common) cases where ABAP comments decrease the code readability a lot even though the aim is exactly the opposite. I will describe three of those in more detail.

 

1. Rescuing unreadable code with comments

Comments are great tool for expressing complex logic in a more readable form. It is also useful for explaining why something is done. However the purpose is not to write the code in unreadable form and then comment it to get away with terrible code. I have experienced this far too often when maintaining ABAP programs. Of course commenting in this is case is far more better than leaving the unreadable code without explanation. Still the code should be written in such a way that we need as little comments as possible. To achieve this developers should use more descriptive variable and method names.

 

2. Commenting self explanatory code

Sometimes developers underestimate their code expressiveness. ABAP is relatively expressive language (in my opinion) and every simple statement does not need to be commented. For example the following is consider a good practice in some source:

 

“Separate the text value at comma into two different variables

SPLIT wa-address_field AT‘,’ INTO lv_address lv_postal_code.

 

No comments needed. The line explains it’s behavior as well as (or even better than) the comment. A little bit modified but still not shining:

 

“The address field is separated into two variables for distinct processing

SPLIT wa-address_field AT‘,’ INTO lv_address lv_postal_code.

 

I would still leave the comment out. Why would we separate the field if we did not want to process them separately in some point? Let the code explain itself.

 

3. Comments as change log

The last issue with commenting is its use as a change log. At first it seems nice way to tell the future readers what has changed and when. But after few modifications it makes the code unbearable to read. There starts to appear modifications inside modifications and even the smallest changes could include many, many rows of comments into the source code. Consider adding a new field as a select option for a report. Comment appears around the select-option declaration and within every query where it is used. The comments within queries are particularly annoying. To demonstrate this:

 

SELECT *

     FROM dbtab

     WHERE field EQ space

     "Start of modification by username for changeid on dd.mm.yyyy

     AND modified_field IN so_modified_field

     "End of modification by username for changeid on dd.mm.yyyy

     "Start of modification by otheruser for changeid2 on dd.mm.yyyy

     AND new_field IN so_new_field.

     "End of modification by otheruser for changeid2 on dd.mm.yyyy

 

 

They are not actually that rare. It is not elegant way at all when it comes to code readability. The problem with this issue is that there might not be an elegant way to document changes so that they are easily visible but do not decrease the readability of source code. Maybe I am after for some built in tool to easily browse the modification history. Of course there are functional and technical design documents but they are too far away when I need them. How do you document the change log inside SAP system?

 

I am eager to hear about other community members’ opinions about the best practices of commenting. Feel free to comment my comments about ABAP comments... This is my first blog post so give me feedback!

Program to change transport request description after release

$
0
0

Sometimes we release the request from DEV system and then quality team come-up saying that there is need of change of the TR description.

Below program will save lots of your efforts to create transport of copy or copy all objects to new transport. Follow it and you will be sorted 

 

Program RDDIT076 is used to change the description of TR which is already released.

 

In development, system will give you two options after execution of program RDDIT076: (Provided you have SE38 authorization)

 

1. Enter your TR number. It will show all child and main request list.

 

2. Double click on each option.

 

3. Click on change button.

 

4. Change description.

 

5. SAVE

 

Best Regards,

Satish Karemore

Two tricks for ALV trees: expanding the full tree and coloring specific tree cells.

$
0
0

Recently, I received a request to create a report structured in an ALV Tree. I'm a fairly novice ABAP developer and this was the first time I had to create something of this nature. Along the way, I bumped into a few pain points for which information is either scarce or non-existent. Now, I feel compelled to share what I learned in the process - maybe this will help someone else in the future.

 

First off, I created my program using ABAP's class cl_gui_alv_tree. There's a series of great sample programs that will help you get started in no time, they cover pretty much everything you'll ever need with this class. All of them seem to start with bcalv_tree_## (where ## is replaced by numbers or words, e.g. bcalv_tree_01) so you can always search for that term and see what comes up. A somewhat comprehensive list can be found here: Abap ALV Tree - A Complete Example Code. The basics are covered by the "01" through "06" programs of that family and they are thoroughly documented, so pay attention to the comments.

 

When you're creating a tree, it's essential to have some kind of structure sorted the way you will be presenting the ALV. Personally, I think this is not trivial as it will either make your job a lot easier or a lot harder. My choice was to use a flat table with all the data I needed there, plus a explicit column to define it's hierarchy level and the row's node ID (the way I did it, each row defined a node). You can also use deep structures to store and handle your data, I didn't go this way so I could minimize the number of loops in my code - this came at the expense of larger tables, but it also allowed me to create simpler methods.

 

The code samples provided will show some hard-coding but that's just for clarity, that's a practice you should avoid.

 

On to the issues I faced: expanding an ALV tree and coloring specific ALV tree cells.

 

Problem #1: Automatically expanding the entire ALV tree.

 

Sadly, there's no easy out-of-the-box way to do this (or at least I couldn't find any) so I had to research this quite a bit. The cl_gui_tree has two methods related to this task (EXPAND_NODE and EXPAND_NODES) but neither expands the whole tree, so how do we solve this? First, you need the node key assigned by the ADD_NODE method to each of your nodes (I added a column to my source table where I kept that ID, so it made things easier); with that, I proceeded to create this method:

 

  METHOD me_expand_tree.

 

    DATA: w_node_key TYPE lvc_nkey,

       it_keys    TYPE lvc_t_nkey.

 

    FIELD-SYMBOLS<fs_data> TYPE y_data.

 

    LOOP ATit_data

      ASSIGNING <fs_data>.

 

      CLEAR w_node_key.

*"Check if the current node has children

      CALL METHODob_alv_tree->get_first_child

        EXPORTING

          i_node_key       = <fs_data>-node_key

        IMPORTING

          e_child_node_key = w_node_key.

*"If there are, append parent's key to table

      IF w_node_key IS NOT INITIAL.

 

        APPEND <fs_data>-node_key TO it_keys.

 

      ENDIF.

 

    ENDLOOP.

 

  UNASSIGN <fs_data>.

*"Expand ALV tree

    CALL METHODio_alv_tree->expand_nodes( it_node_key = it_keys ).

 

  ENDMETHOD.

 

To save some space, I didn't add the exception handling portion of the methods called here to but you should, otherwise your program will be vulnerable to runtime errors.

 

What this method does is go through the ALV data and check each node to verify if it has children. Check that by using the GET_FIRST_CHILD method. Caveat: use a variable to store the returned child node key and then check if that variable is empty (filled = there are children, empty = there aren't), sy-subrc won't help here since it will show 1 whether the node has children or not.

 

For the ones that do have at least one child, their node key should be added to the it_keys table and then sent to the EXPAND_NODES method. It's extremely important to guarantee that a particular node has leafs, if it doesn't and you pass it to the class' method to be expanded, your program will trigger a short dump when the tree is sent to the front end:

Short_dump.PNG

This was a particularly cumbersome error as it wasn't triggered directly by my code, everything went through "fine"... I suspected an issue with the nodes with no children and researched in that direction, fortunately, another forum user also encountered the same problem and documented it here: My favourite cryptic ST22 dumps around CL_GUI_ALV_TREE.

 

The method I provided can be adjusted to expand only a specific level (or levels) of your tree. Since you define the hierarchy yourself, then you will know which nodes you want to get expanded.

 

There's one "bug" I haven't quite fixed yet: when you expand the tree, your container will navigate to the end of the tree, so your user will need to scroll back to the top manually. If I get a fix, I will update this post.

 

Problem #2: Coloring specific ALV tree cells (single cells, not entire rows).

 

Now, this one really didn't have an answer, I found tons of posts asking the same question but every answer was people either talking about the ALV grid or flat out saying it couldn't be done. Luckily, another dev dropped a hint right here Coloring of ROWS in ALV tree which pointed to a sample program from the family I mentioned above, it's the bcalv_tree_itemlayout.

 

That program allows the user to manually colorize a particular cell, but I needed that to happen automatically depending on the values of the cell in question. So how did I do it? With this method:

 

  METHOD me_colorize.

 

    DATA: it_color TYPE lvc_t_laci

      e_color  TYPElvc_s_laci.

 

    FIELD-SYMBOLS<fs_data> TYPE y_data.

 

    LOOP ATit_data

      ASSIGNING <fs_data>.


*"Condition 1 to be checked for <fs_data>

      IF condition_1.

*"Set cell color as GREEN

        MOVE: field_name  TO e_color-fieldname,

                    6                          TO e_color-style,

        'X'        TO e_color-u_style.


*"Condition 2 to be checked for <fs_data>

      ELSEIF condition_2.

*"Set cell color as ORANGE

        MOVE: field_nameTO e_color-fieldname,

                   10                       TO e_color-style,

        'X'         TO e_color-u_style.


*"All other cases

      ELSE.

*"Set cell color as RED

        MOVE: field_nameTO e_color-fieldname,

                    5                        TO e_color-style,

        'X'         TO e_color-u_style.

 

      ENDIF.

 

      APPEND e_color TO it_color.

*"Modify node

      CALL METHODob_alv_tree->change_node

        EXPORTING

          i_node_key     = <fs_data>-node_key

          i_outtab_line  = <fs_data>

          it_item_layout = it_color.

 

      FREE: ce_color,

       it_color.

 

    ENDLOOP.

 

  ENDMETHOD.

 

Again, remember to add the exception handling portion for the methods you call.

 

The magic here happens thanks to the CHANGE_NODE method. It needs the node key, the line where your data is and the color parameters (which include the specific structure component to be colored, defined above by field_name). Once you provide all that information, a single cell will be granted the color you chose.

 

I think it's possible to add the color when you initially create the node with the ADD_NODE method, since it also has a parameter for it_item_layout, I didn't do it that way because of the particularities of my requirement.

 

Though there's no info about possible color codes you can use (or at least none that I could find - all I got was for the ALV grid and the ones for the tree are different) feel free to experiment, that's how I landed on the colors I needed.

 

There you go, those two things are pretty simple once you know how to get them done, but the getting there was quite difficult and required a bunch of research time, which I hope this post saves you .

Dunning Notice in SAP Best Practice from ABAPer prospective

$
0
0

Introduction:

In conventional SAP, the form provided for the Dunning Letter is a sap script, whereas in SAPBest Practice, SAP has provided a smartform for Dunning Letter.

In this edition, I will share my findings in one of my SAP Best Practice imply project.

This blog is related to Dunning Letter config & coding  from ABAPer prospective only.You may find some other ways also to do the same.

 

We have to follow below mentioned steps:

  • Copy Smartform
  • Config BTE
  • Attach dunning form to Dunning procedures
  • Coding for email
  • Final Output

 

 

 

1.   Copy Smartform

  • Smartform for Dunning Letter - YBUS_FIMA.
  • We just need to copy it into our Z* smartform and make the changes.
  • This smartform has almost everything, you only need to add company logo & address

F Only catch here is the length of smartform name, it should not exceed 16.

1.png

  • SAP Best Practice also provided the smart style YBUS_SFSTYLE, we can copy it and use it OR we can make the changes in it as well

 

2.png

 

 

2. Config BTE

  • Transaction code - FIBF - Maintenance transaction BTE
  • Click on Settings->P/S Modules->...of an SAP Application (check figure)

 

3.png

  • Hit ENTER 2 times
  • Check for Event 00001720 FI-FI (check figure)
  • Change the FM to FI_PRINT_DUNNING_NOTICE_SMARTF

 

4.png

  • Save it

 

 

3. Attach dunning form to dunning procedures

  • Go to tcode FBMP

 

5.png

  • Double click on Procedure 0001
  • Click on Dunning texts(check figure)

 

6.png

  • Enter company code 1000

7.png

  • Change the form name to Z* dunning smartform for all the four levels OR if you have different dunning forms for each level, maintain those forms here for each procedure

8.png

  • Save it

 

 

 

4. Coding for email

  • There is standard BTE 00001040 provided by SAP which is called when dunning is running (F150). SAP has also provided sample function module SAMPLE_PROCESS_00001040 to indicate how to use this BTE. The FM imports I_KNA1 structure and return structure C_FINAA.
  • Copy this FM SAMPLE_PROCESS_00001040 to Z*FM

 

9.png

  • Here we have passed C_FINAA-NACHA = ‘I’, C_FINAA-INTAD = customer email id(check the coding)
  • And also pass email Subject in C_ITCPO-TDCOVTITLE = ‘Reminder: Dunning Letter’
  • For email body we have to create a text ID in SO10 as

10.png

11.png

  • We need to attach this Z*FM to BTE 00001040
  • Go to transaction FIBF. Settings-> Process Modules-> of SAP Application
  • Add new entry with Process 00001040 FI-FI and FM as Z*FM created above

 

12.png

 

 

5. Final Output

  • Transaction code – F150, click Dunn.history

 

13.png

  • Next screen enter the values

14.png

  • On next screen, select one entry and click on Display dunning notice icon

 

15.png

  • Print preview

 

17.png

 

  • On print preview screen hit … F3…will get a popup as

 

18.png

  • Press Yes, it will trigger an email
  • You can check in tcode SOST
  • The above popup email id will appear automatically if it is maintained in the customer master

19.png

 

Thanks,

Rahul


Web Dynpro: Creating a blog application/ Common Chat group in ABAP

$
0
0

When we see all the groups like SDN/Facebook/Some common chat groups then probably it might come in your mind "Can we do it in our organization for knowledge sharing purpose ? ". May be this is very common question in your mind or may be very few people understands the importance or whatever, but in an organization/project where some complex developments/scenarios occur repeatedly it may be helpful to store the previous research in small and organization specific groups.

Here I am sharing one application which consists of user profile (containing his/her skill level) and a group where user can post it's concern. The post will be sent to all in the group with relevant skill. The Comment thread can also be used in future by others or the user itself. Let me know if you find it helpful and willing to implement. I will share the code on request.

 

First creating Skill Set

User_profile.jpg

Once user selects the relevant experience he can save it with save button as shown above. So after updating the skill level user can have a view of skill set something like:

User_skill.JPG

Now lets come to the Common chat group application

Contents: A group or a common page must have below elements :

1) User identification : e.g. Profile picture with edit/change option.

2) Search Field:  Which can return results from history

3) Search result List: Based on the search from 2.

4) Option to post new question with category: User can also attach some document.

5) Additional options: To find the comment threads where the user itself is involved or creating own repository. for now I am using it for comment thread only.

Considering all above basic requirements I designed a page like below:

The numbers have been written in red maps to the elements mentioned above.

Common Group pic1.jpg

Using different Options:

1) Change Picture: User can simply click on edit/upload photo and browse a pic from it's system and upload.
edit_pic.jpg

Once saved this will save the profile pic and will be displayed in comment threads and profile. e.g.

Common Group pic2.jpg

2) Search Field: This is supposed to retrieve a history of previous discussions e.g. here user enters a text 'HOW' and it returns the text containing 'HOW'.

So when user clicks on one of the links say, the third one"How to use Shared Memory of class"

Common Group search.jpg

Common Group comment thread.jpg

User can add new comments and attachments by the option available above "Previous Posts".

Option to post new question with category:

Here user can select category of the concern, a suitable title and a detail text like below.

Common Group post new.jpg

after submitting it will generate an email to the concerned recipients.

e.g.

Common Group mail.jpg

The link provided in the email will open a new window with the comment thread.

Common Group mail link.jpg

Additional options:

This option will provide the list of comment thread where user has posted some comment, triggered new thread, or can look at others comment. Once the list is displayed user can click on the link to get the detail.

Common Group Additional option.jpg

My biggest mistakes as an ABAP Developer

$
0
0

This is not a blog about code errors and/or best practices.

 

It's always great to talk about cool things we've made throughout our careers. But our mistakes can really push us to rethink our values, conduct and how we interact with people. They can make us better.

 

I've made tons of mistakes as an software developer. Here I'll talk about four of them, the ones that really had an impact on how I act not only in my job, but in my whole life.

 

 

Believe that programming is the only thing that matter

 

It's easy to fall into the mistake of thinking that programming is the one and only thing that matter in the IT world. Specially when you're an unexperienced programmer, without much vision on how this industry works. Basically I thought that technical people were the only ones that actually did something, and that everybody else just spent time chasing their own tails instead of doing what had to be done.

 

However, the mechanics of this world goes way beyond programming. There's a huge amount of people involved in the process of making any programming happen and every single one of then are equality important.

 

At the time I realized this, I became a much better developer.

 

 

Not hearing a senior developer advice "just because"

 

Let's say you spent countless hours debugging an standard process, turning someone else's code upside-down in the search of a solution for an error. Google and SCN couldn't help you. You truly believe that you read everything there was to be read about that issue and started thinking there wouldn't be any solution.

 

But then an experienced developer shows up by your side. You tell him your sad story already "knowing" he won't be able to help. Your mind thinks this is a problem that can be solved by few, if any - after all, you've spent too many time searching for an answer that still could not be found.

 

He thinks a little and gives you a really simple answer. The one that "just can't be right". The one that seems outrageous to your mind. Your pride ignores the advice and you get back to Google for a few more hours. It just can't be that simple.

 

... however, something tells you that his theory must be tested. You go and change that small IF condition in your BADI. Everything works.

 

Turns out the solutions was not simple, it was something created based on his experience. Not being able to see that is a big mistake.

 

 

Underestimate someone because of their age

 

One time I was assigned to a project where I had to build the structure of a complex program. The process was full of small rules, various paths and some crazy features, all needed to automate a big user requirement. I've used ABAP Objects to solve this, drawing UML diagrams and creating mockups during the BBP, which would be used to create the code in a future project phase.

 

I didn't know which developer was going to be assigned to implement that project, but I asked for someone that were opened to work with OO, Trello and that kind of stuff. But our client liked one of our developers, a guy who's after his 50's, and asked for him.

 

When my boss told me that guy was going to be the other ABAP developer, all I could think was "this is definitely not going to work".

 

The guy really didn't understand basic OO concepts. Inheritance, polymorphism, visibility, and all those things. However, I've seen very few people showing so much passion about learning. During the project I took my time to explain every single concept to a point where he was able to contribute in solving a complex part of my design. He was able to use abstraction to reuse something in a way I wasn't expecting. The solution he though got implemented and was way better than what I initially created. I remember getting really happy when that happened.

 

I was totally wrong underestimating this guy based on his age. I like to use the term "ABAPossaur" to describe ABAPers who are programming in 2015 just like they did in 1999. But being an ABAPossaur has nothing to do with age. It's about how passioned you are about what you're doing. I've been able to work with two guys that totally changed the way I look to older developers (this story is about one of those devs), and I can't thank them enough for that.

 

Of course there are some 50's ABAPossaurs out there, but I bet there's way more ABAPossaurs in their 20's or 30's.

 

 

 

Blaming someone else for my mistakes

 

Believe me when I say that I hate people that blame others for their mistake. Really. I've always been like that since I was a child, and I've always assumed I was wrong every time I screwed up something. But there was one time, when I was 2 years into the ABAP world (now I'm a 10 years old ABAPer), that I blamed another dev for an error I'd created.

 

It was just an small problem reported by our client, in a program I made together with another dev (an intern who had just started with ABAP). It was clearly an error on my code, but I told the project manager that it happened because of the intern.

 

The reason that lead me to do that was the perception I had that my manager was really angry with me. Previously I made a huge program with over 6k lines of code (the FS had over 40 pages) that was constantly showing problems in QAS. Later, at the feedback meeting by the end of the project my manager told me he knew he couldn't ask for a 2 years old ABAP developer to make everything right in such a huge development, but during the project I really thought that amount of errors showed how unprepared I was to work with software development.

 

That's why when I saw that small READ TABLE problem, I didn't give much thought and reluctantly said that the error was caused by the intern. At the moment I finished those words I was already ashamed of myself. There's was nothing to do, it couldn't be un-said. It was done.

 

However the intern, a man I respect, called me to the coffee room and confronted my words. He said that I was completely wrong by throwing him in that situation, as the error was clearly mine. I agreed in silence, returned to my manager, apologized and told him that the error was caused by my code. It was the right thing to do.

 

Everything I just said happened over something like 10 minutes, between I blamed the intern, confronted him and apologized to my manager. But it marked me for life.

 

How many times I've seen people on the SAP world blaming others for their mistakes? Plenty. And every time I see this situation I always remember this story and how bad I felt about myself when I said those words. How someone can tell so many lies without felling any guilt? It's extremely bizarre.

 

 

 

To err is ABAPer

 

Everybody makes mistakes, including ABAPers. Just try to learn something from them.

 

If you feel comfortable about it, I ask you to share some of you biggest mistakes in the comments section. You can learn something from showing them to people,as I certainly learned even more just by writing this.

 

Thanks for reading. See you next time! (and it's all your fault! )

 


*This is a cross-post from my personal brazilian ABAP website called ABAPZombie. We want everybody to get rid of zombie-mode!

Combining Object Services and Change Documents

$
0
0

„How can I combine Object Services (OS, aka persistent classes) with Change Documents (CDO)?“

 

This question has been asked a number of times in various places before, and as of yet, I’ve not come across an answer that might serve as an implementation guideline. Since we will need to combine the two frameworks for a development project, I’ve decided to do a quick feasibility analysis and share some details and pitfalls with the community. For this article you’ll need a basic understanding of both the object services and change documents and a fairly solid understanding of basic object orientation principles.

 

The first important point is to remember that the object services and change documents work on different levels of abstraction. The persistent classes generated by object services operate on the technical representation of the entities in question – for example, the invoice header or a single position of an invoice. The general rule of thumb is “one table, one class”. For change documents, that’s different. Usually, you will find change document objects for logical objects rather than the technical representations. One change document object will ususally comprise multiple table definitions that are needed to store the logical object. For example, you might find a change document object for an invoice that records both changes to the invoice header and the corresponding positions. In this respect, change documents resemble lock objects. There’s already a document by Katan Patel available that covers some of the basic aspects of this approach.

 

In this article, I use a basic model of some arbitrary header data with some arbitrary items. The setup contains two tables with associated persistent classes and looks approximately like this:

Basics.png

Note that I have left out the agent, base agent and standard class and interface methods for a better overview.

 

The object services provide a means to place the entire key handling in the hands of the generated persistency class. You simply have to use the data type OS_GUID for a primary key field. While this might be handy in some cases, do not use this feature if you want to record change documents based on the data tables. OS_GUID is a RAW type, and this causes all kinds of trouble within the change document generator and the reports used to display the change documents. In this example, I’ve used a composite business key comprising the company code and an arbitrary key – probably a GUID, but that’s irrelevant in this case.

 

When the tables are present and active, it is possible to create the change document object and generate the associated objects. There’s nothing special to observe in this case: the header is passed as a singular entry while the items are passed as a table:

CDO-Def.png

The function module to write the change documents can then be generated using the default parameters. In this case, I’ve used the default name ZOSCDO_WRITE_DOCUMENT.

 

Now before we can turn to the actual change document magic, there’s a slight problem to resolve. Change documents are used to record creation, changes and deletion of business objects. Creation and changes are easy, but there’s a problem concerning deleted objects. The generated agent/base agent combination provides an event named IF_OS_FACTORY~DELETED that is raised whenever an object is deleted. Unfortunately, the event is raised after the object instance is invalidated, and therefore any further attempt to get the business key from the object yields an exception. The interface IF_OS_FACTORY also provides an event named TO_BE_DELETED that appears to be just the solution for this problem, but at least in my scenario, that event is never raised by the generated agents. I was only able to find some references to this event in older agent implementations – it looks like this event was removed from the default implementation for some reason. Fortunately it is rather easy to reenable it – I just had to redefine the method EXT_PM_DELETED_PERSISTENT in each of the agents and add the following implementation:

 

METHOD ext_pm_deleted_persistent.  DATA: ls_backup_object_info  TYPE typ_object_info,        l_backup_object_index  TYPE typ_index,        lr_backup_object_iref  TYPE typ_object_iref.  CALL METHOD super->ext_pm_deleted_persistent.  ls_backup_object_info  = current_object_info.  l_backup_object_index  = current_object_index.  lr_backup_object_iref  = current_object_iref.  RAISE EVENT if_os_factory~to_be_deleted    EXPORTING      object = current_object_iref.  current_object_info  = ls_backup_object_info.  current_object_index = l_backup_object_index.  current_object_iref  = lr_backup_object_iref.

ENDMETHOD.

 

It is important to save and restore some of the attributes as shown above – otherwise the read access required by the event handler later on would change these variables and again lead to a short dump.

 

With these preparations in place, it is possible to tackle the actual change document generation. In this example, I’ve used a separate class called ZCL_OSCDO_CHANGE_DOC_WRITER to wrap the event handling and data processing. Inside this class, I use the following data types to keep track of the changes to the data:

    TYPES:      BEGIN OF t_item_data,             item_number TYPE zoscdo_item_number,             change      TYPE cdchngind,             old_data    TYPE zoscdo_item,             new_data    TYPE zoscdo_item,           END OF t_item_data .    TYPES:      tt_item_data TYPE SORTED TABLE OF t_item_data                        WITH UNIQUE KEY item_number .    TYPES:      BEGIN OF t_header_data,             company_code TYPE bukrs,             header_id    TYPE zoscdo_header_id,             change       TYPE cdchngind,             old_data     TYPE zoscdo_header,             new_data     TYPE zoscdo_header,             items        TYPE tt_item_data,           END OF t_header_data .    TYPES:      tt_header_data TYPE SORTED TABLE OF t_header_data                          WITH UNIQUE KEY company_code header_id .

 

This is basically an in-memory representation of the header with its associated items. The class has a global attribute GT_CHANGE_DATA TYPE TT_HEADER_DATA that is used to keep track of the changes. This attribute is populated using the following two methods:

 

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_OSCDO_CHANGE_DOC_WRITER->RECORD_HEADER_STATE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IR_HEADER                      TYPE REF TO ZCL_OSCDO_HEADER
* | [--->] I_CHANGE                       TYPE        CDCHNGIND(optional)
* | [--->] I_OLD_STATE                    TYPE        ABAP_BOOL (default =ABAP_FALSE)
* | [--->] I_RECORD_CONTENTS              TYPE        ABAP_BOOL (default =ABAP_TRUE)
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD record_header_state.    FIELD-SYMBOLS: <ls_header> TYPE t_header_data.    DATA: ls_header TYPE t_header_data.

*   try to locate the corresponding record in the global table    READ TABLE gt_change_data ASSIGNING <ls_header>      WITH TABLE KEY company_code = ir_header->get_company_code( )                     header_id    = ir_header->get_header_id( ).    IF sy-subrc <> 0.
*     no record found - create a new one      ls_header-company_code = ir_header->get_company_code( ).      ls_header-header_id    = ir_header->get_header_id( ).      INSERT ls_header INTO TABLE gt_change_data ASSIGNING <ls_header>.    ENDIF.

*   When recording the 'old' state, we don't want to set the change indicator yet.
*   Therefore only set the change indicator if it is supplied.    IF i_change IS SUPPLIED.      <ls_header>-change = i_change.    ENDIF.

*   If required, record the current state, either as 'new' or as 'old'.    IF i_record_contents = abap_true.      IF i_old_state = abap_true.        ir_header->record_cdo_data( CHANGING cs_data = <ls_header>-old_data ).      ELSE.        ir_header->record_cdo_data( CHANGING cs_data = <ls_header>-new_data ).      ENDIF.    ENDIF.  ENDMETHOD.                    "record_header_state

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_OSCDO_CHANGE_DOC_WRITER->RECORD_ITEM_STATE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IR_ITEM                        TYPE REF TO ZCL_OSCDO_ITEM
* | [--->] I_CHANGE                       TYPE        CDCHNGIND(optional)
* | [--->] I_OLD_STATE                    TYPE        ABAP_BOOL (default =ABAP_FALSE)
* | [--->] I_RECORD_CONTENTS              TYPE        ABAP_BOOL (default =ABAP_TRUE)
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD record_item_state.    FIELD-SYMBOLS: <ls_header> TYPE t_header_data,                   <ls_item>   TYPE t_item_data.    DATA: ls_header TYPE t_header_data,          ls_item   TYPE t_item_data.

*   try to locate the corresponding record in the global header table    READ TABLE gt_change_data ASSIGNING <ls_header>      WITH TABLE KEY company_code = ir_item->get_company_code( )                     header_id    = ir_item->get_header_id( ).    IF sy-subrc <> 0.
*     no header record found - create a new one      ls_header-company_code = ir_item->get_company_code( ).      ls_header-header_id    = ir_item->get_header_id( ).      INSERT ls_header INTO TABLE gt_change_data ASSIGNING <ls_header>.    ENDIF.

*   try to locate the corresponding record in the subordinate item table    READ TABLE <ls_header>-items ASSIGNING <ls_item>      WITH TABLE KEY item_number = ir_item->get_item_number( ).    IF sy-subrc <> 0.
*     no item record found - create a new one      ls_item-item_number = ir_item->get_item_number( ).      INSERT ls_item INTO TABLE <ls_header>-items ASSIGNING <ls_item>.    ENDIF.

*   When recording the 'old' state, we don't want to set the change indicator yet.
*   Therefore only set the change indicator if it is supplied.    IF i_change IS SUPPLIED.      <ls_item>-change = i_change.    ENDIF.

*   If required, record the current state, either as 'new' or as 'old'.    IF i_record_contents = abap_true.      IF i_old_state = abap_true.        ir_item->record_cdo_data( CHANGING cs_data = <ls_item>-old_data ).      ELSE.        ir_item->record_cdo_data( CHANGING cs_data = <ls_item>-new_data ).      ENDIF.    ENDIF.  ENDMETHOD.                    "record_item_state

 

The methods RECORD_CDO_DATA are manual additions to the persistent classes that just fill a structure with the values of the attributes. These methods are rather trivial and therefore not displayed here. If you don’t want to add methods to the persistent classes, you could also add this logic to the change document writer.

 

In order to fill the data structure at runtime, we need to handle a few events, namely IF_OS_FACTORY~TO_BE_DELETED and IF_OS_FACTORY~LOADED_WITH_STATE. The latter is used to store the ‘old’ state of the object before any changes were made. Since the event is the same for both the header and the items, the methods simply cast to the corresponding reference variable and defer to one of the methods introduced above.

 

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_OSCDO_CHANGE_DOC_WRITER->ON_LOADED_WITH_STATE
* +-------------------------------------------------------------------------------------------------+
* | [--->] OBJECT                         LIKE
* | [--->] WRITE_ACCESS                   LIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD on_loaded_with_state.    DATA: lr_header TYPE REF TO zcl_oscdo_header,          lr_item   TYPE REF TO zcl_oscdo_item.    CASE cl_abap_classdescr=>get_class_name( object ).      WHEN co_class_name_header. " TYPE abap_abstypename VALUE '\CLASS=ZCL_OSCDO_HEADER'        lr_header ?= object.        record_header_state( ir_header   = lr_header                             i_old_state = abap_true ).      WHEN co_class_name_item. " TYPE abap_abstypename VALUE '\CLASS=ZCL_OSCDO_ITEM'        lr_item ?= object.        record_item_state( ir_item     = lr_item                           i_old_state = abap_true ).    ENDCASE.  ENDMETHOD.                    "on_loaded_with_state

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_OSCDO_CHANGE_DOC_WRITER->ON_TO_BE_DELETED
* +-------------------------------------------------------------------------------------------------+
* | [--->] OBJECT                         LIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD on_to_be_deleted.    DATA: lr_header TYPE REF TO zcl_oscdo_header,          lr_item   TYPE REF TO zcl_oscdo_item.    CASE cl_abap_classdescr=>get_class_name( object ).      WHEN co_class_name_header. " TYPE abap_abstypename VALUE '\CLASS=ZCL_OSCDO_HEADER'        lr_header ?= object.        record_header_state( ir_header         = lr_header                             i_change          = 'D'                             i_record_contents = abap_false ).      WHEN co_class_name_item. " TYPE abap_abstypename VALUE '\CLASS=ZCL_OSCDO_ITEM'        lr_item ?= object.        record_item_state( ir_item           = lr_item                           i_change          = 'D'                           i_record_contents = abap_false ).    ENDCASE.  ENDMETHOD.                    "on_to_be_deleted

 

Remember the prefix \CLASS= when defining the constants for the class name!

 

With these methods, the writer can record the unchanged state of an object once it is loaded and flag it as deleted. We still need a way to track newly created objects, identify the changed objects and store the corresponding new/old structures for future use. This can be done using the basic agent methods:

 

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_OSCDO_CHANGE_DOC_WRITER->COMPLETE_CHANGE_LIST
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD complete_change_list.    FIELD-SYMBOLS: <lr_object> TYPE REF TO object.    DATA: lt_objects TYPE ostyp_ref_tab,          lr_header  TYPE REF TO zcl_oscdo_header,          lr_item    TYPE REF TO zcl_oscdo_item.

*   add the newly created headers to the change list    lt_objects = zca_oscdo_header=>agent->if_os_ca_instance~get_created( ).    LOOP AT lt_objects ASSIGNING <lr_object>.      lr_header ?= <lr_object>.      record_header_state( ir_header   = lr_header                           i_change    = 'I' ).    ENDLOOP.

*   add the changed headers to the change list    lt_objects = zca_oscdo_header=>agent->if_os_ca_instance~get_changed( ).    LOOP AT lt_objects ASSIGNING <lr_object>.      lr_header ?= <lr_object>.      record_header_state( ir_header   = lr_header                           i_change    = 'U' ).    ENDLOOP.

*   add the newly created items to the change list    lt_objects = zca_oscdo_item=>agent->if_os_ca_instance~get_created( ).    LOOP AT lt_objects ASSIGNING <lr_object>.      lr_item ?= <lr_object>.      record_item_state( ir_item     = lr_item                         i_change    = 'I' ).    ENDLOOP.

*   add the changed items to the change list    lt_objects = zca_oscdo_item=>agent->if_os_ca_instance~get_changed( ).    LOOP AT lt_objects ASSIGNING <lr_object>.      lr_item ?= <lr_object>.      record_item_state( ir_item     = lr_item                         i_change    = 'U' ).    ENDLOOP.  ENDMETHOD.                    "complete_change_list

 

Assuming that the recorded state is complete, it is now only a matter of simple data manipulation to write the change documents:

 

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_OSCDO_CHANGE_DOC_WRITER->SAVE_CHANGE_DOCUMENTS
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD save_change_documents.    DATA: lr_persistency_manager TYPE REF TO if_os_persistency_manager,          l_user                 TYPE syuname,          l_tcode                TYPE sytcode,          l_object_id            TYPE cdobjectv,          l_item_change          TYPE cdchngind,          l_object_change        TYPE cdchngind,          lt_new_items           TYPE TABLE OF yzoscdo_item,          lt_old_items           TYPE TABLE OF yzoscdo_item.    FIELD-SYMBOLS: <ls_change>      TYPE t_header_data,                   <ls_item>        TYPE t_item_data,                   <ls_item_change> TYPE yzoscdo_item.    lr_persistency_manager = cl_os_persistency_manager=>get_persistency_manager( ).    l_user  = cl_abap_syst=>get_user_name( ).    l_tcode = cl_abap_syst=>get_transaction_code( ).    LOOP AT gt_change_data ASSIGNING <ls_change>.      FREE: l_object_id, l_item_change, lt_new_items, lt_old_items.

*     determine the object ID - this refers to the header, so it's MANDT BUKRS HEADER_ID      l_object_id(3)    = cl_abap_syst=>get_client( ).      l_object_id+3(4)  = <ls_change>-company_code.      l_object_id+7(32) = <ls_change>-header_id.

*     assemble the item change data      IF <ls_change>-items IS NOT INITIAL.        l_item_change = 'U'.        LOOP AT <ls_change>-items ASSIGNING <ls_item>.          CASE <ls_item>-change.            WHEN 'I'.              APPEND INITIAL LINE TO lt_new_items ASSIGNING <ls_item_change>.              MOVE-CORRESPONDING <ls_item>-new_data TO <ls_item_change>.              <ls_item_change>-kz = 'I'.            WHEN 'U'.              APPEND INITIAL LINE TO lt_old_items ASSIGNING <ls_item_change>.              MOVE-CORRESPONDING <ls_item>-old_data TO <ls_item_change>.              <ls_item_change>-kz = 'U'.              APPEND INITIAL LINE TO lt_new_items ASSIGNING <ls_item_change>.              MOVE-CORRESPONDING <ls_item>-new_data TO <ls_item_change>.              <ls_item_change>-kz = 'U'.            WHEN 'D'.              APPEND INITIAL LINE TO lt_old_items ASSIGNING <ls_item_change>.              MOVE-CORRESPONDING <ls_item>-old_data TO <ls_item_change>.              <ls_item_change>-kz = 'D'.          ENDCASE.        ENDLOOP.      ENDIF.

*     determine the overall change indicator      IF <ls_change>-change IS NOT INITIAL.        l_object_change = <ls_change>-change.      ELSEIF l_item_change IS NOT INITIAL.        l_object_id = 'U'.      ENDIF.

*     update mode or direct call?      IF lr_persistency_manager->get_update_mode( ) = oscon_dmode_direct.        CALL FUNCTION 'ZOSCDO_WRITE_DOCUMENT'          EXPORTING            objectid                = l_object_id            tcode                   = l_tcode            utime                   = sy-uzeit            udate                   = sy-datum            username                = l_user            object_change_indicator = l_object_change            n_zoscdo_header         = <ls_change>-new_data            o_zoscdo_header         = <ls_change>-old_data            upd_zoscdo_header       = <ls_change>-change            upd_zoscdo_item         = l_item_change          TABLES            xzoscdo_item            = lt_new_items            yzoscdo_item            = lt_old_items.      ELSE.        CALL FUNCTION 'ZOSCDO_WRITE_DOCUMENT' IN UPDATE TASK          EXPORTING            objectid                = l_object_id            tcode                   = l_tcode            utime                   = sy-uzeit            udate                   = sy-datum            username                = l_user            object_change_indicator = l_object_change            n_zoscdo_header         = <ls_change>-new_data            o_zoscdo_header         = <ls_change>-old_data            upd_zoscdo_header       = <ls_change>-change            upd_zoscdo_item         = l_item_change          TABLES            xzoscdo_item            = lt_new_items            yzoscdo_item            = lt_old_items.      ENDIF.    ENDLOOP.  ENDMETHOD.                    "save_change_documents

 

The hard part of the implementation was to find a way to grab the changed state right before it is saved and trigger the generated function module at the right time. For this, I decided to register the change document writer as a so-called save handler. The class needs to implement the interface IF_OS_CA_SERVICE for this, but with two exceptions, none of the methods are required. To safeguard against accidental invocation, I simply placed the statement

RAISE EXCEPTION TYPE cx_os_no_implementation.

in each method introduced by the interface, except for the following two methods.

 

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_OSCDO_CHANGE_DOC_WRITER->IF_OS_CA_SERVICE~PREPARE_FOR_TOP_TRANSACTION
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_INVALIDATE                   TYPE        OS_BOOLEAN
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD if_os_ca_service~prepare_for_top_transaction.    FIELD-SYMBOLS: <lr_agent> TYPE REF TO if_os_ca_service .

*   a new transaction is started - forget all previously stored change data    FREE gt_change_data.

*   defer the actual method call to the wrapped agents    LOOP AT gt_agents ASSIGNING <lr_agent>.      <lr_agent>->prepare_for_top_transaction( i_invalidate ).    ENDLOOP.  ENDMETHOD.                    "if_os_ca_service~prepare_for_top_transaction

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_OSCDO_CHANGE_DOC_WRITER->IF_OS_CA_SERVICE~SAVE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD if_os_ca_service~save.    FIELD-SYMBOLS: <lr_agent> TYPE REF TO if_os_ca_service .

*   defer the actual method call to the wrapped agents    LOOP AT gt_agents ASSIGNING <lr_agent>.      <lr_agent>->save( ).    ENDLOOP.

*   then complete the list of changed objects and write the change documents    complete_change_list( ).    save_change_documents( ).  ENDMETHOD.                    "if_os_ca_service~save

 

As you can see, the implementation is rather straightforward: leave the complex stuff to the generated agents (that we will store in a table named GT_AGENTS in the not too distant future) and just add our processing logic.

 

Now that we have the basic data recoding structures in place, we can start to wire the change document writer to the object services. The writer will need to be registered as an event handler, and it would be unwise to register multiple instances. For this reason I designed it as a simple singleton: flag the class as CREATE PRIVATE, add a static attribute SR_INSTANCE TYPE REF TO  ZCL_OSCDO_CHANGE_DOC_WRITER and a static initialization method like this:

 

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_OSCDO_CHANGE_DOC_WRITER=>INITIALIZE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD initialize.    IF sr_instance IS NOT INITIAL.      CREATE OBJECT sr_instance.      sr_instance->register_handlers_for_agent( zca_oscdo_header=>agent ).      sr_instance->register_handlers_for_agent( zca_oscdo_item=>agent ).    ENDIF.  ENDMETHOD.                    "initialize

 

During the initialization, the following method is used to register both the event handling methods and the save handler:

 

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_OSCDO_CHANGE_DOC_WRITER->REGISTER_HANDLERS_FOR_AGENT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IR_AGENT                       TYPE REF TO CL_OS_CA_COMMON
* +--------------------------------------------------------------------------------------</SIGNATURE>  METHOD register_handlers_for_agent.    DATA: lr_persistency_manager TYPE REF TO if_os_persistency_manager.    APPEND ir_agent TO gt_agents. " TYPE TABLE OF REF TO if_os_ca_service .    lr_persistency_manager = cl_os_persistency_manager=>get_persistency_manager( ).    lr_persistency_manager->register_save_manager_for_ca( i_save_manager = me                                                          i_class_agent  = ir_agent ).    SET HANDLER on_loaded_with_state FOR ir_agent.    SET HANDLER on_to_be_deleted FOR ir_agent.  ENDMETHOD.                    "register_handlers_for_agent

 

With the initialization methods completed, a simple call to

  zcl_oscdo_change_doc_writer=>initialize( ).

during the initialization of the application is sufficient to start recording change documents. This article only outlines the basic procedure, but from here on it should be a lot easier to add functionality to the implementation

Posting GR only for few line items in an Inbound Delivery

$
0
0

Some times there will be rare scenarios that  GR to be done for only few line items in an inbound delivery. In this cases we can use  BAPI_GOODSMVT_CREATE to create GR. off course it is well know FM, but there is a reason why I am writing this blog, when we use this BAPI we will come across  two issues, those are wired issues and to resolve them I had to struggle a bit, so I wanted to mention those remedies in this blog.

 

The first issue is Once GR has been create the GR is not showing in the Inbound Delivery document flow, for this we have one FM which can be used to resolve this. i.e SD_DELIVERY_UPDATE.

 

The Second issue is the Inbound status have not been updated as expected, for this we have a standard program RVDELSTA, after above FM has been called we need to run this program and it will be updated the IBD status as appropriate. actually foe every delivery we can't manually execute this program, so we have to call this program in our program. So, what i did just copied this program and removed the code which gives output. and called the program in my program and issue got resolved.

 

Those two remedies I just wanted share in this blog, for detailed code check the attachment which may helpful if you stuck in same situation.

ALV grids: texts on subtotal lines

$
0
0

Hi all,

 

this is a small tip for subtotals in ALV grids.Many times I saw reports in which, for example, material code and material Long text are displayed in the ALV grid, but on the material subtotal line, the material Long text is missing. This is annoying especially if you only display subtotal lines in your report.

 

There is a easy way to display the texts on ALV subtotal lines:

 

In the field catalog, put in TXT_FIELD the name from the field catalog field containing the Long text to display.

For example, if in your field catalog you have the fields MATNR and MAKTX, for the field MATNR put in TXT_FIELD 'MAKTX'. The Content of MAKTX will be displayed on MATNR subtotals lines too.

 

I hope this will be helpful

 

Fred

How to request for a new developer key in SAPt

$
0
0


What is developer key?

 

                                   The developer key is a combination of your installation number, your license key (that you get from http://service.sap.com/licensekey) and the user name. You need this for each person that will make changes (Dictionary or programs) in the system.


To request for a new developer key,


Log on to the URL http://service.sap.com/sscr with your SAP S-user






developer key sap

           


Click on Register Developer


Enter the user name(s) and select the Installation for which the developer key is required




Enter the user name(s) and select the Installation for which the developer key is required


Register developer acces key in sap



Click on Register


How to register developers in SAP



The key will be displayed in the same screen or you can check from Developer Registered by Me or in DEVACCESS table

 

 

 

 

 


Developer access key is nothing but an algorithm based on system number and SID and some other system values (SAP does not reveal the information). The developer access key is validated by SAP using a Kernel level C system program ''CHECK_DEVELOPER_KEY'. So, even if the developer access key has been deleted for a user ID in the DEVACCESS table, user can still use the same developer access key.

 


if you would like to look up at your developer key and save it and have it available for the next system refresh. 
The table name is DEVACCESS and can be viewed with SE16 and SE11.
For new ABAP developer, you will be prompt for the developer if you are trying to create a program using the standard SAP naming convention.
Customer own created program should all start with a "Y" or "Z".

My Monster! It's Alive! IT'S ALIVE!

$
0
0

IT’S ALIVE! IT’S ALIVE!

image001.jpgimage002.jpg

Writing a Book for SAP Press – Part One


Table of Contents

Background

First Step - Accessing a 740 Trial System

Next Step – What to put in the book?

To Be Continued


Once Upon A Time….


On the 29th of January 2014 I had published the following blog on SCN:-


http://scn.sap.com/community/abap/blog/2014/01/29/team-procedural-vs-team-oo

 

That blog was discussing the merits of OO Programming vs Procedural Programming. A great deal has been written about that subject on SCN, but what may possibly have made my blog unique was that it contained two songs, one about each style of programming.


By co-incidence or otherwise, when I woke up the next day and looked to see if there were any comments, I got one from Tammy Powlas saying that a lady called Kelly Weaver from SAP Press wanted to talk to me about writing a book.

Well, I jumped at the chance, and my book comes out on April the 3rd. Now I was very wary about doing a puff piece of advertising for the book masquerading as a blog, so I checked with Matthew Billingham and he said to talk about the process of writing the book, with just a link to the relevant part of the SAP Press Web Site at the end.


So I am not going to try not to talk about the book at all, but the process of writing it. Who knows, you may end up writing one yourself one day in the not too distant future.


I will split this into several blogs and this blog will concentrate on the first two steps of that process.


First of all I needed to get access to a trial SAP 740 system, so I will talk about how to do that, it is not as easy as you might think, so I will step through the process.


Then I will talk about the reasoning behind how I worked out what new technologies to put in the book and what sort of running example would best tie them all together.


Life Begins at 740


Now I did not get to choose the topic of the book, which was fine by me – I would have written about anything they wanted. It turned out I was to be covering the topic that Thomas Jung & Rich Heilman used to publish books about – theirs was called “Next Generation ABAP Development” and they (Thomas & Rich) did not want to write a third edition, so SAP Press turned to me instead to write a similar sort of book (but not a sequel) which was very flattering.


However my company is many years away from getting a 740 ABAP system, so I had to lay my hands on one in a hurry. Luckily it is possible for anyone to get their hands on a “free” trial SAP system with a 740 ABAP system and a HANA database. It took me a while to work out how to do this, so I thought I would guide you through the process.


The first thing you need is an SCN ID – I would presume you have one, as you are reading this. The second thing you need is to sign up with Amazon Web Services (AWS). That part is ludicrously easy as (a) since you have to pay they (Amazon not SAP) want your money and (b) as might be expected Amazon make their web site as intuitive as possible.


https://console.aws.amazon.com/iam/home

 

Since that is so easy there is no point on dwelling on it, or even saying one word about it. I was amazed by how technically advanced that company is – during the process a robot phones you up, and as you talk to it the screen in front of you changes without you touching it. This is the sufficiently advanced technology which appears to be magic to me.

 

The cost is the important bit – just having an AWS account costs you about five dollars a month, plus about a dollar for every hour you have the trail SAP system in existence. Not the end of the world, especially if you can get your company to pay for it.

 

Cloud Cuckoo Land

 

Now you have all your credentials it is time to navigate the “SAP Cloud Appliance Library”.

 

https://cal.sap.com/

 

You will then get a screen saying “cloud appliance library loading” which may take a long while. The website seems really slow, it may just be me, but I wonder. If you press the “login” button you should get a message to the effect that you have been authenticated and are being directed to the main site. That is, if you normally log in to SCN and/or the SAP support portal using a certificate with your “S” number (SCN ID). You then see a nice picture of a hot air balloon, not that SAP is full of hot air or anything.

 

image003.png

 

Up up and away in my beautiful – yes beautiful - balloon

 

Now you might think that to get started you might go to the “get started” section at the bottom of the screen – how wrong you would be. Try that and half way through you will get asked if you want to pay ten billion dollars for a new SAP system.

 

Instead, navigate to the “accounts” tab where you can create an account which links your SCN ID to your AWS ID.

 

image004.png

 

Silence you User

 

So far so good. The next cab off the rank is to go to the “solutions” tab where you get a huge list of possible trial systems. The ones that are free are highlighted with big blue boxes.

 

image005.png

 

Solutions looking for Problems

 

When I first started playing with this I thought the round circles that looked like radio buttons were in fact radio buttons, but they are not – they are just status indicators. That is obviously what you must do to your users – give them familiar looking icons which do something utterly different from what they are used to. That is rather like the icon in transaction MIRO which normally means “refresh” but there means “delete”.

 


image006.png

 

Watch Out! – Not a Refresh Icon- it means DELETE

 

Anyway, getting back to the matter at hand, what you need to do is click on “try now” on the right hand side. I was on Internet Explorer 9 and had all sorts of problems, but now I am on version 11 all is well. You get the usual “terms and conditions” to click through and there is an interim, apparently pointless, step where the text reads “activate” and you press that and then you get to a stage where the text reads “create instance”.

 

This is the important bit – an instance is an SAP system in the cloud where you are the only user. You choose how long the instance is to remain alive i.e. you enter a “termination” date and time. Like the enamel on your teeth, when it’s gone its gone forever so you lose all your work, so be sure to download any custom objects you have created you feel like keeping for posterity using SAPLINK. As I said you get charged about a dollar for every hour the system is alive, and you get an estimate of the cost before you press “go”. When you are finished a so called PEM file gets downloaded to your PC which will be used to enable a remote desktop connection.

 

You then have to wait an hour whilst the new SAP instance creates itself, which is nothing in the grand scheme of things. Then the fun really starts.

 

Instance Coffee

 

After an hour, navigate to the “instances” tab. If there is a clock on the left hand side the instance has not finished creating itself, if there is a big green square you are good to go and there will be text on the right hand side saying “connect”.

 

When you press “connect” you get a “connect to the instance” pop-up box and you choose “remote desktop” and are then asked if you want to open the PEM file that was downloaded to your PC earlier. You say yes, and then after assorted security warnings a remote desktop session opens up, with icons for Eclipse and SAP.

 

Note – I have found that if you are inside a corporate firewall the remote desktop session will most likely not work. At the SAP Developer summit in Sydney last year most people were using their work PC’s and had noticed the same thing.

 

Pull That Branch Three Times

 

Now this SAP system has no ERP content – you can’t create sales orders or purchase orders or any of that nonsense. All that exists is the ABAP content, so you can muck about writing programs and the like – here is what is installed.

 

image007.jpg

 

Software components in the Trial SAP 740 System that are installed, by the old gasworks wall

 

Sadly the BOPF framework is not there, as that is part of the “Business Suite Foundation”, but one day the BOPF will officially join the NetWeaver club and become part of such trial systems.

 

Now I want to stress something here:-

·         You are the only user on this system so nothing you can do can affect any other user

·         There is no Business Suite content, so the only thing you can do is play around with ABAP, creating custom objects and the like, trying out new ABAP syntax and so forth.

 

You have a user name DEVELOPER and you would expect, given the only possible thing you can do in this system is develop, that this user would have a developer key. How wrong you would be.

 

I will now step through the process for granting the DEVELOPER user a developer key. Be warned, this is going to be rather like following a Da Vinci Code trail of clues. When I explained the process to my colleagues at work and they realised what one had to do they all fell about laughing.

 

First off, log into the trial SAP system using Client 000 and user SAP*. Then call transaction code SLICENSE which looks like this:-

 

image008.jpg

 

Transaction SLICENSE - to kill

 

You will see a randomly generated hardware key. The lights will all be red at the start, not like they are in the picture. You have to make a note of this really long code, put it on the clipboard or write it on a beermat or something.

 

Then go to the following website:-

 

http://www.sap.com/minisap

 

You will see a screen asking you for your name, email address and “S” number.

 

image009.png

 

MINISAP / Mini Me

 

You need to choose the “A4H – SAP Netweaver 7.4 AS ABAP / HANA DB / Linux” choice. The F4 drop down looks crazy on my screen, the boxes with the two choices are half the size of the screen, and if you try it twice the screen locks up and you have to start again.

 

Anyway, I press “submit” and then I get a message that an email will be sent to me with the licence key. As I need my corporate email I log into the company system, which breaks the remote desktop connection. I then wait about ten minutes until the email arrives.

 

I open the email and paste the contents of the attached text file onto the clipboard.

 

I then log out of the corporate system and restart the remote connection.

 

I then open a new text file in the remote system and paste the licence key into it, then save this new file.

 

I then, in transaction SLICENCE press the “install” button and upload the file. The lights go green.

 

I then go into the forest and pull the third branch of the fifth tree on the left three times.

 

I then need to go into transaction SECSTORE and then press the “execute” button and the screen fills up with green lights.

 

image010.jpg

 

Transaction SECSTORE

 

What is happening is that client 000 is making an RFC call to system 001 saying that the DEVELOPER user account is allowed to develop.

 

Now, I can go into client 001 as DEVELOPER and will now be able to create Z objects. But only if the **** crows three times after midnight and the hen lays four addled eggs and Jupiter is in conjunction with Uranus.

 

There, that was easy, was it not? You hardly took even one hour of the time you are paying for doing housekeeping tasks for no apparent reason. It’s like going into a hotel room and finding the bathroom and cupboard padlocked, but with a note on the table saying the keys to the padlocks are hidden in the room somewhere and here are some clues to their location in rhyme. All the hotels I stay in do that – you probably find the same yourself.

 

Anyway, you soon get used to it, and the upside is that you have an (almost – no BOPF) fully functional 740 system to play with. Oh and you have to go into transaction SICF and activate assorted services if you want things like BRF+ and Web Dynpro to work.

 

Choosing what to Put in the Pot

 

Having got the technical barriers out of the way, I had a lovely brand spanking new 740 system to play chock full of new technologies. The task now was to choose which of the myriad of those new SAP technologies to write about.

 

Where do new technologies come from? There are several possibilities:-

·         The stork brings them

·         You find them behind the mulberry bush

·         They get delivered as part of an upgrade to your SAP system

 

I have often said that going through an SAP Upgrade is like building an extra storey on top of your house. It is really expensive and takes time and effort, and in the end you have a whole new floor where you can go up and try out all the exciting new things that are up there.

 

The funny thing is though, after all that effort most companies never bother going upstairs and don’t use any of the new functionality. This is why so much ABAP development is for the purpose of adding “missing functionality” i.e. functionality available in SAP standard that no-one knows is there. The problem is compounded by all the new (business facing) functionality in enhancement packs being delivered in a dormant state – my experience is that companies are too scared to turn it on.

 

With an enhancement pack installation (upgrade in other words) you also get a new version of ABAP and naturally that is not dormant so you can start using all the new goodies from day one. Again, very few people ever do, they just stick to programming using DYNPRO screens and function modules and pretty much the exact same toolset they were using in 2000.

 

This is partially to do with resistance to change, but also to do with the problem that people just don’t seem to know about all the new things in their system. Let us say you have been on 7.02 for a while – have you ever used ABAP Unit? Or BRF+? Or Shared Memory? Do you even know what they are for? Do you know you can use UI5 with a 7.02 if you install an add-on?

 

And that is just in 7.02. More things followed in 7.31, and in 7.40 a whacking great sea change came along, completely renovating the ABAP language and making it possible to write programs with half the lines of code.

 

Just to make things scary, there are a new generation of young programmers sneaking up beside us old fogies and they do know what these things are, and have no fear of them.

 

“These kids [of the current generation] have no fear of technology … sort of like I have no fear of a refrigerator.”

Don Tapscott: Four principles for the open world

 

So, in theory at least, there should be a need for a book to tell programmers all about the new tools they have which are hiding in plain sight, and they should become conversant with if they don’t want to get edged out by the younger generation. And I could have my cake and eat it too; as such a book would also be of interest to the new young programmers so they could learn about new things in order to displace the older generation.

 

So I was told I need to make a list of 15 chapters, each covering a recently introduced ABAP based SAP technology. At first I thought I was never going to be able to come up with fifteen different new technologies to talk about. I took a piece of paper and divided into sixteen squares and started writing down things like “BOPF” and “BRF+” in each square. After the first few I ran out and started to panic, but then a few more started popping into my head, and before I knew it I had filled up all the squares and was writing extra things around the edges. Then it was a question of what topics to remove.

 

So, with the technical topics sorted out, the next thing to think about was the best way to type out these technologies to the waiting world, as Bob Geldof would say.

 

The Style Council

 

Next was the question of style – good as the book by Thomas Jung and Rich Heilman was, I wanted to do something as different as possible, and so I could not talk about a programmer at a university called “Bustle” or some such.

 

Nonetheless there has to be a running example, to give some sort of continuity between assorted chapters which all be concerned with different subjects.

Surprising as it may seem the easiest part of each chapter (to write at any rate) is to explain how to technically do “whatever it is” that is covered in the chapter. After all there is half a ton of online SAP help for each subject. However, having read all this myself and watched assorted TECHED videos online, I can see that sometimes there is a need to present this material in a somewhat more flamboyant manner. You can be delivering the most exciting innovation the world has ever seen, but if the audience falls asleep half way through, you have failed to get the message across.


A common complaint with the standard documentation you are directed to is that it is a bit abstract / divorced from reality, even when examples are given. I grant you that the SFLIGHT model is something we can all relate to, but I spend half of my life at airports due to business, and sometimes I would like to think about something else.


When writing about “Domain Specific Languages” Michael Feathers also said most of the examples he found in the Java field were just plain boring, so he made up an example based on a certain film genre. The Head First Design books use frivolous examples also. It is easy to relate to fictitious situations because we watch so much TV, and watch so many films (movies), and some of us even read novels. The difference is we do all these things for pleasure, but we go to the airport because we have to.


So, if I really want to show how to do the “whatever it is” from each chapter in a realistic way, then I need a sample application which runs throughout the book - which is normal in the SAP ABAP series – and for which the reader can look at the source code from magic realm in the internet where it will be stored, but is entertaining at the same time - more like the movie “Airplane” (called “Flying High” in some countries) than SFLIGHT.


So I chose for the running example a common situation most programmers find themselves in at some point in their lives – working for Baron Frankenstein, programming an SAP system to make monsters. I mean, who hasn’t done that? So it’s something everyone can relate to.


The Right Tool for the Right Job


Another departure is that a lot of books just say that the new technology is wonderful, and would not dream of saying a single negative thing for fear of upsetting SAP – I imagine this must cross the minds of authors who are also SAP employees.


So I decided that sometimes in my examples you would see me demonstrate the new “whatever it is” in my example application, and then decide to change it back to the way it was before. This is not because I came to the conclusion that the new tool is useless – if I thought that, I would not include it in the book – but because no new technology can be a panacea for every single problematic situation you come across.


In regard to the lack of effectiveness of such “magic bullets” I always like to draw analogies, and in this case I am going to bring up the plot of a UK comedy / drama from about 25 years ago called “A Very Peculiar Practice”. This was about a group of doctors who worked at a university.


In one episode they were being pushed to test a new wonder drug that was supposed to cure everything in the world. One doctor was really taken with the promise of this new drug and prescribed it to everyone who came to him, or even came near him. The hero of the piece (Doctor Who actor Peter Davison), however, only prescribed it where it seemed to make sense, and then only in conjunction with established medical techniques.


In other words, with all the new ABAP goodies we have all these new hammers, what is to stop us running round looking for nails to hit them with?

So I thought I would try and give my two cents worth on when to use “whatever it is” and when NOT to i.e. use it when it makes sense, not for the sake of using it because it is new.


Coping with a lack of perfection

I wonder how many times someone looks at something new from SAP and says “that is not exactlywhat I want” and so goes off and gets the development department to build something similar from scratch. I am thinking of business facing applications here e.g. a company building its own EHS system because they don’t like the SAP one, but developers can be just as picky, or maybe even more so and looking at something new like BRF+ and saying “that is quite good, but it cannot do the ABC123 task so I won’t bother with it”.


In other words the new tool is not perfect. After coming to Australia I explained to my father what my new job involved. He asked me “What happens when everything is working perfectly and all the end users are happy?” the inference being that when that day dawned I would be out on my ear.


Luckily for me, and for every programmer in the world, the end users will never be happy, because being satisfied with something appears to be contrary to human nature. In the same way, once you become familiar with a given new SAP innovation you may say “well that’s not good enough, what about the X, what about the Y, that won’t work at all when I want to do Z”.


I think the innovations from SAP I wanted to put in the book are really good, but they are not perfect due to the fact that nothing can be. Once you get to perfection then you don’t need to innovate any more, and that would be the end of the world.


Some SAP salesman will tell you that all the lovely new toys do everything you need right out of the box. Nobody would want anything more. Of course they wouldn’t. Or would they? We asked The Black Adder.


“Nonsense, nonsense …. but just in case it’s true….” – Black Adder II, Ben Elton / Richard Curtis.


I am as picky as the next person, and often when I have tried out the new technology there have been aspects I have disliked, or features I felt were missing. In such cases I wanted to say how I personally have got around these perceived shortcomings using my own ABAP code, often adapting solution I found on SCN. Even better, in some cases, such as ABAP in Eclipse, or BRFPlus, it is possible to enhance the standard tool with your own improvements till the cows come home to roost.


To be Continued


I am going to do a few follow up blogs, in which I will talk about the book writing process, and spice things up with assorted content which was cut from the final edition from the book. The vast bulk of that (the cut material) relates to the philosophy of programming i.e. the why the bit that rarely changes, as opposed to the how which changes all the time as new technologies come out.

 

Cheersy Cheers

 

Paul

 

https://www.sap-press.com/abap-to-the-future_3680/

 

 

 


Rosetta Code and ABAP

$
0
0

Last week Christian Drumm (@ceedee666) and Fred Verheul (@fredverheul) had a short conversation on Twitter about functional programming in ABAP which results into new code on the internet project "Rosetta Code".

 

rosetta1.PNG

On Rosetta Code developers "present solutions to the same task in as many different languages as possible". From 766 tasks currently only 31 are solved in ABAP.


We can do better, can't we?

 

To motivate our ABAP friends to help us to increase the number I've reached out to the SCN Gamification crew and asked for new badges. Unfortunately there is no program yet to create missions for external stakeholders. Now I'm searching for an SAP internal sponsor who is willing to fund the creation of these missions. Anybody out there?

 

However, feel free to contribute to Rosetta Code also without badges (badges may be awarded later if possible).

 

You can find me on Twitter and G+

FIORI Notes 1 : One UX to Rule them All

$
0
0

The first week of the open SAP “Build Your Own SAP Fiori App in the Cloud” has just been done.

I'll use this blog series as my personal notes on the Course.

 

I post this in ABAP development as that is the kind of audience similar to myself.

If things have been pretty stable in your system for the last few years, SAP’s direction on Fiori may just rock your boat a little. 

I’ve been watching this space for a while, and evidently SAP is really getting serious on it now.

 

 

I'll note 2 points from the first week

 

1. “SAP Fiori UX is the new face of SAP to all business users for ALL lines of business across devices and deployment options”.

Think of it. No SAPGUI. No Webdynpro. Only Fiori UX. Personally, I think that statement is aspirational.  But it’s a good one.

 

2. Shift from complex monolithic transactional apps to smaller simpler role specific apps that can be consumed on any device.

This shift addresses the complexity in using transactional apps. Role/task specific apps are more simple. Simple = Productive. Using the launchpad, users can have multiple role-specific apps which are tailored to their activities.

 


DEMO

If you haven’t played with FIORI, try the demo : http://demo-fioritrial.dispatcher.hana.ondemand.com

Discover how you can perform functions that are typically more difficult in legacy systems.

FIORI Demo.png

 

 

FIORI APP LIBRARY

Then, look at the App Library : http://www.sap.com/fiori-apps-library

 

The library allows you to get a feel of the standard, extensible FIORI apps that SAP currently have. 

You can always create your own, but building on existing ones is probably the first option.  This site contain a list of apps (currently 541) with their corresponding description, installation and  configuration information.

Note that most apps require the HANA DB There are some transactional applications that only requires ECC, but all Analytical and Fact Sheet applications require HANA.

 

 

FIORI app library.png

 

 

 

UI5 CONTROLS

 

UI5 is the foundation for FIORI apps.

This link lists available controls in UI5 https://sapui5.netweaver.ondemand.com/sdk/explored.html

 

UI5 Controls.png

Reading a Smartstyle from the Smartform

$
0
0

Hi,

 

just want to share my findings and code regarding the topic.

Recently I've been working on the functionality which would allow our users to interact with the Smartform's text (which is usually comes from SO10 texts) before it is passed on to the Smartform function.

We already have gone through some iterations of implementation. First we have delivered it using standard simple text edit gui component which was fine from the technical side but was not good enough from the user's perspective as the initial SO10's formatting was lost ones text have been processed using text edit.

The next iteration was logical one. We have switched from text edit to CL_GUI_SAPSCRIPT_EDITOR, which give a native SO10 text editing environment. The issue with this editor though is that you have to provide a suitable style during initialization. We can always init it with style SYSTEM but our approach was to limit user's formatting options down to the ones supported by particular smartform.

 

So this post is about how we are getting style name from the smartform.

Bellow is the form's code which determines the proper smartstyle name based on the smartform name. Hope it will help some of you. If you have any better solution, please share here.

 

FORM get_form_smartstyle USING    p_form        TYPE tdsfname

                          CHANGING cp_smartstyle TYPE tdssname.

   DATA:

       nodename     TYPE ssfname VALUE 'HEADER',

       ivarheader   TYPE tsfivhd,

       varheader_wa TYPE ssfivhd.

 

   cp_smartstyle = 'SYSTEM'.

 

   IF NOT p_form IS INITIAL.

     CALL FUNCTION 'SSF_READ_FORM'

       EXPORTING

         i_formname = p_form

         i_language = sy-langu

       EXCEPTIONS

         OTHERS     = 4.

     IF sy-subrc EQ 0.

       CALL FUNCTION 'SSF_READ_NODE_BEGIN'

         EXPORTING

           i_nodetype = 'SF'

           i_nodename = nodename

         EXCEPTIONS

           OTHERS     = 4.

       IF sy-subrc EQ 0.

         CALL FUNCTION 'SSF_READ_DATE'

           EXPORTING

             i_name = 'IVARHEADER'

           IMPORTING

             o_date = ivarheader

           EXCEPTIONS

             OTHERS = 4.

         IF NOT ivarheader[] IS INITIAL.

           READ TABLE ivarheader INTO varheader_wa INDEX 1.

           cp_smartstyle = varheader_wa-stdstyle.

         ENDIF.

       ENDIF.

     ENDIF.

   ENDIF.

ENDFORM.                    "get_form_smartstyle

Maintaining Transport request transparency and control through add-on feature – Attribute

$
0
0

Introduction


In SAP system landscape of automotive components Supplier Company where there are many Roll-out projects running across, it is required to plan development work and customizing activities in structured projects and changes can be structured independently of each other in different projects, and then import them independently into target systems. SAP recommends do this if, for example, you want to go live with different projects at different times, or if you want to link development work in a single area. In this blog, have an attempt to explain the advantage of defining and setting up Attribute of Transport request in sensitive SAP environment of an Automotive component Supplier Company.

 

1.jpg

 

The CTS is the central tool for managing changes to Customizing and Repository data that is incurred during project realization phase made in the IMG or ABAP Workbench. The changes in change requests can be linked together logically, or can be completely independent of each other. The activity including the configuration is purely managed by Basis folks. The change request is then used to copy the changes from this client to other clients or systems, thus to allows us develop in one environment, test development work in a test environment, and then, if the tests are successful, use it to productive system. This makes sure that productive operations are not placed at risk by faulty settings or program errors.

 

Editing Attributes of Transport Request

 

This requires the administration authorization (Basis Team) in the CTS to edit attributes.


Procedure (To edit attributes, proceed as follows)


1.  Call Transaction SE03, or choose Goto → Transport Organizer tools in the Transport Organizer.

2. Choose Administration → Display/Change Request Attributes.


New attributes as per Client requirement which is intended to be created and maintained needs to begin with the letters Z or Y. If the attribute is required to be obligatory for all change requests, select Attribute obligatory for requests. This means that change requests that do not have this attribute cannot be released. If it is essential that a value is specified for the attribute, select Attribute value obligatory and this kind of requirement is very Client specific. In short this prevents unnecessary Transport request release and each transport request gets assigned to meaningful attribute i.e. Z_Change_Approval and Z_Change_Reason for Project. This exhibits better transparency and control for transport request generated due to stringent Project development objects as a part of multiple Roll-Out Projects in system Landscape.

 

1.jpg

 

1.jpg


Releasing Change Requests

 

Once all the task in a change request are released, then the change request itself can be released. At this point, the object list of the change request contains all objects that have been changed by the users involved. To release the change request, position the cursor on the request and choose Release Directly.


1.jpg

 

 

The following occurs when the change request is released:


●  The current version of all objects entered in the request is stored in the version database. This means that the sequence of the change requests under which an object is edited corresponds to the various object versions archived in the database.

●  If the change request contains repairs, the repair flag for these objects is reset when you release the request, as long as no sub-objects are locked in another change request. If this is the case, the object’s repair flag will be reset only when the last change request is released. After the repair flag has been reset, the objects are no longer protected from being overwritten by imports into the system.

●  When you release a transportable change request, its objects are exported out of the SAP System and copied to an operating system file. The request is also marked for import into the target system.

●  The objects entered in the request are unlocked. They can now be changed again.

 

 

For the system administrator:

For the export, the transport dispatcher program RDDIMPDP must be scheduled in the background in client 000. You only need to perform this scheduling once. To do this, log on as a user with administration authorization (S_CTS_ADMIN) and execute the report RDDNEWPP in the initial screen of the ABAP Editor (transaction SE38). If you export more objects at a later time, you do not need to reschedule the program unless the scheduling information was deleted manually. For more information, refer to the program documentation of the transport dispatcher program RDDIMPDP.

 

 

Once testing of the Development object is completed and approved at Quality system, run the transaction code STMS_QA where the approval for the Transport Request is updated so that it will be finally deployed to PRD system. Select the Transport request as per the sequence which needs to be moved to Production system; from the menu bar select the approval step since this is the first formal step of releasing the Transport request to Production system.

 

1.jpg

 

1.jpg

 

A transportable request is not automatically imported into the target system, since this could disrupt work significantly, particularly if the target system is an SAP System used for production operation. Approval Step can be updated as per the process established in the project by Basis and often; first option is preferred where the system owners do finally review before release. The import must be started by the system administrator at an appropriate point in time. The system administrator can decide whether only particular requests or all requests waiting for import should be imported into the target system. Moreover, rejection option is also available here which helps in rejecting the transport request so that it is not moved further to Production system and all the information related to attribute of Transport request, it is available in SAP table - WBOATTR.

 

 

Reference Link :-

 

http://scn.sap.com/community/abap/blog/2012/04/07/how-to-record-dependencies-between-transport-requests

 

http://wiki.scn.sap.com/wiki/display/ABAP/Transport+Dependency+Utilities

 

http://help.sap.com/saphelp_nw70/helpdata/en/14/94fc3f8fc2c542e10000000a1550b0/content.htm?frameset=/en/14/94fc3f8fc2c542e10000000a1550b0/frameset.htm&current_toc=/en/b4/d0340a2d0f433cbeb69660e750d74b/plain.htm&node_id=3&show_children=true#jump3

What's that coming over the hill? Is it a MONSTER?

$
0
0

image001.pngimage002.png

What’s that coming over the hill? Is it a Monster? IS IT A MONSTER?

 

Writing a Book for SAP Press – Part Two

Table of Contents

Background

Eclipse

UML

ABAP 740

To Be Continued


It’s Alive – In the City of Light


Simple things please simple minds, so I was delighted by the positive response to my first blog about writing a book for SAP Press, a book about monsters (and the latest ABAP features).


http://scn.sap.com/community/abap/blog/2015/03/27/my-monster-its-alive-its-alive

 

In that blog I talked about the process of getting access to a trial SAP system, and some thinking about what type of content to put in the book. Once I had scribbled down by list of topics on the back of an envelope, which co-incidentally is the same medium that is used for storing technical specifications for ABAP programs, then the next question was how to arrange those topics.


Turn Around Bright Eyes


When connecting to the trial SAP 740 HANA system you log on by means of a remote desktop session. On that remote desktop is an SAP GUI logon pad as might be expected, but also an icon to call up Eclipse. The idea is to open the Eclipse system, not use the SAP logon pad, and do your programming from Eclipse.


Now, Eclipse is not everyone’s cup of tea – comments made in regard to my last blog described programming in Eclipse as “programming with broken fingers” and no doubt there are far better equivalent tools out there, but that is rather like discussing which airline is best with someone who refuses to fly.

In other words there seemed to be a lot of people who would rather die than stop using SE80. So as a first step talking about Eclipse seemed a good idea. If they don’t accept the idea that an alternative to SE80 is even possible / desirable then the other tools will not get a look in, and I bet some conservative development managers would not be comfortable with having their team move to a development environment that was not endorsed by SAP.

I try to keep an open mind, so some considerable time before Eclipse became available for ABAP I installed Eclipse to see what it was like and ran through all the tutorials – which were all to do with Java naturally – and was very impressed.


Even at that point Eclipse was not just for Java – it could be used to develop in a large number of languages, for example Ada, C, C++, COBOL, Fortran, Haskell, JavaScript, Lasso, Natural, Perl, PHP, Prolog, Python, R, Ruby, Scala, Avengers Assembler, Clojure, Groovy, Scheme, and Bang Bang Thank You Erlang. Given the size of that list it would seem that some years later when support for ABAP was added it was just a case of another member joining the club.


So, I put Eclipse in as the first chapter on the grounds that what development environment you use would seem to be the first step in any programming project. I would try to look for ways in which you could do useful things in Eclipse whilst writing code which you could not normally do in an SE80 environment.


I would also note that an open source IDE such as Eclipse evolves far faster than an SAP system. Already since the book was finished there have been two minor releases of the SAP tools and I have started making a list of new features in case I get asked to write a second edition of the book in 3 years’ time.

An open source IDE might evolve faster, but in fact the whole of the SAP technology stack – every single subject I write about in the book - is evolving at a ridiculous pace. Most likely in 3 years’ time so much will have changed the book will need a total re-write, which is fine by me.


The Bash Street Kids – featuring Plug-In


American songwriter Steve Earle once sang a song called “I ain’t ever satisfied” which is what gives us IT types job security – not only are the end users never happy, but neither are the developer community.


Due to this fact I was hoping to try to end each chapter which dealt with an imperfect new tool (and how many are going to be perfect? Oh yes that’s right, none of them) with ways that it is possible to improve the functionality that you get “out of the box”.


In the case of Eclipse adding new functionality takes the form of “user defined plug ins”.


As an example, if I found a boring repetitive task that I had to do every day in the ABAP workbench I would write a tool to help me, but that would be my tool and I could not add it into the standard SE80 menu without the sort of modification to the core system we try to avoid, so even my colleagues inside the company would find it difficult to re-use this, let alone the whole world.


Eclipse works off the principle of being able to add such tools as plug-ins – the whole ABAP in Eclipse framework is such a plug-in. So I wanted to find an example of where there was a gap in the ABAP workbench and someone had added a plug-in to ABAP in Eclipse to address that gap.


I am a Universal Model, if you know what I mean


When I first started getting interested in object orientated programming someone said to me “before you do anything, learn UML”. So I found and read a corker of a book called “UML Distilled” by Martin Fowler.


http://martinfowler.com/books/uml.html

 

My favourite quote is as follows:-


“If someone came up to you in a dark alley and said ‘psst – wanna see a UML diagram?’ it would probably be a class diagram”


We have two programming teams where I work – the “yellow shirts” who program in ABAP and the “pink shirts” who program in what traditional ABAP people would consider weird and obscure languages like Angular JavaScript.


When I walked past this enemy territory I noticed that they had pinned to the wall above their desks posters full of square boxes all connected with arrows. It turns out those were UML diagrams, literally a map of whatever application they were creating.


It seems the idea in OO programming is to draw up a diagram showing what classes you need and how they inter-relate, and what methods and attributes such classes have before you start programming. Moreover, such UML diagrams can be created with VISIO like tools within IDE’s like Eclipse, and then for languages like Java and Avengers Assembler at the press of a button the system will generate skeletons of the classes and methods and method signatures for you.


Then you are supposed to write unit tests for these skeleton classes before putting any real code in them – but I am getting ahead of myself.


So, if that is what a real OO programmer does, and I want to act like one to see what it is like, then I would need something similar in ABAP. So if I could find an Eclipse plug-in that enables this functionality in ABAP (i.e. creating skeletons of ABAP classes and methods based on a diagram) that would be a wonderful example.


Hunting for the UML Snark


It doesn’t take much googling to find blogs about UML for ABAP. I found two almost at once, and I thought they were both talking about the same plug-in but in fact they were utterly different.


Now I don’t want to go into how to install these or how they work – as that is in the book – but I do want to thank the creators of both for the help they gave me, and to make sure people do not get as confused as I was at the start.


The problem is the name of both tools appears at first glance to be the same, which is why I thought there was only one.


UML2ABAP is the name of a product which you would have to pay for, from a French company called Obeo.


UMAP is an open source project, but just to confuse everybody, the web site for this is called UML2ABAP, and the open source project uses a lot of technology supplied by Obeo.


The company Obeo were kind enough to give me a trial edition of their product, for which I am grateful. I imagine they were very happy to have their product being mentioned in a book, though they only get a couple of paragraphs.


I also conversed via email with the inventor of the open source UMAP, Mathias Märker.


You are not my TYPE


One point that he mentioned I was meaning to put in the book but never got around to, so I will mention it here. UML is language independant, and you download whatever open source tool you can find to Eclipse or somewhere similar to create the diagrams.


Naturally since such tools that you use to create UML diagrams in the first place have never even heard of SAP, so when when someone writes a tool to convert the diagram into ABAP code they have a whacking get problem.


Creating classes and methods is easy enough, as is generating the names of the input and output pramters in the signatures. In languages like JavaScript you don;t TYPE a variable, it takes on the type of any value passed into it. However in ABAP world attributes and method parameters need a TYPE and how in the world does the conversion tool know how to TYPE such thing? For example you would manually type ID_SALES_ORDER TYPE VBELN but VBELN is 100% SAP specific.


Naturally it cannot, so the generated code in SAP comes out looking like:-


IMPORTING ID_SALES_ORDER TYPE (empty space) .


Or


IMPORTING ID_SALES_ORDER TYPE INVALID.


That is how the two tools deal with the problem i.e. by giving up in the face of the seemingly impossible. Then you would have to manually add the data type yourself.  According to Mathias in UMAP the workaround is in the UML diagram creation tool to create a package called “datatypes” and in there you can create UML elements of type “Data Type” and name them like standard SAP data elements e.g. PERNR or VBELN. Those you can then assign to your UML attributes (either class attributes or signature parameters) in the diagram you are building and when the conversion tool is called in your SAP System the generated code will have the attributes and parameters that are created TYPED with the corresponding data element.


I tried this myself to make sure and it works fine.


Language Timothy!


The limits of my language means the limits of my world.

-          Ludwig Wittgenstein


If the first step in programming is the development environment, and the next stpe is to generate skeletons of classes and what have you, then the next step is to fill up those skeletons .... with code! And what sort of code do we like?


  • ·         Morse Code
  • ·         The Spy who Came in from the Code
  • ·         ABAP Code

I thought I would go with the third one, and so therefore the next obvious subject to include was a chapter on the improvements in the ABAP language that came along in version 740 – what can only be described as a sea change. I can‘t stress that enough – going from 7.02 to 7.40 is an enormous boost.

Mind you since ABAP is backwards compatible, you can get away with writing things the same way you did in version 3.0 and everything will work fine, though the extended syntax check will – quite rightly - have a cow as Bart Simpson would say.


So, given the „we have always done it this way“ nature of some programmers, along with all the new 740 things I also included some features that came in with version 7.02 which I strongly suspected a lot of people did not know about, let alone use.


Obviously there is standard SAP online documentation for each new ABAP statement, but (a) IT people do not read documentation and (b) most of it is boring and (c) often such documentation does not appear related to the real world. It is difficult to grasp the idea when the examples use variables called A and B, when we are used to dealing with real world objects like sales orders and purchase orders. That is why at the SAP Architects and Developers conference in Sydney in 2014 Thomas Jung used all his own examples for each new feature.


However credit where credit is due – unless it is been censored by now, if you go on the internet looking for SAP online help. Once you have found the site take the path ABAP Keyword Documentation -> ABAP Reference -> Declarations -> Local Declarations in Expressions, and if you look at the example code for the LET expression then that may well win the award for the funniest example code in the history of SAP online help. Of course, now I have said that „they“ will probably remove it, and take out the author and shoot them.


The Man who Never Asked WHY?


I have a horrible habit of mixing the HOW with the WHY. What I mean by this is that when a new feature comes along 99% of the blogs and documentation are concerned with how to get whatever it is working technically. As to discussing whether using this shiny new feature is a good idea or not – that discussion never seems to get a look in.


The „how“ part of programming is always changing as technology evolves, the „why“ part is philosopical and so never changes. As part of the chapter on new ABAP language features I had included a discussion as to whether the new (much more condensed) syntax made the code less readable and how we can counteract this.


I was allowed to keep that in the book, though it got moved to an appendix. As time goes by I have started to wonder if I am a madman – thus far everyone I have asked says that mixing the WHY and the HOW is a no-no. The consensus seems to be that the two topics should not even be in the same book, let alone the same chapter. However to me it seems they go hand in hand.


As an example the other day I saw a series of blogs on SCN about the BUS framework for coding DYNPRO screens in an object orientated manner. That was very well written but focused solely on how to get this working. I did not spot anything about why using this framework was a Good Thing, though that may be coming along in a subsequent blog.


When trying to justify something as a Good Thing I don’t accept statements like „because it is object orientated“. I want an example of the bad way of doing things, and the good way, and it should be obvious that the good way makes things more resistant to change, or faster to develop, or some other benefit.

So when I was trying to write a book I wanted to say why these new tools were good, alongside the mechanics of how they worked. However due to the vast amount of content a lot of the WHY had to be cut in order to concentrate on the HOW.


That makes perfect sense, but just for my curiousity I would like to ask the floor – is it enough just to say how to make something work? Do the philosophical aspects have no place in SCN blogs or in „how to“ textbooks?


To Be Continued


In subsequent blogs I will continue to talk about the thought process behind how I chose what topics to include in the book, enriched with some content that was cut from the final version of the book for reasons of space.


Cheersy Cheers

 

Paul

 

https://www.sap-press.com/abap-to-the-future_3680/

 

Viewing all 948 articles
Browse latest View live


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