This page describes techniques for creating a robust application that responds appropriately to result codes and status codes received from QuickBooks. It covers the following major topics:
Your application needs to deal with three levels of error codes:
To help you create an application that integrates successfully with QuickBooks, this chapter provides some pointers on particular result codes and status codes that are especially important to monitor. This material is meant to be a starting point for how your application should handle certain error conditions. Beyond that, of course, are many application- specific concerns that cannot be anticipated here.
Error codes related to communicating with QuickBooks must be monitored and handled appropriately. The section in this chapter called “Synchronizing Data between Your Application and QuickBooks” describes a general strategy for implementing an error recovery routine that is invoked each time your application starts up. The error recovery routine checks for possible processing problems in the previous session. It is also invoked whenever certain error codes having to do with processing or communication problems are generated.
An example of an HRESULT returned by the qbXML Request Processor is:
0x80040416: If QuickBooks is not running, the company data file name must be supplied to BeginSession.
Status codes in response messages lists the HRESULTs returned by the QBFC COM API, which are very similar to those sent by the qbXML Request Processor API.
This status code deals with the message set as a whole and is returned in response to a status check or clear status. It is also returned if some specific error recovery operation is invoked and fails, such as a standard check for a valid message set ID.
Status codes (and their accompanying status message and status severity) are included in the response for each request. This chapter provides special sections describing how your application might deal with status codes related to versioning issues, and with status codes related to problems in synchronizing company data between your application and QuickBooks.
An example of a status code is:
1 | <CustomerAddRs requestID=”2” status code=”3231” statusSeverity=”Error” statusMessage=”The request has not been processed.”/> |
Status codes in response messages contains relevant error/status codes. It lists the status codes, status messages, and status severity, which are all returned as attributes in the response message for every request,
When your application integrates with QuickBooks, QuickBooks creates a log file (qbsdklog.txt)in the common files directory.
As your application interacts with QuickBooks, three categories of information are logged:
In some cases, the log file can help you to identify specific problematic fields (elements) in a request that raised an error. Sometimes the message will refer to a field or element that borders an area in error. This log information might occur, for instance, if the error occurred because a required field is missing. The following table shows an example of a log file.
Date and time | Level | PID | SDK component | Event message |
---|---|---|---|---|
20011107.145109 | I | 1884 | RequestProcessor | Started Connection |
20011107.145109 | I | 1884 | RequestProcessor | Connection opened by app named ‘SdkTest’ |
20011107.145109 | I | 1884 | CertVerifier | The file does not contain an Authenticode signature. |
20011107.145109 | I | 1884 | RequestProcessor | Opening the file in the DoNotCare mode. |
20011107.145120 | I | 1936 | QBSDKProcessRequest | Application named ‘SdkTest’ starting requests (process 1884). |
20011107.145122 | I | 1936 | QBSDKMsgSetHandler | QUERY: Invoice |
20011107.145128 | I | 1936 | QBSDKMsgSetHandler | Request 234578 completed successfully. |
20011107.145128 | I | 1936 | MsgSetHandler | Finished. |
20011107.145128 | I | 1936 | QBSDKProcessRequest | Application named ‘SdkTest’ finishing requests (process 1884), ret = 0. |
20020219.144648 | I | 393 | SpecVersion | Current version of qbXML in use: 3.0 |
20011107.145129 | I | 1884 | RequestProcessor | Connection closed by app named ‘SdkTest’ |
20011107.145129 | I | 1884 | RequestProcessor | Ended Connection |
The following checklist summarizes important tasks your application must address in order to work with multiple versions of QuickBooks:
At runtime, your application needs to determine what versions of qbXML are supported by the version of QuickBooks that is processing your requests. Once it determines the current version, it should then load the appropriate prolog citing the correct version of the qbXML specification. (Or, if your application is using QBFC, it should create a message set request that corresponds to the correct version of the QuickBooks Request Processor.) The following two code examples (one for qbXML and one for QBFC) illustrate the tasks your application must complete in order to accommodate any version of QuickBooks that might be running when your application is launched.
The following code excerpt contains two functions. The first function (qbXMLLatestVersion) shows using the HostQuery function to obtain the supported versions of the QuickBooks Request Processor that are currently running. It then loops through the versions to determine the highest supported version.
The second function (qbXMLAddProlog) then adds the qbXML prolog that corresponds to this latest version of the QuickBooks Request Processor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | Function qbXMLLatestVersion(rp As requestProcessor, ticket As String) As String Dim strXMLVersions() As String 'Create a DOM document object for creating our request. Dim xml As New DOMDocument 'Create the QBXML aggregate Dim rootElement As IXMLDOMNode Set rootElement = xml.createElement("QBXML") xml.appendChild rootElement 'Add the QBXMLMsgsRq aggregate to the QBXML aggregate Dim QBXMLMsgsRqNode As IXMLDOMNode Set QBXMLMsgsRqNode = xml.createElement("QBXMLMsgsRq") rootElement.appendChild QBXMLMsgsRqNode Dim onErrorAttr As IXMLDOMAttribute Set onErrorAttr = xml.createAttribute("onError") onErrorAttr.Text = "stopOnError" QBXMLMsgsRqNode.Attributes.setNamedItem onErrorAttr 'Add the HostQuery aggregate to QBXMLMsgsRq aggregate Dim HostQuery As IXMLDOMNode Set HostQuery = xml.createElement("HostQueryRq") QBXMLMsgsRqNode.appendChild HostQuery 'Add a lowest-common-denominator prolog' Dim strXMLRequest As String strXMLRequest = _ " <?xml version=""1.0"" ?>" & _ " <!DOCTYPE QBXML PUBLIC '-//INTUIT//DTD QBXML QBD 1.0//EN'_ 'http://developer.intuit.com'>" _ & rootElement.xml Dim strXMLResponse As String strXMLResponse = rp.ProcessRequest(ticket, strXMLRequest) Dim QueryResponse As New DOMDocument 'Parse the response XML QueryResponse.async = False QueryResponse.loadXML (strXMLResponse) Dim supportedVersions As IXMLDOMNodeList Set supportedVersions = QueryResponse.getElementsByTagName("SupportedQBXMLVersion") Dim VersNode As IXMLDOMNode Dim i As Long Dim vers As Double Dim LastVers As Double LastVers = 0 For i = 0 To supportedVersions.length - 1 Set VersNode = supportedVersions.Item(i) vers = VersNode.firstChild.Text If (vers > LastVers) Then LastVers = vers qbXMLLatestVersion = VersNode.firstChild.Text End If Next i End Function 'Get an XML prolog that is appropriate for the latest version of qbXML Function qbXMLAddProlog(supportedVersion As String, xml As String) As String Dim qbXMLVersionSpec As String If (Val(supportedVersion) >= 2) Then qbXMLVersionSpec = " <?qbxml version=""" & supportedVersion & """?>" ElseIf (supportedVersion = "1.1") Then qbXMLVersionSpec= " <!DOCTYPE QBXML PUBLIC '-//INTUIT//DTD QBXML QBD " _ & supportedVersion & "//EN' 'http://developer.intuit.com'>" Else MsgBox "You are apparently running QuickBooks 2002 Release 1, we strongly recommend that you use QuickBooks' online update feature to obtain the latest fixes and enhancements", vbExclamation qbXMLVersionSpec = " <!DOCTYPE QBXML PUBLIC '-//INTUIT//DTD QBXML QBD " _ & supportedVersion & "//EN' 'http://developer.intuit.com'>" End If qbXMLAddProlog = " <?xml version=""1.0""?>" & vbCrLf & qbXMLVersionSpec & xml End Function |
This example parallels the preceding example, but uses QBFC syntax. The first function (QBFCLatestVersion) determines the highest version of QuickBooks that is currently running. The second function (GetLatestMsgSetRequest) creates a message set request for the current version of QuickBooks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | Function QBFCLatestVersion(SessionManager As QBSessionManager) As String Dim strXMLVersions() As String Dim msgset As IMsgSetRequest 'Use oldest version to ensure that we work with any QuickBooks (US) Set msgset = SessionManager.CreateMsgSetRequest(1, 0) msgset.AppendHostQueryRq Dim QueryResponse As QBFC2Lib.IMsgSetResponse Set QueryResponse = SessionManager.DoRequests(msgset) Dim response As QBFC2Lib.IResponse ' The response list contains only one response, ' which corresponds to our single HostQuery request Set response = QueryResponse.ResponseList.GetAt(0) Dim HostResponse As IHostRet Set HostResponse = response.Detail Dim supportedVersions As IBSTRList Set supportedVersions = HostResponse.SupportedQBXMLVersionList Dim i As Long Dim vers As Double Dim LastVers As Double LastVers = 0 For i = 0 To supportedVersions.Count - 1 vers = Val(supportedVersions.GetAt(i)) If (vers > LastVers) Then LastVers = vers QBFCLatestVersion = supportedVersions.GetAt(i) End If Next i End Function 'QBFC: Get a MsgSetRequest that supports the latest possible version 'of qbXML Public Function GetLatestMsgSetRequest(SessionManager As QBSessionManager) As IMsgSetRequest Dim supportedVersion as String supportedVersion = QBFCLatestVersion(SessionManager) If (Val(supportedVersion) >= 3) Then Set GetLatestMsgSetRequest = SessionManager.CreateMsgSetRequest("US", 3, 0) addr4supported = True ElseIf (Val(supportedVersion) >= 2) Then Set GetLatestMsgSetRequest = SessionManager.CreateMsgSetRequest("US", 2, 0) addr4supported = True ElseIf (Val(supportedVersion) = 1.1) Then Set GetLatestMsgSetRequest = SessionManager.CreateMsgSetRequest("US", 1, 1) Else MsgBox "You are apparently running QuickBooks 2002 Release 1, we strongly recommend that you use QuickBooks' online update feature to obtain the latest fixes and enhancements", vbExclamation Set GetLatestMsgSetRequest = SessionManager.CreateMsgSetRequest("US", 1, 0) End If |
If your application takes advantage of features added in later versions of QuickBooks that are unsupported in earlier versions (for example, transaction Modify requests), it needs to control what will happen when it is running against one of the earlier versions of QuickBooks that does not contain the later functionality.
The following QBFC function is an example of a useful way to test for support of a particular version and then branch according to the version support currently available. For example, you could place this function at the beginning of the application and then check the Boolean value set by the function when support for Version 2.0 is required. The CustomerAdd example included in the QuickBooks SDK uses this function to check whether Version 2.0 is supported. If it is, the application sets the value for Addr4 (a 2.0 feature). If not, it does not set the Addr4 value.
1 2 3 4 5 | Dim booSupports2dot0 as boolean booSupports2dot0 = False Dim supportedVersion As String supportedVersion = QBFCLatestVersion(SessionManager) If (val(supportedVersion) >= 2.0) Then booSupports2dot0 = True Set requestSet = SessionManager.CreateMsgSetRequest("US",3,0) End If |
If your application requires use of a new feature, it should display an appropriate error message and deal gracefully with earlier versions of QuickBooks that do not contain the feature. The following qbXML example shows checking the version and exiting when appropriate QuickBooks support is unavailable.
1 2 3 4 5 6 7 8 9 | Dim supportedVersion As String supportedVersion = qbXMLLatestVersion(qbXMLRP, ticket) If (val(supportedVersion) < 2.0) Then MsgBox "This sample requires support for qbXML 2.0 or later (QuickBooks 2003 or later) " & _ "Expect a parsing error when attempting to send requests to QuickBooks", _ vbExclamation End If |
In most cases, an actual application would not need to take the drastic measure of exiting; it would deal gracefully with the version issues and alert the user that it cannot integrate successfully with QuickBooks.
An important feature of every robust application is error recovery. Details on implementing error recovery are provided in Error recovery.
If your application maintains a database or internal file that stores portions of data from the QuickBooks company file, the application needs to ensure that the two sets of data are synchronized with each other. Event notification, described in Subscribing to events and processing event notifications, is a useful way to maintain synchronization.
There are two main actions that lead to a lack of synchronization:
In the first case, your application might need to update the QuickBooks version of the company file to reflect the changes made by your application to that data. Before you update the QuickBooks file, be sure to query the user and obtain his or her approval.
In the second case, your application would need to update its own database to reflect the changes made in the QuickBooks company file.
The following status codes indicate a problem with data synchronization. Your application also needs to check for these status codes and take appropriate action if it receives them.
1 | > 3120 Object not found. Object <value> specified in the request cannot be found. |
Your application attempted to modify an object that it previously added to QuickBooks or that it obtained using a Query request, and the application received an error stating that the object doesn’t exist. At this point, your application might enter its synchronization routine to attempt to determine whether the object was intentionally deleted by the user or whether the company file was restored.
1 | > 3140 Reference not found or 3130 Parent reference not found |
If your application received one of these messages and it had previously referenced the object successfully, there is the possibility that the object was intentionally deleted or that the company file was restored. Your application would need to take some action to ensure that the error condition didn’t occur again because the referenced object no longer exists.
1 | > 3240 Time creation mismatch. File has been restored. |
If the company file was restored, your application could receive this message, for example, after issuing a modify request for an object that it previously added, specifying the ListID assigned to the object and returned by QuickBooks. Because the user restored a version the company file that pre-dates addition of the object, the ListID (and the object it pertains to) do not exist. This message unambiguously indicates that the user restored the company file. Your application needs to take appropriate action to re-sync its data with QuickBooks.
The following example outlines a useful procedure for keeping data in sync, based on the following requests:
Suppose an application requires a list of active customers and needs to keep this list in sync with the list contained in the QuickBooks company file. The application uses the ListID as the primary key of the customer records because the ListID, unlike the FullName, is guaranteed not to change.
The first time the application connects to QuickBooks, it needs to obtain the entire active customer list. The following figure shows the steps for using this request to synchronize the data. Immediately before this request, the application needs to obtain and record the date and time of this action. In this example, this date/time is referred to as the last sync datetime.
The following example shows the request:
1 2 3 | <CustomerQueryRq requestID = "UUIDTYPE"> <ActiveStatus>ActiveOnly</ActiveStatus> </CustomerQueryRq> |
Note that since the default ActiveStatus value is Active Only, that field could actually have been omitted from the above.
Periodically, the application needs to re-sync its data with QuickBooks.
To do so, it first issues a Company ActivityQueryRq to obtain the LastRestoreTime:
Request that checks for customers that have been added, modified, or deleted:
1 2 3 4 5 6 7 8 9 10 | <CustomerQueryRq requestID = "1"> <ActiveStatus>All</ActiveStatus> <FromModifiedDate> last sync datetime</FromModifiedDate> </CustomerQueryRq> <ListDeletedQueryRq requestID = "2"> <ListDelType>Customer</ListDelType> <DeletedDateRangeFilter> <FromDeletedDate> last sync datetime </FromDeletedDate> </DeletedDateRangeFilter> </ListDeletedQueryRq> |
Based on the CustomerQuery response, the application needs to add or refresh existing customer records, matching ListIDs from the response to the cached list. Note that the response also contains the Inactive customers so that the customers that have changed status from Active to Inactive can be taken out of the list. The Inactive customers that are returned and not found in the cached list should be ignored, since the sample shows keeping the active customer list in sync. Next, based on the ListDeletedQuery response, the application needs to remove customer records that are no longer necessary.
There are a few considerations and limitations to the synchronization process described above. Be aware that ListDeletedQueryRq returns only elements deleted for the previous three months. If the most recent re-sync happened more than three months ago, a full synchronization is necessary.
Unlike single-user mode, in multi-user mode, the QuickBooks recorded modification time is the time of the system where the data file resides, not the time of the system where QuickBooks is running. The clocks on these two systems (that is, the clock on the system where the data file resides and the clock on the system that runs the QuickBooks executable file and runs the SDK requests) may be out of sync. To account for such differences, it is strongly recommended that you expand the query time range and move the “last sync datetime” a few hours in the past. The application needs to be prepared to deal with response duplicates that have already been taken into account in the previous sync as a result of this time overlap.
Depending on what data you want to keep in sync, you may need to re-fetch the entire list every time you want to re-sync because the list of list objects or transactions that have been modified since the given “last sync datetime” is not accurate.
Examples are:
Your application should always interact with the user before modifying the QuickBooks version of the company file as a result of synchronization problems. How you do this is application-dependent.
If your application discovers that the QuickBooks company file has been restored, then you might want to prompt the user further to inquire whether the user would like you to update the company file in QuickBooks to reflect the more recent changes stored in your application’s database.This interaction lets the user know about new information that might otherwise be confusing.
For instance, you might present a window that includes a question similar to this one: