Is there a function module or BAPI or method that nicely performs a material/material ledger consistency check for a given material?
I am aware of report SAPRCKMU which would be very hard to use inside my own program.
I am also aware of and using function module CKML_F_CKML1_PRICES_GET which performs a consistency check.
When this function module finds an inconsistency, it calls MESSAGE E... which means I lose control in my program. This is the core problem that I have.
So I am searching a way to check consistency before I call CKML_F_CKML1_PRICES_GET in a way that gives me a return parameter with the error message without calling MESSAGE E....
I found a solution that works very well:
add the line error_message = 99 to the function module call:
CALL FUNCTION 'CKML_F_CKML1_PRICES_GET'
....
EXCEPTIONS
...
error_message = 99
others = 98.
Now the program doesn't interrupt the control flow when the function module itself uses MESSAGE E... instead of RAISE ....
Whenever MESSAGE E... is called inside, it is converted into SY-SUBRC = 99 and the error-fields in SY-... are also set.
Related
I inherited a VB.NET project that uses a module to check some user permissions.
One of the functions is called UserLevel and it makes a few calls to a hardware .dll file to read some serial numbers. The function looks like this:
Public Function UserLevel() As Integer
Dim status As Integer = userLevelWrapper.hardware.ReadInteger()
If status = 0 Then
If userLevelWrapper.readDaysLeft() > 0 Then
Return 2 'The user is a temporary user
Else
Return 0 'The user is invalid
End If
ElseIf Environment.UserName = "User1" OrElse _
Environment.UserName = "User2" Then
'There are more of these, and the user names are obviously not "User1" and "User2" because I've changed them for posting purposes.
Return 1 'The user is a developer
Else
Return 0 'The user is invalid
End If
End Function
For some reason I'm not able to step into this module when debugging. I can't figure out how it's configured, so I've had to make changes as I go and just check the result. I'm just trying to have the module tell my application that I'm a developer so I get uninterrupted use of the app. I've done this successfully by changing the UserLevel function to look like this:
Public Function UserLevel() As Integer
Return 1 'I am a developer
'All other code remains the same, and is not commented.
End Function
Because I don't have that userLevelWrapper package properly installed, I get a FileNotFoundException when actually executing the code. I assumed that happened when the Dim status As Integer... line is executed, so I altered that line to be
Dim status As Integer = 123456789 'userLevelWrapper.hardware.ReadInteger()
which will obviously force the If statement to evaluate to false. When I run it, I still get the FileNotFoundException.
I found out that the function is generating the exception because there exists a call to the hardware .dll on the 5th line where it's calling .readDaysLeft(), even though it's not being executed. When I comment that line and the .ReadInteger() call, no exception is thrown.
My question in this case is two parts:
1. Why doesn't the exception get thrown when the first line of the function is Return 1, and I haven't commented the hardware calls?
2. Why is the module trying to resolve where the file is when code is not being executed?
It makes sense to try to resolve the file at compile-time, but why is it just generating its own rules here by resolving it at run time but only under some arbitrary conditions?
It's not arbitrary.
When the code is commented out, it will not be compiled into the IL code that is translated by the JIT compiler into machine code.
When you don't comment it out, whether that branch of the code is compiled to IL or not becomes a compiler implementation detail that you can't make assumptions about. Maybe it is smart enough to know that branch will never get executed... maybe that analysis costs to much so it doesn't do it. The JIT compiler might compile your code to the machine level at a function level, in which case it will have to compile the entire function to machine code. At that time it'll need to find the assembly containing the function you call and fail.
It is possible that if you change status to a Constant the compiler might recognize that there's a branch that will never be executed and optimize it out of the IL.
I have a set of classes to which I am trying to apply unit tests, to maintain their current utility through future revisions.
My problem is that within CPPUNIT, to which I am new, where-ever I call CPPUNIT_ASSERT ( [condition] ), I am met with Error Unhandled Exception...: Access Violation at 0xffffffffffffffff.
This happens even I write the simplest test case
int main(){
CPPUNIT_ASSERT ( true );
}
I have tried calling my testing functions with manual calls, as well as adding them to a registry, as is done in the Money example. The problem reportedly arises within the constructor for SourceLine, as the filename string it expects is a bad pointer.
After a bit of a search I've found that this is called within the CPPUNIT_ASSERT, as it's a macro with the following definition
#define CPPUNIT_ASSERT(condition) \
( CPPUNIT_NS::Asserter::failIf( !(condition), \
CPPUNIT_NS::Message( "assertion failed", \
"Expression: " #condition), \
CPPUNIT_SOURCELINE() ) )
I've searched the tutorials on CppUnit's site, and scrutinised stackoverflow, but I have not found anything that addresses this in particular. I do find it strange that what is, in every example I've seen, a single-parameter function (assert), will call another function with no arguments (sourceline) that is actually another macro that is assuming it receives a string, but can receive no such thing. I found that SourceLine is a class that still has a default constructor, but above is called a macro, which really refers to the 2-parameter constructor, but is passed no arguments that I can see. I am at a loss.
I am using a 64 bit compilation of CppUnit, verified with a dumpbin, and Visual Studio 2008.
Cppunit's assertion system uses macros so it is expected that your simple example complains about unhandled exception.
Normally you don't use an assertion outside of a test method. I suggest you have a look at the Cppunit Cookbook which provides some information and examples how to effectively use cppunit.
I have a problem with the sequence model seen in the diagram below, specifically where the System object is creating a new Number. In this case, there is no need for a return message since the function SaveInput(n), both in System and Number, is the end of the line for that portion of the program, but unless I include one, the modeller reshaped my diagram into the other one I've uploaded here, and I can't see how to arrange the messages so that my program will work the way I intend without including the return message (the one without a name) from Number to System, since the functions SaveInput() both return a void.
How should void-returning functions be handled in sequence diagrams so that they behave correctly? I have opened the message properties and explicitly defined it as returning a void, but that hasn't helped.
When A calls operation b in B, the "return" arrow from B to A indicates the end of the operation b has finished its execution. This doesn´t mean that as part of the return message you have to return a value, it only means that the execution is done and you can continue with the next messages. Visually, most tools also use these return messages to manage the life bar of the object.
How do I call the SAP report (for example RSPARAM) with help JCo?
What RFC may be used to remotely call SA38 transaction with RSPARAM (e.t.c.) as parameter and then return results for later work ?
RFC is for calling function modules, not programs. It's possible to use some generic function module to start a report, but since you'll usually want to process the results of the program and the program does not know that it was meant to deliver its results in a machine-readable way, you probably won't get too far this was. What exactly are you trying to do?
With the nearly infinite possible results of calling a transaction, i don't think there is a RFC to execute such an operation and return a result. What would be the result in case of an ALV display, or if the program then wait for some interactions ?
You can display a transaction in SAP portal using transactions Iviews. You're then using the portal page as a HTMLGui for your transaction.
also, some FM can sometime be used to perform operations instead of a full program (ie HR_INFOTYPE_OPERATION instead of pa30).
regards
Guillaume
Edition : since you want the result of RRSPARAM, you could encapsulate the "important" part (form SHOW_ACTUAL_PAR_VALUES_ALV) in a module function accessible by RFC, and returning a table of CST_RSPFPAR_ALV (ie the same structure that is displayed in the report)
regards
If You don't find a function to call, just create one by yourself. Tag it as callable from outside via RFC and in the coding, perform such things as "submit report xyz with param1 = value1 ... and return ... exporting list to memory". Then you can even return list output from this. Define the interface of the freshly created function module as you need (that means, report name as input, list output as a table of strings, e.g.). Attention, there is of course a big security risk, having an remote function accepting variable reportnames. But I am sure You know :-)
I want to expose the functionality of an SAP program (transaction) as a BAPI.
I need to call a report and supply range filters such that the GUI is bypassed.
Does anyone have a working example of the SUBMIT ... WITH ... ABAP construct, or other suggestions on how to accomplish what I need to do?
Here is a working example:
SUBMIT SAPF140
TO SAP-SPOOL "optional"
SPOOL PARAMETERS print_parameters "optional"
WITHOUT SPOOL DYNPRO "optional (hides the spool pop-up)"
VIA JOB jobname NUMBER l_number "optional"
AND RETURN "optional - returns to the calling prog"
WITH EVENT = REVENT
WITH BUKRS IN RBUKRS
WITH BELNR IN lRBELNR
WITH GJAHR IN RGJAHR
WITH USNAM = SY-UNAME
WITH DATUM = SAVE_DATUM
WITH UZEIT = SAVE_UZEIT
WITH DELDAYS = RDELDAYS
WITH KAUTO = 'X'
WITH RPDEST = SAVE_PDEST
WITH TITLE = TITLE.
All the "WITH" statements relates to selection fields on the called program where I use = it is a PARAMETER statement (single field), where I use IN it is a SELECT_OPTIONS statement (range)
Here is a simple example of how to fill a range:
REFRESH lrbelnr.
lrbelnr-sign = 'I'.
lrbelnr-option = 'EQ'.
lrbelnr-low = HBKORM-belnr.
CLEAR lrbelnr-high.
append lrbelnr.
If you want to suppress this functionality as a BAPI you have to wrap the functionality in a Remote Function Call (RFC) module. Just implement a RFC function module. Depending how the report is implemented, it may use ABAP objects, which can also be called from your RFC implementation. Given that case you have a quite good solution. Whenever the report is adjusted, also your BAPI will reflect the changes. In case it's a standard programm from SAP which cannot be wrapped, think about copying it into your namespace and adjusting it. Nevertheless this might give some hassle, when SAP performs an update via Support Package Stack and you won't realize it. The output of the two methods is different. Apart from that, if you want to call it from outside, there is nothing else possible than implementing a RFC module.
A submit report can not return the values outside. Reports are always only for GUI functionalities and not for exchanging data. In case your report uses select options, you somehow have to implement this feature "by hand" in your RFC, as this statements can not be used inside RFC modules. I would generally try to rework the report, modularize it and put the selection information in a central class or maybe another function module wich can be called from the report and your BAPI function module. The filters you are talking about can not be implemented in RFCs automatically. You have to implement those ranges manually. The warning which comes up cannot be suppressed, if you do a RFC call from a remote system and the popup with the warning comes up you'll end with a shortdump. Therefore, you have to rework the report and to re-implement it for your needs.
If you are just looking for bypassing it via job scheduling, create a variant and schedule the report with that variant but I suppose that's not the solution you're looking for.
You can use inbuilt BAPI also just write "Range" and press F4.
You can wrap your report in an BATCH INPUT session and execute it inside a function. The only drawback is that you need to rewrite the BATCH INPUT every time you change the report.