Thu, 2008 Jan 17

QBFC and Ruby

Posted in Computing at 02:50 by jmorgan

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.


0 Comments

Add a comment