require File.dirname(__FILE__) + '/modifiable'
module QBFC
# An Element is a Transaction or a List; that is any QuickBooks objects that can
# be created, edited (possibly), deleted and read. Contrast to a Report or Info
# which are read-only.
#
# Inheritance from Element implies a set of shared methods, such as find, but the
# only shared implementation defined here is #custom, for getting custom field information.
class Element < Base
class << self
# Set that this is a "base class", one which is inherited,
# such as List, Transaction, Entity, or Terms.
# Base classes do not accept Add Requests, and their finders
# will return an instance of an inherited class.
def is_base_class
@is_base_class = true
end
# Check if this is a "base class" (see is_base_class)
def is_base_class?
@is_base_class ? true : false
end
# Find a QuickBooks record for the given session.
#
# session.[qb_name] aliases this functionality. The following
# pairs are equivalent:
#
# QBFC::Vendor.find(session, :first) <-> session.vendor
# QBFC::Vendor.find(session, "Supply Shop") <-> session.vendor("Supply Shop")
# QBFC::Vendor.find(session, :all) <-> session.vendors.find(:all)
#
# Find requires a +session+ (representing a QBFC::Session) and
# a +what+ argument. +what+ can be one of:
# - :first - finds the first record fitting any given conditions.
# - :finds - finds all records fitting any given conditions.
# - An unique identifier, such as a ListID, FullName, RefNumber or TxnID
#
# .find can also receive a optional Request object followed
# by an optional options Hash. Valid argument sets are:
#
# QBFC::Vendor.find(session, :first)
# QBFC::Vendor.find(session, :first, request)
# QBFC::Vendor.find(session, :first, request, options)
# QBFC::Vendor.find(session, :first, options)
#
# The options hash accepts the following:
# - :owner_id: One or more OwnerIDs, used in accessing
# custom fields (aka private data extensions).
#
# Additional options are planned, but not really supported in this version.
# Passing a Request object is the current recommended way of applying
# Filters or other options to the Query Request.
def find(sess, what, *args)
if what.kind_of?(String) # Single FullName or ListID
return find_by_unique_id(sess, what, *args)
end
# Setup q, options and base_options arguments
q, options, base_options = parse_find_args(*args)
q ||= create_query(sess)
q.apply_options(options)
# QuickBooks only needs to return one record if .find is
# only returning a single record.
if what == :first && q.filter_available?
q.filter.max_returned = 1
end
# Send the query so far to base_class_find if this is
# a base class to handle special base class functionality.
return base_class_find(sess, what, q, base_options) if is_base_class?
# Get response and return an Array, a QBFC::Element-inherited
# object, or nil, depending on what argument and whether
# the query returned any records.
list = q.response
if list.nil?
(what == :all) ? [] : nil
elsif what == :all
(0..(list.Count - 1)).collect { |i|
new(sess, list.GetAt(i))
}
else
new(sess, list.GetAt(0))
end
end
# Base classes can be used to find members of any of their
# inherited classes. Since QuickBooks has limited options
# for these type of queries (in particular, no custom fields
# are returned), an initial query is run which retrieves
# only IDs and the class type and then individual subsequent
# queries are run for each returned object.
def base_class_find(sess, what, q, options)
q.IncludeRetElementList.Add(self::ID_NAME)
list = q.response
if list.nil?
(what == :all) ? [] : nil
else
ary = (0..(list.Count - 1)).collect { |i|
element = list.GetAt(i)
ret_name = element.ole_methods.detect{ |m| m.to_s =~ /(.*)Ret\Z/ }.to_s
ret_class = QBFC::const_get($1)
ret_class.find(sess, element.send(ret_name).send(ret_class::ID_NAME), options.dup)
}
if what == :all
ary
else
ary[0]
end
end
end
private :base_class_find
end
is_base_class
# Extends Base#initialize to allow for an Add Request if
# .new is called directly (instead of by .find)
def initialize(sess, ole_object = nil)
if self.class.is_base_class?
raise BaseClassNewError, "This is a base class which doesn't allow object initialization"
end
super
if @ole.nil?
add_rq = QBFC::Request.new(sess, "#{qb_name}Add")
@ole = QBFC::OLEWrapper.new(add_rq.ole_object)
@new_record = true
@setter = add_rq
end
end
# Is this a new record, i.e. are we doing an Add Request?
def new_record?
@new_record ? true : false
end
# Access information from a custom field.
def custom(field_name, owner_id = 0)
if @ole.DataExtRetList
@ole.data_ext.each do |field|
if field.data_ext_name == field_name && field.owner_id == owner_id
return field.data_ext_value
end
end
end
return nil
end
# Save (create or update) this record
def save
if @setter
@setter.submit
else
raise NotSavableError, "This record cannot be saved (Probably because it does not support Mod Requests)."
end
end
end
end
# Require subclass files
%w{ list transaction }.each do |file|
require File.dirname(__FILE__) + '/' + file
end