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!