qbo_api 1.8.5 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f304a44d0c7d7231a3f5ef101e1005652bc9cd801d7263b6dc70138a52229c56
4
- data.tar.gz: 2a4544537ec874555c7e1aba96f0ebf2457a1bb34af0f3da651e86b9e38fdbff
3
+ metadata.gz: 922f5a2dd0bb1020d9366c1a993686aa5febdb50e54a5b4c2a6160e572612def
4
+ data.tar.gz: '032848b350e352d8edaf376cd49b41fbaae20bccf902473d775e90c513fc0ff5'
5
5
  SHA512:
6
- metadata.gz: 4b02f2de3f7192ad90a5beb5b491be6fa05923f6c12c5b6c6f1a040f8a857013cd7201cfe3cfd50e7088a4b664976d3b87ecb9e33a567f79c4d95847e1885b8f
7
- data.tar.gz: 346a13001298cb240678ecbe151844181c7504d97263e16e6e118d9509d3962978bee1556a346d76c265b034189afbc8030c35b8c7885ac7f5c52c1902b3d415
6
+ metadata.gz: c4f17dcf8f2fe0680c34dbb8cf9c864d7d42887f291a968023e1538902a8460cc13d968f669777b53efbc21000d1db44b6e78d21ad8619514dd62c7c0375ba10
7
+ data.tar.gz: f2d7a86d02a465e6cc9ce8de0110c250c0e500a5d02b7e0cbc402e3cae37ae11832592ecef08d6c58de8735fd0081fbc8adae277efff3698416fc40da4d02274
data/.gitignore CHANGED
@@ -19,3 +19,4 @@ todo.txt
19
19
  spec/temp/spec_status.txt
20
20
  *.swp
21
21
  scrap.txt
22
+ .tool-versions
data/.travis.yml CHANGED
@@ -1,8 +1,12 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.2.2
5
- - 2.3.0
4
+ - 2.6.8
5
+ - 2.7.4
6
+ - 3.0.2
7
+
8
+ before_install:
9
+ - gem install bundler
6
10
 
7
11
  before_script:
8
12
  - cp .env.test .env
@@ -10,7 +14,6 @@ before_script:
10
14
  script:
11
15
  - bundle exec rspec spec/
12
16
 
13
-
14
17
  notifications:
15
18
  email:
16
19
  - christian@minimul.com
data/README.md CHANGED
@@ -1,20 +1,11 @@
1
1
  # QboApi
2
2
 
3
3
  Ruby client for the QuickBooks Online API version 3.
4
- - Built on top of the excellent Faraday gem.
5
4
  - JSON only support.
6
5
  - Please don't ask about XML support. [Intuit has stated](https://github.com/ruckus/quickbooks-ruby/issues/257#issuecomment-126834454) that JSON is the primary data format for the QuickBooks API (v3 and beyond). This gem will specialize in JSON only. The [`quickbooks-ruby`](https://github.com/ruckus/quickbooks-ruby) gem has fantastic support for those who favor XML.
7
6
  - Features specs built directly against a QuickBooks Online Sandbox via the VCR gem.
8
7
  - Robust error handling.
9
8
 
10
- ## Tutorials and Screencasts
11
- - <a href="http://minimul.com/introducing-a-new-ruby-quickbooks-online-client.html" target="_blank">Why qbo_api is a better choice </a> than the <a href="https://github.com/ruckus/quickbooks-ruby" target="_blank">quickbooks-ruby</a> gem.
12
- - <a href="http://minimul.com/getting-started-with-the-modern-ruby-quickbooks-online-client-qbo_api-part-1.html" target="_blank">Part 1</a>: Learn how to spin up the <a href="https://github.com/minimul/qbo_api#spin-up-an-example">example app</a>.
13
- - <a href="http://minimul.com/the-modern-ruby-quickbooks-client-part-2.html" target="_blank">Part 2</a>: <a href="https://github.com/minimul/qbo_api#running-the-specs">Running the specs</a> to aid you in understanding a QuickBooks API transaction.
14
- - <a href="http://minimul.com/the-modern-ruby-quickbooks-client-contributing.html" target="_blank">Part 3</a>: <a href="https://github.com/minimul/qbo_api#creating-new-specs-or-modifying-existing-spec-that-have-been-recorded-using-the-vcr-gem">Contributing to the gem</a>.
15
- ### Important Note: The videos are out of date.
16
- If you signed up for a Intuit developer account after July 17th, 2017 then you will have to
17
- follow <a href='#OAuth2-example'>OAuth2: Spin up an example</a>
18
9
  ## The Book
19
10
 
20
11
  <a href="https://leanpub.com/minimul-qbo-guide-vol-1" target="_blank">
@@ -22,7 +13,7 @@ follow <a href='#OAuth2-example'>OAuth2: Spin up an example</a>
22
13
  </a>
23
14
 
24
15
 
25
- ## Ruby >= 2.2.2 required
16
+ ## Ruby >= 2.6 required
26
17
 
27
18
  ## Installation
28
19
 
@@ -43,41 +34,22 @@ Or install it yourself as:
43
34
  ## Usage
44
35
 
45
36
  ### Initialize
46
- #### OAuth
47
- ```ruby
48
- q = account.qbo_account # or wherever you are storing the OAuth creds
49
- qbo_api = QboApi.new(token: q.token,
50
- token_secret: q.secret,
51
- realm_id: q.companyid,
52
- consumer_key: '*****',
53
- consumer_secret: '********')
54
- ```
55
- #### OAuth2
56
37
  ```ruby
57
38
  qbo_api = QboApi.new(access_token: 'REWR342532asdfae!$4asdfa', realm_id: 32095430444)
39
+ - qbo_api.get :customer, 1
58
40
  ```
59
41
 
60
- ### Super fast way to use QboApi no matter your current tech stack as long as Ruby > 2.2.2 is installed
42
+ ### Super fast way to use QboApi as long as Ruby >= 2.5 is installed
61
43
  ```
62
44
  - cd ~/<local dir>
63
45
  - git clone git@github.com:minimul/qbo_api.git && cd qbo_api
64
46
  - bundle
65
47
  - bin/console
66
48
  - QboApi.production = true
67
- - # OAuth 1
68
- - qboapi = QboApi.new(token: "qyprd2uvCOdRq8xzoSSiiiiii",
69
- token_secret:"g8wcyQEtwxxxxxxm",
70
- realm_id: "12314xxxxxx7",
71
- consumer_key: "qyprdwzcxxxxxxbIWsIMIy9PYI",
72
- consumer_secret: "CyDN4wpxxxxxxxPMv7hDhmh4")
73
- - # OAuth 2
74
- - qboapi = QboApi.new(access_token: "qyprd2uvCOdRq8xzoSSiiiiii", realm_id: "12314xxxxxx7")
75
- - qboapi.get :customer, 1
49
+ - qbo_api = QboApi.new(access_token: "qyprd2uvCOdRq8xzoSSiiiiii", realm_id: "12314xxxxxx7")
50
+ - qbo_api.get :customer, 1
76
51
  ```
77
52
 
78
- ### TLS v1.2
79
- Intuit will be [requiring](https://developer.intuit.com/hub/blog/2017/08/03/upgrading-your-apps-to-support-tls-1-2) API client connections to be negotiated over TLS1.2 by December 31st, 2017. Using the default HTTP client (Net::HTTP) with Faraday this is the case with QboApi, however, if you are using another HTTP client you may need to directly set the TLS version negotiation manually.
80
-
81
53
  ### DateTime serialization
82
54
  Some QBO entities have attributes of type DateTime (e.g., Time Activities with StartTime and EndTime). All DateTimes passed to the QBO API must be serialized in ISO 8601 format.
83
55
  If ActiveSupport is loaded, you can achieve proper serialization with the following configuration:
@@ -119,7 +91,6 @@ QboApi.minor_version = 8
119
91
  # Works with .get, .create, .update, .query methods
120
92
  ```
121
93
 
122
-
123
94
  ### Create
124
95
  ```ruby
125
96
  invoice = {
@@ -191,6 +162,40 @@ QboApi.minor_version = 8
191
162
  p response.size # => 28
192
163
  ```
193
164
 
165
+ ### Import/retrieve all
166
+ *Note: There is some overlap with the `all` and the `get` methods. The `get` method is limited to 1000 results where the `all` method will return all the results no matter the number.*
167
+ ```ruby
168
+ # retrieves all active customers
169
+ qbo_api.all(:customers).each do |c|
170
+ p "#{c['Id']} #{c['DisplayName']}"
171
+ end
172
+
173
+ # retrieves all active or inactive employees
174
+ qbo_api.all(:employees, inactive: true).each do |e|
175
+ p "#{e['Id']} #{e['DisplayName']}"
176
+ end
177
+
178
+ # retrieves all vendors by groups of 5
179
+ qbo_api.all(:vendor, max: 5).each do |v|
180
+ p v['DisplayName']
181
+ end
182
+
183
+ # retrieves all customers by groups of 2 using a custom select query
184
+ where = "WHERE Id IN ('5', '6', '7', '8', '9', '10')"
185
+ qbo_api.all(:customer, max: 2, select: "SELECT * FROM Customer #{where}").each do |c|
186
+ p c['DisplayName']
187
+ end
188
+ ```
189
+
190
+ #### Note: .all() returns a Ruby Enumerator
191
+
192
+ ```
193
+ api.all(:clients).take(50).each { |c| p c["Id"] }
194
+ api.all(:clients).count
195
+ api.all(:clients).first
196
+ api.all(:clients).to_a
197
+ ```
198
+
194
199
  ### Search with irregular characters
195
200
  ```ruby
196
201
  # Use the .esc() method
@@ -264,7 +269,7 @@ Be aware that any errors will not raise a `QboApi::Error`, but will be returned
264
269
  }
265
270
  ]
266
271
  }
267
- response = api.batch(payload)
272
+ response = qbo_api.batch(payload)
268
273
  expect(response['BatchItemResponse'].size).to eq 2
269
274
  expect(batch_response.detect{ |b| b["bId"] == "bid1" }["Vendor"]["DisplayName"]).to eq "Smith Family Store"
270
275
  ```
@@ -273,7 +278,7 @@ Be aware that any errors will not raise a `QboApi::Error`, but will be returned
273
278
 
274
279
  ```ruby
275
280
  params = { start_date: '2015-01-01', end_date: '2015-07-31', customer: 1, summarize_column_by: 'Customers' }
276
- response = api.reports(name: 'ProfitAndLoss', params: params)
281
+ response = qbo_api.reports(name: 'ProfitAndLoss', params: params)
277
282
  p response["Header"]["ReportName"]) #=> 'ProfitAndLoss'
278
283
  ```
279
284
 
@@ -310,31 +315,6 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
310
315
  end
311
316
  ```
312
317
 
313
- ### Import/retrieve all
314
- *Note: There is some overlap with the `all` and the `get` methods. The `get` method is limited to 1000 results where the `all` method will return all the results no matter the number.*
315
- ```ruby
316
- # retrieves all active customers
317
- qbo_api.all(:customers).each do |c|
318
- p "#{c['Id']} #{c['DisplayName']}"
319
- end
320
-
321
- # retrieves all active or inactive employees
322
- qbo_api.all(:employees, inactive: true).each do |e|
323
- p "#{e['Id']} #{e['DisplayName']}"
324
- end
325
-
326
- # retrieves all vendors by groups of 5
327
- qbo_api.all(:vendor, max: 5).each do |v|
328
- p v['DisplayName']
329
- end
330
-
331
- # retrieves all customers by groups of 2 using a custom select query
332
- where = "WHERE Id IN ('5', '6', '7', '8', '9', '10')"
333
- qbo_api.all(:customer, max: 2, select: "SELECT * FROM Customer #{where}").each do |c|
334
- p c['DisplayName']
335
- end
336
- ```
337
-
338
318
  ### What kind of QuickBooks entity?
339
319
  ```ruby
340
320
  p qbo_api.is_transaction_entity?(:invoice) # => true
@@ -343,9 +323,8 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
343
323
  p qbo_api.is_transaction_entity?(:customer) # => false
344
324
  p qbo_api.is_name_list_entity?(:vendors) # => true
345
325
  ```
346
- ## <a name='OAuth2-example'>OAuth2: Spin up an example</a>
347
- ### If you signed up for a Intuit developer account after July 17th, 2017 follow this example
348
- - <a href="http://minimul.com/access-the-quickbooks-online-api-with-oauth2.html" target="_blank">Check out this article on spinning up the OAuth2 example</a>.
326
+ ## <a name='OAuth2-example'>Spin up an example</a>
327
+ - <a href="http://minimul.com/access-the-quickbooks-online-api-with-oauth2.html" target="_blank">Check out this article on spinning up the example</a>.
349
328
  - `git clone git://github.com/minimul/qbo_api && cd qbo_api`
350
329
  - `bundle`
351
330
  - Create a `.env` file
@@ -360,7 +339,7 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
360
339
  - Create a new Company ([from the manage sandboxes page](https://developer.intuit.com/v2/ui#/sandbox))
361
340
  Don't use it for anything else besides testing this app.
362
341
  -. Copy the 'Company ID' to your .env as QBO_API_COMPANY_ID
363
- - Start up the example OAuth2 app
342
+ - Start up the example app
364
343
  - `ruby example/oauth2.rb`
365
344
  - Go to `http://localhost:9393/oauth2`
366
345
  - Use the `Connect to QuickBooks` button to connect to your QuickBooks sandbox, which you receive when signing up at [https://developer.intuit.com](https://developer.intuit.com).
@@ -370,35 +349,13 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
370
349
  - Checkout [`example/oauth2.rb`](https://github.com/minimul/qbo_api/blob/master/example/oauth2.rb)
371
350
  to see what is going on under the hood.
372
351
 
373
- ## OAuth1: Spin up an example
374
- ### OLD LEGACY - SEE OAUTH2 EXAMPLE ABOVE
375
- - <a href="http://minimul.com/getting-started-with-the-modern-ruby-quickbooks-online-client-qbo_api-part-1.html" target="_blank">Check out this tutorial and screencast on spinning up an example</a>.
376
- - `git clone git://github.com/minimul/qbo_api && cd qbo_api`
377
- - `bundle`
378
- - Create a `.env` file
379
- - `cp .env.example_app.oauth1 .env`
380
- - If needed create an account at [https://developer.intuit.com](https://developer.intuit.com)
381
- - Click `Get started coding`
382
- - Create an app with both the `Accounting` & `Payments` selected.
383
- - Go to the `Development` tab and copy and paste the consumer key and secret into the `.env` file
384
- as QBO_API_CONSUMER_KEY and QBO_API_CONSUMER_SECRET respectively.
385
- - Start up the example app
386
- - `ruby example/oauth.rb`
387
- - Go to `http://localhost:9393`
388
- - Use the `Connect to QuickBooks` button to connect to your QuickBooks sandbox, which you receive when signing up at [https://developer.intuit.com](https://developer.intuit.com).
389
- - After successfully connecting to your sandbox run:
390
- - `http://localhost:9393/customer/5`
391
- - You should see "Dukes Basketball Camp" displayed
392
- - Checkout [`example/oauth.rb`](https://github.com/minimul/qbo_api/blob/master/example/oauth.rb)
393
- to see what is going on under the hood.
394
-
395
352
  ## Webhooks
396
353
  - <a href="http://minimul.com/getting-started-with-quickbooks-online-webhooks.html" target="_blank">Check out this tutorial and screencast on handling a webhook request</a>. Also checkout [`example/app.rb`](https://github.com/minimul/qbo_api/blob/master/example/app.rb) for the request handling code.
397
354
 
398
355
  See https://www.twilio.com/blog/2015/09/6-awesome-reasons-to-use-ngrok-when-testing-webhooks.html
399
356
  for how to install ngrok and what it is.
400
357
 
401
- - With either the oauth1 or oauth2 examples running, run:
358
+ - With the example app running, run:
402
359
  `ngrok http 9393 -subdomain=somereasonablyuniquenamehere`
403
360
 
404
361
  - Go to the [`Development` tab](https://developer.intuit.com/v2/ui#/app/dashboard)
@@ -408,7 +365,7 @@ for how to install ngrok and what it is.
408
365
  - After saving the webhook, click 'show token'.
409
366
  Add the token to your .env as QBO_API_VERIFIER_TOKEN
410
367
 
411
- - In another tab, create a customer via the (OAuth2) API:
368
+ - In another tab, create a customer via the API:
412
369
  `bundle exec ruby -rqbo_api -rdotenv -e 'Dotenv.load; p QboApi.new(access_token: ENV.fetch("QBO_API_OAUTH2_ACCESS_TOKEN"), realm_id: ENV.fetch("QBO_API_COMPANY_ID")).create(:customer, payload: { DisplayName: "TestCustomer" })'`
413
370
  (You'll also need to have added the QBO_API_COMPANY_ID and QBO_API_OAUTH2_ACCESS_TOKEN to your .env)
414
371
 
@@ -421,6 +378,28 @@ for how to install ngrok and what it is.
421
378
  "POST /webhooks HTTP/1.1" 200 - 0.0013
422
379
  ```
423
380
 
381
+ ### Just For Hackers
382
+
383
+ - Using the build_connection method
384
+ ```
385
+ connection = build_connection('https://oauth.platform.intuit.com', headers: { 'Accept' => 'application/json' }) do |conn|
386
+ conn.basic_auth(client_id, client_secret)
387
+ conn.request :url_encoded # application/x-www-form-urlencoded
388
+ conn.use FaradayMiddleware::ParseJson, parser_options: { symbolize_names: true }
389
+ conn.use Faraday::Response::RaiseError
390
+ end
391
+
392
+ raw_response = connection.post do |req|
393
+ req.body = { grant_type: :refresh_token, refresh_token: current_refresh_token }
394
+ req.url '/oauth2/v1/tokens/bearer'
395
+ end
396
+ ```
397
+ - Once your .env file is completely filled out you can use the console to play around in your sandbox
398
+ ```
399
+ bin/console test
400
+ >> @qbo_api.get :customer, 1
401
+ ```
402
+
424
403
  ## Contributing
425
404
 
426
405
  Bug reports and pull requests are welcome on GitHub at https://github.com/minimul/qbo_api.
@@ -438,11 +417,6 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/minimu
438
417
  - All specs that require interaction with the API must be recorded against your personal QuickBooks sandbox. More coming on how to create or modifying existing specs against your sandbox.
439
418
  - <a href="http://minimul.com/the-modern-ruby-quickbooks-client-contributing.html" target="_blank">Check out this tutorial and screencast on contributing to qbo_api</a>.
440
419
 
441
- #### Protip: Once your .env file is completely filled out you can use the console to play around in your sandbox
442
- ```
443
- bin/console test
444
- >> @qbo_api.get :customer, 1
445
- ```
446
420
 
447
421
  ## License
448
422
 
data/example/base.rb CHANGED
@@ -25,6 +25,7 @@ BASE_APP_CONFIG = proc do
25
25
  configure do
26
26
  $VERBOSE = nil # silence redefined constant warning
27
27
  register Sinatra::Reloader
28
+ set :public_folder => "#{__dir__}/public"
28
29
  end
29
30
 
30
31
  set :sessions, :true
data/example/oauth2.rb CHANGED
@@ -24,16 +24,29 @@ class OAuth2App < Sinatra::Base
24
24
  Rack::OAuth2::Client.new(
25
25
  identifier: CLIENT_ID,
26
26
  secret: CLIENT_SECRET,
27
- redirect_uri: "http://localhost:#{PORT}/oauth2-redirect",
27
+ redirect_uri: redirect_url,
28
28
  authorization_endpoint: "https://appcenter.intuit.com/connect/oauth2",
29
29
  token_endpoint: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
30
30
  )
31
31
  end
32
+
33
+ def authorize_url(state:)
34
+ oauth2_client.authorization_uri(
35
+ client_id: CLIENT_ID,
36
+ scope: "com.intuit.quickbooks.accounting",
37
+ redirect_uri: redirect_url,
38
+ response_type: "code",
39
+ state: state
40
+ )
41
+ end
42
+
43
+ def redirect_url
44
+ "http://localhost:#{PORT}/oauth2-redirect"
45
+ end
32
46
  end
33
47
 
34
48
  get '/oauth2' do
35
49
  session[:state] = SecureRandom.uuid
36
- @client = oauth2_client
37
50
  erb :oauth2
38
51
  end
39
52
 
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" viewBox="0 0 775.39 132"><defs><clipPath id="a"><path d="M0 0h775.39v132H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M775.395 124c0 4.4-3.6 8-8 8H8c-4.4 0-8-3.6-8-8V8c0-4.4 3.6-8 8-8h759.395c4.4 0 8 3.6 8 8v116z" fill="#328538"/><path d="M775.395 124c0 4.4-3.6 8-8 8H8c-4.4 0-8-3.6-8-8V8c0-4.4 3.6-8 8-8h759.395c4.4 0 8 3.6 8 8v116z" fill="none" vector-effect="non-scaling-stroke" stroke-width="4" stroke="#328538" stroke-miterlimit="10"/><path d="M178.168 56.127c-1.033-1.4-2.38-2.424-4.039-3.07-1.66-.645-3.284-.968-4.869-.968-2.028 0-3.872.368-5.532 1.106a13.005 13.005 0 0 0-4.287 3.042c-1.198 1.292-2.121 2.804-2.766 4.538-.646 1.733-.968 3.614-.968 5.642 0 2.14.313 4.093.941 5.864.627 1.771 1.521 3.291 2.683 4.563a12.012 12.012 0 0 0 4.176 2.96c1.622.703 3.448 1.052 5.477 1.052 2.103 0 3.964-.415 5.588-1.244 1.623-.831 2.932-1.928 3.928-3.292l5.587 3.926a17.878 17.878 0 0 1-6.362 5.063c-2.509 1.198-5.441 1.799-8.796 1.799-3.062 0-5.873-.508-8.437-1.523-2.564-1.014-4.767-2.433-6.611-4.258-1.844-1.826-3.282-4.002-4.314-6.53-1.034-2.524-1.55-5.318-1.55-8.38 0-3.134.544-5.965 1.632-8.492 1.088-2.527 2.582-4.674 4.482-6.445 1.898-1.77 4.14-3.135 6.721-4.094 2.581-.958 5.384-1.437 8.408-1.437 1.255 0 2.564.119 3.928.359 1.365.24 2.675.608 3.928 1.105a19.141 19.141 0 0 1 3.541 1.855 11.42 11.42 0 0 1 2.82 2.654l-5.309 4.205m13.056 16.597c0 1.032.156 2.065.471 3.097a8.468 8.468 0 0 0 1.41 2.767 7.381 7.381 0 0 0 2.378 1.991c.96.517 2.102.774 3.43.774 1.328 0 2.471-.257 3.43-.774a7.42 7.42 0 0 0 2.38-1.991 8.566 8.566 0 0 0 1.41-2.767 10.66 10.66 0 0 0 .47-3.097c0-1.033-.158-2.056-.47-3.071a8.637 8.637 0 0 0-1.41-2.738 7.1 7.1 0 0 0-2.38-1.963c-.959-.5-2.102-.748-3.43-.748-1.328 0-2.47.248-3.43.748a7.063 7.063 0 0 0-2.378 1.963 8.536 8.536 0 0 0-1.41 2.738 10.303 10.303 0 0 0-.471 3.071zm-6.749 0c0-2.103.377-4.011 1.134-5.726.755-1.714 1.779-3.181 3.07-4.398 1.29-1.217 2.821-2.157 4.592-2.821 1.77-.664 3.65-.996 5.642-.996 1.992 0 3.872.332 5.643.996 1.771.664 3.3 1.604 4.592 2.821 1.291 1.217 2.313 2.684 3.071 4.398.754 1.715 1.133 3.623 1.133 5.726 0 2.103-.379 4.02-1.133 5.753-.758 1.733-1.78 3.218-3.071 4.454-1.292 1.236-2.821 2.203-4.592 2.903-1.771.7-3.651 1.052-5.643 1.052s-3.872-.352-5.642-1.052c-1.771-.7-3.302-1.667-4.592-2.903-1.291-1.236-2.315-2.721-3.07-4.454-.757-1.733-1.134-3.65-1.134-5.753m33.91-13.167h6.307v4.26h.111c.589-1.328 1.612-2.498 3.069-3.513 1.457-1.015 3.181-1.521 5.173-1.521 1.734 0 3.218.303 4.454.912 1.234.609 2.249 1.412 3.042 2.408a9.715 9.715 0 0 1 1.742 3.429 14.43 14.43 0 0 1 .554 3.983v16.597h-6.638V71.396c0-.775-.056-1.586-.167-2.435a6.59 6.59 0 0 0-.719-2.294 4.775 4.775 0 0 0-1.521-1.688c-.647-.443-1.504-.664-2.572-.664-1.071 0-1.992.212-2.767.637a5.872 5.872 0 0 0-1.908 1.631 7.188 7.188 0 0 0-1.134 2.296 9.124 9.124 0 0 0-.387 2.628v14.605h-6.639V59.557m30.814 0h6.306v4.26h.111c.588-1.328 1.612-2.498 3.069-3.513 1.458-1.015 3.182-1.521 5.174-1.521 1.732 0 3.217.303 4.452.912 1.236.609 2.25 1.412 3.044 2.408a9.713 9.713 0 0 1 1.741 3.429c.369 1.292.553 2.619.553 3.983v16.597h-6.638V71.396c0-.775-.055-1.586-.166-2.435a6.569 6.569 0 0 0-.718-2.294 4.788 4.788 0 0 0-1.522-1.688c-.646-.443-1.504-.664-2.572-.664-1.07 0-1.992.212-2.766.637a5.851 5.851 0 0 0-1.908 1.631 7.169 7.169 0 0 0-1.135 2.296 9.124 9.124 0 0 0-.387 2.628v14.605h-6.638V59.557m49.51 10.622c0-.848-.12-1.66-.358-2.435a5.614 5.614 0 0 0-1.135-2.047c-.516-.588-1.171-1.06-1.964-1.411-.793-.349-1.724-.525-2.793-.525-1.992 0-3.679.6-5.063 1.799-1.383 1.198-2.148 2.737-2.295 4.619h13.608zm6.639 2.988v.885c0 .294-.019.589-.055.884h-20.192c.072.96.322 1.836.747 2.628a6.69 6.69 0 0 0 1.687 2.048 8.437 8.437 0 0 0 2.378 1.355 7.86 7.86 0 0 0 2.767.497c1.659 0 3.06-.304 4.204-.912a7.856 7.856 0 0 0 2.821-2.518l4.426 3.541c-2.619 3.541-6.418 5.311-11.396 5.311-2.066 0-3.964-.323-5.698-.969-1.734-.644-3.236-1.557-4.509-2.738-1.272-1.179-2.268-2.627-2.987-4.342-.72-1.716-1.078-3.661-1.078-5.837 0-2.139.358-4.084 1.078-5.836.719-1.752 1.706-3.245 2.96-4.481 1.254-1.235 2.738-2.194 4.452-2.878 1.716-.681 3.57-1.022 5.56-1.022 1.844 0 3.55.303 5.118.912a11.122 11.122 0 0 1 4.066 2.71c1.143 1.2 2.038 2.693 2.683 4.483.645 1.788.968 3.881.968 6.279m23.179-6.252c-.518-.738-1.291-1.355-2.324-1.852-1.032-.5-2.084-.748-3.152-.748-1.218 0-2.288.248-3.21.748a6.992 6.992 0 0 0-2.296 1.962 8.446 8.446 0 0 0-1.354 2.739 10.907 10.907 0 0 0-.443 3.07c0 1.033.156 2.057.471 3.07a8.538 8.538 0 0 0 1.409 2.739 7.183 7.183 0 0 0 2.352 1.964c.94.498 2.037.746 3.292.746a8.386 8.386 0 0 0 3.097-.608c1.032-.405 1.862-.996 2.49-1.77l4.149 4.204c-1.107 1.181-2.517 2.094-4.232 2.738-1.715.646-3.568.969-5.56.969-1.956 0-3.808-.314-5.56-.941-1.752-.626-3.283-1.549-4.592-2.766-1.309-1.218-2.341-2.691-3.097-4.426-.756-1.733-1.134-3.707-1.134-5.919 0-2.138.378-4.074 1.134-5.809.756-1.733 1.778-3.208 3.07-4.425a13.728 13.728 0 0 1 4.508-2.821c1.715-.664 3.55-.996 5.506-.996 1.954 0 3.844.369 5.67 1.106 1.826.738 3.272 1.752 4.342 3.043l-4.536 3.983m6.417-2.047v-5.311h4.647v-7.689h6.528v7.689h6.638v5.311h-6.638v12.336c0 1.181.212 2.157.636 2.932.424.774 1.373 1.161 2.849 1.161.443 0 .921-.045 1.439-.137a5.718 5.718 0 0 0 1.382-.415l.222 5.2c-.591.222-1.291.395-2.103.526-.811.129-1.585.194-2.323.194-1.77 0-3.209-.25-4.314-.748-1.107-.497-1.984-1.18-2.628-2.047-.646-.865-1.088-1.862-1.328-2.986a17.355 17.355 0 0 1-.36-3.624V64.868h-4.647m29.872 0v-5.311h4.648v-7.689h6.527v7.689h6.638v5.311h-6.638v12.336c0 1.181.212 2.157.637 2.932.423.774 1.373 1.161 2.849 1.161.443 0 .92-.045 1.438-.137a5.704 5.704 0 0 0 1.382-.415l.222 5.2c-.591.222-1.291.395-2.102.526-.812.129-1.586.194-2.324.194-1.77 0-3.208-.25-4.314-.748-1.107-.497-1.983-1.18-2.628-2.047-.646-.865-1.088-1.862-1.328-2.986a17.356 17.356 0 0 1-.359-3.624V64.868h-4.648m26.444 7.856c0 1.032.156 2.065.469 3.097a8.512 8.512 0 0 0 1.412 2.767 7.381 7.381 0 0 0 2.378 1.991c.958.517 2.102.774 3.43.774 1.328 0 2.471-.257 3.43-.774a7.392 7.392 0 0 0 2.378-1.991 8.531 8.531 0 0 0 1.412-2.767 10.66 10.66 0 0 0 .47-3.097c0-1.033-.158-2.056-.47-3.071a8.601 8.601 0 0 0-1.412-2.738 7.072 7.072 0 0 0-2.378-1.963c-.959-.5-2.102-.748-3.43-.748-1.328 0-2.472.248-3.43.748a7.063 7.063 0 0 0-2.378 1.963 8.58 8.58 0 0 0-1.412 2.738 10.365 10.365 0 0 0-.469 3.071zm-6.749 0c0-2.103.377-4.011 1.133-5.726.756-1.714 1.779-3.181 3.071-4.398 1.29-1.217 2.821-2.157 4.592-2.821 1.77-.664 3.65-.996 5.642-.996 1.992 0 3.872.332 5.643.996 1.771.664 3.3 1.604 4.592 2.821 1.291 1.217 2.313 2.684 3.071 4.398.754 1.715 1.133 3.623 1.133 5.726 0 2.103-.379 4.02-1.133 5.753-.758 1.733-1.78 3.218-3.071 4.454-1.292 1.236-2.821 2.203-4.592 2.903-1.771.7-3.651 1.052-5.643 1.052s-3.872-.352-5.642-1.052c-1.771-.7-3.302-1.667-4.592-2.903-1.292-1.236-2.315-2.721-3.071-4.454-.756-1.733-1.133-3.65-1.133-5.753" fill="#FFF"/><path d="M449.899 52.2c-1.882 0-3.643.351-5.283 1.051-1.641.701-3.053 1.658-4.233 2.876-1.18 1.217-2.111 2.674-2.794 4.371-.682 1.697-1.024 3.541-1.024 5.531 0 2.103.323 4.011.968 5.727.646 1.715 1.551 3.18 2.712 4.397 1.162 1.217 2.554 2.167 4.176 2.85 1.623.682 3.412 1.022 5.367 1.022 1.917 0 3.696-.34 5.339-1.022 1.64-.683 3.05-1.633 4.232-2.85 1.178-1.217 2.101-2.682 2.765-4.397.664-1.716.996-3.624.996-5.727 0-1.99-.313-3.834-.94-5.531-.628-1.697-1.521-3.154-2.683-4.371-1.162-1.218-2.554-2.175-4.177-2.876-1.623-.7-3.429-1.051-5.421-1.051zm23.51 33.912h-23.621c-3.136 0-5.984-.452-8.548-1.356-2.563-.904-4.757-2.213-6.583-3.928-1.825-1.715-3.236-3.818-4.232-6.307-.996-2.489-1.493-5.318-1.493-8.492 0-2.986.525-5.707 1.576-8.16 1.052-2.452 2.517-4.564 4.399-6.333 1.88-1.771 4.101-3.144 6.665-4.123 2.564-.976 5.339-1.464 8.327-1.464 2.986 0 5.753.488 8.298 1.464 2.544.979 4.748 2.352 6.611 4.123 1.861 1.769 3.309 3.881 4.341 6.333 1.034 2.453 1.551 5.174 1.551 8.16 0 1.771-.204 3.393-.609 4.868-.407 1.476-.932 2.813-1.578 4.011a15.475 15.475 0 0 1-2.212 3.155 16.224 16.224 0 0 1-2.573 2.294v.111h9.681v5.644m27.439 0h-6.307v-4.261h-.11c-.591 1.328-1.614 2.498-3.07 3.513-1.457 1.015-3.181 1.522-5.173 1.522-1.733 0-3.217-.305-4.453-.913-1.236-.609-2.25-1.41-3.042-2.408a9.677 9.677 0 0 1-1.744-3.429 14.461 14.461 0 0 1-.553-3.983V59.557h6.639v14.716c0 .773.056 1.586.166 2.434.111.849.351 1.613.719 2.296a4.767 4.767 0 0 0 1.521 1.686c.646.443 1.503.664 2.572.664 1.034 0 1.946-.212 2.74-.636.792-.424 1.438-.968 1.936-1.632a7.23 7.23 0 0 0 1.134-2.296 9.19 9.19 0 0 0 .386-2.626V59.557h6.639v26.555m6.693-26.555h6.639v26.555h-6.639V59.557zm-.941-9.017c0-1.069.397-2 1.189-2.795.794-.792 1.799-1.188 3.016-1.188 1.218 0 2.24.379 3.07 1.134.83.757 1.245 1.705 1.245 2.849 0 1.143-.415 2.093-1.245 2.849-.83.756-1.852 1.133-3.07 1.133-1.217 0-2.222-.395-3.016-1.188-.792-.793-1.189-1.724-1.189-2.794zm32.419 16.375c-.518-.738-1.291-1.355-2.324-1.852-1.032-.5-2.084-.748-3.154-.748-1.217 0-2.286.248-3.208.748a6.962 6.962 0 0 0-2.296 1.962 8.47 8.47 0 0 0-1.356 2.739 10.978 10.978 0 0 0-.442 3.07c0 1.033.157 2.057.47 3.07a8.583 8.583 0 0 0 1.411 2.739 7.183 7.183 0 0 0 2.352 1.964c.94.498 2.036.746 3.291.746a8.395 8.395 0 0 0 3.098-.608c1.032-.405 1.862-.996 2.49-1.77l4.149 4.204c-1.107 1.181-2.517 2.094-4.232 2.738-1.716.646-3.568.969-5.56.969-1.956 0-3.809-.314-5.56-.941-1.752-.626-3.283-1.549-4.592-2.766-1.309-1.218-2.343-2.691-3.097-4.426-.758-1.733-1.135-3.707-1.135-5.919 0-2.138.377-4.074 1.135-5.809.754-1.733 1.778-3.208 3.07-4.425a13.718 13.718 0 0 1 4.508-2.821c1.715-.664 3.55-.996 5.504-.996 1.955 0 3.846.369 5.671 1.106 1.825.738 3.272 1.752 4.343 3.043l-4.536 3.983m7.578-22.627h6.639v26.444h.165l10.07-11.175h8.518l-11.506 12.006 12.225 14.549h-8.795l-10.512-13.609h-.165v13.609h-6.639V44.288zm35.847 35.958h6.252c.885 0 1.843-.063 2.876-.193a9.396 9.396 0 0 0 2.849-.802 5.593 5.593 0 0 0 2.158-1.77c.572-.774.857-1.808.857-3.097 0-2.065-.701-3.504-2.101-4.316-1.403-.811-3.523-1.217-6.363-1.217h-6.528v11.395zm0-17.37h6.196c2.324 0 4.093-.46 5.311-1.383 1.217-.921 1.826-2.23 1.826-3.928 0-1.77-.628-3.022-1.881-3.761-1.255-.739-3.209-1.107-5.864-1.107h-5.588v10.179zm-6.969-15.932h15.268c1.474 0 2.932.175 4.37.525 1.439.351 2.719.923 3.844 1.715 1.126.793 2.038 1.817 2.739 3.071.7 1.253 1.052 2.765 1.052 4.536 0 2.213-.628 4.038-1.881 5.477-1.255 1.439-2.896 2.471-4.924 3.097v.111c2.47.332 4.5 1.292 6.085 2.877 1.585 1.587 2.379 3.707 2.379 6.363 0 2.139-.424 3.936-1.272 5.393-.85 1.456-1.964 2.627-3.348 3.512-1.383.886-2.968 1.522-4.756 1.91a25.792 25.792 0 0 1-5.45.581h-14.106V46.944m39.277 25.78c0 1.032.156 2.065.469 3.097a8.49 8.49 0 0 0 1.411 2.767 7.395 7.395 0 0 0 2.379 1.991c.958.517 2.102.774 3.43.774 1.327 0 2.47-.257 3.43-.774a7.413 7.413 0 0 0 2.378-1.991 8.51 8.51 0 0 0 1.411-2.767c.313-1.032.471-2.065.471-3.097 0-1.033-.158-2.056-.471-3.071a8.578 8.578 0 0 0-1.411-2.738 7.092 7.092 0 0 0-2.378-1.963c-.96-.5-2.103-.748-3.43-.748-1.328 0-2.472.248-3.43.748a7.076 7.076 0 0 0-2.379 1.963 8.558 8.558 0 0 0-1.411 2.738 10.365 10.365 0 0 0-.469 3.071zm-6.749 0c0-2.103.377-4.011 1.133-5.726.756-1.714 1.779-3.181 3.071-4.398 1.29-1.217 2.821-2.157 4.59-2.821 1.771-.664 3.652-.996 5.644-.996 1.991 0 3.872.332 5.643.996 1.769.664 3.3 1.604 4.591 2.821 1.29 1.217 2.314 2.684 3.07 4.398.756 1.715 1.135 3.623 1.135 5.726 0 2.103-.379 4.02-1.135 5.753-.756 1.733-1.78 3.218-3.07 4.454-1.291 1.236-2.822 2.203-4.591 2.903-1.771.7-3.652 1.052-5.643 1.052-1.992 0-3.873-.352-5.644-1.052-1.769-.7-3.3-1.667-4.59-2.903-1.292-1.236-2.315-2.721-3.071-4.454-.756-1.733-1.133-3.65-1.133-5.753m39.11 0c0 1.032.156 2.065.471 3.097a8.47 8.47 0 0 0 1.411 2.767 7.367 7.367 0 0 0 2.377 1.991c.96.517 2.103.774 3.431.774 1.328 0 2.47-.257 3.429-.774a7.41 7.41 0 0 0 2.38-1.991 8.588 8.588 0 0 0 1.411-2.767c.312-1.032.469-2.065.469-3.097 0-1.033-.157-2.056-.469-3.071a8.66 8.66 0 0 0-1.411-2.738 7.09 7.09 0 0 0-2.38-1.963c-.959-.5-2.101-.748-3.429-.748-1.328 0-2.471.248-3.431.748a7.05 7.05 0 0 0-2.377 1.963 8.538 8.538 0 0 0-1.411 2.738 10.303 10.303 0 0 0-.471 3.071zm-6.749 0c0-2.103.377-4.011 1.135-5.726.754-1.714 1.778-3.181 3.069-4.398 1.291-1.217 2.821-2.157 4.592-2.821 1.771-.664 3.651-.996 5.643-.996s3.872.332 5.642.996c1.771.664 3.3 1.604 4.592 2.821 1.291 1.217 2.314 2.684 3.071 4.398.755 1.715 1.133 3.623 1.133 5.726 0 2.103-.378 4.02-1.133 5.753-.757 1.733-1.78 3.218-3.071 4.454-1.292 1.236-2.821 2.203-4.592 2.903-1.77.7-3.65 1.052-5.642 1.052-1.992 0-3.872-.352-5.643-1.052-1.771-.7-3.301-1.667-4.592-2.903-1.291-1.236-2.315-2.721-3.069-4.454-.758-1.733-1.135-3.65-1.135-5.753m34.021-28.436h6.638v26.444h.166l10.068-11.175h8.52l-11.506 12.006 12.226 14.549H691.7l-10.511-13.609h-.166v13.609h-6.638V44.288z" fill="#F4F5F5"/><path d="M717.149 66.639c-.589-.775-1.402-1.448-2.433-2.02a6.867 6.867 0 0 0-3.376-.858c-1.069 0-2.047.222-2.932.664-.885.443-1.328 1.182-1.328 2.214 0 1.033.489 1.759 1.467 2.185.976.424 2.405.856 4.288 1.298.996.222 2 .518 3.014.886 1.014.369 1.936.857 2.767 1.467a7.23 7.23 0 0 1 2.019 2.268c.516.903.773 2.001.773 3.291 0 1.623-.303 2.997-.912 4.122a7.773 7.773 0 0 1-2.433 2.739c-1.015.7-2.196 1.208-3.542 1.52a18.318 18.318 0 0 1-4.177.471c-2.064 0-4.075-.379-6.029-1.134-1.956-.756-3.579-1.835-4.868-3.237l4.37-4.094c.738.96 1.695 1.752 2.876 2.379 1.18.628 2.49.94 3.928.94.479 0 .968-.055 1.466-.165.498-.111.96-.286 1.384-.526.424-.24.764-.561 1.024-.968.256-.406.386-.904.386-1.493 0-1.107-.508-1.9-1.521-2.379-1.016-.48-2.536-.96-4.564-1.438a21.777 21.777 0 0 1-2.904-.859 9.374 9.374 0 0 1-2.517-1.383 6.382 6.382 0 0 1-1.771-2.129c-.443-.848-.664-1.899-.664-3.154 0-1.474.304-2.746.912-3.817a7.867 7.867 0 0 1 2.408-2.628c.995-.682 2.12-1.188 3.373-1.52a15.082 15.082 0 0 1 3.874-.498c1.917 0 3.789.332 5.614.996 1.827.664 3.274 1.677 4.343 3.042l-4.315 3.818" fill="#F4F5F5"/><path d="M95.897 66.634c0-9.662-7.862-17.524-17.525-17.524h-1.604v6.157h1.604c6.269 0 11.368 5.1 11.368 11.367 0 6.27-5.099 11.37-11.368 11.37h-5.507v-37.37h-6.157V84.16h11.664c9.663 0 17.525-7.862 17.525-17.526zM62.793 49.11H51.13c-9.663 0-17.525 7.862-17.525 17.524 0 9.664 7.862 17.526 17.525 17.526h1.604v-6.156H51.13c-6.269 0-11.369-5.1-11.369-11.37 0-6.267 5.1-11.367 11.369-11.367h5.506v37.367h6.157V49.11zm45.991 17.557c0 24.301-19.7 44-44 44-24.301 0-44-19.699-44-44 0-24.3 19.699-44 44-44 24.3 0 44 19.7 44 44z" fill="#FFF"/></g></svg>
@@ -3,20 +3,10 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <title>QBO Connect via OAuth2</title>
6
-
7
- <script type="text/javascript" src="<%= QboApi::APP_CENTER_BASE %>/Content/IA/intuit.ipp.anywhere-1.3.1.js"></script>
8
- <script>
9
- intuit.ipp.anywhere.setup({
10
- grantUrl: "<%= @client.authorization_uri(scope: 'com.intuit.quickbooks.accounting', state: session[:state]) %>",
11
- datasources: {
12
- quickbooks : true,
13
- payments : true
14
- }
15
- });
16
- </script>
17
6
  </head>
18
- <body>
19
-
20
- <ipp:connectToIntuit></ipp:connectToIntuit>
7
+ <body style="padding:15px;">
8
+ <a href="<%= authorize_url(state: session[:state]) %>">
9
+ <img src="connect-to-qbo.svg" alt="Connect to QuickBooks Online Button" width="400">
10
+ </a>
21
11
  </body>
22
12
  </html>
@@ -1,9 +1,8 @@
1
1
  class QboApi
2
2
  module ApiMethods
3
-
4
3
  def all(entity, max: 1000, select: nil, inactive: false, params: nil, &block)
5
- enumerator = create_all_enumerator(entity, max: max, select: select, inactive: inactive, params: params)
6
-
4
+ enumerator = create_all_enumerator(entity, max: max, select: select,
5
+ inactive: inactive, params: params)
7
6
  if block_given?
8
7
  enumerator.each(&block)
9
8
  else
@@ -17,9 +16,6 @@ class QboApi
17
16
  request(:get, entity: entity, path: path, params: params)
18
17
  end
19
18
 
20
- # @example
21
- # get(:customer, 5)
22
- # @see #get_by_query_filter
23
19
  def get(entity, id_or_query_filter_args, params: nil)
24
20
  if id_or_query_filter_args.is_a?(Array)
25
21
  get_by_query_filter(entity, id_or_query_filter_args, params: params)
@@ -29,11 +25,6 @@ class QboApi
29
25
  end
30
26
  end
31
27
 
32
- # @example
33
- # get_by_query_filter(:customer, ["DisplayName", "Dukes Basketball Camp"])
34
- # get_by_query_filter(:customer, ["DisplayName", "LIKE", "Dukes%"])
35
- # get_by_query_filter(:vendor, ["DisplayName", "IN", "(true, false)"])
36
- # get_by_query_filter(:customer, ["DisplayName", "Amy's Bird Sanctuary"])
37
28
  def get_by_query_filter(entity, query_filter_args, params: nil)
38
29
  query_str = get_query_str(entity, query_filter_args)
39
30
  if resp = query(query_str, params: params)
@@ -143,6 +134,5 @@ class QboApi
143
134
  resp = get(entity, id)
144
135
  build_deactivate(entity, resp)
145
136
  end
146
-
147
137
  end
148
138
  end
@@ -1,5 +1,11 @@
1
1
  class QboApi
2
2
  module Attachment
3
+ def read_attachment(id:)
4
+ raw_response = connection.get do |request|
5
+ request.url "#{realm_id}/attachable/#{id}"
6
+ end
7
+ response(raw_response, entity: :attachable)
8
+ end
3
9
 
4
10
  def upload_attachment(payload:, attachment:)
5
11
  content_type = payload['ContentType'] || payload[:ContentType]
@@ -7,19 +13,28 @@ class QboApi
7
13
  raw_response = attachment_connection.post do |request|
8
14
  request.url "#{realm_id}/upload"
9
15
  request.body = {
10
- 'file_metadata_01':
11
- Faraday::UploadIO.new(StringIO.new(payload.to_json), 'application/json', 'attachment.json'),
12
- 'file_content_01':
13
- Faraday::UploadIO.new(attachment, content_type, file_name)
16
+ 'file_metadata_01':
17
+ Faraday::UploadIO.new(StringIO.new(payload.to_json), 'application/json', 'attachment.json'),
18
+ 'file_content_01':
19
+ Faraday::UploadIO.new(attachment, content_type, file_name)
14
20
  }
15
21
  end
16
22
  response(raw_response, entity: :attachable)
17
23
  end
18
24
 
25
+ # The `attachable` must be the full payload returned in the read response
26
+ def delete_attachment(attachable:)
27
+ raw_response = connection.post do |request|
28
+ request.url "#{realm_id}/attachable?operation=delete"
29
+ request.body = attachable.to_json
30
+ end
31
+
32
+ response(raw_response, entity: :attachable)
33
+ end
34
+
19
35
  def attachment_connection
20
36
  @attachment_connection ||= authorized_multipart_connection(endpoint_url)
21
37
  end
22
-
23
38
  end
24
39
  end
25
40
 
@@ -1,6 +1,5 @@
1
1
  class QboApi
2
2
  module Configuration
3
-
4
3
  def logger
5
4
  @logger ||= ::Logger.new($stdout)
6
5
  end
@@ -4,16 +4,10 @@ require 'faraday/detailed_logger'
4
4
 
5
5
  class QboApi
6
6
  module Connection
7
- AUTHORIZATION_MIDDLEWARES = []
8
-
9
- def Connection.add_authorization_middleware(strategy_name)
10
- Connection::AUTHORIZATION_MIDDLEWARES << strategy_name
11
- end
12
-
13
7
  def authorized_json_connection(url, headers: nil)
14
8
  headers ||= {}
15
- headers['Accept'] ||= 'application/json' # required "we'll only accept JSON". Can be changed to any `+json` media type.
16
- headers['Content-Type'] ||= 'application/json;charset=UTF-8' # required when request has a body, else harmless
9
+ headers['Accept'] ||= 'application/json'
10
+ headers['Content-Type'] ||= 'application/json;charset=UTF-8'
17
11
  build_connection(url, headers: headers) do |conn|
18
12
  add_authorization_middleware(conn)
19
13
  add_exception_middleware(conn)
@@ -35,17 +29,6 @@ class QboApi
35
29
  end
36
30
  end
37
31
 
38
- # @example
39
- # connection = build_connection('https://oauth.platform.intuit.com', headers: { 'Accept' => 'application/json' }) do |conn|
40
- # conn.basic_auth(client_id, client_secret)
41
- # conn.request :url_encoded # application/x-www-form-urlencoded
42
- # conn.use FaradayMiddleware::ParseJson, parser_options: { symbolize_names: true }
43
- # conn.use Faraday::Response::RaiseError
44
- # end
45
- # raw_response = connection.post {|req|
46
- # req.body = { grant_type: :refresh_token, refresh_token: current_refresh_token }
47
- # req.url '/oauth2/v1/tokens/bearer'
48
- # }
49
32
  def build_connection(url, headers: nil)
50
33
  Faraday.new(url: url) { |conn|
51
34
  conn.response :detailed_logger, QboApi.logger, LOG_TAG if QboApi.log
@@ -119,22 +102,11 @@ class QboApi
119
102
  end
120
103
 
121
104
  def add_authorization_middleware(conn)
122
- Connection::AUTHORIZATION_MIDDLEWARES.find(proc do
123
- raise QboApi::Error.new error_body: 'Add a configured authorization_middleware'
124
- end) do |strategy_name|
125
- next unless public_send("use_#{strategy_name}_middleware?")
126
- public_send("add_#{strategy_name}_authorization_middleware", conn)
127
- true
128
- end
105
+ conn.request :oauth2, access_token, token_type: 'bearer'
129
106
  end
130
107
 
131
108
  def entity_name(entity)
132
109
  singular(entity)
133
110
  end
134
-
135
- require_relative 'connection/oauth1'
136
- include OAuth1
137
- require_relative 'connection/oauth2'
138
- include OAuth2
139
111
  end
140
112
  end
@@ -1,6 +1,5 @@
1
1
  class QboApi
2
2
  module Entity
3
-
4
3
  def singular(entity)
5
4
  e = snake_to_camel(entity)
6
5
  case e
@@ -96,6 +95,5 @@ class QboApi
96
95
  .tr("-", "_")
97
96
  .downcase
98
97
  end
99
-
100
98
  end
101
99
  end
data/lib/qbo_api/error.rb CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  #200 OK The request succeeded. However, the response body may contain a <Fault> element, indicating an error.
3
2
  #400 Bad request Generally, the request cannot be fulfilled due to bad syntax. In some cases, this response code is returned for a request with bad authorization data.
4
3
  #401 Unauthorized Authentication or authorization has failed.
@@ -8,10 +7,12 @@
8
7
  #500 Internal Server Error An error occurred on the server while processing the request. Resubmit request once; if it persists, contact developer support.
9
8
  #502 Bad Gateway The server, while acting as a gateway or proxy, received an invalid response from an inbound server it accessed while attempting to fulfill the request.
10
9
  #503 Service Unavailable The service is temporarily unavailable.
10
+ #504 Gateway Timeout
11
11
  # Custom error class for rescuing from all QuickBooks Online errors
12
12
  class QboApi
13
13
  class Error < StandardError
14
14
  attr_reader :fault
15
+
15
16
  def initialize(errors = nil)
16
17
  if errors
17
18
  @fault = errors
@@ -46,4 +47,7 @@ class QboApi
46
47
 
47
48
  # Raised when QuickBooks Online returns the HTTP status code 503
48
49
  class ServiceUnavailable < Error; end
50
+
51
+ # Raised when QuickBooks Online returns the HTTP status code 504
52
+ class GatewayTimeout < Error; end
49
53
  end
@@ -1,6 +1,5 @@
1
1
  require 'faraday'
2
2
  require 'nokogiri'
3
-
4
3
  # @private
5
4
  module FaradayMiddleware
6
5
  # @private
@@ -25,6 +24,8 @@ module FaradayMiddleware
25
24
  raise QboApi::BadGateway.new({ error_body: response.reason_phrase })
26
25
  when 503
27
26
  raise QboApi::ServiceUnavailable.new(error_message(response))
27
+ when 504
28
+ raise QboApi::GatewayTimeout.new(error_message(response))
28
29
  end
29
30
  end
30
31
  end
@@ -40,7 +41,8 @@ module FaradayMiddleware
40
41
  method: response.method,
41
42
  url: response.url,
42
43
  status: response.status,
43
- error_body: error_body(response.body)
44
+ error_body: error_body(response.body),
45
+ intuit_tid: response[:response_headers]['intuit_tid']
44
46
  }
45
47
  end
46
48
 
@@ -78,6 +80,5 @@ module FaradayMiddleware
78
80
  }
79
81
  end
80
82
  end
81
-
82
83
  end
83
84
  end
@@ -1,6 +1,5 @@
1
1
  class QboApi
2
2
  module Supporting
3
-
4
3
  def cdc(entities:, changed_since:)
5
4
  path = "#{realm_id}/cdc"
6
5
  path = add_params_to_path(path: path, params: { entities: entities, changedSince: cdc_time(changed_since) })
@@ -17,6 +16,5 @@ class QboApi
17
16
  path = add_params_to_path(path: path, params: params) if params
18
17
  request(:get, path: path)
19
18
  end
20
-
21
19
  end
22
20
  end
data/lib/qbo_api/util.rb CHANGED
@@ -53,7 +53,6 @@ class QboApi
53
53
  end
54
54
  uri.to_s
55
55
  end
56
-
57
56
  end
58
57
  end
59
58
 
@@ -1,3 +1,3 @@
1
1
  class QboApi
2
- VERSION = "1.8.5"
2
+ VERSION = "2.0.1"
3
3
  end
data/lib/qbo_api.rb CHANGED
@@ -22,15 +22,15 @@ class QboApi
22
22
  include Attachment
23
23
  include ApiMethods
24
24
 
25
- attr_accessor :realm_id
25
+ attr_accessor :access_token, :realm_id
26
26
  attr_accessor :endpoint
27
27
 
28
28
  V3_ENDPOINT_BASE_URL = 'https://sandbox-quickbooks.api.intuit.com/v3/company/'
29
29
  PAYMENTS_API_BASE_URL = 'https://sandbox.api.intuit.com/quickbooks/v4/payments'
30
30
  LOG_TAG = "[QuickBooks]"
31
31
 
32
- # @param attributes [Hash<Symbol,String>]
33
32
  def initialize(attributes = {})
33
+ raise ArgumentError, "missing keyword: access_token" unless attributes.key?(:access_token)
34
34
  raise ArgumentError, "missing keyword: realm_id" unless attributes.key?(:realm_id)
35
35
  attributes = default_attributes.merge!(attributes)
36
36
  attributes.each do |attribute, value|
data/qbo_api.gemspec CHANGED
@@ -18,14 +18,15 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.10"
22
- spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "rspec"
24
24
  spec.add_development_dependency 'webmock'
25
+ spec.add_development_dependency 'rexml'
25
26
  spec.add_development_dependency 'simple_oauth'
26
27
  spec.add_development_dependency 'dotenv'
27
28
  spec.add_development_dependency 'vcr'
28
- spec.add_development_dependency 'awesome_print'
29
+ spec.add_development_dependency 'amazing_print'
29
30
  spec.add_runtime_dependency 'faraday'
30
31
  spec.add_runtime_dependency 'faraday_middleware'
31
32
  spec.add_runtime_dependency 'faraday-detailed_logger'
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qbo_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.5
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Pelczarski
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-13 00:00:00.000000000 Z
11
+ date: 2021-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.10'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.10'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rexml
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: simple_oauth
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -109,7 +123,7 @@ dependencies:
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
- name: awesome_print
126
+ name: amazing_print
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
129
  - - ">="
@@ -178,14 +192,13 @@ dependencies:
178
192
  - - ">="
179
193
  - !ruby/object:Gem::Version
180
194
  version: '0'
181
- description:
195
+ description:
182
196
  email:
183
197
  - christian@minimul.com
184
198
  executables: []
185
199
  extensions: []
186
200
  extra_rdoc_files: []
187
201
  files:
188
- - ".env.example_app.oauth1"
189
202
  - ".env.example_app.oauth2"
190
203
  - ".env.test"
191
204
  - ".gitignore"
@@ -197,8 +210,8 @@ files:
197
210
  - bin/console
198
211
  - bin/setup
199
212
  - example/base.rb
200
- - example/oauth.rb
201
213
  - example/oauth2.rb
214
+ - example/public/connect-to-qbo.svg
202
215
  - example/views/customer.erb
203
216
  - example/views/index.erb
204
217
  - example/views/oauth2.erb
@@ -208,8 +221,6 @@ files:
208
221
  - lib/qbo_api/attachment.rb
209
222
  - lib/qbo_api/configuration.rb
210
223
  - lib/qbo_api/connection.rb
211
- - lib/qbo_api/connection/oauth1.rb
212
- - lib/qbo_api/connection/oauth2.rb
213
224
  - lib/qbo_api/entity.rb
214
225
  - lib/qbo_api/error.rb
215
226
  - lib/qbo_api/raise_http_exception.rb
@@ -221,7 +232,7 @@ homepage: https://github.com/minimul/qbo_api
221
232
  licenses:
222
233
  - MIT
223
234
  metadata: {}
224
- post_install_message:
235
+ post_install_message:
225
236
  rdoc_options: []
226
237
  require_paths:
227
238
  - lib
@@ -236,8 +247,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
236
247
  - !ruby/object:Gem::Version
237
248
  version: '0'
238
249
  requirements: []
239
- rubygems_version: 3.0.4
240
- signing_key:
250
+ rubygems_version: 3.0.3
251
+ signing_key:
241
252
  specification_version: 4
242
253
  summary: Ruby JSON-only client for QuickBooks Online API v3. Built on top of the Faraday
243
254
  gem.
@@ -1,2 +0,0 @@
1
- export QBO_API_CONSUMER_KEY=<Your QuickBooks apps consumer key>
2
- export QBO_API_CONSUMER_SECRET=<Your QuickBooks apps consumer secret>
data/example/oauth.rb DELETED
@@ -1,62 +0,0 @@
1
- require 'bundler/inline'
2
-
3
- require File.expand_path(File.join('..', 'base'), __FILE__)
4
-
5
- install_gems = true
6
- gemfile(install_gems) do
7
- source 'https://rubygems.org'
8
-
9
- instance_eval(&BASE_GEMS)
10
-
11
- gem 'omniauth'
12
- gem 'omniauth-quickbooks'
13
- end
14
-
15
- instance_eval(&BASE_SETUP)
16
-
17
- class OAuthApp < Sinatra::Base
18
- instance_eval(&BASE_APP_CONFIG)
19
-
20
- CONSUMER_KEY = ENV['QBO_API_CONSUMER_KEY']
21
- CONSUMER_SECRET = ENV['QBO_API_CONSUMER_SECRET']
22
-
23
- use Rack::Session::Cookie, secret: '34233adasf/qewrq453agqr9(lasfa)'
24
- use OmniAuth::Builder do
25
- provider :quickbooks, CONSUMER_KEY, CONSUMER_SECRET
26
- end
27
-
28
- get '/' do
29
- @app_center = QboApi::APP_CENTER_BASE
30
- @auth_data = oauth_data
31
- @port = PORT
32
- erb :index
33
- end
34
-
35
- get '/customer/:id' do
36
- if session[:token]
37
- api = QboApi.new(oauth_data)
38
- @resp = api.get :customer, params[:id]
39
- end
40
- erb :customer
41
- end
42
-
43
- get '/auth/quickbooks/callback' do
44
- auth = env["omniauth.auth"][:credentials]
45
- session[:token] = auth[:token]
46
- session[:secret] = auth[:secret]
47
- session[:realm_id] = params['realmId']
48
- '<!DOCTYPE html><html lang="en"><head></head><body><script>window.opener.location.reload(); window.close();</script></body></html>'
49
- end
50
-
51
- def oauth_data
52
- {
53
- consumer_key: CONSUMER_KEY,
54
- consumer_secret: CONSUMER_SECRET,
55
- token: session[:token],
56
- token_secret: session[:secret],
57
- realm_id: session[:realm_id]
58
- }
59
- end
60
- end
61
-
62
- OAuthApp.run!
@@ -1,60 +0,0 @@
1
- class QboApi
2
- APP_CENTER_BASE = 'https://appcenter.intuit.com'
3
- APP_CENTER_URL = APP_CENTER_BASE + '/Connect/Begin?oauth_token='
4
- APP_CONNECTION_URL = APP_CENTER_BASE + '/api/v1/connection'
5
-
6
- attr_accessor :token, :token_secret
7
- attr_accessor :consumer_key, :consumer_secret
8
-
9
- module Connection::OAuth1
10
-
11
- def self.included(*)
12
- QboApi::Connection.add_authorization_middleware :oauth1
13
- super
14
- end
15
-
16
- def default_attributes
17
- super.merge!(
18
- token: nil, token_secret: nil,
19
- consumer_key: defined?(CONSUMER_KEY) ? CONSUMER_KEY : nil,
20
- consumer_secret: defined?(CONSUMER_SECRET) ? CONSUMER_SECRET : nil,
21
- )
22
- end
23
-
24
- def add_oauth1_authorization_middleware(conn)
25
- gem 'simple_oauth'
26
- require 'simple_oauth'
27
- conn.request :oauth, oauth_data
28
- end
29
-
30
- def use_oauth1_middleware?
31
- token != nil
32
- end
33
-
34
- # https://developer.intuit.com/docs/0100_quickbooks_online/0100_essentials/0085_develop_quickbooks_apps/0004_authentication_and_authorization/oauth_management_api#/Reconnect
35
- def disconnect
36
- path = "#{APP_CONNECTION_URL}/disconnect"
37
- request(:get, path: path)
38
- end
39
-
40
- # https://developer.intuit.com/docs/0100_quickbooks_online/0100_essentials/0085_develop_quickbooks_apps/0004_authentication_and_authorization/oauth_management_api#/Reconnect
41
- def reconnect
42
- path = "#{APP_CONNECTION_URL}/reconnect"
43
- request(:get, path: path)
44
- end
45
-
46
- private
47
-
48
- # Use with simple_oauth OAuth1 middleware
49
- # @see #add_authorization_middleware
50
- def oauth_data
51
- {
52
- consumer_key: @consumer_key,
53
- consumer_secret: @consumer_secret,
54
- token: @token,
55
- token_secret: @token_secret
56
- }
57
- end
58
-
59
- end
60
- end
@@ -1,24 +0,0 @@
1
- class QboApi
2
- attr_accessor :access_token
3
-
4
- module Connection::OAuth2
5
-
6
- def self.included(*)
7
- QboApi::Connection.add_authorization_middleware :oauth2
8
- super
9
- end
10
-
11
- def default_attributes
12
- super.merge!(
13
- access_token: nil
14
- )
15
- end
16
- def add_oauth2_authorization_middleware(conn)
17
- conn.request :oauth2, access_token, token_type: 'bearer'
18
- end
19
-
20
- def use_oauth2_middleware?
21
- access_token != nil
22
- end
23
- end
24
- end