Rails and QuickBooks Integration - Part 4

Make sure you read part 1, part 2, and part 3 of this series if you haven’t already.

The Full Monty

In part 3 we tested the simple case of having no pending requests for the QuickBooks Web Connector (QBWC) which results in the exercise of only authenticate() and closeConnection(). But I know you were craving more…

To test the full send/receive stack we need to return a qbXML request from sendRequestXML(). QBWC will forward this qbXML request to QuickBooks and then return the result by calling our receiveResponseXML(). Let’s put together a sample request that returns all customer names.

quickbooks_controller.rb

class QuickbooksController < ApplicationController
  ssl_required :api, :qwc
  before_filter :set_soap_header, :except => :qwc

  ...
  
  def authenticate(username, password)
    ['85B41BEE-5CD9-427a-A61B-83964F1EB426', '']
  end

  ...

  def sendRequestXML(ticket, hpc_response, company_file_name, country, qbxml_major_version, qbxml_minor_version)
    qbxml = <<-REQUEST
    <?xml version="1.0"?>
    <?qbxml version="4.0"?>
    <QBXML>
      <QBXMLMsgsRq onError="stopOnError">
        <CustomerQueryRq requestID="1">
          <IncludeRetElement>FullName</IncludeRetElement>
        </CustomerQueryRq>
      </QBXMLMsgsRq>
    </QBXML>
    REQUEST
  
    clean_qbxml(qbxml)
  end

  def receiveResponseXML(ticket, response, hresult, message)
    xml = REXML::Document.new(response)
    statusCode = REXML::XPath.first(xml, '//CustomerQueryRs[1]' ).attributes['statusCode']

    if statusCode == 0.to_s
      REXML::XPath.each(xml, '//FullName' ){ |e| logger.info "Customer: #{e.text}" }
    else
      logger.info "Unable to receive the customer list...status code: #{statusCode}"
    end

    100
  end

  ...

  def closeConnection(ticket)
    'OK'
  end

  ...

  private
  
    def set_soap_header
      if request.env['HTTP_SOAPACTION'].blank? || request.env['HTTP_SOAPACTION'] == %Q("")
        xml = REXML::Document.new(request.raw_post)
        element = REXML::XPath.first(xml, '/soap:Envelope/soap:Body/*')
        request.env['HTTP_SOAPACTION'] = element.name if element
      end
    end
  
    def clean_qbxml(qbxml)
      qbxml.gsub(/>\n\s+</, '><').strip
    end
	  
end

First, authenticate returns an empty string. This instructs QBWC to use the current company file. You can check the current company file name by checking the strHCPResponse xml passed to the sendRequestXML() call.

Secondly, we issue a simple qbXML request to QBWC. I like to use here documents («- notation) to keep xml readable. But QBWC will barf on the newlines and whitespace so we have to throw in a quick helper (clean_qbxml) to do our dirty work.

Finally, our receiveResponseXML() simply logs the customer names and returns 100 which signals that we have no future pending requests. QWBC then calls closeConnection() and exits.

Next steps

This has been a wild ride but now we’re home free. The basics of the QBWC communication cycle are understood. QBWC 1.5 should come out soon to improve on the rough edges. Now all that remains is to sit down and determine exactly how your app should sync with QuickBooks. That’s what I’m doing now. If I discover any helpful tidbits as I work through my integration I’ll be sure to post another article. Otherwise I hope these posts were helpful and I wish you luck in your integration quest!

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.