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 +4 -4
- data/.env.test +0 -4
- data/.gitignore +1 -0
- data/.travis.yml +6 -3
- data/README.md +76 -96
- data/example/base.rb +2 -0
- data/example/oauth2.rb +15 -2
- data/example/public/connect-to-qbo.svg +1 -0
- data/example/views/oauth2.erb +4 -14
- data/lib/qbo_api/api_methods.rb +10 -12
- data/lib/qbo_api/attachment.rb +20 -5
- data/lib/qbo_api/configuration.rb +0 -1
- data/lib/qbo_api/connection.rb +20 -46
- data/lib/qbo_api/entity.rb +13 -2
- data/lib/qbo_api/error.rb +5 -1
- data/lib/qbo_api/raise_http_exception.rb +43 -30
- data/lib/qbo_api/supporting.rb +14 -1
- data/lib/qbo_api/util.rb +0 -1
- data/lib/qbo_api/version.rb +1 -1
- data/lib/qbo_api.rb +2 -2
- data/qbo_api.gemspec +5 -6
- metadata +19 -36
- data/.env.example_app.oauth1 +0 -2
- data/example/oauth.rb +0 -62
- data/lib/qbo_api/connection/oauth1.rb +0 -60
- data/lib/qbo_api/connection/oauth2.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9924b785fa2755f09e92bf26198280b198dee80d2621d8c86b4e4f2fdb1cc1d
|
4
|
+
data.tar.gz: 26b76ad24f8760ebb5c39385e9798b3799645cbe6d3d69230a6d720ee9676514
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 827f3a675049aa20889d6e7e7cf9b8e2b05df79c0410b9bbef0c9bcd2c57eb81f77f88f5e5c2b9f161318bbd899ccb94bec9a9d2e199977b8545bd16cb8163e6
|
7
|
+
data.tar.gz: e52c00f610340f0a0d13c711782629c56b80fcc6300b05e5f97705de63545c6cb59dbeba33fb15cbe2770628c38458c2535eabfd00e7e74a87223c267c5229e8
|
data/.env.test
CHANGED
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
- 2.
|
5
|
-
- 2.
|
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.
|
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
|
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
|
-
-
|
68
|
-
-
|
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 =
|
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 =
|
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'>
|
347
|
-
|
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
|
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
|
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
|
412
|
-
`bundle exec ruby -rqbo_api -rdotenv -e 'Dotenv.load; p QboApi.new(access_token: ENV.fetch("
|
413
|
-
(You'll also need to have added the QBO_API_COMPANY_ID and
|
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:
|
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>
|
data/example/views/oauth2.erb
CHANGED
@@ -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
|
-
|
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>
|
data/lib/qbo_api/api_methods.rb
CHANGED
@@ -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,
|
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
|
data/lib/qbo_api/attachment.rb
CHANGED
@@ -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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
|
data/lib/qbo_api/connection.rb
CHANGED
@@ -1,23 +1,20 @@
|
|
1
1
|
require 'faraday'
|
2
|
-
require '
|
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'
|
16
|
-
headers['Content-Type'] ||= 'application/json;charset=UTF-8'
|
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 =
|
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
|
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
|
-
|
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
|
data/lib/qbo_api/entity.rb
CHANGED
@@ -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
|
-
|
5
|
+
class QboApi
|
6
6
|
# @private
|
7
|
-
class RaiseHttpException < Faraday::
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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(
|
51
|
+
def error_message(env)
|
39
52
|
{
|
40
|
-
method:
|
41
|
-
url:
|
42
|
-
status:
|
43
|
-
error_body: error_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
|
data/lib/qbo_api/supporting.rb
CHANGED
@@ -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
data/lib/qbo_api/version.rb
CHANGED
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"
|
22
|
-
spec.add_development_dependency "rake"
|
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 '
|
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:
|
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:
|
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: '
|
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: '
|
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:
|
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:
|
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:
|
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:
|
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:
|
124
|
+
version: 1.10.0
|
139
125
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
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-
|
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.
|
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.
|
data/.env.example_app.oauth1
DELETED
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
|