quickbooks-ruby 0.6.7 → 1.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f0f3695093279eed43fc6d76197a6b5cf69142ef0edc91f680981c1c9b30300
4
- data.tar.gz: 04321daa044502c5bea12a6530323e50fc61e6838b6290598ad535ab11cfa885
3
+ metadata.gz: d1f6e851cfb68ae7f6acf08a355b9d3e917d92f98a0bac9c53098f1a4c8b2f6f
4
+ data.tar.gz: 9db0566d15faef2b617f35c288eee7762ef0e7714586f6c6b9b6dd5add1cb3b3
5
5
  SHA512:
6
- metadata.gz: 2a0c35ff4ccbaf55a1846b00118c6e20de33f0780f477e459c68d6b6a12804c6e97de05c6e00a2a0a8da9c7faaa9ea0d330cf623a8d1036d985b7c2c18a542da
7
- data.tar.gz: 283064cdffe11bbddb36b52d237a25635da700b6cb850391570c803a63d053adc473b458df57c66cdc0e7058ed2b997ad5e2a033d7aa64b609cb2ee4fb25306b
6
+ metadata.gz: 61f501677c4c382b9d4e1200158dc9daac57e12d51274c7eeeabb4415d41bec14a80e32b2cdea40923dcc962aac9e4593bbc83f60f389552aaac3301e241e6c2
7
+ data.tar.gz: 966a4d88b2f45eaa8d6bea233cca742b5d3cdeee1b9340f0b060ea03efade653b432d38e222fd47a13057f502991c477946347dfed4f155868756060260229e1
@@ -7,12 +7,20 @@ require 'uri'
7
7
  require 'date'
8
8
  require 'forwardable'
9
9
  require 'oauth'
10
+ require 'oauth2'
10
11
  require 'net/http/post/multipart'
11
12
  require 'quickbooks/util/collection'
12
13
  require 'quickbooks/util/logging'
13
14
  require 'quickbooks/util/http_encoding_helper'
14
15
  require 'quickbooks/util/name_entity'
15
16
  require 'quickbooks/util/query_builder'
17
+ require 'quickbooks/faraday/middleware/gzip'
18
+
19
+ #== OAuth Responses
20
+ require 'quickbooks/service/responses/oauth_http_response'
21
+ require 'quickbooks/service/responses/methods'
22
+ require 'quickbooks/service/responses/oauth1_http_response'
23
+ require 'quickbooks/service/responses/oauth2_http_response'
16
24
 
17
25
  #== Models
18
26
  require 'quickbooks/model/definition'
@@ -176,9 +184,11 @@ require 'quickbooks/service/transfer'
176
184
  require 'quickbooks/service/change_data_capture'
177
185
  require 'quickbooks/service/refund_receipt_change'
178
186
 
187
+ # Register Faraday Middleware
188
+ Faraday::Middleware.register_middleware :gzip => lambda { Gzip }
189
+
179
190
  module Quickbooks
180
191
  @@sandbox_mode = false
181
-
182
192
  @@logger = nil
183
193
 
184
194
  class << self
@@ -239,4 +249,10 @@ module Quickbooks
239
249
  end
240
250
  end
241
251
 
252
+ class InvalidOauthAccessTokenObject < StandardError
253
+ def initialize(access_token)
254
+ super("Expected access token to be an instance of OAuth::AccessToken or OAuth2::AccessToken, got #{access_token.class}.")
255
+ end
256
+ end
257
+
242
258
  end
@@ -0,0 +1,72 @@
1
+ # https://github.com/lostisland/faraday_middleware/blob/master/lib/faraday_middleware/gzip.rb
2
+
3
+ require 'faraday'
4
+
5
+ # Middleware to automatically decompress response bodies. If the
6
+ # "Accept-Encoding" header wasn't set in the request, this sets it to
7
+ # "gzip,deflate" and appropriately handles the compressed response from the
8
+ # server. This resembles what Ruby 1.9+ does internally in Net::HTTP#get.
9
+ #
10
+ # This middleware is NOT necessary when these adapters are used:
11
+ # - net_http on Ruby 1.9+
12
+ # - net_http_persistent on Ruby 2.0+
13
+ # - em_http
14
+ class Gzip < Faraday::Middleware
15
+ dependency 'zlib'
16
+
17
+ ACCEPT_ENCODING = 'Accept-Encoding'.freeze
18
+ CONTENT_ENCODING = 'Content-Encoding'.freeze
19
+ CONTENT_LENGTH = 'Content-Length'.freeze
20
+ SUPPORTED_ENCODINGS = 'gzip,deflate,br'.freeze
21
+ RUBY_ENCODING = '1.9'.respond_to?(:force_encoding)
22
+
23
+ def call(env)
24
+ env[:request_headers][ACCEPT_ENCODING] ||= SUPPORTED_ENCODINGS
25
+ @app.call(env).on_complete do |response_env|
26
+ case response_env[:response_headers][CONTENT_ENCODING]
27
+ when 'gzip'
28
+ reset_body(response_env, &method(:uncompress_gzip))
29
+ when 'deflate'
30
+ reset_body(response_env, &method(:inflate))
31
+ when 'br'
32
+ reset_body(response_env, &method(:brotli_inflate))
33
+ end
34
+ end
35
+ end
36
+
37
+ def reset_body(env)
38
+ env[:body] = yield(env[:body])
39
+ env[:response_headers].delete(CONTENT_ENCODING)
40
+ env[:response_headers][CONTENT_LENGTH] = env[:body].length
41
+ end
42
+
43
+ def uncompress_gzip(body)
44
+ io = StringIO.new(body)
45
+ gzip_reader = if RUBY_ENCODING
46
+ Zlib::GzipReader.new(io, :encoding => 'ASCII-8BIT')
47
+ else
48
+ Zlib::GzipReader.new(io)
49
+ end
50
+ gzip_reader.read
51
+ end
52
+
53
+ def inflate(body)
54
+ # Inflate as a DEFLATE (RFC 1950+RFC 1951) stream
55
+ Zlib::Inflate.inflate(body)
56
+ rescue Zlib::DataError
57
+ # Fall back to inflating as a "raw" deflate stream which
58
+ # Microsoft servers return
59
+ inflate = Zlib::Inflate.new(-Zlib::MAX_WBITS)
60
+ begin
61
+ inflate.inflate(body)
62
+ ensure
63
+ inflate.close
64
+ end
65
+ end
66
+
67
+ def brotli_inflate(body)
68
+ self.class.dependency 'brotli'
69
+
70
+ Brotli.inflate(body)
71
+ end
72
+ end
@@ -2,6 +2,7 @@ module Quickbooks
2
2
  module Model
3
3
  class BaseModel
4
4
  include Definition
5
+ include ActiveModel::AttributeMethods
5
6
  include ActiveModel::Validations
6
7
  include Validator
7
8
  include ROXML
@@ -54,7 +55,7 @@ module Quickbooks
54
55
  def inspect
55
56
  # it would be nice if we could inspect all the children,
56
57
  # but it's likely to blow the stack in some cases
57
- "#<#{self.class} " +
58
+ "#<#{self.class} " +
58
59
  "#{attributes.map{|k,v| "#{k}: #{v.nil? ? 'nil' : v.to_s }"}.join ", "}>"
59
60
  end
60
61
  class << self
@@ -3,7 +3,8 @@ module Quickbooks
3
3
  class GroupLineDetail < BaseModel
4
4
  include HasLineItems
5
5
 
6
- xml_accessor :group_item_ref, :from => 'CustomerRef', :as => BaseReference
6
+ xml_accessor :id, :from => 'Id'
7
+ xml_accessor :group_item_ref, :from => 'GroupItemRef', :as => BaseReference
7
8
  xml_accessor :quantity, :from => 'Quantity', :as => BigDecimal, :to_xml => to_xml_big_decimal
8
9
  xml_accessor :line_items, :from => 'Line', :as => [Line]
9
10
 
@@ -17,6 +17,7 @@ module Quickbooks
17
17
  XML_COLLECTION_NODE = "Invoice"
18
18
  XML_NODE = "Invoice"
19
19
  EMAIL_STATUS_NEED_TO_SEND = 'NeedToSend'
20
+ MINORVERSION = 37
20
21
 
21
22
  xml_accessor :id, :from => 'Id'
22
23
  xml_accessor :sync_token, :from => 'SyncToken', :as => Integer
@@ -24,6 +25,7 @@ module Quickbooks
24
25
  xml_accessor :custom_fields, :from => 'CustomField', :as => [CustomField]
25
26
  xml_accessor :auto_doc_number, :from => 'AutoDocNumber' # See auto_doc_number! method below for usage
26
27
  xml_accessor :doc_number, :from => 'DocNumber'
28
+ xml_accessor :invoice_link, :from => 'InvoiceLink'
27
29
  xml_accessor :txn_date, :from => 'TxnDate', :as => Date
28
30
  xml_accessor :currency_ref, :from => 'CurrencyRef', :as => BaseReference
29
31
  xml_accessor :exchange_rate, :from => 'ExchangeRate', :as => BigDecimal, :to_xml => to_xml_big_decimal
@@ -1,12 +1,15 @@
1
1
  module Quickbooks
2
2
  module Model
3
3
  class Line < BaseModel
4
+ require 'quickbooks/model/group_line_detail'
5
+
4
6
  #== Constants
5
7
  SALES_ITEM_LINE_DETAIL = 'SalesItemLineDetail'
6
8
  SUB_TOTAL_LINE_DETAIL = 'SubTotalLineDetail'
7
9
  PAYMENT_LINE_DETAIL = 'PaymentLineDetail'
8
10
  DISCOUNT_LINE_DETAIL = 'DiscountLineDetail'
9
11
  JOURNAL_ENTRY_LINE_DETAIL = 'JournalEntryLineDetail'
12
+ GROUP_LINE_DETAIL = 'GroupLineDetail'
10
13
 
11
14
  xml_accessor :id, :from => 'Id'
12
15
  xml_accessor :line_num, :from => 'LineNum', :as => Integer
@@ -22,6 +25,7 @@ module Quickbooks
22
25
  xml_accessor :payment_line_detail, :from => 'PaymentLineDetail', :as => PaymentLineDetail
23
26
  xml_accessor :discount_line_detail, :from => 'DiscountLineDetail', :as => DiscountOverride
24
27
  xml_accessor :journal_entry_line_detail, :from => 'JournalEntryLineDetail', :as => JournalEntryLineDetail
28
+ xml_accessor :group_line_detail, :from => 'GroupLineDetail', :as => GroupLineDetail
25
29
 
26
30
  def initialize(*args)
27
31
  self.linked_transactions ||= []
@@ -73,6 +77,13 @@ module Quickbooks
73
77
  yield self.journal_entry_line_detail if block_given?
74
78
  end
75
79
 
80
+ def group_line!
81
+ self.detail_type = GROUP_LINE_DETAIL
82
+ self.group_line_detail = GroupLineDetail.new
83
+
84
+ yield self.group_line_detail if block_given?
85
+ end
86
+
76
87
  private
77
88
 
78
89
  def update_linked_transactions(txn_ids, txn_type)
@@ -43,6 +43,7 @@ module Quickbooks
43
43
  validates_inclusion_of :name_of, :in => NAMEOF_OPTIONS
44
44
  validate :existence_of_employee_ref, :if => Proc.new { |ta| ta.name_of == "Employee" }
45
45
  validate :existence_of_vendor_ref, :if => Proc.new { |ta| ta.name_of == "Vendor" }
46
+ validates :description, length: { maximum: 4000 }
46
47
 
47
48
  def existence_of_employee_ref
48
49
  if employee_ref.nil? || (employee_ref && employee_ref.value == 0)
@@ -3,7 +3,8 @@ module Quickbooks
3
3
  class AccessToken < BaseService
4
4
 
5
5
  RENEW_URL = "https://appcenter.intuit.com/api/v1/connection/reconnect"
6
- DISCONNECT_URL = "https://appcenter.intuit.com/api/v1/connection/disconnect"
6
+ DISCONNECT_URL_OAUTH1 = "https://appcenter.intuit.com/api/v1/connection/disconnect"
7
+ DISCONNECT_URL_OAUTH2 = "https://developer.api.intuit.com/v2/oauth2/tokens/revoke"
7
8
 
8
9
  # https://developer.intuit.com/docs/0025_quickbooksapi/0053_auth_auth/oauth_management_api#Reconnect
9
10
  def renew
@@ -21,16 +22,24 @@ module Quickbooks
21
22
 
22
23
  # https://developer.intuit.com/docs/0025_quickbooksapi/0053_auth_auth/oauth_management_api#Disconnect
23
24
  def disconnect
24
- result = nil
25
- response = do_http_get(DISCONNECT_URL)
26
- if response
27
- code = response.code.to_i
28
- if code == 200
29
- result = Quickbooks::Model::AccessTokenResponse.from_xml(response.plain_body)
25
+ if oauth_v1?
26
+ response = do_http_get(DISCONNECT_URL_OAUTH1)
27
+ if response && response.code.to_i == 200
28
+ Quickbooks::Model::AccessTokenResponse.from_xml(response.plain_body)
30
29
  end
31
- end
30
+ elsif oauth_v2?
31
+ conn = Faraday.new
32
+ conn.basic_auth oauth.client.id, oauth.client.secret
33
+ response = conn.post(DISCONNECT_URL_OAUTH2, token: oauth.refresh_token || oauth.token)
32
34
 
33
- result
35
+ if response.success?
36
+ Quickbooks::Model::AccessTokenResponse.new(error_code: "0")
37
+ else
38
+ Quickbooks::Model::AccessTokenResponse.new(
39
+ error_code: response.status.to_s, error_message: response.reason_phrase
40
+ )
41
+ end
42
+ end
34
43
  end
35
44
 
36
45
  end
@@ -25,6 +25,7 @@ module Quickbooks
25
25
 
26
26
  def access_token=(token)
27
27
  @oauth = token
28
+ rebuild_connection!
28
29
  end
29
30
 
30
31
  def company_id=(company_id)
@@ -36,6 +37,27 @@ module Quickbooks
36
37
  @company_id = company_id
37
38
  end
38
39
 
40
+ def oauth_v1?
41
+ @oauth.is_a? OAuth::AccessToken
42
+ end
43
+
44
+ def oauth_v2?
45
+ @oauth.is_a? OAuth2::AccessToken
46
+ end
47
+
48
+ # [OAuth2] The default Faraday connection does not have gzip or multipart support.
49
+ # We need to reset the existing connection and build a new one.
50
+ def rebuild_connection!
51
+ return unless oauth_v2?
52
+ @oauth.client.connection = nil
53
+ @oauth.client.connection.build do |builder|
54
+ builder.use :gzip
55
+ builder.request :multipart
56
+ builder.request :url_encoded
57
+ builder.adapter :net_http
58
+ end
59
+ end
60
+
39
61
  def url_for_resource(resource)
40
62
  "#{url_for_base}/#{resource}"
41
63
  end
@@ -61,7 +83,7 @@ module Quickbooks
61
83
  query ||= default_model_query
62
84
  query = "#{query} STARTPOSITION #{start_position} MAXRESULTS #{max_results}"
63
85
 
64
- "#{url_for_base}/query?query=#{URI.encode_www_form_component(query)}"
86
+ "#{url_for_base}/query?query=#{CGI.escape(query)}"
65
87
  end
66
88
 
67
89
  private
@@ -189,7 +211,8 @@ module Quickbooks
189
211
  unless headers.has_key?('Accept-Encoding')
190
212
  headers['Accept-Encoding'] = HTTP_ACCEPT_ENCODING
191
213
  end
192
- @oauth.get(url, headers)
214
+ raw_response = oauth_get(url, headers)
215
+ Quickbooks::Service::Responses::OAuthHttpResponse.wrap(raw_response)
193
216
  end
194
217
 
195
218
  def do_http_file_upload(uploadIO, url, metadata = nil)
@@ -229,21 +252,48 @@ module Quickbooks
229
252
  log_request_body(body)
230
253
  log "REQUEST HEADERS = #{headers.inspect}"
231
254
 
232
- response = case method
233
- when :get
234
- @oauth.get(url, headers)
235
- when :post
236
- @oauth.post(url, body, headers)
237
- when :upload
238
- @oauth.post_with_multipart(url, body, headers)
239
- else
240
- raise "Do not know how to perform that HTTP operation"
241
- end
255
+ raw_response = case method
256
+ when :get
257
+ oauth_get(url, headers)
258
+ when :post
259
+ oauth_post(url, body, headers)
260
+ when :upload
261
+ oauth_post_with_multipart(url, body, headers)
262
+ else
263
+ raise "Do not know how to perform that HTTP operation"
264
+ end
242
265
 
243
- if response.code.to_i == 302 && [:get, :post].include?(method)
244
- do_http(method, response['location'], body, headers)
266
+ response = Quickbooks::Service::Responses::OAuthHttpResponse.wrap(raw_response)
267
+ check_response(response, request: body)
268
+ end
269
+
270
+ def oauth_get(url, headers)
271
+ if oauth_v1?
272
+ @oauth.get(url, headers)
273
+ elsif oauth_v2?
274
+ @oauth.get(url, headers: headers, raise_errors: false)
245
275
  else
246
- check_response(response, :request => body)
276
+ raise InvalidOauthAccessTokenObject.new(@oauth)
277
+ end
278
+ end
279
+
280
+ def oauth_post(url, body, headers)
281
+ if oauth_v1?
282
+ @oauth.post(url, body, headers)
283
+ elsif oauth_v2?
284
+ @oauth.post(url, headers: headers, body: body, raise_errors: false)
285
+ else
286
+ raise InvalidOauthAccessTokenObject.new(@oauth)
287
+ end
288
+ end
289
+
290
+ def oauth_post_with_multipart(url, body, headers)
291
+ if oauth_v1?
292
+ @oauth.post_with_multipart(url, body, headers)
293
+ elsif oauth_v2?
294
+ @oauth.post_with_multipart(url, headers: headers, body: body, raise_errors: false)
295
+ else
296
+ raise InvalidOauthAccessTokenObject.new(@oauth)
247
297
  end
248
298
  end
249
299
 
@@ -258,12 +308,11 @@ module Quickbooks
258
308
  end
259
309
 
260
310
  def check_response(response, options = {})
261
- log "------ RESPONSE_HEADERS -----"
262
- if log?
263
- response.each_header {|h| log "#{h}: #{response[h]}"}
264
- end
265
311
  log "------ QUICKBOOKS-RUBY RESPONSE ------"
266
312
  log "RESPONSE CODE = #{response.code}"
313
+ if response.respond_to?(:headers)
314
+ log "RESPONSE HEADERS = #{response.headers}"
315
+ end
267
316
  log_response_body(response)
268
317
  status = response.code.to_i
269
318
  case status
@@ -293,7 +342,7 @@ module Quickbooks
293
342
  when 429
294
343
  message = parse_intuit_error[:message]
295
344
  raise Quickbooks::TooManyRequests, message
296
- when 502, 503, 504
345
+ when 503, 504
297
346
  raise Quickbooks::ServiceUnavailable
298
347
  else
299
348
  raise "HTTP Error Code: #{status}, Msg: #{response.plain_body}"
@@ -305,6 +354,8 @@ module Quickbooks
305
354
  if is_json?
306
355
  log ">>>>#{response.plain_body.inspect}"
307
356
  parse_json(response.plain_body)
357
+ elsif is_pdf?
358
+ log("BODY is a PDF : not dumping")
308
359
  else
309
360
  log(log_xml(response.plain_body))
310
361
  parse_xml(response.plain_body)
@@ -315,8 +366,26 @@ module Quickbooks
315
366
  log "REQUEST BODY:"
316
367
  if is_json?
317
368
  log(body.inspect)
369
+ elsif is_pdf?
370
+ log("BODY is a PDF : not dumping")
318
371
  else
319
- log(log_xml(body))
372
+ #multipart request for uploads arrive here in a Hash with UploadIO vals
373
+ if body.is_a?(Hash)
374
+ body.each do |k,v|
375
+ log('BODY PART:')
376
+ val_content = v.inspect
377
+ if v.is_a?(UploadIO)
378
+ if v.content_type == 'application/xml'
379
+ if v.io.is_a?(StringIO)
380
+ val_content = log_xml(v.io.string)
381
+ end
382
+ end
383
+ end
384
+ log("#{k}: #{val_content}")
385
+ end
386
+ else
387
+ log(log_xml(body))
388
+ end
320
389
  end
321
390
  end
322
391
 
@@ -335,9 +404,13 @@ module Quickbooks
335
404
  end
336
405
 
337
406
  def response_is_error?
338
- @last_response_xml.xpath("//xmlns:IntuitResponse/xmlns:Fault")[0] != nil
339
- rescue Nokogiri::XML::XPath::SyntaxError => exception
340
- true
407
+ begin
408
+ @last_response_xml.xpath("//xmlns:IntuitResponse/xmlns:Fault")[0] != nil
409
+ rescue Nokogiri::XML::XPath::SyntaxError => exception
410
+ #puts @last_response_xml.to_xml.to_s
411
+ #puts "WTF: #{exception.inspect}:#{exception.backtrace.join("\n")}"
412
+ true
413
+ end
341
414
  end
342
415
 
343
416
  def parse_intuit_error
@@ -6,10 +6,24 @@ module Quickbooks
6
6
  delete_by_query_string(invoice)
7
7
  end
8
8
 
9
+ def url_for_resource(resource)
10
+ url = super(resource)
11
+ end
12
+
13
+ def fetch_by_id(id, params = {})
14
+ url = "#{url_for_base}/invoice/#{id}?minorversion=#{Quickbooks::Model::Invoice::MINORVERSION}"
15
+ fetch_object(model, url, params)
16
+ end
17
+
18
+ def url_for_query(query = nil, start_position = 1, max_results = 20, options = {})
19
+ url = super(query, start_position, max_results, options)
20
+ "#{url}&minorversion=#{Quickbooks::Model::Invoice::MINORVERSION}"
21
+ end
22
+
9
23
  def send(invoice, email_address=nil)
10
24
  query = email_address.present? ? "?sendTo=#{email_address}" : ""
11
25
  url = "#{url_for_resource(model::REST_RESOURCE)}/#{invoice.id}/send#{query}"
12
- response = do_http_post(url,{})
26
+ response = do_http_post(url, "", {}, { 'Content-Type' => 'application/octet-stream' })
13
27
  if response.code.to_i == 200
14
28
  model.from_xml(parse_singular_entity_response(model, response.plain_body))
15
29
  else
@@ -0,0 +1,17 @@
1
+ module Quickbooks
2
+ module Service
3
+ module Responses
4
+ module Methods
5
+
6
+ def body
7
+ raise "implement me"
8
+ end
9
+
10
+ def code
11
+ raise "implement me"
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ module Quickbooks
2
+ module Service
3
+ module Responses
4
+
5
+ class OAuth1HttpResponse < OAuthHttpResponse
6
+
7
+ attr_accessor :real_response
8
+
9
+ # net/http response
10
+ def initialize(response)
11
+ @real_response = response
12
+ end
13
+
14
+ def version
15
+ 1
16
+ end
17
+
18
+ def code
19
+ @real_response.code.to_i
20
+ end
21
+
22
+ def plain_body
23
+ if @real_response.respond_to?(:plain_body)
24
+ @real_response.plain_body
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ def headers
31
+ if @real_response.respond_to?(:headers)
32
+ @real_response.headers
33
+ else
34
+ nil
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,43 @@
1
+ module Quickbooks
2
+ module Service
3
+ module Responses
4
+
5
+ class OAuth2HttpResponse
6
+ include Quickbooks::Service::Responses::Methods
7
+
8
+ attr_accessor :real_response
9
+
10
+ # response : Faraday response
11
+ def initialize(response)
12
+ @real_response = response
13
+ end
14
+
15
+ def version
16
+ 2
17
+ end
18
+
19
+ def body
20
+ @real_response.body
21
+ end
22
+
23
+ def plain_body
24
+ body
25
+ end
26
+
27
+ def code
28
+ @real_response.status.to_i
29
+ end
30
+
31
+ def headers
32
+ if @real_response.respond_to?(:headers)
33
+ @real_response.headers
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ module Quickbooks
2
+ module Service
3
+ module Responses
4
+
5
+ # This class just proxies and returns a wrapped response so that callers
6
+ # can invoke a common interface
7
+ class OAuthHttpResponse
8
+
9
+ def self.wrap(response)
10
+ if response.is_a?(OAuth2::Response)
11
+ Quickbooks::Service::Responses::OAuth2HttpResponse.new(response)
12
+ else
13
+ Quickbooks::Service::Responses::OAuth1HttpResponse.new(response)
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -25,6 +25,10 @@ module Quickbooks
25
25
  end until results.count < per_page
26
26
  end
27
27
 
28
+ def exists?(field, selector, options={})
29
+ find_by(field, selector, options).count > 0
30
+ end
31
+
28
32
  def find_by(field, selector, options={})
29
33
  if field.class == Symbol
30
34
  field = field.to_s.camelcase
@@ -9,7 +9,7 @@ module Quickbooks
9
9
  # attachable: Quickbooks::Model::Attachable meta-data details, can be null
10
10
  def upload(path_to_file, mime_type, attachable = nil)
11
11
  url = url_for_resource("upload")
12
- uploadIO = UploadIO.new(path_to_file, mime_type)
12
+ uploadIO = class_for_io.new(path_to_file, mime_type)
13
13
  response = do_http_file_upload(uploadIO, url, attachable)
14
14
  prefix = "AttachableResponse/xmlns:Attachable"
15
15
  if response.code.to_i == 200
@@ -19,6 +19,10 @@ module Quickbooks
19
19
  end
20
20
  end
21
21
 
22
+ def class_for_io
23
+ oauth.is_a?(OAuth2::AccessToken) ? Faraday::UploadIO : UploadIO
24
+ end
25
+
22
26
  def download(uploadId)
23
27
  url = url_for_resource("download/#{uploadId}")
24
28
  do_http_get(url, {}, headers)
@@ -72,3 +72,14 @@ OAuth::AccessToken.class_eval do
72
72
  request(:multipart_post, *args)
73
73
  end
74
74
  end
75
+
76
+ OAuth2::AccessToken.class_eval do
77
+
78
+ def post_with_multipart(*args)
79
+ multipart_post *args
80
+ end
81
+
82
+ def multipart_post(*args)
83
+ request(:post, *args)
84
+ end
85
+ end
@@ -1,5 +1,5 @@
1
1
  module Quickbooks
2
2
 
3
- VERSION = "0.6.7"
3
+ VERSION = "1.0.0"
4
4
 
5
5
  end
metadata CHANGED
@@ -1,49 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quickbooks-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.7
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Caughlan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-24 00:00:00.000000000 Z
11
+ date: 2019-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oauth
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.4.7
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.4.7
27
+ - !ruby/object:Gem::Dependency
28
+ name: oauth2
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: 0.4.5
33
+ version: '1.4'
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: 0.4.5
40
+ version: '1.4'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: roxml
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 3.3.1
34
- - - "<"
45
+ - - '='
35
46
  - !ruby/object:Gem::Version
36
- version: '4.1'
47
+ version: 4.0.0
37
48
  type: :runtime
38
49
  prerelease: false
39
50
  version_requirements: !ruby/object:Gem::Requirement
40
51
  requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: 3.3.1
44
- - - "<"
52
+ - - '='
45
53
  - !ruby/object:Gem::Version
46
- version: '4.1'
54
+ version: 4.0.0
47
55
  - !ruby/object:Gem::Dependency
48
56
  name: nokogiri
49
57
  requirement: !ruby/object:Gem::Requirement
@@ -143,19 +151,33 @@ dependencies:
143
151
  - !ruby/object:Gem::Version
144
152
  version: 2.14.1
145
153
  - !ruby/object:Gem::Dependency
146
- name: fakeweb
154
+ name: webmock
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: dotenv
147
169
  requirement: !ruby/object:Gem::Requirement
148
170
  requirements:
149
171
  - - '='
150
172
  - !ruby/object:Gem::Version
151
- version: 1.3.0
173
+ version: 2.2.1
152
174
  type: :development
153
175
  prerelease: false
154
176
  version_requirements: !ruby/object:Gem::Requirement
155
177
  requirements:
156
178
  - - '='
157
179
  - !ruby/object:Gem::Version
158
- version: 1.3.0
180
+ version: 2.2.1
159
181
  description: QBO V3 REST API to Quickbooks Online
160
182
  email: toolbag@gmail.com
161
183
  executables: []
@@ -163,6 +185,7 @@ extensions: []
163
185
  extra_rdoc_files: []
164
186
  files:
165
187
  - lib/quickbooks-ruby.rb
188
+ - lib/quickbooks/faraday/middleware/gzip.rb
166
189
  - lib/quickbooks/model/access_token_response.rb
167
190
  - lib/quickbooks/model/account.rb
168
191
  - lib/quickbooks/model/account_based_expense_line_detail.rb
@@ -305,6 +328,10 @@ files:
305
328
  - lib/quickbooks/service/refund_receipt.rb
306
329
  - lib/quickbooks/service/refund_receipt_change.rb
307
330
  - lib/quickbooks/service/reports.rb
331
+ - lib/quickbooks/service/responses/methods.rb
332
+ - lib/quickbooks/service/responses/oauth1_http_response.rb
333
+ - lib/quickbooks/service/responses/oauth2_http_response.rb
334
+ - lib/quickbooks/service/responses/oauth_http_response.rb
308
335
  - lib/quickbooks/service/sales_receipt.rb
309
336
  - lib/quickbooks/service/service_crud.rb
310
337
  - lib/quickbooks/service/service_crud_json.rb