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.
Files changed (135) hide show
  1. data/README +18 -28
  2. data/Rakefile +17 -30
  3. data/doc/classes/{QuickBooks/Models/DataExt.html → Class.html} +151 -140
  4. data/doc/classes/Class.src/M000003.html +18 -0
  5. data/doc/classes/Hash.html +164 -0
  6. data/doc/classes/Hash.src/M000001.html +20 -0
  7. data/doc/classes/Hash.src/M000002.html +23 -0
  8. data/doc/classes/{QuickBooks/Models/Transaction.html → Object.html} +207 -201
  9. data/doc/classes/Object.src/M000004.html +24 -0
  10. data/doc/classes/Object.src/M000005.html +18 -0
  11. data/doc/classes/Object.src/M000006.html +19 -0
  12. data/doc/classes/Object.src/M000007.html +18 -0
  13. data/doc/classes/{QuickBooks.html → QBHelpers.html} +118 -119
  14. data/doc/classes/QBHelpers/Ole.html +209 -0
  15. data/doc/classes/QBHelpers/Ole.src/M000066.html +21 -0
  16. data/doc/classes/QBHelpers/Ole.src/M000067.html +22 -0
  17. data/doc/classes/QBHelpers/Ole.src/M000068.html +18 -0
  18. data/doc/classes/Quickbooks.html +136 -0
  19. data/doc/classes/Quickbooks/Base.html +618 -0
  20. data/doc/classes/Quickbooks/Base.src/M000034.html +18 -0
  21. data/doc/classes/Quickbooks/Base.src/M000035.html +18 -0
  22. data/doc/classes/Quickbooks/Base.src/M000036.html +18 -0
  23. data/doc/classes/Quickbooks/Base.src/M000037.html +19 -0
  24. data/doc/classes/Quickbooks/Base.src/M000038.html +19 -0
  25. data/doc/classes/Quickbooks/Base.src/M000039.html +25 -0
  26. data/doc/classes/Quickbooks/Base.src/M000040.html +27 -0
  27. data/doc/classes/Quickbooks/Base.src/M000041.html +22 -0
  28. data/doc/classes/Quickbooks/Base.src/M000042.html +30 -0
  29. data/doc/classes/Quickbooks/Base.src/M000043.html +18 -0
  30. data/doc/classes/Quickbooks/Base.src/M000044.html +19 -0
  31. data/doc/classes/Quickbooks/Base.src/M000045.html +18 -0
  32. data/doc/classes/Quickbooks/Base.src/M000046.html +19 -0
  33. data/doc/classes/Quickbooks/Base.src/M000047.html +22 -0
  34. data/doc/classes/Quickbooks/Base.src/M000048.html +23 -0
  35. data/doc/classes/Quickbooks/Base.src/M000049.html +18 -0
  36. data/doc/classes/Quickbooks/Base.src/M000050.html +21 -0
  37. data/doc/classes/Quickbooks/Base.src/M000051.html +25 -0
  38. data/doc/classes/Quickbooks/Base.src/M000052.html +18 -0
  39. data/doc/classes/Quickbooks/Base.src/M000053.html +36 -0
  40. data/doc/classes/Quickbooks/Base.src/M000054.html +18 -0
  41. data/doc/classes/Quickbooks/Base.src/M000055.html +18 -0
  42. data/doc/classes/Quickbooks/Connection.html +369 -0
  43. data/doc/classes/{QuickBooks/Models/Customer.src/M000002.html → Quickbooks/Connection.src/M000056.html} +17 -17
  44. data/doc/classes/Quickbooks/Connection.src/M000057.html +19 -0
  45. data/doc/classes/Quickbooks/Connection.src/M000058.html +25 -0
  46. data/doc/classes/{QuickBooks/Connection.src/M000018.html → Quickbooks/Connection.src/M000059.html} +17 -17
  47. data/doc/classes/Quickbooks/Connection.src/M000060.html +18 -0
  48. data/doc/classes/Quickbooks/Connection.src/M000061.html +21 -0
  49. data/doc/classes/Quickbooks/Connection.src/M000062.html +24 -0
  50. data/doc/classes/{QuickBooks/Connection.src/M000016.html → Quickbooks/Connection.src/M000063.html} +19 -20
  51. data/doc/classes/{QuickBooks/Connection.src/M000019.html → Quickbooks/Connection.src/M000064.html} +23 -21
  52. data/doc/classes/Quickbooks/Connection.src/M000065.html +24 -0
  53. data/doc/classes/{QuickBooks/Models.html → Quickbooks/Customer.html} +112 -120
  54. data/doc/classes/{QuickBooks/Models/CreditCardInfo.html → Quickbooks/ListItem.html} +176 -148
  55. data/doc/classes/Quickbooks/ListItem.src/M000033.html +31 -0
  56. data/doc/classes/Quickbooks/Qbxml.html +138 -0
  57. data/doc/classes/{QuickBooks/Models/ListItem.html → Quickbooks/Qbxml/Error.html} +167 -173
  58. data/doc/classes/{QuickBooks/Models/Base.src/M000011.html → Quickbooks/Qbxml/Error.src/M000031.html} +17 -17
  59. data/doc/classes/Quickbooks/Qbxml/Request.html +182 -0
  60. data/doc/classes/Quickbooks/Qbxml/Request.src/M000024.html +23 -0
  61. data/doc/classes/Quickbooks/Qbxml/Request.src/M000025.html +19 -0
  62. data/doc/classes/Quickbooks/Qbxml/Request.src/M000026.html +57 -0
  63. data/doc/classes/Quickbooks/Qbxml/RequestSet.html +193 -0
  64. data/doc/classes/Quickbooks/Qbxml/RequestSet.src/M000027.html +22 -0
  65. data/doc/classes/Quickbooks/Qbxml/RequestSet.src/M000028.html +26 -0
  66. data/doc/classes/{QuickBooks/Models/Base.src/M000014.html → Quickbooks/Qbxml/RequestSet.src/M000029.html} +17 -16
  67. data/doc/classes/Quickbooks/Qbxml/RequestSet.src/M000030.html +22 -0
  68. data/doc/classes/Quickbooks/Qbxml/RequestSetArrayExt.html +105 -0
  69. data/doc/classes/{QuickBooks/Connection.html → Quickbooks/Qbxml/Response.html} +301 -278
  70. data/doc/classes/Quickbooks/Qbxml/Response.src/M000015.html +24 -0
  71. data/doc/classes/Quickbooks/Qbxml/Response.src/M000016.html +19 -0
  72. data/doc/classes/Quickbooks/Qbxml/Response.src/M000017.html +45 -0
  73. data/doc/classes/Quickbooks/Qbxml/Response.src/M000018.html +18 -0
  74. data/doc/classes/Quickbooks/Qbxml/Response.src/M000019.html +18 -0
  75. data/doc/classes/Quickbooks/Qbxml/Response.src/M000020.html +18 -0
  76. data/doc/classes/{QuickBooks/Models/Base.src/M000013.html → Quickbooks/Qbxml/Response.src/M000021.html} +17 -16
  77. data/doc/classes/{QuickBooks/Models/ListItem.src/M000009.html → Quickbooks/Qbxml/Response.src/M000022.html} +17 -16
  78. data/doc/classes/Quickbooks/Qbxml/Response.src/M000023.html +52 -0
  79. data/doc/classes/{QuickBooks/Models/Base.html → Quickbooks/Qbxml/ResponseSet.html} +237 -213
  80. data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000008.html +22 -0
  81. data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000009.html +26 -0
  82. data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000010.html +24 -0
  83. data/doc/classes/{QuickBooks/Models/Base.src/M000012.html → Quickbooks/Qbxml/ResponseSet.src/M000011.html} +17 -17
  84. data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000012.html +27 -0
  85. data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000013.html +18 -0
  86. data/doc/classes/Quickbooks/Qbxml/ResponseSet.src/M000014.html +18 -0
  87. data/doc/classes/Quickbooks/Qbxml/ResponseSetArrayExt.html +105 -0
  88. data/doc/classes/{QuickBooks/Models/Address.html → Quickbooks/Transaction.html} +194 -158
  89. data/doc/classes/Quickbooks/Transaction.src/M000032.html +26 -0
  90. data/doc/created.rid +1 -1
  91. data/doc/files/LICENSE.html +128 -128
  92. data/doc/files/README.html +185 -173
  93. data/doc/files/lib/quickbooks/base_rb.html +317 -0
  94. data/doc/files/lib/quickbooks/connection_rb.html +108 -108
  95. data/doc/files/lib/quickbooks/models/{base_rb.html → customer_rb.html} +100 -100
  96. data/doc/files/lib/quickbooks/models/list_item_rb.html +101 -0
  97. data/doc/files/lib/quickbooks/models/transaction_rb.html +101 -0
  98. data/doc/files/lib/quickbooks/ole_helper_rb.html +109 -0
  99. data/doc/files/lib/quickbooks/qbxml/error_rb.html +101 -0
  100. data/doc/files/lib/quickbooks/{models/models_rb.html → qbxml/request_rb.html} +108 -107
  101. data/doc/files/lib/quickbooks/qbxml/response_rb.html +109 -0
  102. data/doc/files/lib/quickbooks/ruby_magic_rb.html +111 -0
  103. data/doc/files/lib/quickbooks_rb.html +112 -108
  104. data/doc/fr_class_index.html +44 -35
  105. data/doc/fr_file_index.html +38 -31
  106. data/doc/fr_method_index.html +93 -44
  107. data/doc/index.html +23 -23
  108. data/doc/rdoc-style.css +207 -207
  109. data/lib/quickbooks.rb +6 -1
  110. data/lib/quickbooks/base.rb +282 -0
  111. data/lib/quickbooks/connection.rb +91 -57
  112. data/lib/quickbooks/models/customer.rb +71 -0
  113. data/lib/quickbooks/models/list_item.rb +22 -0
  114. data/lib/quickbooks/models/transaction.rb +40 -0
  115. data/lib/quickbooks/ole_helper.rb +47 -0
  116. data/lib/quickbooks/qbxml/error.rb +20 -0
  117. data/lib/quickbooks/qbxml/request.rb +120 -0
  118. data/lib/quickbooks/qbxml/response.rb +176 -0
  119. data/lib/quickbooks/ruby_magic.rb +67 -0
  120. metadata +173 -84
  121. data/doc/classes/QuickBooks/Connection.src/M000015.html +0 -25
  122. data/doc/classes/QuickBooks/Connection.src/M000017.html +0 -20
  123. data/doc/classes/QuickBooks/Models/Base.src/M000010.html +0 -19
  124. data/doc/classes/QuickBooks/Models/Customer.html +0 -424
  125. data/doc/classes/QuickBooks/Models/Customer.src/M000001.html +0 -34
  126. data/doc/classes/QuickBooks/Models/Customer.src/M000003.html +0 -18
  127. data/doc/classes/QuickBooks/Models/ListItem.src/M000008.html +0 -17
  128. data/doc/classes/QuickBooks/Models/Transaction.src/M000004.html +0 -17
  129. data/doc/classes/QuickBooks/Models/Transaction.src/M000005.html +0 -17
  130. data/doc/classes/QuickBooks/Models/Transaction.src/M000006.html +0 -17
  131. data/doc/classes/QuickBooks/Models/Transaction.src/M000007.html +0 -17
  132. data/lib/quickbooks/models/base.rb +0 -72
  133. data/lib/quickbooks/models/models.rb +0 -43
  134. data/test/quickbooks/quickbooks_test.rb +0 -34
  135. data/test/test_helper.rb +0 -4
data/lib/quickbooks.rb CHANGED
@@ -1,2 +1,7 @@
1
+ require 'rubygems'
1
2
  require 'quickbooks/connection'
2
- require 'quickbooks/models/models'
3
+ require 'quickbooks/base'
4
+ require 'quickbooks/models/list_item'
5
+ require 'quickbooks/models/transaction'
6
+
7
+ require 'quickbooks/models/customer'
@@ -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 QuickBooks
3
- # Connection is used to communicate with QuickBooks RDS Server. You need to configure
4
- # your QuickBooks software to allow RDS connection from your application.
5
- # <code>
6
- # require 'quickbooks'
7
- #
8
- # connection = QuickBooks::Connection.new('admin', 'pass', 'My Test App')
9
- # connection.open
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
- require 'cgi'
26
- require 'soap/wsdlDriver'
27
-
28
- attr_accessor :user, :password, :application_name, :host, :port
29
-
30
- # Initializes an instance of QuickBooks::Session
31
- def initialize(user, password, application_name, host="localhost", port=3790, mode='multiUser')
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
- @host = host
36
- @port = port
37
- @mode = mode
38
- @ticket = nil
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
- # Determines if the Session is connected to a QuickBooks RDS Server
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
- if @ticket && @soap_client
45
- return true
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
- # Opens a connection to a QuickBooks RDS Server
51
- def open
52
- @soap_client = SOAP::WSDLDriverFactory.new("https://#{@host}:#{@port}/QBXMLRemote?wsdl").create_rpc_driver
53
- @ticket = @soap_client.OpenConnectionAndBeginSession(@user, @password, '', @application_name, '', @mode)
54
- return @ticket
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
- # Send a QBXML message to QuickBooks RDS Server
58
- def send(xml)
59
- @soap_client.ProcessRequest(@ticket, xml)
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 session to QuickBooks RDS Server
94
+
95
+ # Close the connection to Quickbooks. Automatically ends the session, if there is one.
63
96
  def close
64
- if connected? && @soap_client
65
- @soap_client.CloseConnection(@ticket)
66
- @soap_client = nil
67
- @ticket = nil
68
- end
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