Skip to content

Commit

Permalink
Added correction for Quickbooks' find-by-date instead of by-time, in …
Browse files Browse the repository at this point in the history
…time-based queries.

git-svn-id: http://quickbooks.rubyforge.org/svn@29 0eb1a872-461d-0410-a379-984e9e9c21cf
  • Loading branch information
dcparker committed May 31, 2008
1 parent f2fbaf7 commit 4f9a22c
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 33 deletions.
3 changes: 2 additions & 1 deletion README
Expand Up @@ -49,4 +49,5 @@ This library is released under the terms of the MIT License.
* 0.1.0 Bugfixes, a little more docs, and connection is a little more robust.
* 0.1.1 Small bugfix.
* 0.4.0 Ready for beta by anyone!
* 0.4.2 A few bugs worked out, added Quickbooks::Base.setup to initialize arguments for establish_connection().
* 0.4.2 A few bugs worked out, added Quickbooks::Base.setup to initialize arguments for establish_connection().
* 0.4.3 A really important addition to the query() method that filters a Quickbooks response to correctly honor time-based filters. (Monitor whether we need to +1 day to incoming time-based filters so that Quickbooks will include all desired results.)
2 changes: 1 addition & 1 deletion Rakefile
Expand Up @@ -6,7 +6,7 @@ require 'rake/gempackagetask'
require 'rake/contrib/rubyforgepublisher'

PKG_NAME = 'quickbooks'
PKG_VERSION = "0.4.2"
PKG_VERSION = "0.4.3"

PKG_FILES = FileList[
"lib/**/*", "rspec/**/*", "[A-Z]*", "Rakefile", "doc/**/*"
Expand Down
8 changes: 2 additions & 6 deletions lib/qbxml/request.rb
@@ -1,19 +1,16 @@
require 'qbxml/support'
require 'builder'
require 'time'
require 'hash_magic'

module Qbxml
VERSION = '6.0'

# module RequestSetArrayExt
# end

class RequestSet
include Enumerable
def set
unless @set.is_a?(Array)
@set = []
# @set.extend(Qbxml::RequestSetArrayExt)
end
@set
end
Expand Down Expand Up @@ -190,8 +187,7 @@ def to_xml(as_set=true)
inner_stuff.call
end
}
# puts req.target!
req.target!
req.target! # The xml string
end

private
Expand Down
32 changes: 11 additions & 21 deletions lib/qbxml/response.rb
Expand Up @@ -2,15 +2,11 @@
require 'formatted_string'

module Qbxml
# module ResponseSetArrayExt
# end

class ResponseSet
include Enumerable
def set
unless @set.is_a?(Array)
@set = []
# @set.extend(Qbxml::ResponseSetArrayExt)
end
@set
end
Expand Down Expand Up @@ -38,8 +34,6 @@ def initialize(xml_or_hash)
end

def append_from_xml(xml)
# puts "ResponseXML:"
# puts xml
self.append_from_hash(xml.formatted(:xml).to_hash)
end
def append_from_hash(hsh)
Expand Down Expand Up @@ -67,8 +61,7 @@ def from_hash(hsh)

class Response
attr_accessor :response_type, :status, :message, :severity, :ret_items
# For Development purposes:
attr_accessor :raw_response
attr_accessor :raw_response # (for development purposes)

def initialize(xml_or_hash)
if(xml_or_hash.is_a?(Hash))
Expand All @@ -87,24 +80,22 @@ def import_from_xml(xml)
def import_from_hash(hsh)
raise ArgumentError, "Hash passed to Qbxml::Response.from_hash must contain only one top-level key" unless hsh.keys.length == 1
name = hsh.keys.first
# for development
self.raw_response = hsh
# * * * *
self.raw_response = hsh # (for development purposes)
hsh = hsh[name]

self.status = hsh['statusCode'].to_i
self.severity = hsh['statusSeverity']
self.message = hsh['statusMessage']
# if self.status == 0 # Status is good, proceed with eating the request.
# <ListDeletedQueryRs requestID="5" statusCode="0" statusSeverity="Info" statusMessage="Status OK">
# <ListDeletedRet>
# <ListDelType>Customer</ListDelType>
# <ListID>80000030-1203622308</ListID>
# <TimeCreated>2008-02-21T14:31:48-05:00</TimeCreated>
# <TimeDeleted>2008-03-18T17:31:12-05:00</TimeDeleted>
# <FullName>Rachel Parker</FullName>
# </ListDeletedRet>
# </ListDeletedQueryRs>
# <ListDeletedQueryRs requestID="5" statusCode="0" statusSeverity="Info" statusMessage="Status OK">
# <ListDeletedRet>
# <ListDelType>Customer</ListDelType>
# <ListID>80000030-1203622308</ListID>
# <TimeCreated>2008-02-21T14:31:48-05:00</TimeCreated>
# <TimeDeleted>2008-03-18T17:31:12-05:00</TimeDeleted>
# <FullName>Joe Schmoe</FullName>
# </ListDeletedRet>
# </ListDeletedQueryRs>
if m = name.match(/^(List|Txn)Del(etedQuery)?Rs$/)
# (List|Txn)DelRs, or (List|Txn)DeletedQueryRs - both return just a few attributes, like ListID / TxnID and TimeDeleted
list_or_txn = m[1]
Expand All @@ -121,7 +112,6 @@ def import_from_hash(hsh)
# else # Status is bad.

# end
# puts self.inspect
self
end

Expand Down
30 changes: 28 additions & 2 deletions lib/quickbooks/base.rb
Expand Up @@ -162,9 +162,35 @@ def query(obj_or_args,*args)
nil
end
objects = [] # This will hold and return the instantiated objects from the quickbooks response
# The following is subject to bugginess, IF the response contains more than one object: it will instantiate only the last one.
# The following line is subject to unexpected results: IF the response contains more than one object, it will re-instantiate only the last one.
self.request(reinstantiate || self, *args).each { |response| objects << response.instantiate(reinstantiate) } # Does not instantiate if it's an error, but simply records response into response_log
objects.length == 1 ? objects[0] : objects
# Since Quickbooks only honors the Date in queries, we can filter the list further here to honor the Time requested.
# filters we're triggered on: created_before, created_after, updated_before, updated_after, deleted_before, deleted_after
if args[-1].is_a?(Hash) && !(time_filters = args.stringify_keys.only('created_before', 'created_after', 'updated_before', 'updated_after', 'deleted_before', 'deleted_after')).empty?
objects.reject! do |object|
passes = true
time_filters.each do |filter,time|
case filter
when 'created_before'
passes = Time.parse(object.time_created) < Time.parse(time.to_s)
when 'created_after'
passes = Time.parse(object.time_created) >= Time.parse(time.to_s)
when 'updated_before'
passes = Time.parse(object.time_modified) < Time.parse(time.to_s)
when 'updated_after'
passes = Time.parse(object.time_modified) >= Time.parse(time.to_s)
when 'deleted_before'
passes = Time.parse(object.time_deleted) < Time.parse(time.to_s)
when 'deleted_after'
passes = Time.parse(object.time_deleted) >= Time.parse(time.to_s)
end
break unless passes # Skip the rest of the tests if it fails one
end
!passes
end
end
# ****
objects.length == 1 ? objects[0] : objects # Here, we may rather always return an array, then return the first element by methods such as .first
end

# Generates a request using Qbxml::Request, sends it, and returns a Qbxml::ResponseSet object containing the response(s).
Expand Down
3 changes: 3 additions & 0 deletions lib/quickbooks/model.rb
Expand Up @@ -79,7 +79,10 @@ def #{prop.class_leaf_name.underscore}; @#{prop.class_leaf_name.underscore}; end
end
end

# Lists the registered properties, first read_only properties, then read_write
def properties
# Quickbooks seems to always include the read-only attributes first... if this isn't always true,
# the two above methods will need to also append the attribute names into a common properties list.
read_only + read_write
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/quickbooks/models/list_item.rb
Expand Up @@ -11,7 +11,7 @@ class ListItem < Base

def self.inherited(klass)
super
# :time_deleted only comes from ListDeleted, but that way all ListDeleted attributes can be instantiated into the respective ListItem model
# :time_deleted only comes from ListDeleted, but that way all ListDeleted attributes can be instantiated into their respective ListItem model
klass.read_only :list_id, :full_name, :edit_sequence, :time_created, :time_modified, :time_deleted
end

Expand Down
2 changes: 1 addition & 1 deletion lib/quickbooks/ruby_magic.rb
Expand Up @@ -133,7 +133,7 @@ def -(v)
end

def only(*keys)
keys.flatten.inject(dup.clear) {|h,(k,v)| h[k] = self[k]}
keys.flatten.inject(dup.clear) {|h,(k,v)| h[k] = self[k]; h}
end
def only!(*keys)
replace(only(*keys))
Expand Down

0 comments on commit 4f9a22c

Please sign in to comment.