Technical Articles
Custom error message for PM Order Components (iw31/iw32)
Searching User Exits and BADI
In this blog, we will look at another way to debug and find a place to enhance custom error message. Also, I am going to explain the problem we faced and the solution to it.
P.S You can read my previous blog about the enhancement for Fiori.
Problem: The customer wants to get the error message when the user tries to modify any components of the order.
Clarifying the problem: in SAP GUI run t-code IW32 -> enter test order -> and click on Components
So, if the user is not in set ZUSERS and the order type is ‘PM01’, in this case, the user shouldn’t modify the components and get the error message with the text “You are not authorized to change order components! For further information contact authorized staff.”
For solving this problem, first, we are going to find an enhancement point for this screen. We start with searching BADIs.
Method for finding BADI:
Run t-code SE24 and display class CL_EXITHANDLER -> set a breakpoint on method get_class_name_by_interface in class-method GET_INSTANCE – because of this breakpoint, we’ll be redirected to the debugger screen when we click/run any button/t-code. Just press F8 to continue.
-> Go back and run t-code IW32 -> Enter test order and open Components -> On item line add a new component -> In debug screen open exit_name value – this is a BADI for Components screen. (IWO1_ORDER_BADI) If we continue with F8 exit_name will be changed to W_RETAILSYSTEM_IDENT. It means we can implement both of these BADIs for controlling components.
To make sure that one of these BADIs is relevant to our problem we have to look through the methods of BADI and the import/export parameters of the methods.
For instance, in this BADI (IWO1_ORDER_BADI) there is AUTHORITY_CHECK_AUART_ACTIVIT which looks relevant according to its import/export parameters. But when we implement this BADI, the result of this implementation is if the user is not in ZUSERS, then the user won’t be able to even open the order. So that’s why our implementation won’t be successful. And we have the same situation in W_RETAILSYSTEM_IDENT BADI. That’s why we cannot write the error message in this BADI too.
Another method to find BADI is searching BADI using CALL BADI statement in debugger. After setting a breakpoint at statement ‘CALL BADI’ we reach the other two BADIs but according to their parameters we cannot implement these BADIs for our problem.
Because of unsuccessful implementation in BADI, we are going to search for User Exits to enhance for Components screen.
One of the ways for finding user exits is by searching exits according to their package. First, find the package of Components screen: in Components screen click on System -> Status -> double click on Program (Subdynpro) name – you can find the package name from program Attributes.
Go to SE84 and open: Enhancement -> Customer Exits -> Enhancement – execute package of Components screen. The list of user exits and their description will be displayed.
Through the package, we reach limited user exits and none of them is relevant to our problem. That’s why we explain below another method for finding user exits.
In Components screen turn on the debugger with /h and add any component. In debugger screen set a breakpoint at statement CALL CUSTOMER-FUNCTION.
Then continue with F8 and you will see the codes below:
While you continue with F8 you will see a function module with different parameters and id. For choosing the right user exit for our solution, again, we have to focus on the user exit’s parameters. For example, this exit which is shown above picture doesn’t have parameters for the error message or exception. So, we continue with F8 until we find the exit with relevant parameters.
During debugging I found these two user exits (mentioned below pictures) which look relevant according to their parameters. After finding the user exit place, our next step will be finding their name and project.
Tips: while debugging for user exits, if we click F5 to see what code is inside the user exit. If it is redirecting to include of exit it means this exit has already been implemented and has been assigned to any project, and if it’s not redirecting to the include it means it’s not implemented.
In our system, none of these user exits has been implemented and we are going to find exit name for assigning it to the project.
So, we used the exit’s import/export parameters and POPUP_FOR_INTERACTION standard function module for getting the popup.
After activating the include, function module, and project we can test it now.
All is done!
Conclusion: using these methods we can find BADI and User Exits in any standard screen and implement them. While choosing BADI or User Exits just focus on its import/export parameters and when it triggers. Because if we implement the wrong BADI or User Exits it’s not going to work and even if we write the code correctly.
Hope this will help to solve the problem you faced. You can share your thoughts about the topic in comments.
P.S. All of the pictures in this blog have taken by me from our demo system.
Thank you for this insight into the depths of old-school user exits - I wasn't aware of these inner workings. I'll keep a mental note, for future use.
One thing that makes me wonder, though. Usually these exits are documented in the implementation guide. In the case of PM/SM, for instance, you'd find a lengthy list in the IMG under "Plant Maintenance and Customer Service > System Enhancements and Data Transfer > Develop Enhancements" - but the one you've found and used above, CNEX0037, is missing from this list, at least in my ECC6 EhP 8 system. This makes me wonder if using it is really a good, i.e. sustainable idea. But as long as it works...
I also have a more general remark. In your text, you make your logic dependent on whether "the user is not in set ZUSERS". You don't really say anywhere, but I assume this is a table, right? In which you maintain a list of users that have specific rights, or functions? I have seen this done often, but in my experience this is not a particularly good idea, because you now have a parallel authorization repository which isn't in any way connected to the normal user role and authorization administration. And this makes it more difficult to understand how user rights are organized, and should therefore be avoided. Depending on the topic, this may even create issues with auditors, because chances are that for your Z table you don't have the same level of control and audit trails as you would have for ordinary authorization assignment.
An alternative approach would have been to define a custom authorization object, so that you can assign these rights to users via the normal processes.
Oh, and one more thing. Function module POPUP_FOR_INTERACTION is undocumented and unreleased. For such dialogs, I would rather use one of the officially released dialogs of function groups SPO..., e.g. POPUP_DISPLAY_TEXT. You'll be happier in the long run.
Thank you for your detailed comment.
I found directly triggered user exits by using this method. For the problem that I mentioned this method suits perfectly.
You’re right, ZUSERS is a set that contains usernames. And yes, we could use the custom authorization object method to control the rights but we know that most times the logic doesn’t depend on a developer, depends on a customer's request. 🙂
I have tested the function module you mentioned, it works fine so far. But I just wanted to show another function module that can be used which is undocumented. Thanks for your suggestions.
Thank you for this detailed guidance for us, It is really helped me for now a days. 🙂
Thanks and keep sharing Fatima Yagubova
Happy to hear that 🙂
I will, definitely. Thank you.