Subscribing to events and processing event notifications

An application that is integrated with QuickBooks via the SDK may need to be notified about actions occurring in a QuickBooks company file, including actions that add or change data values, at the time when the actions occur. These actions are referred to as events, and the SDK recognizes three types of events:

Any QuickBooks list or transaction object that is supported by the SDK is also supported by the event notification framework, and can be a source of data events.

Your application can receive notification about data events whether the changes are made directly in the QuickBooks UI or programmatically by an integrated application.

The event mechanism described on this page operates only when a company file has been opened in interactive mode through the QuickBooks UI. If QuickBooks is run in auto-login mode, also called unattended mode, event notifications are not sent to subscribing applications. (Auto-login mode is used where applications access company files without the QuickBooks UI running.)

Note

Note

Events are not supported for QuickBooks Simple Start edition or through QuickBooks Web Connector.

Event subscribing and processing workflow

For all three types of events, the workflow is the same:

  1. The application sends a request message that subscribes it to one or more events.
  2. The subscription request is authorized by the QuickBooks administrator.
  3. The application is notified, via a QBXMLEvents message, that a subscribed event has occurred.
  4. The application processes the content of the QBXMLEvents message.
qbdesktop/docs/develop/tutorials/Image_253.gif

The application receiving the events handles them in a callback, as described later on this page.

Development time and deployment time steps

To achieve the behavior described above, your development process should include all the following steps, in approximately the listed order:

  1. Identify any events that are required by the functionality of your application.
  2. Develop the callback logic for handling messages that notify of those event.
  3. The callback logic must be implemented as follows:
    • The callback logic must be contained in an implementation of the IQBSDKCallback class and its Inform method.
    • To create an IQBSDKCallback implementation, you must import one of the libraries that support event processing.
    • The callback logic must be packaged as an .exe (not a DLL)
    • The callback .exe must be registered with a CLSID or PROGID, because the subscription request will identify it by its CLSID or PROGID, and QuickBooks will address event notifications to the CLSID or PROGID specified in the subscription request.
  4. The subscription request must be written to identify the callback portion of your application

In addition to developing the callback logic and the subscription request message, you need to consider how the callback portion of your application will be registered at deployment time, and how the subscription request will be sent to QuickBooks. The key point here is that the event-handling (callback) logic must be registered with its CLSID or PROGID before the subscription request is sent. A typical way to do this is described below. The documentation you supply with your application should instruct the QuickBooks installer/administrator how to perform the installation and authorization:

  1. Your installation procedures would install and register the callback application.
  2. On first start-up, or as part of completing the installation, the application can issue the subscription request.
  3. When QuickBooks receives the subscription request, it will open the authorization dialog, and the QuickBooks administrator can approve the necessary authorization.

Again, the key points are to prepare a deployment procedure that registers the callback portion of your application before the subscription request is issued, and to supply the QuickBooks administrator/installer with sufficient documentation do the correct things during installation and setup.

Developing the callback application for processing events

In order to process events, your callback application must implement the required COM interface and it must account for the range of expected event behaviors. The COM interface is defined in the file SDKEvent.dll, located in the QuickBooks install directory.

Importing the required libraries

In addition to implementing the callback class, you must import the required event library into the project that implements the callback.

1
#import "sdkevent.dll"

in the header file for the callback.

In Microsoft Visual Studio, remember to specify the QuickBooks executable path for the project. The methods for doing this is different for Visual Studio 6.0 and Visual Studio.NET:

Adding the IQBEventCallback callback class to an application

The event notification framework uses COM to notify applications about events. Accordingly, for an application to receive notification messages about events it subscribes to, it must contain in implementation of the SDK’s COM interface for events – IQBEventCallback. As already mentioned above, the callback .exe must be registered before and event subscription requests are sent to QuickBoooks.

Note

Note

In-process COM servers are not allowed, only out-of-process local servers. Therefore, the requirement to implement the callback class in an .exe, not in a DLL.

You need to implement your callback logic in the Inform method defined in the the IQBEventCallback interface (IQBSDKCallback::Inform). The inform method returns the event notification string in XML format. The following is the virtual method signature for IQBSDKCallback::Inform:

1
virtual HRESULT stdcall inform (/*[in]*/ BSTR eventXML ) = 0;

If you use Visual Basic, you need to implement it by adding these lines,

1
2
Implements QBSDKEVENTLib.IQBEventCallback
Public Sub IQBEventCallback_inform(ByVal eventXML As String)

followed by your callback implementation code.

Other considerations for implementing the callback logic

Some other things to keep in mind as you develop a callback implementation are covered below.

Specifying a CLSID and/or PROGID for the callback class

In the subscription code you must supply the class ID (CLSID) or PROGID for the callback class. QuickBooks uses the CLSID/PROGID to invoke your application’s callback method when a subscribed event occurs.

In some programming languages you can use the PROGID instead of CLSID. For VB projects, the PROGID is the ’<Name of Project>.<Name of COM class>.

Note

Note

If you use CLSIDs in VB, you must set the VB project properties for binary compatibility or this value will change every time you compile and the CLSID won’t match the one expected by QuickBooks. You must remember to do this because the VB default for projects does not use binary compatibility.

To set binary compatibility, open your project, select the Project pull-down menu, and click on your application’s properties at the bottom of the pull-down. In the ensuing properties window, select the Component tab. In the ensuing tab window, select the option Binary Compatibility and click OK.

Determine which delivery policy your callback supports

DeliveryPolicy determines whether QuickBooks will start your callback application when the application is not running. If your application specifies a delivery policy of “deliver always” then it will start up (if not running already) upon receiving the first subscribed QuickBooks event notification. If the subscription specifies “deliver only if running” then any events occurring when the application is not running are not delivered but are marked as “lost events.”

Regardless of the delivery policy, once your callback application starts, you should be aware that QuickBooks doesn’t release that callback application’s COM pointer until the company file closes. The callback application therefore cannot be dismissed by the user. So if you use a UI for your callback, you need to design the UI to handle this.

If your application needs to distinguish between being started by QuickBooks and being started by the user, you should add a command line argument to the shortcut for the .exe, because QuickBooks never passes a command line argument when starting the application.

If your application subscribes with a delivery policy of “deliver only if running,” then you may want to implement lost event handling, as described in Recovering from lost data events.

What to do and what to avoid in the callback

Your implementation of the IQBEventCallback routine should do minimal processing and should return quickly. Why is this a design requirement? First, your callback application cannot receive any other events until you return from your callback. Instead, QuickBooks maintains such events (except company file close) in a queue in the order in which they occur.

Once you return from the callback, QuickBooks will send the next event from this queue. It is therefore recommended that if the application needs to display some UI in the callback, it should choose to use non-blocking UI calls instead of blocking UI calls, so that the callback method can return without delay.

The queue contains a limited number of events. If the queue becomes full, events are no longer delivered to your application but are marked as lost events. If this is happening, your application is not processing events fast enough.

Note

Note

Even though your application does not receive more events until it has returned from its callback method, during this time other applications are free to receive events and QuickBooks itself is able to function normally. (QuickBooks can handle UI actions from the user, as well as SDK requests.)

Another reason for performing minimal processing in the callback implementation is that the callback application must be able to respond quickly to a company file close event.

If your callback makes SDK queries into QuickBooks, rather than caching the Request Processor pointer, we recommend that you make the BeginSession and EndSession calls within the callback.

What the Callback implementation cannot do

In your implementation of the IQBEventCallback::Inform callback routine, you cannot invoke any QuickBooks SDK request that writes immediately to the QuickBooks company file, if the callback is a data event callback. As a result, you can only issue query requests, as well as make subscription changes, since they aren’t immediately written to the company file. The only exception to this is that you can also perform a DataEventRecoveryInfoDel request during a callback. See Recovering From Lost Data Events for information on data event recovery.

Also, in a data event callback, you cannot invoke the QuickBooks UI, that is, post some QuickBooks form.

Finally, you should not make SDK requests in the callback for company close events.

Avoiding infinite loops

As noted above, an application is prevented from making data modifying requests in its callback routine. This is done to help avoid an infinite recursion problem, for example, where applications A and B each modify data in its callback that the other listens to, thus becoming locked in an infinite recursion.

Consequently, as much as possible, you should avoid writing to QuickBooks in direct response to events.

For ideas on how to work with these concerns, see the three sample set under \samples\qbdt\vb\qbxml\DataEvents.

What kind of information is contained in an event notification?

When a subscribed event occurs, your application’s callback routine receives the event in the form of a qbXML aggregate, QBXMLEvents, which contains one of three sub-aggregates based on the type of event that occurred: DataEventRet, UIExtensionRet, and UIEventRet.

The path to the company file is included in all three types of event notifications. In addition, the following is included:

See the API Reference for a complete listing of the possible contents of the QBXMLEvents aggregate.

Example: implementing a qbXML-based callback (IQBEventCallback)

The callback that handles the incoming QuickBooks events must be an implementation of the SDK-defined callback interface, IQBEventCallback. This callback accepts the event XML string sent by QuickBooks and does whatever handling is desired. The best way to handle events is to hand them off to another application for queuing and processing.

Other than the Implements statement and the required input parameter, there are no restrictions on your callback other than the ones described above.

The following sample is excerpted from a more fully commented sample in the SDK called QBDataEventSubscriber, which is located at the QBSDK subdirectory (\samples\qbdt\vb\qbxml\DataEvents\QBDataEventManager).

The main items to take away from the sample are:

 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
Implements QBSDKEVENTLib.IQBEventCallback
Public Sub IQBEventCallback_inform(ByVal eventXML As String)

' You should treat this like interrupt handling in an OS, where
' you process the interrupt (event) as quickly as possible
' Display the event we received
Dim tmpXML As String tmpXML = eventXML
EventCounter = EventCounter + 1
QBDataEventManagerDisplay.eventXML.Text = Replace(tmpXML, vbLf, vbCrLf, 1, -1, vbTextCompare)
QBDataEventManagerDisplay.eventLabel.Caption = "Received Event #" & EventCounter
QBDataEventManagerDisplay.Show
SetForegroundWindow QBDataEventManagerDisplay.hwnd

'Now check if it is a company close event or a data event
If (InStr(1, eventXML, "CompanyFileEventOperation>Close<", vbTextCompare) > 0)
  Then
  'Company close, shut ourselves down
  QBDataEventManagerDisplay.Hide
  Unload QBDataEventManagerDisplay
End If

'Queue it up if we are supposed to be tracking events.
If (QBDataEventManagerDisplay.Tracking) Then
  QBDataEventManagerDisplay.Debug.Text = "Queing event #" & EventCounter
  QBDataEventManagerDisplay.EventQueue.EnQueue
(eventXML)
End If
End Sub

Event behavior you should be aware of

The following subsections describe some event behaviors that you should be aware of when you design and implement a callback application.

Can the user dismiss the callback application?

QuickBooks doesn’t release a callback application’s COM pointer until the company file closes. Consequently, if the callback application has a UI that can be dismissed by the user, you should be aware that the callback app doesn’t really go away. It goes away only when the company file closes. If you use a UI for your callback, you need to design the UI to handle this.

Do applications receive events from their own requests?

Beginning with SDK 4.0, an application can choose not to receive its own data events when it makes its subscription. By default, however, applications do receive subscribed-to events for QuickBooks activity resulting from the application’s own add/mod/delete activities within QuickBooks. To avoid receiving your own events, set the DeliverOwnEvents field to False in the DataEventSubscriptionAdd request. You definitely want to do this when event notifications are being delivered to a different executable than the subscribing executable.

Indirect events

You should be aware that some QuickBooks actions may generate multiple events if the action affects different QuickBooks objects. For example, adding a new invoice in QuickBooks also affects accounts. Accordingly, when there is an InvoiceAdd event, there could be multiple AccountMod events.

Are events generated from custom fields and private data extensions?

If an end user adds or changes data in a custom field via the QuickBooks UI, or if an integrated application successfully issues a DataExtAdd or DataExtMod request for a custom field or private data extension, a Mod event is generated for the parent object, and the Time Modified value for the parent object is updated. For example, if a Customer has a custom field called “shoe size,” modifying the value of that custom field generates a Customer mod event and causes an update to the customer’s Time Modified field.

Can applications receive events from remote machines?

An application running on one machine with QuickBooks generally receives events only from events generated by that local QuickBooks. The application won’t receive events generated by interactive users sharing the same company file on other machines or by SDK clients running on other machines. If you need to track those remotely-made changes in the company file, you can can use the event recovery mechanism described under Recovering From Lost Data Events.

However, you should be aware that if the local QuickBooks needs to refresh its view of an object, because it is being edited locally, or because a list is being refreshed, or because an SDK client issues a query request, then events may be delivered that came from other machines.

Authorizing a callback application to receive events

The QuickBooks UI for authorizing an application to receive data, UI, and UI extension events is the same as for regular SDK calls. Notice that the QuickBooks UI prompts for permissions based on the callback’s certificate if it has been signed or the AppName specified in the subscription XML if the callback is not signed.

Once an application is authorized to access QuickBooks via the SDK, the application automatically has permission to receive event notifications. Similarly, once an application is authorized to receive events, it is automatically authorized to access QuickBooks via the SDK.

However, there is one difference worth noting. With standard SDK requests, when the user has chosen to be prompted before allowing access, a prompt will be displayed at each call to BeginSession. With events, when this same access level is chosen, a prompt will also be displayed each time the company file is opened in attended mode. Then, if the user grants the application permission by selecting “Yes, Always,” the application will receive events in future sessions without prompting. If the user selects “Yes, This time,” the application will receive events for as long as that company file remains open. If the user selects “Yes, Always,” the application will not be prompted in future sessions. In your documentation and messaging to your user, you should recommend that they choose “Yes, Always” as this will provide the best user experience.

If the company file is opened in unattended mode, a prompt will not be displayed and no events will be sent to the application while that company file remains open.

Security and Certification

If your application is digitally signed, as described in Digitally signing your code, QuickBooks verifies that the correct application is receiving the notification to which your application is subscribed.

QuickBooks reads, encrypts, and stores the certificate information from the callback executable when the subscription request is made. Then, starting the callback application, QuickBooks reads the signature information from the callback executable that is about to be notified and makes sure that it matches the information that was read when the subscription request was made.

If the certificate is invalid or revoked, QuickBooks silently fails to start the application and an error is logged because it is considered disruptive to tell the user in the UI (which is what regular SDK requests do) in this case.

If the certificate is expired, and the user has chosen to be prompted about expired certificates, QuickBooks will also silently fail to start the application. However, if the user hasn’t chosen to be prompted about expired certificates, or has previously allowed access to an application even though it is expired, then the application will continue to receive events.

If the information does not match (meaning that the executable has been replaced), no notification will be sent, and for UI extensions an error dialog will be displayed (the same one that’s shown when the notification fails for any other reason).

If your application is not digitally signed, the SDK will send notification events without any verification.

Using the C# app template to implement event handling

The QB SDK includes an application template wizard that generates a great deal of the event code you need or may want to implement. It does a lot of the heavy lifting for you and we strongly recommend using this if you can. The information in this chapter is still useful background information, but the template will save you LOTS of time and potential mistakes. The template is for Visual Studio 2005 and later and works for C# applications. If you have VS 2005, this will be automatically installed for you in the templates directory.

For more information see “C# Project Wizard” in the QB SDK program group accessed from the Windows Start menu.

Event subscription request messages

The following requests are available for managing event subscriptions.

Name Description
DataEventSubscriptionAdd Adds one or more subscriptions to the specified QuickBooks data events.
DataEventSubscriptionQuery Queries for subscriptions by SubscriberID and qbXML version.
SubscriptionDel Deletes all subscriptions matching subscriber ID and qbXML version.
UIEventSubscriptionAdd Adds one or more subscriptions to the specified QuickBooks UI events.
UIEventSubscriptionQuery Queries for subscriptions by SubscriberID and qbXML version.
UIExtensionSubscriptionAdd Adds one or more subscriptions to the specified QuickBooks UI extension events.
UIExtensionSubscriptionQuery Queries for subscriptions by SubscriberID and qbXML version.

These requests are documented in the qbXML messages reference.

Your callback application receives all event notifications in the form of QBXMLEvents messages.

QBFC subscription request

If you use QBFC, instead of calling QBSession manager to create a MsgsSetRq, call SessionManager. CreateSubscriptionMsgSetRequest() you must append the subscription request to an ISubscriptionMsgSetRequest object instantiated by the QBSessionManager methodand invoke the method DoSubscriptionRequests().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
‘ Build a 6.0 request set and create a data ext def add request
Dim SubscriptionMessageSet As ISubscriptionMsgSetRequest
Set SubscriptionMessageSet = SessionManager.CreateSubscriptionMsgSetRequest("US", 6, 0)
SubscriptionMessageSet.Attributes.OnError = roeContinue

‘ Request will write to the custom field "Category" using a DataExtMod message
‘ (For private data, our first write to an object’s data ext MUST be a DataExtAdd)
Dim EventSubscriptionAdd As IDataEventSubscriptionAdd
Set EventSubscriptionAdd = SubscriptionMessageSet.AppendSubscriptionAddRq

‘ Now send the request to QuickBoooks
Dim EventSubscriptionAddRs As ISubscriptionMsgSetResponse
Set EventSubscriptionAddRs = SessionManager.DoSubscriptionRequests(SubscriptionMessageSet)
SessionManager.EndSession
SessionManager.CloseConnection
Set SessionManager = Nothing

qbXML subscription request

If you use qbXML, you must invoke the requests to add, query, and delete subscriptions using the request processor’s ProcessSubscription method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?xml version="1.0" ?>
<?qbxml version="6.0"?>
<QBXML>
  <QBXMLMsgsRq onError = "stopOnError">
    <DataExtModRq requestID = "0">
      <DataExtMod>
        <OwnerID>0</OwnerID>
        <DataExtName>Category</DataExtName>
        <ListDataExtType>Customer</ListDataExtType>
        <ListObjRef>
          <FullName>John Sidmark</FullName>
        </ListObjRef>
        <DataExtValue>Gold Member</DataExtValue>
      </DataExtMod>
    </DataExtModRq>
  </QBXMLMsgsRq>
</QBXML>

Note

Note

You cannot invoke QBXMLEvent, since that is a return-only message.

Subscription request parameters

You need to supply the following information in your subscription requests:

Information Description
Callback application name The name of the application that contains the callback that handles the events.
CLSID (or PROGID)

You must assign a CLSID (or a PROGID, depending on the programming language that you use and your own preferences) for the callback class that implements the SDK interface IQBEventCallback. The CLSID or ProgID must be registered in the Windows registry before the subscription request can be made successfully.

Notice that you can only have one CLSID/PROGID per SubscriberID. For example, if you use the same SubscriberID to subscribe to data event, UI event, and UI extension events, then you will also need to specify the same CLSID.

If you want multiple CLSIDs for your application (perhaps because you want one EXE to handle data events, another EXE to handling UI events, and still another EXE to handle UI extension events), you use a different SubscriberID to subscribe to each event type

DeliveryPolicy

You need to specify the QBFC or qbXML value for “deliver only if running” if you want your application to receive events only when it is running.

Specify the QBFC or qbXML value for “deliver always” if you want your application to be started up to receive the incoming events if the application isn’t running. Notice that the callback will be started up only once during the QuickBooks session.

The actual values specified vary depending on whether QBFC or qbXML is used.

subscriberID This is a GUID that you must create for your application. You also use this value whenever you query or delete subscriptions.
TrackLostEvents

For data events only. Specify the QBFC or qbXML value for “all” if you want a DataEventRecoveryTime to be recorded when there is a lost event. You would do this if you wanted to implement lost event recovery, as described lower on the page in “Recovering From Lost Data Events”.

Specify the QBFC or qbXML value for “none” if your application does not care about lost events.

How QuickBooks handles subscription requests

Once your application is subscribed, your application will receive all the specified events. For example, if it is subscribed to CustomerAdd events it will receive notifications whenever a new customer is added in QuickBooks to any company file.

When does a subscription go into effect?

QuickBooks does not need to be running when you subscribe and unsubscribe an application. Notice that the subscribe or unsubscribe does not go into effect immediately, however. For data and UI events, the subscribe/unsubscribe goes into effect when the company file is next opened by QuickBooks. (Consequently, when you subscribe or unsubscribe, you should notify the user to reopen any company files that are currently open.) For UI extension events, the subscribe/unsubscribe goes into effect when QuickBooks is next started.

How qbXML versioning is handled in subscription requests

The event data that is returned can potentially differ depending on the qbXML version. For example, in the 4.0 qbXML spec, there is a new tag that could be returned in the QBXMLEvent response called CurrentWindow. If an application is designed for the 3.0 spec but not the 4.0 spec, how is this situation handled?

Beginning with SDK 4.0, the spec version that issued the original subscription request determines which data is returned in the response. For example, if your application subscribed using qbXML 3.0 (that is, the qbXML processing instruction is set like this: <?qbxml version=”3.0”?> ), then the QBXMLEvent data that is returned is the data from 3.0, that is, you don’t receive additional data made available in 4.0. If you needed that data, you would first do a 3.0 unsubscribe to get rid of the old subscription, then resubscribe using a qbXML 4.0 subscription request.

In addition, suppose you have a current subscription issued using qbXML 3.0. To delete that subscription, you have to issue a SubscriptionDel request with the qbXML version tag set to 3.0. The reason for this is that you might want to keep 3.0 spec subscriptions for backwards compatibility.

Note

Note

The application that makes a subscription request does not have to be the same application that will receive the event notification. (For example, your installation application might call a subscription request that specifies callback information for your main application.)

Which company files are affected by a subscription?

When you add a subscription, it applies to all company files on that machine. However, notice that the QuickBooks user must still authorize your application for each company file.

If you want events from only one particular company file, you can filter out the events from any unwanted company file by checking the CompanyFilePath element in the incoming event XML that your application receives.

Recovering From lost data events

There are a few situations in which data events aren’t sent to your application by QuickBooks. When this happens, the event notification framework provides a way for you to recover from these lost data events in order to synchronize the data your application maintains with the data in QuickBooks.

How are data events lost?

Data events can be lost due to a variety of conditions. There are basically two groups of causes: normal conditions and failure conditions. This distinction is important because the event notification system behaves differently depending on whether an event was lost due to failure conditions or not. If data events are lost due to normal conditions, attempts will still be made to deliver future events. If events are lost due to failure conditions, no attempt will be made to deliver future events during the rest of the current session with the company file.

Normal conditions leading to lost events. The list below describes normal conditions in which data events are lost for your application:

Failure conditions leading to lost data events. The list below describes failure conditions in which data events are lost for your application:

Note

Note

If data events are lost due to failure conditions, no more data events are sent to the application until the company file is re-opened.

How do I determine whether any data events have been lost?

Provided that you set the TrackLostEvents field in the data event subscription request to All, the DataEventRecoveryTime will be recorded whenever data events are lost, as described above. There are then two ways to check the DataEventRecoveryTime to determine if any events have been lost.

The first way is by examining a data event for the presence of the DataEventRecoveryTime field. If this field exists, then a data event was lost as of this time. The other way is by issuing a DataEventRecoveryInfoQuery request. If the response contains a DataEventRecoveryTime a data event was lost as of this time.

Notice that if more than one event was lost, the DataEventRecoveryTime will retain the time of the first lost event.

How do I recover from lost data events?

After you determine that data events have in fact been lost, you can query for all the objects your application cares about, with the FromModifiedDate filter set to the DataEventRecoveryTime. This will synchronize your records with the QuickBooks company file and account for any data events that were lost after the specified time.

Once you have done this, you must then clear the DataEventRecoveryTime using the DataEventRecoveryInfoDel request, specifying your application’s SubscriberID. By resetting this time, you are then guaranteed that any future existence of the DataEventRecoveryTime will indicate that data events have been lost from which your application has yet to recover.

Handling special QuickBooks operations

There are special QuickBooks operations that affect an application’s subscriptions and data synchronization with QuickBooks. They are listed below:

Each of these is described in more detail in the following subsections.

Restore

After a company file goes through a restore, its application permission records (the information in the Preferences > Integrated Applications window) may not be current anymore; there may be applications whose permission records weren’t in the backup file that the company file restored to. Upon opening the company file after the restore operation, QuickBooks will prompt the user to grant permission for those applications that still have subscriptions so that they can keep receiving events after the user grants them permission again.

Any application that has data that needs to match what is currently in QuickBooks will need to resynchronize its data with QuickBooks after a restore. The LastRestoreTime in the company file is updated every time a restore happens. An application can use this timestamp to detect that a restore happened by saving this time when it first sees it and then comparing it with the one currently stored by QuickBooks. To get the current LastRestoreTime, an application can issue a CompanyActivityQuery request. Alternatively, the last restore timestamp is also included in an application’s first data event after a company file is opened, so that an application doesn’t need to make a separate query request. Notice that an application only needs to check this timestamp once while a company file is open, as a restore always involves closing and then reopening the company file.

Condense

No events are sent during the condense operation of a company file. Any application that has data that needs to match what is currently in QuickBooks will need to detect when a condense has happened and then synchronize any data changes after the condense operation.

After the application detects a condense, it can get all the data changes as a result of the condense by using LastCondenseTime as a filter in the queries (the FromModifiedDate and FromDeletedDate). A condense operation also always involves closing and then reopening the company file.

Merge

A list object in QuickBooks can be merged with another list object of the same type. After the merge operation, all transactions that reference the merged-from object will be changed to reference the merged-to object, and the merged-from object is deleted. For example, after the user merges object A to object B, all transactions that used to refer to object A will now refer to object B, and object A will be deleted.

An application can expect to get a merge event and a delete event during a merge operation, but it will not get any transaction modify events. For example, in the above scenario, an application will get a merge event on object A (containing the after-merge list ID, which is object B’s list ID) and a delete event on object A. However, the application is expected to walk its own transaction list and update any references to object A itself.

Unsubscribing from events

Both QBFC and qbXML support unsubscribing from events of a specified type: data events, UI events or UI extension events. The unsubscribe request specifies the type and the application. For example, if you unsubscribe from data events, the application is unsubscribed from all data events, if you unsubscribe from UI events, the application is unsubscribed from all UI events, and so on. Just like subscribing, the unsubscribe changes take effect only when the company file is next opened (for data events and UI events) or when QuickBooks is restarted (for UI extension events).

Note

Note

During your application’s uninstall, you should always unsubscribe from any events to which your application is subscribed.

Modifying a subscription

There is no subscription Modify functionality. However, you can achieve the same result by deleting the subscription and adding a new subscription that contains all of the events of that type you want to receive, including ones that may have been in the previous subscription.

Querying a subscription

Both QBFC and qbXML support querying for the events that are currently under subscription. This is useful for determining the current subscription. The response returns different information depending on the query type. See the API Reference for more information.

Implementing event-awareness in qbXML

This section describes implementation details for qbXML-based applications. In addition, the syntax and code samples shown are in Visual Basic. If you are programming in Visual C++, see the fully commented code samples located at the QBSDK install subdirectory – \samples\qbdt\cpp\qbxml\UIandEventTest.

Note

Note

If you have used previous versions of the SDK, you may have used the Request Processor named QBXMLRPLib. Starting with SDK 3.0, a new Request Processor is available, QBXMLRP2Lib.RequestProcessor2. Only this new Request Processor supports event subscription and other new features of SDK 3.0. Backwards compatibility with the old Request Processor is maintained in the new one.

To enable your application to receive and respond to QuickBooks events, you need to subscribe the application to the events and you need to handle those incoming events in your callback code. This section describes each of these coding activities.

Subscribing, unsubscribing, and querying for subscription data are performed via the Request Processor ProcessSubscription method call. (In Visual Basic, QBXMLRP2Lib.RequestProcessor2::ProcessSubscription.)

This method call takes a qbXML request string containing the desired subscription, subscription delete, or subscription query qbXML.

Performing a Subscription in qbXML

In order to subscribe an application to events, a qbXML-based application creates an instance of the Request Processor, connects to QuickBooks, builds the desired SubscriptionAddRq request, and makes a call to the method ProcessSubscription (QBXMLRP2Lib.RequestProcessor2::ProcessSubscription).

When you build the qbXML SubscriptionAdd request you use one of the following requests, depending on the type of subscription you are making:

For the full description of each of these subscription messages, see the API Reference.

Building the Subscription Add Request in Visual Basic

The following sample is excerpted from a more fully commented sample in the SDK called QBDataEventSubscriber, which is located at the SDK installation subdirectory

\samples\qbdt\vb\qbxml\DataEvents\QBDataEventSubscriber. (Notice that sample does not check for errors or exceptions.)

The main items to take away from the sample are:

Note

Note

If an application attempts to subscribe before deleting its current subscription, it will generate an error. Your application must check for the error and act accordingly.

 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
Private Sub SubscribeBtn_Click()

' Subscribe to events...
Dim ConnOpen As Integer
ConnOpen = 0

Dim QBXML As IXMLDOMElement
Set QBXML = doc.createElement("QBXML")
doc.appendChild QBXML

Dim SubReq As IXMLDOMElement
Set DataSubReq = doc.createElement("DataEventSubscriptionAddRq")
SubReq.appendChild DataSubReq
Dim DataSubAdd As IXMLDOMElement
Set DataSubAdd = doc.createElement("DataEventSubscriptionAdd")
DataSubReq.appendChild DataSubAdd
Dim COMCallback As IXMLDOMElement
Set COMCallback = doc.createElement("COMCallbackInfo")
DataSubAdd.appendChild COMCallback
AddSimpleElement doc, COMCallback, "AppName", "DataEventSample"
Dim ListEventSub As IXMLDOMElement
Set ListEventSub = doc.createElement("ListEventSubscription")
DataSubAdd.appendChild ListEventSub
AddSimpleElement doc, ListEventSub, "ListEventType", "Customer"
AddSimpleElement doc, ListEventSub, "ListEventOperation", "Add"
AddSimpleElement doc, ListEventSub, "ListEventOperation", "Modify"
AddSimpleElement doc, ListEventSub, "ListEventOperation", "Delete"
AddSimpleElement doc, ListEventSub, "ListEventOperation", "Merge"

'We're all done we are going to subscribe to the UIEvents for company
'otherwise QuickBooks won't be able to close
Dim UISubReq As IXMLDOMElement
Set UISubReq = doc.createElement("UIEventSubscriptionAddRq")
SubReq.appendChild UISubReq
Dim UISubAdd As IXMLDOMElement
Set UISubAdd = doc.createElement("UIEventSubscriptionAdd")
UISubReq.appendChild UISubAdd
AddSimpleElement doc, UISubAdd, "SubscriberID", "{2B6C9DB4-EBE2-45E7-A14F-4E1C49C965F7}"

' Same Callback info as for DataEvents, and same delivery policy Set
COMCallback = doc.createElement("COMCallbackInfo")
UISubAdd.appendChild COMCallback
AddSimpleElement doc, COMCallback, "AppName", "DataEventSample"
AddSimpleElement doc, COMCallback, "ProgID", "QBDataEventManager.QBEventHandler"
AddSimpleElement doc, UISubAdd, "DeliveryPolicy", "DeliverAlways"
Dim UIEventSub As IXMLDOMElement
Set UIEventSub = doc.createElement("CompanyFileEventSubscription")
UISubAdd.appendChild UIEventSub

' We care only about the Close event, not the open event.
AddSimpleElement doc, UIEventSub, "CompanyFileEventOperation", "Close"

'Send the subscription request to QuickBooks Dim subXML As String
subXML = "<?xml version=""1.0""?>" & vbCrLf & "<?qbxml version=""3.0""?>" & vbCrLf & doc.xml
saveXMLStream subXML

Dim resp As String
resp = RP.ProcessSubscription(subXML)
' We'll just show the response.
MsgBox Prompt:=resp, Title:="Subscribe Complete"
' And finally close our connection to QuickBooks
If (ConnOpen) Then
  RP.CloseConnection
End If
End Sub

Unsubscribing in qbXML

When you no longer want to receive events of a certain type, or want to change a subscription, you make a call to the same method used to start receiving the events in the first place, QBXMLRP2Lib.RequestProcessor2::ProcessSubscription, but instead of supplying a SubscriptionAdd request, you provide a SubscriptionDel request. This deletes all subscription information for your application’s SubscriberID for the type of events you specify (data, UI extension, or UI).

Notice that you cannot unsubscribe from a subset of the original subscription of any type using the SubscriptionDel request. This request deletes all subscriptions of the specified type for the application that invokes it.

When you build the qbXML SubscriptionDelRq request you use one of the following requests, depending on the type of subscription you are making:

For the full description of each of these subscription messages,see qbXML messages reference.

Building the Subscription Delete Request in Visual Basic

The following sample is excerpted from a more fully commented sample in the SDK called QBDataEventSubscriber, which is located at the QBSDK subdirectory \samples\qbdt\vb\qbxml\DataEvents\QBDataEventSubscriber.

The main items to take away from the sample are:

 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
Private Sub Unsubscribe_Click()

'Simply delete the subscriptions we set up in Subscribe_click
Dim ConnOpen As Integer
ConnOpen = 0
Dim RP As New QBXMLRP2Lib.RequestProcessor2
RP.OpenConnection "", "DataEventSample"
ConnOpen = 1

' Create the outer subscription request XML "envelope"
Dim doc As New DOMDocument40
Dim QBXML As IXMLDOMElement
Set QBXML = doc.createElement("QBXML")
doc.appendChild QBXML
Dim SubReq As IXMLDOMElement
Set SubReq = doc.createElement("QBXMLSubscriptionMsgsRq")
QBXML.appendChild SubReq

' Create a subscription delete request for the Data event subscription
Dim DataSubDel As IXMLDOMElement
Set DataSubDel = doc.createElement("SubscriptionDelRq")
SubReq.appendChild DataSubDel
AddSimpleElement doc, DataSubDel, "SubscriberID", "{2B6C9DB4-EBE2-45E7-A14F-4E1C49C965F7}"
AddSimpleElement doc, DataSubDel, "SubscriptionType", "Data"

'Create subscription delete request for the UIEvent for company close
Dim UISubDel As IXMLDOMElement
Set UISubDel = doc.createElement("SubscriptionDelRq")
SubReq.appendChild UISubDel
AddSimpleElement doc, UISubDel, "SubscriberID", "{2B6C9DB4-EBE2-45E7-A14F-4E1C49C965F7}"
AddSimpleElement doc, UISubDel, "SubscriptionType", "UI"

'Send the subscription delete requests to QuickBooks
Dim subXML As String
subXML = "<?xml version=""1.0""?>" & vbCrLf & "<?qbxml version=""3.0""?>" & vbCrLf & doc.xml
saveXMLStream subXML

Dim resp As String
resp = RP.ProcessSubscription(subXML)

' Show the response
MsgBox Prompt:=resp, Title:="Subscriptions Removed"
' Close the connection to QuickBooks.
If (ConnOpen) Then
  RP.CloseConnection
End If
End Sub