quickbooks 0.0.2 → 0.0.3
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 +18 -28
- data/Rakefile +17 -30
- data/doc/classes/{QuickBooks/Models/DataExt.html → Class.html} +151 -140
- data/doc/classes/Class.src/M000003.html +18 -0
- data/doc/classes/Hash.html +164 -0
- data/doc/classes/Hash.src/M000001.html +20 -0
- data/doc/classes/Hash.src/M000002.html +23 -0
- data/doc/classes/{QuickBooks/Models/Transaction.html → Object.html} +207 -201
- data/doc/classes/Object.src/M000004.html +24 -0
- data/doc/classes/Object.src/M000005.html +18 -0
- data/doc/classes/Object.src/M000006.html +19 -0
- data/doc/classes/Object.src/M000007.html +18 -0
- data/doc/classes/{QuickBooks.html → QBHelpers.html} +118 -119
- data/doc/classes/QBHelpers/Ole.html +209 -0
- data/doc/classes/QBHelpers/Ole.src/M000066.html +21 -0
- data/doc/classes/QBHelpers/Ole.src/M000067.html +22 -0
- data/doc/classes/QBHelpers/Ole.src/M000068.html +18 -0
- data/doc/classes/Quickbooks.html +136 -0
- data/doc/classes/Quickbooks/Base.html +618 -0
- data/doc/classes/Quickbooks/Base.src/M000034.html +18 -0
- data/doc/classes/Quickbooks/Base.src/M000035.html +18 -0
- data/doc/classes/Quickbooks/Base.src/M000036.html +18 -0
- data/doc/classes/Quickbooks/Base.src/M000037.html +19 -0
- data/doc/classes/Quickbooks/Base.src/M000038.html +19 -0
- data/doc/classes/Quickbooks/Base.src/M000039.html +25 -0
- data/doc/classes/Quickbooks/Base.src/M000040.html +27 -0
- data/doc/classes/Quickbooks/Base.src/M000041.html +22 -0
- data/doc/classes/Quickbooks/Base.src/M000042.html +30 -0
- data/doc/classes/Quickbooks/Base.src/M000043.html +18 -0
- data/doc/classes/Quickbooks/Base.src/M000044.html +19 -0
- data/doc/classes/Quickbooks/Base.src/M000045.html +18 -0
- data/doc/classes/Quickbooks/Base.src/M000046.html +19 -0
- data/doc/classes/Quickbooks/Base.src/M000047.html +22 -0
- data/doc/classes/Quickbooks/Base.src/M000048.html +23 -0
- data/doc/classes/Quickbooks/Base.src/M000049.html +18 -0
- data/doc/classes/Quickbooks/Base.src/M000050.html +21 -0
- data/doc/classes/Quickbooks/Base.src/M000051.html +25 -0
- data/doc/classes/Quickbooks/Base.src/M000052.html +18 -0
- data/doc/classes/Quickbooks/Base.src/M000053.html +36 -0
- data/doc/classes/Quickbooks/Base.src/M000054.html +18 -0
- data/doc/classes/Quickbooks/Base.src/M000055.html +18 -0
- data/doc/classes/Quickbooks/Connection.html +369 -0
- data/doc/classes/{QuickBooks/Models/Customer.src/M000002.html → Quickbooks/Connection.src/M000056.html} +17 -17
- data/doc/classes/Quickbooks/Connection.src/M000057.html +19 -0
- data/doc/classes/Quickbooks/Connection.src/M000058.html +25 -0
- data/doc/classes/{QuickBooks/Connection.src/M000018.html → Quickbooks/Connection.src/M000059.html} +17 -17
- data/doc/classes/Quickbooks/Connection.src/M000060.html +18 -0
- data/doc/classes/Quickbooks/Connection.src/M000061.html +21 -0
- data/doc/classes/Quickbooks/Connection.src/M000062.html +24 -0
- data/doc/classes/{QuickBooks/Connection.src/M000016.html → Quickbooks/Connection.src/M000063.html} +19 -20
- data/doc/classes/{QuickBooks/Connection.src/M000019.html → Quickbooks/Connection.src/M000064.html} +23 -21
- data/doc/classes/Quickbooks/Connection.src/M000065.html +24 -0
- data/doc/classes/{QuickBooks/Models.html → Quickbooks/Customer.html} +112 -120
- data/doc/classes/{QuickBooks/Models/CreditCardInfo.html → Quickbooks/ListItem.html} +176 -148
- data/doc/classes/Quickbooks/ListItem.src/M000033.html +31 -0
- data/doc/classes/Quickbooks/Qbxml.html +138 -0
- data/doc/classes/{QuickBooks/Models/ListItem.html → Quickbooks/Qbxml/Error.html} +167 -173
- data/doc/classes/{QuickBooks/Models/Base.src/M000011.html → Quickbooks/Qbxml/Error.src/M000031.html} +17 -17
- data/doc/classes/Quickbooks/Qbxml/Request.html +182 -0
- data/doc/classes/Quickbooks/Qbxml/Request.src/M000024.html +23 -0
- data/doc/classes/Quickbooks/Qbxml/Request.src/M000025.html +19 -0
- data/doc/classes/Quickbooks/Qbxml/Request.src/M000026.html +57 -0
- data/doc/classes/Quickbooks/Qbxml/RequestSet.html +193 -0
- data/doc/classes/Quickbooks/Qbxml/RequestSet.src/M000027.html +22 -0
- data/doc/classes/Quickbooks/Qbxml/RequestSet.src/M000028.html +26 -0
- data/doc/classes/{QuickBooks/Models/Base.src/M000014.html → Quickbooks/Qbxml/RequestSet.src/M000029.html} +17 -16
- data/doc/classes/Quickbooks/Qbxml/RequestSet.src/M000030.html +22 -0
- data/doc/classes/Quickbooks/Qbxml/RequestSetArrayExt.html +105 -0
- data/doc/classes/{QuickBooks/Connection.html → Quickbooks/Qbxml/Response.html} +301 -278
- data/doc/classes/Quickbooks/Qbxml/Response.src/M000015.html +24 -0
- data/doc/classes/Quickbooks/Qbxml/Response.src/M000016.html +19 -0
- data/doc/classes/Quickbooks/Qbxml/Response.src/M000017.html +45 -0
- data/doc/classes/Quickbooks/Qbxml/Response.src/M000018.html +18 -0
- data/doc/classes/Quickbooks/Qbxml/Response.src/M000019.html +18 -0
- data/doc/classes/Quickbooks/Qbxml/Response.src/M000020.html +18 -0
- data/doc/classes/{QuickBooks/Models/Base.src/M000013.html → Quickbooks/Qbxml/Response.src/M000021.html} +17 -16
- data/doc/classes/{QuickBooks/Models/ListItem.src/M000009.html → Quickbooks/Qbxml/Response.src/M000022.html} +17 -16
- data/doc/classes/Quickbooks/Qbxml/Response.src/M000023.html +52 -0
- data/doc/classes/{QuickBooks/Models/Base.html → Quickbooks/Qbxml/ResponseSet.html} +237 -213
- data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000008.html +22 -0
- data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000009.html +26 -0
- data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000010.html +24 -0
- data/doc/classes/{QuickBooks/Models/Base.src/M000012.html → Quickbooks/Qbxml/ResponseSet.src/M000011.html} +17 -17
- data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000012.html +27 -0
- data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000013.html +18 -0
- data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000014.html +18 -0
- data/doc/classes/Quickbooks/Qbxml/ResponseSetArrayExt.html +105 -0
- data/doc/classes/{QuickBooks/Models/Address.html → Quickbooks/Transaction.html} +194 -158
- data/doc/classes/Quickbooks/Transaction.src/M000032.html +26 -0
- data/doc/created.rid +1 -1
- data/doc/files/LICENSE.html +128 -128
- data/doc/files/README.html +185 -173
- data/doc/files/lib/quickbooks/base_rb.html +317 -0
- data/doc/files/lib/quickbooks/connection_rb.html +108 -108
- data/doc/files/lib/quickbooks/models/{base_rb.html → customer_rb.html} +100 -100
- data/doc/files/lib/quickbooks/models/list_item_rb.html +101 -0
- data/doc/files/lib/quickbooks/models/transaction_rb.html +101 -0
- data/doc/files/lib/quickbooks/ole_helper_rb.html +109 -0
- data/doc/files/lib/quickbooks/qbxml/error_rb.html +101 -0
- data/doc/files/lib/quickbooks/{models/models_rb.html → qbxml/request_rb.html} +108 -107
- data/doc/files/lib/quickbooks/qbxml/response_rb.html +109 -0
- data/doc/files/lib/quickbooks/ruby_magic_rb.html +111 -0
- data/doc/files/lib/quickbooks_rb.html +112 -108
- data/doc/fr_class_index.html +44 -35
- data/doc/fr_file_index.html +38 -31
- data/doc/fr_method_index.html +93 -44
- data/doc/index.html +23 -23
- data/doc/rdoc-style.css +207 -207
- data/lib/quickbooks.rb +6 -1
- data/lib/quickbooks/base.rb +282 -0
- data/lib/quickbooks/connection.rb +91 -57
- data/lib/quickbooks/models/customer.rb +71 -0
- data/lib/quickbooks/models/list_item.rb +22 -0
- data/lib/quickbooks/models/transaction.rb +40 -0
- data/lib/quickbooks/ole_helper.rb +47 -0
- data/lib/quickbooks/qbxml/error.rb +20 -0
- data/lib/quickbooks/qbxml/request.rb +120 -0
- data/lib/quickbooks/qbxml/response.rb +176 -0
- data/lib/quickbooks/ruby_magic.rb +67 -0
- metadata +173 -84
- data/doc/classes/QuickBooks/Connection.src/M000015.html +0 -25
- data/doc/classes/QuickBooks/Connection.src/M000017.html +0 -20
- data/doc/classes/QuickBooks/Models/Base.src/M000010.html +0 -19
- data/doc/classes/QuickBooks/Models/Customer.html +0 -424
- data/doc/classes/QuickBooks/Models/Customer.src/M000001.html +0 -34
- data/doc/classes/QuickBooks/Models/Customer.src/M000003.html +0 -18
- data/doc/classes/QuickBooks/Models/ListItem.src/M000008.html +0 -17
- data/doc/classes/QuickBooks/Models/Transaction.src/M000004.html +0 -17
- data/doc/classes/QuickBooks/Models/Transaction.src/M000005.html +0 -17
- data/doc/classes/QuickBooks/Models/Transaction.src/M000006.html +0 -17
- data/doc/classes/QuickBooks/Models/Transaction.src/M000007.html +0 -17
- data/lib/quickbooks/models/base.rb +0 -72
- data/lib/quickbooks/models/models.rb +0 -43
- data/test/quickbooks/quickbooks_test.rb +0 -34
- data/test/test_helper.rb +0 -4
data/lib/quickbooks.rb
CHANGED
@@ -0,0 +1,282 @@
|
|
1
|
+
# Contains Quickbooks::Base. Two models inherit directly from Quickbooks::Base: ListItem and Transaction.
|
2
|
+
# All other models inherit from one of these.
|
3
|
+
#
|
4
|
+
# Inheriting from ListItem:
|
5
|
+
# - Account
|
6
|
+
# - Account List
|
7
|
+
# - BillingRate
|
8
|
+
# - Class
|
9
|
+
# - Currency
|
10
|
+
# - Customer
|
11
|
+
# - CustomerMessage
|
12
|
+
# - CustomerType
|
13
|
+
# - DateDrivenTerms
|
14
|
+
# - Employee
|
15
|
+
# - ItemDiscount
|
16
|
+
# - ItemFixedAsset
|
17
|
+
# - ItemGroup
|
18
|
+
# - ItemInventory
|
19
|
+
# - ItemInventoryAssembly
|
20
|
+
# - ItemNonInventory
|
21
|
+
# - ItemOtherCharge
|
22
|
+
# - ItemPayment
|
23
|
+
# - ItemSalesTax
|
24
|
+
# - ItemSalesTaxGroup
|
25
|
+
# - ItemService
|
26
|
+
# - ItemSubtotal
|
27
|
+
# - JobType
|
28
|
+
# - OtherName
|
29
|
+
# - PaymentMethod
|
30
|
+
# - PayrollItemNonWage
|
31
|
+
# - PayrollItemWage
|
32
|
+
# - PriceLevel
|
33
|
+
# - SalesRep
|
34
|
+
# - SalesTaxCode
|
35
|
+
# - ShipMethod
|
36
|
+
# - StandardTerms
|
37
|
+
# - TaxCode
|
38
|
+
# - Template
|
39
|
+
# - ToDo
|
40
|
+
# - Vehicle
|
41
|
+
# - Vendor
|
42
|
+
# - VendorType
|
43
|
+
# Inheriting from Transaction:
|
44
|
+
# - Bill
|
45
|
+
# - BillPaymentCheck
|
46
|
+
# - BillPaymentCreditCard
|
47
|
+
# - BuildAssembly
|
48
|
+
# - Charge
|
49
|
+
# - Check
|
50
|
+
# - CreditCardCharge
|
51
|
+
# - CreditCardCredit
|
52
|
+
# - CreditCardRefund
|
53
|
+
# - CreditMemo
|
54
|
+
# - Deposit
|
55
|
+
# - Estimate
|
56
|
+
# - InventoryAdjustment
|
57
|
+
# - Invoice
|
58
|
+
# - ItemReceipt
|
59
|
+
# - JournalEntry
|
60
|
+
# - PurchaseOrder
|
61
|
+
# - ReceivePayment
|
62
|
+
# - SalesOrder
|
63
|
+
# - SalesReceipt
|
64
|
+
# - SalesTaxPaymentCheck
|
65
|
+
# - TimeTracking
|
66
|
+
# - VehicleMileage
|
67
|
+
# - VendorCredit
|
68
|
+
|
69
|
+
require 'activesupport'
|
70
|
+
require 'quickbooks/connection'
|
71
|
+
require 'quickbooks/qbxml/request'
|
72
|
+
require 'quickbooks/qbxml/response'
|
73
|
+
|
74
|
+
module Quickbooks
|
75
|
+
class Base
|
76
|
+
# Stores a log of Quickbooks::Qbxml::Response objects that were a result of methods performed on this object.
|
77
|
+
attr_accessor :response_log
|
78
|
+
def response_log #:nodoc:
|
79
|
+
@response_log || (@response_log = [])
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns success (true/false) status of the last quickbooks communication called from this object.
|
83
|
+
def success?
|
84
|
+
@response_log.last.success?
|
85
|
+
end
|
86
|
+
def inspect #:nodoc:
|
87
|
+
"#<#{self.class.name}:#{self.object_id} #{instance_variables.reject {|i| i.is_one_of?('@response_log', '@original_values')}.map {|i| "#{i}=#{instance_variable_get(i).inspect}"}.join(' ')}>"
|
88
|
+
end
|
89
|
+
class << self
|
90
|
+
|
91
|
+
# Establishes a connection to the Quickbooks RDS Server for all Model Classes
|
92
|
+
def establish_connection(application_name='RubyApplication', file='', user='', password='', connection_type='localQBD', connection_mode='DoNotCare')
|
93
|
+
@@connection = Connection.new(application_name, file, user, password, connection_type, connection_mode)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns the current Connection
|
97
|
+
def connection
|
98
|
+
@connection || (@@connection ||= self.establish_connection())
|
99
|
+
end
|
100
|
+
|
101
|
+
# Sets the current Connection.
|
102
|
+
#
|
103
|
+
# This is normally not needed, but in the case that you may want to connect a separate connection to Quickbooks,
|
104
|
+
# you can use this method to explicitly set the connection in a class that inherits from Quickbooks::Base.
|
105
|
+
# Quickbooks::Models::Base.connection = Quickbooks::Connection.new('My Test App', 'C:\\Some File.QBW', 'user', 'pass')
|
106
|
+
def connection=(conn)
|
107
|
+
raise ArgumentError, "Cannot set connection to anything but a Quickbooks::Connection object" unless conn.is_a?(Quickbooks::Connection)
|
108
|
+
@connection = conn
|
109
|
+
end
|
110
|
+
|
111
|
+
# Register a property in the current class. For example in the Customer class:
|
112
|
+
# property :first_name
|
113
|
+
def property(*args)
|
114
|
+
raise ArgumentError, "must include a property name" unless args.length > 0
|
115
|
+
properties(*args)
|
116
|
+
end
|
117
|
+
# Register multiple properties at once. For example:
|
118
|
+
# properties :first_name, :last_name, :phone, :alt_phone
|
119
|
+
def properties(*args)
|
120
|
+
if args.blank?
|
121
|
+
@properties || (@properties = [])
|
122
|
+
else
|
123
|
+
args.each do |property|
|
124
|
+
properties << property
|
125
|
+
attr_accessor property
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Generates a request by sending *args to Quickbooks::Qbxml::Request.new, sends the request over the current connection,
|
131
|
+
# and interprets the response using Quickbooks::Qbxml::ResponseSet.
|
132
|
+
# The response is then instantiated into an object or an array of objects.
|
133
|
+
#
|
134
|
+
# This method is used mostly internally, but it is the yoke of this library - use it to perform custom requests.
|
135
|
+
def request_and_instantiate(obj_or_args,*args)
|
136
|
+
if obj_or_args.is_a?(Quickbooks::Base)
|
137
|
+
reinstantiate = obj_or_args
|
138
|
+
else
|
139
|
+
reinstantiate = nil
|
140
|
+
args.unshift(obj_or_args)
|
141
|
+
end
|
142
|
+
|
143
|
+
objects = [] # This will hold and return the instantiated objects from the quickbooks response
|
144
|
+
self.request(*args).each { |response| objects << response.instantiate(reinstantiate) } # Does not instantiate if it's an error, but simply records response into response_log
|
145
|
+
objects.length == 1 ? objects[0] : objects
|
146
|
+
end
|
147
|
+
|
148
|
+
# Generates a request using Quickbooks::Qbxml::Request, sends it, and returns a Quickbooks::Qbxml::ResponseSet object containing the response(s).
|
149
|
+
def request(*args)
|
150
|
+
Qbxml::ResponseSet.new(
|
151
|
+
self.connection.send_xml(
|
152
|
+
Qbxml::Request.new(*args).to_xml
|
153
|
+
)
|
154
|
+
)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Instantiate a new object with just attributes, or an existing object replacing the attributes
|
158
|
+
def instantiate(obj_or_attrs={},attrs={})
|
159
|
+
if obj_or_attrs.is_a?(Quickbooks::Base)
|
160
|
+
obj = obj_or_attrs
|
161
|
+
else
|
162
|
+
obj = allocate
|
163
|
+
attrs = obj_or_attrs
|
164
|
+
end
|
165
|
+
attrs.each do |key,value|
|
166
|
+
if obj.respond_to?(key.to_s.underscore+'=')
|
167
|
+
obj.send(key.to_s.underscore+'=', value)
|
168
|
+
obj.original_values[key.to_s.underscore] = value
|
169
|
+
end
|
170
|
+
end if attrs
|
171
|
+
obj # Will be either a nice object, or a Quickbooks::Qbxml::Error object.
|
172
|
+
end
|
173
|
+
|
174
|
+
# Queries Quickbooks for all of the objects of the current class's type. For example, Quickbooks::Customer.all will return an array of Quickbooks::Customer objects representing all customers.
|
175
|
+
def all(filters={})
|
176
|
+
[request_and_instantiate(self.class_leaf_name, :query, filters)].flatten
|
177
|
+
end
|
178
|
+
|
179
|
+
# Queries Quickbooks for the first object of the current class's type. For example, Quickbooks::Customer.first will return a Quickbooks::Customer object representing the first customer.
|
180
|
+
def first(filters={})
|
181
|
+
filters.merge!(:MaxReturned => 1) unless filters.keys.include?(:ListID) || filters.keys.include?(:TxnID) || filters.keys.include?(:FullName)
|
182
|
+
request_and_instantiate(self.class_leaf_name, :query, filters)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Creates a new object of the current class's type. For example, Quickbooks::Customer.create(:name => 'Tommy') will create a customer object with a Name of Tommy.
|
186
|
+
def create(*args)
|
187
|
+
new(*args).save
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# The default for all subclasses is simply to apply the attributes given, and mark the object as a new_record?
|
192
|
+
def initialize(args={})
|
193
|
+
self.attributes = args
|
194
|
+
@new_record = true
|
195
|
+
end
|
196
|
+
|
197
|
+
# Returns a hash that represents all this object's attributes.
|
198
|
+
def attributes
|
199
|
+
attrs = {}
|
200
|
+
self.class.properties.each do |column|
|
201
|
+
attrs[column.to_s] = instance_variable_get('@' + column.to_s)
|
202
|
+
end
|
203
|
+
attrs
|
204
|
+
end
|
205
|
+
# Updates all attributes included in _attrs_ to the values given. The object will now be dirty?.
|
206
|
+
def attributes=(attrs)
|
207
|
+
raise ArgumentError, "attributes can only be set to a hash of attributes" unless attrs.is_a?(Hash)
|
208
|
+
attrs.each do |key,value|
|
209
|
+
if self.respond_to?(key.to_s.underscore+'=')
|
210
|
+
self.send(key.to_s.underscore+'=', value)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Keeps track of the original values the object had when it was instantiated from a quickbooks response. dirty? and dirty_attributes compare the current values with these ones.
|
216
|
+
def original_values
|
217
|
+
@original_values || (@original_values = {})
|
218
|
+
end
|
219
|
+
|
220
|
+
# Returns true if any attributes have changed since the object was last loaded or updated from Quickbooks.
|
221
|
+
def dirty?
|
222
|
+
# Concept: For each column that the current model includes, has the value been changed?
|
223
|
+
self.class.properties.any? do |column|
|
224
|
+
self.instance_variable_get('@' + column.to_s) != original_values[column.to_s]
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Returns a hash of the attributes and their (new) values that have been changed since the object was last loaded or updated from Quickbooks.
|
229
|
+
def dirty_attributes
|
230
|
+
pairs = {}
|
231
|
+
self.class.properties.each do |column|
|
232
|
+
value = instance_variable_get('@' + column.to_s)
|
233
|
+
if value != original_values[column.to_s]
|
234
|
+
pairs[column.to_s] = value
|
235
|
+
end
|
236
|
+
end
|
237
|
+
pairs
|
238
|
+
end
|
239
|
+
|
240
|
+
# Returns true if the object is a new object (that doesn't represent an existing object in Quickbooks).
|
241
|
+
def new_record?
|
242
|
+
@new_record
|
243
|
+
end
|
244
|
+
|
245
|
+
# Saves the attributes that have changed.
|
246
|
+
#
|
247
|
+
# If the EditSequence is out of date but none of the changes conflict, the object will be saved to Quickbooks.
|
248
|
+
# But if there are conflicts, the updated values from Quickbooks will be written to the original_values, and false is returned.
|
249
|
+
# This way you can deal with the differences (conflicts), if you so desire, and simply call save again to commit your changes.
|
250
|
+
def save
|
251
|
+
return false unless dirty?
|
252
|
+
if new_record?
|
253
|
+
self.class.request_and_instantiate(self, self.class.class_leaf_name, :add, dirty_attributes.camelize_keys!)
|
254
|
+
@new_record = false if !dirty?
|
255
|
+
else
|
256
|
+
# Smart system that respects EditSequences and other people's changes.
|
257
|
+
# 1) Try to save
|
258
|
+
# 2) When we get a status of 3200, that means our EditSequence is not up to date
|
259
|
+
# 3) Replace self's original_attributes with those just retrieved, and update the automatic attributes, like EditSequence and TimeModified
|
260
|
+
# 4) Return false, return the object dirty but ready to save
|
261
|
+
old_originals = original_values.dup
|
262
|
+
self.class.request_and_instantiate(self, self.class.class_leaf_name, :mod, dirty_attributes.camelize_keys!.merge(:ListID => self.list_id, :EditSequence => self.edit_sequence))
|
263
|
+
# If save failed because of old record, but none of the fields conflict, re-save.
|
264
|
+
if dirty? && self.response_log.last.status == 3200
|
265
|
+
# puts "Now Dirty: #{dirty_attributes.keys.join(', ')}\nUpdated: #{old_originals.diff(original_values).keys.join(', ')}"
|
266
|
+
return self.save if dirty_attributes.keys.length == (dirty_attributes.keys - old_originals.diff(original_values).keys).length
|
267
|
+
end
|
268
|
+
end
|
269
|
+
!dirty?
|
270
|
+
end
|
271
|
+
|
272
|
+
# Reloads the record from Quickbooks, discarding any changes that have been made to it.
|
273
|
+
def reload
|
274
|
+
self.class.request_and_instantiate(self, self.class.class_leaf_name, :query, :ListID => self.list_id)
|
275
|
+
end
|
276
|
+
|
277
|
+
# Destroys a record in Quickbooks. Note that even though Quickbooks will destroy the record, the record's ListID and DeletedTime can be accessed by doing a query for deleted objects of the appropriate type.
|
278
|
+
def destroy
|
279
|
+
self.class.request_and_instantiate(self, self.class.class_leaf_name, :delete, self.is_a?(Quickbooks::ListItem) ? {:ListID => self.list_id} : {:TxnID => self.txn_id}).success?
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
@@ -1,72 +1,106 @@
|
|
1
|
+
require 'win32ole'
|
2
|
+
require 'quickbooks/ole_helper'
|
1
3
|
|
2
|
-
module
|
3
|
-
# Connection is
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# xml = <<END
|
11
|
-
# <?xml version="1.0"?>
|
12
|
-
# <?qbxml version="3.0"?>
|
13
|
-
# <QBXML>
|
14
|
-
# <QBXMLMsgsRq onError="continueOnError">
|
15
|
-
# <InvoiceQueryRq requestID="1">
|
16
|
-
# <RefNumber>81</RefNumber>
|
17
|
-
# <IncludeLineItems>true</IncludeLineItems>
|
18
|
-
# </InvoiceQueryRq>
|
19
|
-
# </QBXMLMsgsRq>
|
20
|
-
# </QBXML>
|
21
|
-
# <<END
|
22
|
-
# connection.send(xml)
|
23
|
-
# connection.close
|
4
|
+
module Quickbooks
|
5
|
+
# Connection is used internally by Quickbooks::Base to automatically manage a the communication with quickbooks.
|
6
|
+
# Currently the only connection mode supported is WIN32OlE, which means your application must be running on the
|
7
|
+
# same computer as Quickbooks.
|
8
|
+
#
|
9
|
+
# Quickbooks does not allow the user to close the company or exit the program until all outside applications are
|
10
|
+
# disconnected from its API. Therefore, this class includes an at_exit hook that automatically closes all open
|
11
|
+
# connections for you when your program exits.
|
24
12
|
class Connection
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
13
|
+
include QBHelpers
|
14
|
+
|
15
|
+
class << self #:nodoc: all
|
16
|
+
def connections
|
17
|
+
@connections || (@connections = [])
|
18
|
+
end
|
19
|
+
def connections=(v)
|
20
|
+
# raise ArgumentError, "Quickbooks::Connection.connections can only contain Quickbooks::Connection objects, but contains #{v.collect {|c| c.class.name}.uniq.join(', ')} objects" unless v.collect {|c| c.class.name}.uniq == ['Quickbooks::Connection']
|
21
|
+
@connections = v
|
22
|
+
end
|
23
|
+
|
24
|
+
at_exit do
|
25
|
+
Quickbooks::Connection.connections.each do |conn|
|
26
|
+
conn.close
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Initializes an instance of Quickbooks::Session.
|
32
|
+
# - _application_name_ is required.
|
33
|
+
# - _file_ is optional, in which case the connection will be made to the currently open company file in the Quickbooks application.
|
34
|
+
# - _user_ and _password_ may be required if you have specified a specific file to open.
|
35
|
+
# - _connection_type_ can be one of: ['unknown', 'localQBD', 'remoteQBD', 'localQBDLaunchUI', 'remoteQBOE']
|
36
|
+
# - _connection_mode_ can be one of: ['SingleUser', 'MultiUser', 'DoNotCare']
|
37
|
+
def initialize(application_name='RubyApplication', file='', user='', password='', connection_type='localQBD', connection_mode='DoNotCare')
|
38
|
+
@file = file
|
32
39
|
@user = user
|
33
40
|
@password = password
|
34
41
|
@application_name = application_name
|
35
|
-
@
|
36
|
-
@
|
37
|
-
@
|
38
|
-
|
39
|
-
@soap_client = nil
|
42
|
+
@quickbooks = Ole.new('QBXMLRP2.RequestProcessor', 'QBXMLRP2 1.0 Type Library')
|
43
|
+
@connection_type = @quickbooks.get_variable(connection_type)
|
44
|
+
@connection_mode = @quickbooks.get_variable('qbFileOpen'+connection_mode)
|
45
|
+
connection # Just to make it fail now instead of later if it can't connect properly.
|
40
46
|
end
|
41
|
-
|
42
|
-
#
|
47
|
+
|
48
|
+
# Returns true if there is an open connection to Quickbooks, false if not. Use session? to determine an open session.
|
43
49
|
def connected?
|
44
|
-
|
45
|
-
|
50
|
+
@connected ||= false
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns true if there is an active session. Use connected? to determine whether you are connected or not.
|
54
|
+
def session?
|
55
|
+
!@session.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
# Sends a request to Quickbooks. This request should be a valid QBXML request. Use Quickbooks::Qbxml::Request to generate valid requests.
|
59
|
+
def send_xml(xml)
|
60
|
+
connection.ProcessRequest(session, xml)
|
61
|
+
rescue => e
|
62
|
+
warn "ERROR processing request:\n#{xml}"
|
63
|
+
raise # Reraises the original error, only this way we got the xml output
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns the active connection to Quickbooks, or creates a new one if none exists.
|
67
|
+
def connection
|
68
|
+
@connection || begin
|
69
|
+
@connection = @quickbooks.ole
|
70
|
+
@connection.OpenConnection2('',@application_name,@connection_type)
|
71
|
+
Quickbooks::Connection.connections << self
|
72
|
+
@connected = true
|
73
|
+
@connection
|
46
74
|
end
|
47
|
-
return false
|
48
75
|
end
|
49
|
-
|
50
|
-
#
|
51
|
-
def
|
52
|
-
@
|
53
|
-
|
54
|
-
|
76
|
+
|
77
|
+
# Begin a session to Quickbooks.
|
78
|
+
def session
|
79
|
+
@session || begin
|
80
|
+
@session = connection.BeginSession(@file,@connection_mode)
|
81
|
+
end
|
55
82
|
end
|
56
|
-
|
57
|
-
#
|
58
|
-
def
|
59
|
-
|
83
|
+
|
84
|
+
# End the current Quickbooks session. After ending a session, a new session may be reopened if desired.
|
85
|
+
def end_session
|
86
|
+
if !@session.nil?
|
87
|
+
connection.EndSession(@session)
|
88
|
+
@session = nil
|
89
|
+
true
|
90
|
+
else
|
91
|
+
false
|
92
|
+
end
|
60
93
|
end
|
61
|
-
|
62
|
-
# Close the
|
94
|
+
|
95
|
+
# Close the connection to Quickbooks. Automatically ends the session, if there is one.
|
63
96
|
def close
|
64
|
-
|
65
|
-
|
66
|
-
@
|
67
|
-
@
|
68
|
-
|
97
|
+
end_session
|
98
|
+
if connected? && connection.CloseConnection(@session)
|
99
|
+
@connected = false
|
100
|
+
@connection = nil
|
101
|
+
Quickbooks::Connection.connections = Quickbooks::Connection.connections - [self]
|
102
|
+
end
|
103
|
+
return !@connected # Returns false if CloseConnection failed.
|
69
104
|
end
|
70
|
-
|
71
105
|
end
|
72
106
|
end
|