qbfc 0.1.0-x86-mswin32-60 → 0.2.0-x86-mswin32-60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README CHANGED
@@ -5,7 +5,29 @@ allowing more or less direct access to the actual COM object.
5
5
 
6
6
  Obviously, test before using on your production data...
7
7
 
8
- ==Examples
8
+ ==Find
9
+
10
+ QBFC-Ruby supports +find+ queries with options, which utitilize QBFC's Query
11
+ Requests. See QBFC::Element.find for details and options.
12
+
13
+ QBFC::session do | qb |
14
+ checks = qb.checks.find(:first, :conditions => {:entity => 'ABC Supplies'})
15
+ end
16
+
17
+ ==Relationships
18
+
19
+ QBFC-Ruby supports loading of related records. These are records
20
+ represented by "*Ref" in the QBFC documentation. For example, a Check
21
+ has, among others, a PayeeEntityRef and an AccountRef. These can be
22
+ accessed via, respectively, <tt>check.payee</tt> and <tt>check.account</tt>.
23
+
24
+ <tt>check.payee.name</tt> returns the name of the payee.
25
+
26
+ You can also access the *ID and Name fields of referenced records.
27
+ Example: for the payee of a Check, <tt>check.payee_id</tt> and
28
+ <tt>check.payee_name</tt>.
29
+
30
+ ==General Examples
9
31
 
10
32
  # A very simple example, finding a single Customer by name
11
33
  QBFC::session do | qb |
@@ -37,5 +59,27 @@ Obviously, test before using on your production data...
37
59
  first_customer = customer_set.Detail[0]
38
60
  puts first_customer.full_name
39
61
  end
62
+
63
+ ==Alternatives
64
+
65
+ [QuickBooks for Ruby]
66
+ (docs: http://quickbooks.rubyforge.org,
67
+ homepage: http://rubyforge.org/projects/quickbooks)
68
+
69
+ This is a project with similar goals to QBFC-Ruby. I believe the approach
70
+ is creating Ruby classes that mirror the QuickBooks types and generate / parse
71
+ qbXML. In my opinion, this approach is more stable and flexible than what I'm
72
+ doing with QBFC-Ruby, but at the cost of slower development. (As in, QBFC-Ruby
73
+ was intended as a collection of quick and dirty shortcuts; QuickBooks for Ruby
74
+ seems to be intended as a much more *complete* project)
75
+
76
+ [QBFC/qbXML COM Objects]
77
+ Using the SDK directly is an option. Unless you need to use QBWC (QuickBooks
78
+ Web Connector) or have some other reason for *wanting* to us qbXML, I suggest
79
+ using QBFC. The SDK documents (see http://developer.intuit.com/ ) are pretty
80
+ easy to use and navigate.
81
+
82
+ There are some other libraries on rubyforge in early stages which I haven't
83
+ really explored.
40
84
 
41
85
  Copyright (c) 2008 Jared E. Morgan, released under the MIT license
data/Rakefile CHANGED
@@ -63,7 +63,7 @@ require 'rake/gempackagetask'
63
63
 
64
64
  spec = Gem::Specification.new do |s|
65
65
  s.name = "qbfc"
66
- s.version = "0.1.0"
66
+ s.version = "0.2.0"
67
67
  s.author = "Jared Morgan"
68
68
  s.email = "jmorgan@morgancreative.net"
69
69
  s.homepage = "http://rubyforge.org/projects/qbfc/"
@@ -50,10 +50,74 @@ module QBFC
50
50
  # The options hash accepts the following:
51
51
  # - <tt>:owner_id</tt>: One or more OwnerIDs, used in accessing
52
52
  # custom fields (aka private data extensions).
53
+ # - <tt>:limit</tt>: The maximum number of records to be returned.
54
+ # - <tt>:include</tt>: Elements to include (see below for details)
55
+ # - <tt>:conditions</tt>: A hash of conditions (generally 'Filters' in
56
+ # QuickBooks SDK. See below:
53
57
  #
54
58
  # Additional options are planned, but not really supported in this version.
55
59
  # Passing a Request object is the current recommended way of applying
56
- # Filters or other options to the Query Request.
60
+ # unsupported conditions (Filters) or other options to the Query Request.
61
+ #
62
+ # ==Include
63
+ #
64
+ # The :include option accepts an Array of elements to include in the
65
+ # return of the Query. The array may include either or both of elements
66
+ # that are additional to normal returns (such as Line Items, Linked
67
+ # Transactions) or elements that are normally included (to be added to the
68
+ # IncludeRetElementList).
69
+ #
70
+ # If elements are given that would be added to IncludeRetElementList, this
71
+ # limits the elements returned to *only* those included in the array.
72
+ #
73
+ # Another option is to give :all as the argument, which will always return
74
+ # as many elements as possible.
75
+ #
76
+ # @sess.checks.find(:all, :include => [:linked_txns]) -> Include linked transactions
77
+ # @sess.checks.find(:all, :include => [:txn_id]) -> Include +only+ TxnID
78
+ # @sess.checks.find(:all, :include => :all) ->
79
+ # Includes all elements, including LinkedTxns and LineItems.
80
+ #
81
+ # ==Conditions
82
+ #
83
+ # Conditions are dependent on the particular Request. See the QuickBooks
84
+ # SDK documentation for applicable filters for each Query Request. Note
85
+ # that not all Filters are supported.
86
+ #
87
+ # Typically the condition is given as :filter_name => value where
88
+ # +filter_name+ is the name of the filter less the word 'Filter' (see
89
+ # examples below).
90
+ #
91
+ # Here are some general rules:
92
+ #
93
+ # [List filters]
94
+ # These are filters that end in List. They take an Array of values.
95
+ #
96
+ # :ref_number_list => ["1001", "1003", "1003a"]
97
+ # :txn_id_list => ["123-456"]
98
+ #
99
+ # [Range Filters]
100
+ # Filters which take a range of values. These accept any
101
+ # object which responds to +first+ and +last+, such as a Range or Array.
102
+ # +first+ is used to set the From value, +last+ sets the To value. If a
103
+ # scalar value is given (or a single element Array), To is set and From
104
+ # is left empty. nil can also be given for either value.
105
+ #
106
+ # :txn_date_range => ['2008-01', nil]
107
+ # :txn_date_range => ['2008-01']
108
+ # :txn_date_range => '2008-01'
109
+ #
110
+ # :ref_number_range => "1001".."1003"
111
+ # :ref_number_range => ["1001", "1003"]
112
+ #
113
+ # [Reference Filters]
114
+ # Filters which reference another object (belongs to
115
+ # filters). These current only accept Name arguments, as a single value
116
+ # or an Array.
117
+ #
118
+ # :account => 'Checking'
119
+ # :entity => ['ABC Supplies', 'CompuStuff']
120
+ #
57
121
  def find(sess, what, *args)
58
122
 
59
123
  if what.kind_of?(String) # Single FullName or ListID
@@ -63,12 +127,13 @@ module QBFC
63
127
  # Setup q, options and base_options arguments
64
128
  q, options, base_options = parse_find_args(*args)
65
129
  q ||= create_query(sess)
130
+
66
131
  q.apply_options(options)
67
132
 
68
133
  # QuickBooks only needs to return one record if .find is
69
134
  # only returning a single record.
70
135
  if what == :first && q.filter_available?
71
- q.filter.max_returned = 1
136
+ q.add_limit(1)
72
137
  end
73
138
 
74
139
  # Send the query so far to base_class_find if this is
@@ -106,9 +171,11 @@ module QBFC
106
171
  else
107
172
  ary = (0..(list.Count - 1)).collect { |i|
108
173
  element = list.GetAt(i)
109
- ret_name = element.ole_methods.detect{ |m| m.to_s =~ /(.*)Ret\Z/ }.to_s
174
+ ret_name = element.ole_methods.detect { |m|
175
+ m.to_s =~ /(.*)Ret\Z/ && element.send(m.to_s)
176
+ }.to_s
110
177
  ret_class = QBFC::const_get($1)
111
- ret_class.find(sess, element.send(ret_name).send(ret_class::ID_NAME), options.dup)
178
+ ret_class.find(sess, element.send(ret_name).send(ret_class::ID_NAME).GetValue, options.dup)
112
179
  }
113
180
 
114
181
  if what == :all
@@ -119,7 +186,7 @@ module QBFC
119
186
  end
120
187
  end
121
188
 
122
- private :base_class_find
189
+ private :base_class_find, :is_base_class
123
190
 
124
191
  end
125
192
 
@@ -1,6 +1,25 @@
1
1
  module QBFC
2
2
  class Item < List
3
3
  is_base_class
4
+
5
+ class << self
6
+
7
+ # Adds a SpecialItem.
8
+ #
9
+ # +item_type+ should be a constent, for example:
10
+ #
11
+ # Account.add_special(sess, QBFC_CONST::SitFinanceCharge)
12
+ #
13
+ # See SDK docs for SpecialItemAdd for more details.
14
+ def add_special(sess, item_type)
15
+ rq = QBFC::Request.new(sess, "SpecialItemAdd")
16
+ rq.special_item_type = item_type
17
+
18
+ # Insofar as I never actually plan to use this method, just return
19
+ # response.
20
+ return rq.response
21
+ end
22
+ end
4
23
  end
5
24
  end
6
25
 
@@ -0,0 +1,24 @@
1
+ module QBFC
2
+ class Account < List
3
+ include Modifiable
4
+
5
+ class << self
6
+
7
+ # Adds a SpecialAccount, per SDK documentation:
8
+ # "An account normally created automatically as needed within the
9
+ # QuickBooks UI, or in the SDK via the SpecialAccountAdd request."
10
+ #
11
+ # +account_type+ should be a constent, for example:
12
+ #
13
+ # Account.add_special(sess, QBFC_CONST::SatAccountsPayable)
14
+ #
15
+ # See SDK docs for SpecialAccountAdd for more details.
16
+ def add_special(sess, account_type)
17
+ rq = QBFC::Request.new(sess, "SpecialAccountAdd")
18
+ rq.special_account_type = account_type
19
+
20
+ new(sess, rq.response)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,15 +1,15 @@
1
1
  module QBFC
2
2
 
3
3
  # Generated List types that will inherit directly from QBFC::List
4
- LIST_TYPES = %w{Account BillingRate CustomerMsg CustomerType JobType PaymentMethod
5
- PayrollItemNonWage PayrollItemWage PriceLevel SalesRep SalesTaxCode ShipMethod ToDo
6
- Vehicle VendorType}
4
+ LIST_TYPES = %w{ BillingRate CustomerMsg CustomerType JobType PaymentMethod
5
+ PayrollItemNonWage PayrollItemWage PriceLevel SalesRep SalesTaxCode
6
+ ShipMethod ToDo Vehicle VendorType}
7
7
 
8
- # Generated List types that do not accept Mod Requests
9
- LIST_NO_MOD_TYPES = %w{ BillingRate CustomerMsg CustomerType JobType PaymentMethod
10
- PayrollItemWage SalesTaxCode ShipMethod ToDo VendorType}
8
+ # Generated List types that do accept Mod Requests
9
+ # (most direct subclasses of List do not)
10
+ LIST_MOD_TYPES = %w{ PriceLevel SalesRep Vehicle }
11
11
 
12
12
  # Generate List subclasses
13
- generate(LIST_TYPES, List, {Modifiable => LIST_TYPES - LIST_NO_MOD_TYPES})
13
+ generate(LIST_TYPES, List, {Modifiable => LIST_MOD_TYPES})
14
14
 
15
15
  end
@@ -103,6 +103,7 @@ module QBFC
103
103
  obj = @ole_object.send(ole_method_name)
104
104
 
105
105
  if detect_ole_method?(obj, "SetValue")
106
+ params[0] = params[0].strftime("%Y-%m-%d") if params[0].kind_of?(Date)
106
107
  obj.SetValue(*params)
107
108
  if @setter && detect_ole_method?(@setter, ole_method_name)
108
109
  @setter.send(ole_method_name).SetValue(*params)
@@ -1,34 +1,21 @@
1
1
  # This file sets up the classes for QuickBooks entities, transactions and reports.
2
2
 
3
- # Types that allow Query and Delete only
4
- QBFC_DELETE_ONLY = %w{PayrollItemNonWage DataEventRecoveryInfo}
5
-
6
3
  # Report types return an IReportRet
7
- QBFC_REPORT_TYPES = %w{AgingReport BudgetSummaryReport CustomDetailReport CustomSummaryReport
8
- GeneralDetailReport GeneralSummaryReport JobReport PayrollDetailReport PayrollSummaryReport TimeReport }
9
-
10
- # Types that allow Special adds (Pre-defined and normally added automatically by QuickBooks)
11
- QBFC_HAS_SPECIAL_ADD = %w{Account Item}
4
+ QBFC_REPORT_TYPES = %w{AgingReport BudgetSummaryReport CustomDetailReport
5
+ CustomSummaryReport GeneralDetailReport GeneralSummaryReport JobReport
6
+ PayrollDetailReport PayrollSummaryReport TimeReport }
12
7
 
13
- # TODO: Here and below arrays I haven't yet formed any approach to dealing with.
14
- # I leave them here as a reminder.
15
- ELEMENTS_ADD_MOD = %w{ DataExt }
16
-
17
- ELEMENTS_ADD_MOD_QUERY = %w{ DataExtDef }
18
-
19
- # Types that have their own DelRq
20
- ELEMENT_DEL_TYPES = %w{DataEventRecoveryInfo DataExt DataExtDef}
8
+ # Very non-standard elements. I haven't yet formed an approach to dealing
9
+ # with these; I leave them here as a reminder.
10
+ QBFC_NON_STANDARD_TYPES = %w{ DataExt DataExtDef DataEventRecoveryInfo ItemAssembliesCanBuild}
21
11
 
22
12
  # Query types support Query requests only and return an itemized list of some sort;
23
13
  # most of these may be integrated as special finders for their types.
24
14
  QBFC_QUERY_TYPES = %w{BillToPay ListDeleted ReceivePaymentToDeposit Template TxnDeleted SalesTaxPaymentCheck}
25
15
 
26
- QBFC_ANOTHER_TO_INTEGRATE_SOMEWHERE = %w{ ItemAssembliesCanBuild }
27
-
28
-
29
16
  module QBFC
30
17
  # Create QBElement classes
31
- (QBFC_REPORT_TYPES + QBFC_DELETE_ONLY + %w{DataExt DataExtDef}).uniq.each do | qb_element_name |
18
+ (QBFC_REPORT_TYPES + QBFC_NON_STANDARD_TYPES + QBFC_QUERY_TYPES).uniq.each do | qb_element_name |
32
19
  const_set(qb_element_name, Class.new(Base))
33
20
  end
34
21
  end
@@ -75,45 +75,58 @@ module QBFC
75
75
  self.query.ole_object.ortype == -1 ||
76
76
  self.query.ole_object.ortype == 2
77
77
  end
78
-
79
- # Applies options from a Hash. This method is primarily experimental
80
- # (and proof of concept) at this time.
78
+
79
+ # Applies options from a Hash. This method is generally used by find methods
80
+ # (see Element.find for details)
81
81
  def apply_options(options)
82
82
  if options.kind_of? Hash
83
- filters = options[:conditions]
84
- if filters
85
- if filters[:txn_date]
86
- txn_date_filter = q.ORTxnQuery.TxnFilter.ORDateRangeFilter.TxnDateRangeFilter.ORTxnDateRangeFilter.TxnDateFilter
87
- txn_date_filter.FromTxnDate.SetValue( filters[:txn_date][0] ) if filters[:txn_date][0]
88
- txn_date_filter.ToTxnDate.SetValue( filters[:txn_date][1] ) if filters[:txn_date][1]
89
- filters.delete(:txn_date)
90
- end
83
+ conditions = options.delete(:conditions) || {}
84
+
85
+ conditions.each do | c_name, c_value |
86
+ c_name = c_name.to_s
91
87
 
92
- if filters[:ref_number]
93
- ref_num_filter = q.send("OR#{self.qb_name}Query").send("#{self.qb_name}Filter").
94
- ORRefNumberFilter.RefNumberRangeFilter
95
- ref_num_filter.FromRefNumber.SetValue( filters[:ref_number][0] ) if filters[:ref_number][0]
96
- ref_num_filter.ToRefNumber.SetValue( filters[:ref_number][1] ) if filters[:ref_number][1]
97
- filters.delete(:ref_number)
98
- end
99
-
100
- filters.each do |filter, value|
101
- q.send("OR#{self.qb_name}Query").
102
- send("#{self.qb_name}Filter").
103
- send("#{filter}=", QBFC_CONST::PsNotPaidOnly)
88
+ case c_name
89
+ when /list\Z/i
90
+ # List filters
91
+ list = query.__send__(c_name.camelize)
92
+ c_value = [c_value] unless c_value.kind_of?(Array)
93
+ c_value.each { |i| list.Add(i) }
94
+ when /range\Z/i
95
+ # Range filters
96
+ c_value = parse_range_value(c_value)
97
+ range_filter = filter_for(c_name)
98
+ range_name = c_name.match(/(.*)_range\Z/i)[1]
99
+ if range_name == 'modified_date'
100
+ # Modified Date Range use the IQBDateTimeType which requires a\
101
+ # boolean 'asDateOnly' value.
102
+ range_filter.__send__("from_#{range_name}=", c_value.first, true) if c_value.first
103
+ range_filter.__send__("to_#{range_name}=", c_value.last, true) if c_value.last
104
+ else
105
+ range_filter.__send__("from_#{range_name}=", c_value.first) if c_value.first
106
+ range_filter.__send__("to_#{range_name}=", c_value.last) if c_value.last
107
+ end
108
+ when /status\Z/i
109
+ # Status filters
110
+ filter.__send__("#{c_name}=", c_value)
111
+ else
112
+ # Reference filters - Only using FullNameList for now
113
+ ref_filter = filter_for(c_name)
114
+ c_value = [c_value] unless c_value.respond_to?(:each)
115
+ c_value.each do | val |
116
+ ref_filter.FullNameList.Add(val)
117
+ end
104
118
  end
105
-
106
- options.delete(:conditions)
107
119
  end
108
120
 
109
121
  add_owner_ids(options.delete(:owner_id))
122
+ add_limit(options.delete(:limit))
123
+ add_includes(options.delete(:include))
110
124
 
111
125
  options.each do |key, value|
112
- q.send(key.to_s.camelize).SetValue(value)
126
+ self.send(key.to_s.camelize).SetValue(value)
113
127
  end
114
128
  end
115
- end
116
-
129
+ end
117
130
 
118
131
  # Add one or more OwnerIDs to the Request. Used in retrieving
119
132
  # custom fields (aka private data extensions).
@@ -127,6 +140,111 @@ module QBFC
127
140
  end
128
141
  end
129
142
 
143
+ # Set MaxReturned to limit the number of records returned.
144
+ def add_limit(limit)
145
+ filter.max_returned = limit if limit
146
+ end
147
+
148
+ # add_includes accepts an Array of elements to include in the return of the
149
+ # Request. The array may include either or both of elements that are
150
+ # additional to normal returns (such as Line Items, Linked Transactions)
151
+ # or elements that are normally included (to be added to the
152
+ # IncludeRetElementList).
153
+ #
154
+ # If elements are given that would be added to IncludeRetElementList, this
155
+ # limits the elements returned to *only* those included in the array.
156
+ #
157
+ # Another option is to give :all as the argument, which will always return
158
+ # as many elements as possible.
159
+ #
160
+ # add_includes is typically called by #apply_options, typically called
161
+ # from Element.find, as seen in the examples below:
162
+ #
163
+ # @sess.checks.find(:all, :include => [:linked_txns]) -> Include linked transactions
164
+ # @sess.checks.find(:all, :include => [:txn_id]) -> Include +only+ TxnID
165
+ # @sess.checks.find(:all, :include => :all) ->
166
+ # Includes all elements, including LinkedTxns and LineItems.
167
+ def add_includes(inc)
168
+ return if inc.nil?
169
+
170
+ inc = [inc] if (!inc.respond_to?(:each) || inc.kind_of?(String))
171
+
172
+ if inc.include?(:all)
173
+ ole_methods.each do |m|
174
+ m = m.to_s
175
+ if m =~ /\AInclude/ && m != 'IncludeRetElementList'
176
+ @request.__send__("#{m.underscore}=", true)
177
+ end
178
+ end
179
+ return
180
+ end
181
+
182
+ inc.each do |item|
183
+ cam_item = item.to_s.camelize.gsub(/Id/, "ID")
184
+ if @request.respond_to_ole?("Include#{cam_item}")
185
+ @request.__send__("include_#{item}=", true)
186
+ else
187
+ @request.IncludeRetElementList.Add(cam_item)
188
+ end
189
+ end
190
+ end
191
+
192
+ # Parse a value for a range filter. This can be a Range, a one or more
193
+ # element Array or a single value. For a single value or one-element array
194
+ # value#last should return nil. The calling method (#apply_options) will
195
+ # call value#first and value#last to set the from and to values
196
+ # respectively.
197
+ def parse_range_value(value)
198
+ value << nil if value.kind_of?(Array) && value.length == 1
199
+ value = [value, nil] if (value.kind_of?(String) || !value.respond_to?(:first))
200
+ value
201
+ end
202
+
203
+ # Determine and return the Filter object for the given filter name, dealing
204
+ # with OR's and other "weird" circumstances.
205
+ # NB: This method may well miss some situations. Hopefully, it will become
206
+ # more complete in time.
207
+ def filter_for(name)
208
+ name = name.camelize + "Filter"
209
+ f = nil
210
+
211
+ # List queries place the modified_date_range directly in the filter
212
+ if name == 'ModifiedDateRangeFilter'
213
+ return filter if filter.respond_to_ole?('FromModifiedDate')
214
+ end
215
+
216
+ # Try to get the filter directly
217
+ if filter.respond_to_ole?(name)
218
+ f = filter.send(name)
219
+ end
220
+
221
+ # Check if this is within an 'OR'
222
+ if filter.respond_to_ole?("OR#{name}")
223
+ f = filter.send("OR#{name}").send(name)
224
+ elsif filter.respond_to_ole?("OR#{name.gsub(/Range/, '')}")
225
+ f = filter.send("OR#{name.gsub(/Range/, '')}").send(name)
226
+ end
227
+
228
+ # DateRange OR's
229
+ if filter.respond_to_ole?("ORDateRangeFilter") && name =~ /DateRange/i
230
+ f = filter.send("ORDateRangeFilter").send(name)
231
+ end
232
+
233
+ # It might have a nested OR
234
+ if f && f.respond_to_ole?("OR#{name}")
235
+ f = f.send("OR#{name}")
236
+ end
237
+
238
+ # Ranges might have another step, with the 'Range' removed.
239
+ if f && f.respond_to_ole?(name.gsub(/Range/, ''))
240
+ f = f.send(name.gsub(/Range/, ''))
241
+ end
242
+
243
+ return f
244
+ end
245
+
246
+ private :parse_range_value, :filter_for
247
+
130
248
  # Send missing methods to @ole_object (OLEWrapper)
131
249
  def method_missing(symbol, *params) #:nodoc:
132
250
  @request.qbfc_method_missing(@sess, symbol, *params)
@@ -114,8 +114,12 @@ module QBFC
114
114
  def method_missing(symbol, *params) #:nodoc:
115
115
  if (('a'..'z') === symbol.to_s[0].chr && symbol.to_s[-1].chr != '=')
116
116
  camelized_method = symbol.to_s.camelize.to_sym
117
- single_camelized_method = symbol.to_s.singularize.camelize.to_sym
118
- if QBFC.const_defined?(camelized_method)
117
+ if camelized_method.to_s =~ /Terms\Z/
118
+ single_camelized_method = camelized_method
119
+ else
120
+ single_camelized_method = symbol.to_s.singularize.camelize.to_sym
121
+ end
122
+ if QBFC.const_defined?(camelized_method) && camelized_method.to_s !~ /Terms\Z/
119
123
  if params[0]
120
124
  return QBFC::const_get(camelized_method).find_by_unique_id(self, params[0])
121
125
  else
@@ -1,18 +1,25 @@
1
1
  module QBFC
2
2
 
3
3
  # Generated Transaction types
4
- TXN_TYPES = %w{ARRefundCreditCard Bill BillPaymentCheck BillPaymentCreditCard BuildAssembly Charge Check CreditCardCharge
5
- CreditCardCredit CreditMemo Deposit Estimate InventoryAdjustment Invoice ItemReceipt JournalEntry PurchaseOrder
6
- ReceivePayment SalesOrder SalesReceipt SalesTaxPaymentCheck TimeTracking VehicleMileage VendorCredit}
4
+ TXN_TYPES = %w{ARRefundCreditCard Bill BillPaymentCheck BillPaymentCreditCard
5
+ BuildAssembly Charge Check CreditCardCharge CreditCardCredit CreditMemo
6
+ Deposit Estimate InventoryAdjustment Invoice ItemReceipt JournalEntry
7
+ PurchaseOrder ReceivePayment SalesOrder SalesReceipt SalesTaxPaymentCheck
8
+ TimeTracking VehicleMileage VendorCredit}
7
9
 
8
10
  # Generated Transaction types that support TxnVoid Request
9
- TXN_VOIDABLE_TYPES = %w{ARRefundCreditCard Bill BillPaymentCheck BillPaymentCreditCard Charge Check CreditCardCharge CreditCardCredit
10
- CreditMemo Deposit InventoryAdjustment Invoice ItemReceipt JournalEntry SalesReceipt VendorCredit}
11
+ TXN_VOIDABLE_TYPES = %w{ARRefundCreditCard Bill BillPaymentCheck
12
+ BillPaymentCreditCard Charge Check CreditCardCharge CreditCardCredit
13
+ CreditMemo Deposit InventoryAdjustment Invoice ItemReceipt JournalEntry
14
+ SalesReceipt VendorCredit}
11
15
 
12
16
  # Generated Transaction types that don't support Mod Requests
13
- TXN_NO_MOD_TYPES = %w{ARRefundCreditCard BillPaymentCreditCard Deposit InventoryAdjustment VehicleMileage VendorCredit }
17
+ TXN_NO_MOD_TYPES = %w{ARRefundCreditCard BillPaymentCreditCard Deposit
18
+ InventoryAdjustment VehicleMileage VendorCredit }
14
19
 
15
20
  # Generate Transaction subclasses
16
- generate(TXN_TYPES, Transaction, {Modifiable => (TXN_TYPES - TXN_NO_MOD_TYPES), Voidable => TXN_VOIDABLE_TYPES})
21
+ generate(TXN_TYPES, Transaction,
22
+ { Modifiable => (TXN_TYPES - TXN_NO_MOD_TYPES),
23
+ Voidable => TXN_VOIDABLE_TYPES })
17
24
 
18
25
  end
@@ -52,8 +52,9 @@ module QBFC
52
52
 
53
53
  def close
54
54
  @sess.close
55
+ sleep(1)
55
56
  unless @is_reader
56
- sleep(5)
57
+ sleep(3)
57
58
  FileUtils.rm_rf(@dirname)
58
59
  end
59
60
  end
@@ -37,7 +37,7 @@ describe QBFC::Element do
37
37
  # Filter mock
38
38
  @filter = mock("QBFC::OLEWrapper#Filter")
39
39
  @request.stub!(:filter).and_return(@filter)
40
- @filter.stub!(:max_returned=)
40
+ @request.stub!(:add_limit)
41
41
  @request.stub!(:filter_available?).and_return(true)
42
42
  @request.stub!(:apply_options)
43
43
  end
@@ -66,16 +66,15 @@ describe QBFC::Element do
66
66
 
67
67
  it "should set request#max_returned to 1 if :first" do
68
68
  setup_request
69
- @request.should_receive(:filter).and_return(@filter)
69
+ @request.should_receive(:add_limit).with(1)
70
70
  @request.stub!(:filter_available?).and_return(true)
71
- @filter.should_receive(:max_returned=).with(1)
72
71
  QBFC::Test::ElementFind::find(@sess, :first)
73
72
  end
74
73
 
75
74
  it "should not set request#max_returned if not request.filter_available?" do
76
75
  setup_request
77
76
  @request.stub!(:filter_available?).and_return(false)
78
- @request.should_not_receive(:filter)
77
+ @request.should_not_receive(:add_limit)
79
78
  QBFC::Test::ElementFind::find(@sess, :first)
80
79
  end
81
80
 
@@ -97,9 +96,11 @@ describe QBFC::Element do
97
96
  QBFC::Test::ElementFind::find(@sess, :first).should be_nil
98
97
  end
99
98
 
100
- it "can accept a Request object"
101
- it "generates a Request object if not given one"
102
- it "accepts conditions"
99
+ it "should call Base.parse_find_args" do
100
+ setup_request
101
+ QBFC::Test::ElementFind::should_receive(:parse_find_args).with({:option => true})
102
+ QBFC::Test::ElementFind::find(@sess, :all, {:option => true})
103
+ end
103
104
 
104
105
  it "applies options to request" do
105
106
  setup_request
@@ -107,8 +108,6 @@ describe QBFC::Element do
107
108
  QBFC::Test::ElementFind::find(@sess, :first, :owner_id => 0)
108
109
  end
109
110
 
110
- it "passes additional arguments to Request"
111
-
112
111
  it "should get request#response" do
113
112
  setup_request
114
113
  @request.should_receive(:response).and_return(@response)
@@ -138,9 +137,12 @@ describe QBFC::Element do
138
137
  @element = mock(QBFC::Test::ElementFind)
139
138
  @base_element = mock(QBFC::Test::BaseFind)
140
139
  @customer_ret = mock("CustomerRet")
141
- @base_element.stub!(:ole_methods).and_return(["CustomerRet"])
140
+ @list_id = mock("ListID")
141
+ @base_element.stub!(:ole_methods).and_return(["VendorRet", "CustomerRet"])
142
+ @base_element.stub!(:VendorRet).and_return(nil)
142
143
  @base_element.stub!(:CustomerRet).and_return(@customer_ret)
143
- @customer_ret.stub!(:ListID).and_return("123-456")
144
+ @customer_ret.stub!(:ListID).and_return(@list_id)
145
+ @list_id.stub!(:GetValue).and_return("123-456")
144
146
  QBFC::Customer.stub!(:find_by_id).and_return(@element)
145
147
 
146
148
  @response.stub!(:GetAt).and_return(@base_element)
@@ -154,7 +156,8 @@ describe QBFC::Element do
154
156
 
155
157
  it "should send class ChildList::find_by_id with ListID and find options for each" do
156
158
  @base_element.should_receive(:CustomerRet).at_least(:once).and_return(@customer_ret)
157
- @customer_ret.should_receive(:ListID).at_least(:once).and_return("789-012")
159
+ @customer_ret.should_receive(:ListID).at_least(:once).and_return(@list_id)
160
+ @list_id.should_receive(:GetValue).at_least(:once).and_return("789-012")
158
161
  QBFC::Customer.should_receive(:find_by_id).at_least(:once).with(@sess, "789-012", {}).and_return(@element)
159
162
  QBFC::Test::BaseFind.find(@sess, :first, @request, {}).should be(@element)
160
163
  end
@@ -15,4 +15,19 @@ describe QBFC::Item do
15
15
  it "should return subclass objects"
16
16
  end
17
17
 
18
+ describe ".add_special" do
19
+ before(:each) do
20
+ @request = mock("QBFC::Request")
21
+ @response = mock("QBFC::Request#response")
22
+ end
23
+
24
+ it "should add a Special Account" do
25
+ QBFC::Request.should_receive(:new).with(@sess, "SpecialItemAdd").and_return(@request)
26
+ @request.should_receive(:special_item_type=).with(QBFC_CONST::SitFinanceCharge)
27
+ @request.should_receive(:response).and_return(@response)
28
+
29
+ QBFC::Item.add_special(@sess, QBFC_CONST::SitFinanceCharge)
30
+ end
31
+ end
32
+
18
33
  end
@@ -23,7 +23,7 @@ describe QBFC::List do
23
23
  # Filter mock
24
24
  @filter = mock("QBFC::OLEWrapper#Filter")
25
25
  @request.stub!(:filter).and_return(@filter)
26
- @filter.stub!(:max_returned=)
26
+ @request.stub!(:add_limit)
27
27
  @request.stub!(:filter_available?).and_return(true)
28
28
  @request.stub!(:apply_options)
29
29
  end
@@ -0,0 +1,20 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe QBFC::Account do
4
+
5
+ before(:each) do
6
+ @sess = mock(QBFC::Session)
7
+ @request = mock("QBFC::Request")
8
+ @response = mock("QBFC::Request#response")
9
+ end
10
+
11
+ it "should add a Special Account" do
12
+ QBFC::Request.should_receive(:new).with(@sess, "SpecialAccountAdd").and_return(@request)
13
+ @request.should_receive(:special_account_type=).with(QBFC_CONST::SatAccountsReceivable)
14
+ @request.should_receive(:response).and_return(@response)
15
+ QBFC::Account.should_receive(:new).with(@sess, @response)
16
+
17
+ QBFC::Account.add_special(@sess, QBFC_CONST::SatAccountsReceivable)
18
+ end
19
+
20
+ end
@@ -140,6 +140,13 @@ describe QBFC::OLEWrapper do
140
140
 
141
141
  @wrapper.qbfc_method_missing(@sess, :full_name=, 'Full Name')
142
142
  end
143
+
144
+ it "should convert Dates in setter method" do
145
+ @ole_object.should_receive(:TimeModified).and_return(@full_name)
146
+ @full_name.should_receive(:SetValue).with('2008-01-01')
147
+
148
+ @wrapper.qbfc_method_missing(@sess, :time_modified=, Date.parse('2008-01-01'))
149
+ end
143
150
 
144
151
  it "should set @setter also when acting as a setter method, if applicable" do
145
152
  @setter = mock(WIN32OLE)
@@ -6,7 +6,7 @@ lists
6
6
  - list_id_list
7
7
  - full_name_list
8
8
  - txn_id_list
9
- - ref_number_list
9
+ X ref_number_list
10
10
  - ref_number_case_sensitive_list
11
11
 
12
12
  filters
@@ -199,12 +199,249 @@ describe QBFC::Request do
199
199
  describe "#apply_options" do
200
200
  before(:each) do
201
201
  @request = QBFC::Request.new(@sess, 'CustomerQuery')
202
+ @query = mock('Request#query')
203
+ @filter = mock('Request#filter')
204
+ @request.stub!(:query).and_return(@query)
202
205
  end
203
206
 
204
- it "accepts an :owner_id option" do
207
+ it "should apply an :owner_id option" do
205
208
  @request.should_receive(:add_owner_ids).with(1)
206
209
  @request.apply_options(:owner_id => 1)
207
210
  end
211
+
212
+ it "should apply an :limit option" do
213
+ @request.should_receive(:add_limit).with(1)
214
+ @request.apply_options(:limit => 1)
215
+ end
216
+
217
+ it "should apply an :include option" do
218
+ include_ary = [1,2,3]
219
+ @request.should_receive(:add_includes).with(include_ary)
220
+ @request.apply_options(:include => include_ary)
221
+ end
222
+
223
+ it "should apply lists to query" do
224
+ ref_number_list = mock('OLEWrapper#ref_number_list')
225
+ @query.should_receive(:RefNumberList).and_return(ref_number_list)
226
+ ref_number_list.should_receive(:Add).with('82')
227
+ ref_number_list.should_receive(:Add).with('1234')
228
+
229
+ @request.apply_options(:conditions => {:ref_number_list => %w{82 1234}})
230
+ end
231
+
232
+ it "should apply lists to query when given a single item" do
233
+ ref_number_list = mock('OLEWrapper#ref_number_list')
234
+ @query.should_receive(:RefNumberList).and_return(ref_number_list)
235
+ ref_number_list.should_receive(:Add).with('20')
236
+
237
+ @request.apply_options(:conditions => {:ref_number_list => '20'})
238
+ end
239
+
240
+ describe "(range)" do
241
+ before(:each) do
242
+ @range_filter = mock('Request#TxnDateRangeFilter')
243
+ @request.stub!(:filter_for).with('txn_date_range').and_return(@range_filter)
244
+ @request.stub!(:filter_for).with('modified_date_range').and_return(@range_filter)
245
+ @range_filter.stub!(:from_txn_date=)
246
+ @range_filter.stub!(:to_txn_date=)
247
+ end
248
+
249
+ it "should #parse_range_value" do
250
+ @request.should_receive(:parse_range_value).with([0,2]).and_return([0,2])
251
+ @request.apply_options(:conditions => {:txn_date_range => [0,2]})
252
+ end
253
+
254
+ it "should get appropriate filter" do
255
+ @request.should_receive(:filter_for).with('txn_date_range').and_return(@range_filter)
256
+ @request.apply_options(:conditions => {:txn_date_range => [0,2]})
257
+ end
258
+
259
+ it "should apply date range to filter" do
260
+ @range_filter.should_receive(:from_txn_date=).with(0)
261
+ @range_filter.should_receive(:to_txn_date=).with(2)
262
+ @request.apply_options(:conditions => {:txn_date_range => [0,2]})
263
+ end
264
+
265
+ it "should add 'true' argument (asDateOnly) for modified_date ranges" do
266
+ @range_filter.should_receive(:from_modified_date=).with(0, true)
267
+ @range_filter.should_receive(:to_modified_date=).with(2, true)
268
+ @request.apply_options(:conditions => {:modified_date_range => [0,2]})
269
+ end
270
+ end
271
+
272
+ describe "(status)" do
273
+ it "should set status" do
274
+ @filter = mock('Request#filter')
275
+ @request.stub!(:filter).and_return(@filter)
276
+ @filter.should_receive(:paid_status=).with(QBFC_CONST::PsPaidOnly)
277
+ @request.apply_options(:conditions => {:paid_status => QBFC_CONST::PsPaidOnly})
278
+ end
279
+ end
280
+
281
+ describe "(reference)" do
282
+ before(:each) do
283
+ @ref_filter = mock('Request#RefFilter')
284
+ @full_name_list = mock('OLEWrapper#FullNameList')
285
+ @request.stub!(:filter_for).with('entity').and_return(@ref_filter)
286
+ @ref_filter.should_receive(:FullNameList).at_least(:once).and_return(@full_name_list)
287
+ @full_name_list.stub!(:Add)
288
+ end
289
+
290
+ it "should get appropriate filter" do
291
+ @request.should_receive(:filter_for).with('entity').and_return(@ref_filter)
292
+ @request.apply_options(:conditions => {:entity => 'ABC Supplies'})
293
+ end
294
+
295
+ it "should set a single full name" do
296
+ @full_name_list.should_receive(:Add).with('ABC Supplies')
297
+ @request.apply_options(:conditions => {:entity => 'ABC Supplies'})
298
+ end
299
+
300
+ it "should set a single full name (non-string)" do
301
+ @full_name_list.should_receive(:Add).with(1)
302
+ @request.apply_options(:conditions => {:entity => 1})
303
+ end
304
+
305
+ it "should set a multiple full names" do
306
+ @full_name_list.should_receive(:Add).with('ABC Supplies')
307
+ @full_name_list.should_receive(:Add).with('CompuStuff')
308
+ @request.apply_options(:conditions => {:entity => %w{ABC\ Supplies CompuStuff}})
309
+ end
310
+ end
311
+ end
312
+
313
+ describe "#add_includes" do
314
+ before(:each) do
315
+ @request = QBFC::Request.new(@sess, 'CustomerQuery')
316
+ @ret_list = mock('RetElementList')
317
+
318
+ @ole_request.stub!(:respond_to_ole?).with('IncludeLineItems').and_return(true)
319
+ @ole_request.stub!(:respond_to_ole?).with('IncludeLinkedTxns').and_return(true)
320
+ @ole_request.stub!(:respond_to_ole?).with('IncludeTxnID').and_return(false)
321
+ @ole_request.stub!(:respond_to_ole?).with('IncludeCustomerRef').and_return(false)
322
+ end
323
+
324
+ it "should add specific include requests" do
325
+ @ole_request.should_receive(:include_line_items=).with(true)
326
+ @request.__send__(:add_includes, [:line_items])
327
+ end
328
+
329
+ it "should apply additional includes to IncludeRetElementList" do
330
+ @ole_request.should_receive(:IncludeRetElementList).twice.and_return(@ret_list)
331
+ @ret_list.should_receive(:Add).with('TxnID')
332
+ @ret_list.should_receive(:Add).with('CustomerRef')
333
+ @request.__send__(:add_includes, [:txn_id, :customer_ref])
334
+ end
335
+
336
+ it "should include :all" do
337
+ @ole_request.should_receive(:ole_methods).and_return(%w{ORTxnQuery IncludeLineItems IncludeLinkedTxns iterator})
338
+ @ole_request.should_receive(:include_line_items=).with(true)
339
+ @ole_request.should_receive(:include_linked_txns=).with(true)
340
+ @request.__send__(:add_includes, :all)
341
+ end
342
+ end
343
+
344
+ describe "#parse_range_value" do
345
+ before(:each) do
346
+ @request = QBFC::Request.new(@sess, 'CustomerQuery')
347
+ end
348
+
349
+ it "should add a nil element to a one-element Array" do
350
+ ary = [0]
351
+ @request.__send__(:parse_range_value, ary).should == [0, nil]
352
+ end
353
+
354
+ it "should return unchanged a multiple element Array" do
355
+ ary = [0, 1]
356
+ @request.__send__(:parse_range_value, ary).should be(ary)
357
+ end
358
+
359
+ it "should return unchanged a Range" do
360
+ rng = 0..1
361
+ @request.__send__(:parse_range_value, rng).should be(rng)
362
+ end
363
+
364
+ it "should take a scalar and return an array with the second element nil" do
365
+ val = 0
366
+ @request.__send__(:parse_range_value, val).should == [val, nil]
367
+ end
368
+
369
+ it "should take a String scalar and return an array with the second element nil" do
370
+ val = '0'
371
+ @request.__send__(:parse_range_value, val).should == [val, nil]
372
+ end
373
+
374
+ end
375
+
376
+ describe "#filter_for" do
377
+ before(:each) do
378
+ @request = QBFC::Request.new(@sess, 'CustomerQuery')
379
+ @query = mock('Request#query')
380
+ @filter = mock('Request#filter')
381
+ @request.stub!(:query).and_return(@query)
382
+ @request.stub!(:filter).and_return(@filter)
383
+
384
+ @or_date_range_filter = mock('Request#ORDateRangeFilter')
385
+ @or_ref_number_filter = mock('Request#ORRefNumberFilter')
386
+ @txn_date_range_filter = mock('Request#TxnDateRangeFilter')
387
+ @final_filter = mock('Request#FinalFilter')
388
+
389
+ @filter.stub!(:respond_to_ole?).and_return(false)
390
+ @or_date_range_filter.stub!(:respond_to_ole?).and_return(false)
391
+ @final_filter.stub!(:respond_to_ole?).and_return(false)
392
+ end
393
+
394
+ it "should follow ORDateRangeFilter for date_ranges" do
395
+ @filter.should_receive(:respond_to_ole?).with('ORDateRangeFilter').and_return(true)
396
+ @filter.should_receive(:ORDateRangeFilter).and_return(@or_date_range_filter)
397
+ @or_date_range_filter.should_receive(:ModifiedDateRangeFilter).and_return(@final_filter)
398
+
399
+ @request.__send__(:filter_for, 'modified_date_range').should be(@final_filter)
400
+ end
401
+
402
+ it "should follow OR{name}Filter" do
403
+ @filter.should_receive(:respond_to_ole?).with('ORRefNumberFilter').and_return(true)
404
+ @filter.should_receive(:ORRefNumberFilter).and_return(@or_ref_number_filter)
405
+ @or_ref_number_filter.should_receive(:RefNumberFilter).and_return(@final_filter)
406
+
407
+ @request.__send__(:filter_for, 'ref_number').should be(@final_filter)
408
+ end
409
+
410
+ it "should follow OR{name}Filter, with 'Range' removed" do
411
+ @filter.should_receive(:respond_to_ole?).with('ORRefNumberFilter').and_return(true)
412
+ @filter.should_receive(:ORRefNumberFilter).and_return(@or_ref_number_filter)
413
+ @or_ref_number_filter.should_receive(:RefNumberRangeFilter).and_return(@final_filter)
414
+
415
+ @request.__send__(:filter_for, 'ref_number_range').should be(@final_filter)
416
+ end
417
+
418
+ it "should return #filter if *ModifiedDate in #filter" do
419
+ @filter.should_receive(:respond_to_ole?).with('FromModifiedDate').and_return(true)
420
+ @request.__send__(:filter_for, 'modified_date_range').should == @filter
421
+ end
422
+
423
+ it "should follow OR below the Filter" do
424
+ @filter.should_receive(:respond_to_ole?).with('TxnDateRangeFilter').and_return(true)
425
+ @filter.should_receive(:TxnDateRangeFilter).and_return(@txn_date_range_filter)
426
+
427
+ @txn_date_range_filter.should_receive(:respond_to_ole?).with('ORTxnDateRangeFilter').and_return(true)
428
+ @txn_date_range_filter.should_receive(:ORTxnDateRangeFilter).and_return(@or_date_range_filter)
429
+
430
+ @request.__send__(:filter_for, 'txn_date_range').should be(@or_date_range_filter)
431
+ end
432
+
433
+ it "should get a nested Filter with 'Range' removed" do
434
+ @filter.should_receive(:respond_to_ole?).with('TxnDateRangeFilter').and_return(true)
435
+ @filter.should_receive(:TxnDateRangeFilter).and_return(@txn_date_range_filter)
436
+
437
+ @txn_date_range_filter.should_receive(:respond_to_ole?).with('ORTxnDateRangeFilter').and_return(true)
438
+ @txn_date_range_filter.should_receive(:ORTxnDateRangeFilter).and_return(@or_date_range_filter)
439
+
440
+ @or_date_range_filter.should_receive(:respond_to_ole?).with('TxnDateFilter').and_return(true)
441
+ @or_date_range_filter.should_receive(:TxnDateFilter).and_return(@final_filter)
442
+
443
+ @request.__send__(:filter_for, 'txn_date_range').should be(@final_filter)
444
+ end
208
445
  end
209
446
 
210
447
  describe "#add_owner_ids" do
@@ -233,4 +470,17 @@ describe QBFC::Request do
233
470
  @request.add_owner_ids(nil)
234
471
  end
235
472
  end
473
+
474
+ describe "#add_limit" do
475
+ before(:each) do
476
+ @request = QBFC::Request.new(@sess, 'CustomerQuery')
477
+ @filter = mock('Request#filter')
478
+ @request.stub!(:filter).and_return(@filter)
479
+ end
480
+
481
+ it "can should update the filter's max_returned value" do
482
+ @filter.should_receive(:max_returned=).with(1)
483
+ @request.add_limit(1)
484
+ end
485
+ end
236
486
  end
@@ -124,6 +124,12 @@ describe QBFC::Session do
124
124
  QBFC::QBCollection.should_receive(:new).with(@qb_sess, :QBClass).and_return(@collection)
125
125
  @qb_sess.classes.should == @collection
126
126
  end
127
+
128
+ it "should create QBFC::QBCollection for QBFC::Terms from #terms" do
129
+ @collection = mock(QBFC::QBCollection)
130
+ QBFC::QBCollection.should_receive(:new).with(@qb_sess, :Terms).and_return(@collection)
131
+ @qb_sess.terms.should == @collection
132
+ end
127
133
 
128
134
  it "should let OLEWrapper handle other unknown methods" do
129
135
  @ole_wrapper.should_receive(:qbfc_method_missing).with(@qb_sess, :FullName).and_return(true)
@@ -23,7 +23,7 @@ describe QBFC::Transaction do
23
23
  # Filter mock
24
24
  @filter = mock("QBFC::OLEWrapper#Filter")
25
25
  @request.stub!(:filter).and_return(@filter)
26
- @filter.stub!(:max_returned=)
26
+ @request.stub!(:add_limit)
27
27
  @request.stub!(:filter_available?).and_return(true)
28
28
  @request.stub!(:apply_options)
29
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qbfc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: x86-mswin32-60
6
6
  authors:
7
7
  - Jared Morgan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-22 00:00:00 -06:00
12
+ date: 2008-03-24 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -42,6 +42,7 @@ files:
42
42
  - lib/qbfc/entities/generated.rb
43
43
  - lib/qbfc/infos/generated.rb
44
44
  - lib/qbfc/items/generated.rb
45
+ - lib/qbfc/lists/account.rb
45
46
  - lib/qbfc/lists/generated.rb
46
47
  - lib/qbfc/lists/qb_class.rb
47
48
  - lib/qbfc/terms/generated.rb
@@ -81,6 +82,7 @@ files:
81
82
  - spec/unit/entities/generated_spec.rb
82
83
  - spec/unit/info/generated_spec.rb
83
84
  - spec/unit/items/generated_spec.rb
85
+ - spec/unit/lists/account_spec.rb
84
86
  - spec/unit/lists/generated_spec.rb
85
87
  - spec/unit/lists/qb_class_spec.rb
86
88
  - spec/unit/terms/generated_spec.rb
@@ -134,6 +136,7 @@ test_files:
134
136
  - spec/unit/entities/generated_spec.rb
135
137
  - spec/unit/info/generated_spec.rb
136
138
  - spec/unit/items/generated_spec.rb
139
+ - spec/unit/lists/account_spec.rb
137
140
  - spec/unit/lists/generated_spec.rb
138
141
  - spec/unit/lists/qb_class_spec.rb
139
142
  - spec/unit/terms/generated_spec.rb