Half-Penny For Your Thoughts

rounded down to the nearest cent



Categories


Recent Articles




Computing

QBFC and Ruby

I discovered how to use QBFC with Ruby. QBFC is part of the Quickbooks SDK and is a fairly basic wrapper around QBXML. To me, it’s not the simplest interface, but it’s a nice not to bother with the XML, as I’ve been doing. Whereas when using QBXML, you would call WIN32OLE.new(“QBXMLRP2.RequestProcessor”), use WIN32OLE.new(“QBFC6.QBSessionManager”) instead.

Here’s quick example:

require 'win32ole'

qb = WIN32OLE.new("QBFC6.QBSessionManager")

qb.OpenConnection2 "", "Ruby Test", 1 # 1 is ctLocalQBD
qb.BeginSession("", 2) # 2 is omDontCare

request_set = qb.CreateMsgSetRequest("US", 6, 0)
customer_query = request_set.AppendCustomerQueryRq

response = qb.DoRequests(request_set)
customer_set = response.ResponseList.GetAt(0)
first_customer = customer_set.Detail.GetAt(0)
puts first_customer.FullName.GetValue

qb.EndSession
qb.CloseConnection
qb = nil

Now, I like to wrap all that opening and closing connection stuff in a block, so here’s a version I like a bit better:

require 'win32ole'

OPEN_MODES = {
  :single => 0,
  :multi  => 1,
  :either => 2
}

def session(app_name, options = {})
  com_obj = WIN32OLE.new("QBFC6.QBSessionManager")
  com_obj.OpenConnection2(options[:app_id].to_s, app_name, 1) # 1 is ctLocalQBD

      open_mode = OPEN_MODES[options[:open_mode].to_s] || 2 # :either is default
  com_obj.BeginSession(options[:filename].to_s, open_mode)

  begin
    yield(com_obj)
  ensure
    com_obj.EndSession
    com_obj.CloseConnection
    com_obj = nil
  end
end

session("Test Application") do | qb |
  request_set = qb.CreateMsgSetRequest("US", 6, 0)
  customer_query = request_set.AppendCustomerQueryRq

  response = qb.DoRequests(request_set)
  customer_set = response.ResponseList.GetAt(0)
  first_customer = customer_set.Detail.GetAt(0)
  puts first_customer.FullName.GetValue
end

And, finally, a bit of playing with WIN32OLE (risky, most likely):

require 'win32ole'

unless Object.const_defined?(:ActiveSupport)
  gem 'activesupport'
  require 'active_support'
end

class WIN32OLE

  alias_method :old_array_selector, :[]

  def [](idx)
    if idx.kind_of? Integer
      self.GetAt(idx)
    else
      old_array_selector(idx)
    end
  end

  alias_method :old_method_missing, :method_missing

  def method_missing(symbol, *params)
    if (('a'..'z') === symbol.to_s[0].chr)
      obj = old_method_missing(symbol.to_s.camelize.to_sym, *params)

      if obj.ole_methods.detect{|m| m.to_s == 'GetValue'}
        obj.GetValue
      end
    else
      old_method_missing(symbol, *params)
    end
  end
end

The new definition of [] checks if an integer was passed. If so, and if self responds to “GetAt”, go ahead and send the integer value to self#GetAt . This allows me to use response.ResponseList[0] instead response.ResponseList.GetAt(0).

The method_missing stuff allows does a similar shortcut for GetValue . Instead of first_customer.FullName.GetValue, I can call first_customer.full_name.

This is not at all tested, so I can’t say what these changes might mess up.


blog comments powered by Disqus