Beruflich Dokumente
Kultur Dokumente
On Technical/
Customizing EnterpriseOne
Overview
Business Functions (BSFNs), both C and NERs, are very tightly coupled with Interactive
Applications (APPLs) when it comes to error handling. When a function is called from an APPL,
any errors or warnings thrown by that function are immediately displayed to the user in the APPL;
and depending on which event the function was called from, may stop processing the action that
initiated the event (see Figure 1). In addition to the error message, information about the error or
warning is also displayed such as the Error ID and the functions source file and line number
where the error was thrown (see Figure 2).
Figure 1: Error Displayed in Address Book When User Tries to Delete a Record that is In
Use, and Stopping the Delete Action.
This only returns the error ID without any error message or additional error information.
Only one error ID can be returned; if there were multiple errors there is no simple way to
return the entire list of error IDs to the caller.
The error may not be thrown directly in the called function at all, but instead by a function
call made inside of the called function or even further down the call stack. More than
likely this error ID will not be returned by the top level function call made from the UBE.
Finally, and probably more importantly, most functions do not employ this work-around of
returning the error ID as a parameter. In other words, you are completely at the mercy of
the function you are calling as to whether or not you can check for errors and warnings
when the function is called from your UBE.
In this article I will show you how you can implement a simple technique to create an error
handling mechanism inside of UBEs that works much the same way the default error handling
mechanism works inside of APPLs. Additionally this tip will work with calls to any BSFN, doesnt
require any special code or return parameters by the called BSFN, and can catch any error,
regardless of where in the call stack the error is thrown.
Example
To illustrate, I have set up a very simple example; we'll
start by using this custom table I created with three
fields (see Figure 3).
Figure 3: Example Table Structure
I then created a simple APPL with a Search and Select form over the table as well as a
Headerless Detail form to add/edit the data in the table. In the Row Exited & Changed Inline
event of the Headerless Detail form, I call two functions as per the following ER code:
www.JDEtips.com
Page 2
The F0101 Get Address Book Info function will throw a warning if the passed Address Number
is not in the Address Book. The JDETipsValidateEffectiveDates function is a custom function I
created for this example that will throw an error if the Ending Effective Date is prior to the
Beginning Effective Date. For this example, I will enter in a mix of good records and erroneous
ones (see Figure 4).
www.JDEtips.com
Page 3
=======================================================================
SECTION: JDEips UBE Error Handling Example - F59JDET1 - All Fields [COLUMNAR SECTION]
(S1)
=======================================================================
OBJECT: SECTION
EVENT: Do Section
----------------------------------------------------------------------OPT: Using Defaults
F0101 Get Address Book Info
BC Address Number (F59JDET1)(AN8) -> BF mnAddressNumber
JDETipsValidateEffectiveDates
BC Beginning Effective Date - Julian (F59JDET1)(BEFD) -> BF jdBeginningEffectiveDate
BC Ending Effective Date - Julian (F59JDET1)(EEFD) -> BF jdEndingEffectiveDate
Notice that the code is identical to the code in the APPL, making the exact same function calls for
each record in the table. When we run the UBE we get the output shown in Figure 5.
Solution
Before I describe the solution to our UBE BSFN error problem, I should note that this solution was
created on tools release 8.98.4.x. I currently implement this solution in numerous UBEs running
on the 8.98.4.x tools release. I have also used this solution in Xe.
In order to catch the errors and warnings and display them in the output, we will need to write a
little Error Utility BSFN which, once created, can be used in any UBE. Because the central focus
of this article is not so much on this utility BSFN, but rather how to use it, I will give you the code
and instructions to create this utility BSFN a little later. For now we'll start with the parameters
and the documentation for each function call in the Error Utility BSFN along with detailed
instructions on how to use it in your UBEs.
www.JDEtips.com
Page 4
ALIAS
Type
In
Out
Description
mnHandle
JOBS
MATH_NUMERIC
nWarningCount
INT01
int
nErrorCount
INT01
int
nTotalCount
INT01
int
Function: JDETipsViewErrorStackIterate
Iterates the saved error stack information created by JDETipsViewErrorStackInit.
Parameter
ALIAS
Type
In
mnHandle
JOBS
MATH_NUMERIC
idCursorHandle
GENLNG
unsigned long
cEndOfList
CHAR
JCHAR
Out
Description
Pass the value returned by
JDETipsViewErrorStackInit.
cCloseCursor
CHAR
JCHAR
szErrorID
DTAI
String(10)
nErrorLevel
INT01
int
szErrorMsg
DL011
String(100)
szSourceFile
CDCFPATH
String(255)
nLineNo
INT01
int
www.JDEtips.com
Page 5
Function: JDETipsViewErrorStackFree
Frees all resources allocated by JDETipsViewErrorStackInit. Note: This does NOT free or clear
the actual error stack, it only frees the copy of the error stack created by
JDETipsViewErrorStackInit. To clear the actual error stack, please use the function
JDETipsClearErrorStack.
Parameter
ALIAS
Type
In
mnHandle
JOBS
MATH_NUMERIC
Out
Description
Pass the value returned by
JDETipsViewErrorStackInit.
Function: JDETipsClearErrorStack
Clears the actual JDE error stack of all errors and warnings.
Parameter
ALIAS
Type
cNotUsed
CHAR
JCHAR
In
Out
Description
Parameter is not used
We are now going to create the exact same UBE to display the records in our custom table and
make the exact same BSFN calls to validate the data, but we are going to add in a little code to
catch and display any errors and warnings using the function calls listed above.
The first thing we need to do is create two new group sections in our UBE. The properties for
each section are listed below:
UBE Sections for Error Display
Section Name
Section Type
Business View
Visible
Conditional
errorCheckStack
Group
None
No
Yes
errorDisplay
Group
None
Yes
Yes
ALIAS
Label
Text
Global
errorID
DTAI
Error ID
Yes
errorMsg
DL011
Msg
Yes
errorSourceFile
CDCFPATH
Source
File
Yes
errorLineNo
INT01
Line
Yes
Description
When you are done, your UBE should look something like what is shown in Figure 6.
www.JDEtips.com
Page 6
ALIAS
Scope
cEndOfList
CHAR
Event
idCursorHandle
GENLNG
Event
mnHandle
JOBS
Event
=======================================================================
SECTION: errorCheckStack [GROUP SECTION] (S3)
=======================================================================
OBJECT: SECTION
EVENT: Do Section
----------------------------------------------------------------------evt_cEndOfList
evt_idCusorHandle
evt_mnHandle
OPT: Using Defaults
VA evt_idCusorHandle = "0"
VA evt_cEndOfList = "0"
JDETipsViewErrorStackInit
VA evt_mnHandle <- BF mnHandle
While VA evt_cEndOfList is not equal to "1"
JDETipsViewErrorStackIterate
VA evt_mnHandle -> BF mnHandle
VA evt_idCusorHandle <> BF idCursorHandle
VA evt_cEndOfList <- BF cEndOfList
<Blank> -> BF cCloseCursor
RV errorID <- BF szErrorID
RV errorMsg <- BF szErrorMsg
RV errorSourceFile <- BF szSourceFile
RV errorLineNo <- BF nLineNo
If VA evt_cEndOfList is not equal to "1"
Do Custom Section(RS errorDisplay)
End If
End While
JDETipsViewErrorStackFree
VA evt_mnHandle -> BF mnHandle
JDETipsClearErrorStack
<Blank> X BF cNotUsed
www.JDEtips.com
Page 7
After every record is processed, the errorCheckStack section is called. This section will check
for any errors, and if present, output them by calling the errorDisplay section. At this point it is
worth noting that in the ER code in the Do Section event of the errorCheckStack section we
Copyright 2012 by Klee Associates, Inc.
www.JDEtips.com
Page 8
www.JDEtips.com
Page 9
The jdeErrorSetToFirstEx call sets the pointer to the first error on the error stack and repeated
calls to jdeErrorGetNextDDItemNameInfoEx iterates the error stack and returns information about the
error. I simply store this error information in JDE cache.
No doubt many of you have started to realize that the uses for these API calls and this Error
Utility BSFN are not limited to UBEs. While this is correct, there are some limitations and
differences depending on your tools release. When used in UBEs in the manner that I have
described, the behavior should be consistent across multiple tools releases and E1 versions. As
previously stated, I have used this in both Xe and 9.0. In Xe, I also used this utility BSFN (or a
version of it) inside of APPLs to interrogate the error stack in order to enhance the default error
handling of APPLs. For example, it could be used to look for a specific error ID and invoke certain
error handling logic accordingly. In Xe, in which all of our clients ran on Citrix, this Error Utility
function worked fine when called directly from an APPL running as a Win32 application.
However, when we moved to 9.0 and HTML clients, this technique no longer worked the way it
was coded in Xe. It turns out that if you call this Utility BSFN directly from an APPL running on an
HTML client, it will never return any error stack information. We were still able to use this
technique in 9.0 but it required some modification. It appears that when called from an APPL
running on an HTML client, the jdeErrorGetNextDDItemNameInfoEx API call will only return error
information for BSFN calls on the current call stack of the APPL. To use this from an APPL, you
have to create a wrapper function that calls the target function and then checks the error stack
from within the wrapper function.
www.JDEtips.com
Page 10
The following pseudo code WILL work correctly for an APPL running on an HTML client:
P4210
MyBeginDocWrapperFunction
F4211FSBeginDoc
JDETipsViewErrorStackInit
//called from wrapper BSFN - will correctly save error
stack information
//
While(no more errors)
JDETipsViewErrorStackIterate //called from wrapper BSFN
End While
//
JDETipsViewErrorStackFree
//called from wrapper BSFN
Or optionally:
P4210
MyBeginDocWrapperFunction
F4211FSBeginDoc
JDETipsViewErrorStackInit
saved error stack
//
While(no more errors)
JDETipsViewErrorStackIterate
End While
//
JDETipsViewErrorStackFree
www.JDEtips.com
Page 11
/* Alias
/* -------/* CHAR
#define IDERRcNotUsed_1
Required In
-------- ---No
Out */
---- */
*/
1L
#endif
/*****************************************
* TYPEDEF for Data Structure
*
Template Name: Free Error Stack
*
Template ID:
D59JDET1C
*
Generated:
Sun Jan 15 09:45:09 2012
*
www.JDEtips.com
Page 12
MATH_NUMERIC
mnHandle;
} DSD59JDET1C, *LPDSD59JDET1C;
/* Alias
/* -------/* JOBS
#define IDERRmnHandle_1
Required In
-------- ---Yes
X
Out */
---- */
*/
1L
#endif
/*****************************************
* TYPEDEF for Data Structure
*
Template Name: Save Error Stack State
*
Template ID:
D59JDET1A
*
Generated:
Sun Jan 15 09:45:17 2012
*
* DO NOT EDIT THE FOLLOWING TYPEDEF
*
To make modifications, use the OneWorld Data Structure
*
Tool to Generate a revised version, and paste from
*
the clipboard.
*
**************************************/
#ifndef DATASTRUCTURE_D59JDET1A
#define DATASTRUCTURE_D59JDET1A
typedef struct tagDSD59JDET1A
{
MATH_NUMERIC
mnHandle;
int
nWarningCount;
int
nErrorCount;
int
nTotalCount;
} DSD59JDET1A, *LPDSD59JDET1A;
#define
#define
#define
#define
/*
/*
/*
/*
/*
/*
IDERRmnHandle_1
IDERRnWarningCount_2
IDERRnErrorCount_3
IDERRnTotalCount_4
Alias
-------JOBS
INT01
INT01
INT01
Required In
-------- ---No
No
No
No
Out */
---X
X
X
X
*/
*/
*/
*/
*/
1L
2L
3L
4L
#endif
/*****************************************
* TYPEDEF for Data Structure
*
Template Name: Iterate Error Stack
*
Template ID:
D59JDET1B
*
Generated:
Sun Jan 15 09:45:24 2012
*
* DO NOT EDIT THE FOLLOWING TYPEDEF
*
To make modifications, use the OneWorld Data Structure
*
Tool to Generate a revised version, and paste from
*
the clipboard.
www.JDEtips.com
Page 13
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
IDERRmnHandle_1
IDERRidCursorHandle_2
IDERRcEndOfList_3
IDERRcCloseCursor_4
IDERRszErrorID_5
IDERRnErrorLevel_11
IDERRszErrorMsg_12
IDERRszSourceFile_13
IDERRnLineNo_14
Alias
-------JOBS
GENLNG
CHAR
CHAR
DTAI
INT01
DL011
CDCFPATH
INT01
Required
-------Yes
No
No
No
No
No
No
No
No
In
---X
X
X
Out */
---- */
*/
X
*/
X
*/
*/
X
*/
X
*/
X
*/
X
*/
X
*/
1L
2L
3L
4L
5L
11L
12L
13L
14L
#endif
/*****************************************
* TYPEDEF for Data Structure
*
Template Name: Set Error - DSCA
*
Template ID:
DE0022
*
Generated:
Tue May 24 17:41:04 2005
*
* DO NOT EDIT THE FOLLOWING TYPEDEF
*
To make modifications, use the OneWorld Data Structure
*
Tool to Generate a revised version, and paste from
*
the clipboard.
*
**************************************/
#ifndef DATASTRUCTURE_DE0022
#define DATASTRUCTURE_DE0022
typedef struct tagDSDE0022
{
JCHAR
szDescription[41];
} DSDE0022, *LPDSDE0022;
#define IDERRszDescription_1
1L
#endif
/*****************************************************************************
* Source Preprocessor Definitions
****************************************************************************/
#if defined (JDEBFRTN)
#undef JDEBFRTN
#endif
www.JDEtips.com
Page 14
LPVOID lpVoid,
LPVOID lpVoid,
LPVOID lpVoid,
LPVOID lpVoid,
/*****************************************************************************
* Internal Function Prototypes
****************************************************************************/
#endif
/* __B59JDET1_H */
/* B59JDET1.h file Code Listing End */
www.JDEtips.com
Page 15
/**************************************************************************
* Business Function: JDETipsClearErrorStack
*
*
Description: JDETipsClearErrorStack
*
*
Parameters:
*
LPBHVRCOM
lpBhvrCom
Business Function Communications
*
LPVOID
lpVoid
Void Parameter - DO NOT USE!
*
LPDSD59JD
lpDS
Parameter Data Structure Pointer
*
*************************************************************************/
JDEBFRTN (ID) JDEBFWINAPI JDETipsClearErrorStack (LPBHVRCOM lpBhvrCom, LPVOID lpVoid,
LPDSD59JDET1D lpDS)
{
/************************************************************************
* Variable declarations
************************************************************************/
/************************************************************************
* Check for NULL pointers
************************************************************************/
if ((lpBhvrCom == (LPBHVRCOM) NULL) ||
(lpVoid
== (LPVOID)
NULL) ||
(lpDS
== (LPDSD59JDET1D)NULL))
{
jdeErrorSet (lpBhvrCom, lpVoid, (ID) 0, _J("4363"), (LPVOID) NULL);
return ER_ERROR;
}
/************************************************************************
* Main Processing
************************************************************************/
jdeErrorClearEx(lpBhvrCom, lpVoid);
return ER_SUCCESS;
}
/**************************************************************************
* Business Function: JDETipsViewErrorStackFree
*
*
Description: JDETipsViewErrorStackFree
*
*
Parameters:
*
LPBHVRCOM
lpBhvrCom
Business Function Communications
*
LPVOID
lpVoid
Void Parameter - DO NOT USE!
*
LPDSD59JD
lpDS
Parameter Data Structure Pointer
*
*************************************************************************/
www.JDEtips.com
Page 16
www.JDEtips.com
Page 17
perr = (LPJDEERROR_RECORD)NULL;
errorRec={0};
/* 1 million test is really just there to prevent infinite loop in the event of any kind of
bug in JDE api...
if there over 1 million errors on the error stack, you have bigger issues...
*/
if(idx > 1000000)
{
jdeErrorSet(lpBhvrCom, lpVoid, (ID) 0, _J("018Y"), (LPVOID)NULL);
idReturn = ER_ERROR;
www.JDEtips.com
Page 18
www.JDEtips.com
Page 19
www.JDEtips.com
Page 20
www.JDEtips.com
Page 21
= 1;
= 1;
dsIndex[0].CacheKey[i].nOffset
dsIndex[0].CacheKey[i].nSize
dsIndex[0].CacheKey[i++].idDataType
= offsetof(D59JDET1_ERROR, idx);
= sizeof(dsCache.idx);
= EVDT_INT;
Summary
I add the error handling logic I described in this article to just about every UBE that I create that
makes Business Function calls. By implementing the techniques I describe, you too can quickly
add BSFN error handling capabilities to almost any UBE in a matter of minutes. With some slight
modification, you can display errors and invoke error handling logic in your UBEs to prevent
further processing or stop data updates and other transactional type logic. Additionally, once you
understand how the Utility Business Function works, you can implement the underlying JDE C
API calls to expand error handling capabilities in your own Business Functions and Interactive
Applications as well.
www.JDEtips.com
Page 22
Brian Oster is a JDE developer who performs three different roles at Acme Brick. Brian is the
manager of the development team, creates the code for various business needs, and architects
the system (or solution). He specializes in solutions that promote ease of use, while also following
IT best practices, such as fully normalized data models. You may contact the author at
JDEtips.Authors@ERPtips.com. Be sure to mention the authors name and/or the article title.
License Information: The use of JDE is granted to Klee Associates, Inc. by permission from J.D. Edwards World Source
Company. The information on this website and in our publications is the copyrighted work of Klee Associates, Inc. and is
owned by Klee Associates, Inc. NO WARRANTY: This documentation is delivered as is, and Klee Associates, Inc. makes
no warranty as to its accuracy or use. Any use of this documentation is at the risk of the user. Although we make every
good faith effort to ensure accuracy, this document may include technical or other inaccuracies or typographical errors.
Klee Associates, Inc. reserves the right to make changes without prior notice. NO AFFILIATION: Klee Associates, Inc.
and this publication are not affiliated with or endorsed by J.D. Edwards & Company. J.D. Edwards software referenced on
this site is furnished under license agreements between J.D. Edwards & Company and their customers and can be used
only within the terms of such agreements. J.D. Edwards is a registered trademark of J.D. Edwards & Company. JDE and
OneWorld are registered trademarks of J.D. Edwards World Source Company. WorldSoftware is a trademark of J.D.
Edwards World Source Company. PeopleSoft,the PeopleSoft logo, PeopleTools, PS/inVision, PeopleCode, PeopleBooks,
PeopleTalk, and Pure Internet Architecture are registered trademarks, and Intelligent Context Manager and The RealTime Enterprise are trademarks of PeopleSoft, Inc. Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Klee Associates, Inc. is not affiliated with or endorsed by Oracle Corporation.
www.JDEtips.com
Page 23