qbo_api 1.8.3 → 2.0.0

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
- SHA1:
3
- metadata.gz: 1a14e9e5e66c903adfe8068876926ab4a7cb1a6a
4
- data.tar.gz: 81dea94865459c92b103ae0b6804b85f2287e23c
2
+ SHA256:
3
+ metadata.gz: d72b41eaf72084c4445833378025cd45c902ad44e5df4c3d3f43e6eb69646c58
4
+ data.tar.gz: 7b304ea6e41fc62e6d14f5b3bd68ff001cc8ebc1754cad02238ca86ffeba0813
5
5
  SHA512:
6
- metadata.gz: 5c7a3e681f058684ccec7da9db94da92ce20f010f6762b91eb7e87cf10b83a320897a8fcd84f882d841544ec17b08ab3e90711c3674ef0662669861e3108ed58
7
- data.tar.gz: 5ffdd016f2ef8f8d83b9b700d76a835cdb86fd39a85621976fc0fef99a69c9dff30b5c4b0a40bbf2624a5fd163bfe71753aebc2058ca03f55a6f76b90e8615f2
6
+ metadata.gz: e6362288c9c1e0d29b8a5f181d9f0b1ede2c2fb09804410a4e1deba35e65517c675c14a1649c2a1c4638ec0bf52ca5f0317244b1881f9654ef4b53aa842d22a4
7
+ data.tar.gz: 3ff300fae0442f99747d5d4a6cf2f36c97ad036a5fed351ae0447a8e915a5be265aeeedfe13a34e3dd832adf65543fd3f157d1e0d5c738eaa6f3ca4ac683e028
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
@@ -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.5.7
5
+ - 2.6.6
6
+ - 2.7.1
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.5 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:
@@ -264,7 +236,7 @@ Be aware that any errors will not raise a `QboApi::Error`, but will be returned
264
236
  }
265
237
  ]
266
238
  }
267
- response = api.batch(payload)
239
+ response = qbo_api.batch(payload)
268
240
  expect(response['BatchItemResponse'].size).to eq 2
269
241
  expect(batch_response.detect{ |b| b["bId"] == "bid1" }["Vendor"]["DisplayName"]).to eq "Smith Family Store"
270
242
  ```
@@ -273,7 +245,7 @@ Be aware that any errors will not raise a `QboApi::Error`, but will be returned
273
245
 
274
246
  ```ruby
275
247
  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)
248
+ response = qbo_api.reports(name: 'ProfitAndLoss', params: params)
277
249
  p response["Header"]["ReportName"]) #=> 'ProfitAndLoss'
278
250
  ```
279
251
 
@@ -343,9 +315,8 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
343
315
  p qbo_api.is_transaction_entity?(:customer) # => false
344
316
  p qbo_api.is_name_list_entity?(:vendors) # => true
345
317
  ```
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>.
318
+ ## <a name='OAuth2-example'>Spin up an example</a>
319
+ - <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
320
  - `git clone git://github.com/minimul/qbo_api && cd qbo_api`
350
321
  - `bundle`
351
322
  - Create a `.env` file
@@ -360,7 +331,7 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
360
331
  - Create a new Company ([from the manage sandboxes page](https://developer.intuit.com/v2/ui#/sandbox))
361
332
  Don't use it for anything else besides testing this app.
362
333
  -. Copy the 'Company ID' to your .env as QBO_API_COMPANY_ID
363
- - Start up the example OAuth2 app
334
+ - Start up the example app
364
335
  - `ruby example/oauth2.rb`
365
336
  - Go to `http://localhost:9393/oauth2`
366
337
  - 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 +341,13 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
370
341
  - Checkout [`example/oauth2.rb`](https://github.com/minimul/qbo_api/blob/master/example/oauth2.rb)
371
342
  to see what is going on under the hood.
372
343
 
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
344
  ## Webhooks
396
345
  - <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
346
 
398
347
  See https://www.twilio.com/blog/2015/09/6-awesome-reasons-to-use-ngrok-when-testing-webhooks.html
399
348
  for how to install ngrok and what it is.
400
349
 
401
- - With either the oauth1 or oauth2 examples running, run:
350
+ - With the example app running, run:
402
351
  `ngrok http 9393 -subdomain=somereasonablyuniquenamehere`
403
352
 
404
353
  - Go to the [`Development` tab](https://developer.intuit.com/v2/ui#/app/dashboard)
@@ -408,7 +357,7 @@ for how to install ngrok and what it is.
408
357
  - After saving the webhook, click 'show token'.
409
358
  Add the token to your .env as QBO_API_VERIFIER_TOKEN
410
359
 
411
- - In another tab, create a customer via the (OAuth2) API:
360
+ - In another tab, create a customer via the API:
412
361
  `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
362
  (You'll also need to have added the QBO_API_COMPANY_ID and QBO_API_OAUTH2_ACCESS_TOKEN to your .env)
414
363
 
@@ -421,6 +370,28 @@ for how to install ngrok and what it is.
421
370
  "POST /webhooks HTTP/1.1" 200 - 0.0013
422
371
  ```
423
372
 
373
+ ### Just For Hackers
374
+
375
+ - Using the build_connection method
376
+ ```
377
+ connection = build_connection('https://oauth.platform.intuit.com', headers: { 'Accept' => 'application/json' }) do |conn|
378
+ conn.basic_auth(client_id, client_secret)
379
+ conn.request :url_encoded # application/x-www-form-urlencoded
380
+ conn.use FaradayMiddleware::ParseJson, parser_options: { symbolize_names: true }
381
+ conn.use Faraday::Response::RaiseError
382
+ end
383
+
384
+ raw_response = connection.post do |req|
385
+ req.body = { grant_type: :refresh_token, refresh_token: current_refresh_token }
386
+ req.url '/oauth2/v1/tokens/bearer'
387
+ end
388
+ ```
389
+ - Once your .env file is completely filled out you can use the console to play around in your sandbox
390
+ ```
391
+ bin/console test
392
+ >> @qbo_api.get :customer, 1
393
+ ```
394
+
424
395
  ## Contributing
425
396
 
426
397
  Bug reports and pull requests are welcome on GitHub at https://github.com/minimul/qbo_api.
@@ -438,11 +409,6 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/minimu
438
409
  - 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
410
  - <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
411
 
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
412
 
447
413
  ## License
448
414
 
@@ -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
@@ -21,19 +21,32 @@ class OAuth2App < Sinatra::Base
21
21
 
22
22
  helpers do
23
23
  def oauth2_client
24
- client = Rack::OAuth2::Client.new(
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>
@@ -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|
@@ -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)
@@ -128,7 +119,7 @@ class QboApi
128
119
  payload = build_update(resp).merge('sparse': true, 'Active': false)
129
120
 
130
121
  case singular(entity)
131
- when 'Account'
122
+ when 'Account', 'Class'
132
123
  payload['Name'] = resp['Name']
133
124
  end
134
125
  payload
@@ -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)
@@ -23,7 +17,10 @@ class QboApi
23
17
  end
24
18
 
25
19
  def authorized_multipart_connection(url)
26
- headers = { 'Content-Type' => 'multipart/form-data' }
20
+ headers = {
21
+ 'Content-Type' => 'multipart/form-data',
22
+ 'Accept' => 'application/json'
23
+ }
27
24
  build_connection(url, headers: headers) do |conn|
28
25
  add_authorization_middleware(conn)
29
26
  add_exception_middleware(conn)
@@ -32,17 +29,6 @@ class QboApi
32
29
  end
33
30
  end
34
31
 
35
- # @example
36
- # connection = build_connection('https://oauth.platform.intuit.com', headers: { 'Accept' => 'application/json' }) do |conn|
37
- # conn.basic_auth(client_id, client_secret)
38
- # conn.request :url_encoded # application/x-www-form-urlencoded
39
- # conn.use FaradayMiddleware::ParseJson, parser_options: { symbolize_names: true }
40
- # conn.use Faraday::Response::RaiseError
41
- # end
42
- # raw_response = connection.post {|req|
43
- # req.body = { grant_type: :refresh_token, refresh_token: current_refresh_token }
44
- # req.url '/oauth2/v1/tokens/bearer'
45
- # }
46
32
  def build_connection(url, headers: nil)
47
33
  Faraday.new(url: url) { |conn|
48
34
  conn.response :detailed_logger, QboApi.logger, LOG_TAG if QboApi.log
@@ -116,22 +102,11 @@ class QboApi
116
102
  end
117
103
 
118
104
  def add_authorization_middleware(conn)
119
- Connection::AUTHORIZATION_MIDDLEWARES.find(proc do
120
- raise QboApi::Error.new error_body: 'Add a configured authorization_middleware'
121
- end) do |strategy_name|
122
- next unless public_send("use_#{strategy_name}_middleware?")
123
- public_send("add_#{strategy_name}_authorization_middleware", conn)
124
- true
125
- end
105
+ conn.request :oauth2, access_token, token_type: 'bearer'
126
106
  end
127
107
 
128
108
  def entity_name(entity)
129
109
  singular(entity)
130
110
  end
131
-
132
- require_relative 'connection/oauth1'
133
- include OAuth1
134
- require_relative 'connection/oauth2'
135
- include OAuth2
136
111
  end
137
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
@@ -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.
@@ -6,11 +5,14 @@
6
5
  #404 Not Found The resource is not found.
7
6
  #429 Too Many Requests API Throttling/ Rate limiting
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.
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.
9
9
  #503 Service Unavailable The service is temporarily unavailable.
10
+ #504 Gateway Timeout
10
11
  # Custom error class for rescuing from all QuickBooks Online errors
11
12
  class QboApi
12
13
  class Error < StandardError
13
14
  attr_reader :fault
15
+
14
16
  def initialize(errors = nil)
15
17
  if errors
16
18
  @fault = errors
@@ -40,6 +42,12 @@ class QboApi
40
42
  # Raised when QuickBooks Online returns the HTTP status code 500
41
43
  class InternalServerError < Error; end
42
44
 
45
+ # Raised when QuickBooks Online returns the HTTP status code 502
46
+ class BadGateway < Error; end
47
+
43
48
  # Raised when QuickBooks Online returns the HTTP status code 503
44
49
  class ServiceUnavailable < Error; end
50
+
51
+ # Raised when QuickBooks Online returns the HTTP status code 504
52
+ class GatewayTimeout < Error; end
45
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
@@ -21,8 +20,12 @@ module FaradayMiddleware
21
20
  raise QboApi::TooManyRequests.new(error_message(response))
22
21
  when 500
23
22
  raise QboApi::InternalServerError.new(error_message(response))
23
+ when 502
24
+ raise QboApi::BadGateway.new({ error_body: response.reason_phrase })
24
25
  when 503
25
26
  raise QboApi::ServiceUnavailable.new(error_message(response))
27
+ when 504
28
+ raise QboApi::GatewayTimeout.new(error_message(response))
26
29
  end
27
30
  end
28
31
  end
@@ -38,7 +41,8 @@ module FaradayMiddleware
38
41
  method: response.method,
39
42
  url: response.url,
40
43
  status: response.status,
41
- error_body: error_body(response.body)
44
+ error_body: error_body(response.body),
45
+ intuit_tid: response[:response_headers]['intuit_tid']
42
46
  }
43
47
  end
44
48
 
@@ -76,6 +80,5 @@ module FaradayMiddleware
76
80
  }
77
81
  end
78
82
  end
79
-
80
83
  end
81
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
@@ -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.3"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -18,14 +18,14 @@ 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
25
  spec.add_development_dependency 'simple_oauth'
26
26
  spec.add_development_dependency 'dotenv'
27
27
  spec.add_development_dependency 'vcr'
28
- spec.add_development_dependency 'awesome_print'
28
+ spec.add_development_dependency 'amazing_print'
29
29
  spec.add_runtime_dependency 'faraday'
30
30
  spec.add_runtime_dependency 'faraday_middleware'
31
31
  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.3
4
+ version: 2.0.0
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: 2018-04-12 00:00:00.000000000 Z
11
+ date: 2020-12-18 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
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: awesome_print
112
+ name: amazing_print
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -178,14 +178,13 @@ dependencies:
178
178
  - - ">="
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
- description:
181
+ description:
182
182
  email:
183
183
  - christian@minimul.com
184
184
  executables: []
185
185
  extensions: []
186
186
  extra_rdoc_files: []
187
187
  files:
188
- - ".env.example_app.oauth1"
189
188
  - ".env.example_app.oauth2"
190
189
  - ".env.test"
191
190
  - ".gitignore"
@@ -197,8 +196,8 @@ files:
197
196
  - bin/console
198
197
  - bin/setup
199
198
  - example/base.rb
200
- - example/oauth.rb
201
199
  - example/oauth2.rb
200
+ - example/public/connect-to-qbo.svg
202
201
  - example/views/customer.erb
203
202
  - example/views/index.erb
204
203
  - example/views/oauth2.erb
@@ -208,8 +207,6 @@ files:
208
207
  - lib/qbo_api/attachment.rb
209
208
  - lib/qbo_api/configuration.rb
210
209
  - lib/qbo_api/connection.rb
211
- - lib/qbo_api/connection/oauth1.rb
212
- - lib/qbo_api/connection/oauth2.rb
213
210
  - lib/qbo_api/entity.rb
214
211
  - lib/qbo_api/error.rb
215
212
  - lib/qbo_api/raise_http_exception.rb
@@ -221,7 +218,7 @@ homepage: https://github.com/minimul/qbo_api
221
218
  licenses:
222
219
  - MIT
223
220
  metadata: {}
224
- post_install_message:
221
+ post_install_message:
225
222
  rdoc_options: []
226
223
  require_paths:
227
224
  - lib
@@ -236,9 +233,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
236
233
  - !ruby/object:Gem::Version
237
234
  version: '0'
238
235
  requirements: []
239
- rubyforge_project:
240
- rubygems_version: 2.4.5.2
241
- signing_key:
236
+ rubygems_version: 3.1.2
237
+ signing_key:
242
238
  specification_version: 4
243
239
  summary: Ruby JSON-only client for QuickBooks Online API v3. Built on top of the Faraday
244
240
  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>
@@ -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