quickbooks 0.4.0 → 0.9.9

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 (293) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +23 -0
  3. data/License.txt +54 -0
  4. data/Manifest.txt +73 -0
  5. data/README.txt +79 -0
  6. data/Rakefile +17 -78
  7. data/lib/quickbooks.rb +153 -7
  8. data/lib/quickbooks/adaptability.rb +67 -0
  9. data/lib/quickbooks/adapters/http_adapter.rb +94 -0
  10. data/lib/quickbooks/adapters/https_adapter.rb +57 -0
  11. data/lib/quickbooks/adapters/ole_adapter.rb +141 -110
  12. data/lib/quickbooks/adapters/spew_adapter.rb +39 -0
  13. data/lib/quickbooks/adapters/tcp_adapter.rb +71 -0
  14. data/lib/quickbooks/adapters/test_adapter.rb +62 -0
  15. data/lib/quickbooks/element.rb +385 -0
  16. data/lib/quickbooks/element_collection.rb +105 -0
  17. data/lib/quickbooks/extlib.rb +8 -0
  18. data/lib/quickbooks/extlib/assertions.rb +8 -0
  19. data/lib/quickbooks/extlib/class.rb +98 -0
  20. data/lib/quickbooks/extlib/days_and_times.rb +10 -0
  21. data/lib/quickbooks/extlib/days_and_times/duration.rb +362 -0
  22. data/lib/quickbooks/extlib/days_and_times/numeric.rb +48 -0
  23. data/lib/quickbooks/extlib/days_and_times/object.rb +19 -0
  24. data/lib/quickbooks/extlib/days_and_times/time.rb +137 -0
  25. data/lib/quickbooks/extlib/hash.rb +327 -0
  26. data/lib/quickbooks/extlib/hook.rb +366 -0
  27. data/lib/quickbooks/extlib/inflection.rb +436 -0
  28. data/lib/quickbooks/extlib/logger.rb +202 -0
  29. data/lib/quickbooks/extlib/object.rb +162 -0
  30. data/lib/quickbooks/extlib/pathname.rb +15 -0
  31. data/lib/quickbooks/extlib/rubygems.rb +38 -0
  32. data/lib/quickbooks/extlib/string.rb +32 -0
  33. data/lib/quickbooks/extlib/time.rb +41 -0
  34. data/lib/quickbooks/model.rb +503 -121
  35. data/lib/quickbooks/option.rb +95 -0
  36. data/lib/quickbooks/property.rb +69 -0
  37. data/lib/quickbooks/ruby_ext.rb +251 -0
  38. data/lib/quickbooks/type.rb +75 -0
  39. data/lib/quickbooks/types.rb +58 -0
  40. data/lib/quickbooks/version.rb +10 -0
  41. data/lib/quickbooks/xsd.rb +243 -0
  42. data/lib/quickbooks/xsd/attribute.rb +57 -0
  43. data/lib/quickbooks/xsd/choice.rb +94 -0
  44. data/lib/quickbooks/xsd/complex_type.rb +77 -0
  45. data/lib/quickbooks/xsd/element.rb +214 -0
  46. data/lib/quickbooks/xsd/group.rb +94 -0
  47. data/lib/quickbooks/xsd/restriction.rb +51 -0
  48. data/lib/quickbooks/xsd/sequence.rb +85 -0
  49. data/lib/quickbooks/xsd/simple_type.rb +87 -0
  50. data/lib/quickbooks/xsd/union.rb +70 -0
  51. data/lib/quickbooks/xsd/validation.rb +89 -0
  52. data/lib/quickbooks/xsd/xml_parse.rb +80 -0
  53. data/quickbooks.gemspec +36 -0
  54. data/source/qbxml21_demo.xsd +2223 -0
  55. data/source/qbxmlops_demo.xsd +483 -0
  56. data/source/qbxmltypes.xsd +160 -0
  57. data/spec/association_spec.rb +5 -0
  58. data/spec/element_collection_spec.rb +8 -0
  59. data/spec/find_spec.rb +30 -0
  60. data/spec/lib/quickbooks/element_spec.rb +83 -0
  61. data/spec/lib/quickbooks/elements/sales_order_add_spec.rb +14 -0
  62. data/spec/lib/quickbooks/elements/vendor_add_spec.rb +78 -0
  63. data/spec/lib/quickbooks/model_spec.rb +89 -0
  64. data/spec/lib/quickbooks/models/customer_spec.rb +52 -0
  65. data/spec/lib/quickbooks/models/invoice_spec.rb +12 -0
  66. data/spec/lib/quickbooks/models/sales_order_line_spec.rb +0 -0
  67. data/spec/lib/quickbooks/models/sales_order_spec.rb +145 -0
  68. data/spec/lib/quickbooks/xsd/choice_spec.rb +18 -0
  69. data/spec/pending_spec.rb +11 -0
  70. data/spec/quickbooks_spec.rb +38 -0
  71. data/spec/repeatable_spec.rb +20 -0
  72. data/spec/requires_spec.rb +10 -0
  73. data/spec/spec_helper.rb +5 -0
  74. data/spec/validation_spec.rb +24 -0
  75. metadata +133 -285
  76. metadata.gz.sig +0 -0
  77. data/LICENSE +0 -16
  78. data/README +0 -49
  79. data/doc/classes/Array.html +0 -368
  80. data/doc/classes/Array.src/M000026.html +0 -18
  81. data/doc/classes/Array.src/M000027.html +0 -21
  82. data/doc/classes/Array.src/M000028.html +0 -18
  83. data/doc/classes/Array.src/M000029.html +0 -19
  84. data/doc/classes/Array.src/M000030.html +0 -18
  85. data/doc/classes/Array.src/M000031.html +0 -23
  86. data/doc/classes/Array.src/M000032.html +0 -18
  87. data/doc/classes/Array.src/M000033.html +0 -18
  88. data/doc/classes/Array.src/M000034.html +0 -18
  89. data/doc/classes/Array.src/M000035.html +0 -19
  90. data/doc/classes/Array.src/M000036.html +0 -18
  91. data/doc/classes/Array.src/M000037.html +0 -23
  92. data/doc/classes/Array.src/M000038.html +0 -18
  93. data/doc/classes/Array.src/M000039.html +0 -21
  94. data/doc/classes/Array.src/M000040.html +0 -18
  95. data/doc/classes/Array.src/M000041.html +0 -18
  96. data/doc/classes/Class.html +0 -171
  97. data/doc/classes/Class.src/M000042.html +0 -18
  98. data/doc/classes/Class.src/M000043.html +0 -18
  99. data/doc/classes/Hash.html +0 -516
  100. data/doc/classes/Hash.src/M000001.html +0 -18
  101. data/doc/classes/Hash.src/M000002.html +0 -21
  102. data/doc/classes/Hash.src/M000003.html +0 -18
  103. data/doc/classes/Hash.src/M000004.html +0 -21
  104. data/doc/classes/Hash.src/M000005.html +0 -18
  105. data/doc/classes/Hash.src/M000006.html +0 -20
  106. data/doc/classes/Hash.src/M000007.html +0 -18
  107. data/doc/classes/Hash.src/M000008.html +0 -22
  108. data/doc/classes/Hash.src/M000009.html +0 -18
  109. data/doc/classes/Hash.src/M000010.html +0 -21
  110. data/doc/classes/Hash.src/M000011.html +0 -24
  111. data/doc/classes/Hash.src/M000012.html +0 -18
  112. data/doc/classes/Hash.src/M000013.html +0 -21
  113. data/doc/classes/Hash.src/M000014.html +0 -18
  114. data/doc/classes/Hash.src/M000015.html +0 -21
  115. data/doc/classes/Hash.src/M000016.html +0 -18
  116. data/doc/classes/Hash.src/M000017.html +0 -21
  117. data/doc/classes/Hash.src/M000018.html +0 -27
  118. data/doc/classes/Hash.src/M000019.html +0 -20
  119. data/doc/classes/Hash.src/M000020.html +0 -18
  120. data/doc/classes/Hash.src/M000021.html +0 -18
  121. data/doc/classes/Hash.src/M000022.html +0 -18
  122. data/doc/classes/Hash.src/M000023.html +0 -18
  123. data/doc/classes/Hash.src/M000024.html +0 -18
  124. data/doc/classes/Hash.src/M000025.html +0 -28
  125. data/doc/classes/Object.html +0 -278
  126. data/doc/classes/Object.src/M000044.html +0 -24
  127. data/doc/classes/Object.src/M000045.html +0 -19
  128. data/doc/classes/Object.src/M000046.html +0 -24
  129. data/doc/classes/Object.src/M000047.html +0 -18
  130. data/doc/classes/Object.src/M000048.html +0 -19
  131. data/doc/classes/Object.src/M000049.html +0 -18
  132. data/doc/classes/Object.src/M000050.html +0 -18
  133. data/doc/classes/Object.src/M000051.html +0 -18
  134. data/doc/classes/Qbxml.html +0 -131
  135. data/doc/classes/Qbxml/Request.html +0 -224
  136. data/doc/classes/Qbxml/Request.src/M000132.html +0 -66
  137. data/doc/classes/Qbxml/Request.src/M000133.html +0 -19
  138. data/doc/classes/Qbxml/Request.src/M000134.html +0 -83
  139. data/doc/classes/Qbxml/RequestSet.html +0 -199
  140. data/doc/classes/Qbxml/RequestSet.src/M000135.html +0 -22
  141. data/doc/classes/Qbxml/RequestSet.src/M000136.html +0 -26
  142. data/doc/classes/Qbxml/RequestSet.src/M000137.html +0 -18
  143. data/doc/classes/Qbxml/RequestSet.src/M000138.html +0 -22
  144. data/doc/classes/Qbxml/Response.html +0 -302
  145. data/doc/classes/Qbxml/Response.src/M000123.html +0 -24
  146. data/doc/classes/Qbxml/Response.src/M000124.html +0 -19
  147. data/doc/classes/Qbxml/Response.src/M000125.html +0 -55
  148. data/doc/classes/Qbxml/Response.src/M000126.html +0 -18
  149. data/doc/classes/Qbxml/Response.src/M000127.html +0 -18
  150. data/doc/classes/Qbxml/Response.src/M000128.html +0 -18
  151. data/doc/classes/Qbxml/Response.src/M000129.html +0 -18
  152. data/doc/classes/Qbxml/Response.src/M000130.html +0 -18
  153. data/doc/classes/Qbxml/Response.src/M000131.html +0 -63
  154. data/doc/classes/Qbxml/ResponseSet.html +0 -244
  155. data/doc/classes/Qbxml/ResponseSet.src/M000116.html +0 -22
  156. data/doc/classes/Qbxml/ResponseSet.src/M000117.html +0 -26
  157. data/doc/classes/Qbxml/ResponseSet.src/M000118.html +0 -24
  158. data/doc/classes/Qbxml/ResponseSet.src/M000119.html +0 -20
  159. data/doc/classes/Qbxml/ResponseSet.src/M000120.html +0 -27
  160. data/doc/classes/Qbxml/ResponseSet.src/M000121.html +0 -18
  161. data/doc/classes/Qbxml/ResponseSet.src/M000122.html +0 -18
  162. data/doc/classes/Quickbooks.html +0 -196
  163. data/doc/classes/Quickbooks/Address.html +0 -139
  164. data/doc/classes/Quickbooks/Address.src/M000115.html +0 -19
  165. data/doc/classes/Quickbooks/Base.html +0 -567
  166. data/doc/classes/Quickbooks/Base.src/M000095.html +0 -18
  167. data/doc/classes/Quickbooks/Base.src/M000096.html +0 -20
  168. data/doc/classes/Quickbooks/Base.src/M000097.html +0 -19
  169. data/doc/classes/Quickbooks/Base.src/M000098.html +0 -18
  170. data/doc/classes/Quickbooks/Base.src/M000099.html +0 -19
  171. data/doc/classes/Quickbooks/Base.src/M000100.html +0 -30
  172. data/doc/classes/Quickbooks/Base.src/M000101.html +0 -22
  173. data/doc/classes/Quickbooks/Base.src/M000102.html +0 -30
  174. data/doc/classes/Quickbooks/Base.src/M000103.html +0 -19
  175. data/doc/classes/Quickbooks/Base.src/M000104.html +0 -19
  176. data/doc/classes/Quickbooks/Base.src/M000105.html +0 -18
  177. data/doc/classes/Quickbooks/Base.src/M000106.html +0 -18
  178. data/doc/classes/Quickbooks/Base.src/M000107.html +0 -19
  179. data/doc/classes/Quickbooks/Base.src/M000108.html +0 -18
  180. data/doc/classes/Quickbooks/Base.src/M000109.html +0 -45
  181. data/doc/classes/Quickbooks/Base.src/M000110.html +0 -18
  182. data/doc/classes/Quickbooks/Base.src/M000111.html +0 -18
  183. data/doc/classes/Quickbooks/Base.src/M000112.html +0 -20
  184. data/doc/classes/Quickbooks/BillAddress.html +0 -113
  185. data/doc/classes/Quickbooks/CreditCardInfo.html +0 -113
  186. data/doc/classes/Quickbooks/Customer.html +0 -113
  187. data/doc/classes/Quickbooks/CustomerTypeRef.html +0 -113
  188. data/doc/classes/Quickbooks/Deleted.html +0 -113
  189. data/doc/classes/Quickbooks/ItemSalesTaxRef.html +0 -113
  190. data/doc/classes/Quickbooks/JobTypeRef.html +0 -113
  191. data/doc/classes/Quickbooks/ListDeleted.html +0 -139
  192. data/doc/classes/Quickbooks/ListDeleted.src/M000114.html +0 -18
  193. data/doc/classes/Quickbooks/ListItem.html +0 -170
  194. data/doc/classes/Quickbooks/ListItem.src/M000093.html +0 -20
  195. data/doc/classes/Quickbooks/ListItem.src/M000094.html +0 -18
  196. data/doc/classes/Quickbooks/Model.html +0 -462
  197. data/doc/classes/Quickbooks/Model.src/M000073.html +0 -24
  198. data/doc/classes/Quickbooks/Model.src/M000074.html +0 -19
  199. data/doc/classes/Quickbooks/Model.src/M000075.html +0 -18
  200. data/doc/classes/Quickbooks/Model.src/M000076.html +0 -18
  201. data/doc/classes/Quickbooks/Model.src/M000077.html +0 -18
  202. data/doc/classes/Quickbooks/Model.src/M000078.html +0 -22
  203. data/doc/classes/Quickbooks/Model.src/M000079.html +0 -32
  204. data/doc/classes/Quickbooks/Model.src/M000080.html +0 -32
  205. data/doc/classes/Quickbooks/Model.src/M000081.html +0 -18
  206. data/doc/classes/Quickbooks/Model.src/M000082.html +0 -18
  207. data/doc/classes/Quickbooks/Model.src/M000083.html +0 -22
  208. data/doc/classes/Quickbooks/Model.src/M000084.html +0 -23
  209. data/doc/classes/Quickbooks/Model.src/M000085.html +0 -18
  210. data/doc/classes/Quickbooks/Model.src/M000086.html +0 -21
  211. data/doc/classes/Quickbooks/Model.src/M000087.html +0 -26
  212. data/doc/classes/Quickbooks/Model.src/M000088.html +0 -26
  213. data/doc/classes/Quickbooks/Model.src/M000089.html +0 -26
  214. data/doc/classes/Quickbooks/Model.src/M000090.html +0 -21
  215. data/doc/classes/Quickbooks/Model.src/M000091.html +0 -23
  216. data/doc/classes/Quickbooks/OleAdapter.html +0 -129
  217. data/doc/classes/Quickbooks/OleAdapter/Connection.html +0 -343
  218. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000058.html +0 -18
  219. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000059.html +0 -19
  220. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000060.html +0 -24
  221. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000061.html +0 -18
  222. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000062.html +0 -18
  223. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000063.html +0 -21
  224. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000064.html +0 -24
  225. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000065.html +0 -20
  226. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000066.html +0 -24
  227. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000067.html +0 -24
  228. data/doc/classes/Quickbooks/OleAdapter/Ole.html +0 -209
  229. data/doc/classes/Quickbooks/OleAdapter/Ole.src/M000068.html +0 -21
  230. data/doc/classes/Quickbooks/OleAdapter/Ole.src/M000069.html +0 -22
  231. data/doc/classes/Quickbooks/OleAdapter/Ole.src/M000070.html +0 -18
  232. data/doc/classes/Quickbooks/ParentRef.html +0 -113
  233. data/doc/classes/Quickbooks/PreferredPaymentMethodRef.html +0 -113
  234. data/doc/classes/Quickbooks/PriceLevelRef.html +0 -113
  235. data/doc/classes/Quickbooks/QbxmlDebugAdapter.html +0 -111
  236. data/doc/classes/Quickbooks/QbxmlDebugAdapter/Connection.html +0 -139
  237. data/doc/classes/Quickbooks/QbxmlDebugAdapter/Connection.src/M000057.html +0 -18
  238. data/doc/classes/Quickbooks/Ref.html +0 -146
  239. data/doc/classes/Quickbooks/Ref.src/M000113.html +0 -18
  240. data/doc/classes/Quickbooks/SalesRepRef.html +0 -113
  241. data/doc/classes/Quickbooks/SalesTaxCodeRef.html +0 -113
  242. data/doc/classes/Quickbooks/ShipAddress.html +0 -113
  243. data/doc/classes/Quickbooks/TermsRef.html +0 -113
  244. data/doc/classes/Quickbooks/Transaction.html +0 -154
  245. data/doc/classes/Quickbooks/Transaction.src/M000071.html +0 -19
  246. data/doc/classes/Quickbooks/Transaction.src/M000072.html +0 -18
  247. data/doc/classes/Quickbooks/TxnDeleted.html +0 -139
  248. data/doc/classes/Quickbooks/TxnDeleted.src/M000092.html +0 -18
  249. data/doc/classes/String.html +0 -203
  250. data/doc/classes/String.src/M000052.html +0 -18
  251. data/doc/classes/String.src/M000053.html +0 -18
  252. data/doc/classes/String.src/M000054.html +0 -18
  253. data/doc/classes/String.src/M000055.html +0 -18
  254. data/doc/classes/String.src/M000056.html +0 -18
  255. data/doc/created.rid +0 -1
  256. data/doc/files/LICENSE.html +0 -129
  257. data/doc/files/README.html +0 -225
  258. data/doc/files/lib/qbxml/request_rb.html +0 -110
  259. data/doc/files/lib/qbxml/response_rb.html +0 -109
  260. data/doc/files/lib/qbxml/support_rb.html +0 -101
  261. data/doc/files/lib/qbxml_rb.html +0 -122
  262. data/doc/files/lib/quickbooks/adapters/ole_adapter_rb.html +0 -108
  263. data/doc/files/lib/quickbooks/adapters/qbxml_debug_adapter_rb.html +0 -108
  264. data/doc/files/lib/quickbooks/base_rb.html +0 -327
  265. data/doc/files/lib/quickbooks/model_rb.html +0 -108
  266. data/doc/files/lib/quickbooks/models/common/address_rb.html +0 -101
  267. data/doc/files/lib/quickbooks/models/common/all_refs_rb.html +0 -101
  268. data/doc/files/lib/quickbooks/models/customer/credit_card_info_rb.html +0 -101
  269. data/doc/files/lib/quickbooks/models/customer_rb.html +0 -110
  270. data/doc/files/lib/quickbooks/models/deleted_rb.html +0 -101
  271. data/doc/files/lib/quickbooks/models/list_item_rb.html +0 -101
  272. data/doc/files/lib/quickbooks/models/transaction_rb.html +0 -101
  273. data/doc/files/lib/quickbooks/ruby_magic_rb.html +0 -120
  274. data/doc/files/lib/quickbooks_rb.html +0 -125
  275. data/doc/fr_class_index.html +0 -64
  276. data/doc/fr_file_index.html +0 -45
  277. data/doc/fr_method_index.html +0 -164
  278. data/doc/index.html +0 -24
  279. data/doc/rdoc-style.css +0 -208
  280. data/lib/qbxml.rb +0 -3
  281. data/lib/qbxml/request.rb +0 -207
  282. data/lib/qbxml/response.rb +0 -197
  283. data/lib/qbxml/support.rb +0 -130
  284. data/lib/quickbooks/adapters/qbxml_debug_adapter.rb +0 -10
  285. data/lib/quickbooks/base.rb +0 -277
  286. data/lib/quickbooks/models/common/address.rb +0 -14
  287. data/lib/quickbooks/models/common/all_refs.rb +0 -37
  288. data/lib/quickbooks/models/customer.rb +0 -70
  289. data/lib/quickbooks/models/customer/credit_card_info.rb +0 -5
  290. data/lib/quickbooks/models/deleted.rb +0 -22
  291. data/lib/quickbooks/models/list_item.rb +0 -41
  292. data/lib/quickbooks/models/transaction.rb +0 -49
  293. data/lib/quickbooks/ruby_magic.rb +0 -213
@@ -1,3 +0,0 @@
1
- require 'qbxml/request'
2
- require 'qbxml/response'
3
- QBXML_VERSION = '0.1.0'
@@ -1,207 +0,0 @@
1
- require 'qbxml/support'
2
- require 'builder'
3
- require 'hash_magic'
4
-
5
- module Qbxml
6
- VERSION = '6.0'
7
-
8
- # module RequestSetArrayExt
9
- # end
10
-
11
- class RequestSet
12
- include Enumerable
13
- def set
14
- unless @set.is_a?(Array)
15
- @set = []
16
- # @set.extend(Qbxml::RequestSetArrayExt)
17
- end
18
- @set
19
- end
20
- delegate_methods [:each, :length, :first, :last, :[], :map, :join] => :set
21
- def <<(qbxml_request)
22
- if qbxml_request.is_a?(Qbxml::Request)
23
- set << qbxml_request
24
- elsif qbxml_request.respond_to?(:each)
25
- qbxml_request.each do |request|
26
- self << request
27
- end
28
- else
29
- raise ArgumentError, "Cannot add object of type #{qbxml_request.class.name} to a Qbxml::RequestSet"
30
- end
31
- end
32
-
33
- def initialize(*requests)
34
- self << requests
35
- end
36
-
37
- def to_xml
38
- pre = <<-thequickbooks_qbxmlrequestsetxml
39
- <?xml version="1.0" ?>
40
- <?qbxml version="#{Qbxml::VERSION}" ?>
41
- <QBXML>
42
- <QBXMLMsgsRq onError="stopOnError">
43
- thequickbooks_qbxmlrequestsetxml
44
- requests = map {|x| x.to_xml(false)}.join
45
- post = <<-thequickbooks_qbxmlrequestsetxml
46
- </QBXMLMsgsRq>
47
- </QBXML>
48
- thequickbooks_qbxmlrequestsetxml
49
- # puts pre + requests + post
50
- pre + requests + post
51
- end
52
- end
53
-
54
- class Request
55
- # 1. List queries (:query)
56
- # Request.new(object, :query) # <= will return the record matching the object supplied (automatically searches by list_id or txn_id)
57
- # Request.new(Customer, :query, :limit => 1) # <= will return the first customer
58
- # Request.new(Customer, :query, /some match/) # <= will return all customers matching the regexp
59
- # 2. Deleted queries (:deleted)
60
- # Request.new(object, :deleted) # <= INVALID!! (besides, you wouldn't have an object to check up on anyway :P )
61
- # Request.new(Customer, :deleted) # <= will return all deleted Customers
62
- # Request.new(Customer, :deleted, :deleted_date_range_filter => {'from_deleted_date' => Date.parse('2008/10/05')}) # <= will return all Customers deleted since 5 October 2008
63
- # 3. Object-specific transaction query (:transaction)
64
- # Request.new(Transaction, :query) # <= will return the transaction matching the object supplied
65
- # 4. Mod requests (:mod)
66
- # Request.new(object, :mod) # <= will update the object
67
- # 5. Delete requests (:delete)
68
- # Request.new(object, :delete) # <= will delete the object
69
- # We want the attributes of the object when we are updating, but no other time.
70
- def initialize(object, type, options_or_regexp={})
71
- options = options_or_regexp.is_a?(Regexp) ? {:matches => options_or_regexp} : options_or_regexp
72
- @type = type
73
- raise ArgumentError, "Qbxml::Requests can only be of one of the following types: :query, :transaction, :any_transaction, :mod, :add, :delete, :deleted, or :report" unless @type.is_one_of?(:query, :transaction, :any_transaction, :mod, :report, :add, :delete, :deleted)
74
- @klass = object.is_a?(Class) ? object : object.class
75
- @object = object
76
- @options = options
77
-
78
- # Transform the options received for :deleted requests.
79
- # This way, Request.new(Customer, :deleted) == Request.new(ListDeleted, :list_del_type => 'Customer')
80
- # and Request.new(Transaction, :deleted) == Request.new(TxnDeleted, :txn_del_type => 'Transaction')
81
- if @type == :deleted
82
- case @klass.ListOrTxn
83
- when 'List'
84
- @options[:list_del_type] = @klass.lone_name
85
- @klass = Quickbooks::ListDeleted
86
- when 'Txn'
87
- @options[:txn_del_type] = @klass.lone_name
88
- @klass = Quickbooks::TxnDeleted
89
- end
90
- end
91
-
92
- # Return only specific properties: Request.new(Customer, :query, :only => [:list_id, :full_name]); Quickbooks::Customer.first(:only => :list_id)
93
- @ret_elements = @options.delete(:only).to_a.only(@klass.properties).ordered(@klass.properties).stringify_values.camelize_values!(Quickbooks::CAMELIZE_EXCEPTIONS) if @options.has_key?(:only)
94
-
95
- # Includes only valid filters + aliases for valid filters, # => {underscore/slashed keys + aliases}
96
- # then transforms aliased filters to real filters, # => {underscore/slashed keys}
97
- # then camelizes keys to prepare for writing to XML, # => {}
98
- # lastly orders the keys to a valid filter order.
99
-
100
- # Study the following:
101
- # @klass.filter_aliases = {'deleted_after' => 'deleted_date_range_filter/from_deleted_date'}
102
- # @klass.valid_filters = ['deleted_date_range_filter/from_deleted_date']
103
- # {:deleted_after => "2008-03-20T11:20:26-04:00"}.slashed.
104
- # only(@klass.valid_filters + @klass.filter_aliases.slashed.flat.keys).
105
- # transform_keys!(@klass.filter_aliases.slashed.flat).
106
- # slash_camelize_keys!(Quickbooks::CAMELIZE_EXCEPTIONS).slashed.
107
- # ordered!(@klass.camelized_valid_filters).slashed.expand
108
- # # => {"DeletedDateRangeFilter" => {"FromDeletedDate" => "2008-03-20T11:20:26-04:00"}}
109
- @filters = @options.delete(:filters) || @options.slashed.
110
- only(@klass.valid_filters + @klass.filter_aliases.slashed.flat.keys).
111
- transform_keys!(@klass.filter_aliases.slashed.flat).
112
- slash_camelize_keys!(Quickbooks::CAMELIZE_EXCEPTIONS).
113
- ordered!(@klass.camelized_valid_filters)
114
- @filters = @filters.to_hash unless @filters.is_a?(Hash)
115
- @filters = @filters['FILTERS'] if @filters.keys == ['FILTERS'] # So if you include an xml-formatted string of filters, you can simply wrap them in <FILTERS></FILTERS> as a root key
116
-
117
- # Complain if:
118
- # 1) type is :mod or :delete, and object supplied is not a valid model
119
- raise ArgumentError, "A Quickbooks record object must be supplied to perform an add, mod or del action" if @type.is_one_of?(:add, :mod, :delete) && !@object.is_a?(Quickbooks::Base)
120
- end
121
-
122
- def self.next_request_id
123
- @request_id ||= 0
124
- @request_id += 1
125
- end
126
-
127
- # This is where the magic happens to convert a request object into xml worthy of quickbooks.
128
- def to_xml(as_set=true)
129
- 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.
130
- req = Builder::XmlMarkup.new(:indent => 2)
131
- request_root, container = case
132
- when @type.is_one_of?(:query)
133
- ["#{@klass.class_leaf_name}QueryRq", nil]
134
- when @type == :add
135
- ["#{@klass.class_leaf_name}AddRq", "#{@klass.class_leaf_name}Add"]
136
- when @type == :mod
137
- ["#{@klass.class_leaf_name}ModRq", "#{@klass.class_leaf_name}Mod"]
138
- when @type == :delete
139
- ["#{@klass.ListOrTxn}DelRq", nil]
140
- when @type == :deleted
141
- ["#{@klass.ListOrTxn}DeletedQueryRq", nil]
142
- else
143
- raise RuntimeError, "Could not convert this request to qbxml!\n#{self.inspect}"
144
- end
145
- inner_stuff = lambda {
146
- deep_tag = lambda {|k,v|
147
- if v.is_a?(Hash)
148
- if k == ''
149
- v.each { |k,v|
150
- deep_tag.call(k,v)
151
- }
152
- else
153
- req.tag!(k.camelize) { v.each { |k,v| deep_tag.call(k,v) } }
154
- end
155
- else
156
- req.tag!(k.camelize,uncast(v))
157
- end
158
- }
159
-
160
- # Add the specific elements for the respective request type
161
- if @type.is_one_of?(:add, :mod)
162
- if @type == :mod
163
- # First the ObjectId:
164
- req.tag!(@klass.ListOrTxn + 'ID', @object.send("#{@klass.ListOrTxn}Id".underscore))
165
- # Second the EditSequence
166
- req.tag!('EditSequence', @object.send(:edit_sequence))
167
- end
168
- # Then, all the dirty_attributes
169
- deep_tag.call('',@object.to_dirty_hash) # (this is an hash statically ordered to the model's qbxml attribute order)
170
- elsif @type == :query && @object.class == @klass
171
- # Sent an instance object for a query - we should include the ListId/TxnId (then other filters?)
172
- req.tag!(@klass.ListOrTxn + 'ID', @object.send("#{@klass.ListOrTxn}Id".underscore))
173
- deep_tag.call('', @filters)
174
- elsif @type == :delete
175
- req.tag!(@klass.ListOrTxn + 'DelType', @klass.class_leaf_name)
176
- req.tag!(@klass.ListOrTxn + 'ID', @object.send("#{@klass.ListOrTxn}Id".underscore))
177
- else
178
- # just filters
179
- deep_tag.call('', @filters)
180
- end
181
- # Lastly, specify the fields to return, if desired
182
- @ret_elements.each { |r| req.tag!('IncludeRetElement', r) } if @ret_elements.is_a?(Array) && @ret_elements.length > 0
183
- }
184
- req.tag!(request_root, :requestID => self.class.next_request_id) {
185
- if container
186
- req.tag!(container) {
187
- inner_stuff.call
188
- }
189
- else
190
- inner_stuff.call
191
- end
192
- }
193
- # puts req.target!
194
- req.target!
195
- end
196
-
197
- private
198
- def uncast(v)
199
- case
200
- when v.respond_to?(:xmlschema)
201
- v.xmlschema
202
- else
203
- v
204
- end
205
- end
206
- end
207
- end
@@ -1,197 +0,0 @@
1
- require 'qbxml/support'
2
- require 'formatted_string'
3
-
4
- module Qbxml
5
- # module ResponseSetArrayExt
6
- # end
7
-
8
- class ResponseSet
9
- include Enumerable
10
- def set
11
- unless @set.is_a?(Array)
12
- @set = []
13
- # @set.extend(Qbxml::ResponseSetArrayExt)
14
- end
15
- @set
16
- end
17
- delegate_methods [:each, :length, :first, :last, :[], :map, :join] => :set
18
- def <<(qbxml_response)
19
- if qbxml_response.is_a?(Qbxml::Response)
20
- set << qbxml_response
21
- elsif qbxml_response.respond_to?(:each)
22
- qbxml_response.each do |response|
23
- self << response
24
- end
25
- else
26
- raise ArgumentError, "Cannot add object of type #{qbxml_response.class.name} to a Qbxml::ResponseSet"
27
- end
28
- end
29
-
30
- def initialize(xml_or_hash)
31
- if(xml_or_hash.is_a?(Hash))
32
- self.append_from_hash(xml_or_hash)
33
- elsif(xml_or_hash.is_a?(String))
34
- self.append_from_xml(xml_or_hash)
35
- else
36
- raise ArgumentError, "Qbxml::ResponseSet must be initialized with either a Hash or an xml-formatted String."
37
- end
38
- end
39
-
40
- def append_from_xml(xml)
41
- # puts "ResponseXML:"
42
- # puts xml
43
- self.append_from_hash(xml.formatted(:xml).to_hash)
44
- end
45
- def append_from_hash(hsh)
46
- to_append = []
47
- hsh = hsh['QBXML'] if hsh.has_key?('QBXML')
48
- hsh = hsh['QBXMLMsgsRs'] if hsh.has_key?('QBXMLMsgsRs')
49
- # responses will contain one or more keys.
50
- hsh.each_key do |name|
51
- # response_type is either a single response object, or an array of response objects. Force it into an array:
52
- responses = hsh[name].is_a?(Array) ? hsh[name] : [hsh[name]]
53
- responses.each { |response| to_append << Response.new(name => response) }
54
- end
55
- self << to_append
56
- end
57
-
58
- class << self
59
- def from_xml(xml)
60
- new.append_from_xml(xml)
61
- end
62
- def from_hash(hsh)
63
- new.append_from_hash(hsh)
64
- end
65
- end
66
- end
67
-
68
- class Response
69
- attr_accessor :response_type, :status, :message, :severity, :ret_items
70
- # For Development purposes:
71
- attr_accessor :raw_response
72
-
73
- def initialize(xml_or_hash)
74
- if(xml_or_hash.is_a?(Hash))
75
- self.import_from_hash(xml_or_hash)
76
- elsif(xml_or_hash.is_a?(String))
77
- self.import_from_xml(xml_or_hash)
78
- else
79
- raise ArgumentError, "Qbxml::ResponseSet must be initialized with either a Hash or an xml-formatted String."
80
- end
81
- end
82
-
83
- def import_from_xml(xml)
84
- self.import_from_hash(xml.formatted(:xml).to_hash)
85
- self
86
- end
87
- def import_from_hash(hsh)
88
- raise ArgumentError, "Hash passed to Qbxml::Response.from_hash must contain only one top-level key" unless hsh.keys.length == 1
89
- name = hsh.keys.first
90
- # for development
91
- self.raw_response = hsh
92
- # * * * *
93
- hsh = hsh[name]
94
-
95
- self.status = hsh['statusCode'].to_i
96
- self.severity = hsh['statusSeverity']
97
- self.message = hsh['statusMessage']
98
- # if self.status == 0 # Status is good, proceed with eating the request.
99
- # <ListDeletedQueryRs requestID="5" statusCode="0" statusSeverity="Info" statusMessage="Status OK">
100
- # <ListDeletedRet>
101
- # <ListDelType>Customer</ListDelType>
102
- # <ListID>80000030-1203622308</ListID>
103
- # <TimeCreated>2008-02-21T14:31:48-05:00</TimeCreated>
104
- # <TimeDeleted>2008-03-18T17:31:12-05:00</TimeDeleted>
105
- # <FullName>Rachel Parker</FullName>
106
- # </ListDeletedRet>
107
- # </ListDeletedQueryRs>
108
- if m = name.match(/^(List|Txn)Del(etedQuery)?Rs$/)
109
- # (List|Txn)DelRs, or (List|Txn)DeletedQueryRs - both return just a few attributes, like ListID / TxnID and TimeDeleted
110
- list_or_txn = m[1]
111
- long_name = m[1]+'Del'+m[2].to_s
112
- ret_key = long_name.gsub(/Query$/,'')+'Ret'
113
- self.ret_items = hsh[ret_key].is_a?(Array) ? hsh[ret_key] : [hsh[ret_key]].compact # Force to be an array - it's return items!
114
- self.response_type = self.ret_items.empty? ? m[1] : self.ret_items[0][list_or_txn+'DelType']
115
- elsif m = name.match(/^((?:[A-Za-z][a-z]+)+)(Query|Mod|Add)Rs$/)
116
- self.response_type = m[1]
117
- self.ret_items = hsh[self.response_type+'Ret']
118
- else
119
- raise "Could not read this response:\n#{self.raw_response.inspect}"
120
- end
121
- # else # Status is bad.
122
-
123
- # end
124
- # puts self.inspect
125
- self
126
- end
127
-
128
-
129
- class << self
130
- def from_xml(xml)
131
- new.import_from_xml(xml)
132
- end
133
- def from_hash(hsh)
134
- new.import_from_hash(hsh)
135
- end
136
- end
137
-
138
- def instantiatable? # Just checks to see if it can create an object of this type, and if there is actually data to instantiate
139
- 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
140
- end
141
- def success?
142
- self.status == 0
143
- end
144
- def error?
145
- !success?
146
- end
147
-
148
- def instantiate(reinstantiate=nil)
149
- objs = []
150
- (self.ret_items.is_a?(Array) ? self.ret_items : [self.ret_items]).each do |ret_item|
151
- obj = reinstantiate if reinstantiate
152
- if instantiatable?
153
- if self.status == 0
154
- if obj.nil?
155
- obj = "Quickbooks::#{self.response_type}".constantize.instantiate(ret_item)
156
- else
157
- obj.class.instantiate(obj, ret_item)
158
- end
159
- else
160
- # Instantiatable, but some error status. For any error status
161
- if obj.nil? # Must be a new object. Just as well, create a new object WITHOUT any original_attributes.
162
- obj = "Quickbooks::#{self.response_type}".constantize.new(ret_item)
163
- else # An existing object. Must be an update or delete request. Update object's original_attributes.
164
- updated = []
165
- ret_item.each do |k,v|
166
- k = k.underscore
167
- if obj.original_values[k] != v
168
- updated << k
169
- if obj.class.instance_variable_get('@object_properties').has_key?(k.to_sym)
170
- obj.original_values[k] = obj.class.instance_variable_get('@object_properties')[k.to_sym].new(v)
171
- else
172
- obj.original_values[k] = v
173
- end
174
- end
175
- end
176
- # Update object's 'read-only' attributes (as well as in the original_values):
177
- obj.class.read_only.stringify_values.camelize_values.each do |k|
178
- obj.send(k.underscore + '=', ret_item[k]) if ret_item.has_key?(k) && obj.respond_to?(k.underscore + '=')
179
- end
180
- self.message = self.message + " Other properties were out of date: [" + updated.join(', ') + '].'
181
- end
182
- obj.errors << {:code => self.status, :message => self.message, :response => self}
183
- end
184
- else
185
- if self.status == 0
186
- obj.errors << {:code => nil, :message => "Cannot instantiate object of type #{self.response_type}!", :response => self}
187
- else
188
- obj.errors << {:code => self.status, :message => self.message, :response => self}
189
- end
190
- end
191
- obj.response_log << self unless obj.nil?
192
- objs << obj
193
- end
194
- objs.length > 1 ? objs : objs[0] # Single (fallback nil) if not more than one.
195
- end
196
- end
197
- end
@@ -1,130 +0,0 @@
1
- gem 'formattedstring'
2
- gem 'builder'
3
- gem 'hash_magic'
4
-
5
- class Object
6
- # This allows one to effectively 'proxy' specific methods to be called on the return value of one of its methods.
7
- # For example, obj.length could be delegated to do the same thing as obj.full_text.length
8
- def delegate_methods(hsh)
9
- raise ArgumentError, "delegate_methods should be called like: delegate_methods [:method1, :method2] => :delegated_to_method" unless hsh.keys.first.is_a?(Array)
10
- methods = hsh.keys.first
11
- delegate_to = hsh[methods]
12
- methods.each do |method|
13
- self.send(:eval, <<-ddddddd
14
- def #{method}(*args, &block)
15
- block_given? ? self.#{delegate_to}.#{method}(*args, &block) : self.#{delegate_to}.#{method}(*args)
16
- end
17
- ddddddd
18
- )
19
- end
20
- end
21
-
22
- # Normally one would say, "if [:a, :b, :c].include?(:a)" -- which is backward thinking, instead you should use this magic:
23
- # ":a.is_one_of?(:a, :b, :c)", or :a.is_one_of?([:a, :b, :c]).
24
- def is_one_of?(*ary)
25
- raise ArgumentError, "exists_in? requires an array to be passed" unless ary.is_a?(Array)
26
- ary.flatten.include?(self)
27
- end
28
- end
29
-
30
- class Class
31
- def lone_name
32
- name.gsub(/.*::/, '')
33
- end
34
- end
35
-
36
- class String
37
- def constantize
38
- Object.module_eval("::#{self}", __FILE__, __LINE__)
39
- end
40
-
41
- def underscore
42
- gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
43
- end
44
-
45
- def camelize
46
- gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
47
- end
48
- end
49
-
50
- class Array
51
- def camelize_values(specials={})
52
- self.dup.camelize_values!(specials)
53
- end
54
- def camelize_values!(specials={})
55
- self.each_with_index do |v,i|
56
- self[i] = specials.has_key?(v) ? specials[v] : (v.is_a?(Symbol) ? v.to_s.camelize.to_sym : v.camelize)
57
- end
58
- self
59
- end
60
-
61
- def stringify_values
62
- self.dup.stringify_values!
63
- end
64
- def stringify_values!
65
- self.each_with_index { |v,i| self[i] = v.to_s }
66
- self
67
- end
68
-
69
- def only(*values)
70
- self.dup.only!(*values)
71
- end
72
- def only!(*values)
73
- values.flatten!
74
- i = 0
75
- while i <= length-1 do
76
- self[i].is_one_of?(values) ? i += 1 : self.slice!(i)
77
- end
78
- self
79
- end
80
-
81
- def order(*ordered)
82
- self.dup.order!(*ordered)
83
- end
84
- def order!(*ordered)
85
- self.replace(ordered.flatten!.only!(self))
86
- end
87
- end
88
-
89
- class Hash
90
- # Transform all the keys in the hash to CamelCase format.
91
- def camelize_keys(specials={})
92
- self.dup.camelize_keys!(specials)
93
- end
94
- def camelize_keys!(specials={})
95
- self.each_key do |k|
96
- self[specials.has_key?(k) ? specials[k] : k.camelize] = self.delete(k)
97
- end
98
- self
99
- end
100
-
101
- def stringify_keys(specials={})
102
- self.dup.stringify_keys!(specials)
103
- end
104
- def stringify_keys!(specials={})
105
- self.each_key do |k|
106
- self[specials.has_key?(k) ? specials[k] : k.to_s] = self.delete(k)
107
- end
108
- self
109
- end
110
-
111
- def only(*keys)
112
- self.dup.only!(*keys)
113
- end
114
- def only!(*keys)
115
- keys = keys.flatten
116
- self.keys.each { |k| self.delete(k) unless keys.include?(k) }
117
- self
118
- end
119
-
120
- def transform_keys(trans_hash)
121
- self.dup.transform_keys!(trans_hash)
122
- end
123
- def transform_keys!(trans_hash)
124
- raise ArgumentError, "transform_keys takes a single hash argument" unless trans_hash.is_a?(Hash)
125
- self.each_key do |k|
126
- self[trans_hash.has_key?(k) ? trans_hash[k] : k] = self.delete(k)
127
- end
128
- self
129
- end
130
- end