qbo_api 1.8.5 → 3.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: b9924b785fa2755f09e92bf26198280b198dee80d2621d8c86b4e4f2fdb1cc1d
4
+ data.tar.gz: 26b76ad24f8760ebb5c39385e9798b3799645cbe6d3d69230a6d720ee9676514
5
5
  SHA512:
6
- metadata.gz: 4b02f2de3f7192ad90a5beb5b491be6fa05923f6c12c5b6c6f1a040f8a857013cd7201cfe3cfd50e7088a4b664976d3b87ecb9e33a567f79c4d95847e1885b8f
7
- data.tar.gz: 346a13001298cb240678ecbe151844181c7504d97263e16e6e118d9509d3962978bee1556a346d76c265b034189afbc8030c35b8c7885ac7f5c52c1902b3d415
6
+ metadata.gz: 827f3a675049aa20889d6e7e7cf9b8e2b05df79c0410b9bbef0c9bcd2c57eb81f77f88f5e5c2b9f161318bbd899ccb94bec9a9d2e199977b8545bd16cb8163e6
7
+ data.tar.gz: e52c00f610340f0a0d13c711782629c56b80fcc6300b05e5f97705de63545c6cb59dbeba33fb15cbe2770628c38458c2535eabfd00e7e74a87223c267c5229e8
data/.env.test CHANGED
@@ -1,6 +1,2 @@
1
- export QBO_API_CONSUMER_KEY=
2
- export QBO_API_CONSUMER_SECRET=
3
1
  export QBO_API_ACCESS_TOKEN=
4
- export QBO_API_ACCESS_TOKEN_SECRET=
5
- export QBO_API_OAUTH2_ACCESS_TOKEN=
6
2
  export QBO_API_COMPANY_ID=12345
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
@@ -201,6 +206,12 @@ QboApi.minor_version = 8
201
206
  p response['Id'] # => 1
202
207
  ```
203
208
 
209
+
210
+ ### Email a transaction entity
211
+ ```ruby
212
+ api.send_invoice(invoice_id: 1, email_address: 'billy@joe.com')
213
+ ```
214
+
204
215
  ### Uploading an attachment
205
216
  ```ruby
206
217
  payload = {"AttachableRef":
@@ -264,7 +275,7 @@ Be aware that any errors will not raise a `QboApi::Error`, but will be returned
264
275
  }
265
276
  ]
266
277
  }
267
- response = api.batch(payload)
278
+ response = qbo_api.batch(payload)
268
279
  expect(response['BatchItemResponse'].size).to eq 2
269
280
  expect(batch_response.detect{ |b| b["bId"] == "bid1" }["Vendor"]["DisplayName"]).to eq "Smith Family Store"
270
281
  ```
@@ -273,7 +284,7 @@ Be aware that any errors will not raise a `QboApi::Error`, but will be returned
273
284
 
274
285
  ```ruby
275
286
  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)
287
+ response = qbo_api.reports(name: 'ProfitAndLoss', params: params)
277
288
  p response["Header"]["ReportName"]) #=> 'ProfitAndLoss'
278
289
  ```
279
290
 
@@ -310,31 +321,6 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
310
321
  end
311
322
  ```
312
323
 
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
324
  ### What kind of QuickBooks entity?
339
325
  ```ruby
340
326
  p qbo_api.is_transaction_entity?(:invoice) # => true
@@ -343,9 +329,8 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
343
329
  p qbo_api.is_transaction_entity?(:customer) # => false
344
330
  p qbo_api.is_name_list_entity?(:vendors) # => true
345
331
  ```
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>.
332
+ ## <a name='OAuth2-example'>Spin up an example</a>
333
+ - <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
334
  - `git clone git://github.com/minimul/qbo_api && cd qbo_api`
350
335
  - `bundle`
351
336
  - Create a `.env` file
@@ -360,7 +345,7 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
360
345
  - Create a new Company ([from the manage sandboxes page](https://developer.intuit.com/v2/ui#/sandbox))
361
346
  Don't use it for anything else besides testing this app.
362
347
  -. Copy the 'Company ID' to your .env as QBO_API_COMPANY_ID
363
- - Start up the example OAuth2 app
348
+ - Start up the example app
364
349
  - `ruby example/oauth2.rb`
365
350
  - Go to `http://localhost:9393/oauth2`
366
351
  - 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 +355,13 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
370
355
  - Checkout [`example/oauth2.rb`](https://github.com/minimul/qbo_api/blob/master/example/oauth2.rb)
371
356
  to see what is going on under the hood.
372
357
 
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
358
  ## Webhooks
396
359
  - <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
360
 
398
361
  See https://www.twilio.com/blog/2015/09/6-awesome-reasons-to-use-ngrok-when-testing-webhooks.html
399
362
  for how to install ngrok and what it is.
400
363
 
401
- - With either the oauth1 or oauth2 examples running, run:
364
+ - With the example app running, run:
402
365
  `ngrok http 9393 -subdomain=somereasonablyuniquenamehere`
403
366
 
404
367
  - Go to the [`Development` tab](https://developer.intuit.com/v2/ui#/app/dashboard)
@@ -408,9 +371,9 @@ for how to install ngrok and what it is.
408
371
  - After saving the webhook, click 'show token'.
409
372
  Add the token to your .env as QBO_API_VERIFIER_TOKEN
410
373
 
411
- - In another tab, create a customer via the (OAuth2) API:
412
- `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
- (You'll also need to have added the QBO_API_COMPANY_ID and QBO_API_OAUTH2_ACCESS_TOKEN to your .env)
374
+ - In another tab, create a customer via the API:
375
+ `bundle exec ruby -rqbo_api -rdotenv -e 'Dotenv.load; p QboApi.new(access_token: ENV.fetch("QBO_API_ACCESS_TOKEN"), realm_id: ENV.fetch("QBO_API_COMPANY_ID")).create(:customer, payload: { DisplayName: "TestCustomer" })'`
376
+ (You'll also need to have added the QBO_API_COMPANY_ID and QBO_API_ACCESS_TOKEN to your .env)
414
377
 
415
378
  There could be a delay of up to a minute before the webhook fires.
416
379
 
@@ -421,6 +384,28 @@ for how to install ngrok and what it is.
421
384
  "POST /webhooks HTTP/1.1" 200 - 0.0013
422
385
  ```
423
386
 
387
+ ### Just For Hackers
388
+
389
+ - Using the build_connection method
390
+ ```
391
+ connection = build_connection('https://oauth.platform.intuit.com', headers: { 'Accept' => 'application/json' }) do |conn|
392
+ conn.basic_auth(client_id, client_secret)
393
+ conn.request :url_encoded # application/x-www-form-urlencoded
394
+ conn.response :json
395
+ conn.use QboApi::RaiseHttpException
396
+ end
397
+
398
+ raw_response = connection.post do |req|
399
+ req.body = { grant_type: :refresh_token, refresh_token: current_refresh_token }
400
+ req.url '/oauth2/v1/tokens/bearer'
401
+ end
402
+ ```
403
+ - Once your .env file is completely filled out you can use the console to play around in your sandbox
404
+ ```
405
+ bin/console test
406
+ >> @qbo_api.get :customer, 1
407
+ ```
408
+
424
409
  ## Contributing
425
410
 
426
411
  Bug reports and pull requests are welcome on GitHub at https://github.com/minimul/qbo_api.
@@ -438,11 +423,6 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/minimu
438
423
  - 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
424
  - <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
425
 
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
426
 
447
427
  ## License
448
428
 
data/example/base.rb CHANGED
@@ -3,6 +3,7 @@ BASE_GEMS = proc do
3
3
  # This app
4
4
  gem 'sinatra'
5
5
  gem 'sinatra-contrib'
6
+ gem 'puma'
6
7
 
7
8
  # Creds from ../.env
8
9
  gem 'dotenv'
@@ -25,6 +26,7 @@ BASE_APP_CONFIG = proc do
25
26
  configure do
26
27
  $VERBOSE = nil # silence redefined constant warning
27
28
  register Sinatra::Reloader
29
+ set :public_folder => "#{__dir__}/public"
28
30
  end
29
31
 
30
32
  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)
@@ -67,6 +58,14 @@ class QboApi
67
58
  request(:post, entity: entity, path: entity_path(entity), payload: payload)
68
59
  end
69
60
 
61
+ def void(entity, id:)
62
+ err_msg = "Void is only for voidable transaction entities. Use .delete or .deactivate instead"
63
+ raise QboApi::NotImplementedError.new, err_msg unless is_voidable_transaction_entity?(entity)
64
+ path = add_params_to_path(path: entity_path(entity), params: { operation: :void })
65
+ payload = set_update(entity, id)
66
+ request(:post, entity: entity, path: path, payload: payload)
67
+ end
68
+
70
69
  private
71
70
 
72
71
  def get_query_str(entity, query_filter_args)
@@ -143,6 +142,5 @@ class QboApi
143
142
  resp = get(entity, id)
144
143
  build_deactivate(entity, resp)
145
144
  end
146
-
147
145
  end
148
146
  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
@@ -1,23 +1,20 @@
1
1
  require 'faraday'
2
- require 'faraday_middleware'
2
+ require 'faraday/response/json'
3
+ require 'qbo_api/raise_http_exception'
3
4
  require 'faraday/detailed_logger'
5
+ require 'faraday/multipart'
4
6
 
5
7
  class QboApi
6
8
  module Connection
7
- AUTHORIZATION_MIDDLEWARES = []
8
-
9
- def Connection.add_authorization_middleware(strategy_name)
10
- Connection::AUTHORIZATION_MIDDLEWARES << strategy_name
11
- end
12
-
13
9
  def authorized_json_connection(url, headers: nil)
14
10
  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
11
+ headers['Accept'] ||= 'application/json'
12
+ headers['Content-Type'] ||= 'application/json;charset=UTF-8'
17
13
  build_connection(url, headers: headers) do |conn|
14
+ conn.response :json
18
15
  add_authorization_middleware(conn)
19
- add_exception_middleware(conn)
20
16
  conn.request :url_encoded
17
+ add_exception_middleware(conn)
21
18
  add_connection_adapter(conn)
22
19
  end
23
20
  end
@@ -28,6 +25,7 @@ class QboApi
28
25
  'Accept' => 'application/json'
29
26
  }
30
27
  build_connection(url, headers: headers) do |conn|
28
+ conn.response :json
31
29
  add_authorization_middleware(conn)
32
30
  add_exception_middleware(conn)
33
31
  conn.request :multipart
@@ -35,17 +33,6 @@ class QboApi
35
33
  end
36
34
  end
37
35
 
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
36
  def build_connection(url, headers: nil)
50
37
  Faraday.new(url: url) { |conn|
51
38
  conn.response :detailed_logger, QboApi.logger, LOG_TAG if QboApi.log
@@ -54,14 +41,17 @@ class QboApi
54
41
  }
55
42
  end
56
43
 
57
- def request(method, path:, entity: nil, payload: nil, params: nil)
58
- raw_response = raw_request(method, conn: connection, path: path, params: params, payload: payload)
44
+ def request(method, path:, entity: nil, payload: nil, params: nil, headers: nil)
45
+ raw_response = raw_request(method, conn: connection, path: path, params: params, payload: payload, headers: headers)
59
46
  response(raw_response, entity: entity)
60
47
  end
61
48
 
62
- def raw_request(method, conn:, path:, payload: nil, params: nil)
49
+ def raw_request(method, conn:, path:, payload: nil, params: nil, headers: nil)
63
50
  path = finalize_path(path, method: method, params: params)
51
+
64
52
  conn.public_send(method) do |req|
53
+ req.headers = headers if headers
54
+
65
55
  case method
66
56
  when :get, :delete
67
57
  req.url path
@@ -74,21 +64,13 @@ class QboApi
74
64
  end
75
65
 
76
66
  def response(resp, entity: nil)
77
- data = parse_response_body(resp)
67
+ data = resp.body
78
68
  entity ? entity_response(data, entity) : data
79
69
  rescue => e
80
70
  QboApi.logger.debug { "#{LOG_TAG} response parsing error: entity=#{entity.inspect} body=#{resp.body.inspect} exception=#{e.inspect}" }
81
71
  data
82
72
  end
83
73
 
84
- def parse_response_body(resp)
85
- body = resp.body
86
- case resp.headers['Content-Type']
87
- when /json/ then JSON.parse(body)
88
- else body
89
- end
90
- end
91
-
92
74
  private
93
75
 
94
76
  def entity_response(data, entity)
@@ -115,26 +97,18 @@ class QboApi
115
97
  end
116
98
 
117
99
  def add_exception_middleware(conn)
118
- conn.use FaradayMiddleware::RaiseHttpException
100
+ conn.use QboApi::RaiseHttpException
119
101
  end
120
102
 
103
+ # Faraday 2 deprecated the FaradayMiddleware gem. Middleware is
104
+ # now part of Faraday itself, and :authorization can be used to pass
105
+ # the Bearer token.
121
106
  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
107
+ conn.request :authorization, 'Bearer', access_token
129
108
  end
130
109
 
131
110
  def entity_name(entity)
132
111
  singular(entity)
133
112
  end
134
-
135
- require_relative 'connection/oauth1'
136
- include OAuth1
137
- require_relative 'connection/oauth2'
138
- include OAuth2
139
113
  end
140
114
  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
@@ -21,6 +20,19 @@ class QboApi
21
20
  sym.to_s.split('_').collect(&:capitalize).join
22
21
  end
23
22
 
23
+ def is_voidable_transaction_entity?(entity)
24
+ voidable_transaction_entities.include?(singular(entity))
25
+ end
26
+
27
+ def voidable_transaction_entities
28
+ %w{
29
+ BillPayment
30
+ Invoice
31
+ Payment
32
+ SalesReceipt
33
+ }
34
+ end
35
+
24
36
  def is_transaction_entity?(entity)
25
37
  transaction_entities.include?(singular(entity))
26
38
  end
@@ -96,6 +108,5 @@ class QboApi
96
108
  .tr("-", "_")
97
109
  .downcase
98
110
  end
99
-
100
111
  end
101
112
  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,31 +1,44 @@
1
1
  require 'faraday'
2
+ require 'faraday/response'
2
3
  require 'nokogiri'
3
-
4
4
  # @private
5
- module FaradayMiddleware
5
+ class QboApi
6
6
  # @private
7
- class RaiseHttpException < Faraday::Middleware
8
- def call(env)
9
- @app.call(env).on_complete do |response|
10
- case response.status
11
- when 200
12
- when 400
13
- raise QboApi::BadRequest.new(error_message(response))
14
- when 401
15
- raise QboApi::Unauthorized.new(error_message(response))
16
- when 403
17
- raise QboApi::Forbidden.new(error_message(response))
18
- when 404
19
- raise QboApi::NotFound.new(error_message(response))
20
- when 429
21
- raise QboApi::TooManyRequests.new(error_message(response))
22
- when 500
23
- raise QboApi::InternalServerError.new(error_message(response))
24
- when 502
25
- raise QboApi::BadGateway.new({ error_body: response.reason_phrase })
26
- when 503
27
- raise QboApi::ServiceUnavailable.new(error_message(response))
28
- end
7
+ class RaiseHttpException < Faraday::Response::RaiseError
8
+ def on_complete(env)
9
+ case env[:status]
10
+ when 400
11
+ raise QboApi::BadRequest.new(error_message(env))
12
+ when 401
13
+ raise QboApi::Unauthorized.new(error_message(env))
14
+ when 403
15
+ raise QboApi::Forbidden.new(error_message(env))
16
+ when 404
17
+ raise QboApi::NotFound.new(error_message(env))
18
+ when 407
19
+ # mimic the behavior that we get with proxy requests with HTTPS
20
+ msg = %(407 "Proxy Authentication Required")
21
+ raise Faraday::ProxyAuthError.new(msg, response_values(env))
22
+ when 409
23
+ raise Faraday::ConflictError, response_values(env)
24
+ when 422
25
+ raise Faraday::UnprocessableEntityError, response_values(env)
26
+ when 429
27
+ raise QboApi::TooManyRequests.new(error_message(env))
28
+ when 500
29
+ raise QboApi::InternalServerError.new(error_message(env))
30
+ when 502
31
+ raise QboApi::BadGateway.new({ error_body: env.reason_phrase })
32
+ when 503
33
+ raise QboApi::ServiceUnavailable.new(error_message(env))
34
+ when 504
35
+ raise QboApi::GatewayTimeout.new(error_message(env))
36
+ when ClientErrorStatuses
37
+ raise Faraday::ClientError, response_values(env)
38
+ when ServerErrorStatuses
39
+ raise Faraday::ServerError, response_values(env)
40
+ when nil
41
+ raise Faraday::NilStatusError, response_values(env)
29
42
  end
30
43
  end
31
44
 
@@ -35,12 +48,13 @@ module FaradayMiddleware
35
48
 
36
49
  private
37
50
 
38
- def error_message(response)
51
+ def error_message(env)
39
52
  {
40
- method: response.method,
41
- url: response.url,
42
- status: response.status,
43
- error_body: error_body(response.body)
53
+ method: env.method,
54
+ url: env.url,
55
+ status: env.status,
56
+ error_body: error_body(env.body),
57
+ intuit_tid: env[:response_headers]['intuit_tid']
44
58
  }
45
59
  end
46
60
 
@@ -78,6 +92,5 @@ module FaradayMiddleware
78
92
  }
79
93
  end
80
94
  end
81
-
82
95
  end
83
96
  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) })
@@ -18,5 +17,19 @@ class QboApi
18
17
  request(:get, path: path)
19
18
  end
20
19
 
20
+ def deliver(entity, entity_id:, email_address: nil)
21
+ valid_entities = %i(invoice estimate purchaseorder creditmemo salesreceipt refundreceipt)
22
+ unless valid_entities.include?(entity.to_sym)
23
+ raise ArgumentError, "Invalid entity type '#{entity}'. Must be one of: #{valid_entities.join(', ')}"
24
+ end
25
+
26
+ path = "#{realm_id}/#{entity}/#{entity_id}/send"
27
+ unless email_address.nil?
28
+ params = { minorversion: 63, sendTo: email_address }
29
+ path = add_params_to_path(path: path, params: params)
30
+ end
31
+ headers = { 'Content-Type' => 'application/octet-stream' }
32
+ request(:post, path: path, headers: headers)
33
+ end
21
34
  end
22
35
  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 = "3.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,16 +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 'simple_oauth'
26
25
  spec.add_development_dependency 'dotenv'
27
26
  spec.add_development_dependency 'vcr'
28
- spec.add_development_dependency 'awesome_print'
29
- spec.add_runtime_dependency 'faraday'
30
- spec.add_runtime_dependency 'faraday_middleware'
27
+ spec.add_development_dependency 'amazing_print'
28
+ spec.add_runtime_dependency 'faraday', '>= 1.10.0'
31
29
  spec.add_runtime_dependency 'faraday-detailed_logger'
30
+ spec.add_runtime_dependency 'faraday-multipart'
32
31
  spec.add_runtime_dependency 'nokogiri'
33
32
  end
metadata CHANGED
@@ -1,45 +1,31 @@
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: 3.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: 2023-01-04 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
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '10.0'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - ">="
@@ -53,7 +39,7 @@ dependencies:
53
39
  - !ruby/object:Gem::Version
54
40
  version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
- name: webmock
42
+ name: rspec
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - ">="
@@ -67,7 +53,7 @@ dependencies:
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
- name: simple_oauth
56
+ name: webmock
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - ">="
@@ -109,7 +95,7 @@ dependencies:
109
95
  - !ruby/object:Gem::Version
110
96
  version: '0'
111
97
  - !ruby/object:Gem::Dependency
112
- name: awesome_print
98
+ name: amazing_print
113
99
  requirement: !ruby/object:Gem::Requirement
114
100
  requirements:
115
101
  - - ">="
@@ -128,16 +114,16 @@ dependencies:
128
114
  requirements:
129
115
  - - ">="
130
116
  - !ruby/object:Gem::Version
131
- version: '0'
117
+ version: 1.10.0
132
118
  type: :runtime
133
119
  prerelease: false
134
120
  version_requirements: !ruby/object:Gem::Requirement
135
121
  requirements:
136
122
  - - ">="
137
123
  - !ruby/object:Gem::Version
138
- version: '0'
124
+ version: 1.10.0
139
125
  - !ruby/object:Gem::Dependency
140
- name: faraday_middleware
126
+ name: faraday-detailed_logger
141
127
  requirement: !ruby/object:Gem::Requirement
142
128
  requirements:
143
129
  - - ">="
@@ -151,7 +137,7 @@ dependencies:
151
137
  - !ruby/object:Gem::Version
152
138
  version: '0'
153
139
  - !ruby/object:Gem::Dependency
154
- name: faraday-detailed_logger
140
+ name: faraday-multipart
155
141
  requirement: !ruby/object:Gem::Requirement
156
142
  requirements:
157
143
  - - ">="
@@ -178,14 +164,13 @@ dependencies:
178
164
  - - ">="
179
165
  - !ruby/object:Gem::Version
180
166
  version: '0'
181
- description:
167
+ description:
182
168
  email:
183
169
  - christian@minimul.com
184
170
  executables: []
185
171
  extensions: []
186
172
  extra_rdoc_files: []
187
173
  files:
188
- - ".env.example_app.oauth1"
189
174
  - ".env.example_app.oauth2"
190
175
  - ".env.test"
191
176
  - ".gitignore"
@@ -197,8 +182,8 @@ files:
197
182
  - bin/console
198
183
  - bin/setup
199
184
  - example/base.rb
200
- - example/oauth.rb
201
185
  - example/oauth2.rb
186
+ - example/public/connect-to-qbo.svg
202
187
  - example/views/customer.erb
203
188
  - example/views/index.erb
204
189
  - example/views/oauth2.erb
@@ -208,8 +193,6 @@ files:
208
193
  - lib/qbo_api/attachment.rb
209
194
  - lib/qbo_api/configuration.rb
210
195
  - lib/qbo_api/connection.rb
211
- - lib/qbo_api/connection/oauth1.rb
212
- - lib/qbo_api/connection/oauth2.rb
213
196
  - lib/qbo_api/entity.rb
214
197
  - lib/qbo_api/error.rb
215
198
  - lib/qbo_api/raise_http_exception.rb
@@ -221,7 +204,7 @@ homepage: https://github.com/minimul/qbo_api
221
204
  licenses:
222
205
  - MIT
223
206
  metadata: {}
224
- post_install_message:
207
+ post_install_message:
225
208
  rdoc_options: []
226
209
  require_paths:
227
210
  - lib
@@ -236,8 +219,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
236
219
  - !ruby/object:Gem::Version
237
220
  version: '0'
238
221
  requirements: []
239
- rubygems_version: 3.0.4
240
- signing_key:
222
+ rubygems_version: 3.2.22
223
+ signing_key:
241
224
  specification_version: 4
242
225
  summary: Ruby JSON-only client for QuickBooks Online API v3. Built on top of the Faraday
243
226
  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