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
@@ -0,0 +1,71 @@
1
+ module Quickbooks
2
+ class Customer < ListItem
3
+ properties :parent_ref,
4
+ :sublevel,
5
+
6
+ :name,
7
+ :salutation,
8
+ :first_name,
9
+ :middle_name,
10
+ :last_name,
11
+ :suffix,
12
+ :company_name,
13
+
14
+ :phone,
15
+ :mobile,
16
+ :alt_phone,
17
+ :pager,
18
+ :fax,
19
+ :email,
20
+ :contact,
21
+ :alt_contact,
22
+ :bill_address,
23
+ :ship_address,
24
+
25
+ :notes,
26
+
27
+ :account_number,
28
+ :credit_card_info,
29
+ :credit_limit,
30
+ :balance,
31
+ :open_balance,
32
+ :open_balance_date,
33
+ :total_balance,
34
+ :preferred_payment_method_ref,
35
+
36
+ :job_status,
37
+ :job_start_date,
38
+ :job_projected_end_date,
39
+ :job_end_date,
40
+ :job_desc,
41
+ :job_type_ref,
42
+
43
+ :print_as,
44
+ :customer_type_ref,
45
+ :delivery_method,
46
+ :price_level_ref,
47
+ :terms_ref,
48
+ :sales_rep_ref,
49
+ :sales_tax_code_ref,
50
+ :item_sales_tax_ref,
51
+ :resale_nmber,
52
+ :is_statement_with_parent,
53
+ :data_ext_ref
54
+
55
+ # def initialize
56
+ # @parent_ref = ListItem.new
57
+ # @bill_address = Address.new
58
+ # @terms_ref = ListItem.new
59
+ # @sales_rep_ref = ListItem.new
60
+ # @sales_tax_code_ref = ListItem.new
61
+ # @item_sales_tax_ref = ListItem.new
62
+ # @preferred_payment_method_ref = ListItem.new
63
+ # @job_type_ref = ListItem.new
64
+ # @price_live_ref = ListItem.new
65
+ # @data_ext_ref = ListItem.new
66
+ # @ship_address = Address.new
67
+ # @customer_type_ref = ListItem.new
68
+ # @credit_card_info = CreditCardInfo.new
69
+ # end
70
+ end
71
+ end
@@ -0,0 +1,22 @@
1
+ class Quickbooks::ListItem < Quickbooks::Base
2
+ attr_accessor :list_id, :full_name, :edit_sequence, :time_created, :time_modified, :is_active
3
+
4
+ class << self
5
+ def child_types
6
+ [ "Account", "Account List", "BillingRate",
7
+ "Class", "Currency", "Customer",
8
+ "CustomerMessage", "CustomerType",
9
+ "DateDrivenTerms", "Employee", "ItemDiscount",
10
+ "ItemFixedAsset", "ItemGroup", "ItemInventory",
11
+ "ItemInventoryAssembly", "ItemNonInventory",
12
+ "ItemOtherCharge", "ItemPayment", "ItemSalesTax",
13
+ "ItemSalesTaxGroup", "ItemService", "ItemSubtotal",
14
+ "JobType", "OtherName", "PaymentMethod",
15
+ "PayrollItemNonWage", "PayrollItemWage", "PriceLevel",
16
+ "SalesRep", "SalesTaxCode", "ShipMethod",
17
+ "StandardTerms", "TaxCode", "Template", "ToDo",
18
+ "Vehicle", "Vendor", "VendorType"
19
+ ]
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,40 @@
1
+ class Quickbooks::Transaction < Quickbooks::Base
2
+ # attr_accessor :id, :ref_number
3
+ attr_accessor :list_id, :full_name, :edit_sequence, :time_created, :time_modified, :is_active
4
+
5
+ # Currently, the following transaction types can be modified:
6
+ # • Bill
7
+ # • BillPaymentCheck
8
+ # • BuildAssembly
9
+ # • Charge
10
+ # • Check
11
+ # • CreditCardCharge
12
+ # • CreditCardCredit
13
+ # • CreditMemo
14
+ # • Deposit
15
+ # • Estimate
16
+ # • Invoice
17
+ # • JournalEntry
18
+ # • ItemReceipt
19
+ # • PriceLevel
20
+ # • PurchaseOrder
21
+ # • ReceivePayment
22
+ # • SalesOrder
23
+ # • SalesReceipt
24
+ # • StatementCharge
25
+ # • TimeTracking
26
+
27
+ class << self
28
+ def child_types
29
+ [ "Bill", "BillPaymentCheck", "BillPaymentCreditCard",
30
+ "BuildAssembly", "Charge", "Check", "CreditCardCharge",
31
+ "CreditCardCredit", "CreditCardRefund", "CreditMemo",
32
+ "Deposit", "Estimate", "InventoryAdjustment",
33
+ "Invoice", "ItemReceipt", "JournalEntry",
34
+ "PurchaseOrder", "ReceivePayment", "SalesOrder",
35
+ "SalesReceipt", "SalesTaxPaymentCheck", "TimeTracking",
36
+ "VehicleMileage", "VendorCredit"
37
+ ]
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ # QBHelpers::Ole is a simple helper class that wraps an OLE object and provides methods that make it easier to deal with certain things that OLE makes complicated.
2
+
3
+ module QBHelpers
4
+ class Ole
5
+ # Simply holds the actual OLE object.
6
+ attr_reader :ole
7
+
8
+ # Pass in the OLE name of the application you want connected to, and the name of a type library, if you need one.
9
+ def initialize(ole_app, type_library=nil)
10
+ @ole_app = ole_app
11
+ @type_library = type_library
12
+ @ole = WIN32OLE.new(ole_app)
13
+ self.classes
14
+ end
15
+
16
+ # Finds an OLE variable in the OLE type library, if you specified one in new().
17
+ # This navigates the OLE classes and constants for you and returns the variable that matches the _var_name_ you specify.
18
+ # This is used with Quickbooks to get the qbFileOpenDoNotCare parameter to pass to the OpenConnection2 method:
19
+ # @quickbooks = Ole.new('QBXMLRP2.RequestProcessor', 'QBXMLRP2 1.0 Type Library')
20
+ # @quickbooks.OpenConnection2('','Sample Application',@quickbooks.get_variable('localQBD'))
21
+ # @session = @quickbooks.BeginSession('',@quickbooks.get_variable('qbFileOpenDoNotCare'))
22
+ # ...
23
+ def get_variable(var_name)
24
+ return nil unless @type_library
25
+ self.classes.each do |class_name|
26
+ found = self.constant_for(class_name.name).variables.find {|var| var.name == var_name}
27
+ return found if found
28
+ end
29
+ end
30
+
31
+ def classes #:nodoc:
32
+ return nil unless @type_library
33
+ @classes ||= WIN32OLE_TYPE.ole_classes(@type_library)
34
+ end
35
+
36
+ def constant_for(class_name) #:nodoc:
37
+ return nil unless @type_library
38
+ @constant_for ||= {}
39
+ @constant_for[class_name] ||= WIN32OLE_TYPE.new(@type_library, class_name)
40
+ end
41
+
42
+ # method_missing sends all other methods to the OLE object, so you can treat this object as your OLE object.
43
+ def method_missing(method_name, *args)
44
+ @ole.send(method_name, *args)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,20 @@
1
+ module Quickbooks
2
+ module Qbxml
3
+ # This class exists simply to wrap errors in an object similar in structure to a Quickbooks::Base-inherited object, so the error can be extracted, etc.
4
+ class Error
5
+ # Stores a log of Quickbooks::Qbxml::Response objects that were a result of methods performed on this object.
6
+ attr_accessor :response_log
7
+ def response_log #:nodoc:
8
+ @response_log || (@response_log = [])
9
+ end
10
+
11
+ # Returns success (true/false) status of the last quickbooks communication called from this object.
12
+ def success?
13
+ @response_log.last.success?
14
+ end
15
+ def inspect #:nodoc:
16
+ "#<#{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(' ')}>"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,120 @@
1
+ require 'quickbooks/ruby_magic'
2
+ require 'builder'
3
+
4
+ module Quickbooks
5
+ module Qbxml
6
+ VERSION = '6.0'
7
+ class RequestSet
8
+ include Enumerable
9
+ def set
10
+ unless @set.is_a?(Array)
11
+ @set = []
12
+ @set.extend(Quickbooks::Qbxml::RequestSetArrayExt)
13
+ end
14
+ @set
15
+ end
16
+ delegate_methods [:each, :length, :first, :last, :[], :map, :join] => :set
17
+ def <<(qbxml_request)
18
+ if qbxml_request.is_a?(Quickbooks::Qbxml::Request)
19
+ set << qbxml_request
20
+ elsif qbxml_request.respond_to?(:each)
21
+ qbxml_request.each do |request|
22
+ self << request
23
+ end
24
+ else
25
+ raise ArgumentError, "Cannot add object of type #{qbxml_request.class.name} to a Quickbooks::Qbxml::RequestSet"
26
+ end
27
+ end
28
+
29
+ def initialize(*requests)
30
+ self << requests
31
+ end
32
+
33
+ def to_xml
34
+ pre = <<-thequickbooks_qbxmlrequestsetxml
35
+ <?xml version="1.0" ?>
36
+ <?qbxml version="#{Quickbooks::Qbxml::VERSION}" ?>
37
+ <QBXML>
38
+ <QBXMLMsgsRq onError="stopOnError">
39
+ thequickbooks_qbxmlrequestsetxml
40
+ requests = map {|x| x.to_xml(false)}.join
41
+ post = <<-thequickbooks_qbxmlrequestsetxml
42
+ </QBXMLMsgsRq>
43
+ </QBXML>
44
+ thequickbooks_qbxmlrequestsetxml
45
+ # puts pre + requests + post
46
+ pre + requests + post
47
+ end
48
+ end
49
+
50
+ class Request
51
+ # @type = there are four types of queries...
52
+ # 1) List queries (:query)
53
+ # 2) Object-specific transaction query (:transaction)
54
+ # 3) Generic transaction query (:any_transaction)
55
+ # 4) Reports (:report)
56
+ # ...and then there are Mod requests...
57
+ # # 1) Mod request (:mod)
58
+ def initialize(object, type, options={})
59
+ @type = type
60
+ raise ArgumentError, "Quickbooks::Qbxml::Requests can only be of one of the following types: :query, :transaction, :any_transaction, :mod, :add, :delete, or :report" unless @type.is_one_of?(:query, :transaction, :any_transaction, :mod, :report, :add, :delete)
61
+ @object = object
62
+ @filters = options if @type.is_one_of?(:query, :transaction, :any_transaction, :report)
63
+ @attributes = options.stringify_keys! if @type.is_one_of?(:mod, :add, :delete)
64
+ # puts self.inspect
65
+ end
66
+
67
+ def self.next_request_id
68
+ @request_id ||= 5000
69
+ @request_id += 1
70
+ end
71
+
72
+ # This is where the magic happens to convert a request object into xml worthy of sending off to quickbooks.
73
+ def to_xml(as_set=true)
74
+ return (RequestSet.new(self)).to_xml if as_set # Simple call yields xml as a single request in a request set. However, if the xml for the lone request is required, pass false.
75
+ req = Builder::XmlMarkup.new(:indent => 2)
76
+ case
77
+ when @type.is_one_of?(:query)
78
+ request_root = "#{@object}QueryRq"
79
+ container = nil
80
+ when @type == :mod
81
+ request_root = "#{@object}ModRq"
82
+ container = "#{@object}Mod"
83
+ when @type == :add
84
+ request_root = "#{@object}AddRq"
85
+ container = "#{@object}Add"
86
+ when @type == :delete
87
+ # request_root = "#{@object}DelRq"
88
+ request_root = Quickbooks::ListItem.child_types.include?(@object) ? 'ListDelRq' : 'TxnDelRq'
89
+ container = nil
90
+ # container = Quickbooks::ListItem.child_types.include?(@object) ? 'ListDelType' : 'TxnDelType'
91
+ @attributes.merge!((Quickbooks::ListItem.child_types.include?(@object) ? 'ListDelType' : 'TxnDelType') => @object)
92
+ else
93
+ raise RuntimeError, "Could not convert this request to qbxml!\n#{self.inspect}"
94
+ end
95
+ inner_stuff = lambda {
96
+ ['ListDelType', 'TxnDelType', 'ListID', 'TxnID', 'EditSequence'].each do |key|
97
+ req.tag!(key, @attributes.delete(key)) if @attributes.has_key?(key)
98
+ end if @attributes
99
+ (@filters || @attributes).each do |key,value|
100
+ req.tag!(key, value)
101
+ end
102
+ }
103
+ req.tag!(request_root, :requestID => self.class.next_request_id) {
104
+ if container
105
+ req.tag!(container) {
106
+ inner_stuff.call
107
+ }
108
+ else
109
+ inner_stuff.call
110
+ end
111
+ }
112
+ # puts req.target!
113
+ req.target!
114
+ end
115
+ end
116
+
117
+ module RequestSetArrayExt
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,176 @@
1
+ require 'quickbooks/ruby_magic'
2
+ require 'quickbooks/qbxml/error'
3
+
4
+ module Quickbooks
5
+ module Qbxml
6
+ class ResponseSet
7
+ include Enumerable
8
+ def set
9
+ unless @set.is_a?(Array)
10
+ @set = []
11
+ @set.extend(Quickbooks::Qbxml::ResponseSetArrayExt)
12
+ end
13
+ @set
14
+ end
15
+ delegate_methods [:each, :length, :first, :last, :[], :map, :join] => :set
16
+ def <<(qbxml_response)
17
+ if qbxml_response.is_a?(Quickbooks::Qbxml::Response)
18
+ set << qbxml_response
19
+ elsif qbxml_response.respond_to?(:each)
20
+ qbxml_response.each do |response|
21
+ self << response
22
+ end
23
+ else
24
+ raise ArgumentError, "Cannot add object of type #{qbxml_response.class.name} to a Quickbooks::Qbxml::ResponseSet"
25
+ end
26
+ end
27
+
28
+ def initialize(xml_or_hash)
29
+ if(xml_or_hash.is_a?(Hash))
30
+ self.append_from_hash(xml_or_hash)
31
+ elsif(xml_or_hash.is_a?(String))
32
+ self.append_from_xml(xml_or_hash)
33
+ else
34
+ raise ArgumentError, "Quickbooks::Qbxml::ResponseSet must be initialized with either a Hash or an xml-formatted String."
35
+ end
36
+ end
37
+
38
+ def append_from_xml(xml)
39
+ self.append_from_hash(Hash.from_xml(xml))
40
+ end
41
+ def append_from_hash(hsh)
42
+ to_append = []
43
+ hsh = hsh['QBXML'] if hsh.has_key?('QBXML')
44
+ hsh = hsh['QBXMLMsgsRs'] if hsh.has_key?('QBXMLMsgsRs')
45
+ # responses will contain one or more keys.
46
+ hsh.each_key do |name|
47
+ # response_type is either a single response object, or an array of response objects. Force it into an array:
48
+ responses = hsh[name].is_a?(Array) ? hsh[name] : [hsh[name]]
49
+ responses.each { |response| to_append << Response.new(name => response) }
50
+ end
51
+ self << to_append
52
+ end
53
+
54
+ class << self
55
+ def from_xml(xml)
56
+ new.append_from_xml(xml)
57
+ end
58
+ def from_hash(hsh)
59
+ new.append_from_hash(hsh)
60
+ end
61
+ end
62
+ end
63
+
64
+ class Response
65
+ attr_accessor :response_type, :status, :message, :severity, :ret_items
66
+ # For Development purposes:
67
+ attr_accessor :raw_response
68
+
69
+ def initialize(xml_or_hash)
70
+ if(xml_or_hash.is_a?(Hash))
71
+ self.import_from_hash(xml_or_hash)
72
+ elsif(xml_or_hash.is_a?(String))
73
+ self.import_from_xml(xml_or_hash)
74
+ else
75
+ raise ArgumentError, "Quickbooks::Qbxml::ResponseSet must be initialized with either a Hash or an xml-formatted String."
76
+ end
77
+ end
78
+
79
+ def import_from_xml(xml)
80
+ self.import_from_hash(Hash.from_xml(xml))
81
+ self
82
+ end
83
+ def import_from_hash(hsh)
84
+ raise ArgumentError, "Hash passed to Quickbooks::Qbxml::Response.from_hash must contain only one top-level key" unless hsh.keys.length == 1
85
+ name = hsh.keys.first
86
+ # for development
87
+ self.raw_response = hsh
88
+ # * * * *
89
+ hsh = hsh[name]
90
+
91
+ self.status = hsh['statusCode'].to_i
92
+ self.severity = hsh['statusSeverity']
93
+ self.message = hsh['statusMessage']
94
+ # if self.status == 0 # Status is good, proceed with eating the request.
95
+ if m = name.match(/^(List|Txn)Del(etedQuery)?Rs$/)
96
+ # (List|Txn)DelRs, or (List|Txn)DeletedQueryRs - both return just a few attributes, like ListID / TxnID and TimeDeleted
97
+ self.response_type = hsh.delete(m[1]+'DelType')
98
+ # self.ret_items = ResponseObject.new(self.response_type, hsh.dup)
99
+ self.ret_items = hsh.dup
100
+ elsif m = name.match(/^([A-Za-z][a-z]+)(Query|Mod|Add)Rs$/)
101
+ self.response_type = m[1]
102
+ # self.ret_items = ResponseObject.new(self.response_type, hsh[self.response_type+'Ret'])
103
+ self.ret_items = hsh[self.response_type+'Ret']
104
+ else
105
+ raise "Could not read this response:\n#{self.raw_response.inspect}"
106
+ end
107
+ # else # Status is bad.
108
+
109
+ # end
110
+ # puts self.inspect
111
+ self
112
+ end
113
+
114
+
115
+ class << self
116
+ def from_xml(xml)
117
+ new.import_from_xml(xml)
118
+ end
119
+ def from_hash(hsh)
120
+ new.import_from_hash(hsh)
121
+ end
122
+ end
123
+
124
+ def instantiatable? # Just checks to see if it can create an object of this type, and if there is actually data to instantiate
125
+ self.response_type ? (Quickbooks.const_defined?(self.response_type) && self.ret_items.is_a?(Hash) || (self.ret_items.is_a?(Array) && self.ret_items[0].is_a?(Hash))) : false
126
+ end
127
+ def success?
128
+ self.status == 0
129
+ end
130
+ def error?
131
+ !success?
132
+ end
133
+
134
+ def instantiate(obj=nil)
135
+ objs = []
136
+ (self.ret_items.is_a?(Array) ? self.ret_items : [self.ret_items]).each do |ret_item|
137
+ if instantiatable?
138
+ if self.status == 0
139
+ if obj.nil?
140
+ obj = "Quickbooks::#{self.response_type}".constantize.instantiate(self.ret_items)
141
+ else
142
+ obj.class.instantiate(obj, self.ret_items)
143
+ end
144
+ else
145
+ # Instantiatable, but some error status. For any error status
146
+ if obj.nil? # Must be a new object. Just as well, create a new object WITHOUT any original_attributes.
147
+ obj = "Quickbooks::#{self.response_type}".constantize.new(self.ret_items)
148
+ else # An existing object. Must be an update or delete request. Update object's original_attributes.
149
+ updated = []
150
+ self.ret_items.each do |k,v|
151
+ k = k.underscore
152
+ if obj.original_values[k] != v
153
+ updated << k
154
+ obj.original_values[k] = v
155
+ end
156
+ end
157
+ ['EditSequence', 'TimeModified', 'TimeCreated'].each do |k|
158
+ obj.send(k.underscore + '=', self.ret_items[k]) if self.ret_items.has_key?(k) && obj.respond_to?(k.underscore + '=')
159
+ end
160
+ self.message = self.message + " Other properties were out of date: [" + updated.join(', ') + '].'
161
+ end
162
+ end
163
+ else
164
+ obj = Quickbooks::Qbxml::Error.new(self) # If not instantiatable, use this 'Error' object just as a wrapper for the response_log to convey the error response.
165
+ end
166
+ obj.response_log << self
167
+ objs << obj
168
+ end
169
+ objs.length > 1 ? objs : objs[0] # Single or nil if not more than one.
170
+ end
171
+ end
172
+
173
+ module ResponseSetArrayExt
174
+ end
175
+ end
176
+ end