qbo_api 1.9.0 → 2.0.2

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