Rails and QuickBooks Integration - Part 1

Have a Rails app that needs to integrate with Quickbooks? Unfortunately I do too. I say unfortunately because I have some idea as to where this path leads. But don’t worry, we’ll make it through and it’ll be easier for you now that the trail has been blazed.

  1. The first thing to realize is that while QuickBooks offers a Mac edition, the SDK that developers need to work with is for the PC only. So if you’re on a Mac, fire up Parallels and boot up.
  2. Head over to the Intuit Developer Network, click “Join IDN”, and create a Community Developer membership which is free. As a preview to the painfully antiquated technology that we’ll be dealing with, notice that you are prompted to install a Java Virtual Machine to make the site work better. Don’t bother.
  3. Download and install the QuickBooks SDK.
  4. Decide if your app will integrate with the QuickBooks Online (QBOE) or desktop edition.

The good news is that the SDK will help if you need both. Here is a quote from the docs:

The SDK provides a common methodology for integrating an application with QuickBooks: once you’ve developed an application for one QuickBooks product, modifying your application to support any (or all) of the other QuickBooks products is a straightforward task. This shared SDK approach is based on qbXML, a version of XML (eXtensible Markup Language) designed specifically for QuickBooks.

So why do we need to decide between the Desktop and Online editions? The simple answer is that the communication process is different depending on the product.

QuickBooks Online edition workflow

To enable your hosted web application to communicate with QBOE, you do the following (mostly copied from the docs):

  1. Obtain a test QBOE company from IDN for testing during development. These are available to paid memberships and participants in the Not-For-Resale program. This really sucks as the cheapest option is $295/year.
  2. Register your application with IDN at appreg.intuit.com.
  3. Obtain an server certificate from a supported root certificate authority.
  4. Obtain a client certificate by generating a certificate signing request (CSR) and use the appreg.intuit.com site to get it signed by Intuit.
  5. In your code, using SSL, implement the presentation of the client certificate when POSTing to QBOE.
  6. In your code, prompt your customer to grant a connection ticket authorizing your application to access the QBOE company. Respond by sending the customer to the QBOE login page to get a connection ticket. QBOE POSTs the connection ticket back to the application subscription URL you specified when you registered your application. Handle this POST at that URL and store the connection ticket securely.
  7. In your code, implement session ticket handling code. That is, prior to sending QBOE requests for a particular customer, get a session ticket by sending a SignonMsgsRq containing a SignonAppCertRq with that customer’s connection ticket. You’ll POST this to the QBOE data exchange URL to get the session ticket in the SignonAppCertRs response.
  8. In your code, build the desired requests in a qbXML string. This string contains a SignonMsgsRq containing a SignonTicketRq with the session ticket from the SignonAppCertRs in the previous step, followed by the QBOE requests. POST this whole XML string to the QBOE data exchange URL and process the response.
  9. In your code, handle connection ticket cancellation notification from QBOE. (If the customer cancels the connection ticket, QBOE sends a notification to the Application Cancel URL that you specified when you registered your application.)

QuickBooks Desktop editions workflow

Obviously your web app cannot post requests directly to a client’s desktop Quickbooks installation. So Intuit has come up with a go between - the QuickBooks Web Connector (QBWC).

In a one-time setup action, your web app provides the QBWC with a configuration file (called a QWC file). The configuration file contains your app’s url, the username for the client, and how often you want the QBWC to poll your app.

Sample QWC file

<?xml version="1.0"?>
<QBWCXML>
   <AppName>WCWebService1</AppName>
   <AppID></AppID>
   <AppURL>http://localhost/WCWebService/WCWebService.asmx</AppURL>
   <AppDescription>A short description for WCWebService1</AppDescription>
   <AppSupport>http://developer.intuit.com</AppSupport>
   <UserName>iqbal1</UserName>
   <OwnerID>{57F3B9B1-86F1-4fcc-B1EE-566DE1813D20}</OwnerID>
   <FileID>{90A44FB5-33D9-4815-AC85-BC87A7E7D1EB}</FileID>
   <QBType>QBFS</QBType>
   <Scheduler>
      <RunEveryNMinutes>2</RunEveryNMinutes>
   </Scheduler>
</QBWCXML>

After this initial setup the QBWC will poll your web app at regular intervals. The callbacks to be used in the communication that our Rails app must implement are the following: authenticate, clientVersion, closeConnection, connectionError, getLastError, receiveResponseXML, and sendRequestXML. Here is the communication flow:

  1. QBWC calls your (optional but strongly recommended) clientVersion method.
  2. QBWC calls your authenticate callback. If the username and password in the authenticate call is invalid, your callback returns “nvu”. If the user data is valid but you have no requests for that user, you return “none”. Otherwise, return the full pathname of the company to be used in the current update, or empty string for currently open company.
  3. If the authenticate callback does not return “none” or “nvu”, QBWC invokes OpenConnection and BeginSession on the indicated company. If these calls are successful, QBWC calls your sendRequestXML callback. If the attempt to connect to QuickBooks is unsuccessful, then the QBWC calls your connectionError callback.
  4. QBWC invokes sendRequestXML once the connection and session with QuickBooks is started.
  5. If the return from sendRequestXML is an empty string, QBWC stops the update and calls closeConnection. Otherwise, it passes the supplied string to the QuickBooks request processor to be handled. The string must be a valid qbXML request message.
  6. The data returned by Quickbooks in response to the incoming requests is supplied in the QBWC receiveResponseXML, in the response parameter. Your callback returns a negative integer if there are any errors, such as out of sequence calls due to network problems. Otherwise, it returns a positive integer between 0 and 100, indicating the percentage of work done up to that point, with a value of 100 meaning that the update activity is finished. If there is work left, then QBWC calls sendRequestXML again to allow your web service to continue its work.
  7. If the return from receiveResponseXML is a negative integer, QBWC calls getLastError to allow your web service to supply some message string to inform the user. This message is displayed by QBWC and then QBWC invokes closeConnection to end the session.
  8. If not called prior to this point by some error condition, once all update activity is finished, as indicated by the web service’s return to the receiveResponseXML call, then QBWC invokes closeConnection and ends the current update session.

I told you this would be painful :)

For my current app, Service Sidekick, desktop integration support is crucial. Integration with the Online Edition may be added later depending on customer demand. Stay tuned for the next in the series where we’ll dive right into the desktop integration.

Comment or question via
FYI: This post was migrated over from another blogging engine. If you encounter any issues please let me know on . Thanks.