Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.
/ qbo_api Public archive
forked from ntippie/qbo_api

Ruby JSON-only client for QuickBooks Online API v3. Built on top of the Faraday gem.

License

Notifications You must be signed in to change notification settings

surbhig213/qbo_api

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QboApi

Ruby client for the QuickBooks Online API version 3.

  • Built on top of the excellent Faraday gem.
  • JSON only support.
    • Please don't ask about XML support. Intuit has stated that JSON is the primary data format for the QuickBooks API (v3 and beyond). This gem will specialize in JSON only. The quickbooks-ruby gem has fantastic support for those who favor XML.
  • Features specs built directly against a QuickBooks Online Sandbox via the VCR gem.
  • Robust error handling.

Tutorials and Screencasts

Important Note: The videos are out of date.

If you signed up for a Intuit developer account after July 17th, 2017 then you will have to follow OAuth2: Spin up an example

The Book

The QBO book

Ruby >= 2.2.2 required

Installation

Add this line to your application's Gemfile:

gem 'qbo_api'

And then execute:

$ bundle

Or install it yourself as:

$ gem install qbo_api

Usage

Initialize

OAuth

  q = account.qbo_account # or wherever you are storing the OAuth creds
  qbo_api = QboApi.new(token: q.token,
                       token_secret: q.secret,
                       realm_id: q.companyid,
                       consumer_key: '*****',
                       consumer_secret: '********')

OAuth2

  qbo_api = QboApi.new(access_token: 'REWR342532asdfae!$4asdfa', realm_id: 32095430444)

Super fast way to use QboApi no matter your current tech stack as long as Ruby > 2.2.2 is installed

- cd ~/<local dir>
- git clone [email protected]:minimul/qbo_api.git && cd qbo_api
- bundle
- bin/console
- QboApi.production = true
- # OAuth 1
- qboapi = QboApi.new(token: "qyprd2uvCOdRq8xzoSSiiiiii",
                      token_secret:"g8wcyQEtwxxxxxxm",
                      realm_id: "12314xxxxxx7",
                      consumer_key: "qyprdwzcxxxxxxbIWsIMIy9PYI",
                      consumer_secret: "CyDN4wpxxxxxxxPMv7hDhmh4")
- # OAuth 2
- qboapi = QboApi.new(access_token: "qyprd2uvCOdRq8xzoSSiiiiii", realm_id: "12314xxxxxx7")
- qboapi.get :customer, 1

TLS v1.2

Intuit will be requiring 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.

DateTime serialization

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. If ActiveSupport is loaded, you can achieve proper serialization with the following configuration:

ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
ActiveSupport::JSON::Encoding.time_precision = 0

If you're not using ActiveSupport, you'll need to use #iso8601 method to convert your Time/DateTime instances to strings before passing them to a QboApi instance. Failure to do so will result in a raised QboApi::BadRequest exception.

Configuration options

  • By default this client runs against a QBO sandbox. To run against the production QBO API URL do:
QboApi.production = true
  • Logging:
QboApi.log = true
  • To change logging target from $stdout e.g.
QboApi.logger = Rails.logger
QboApi.request_id = true
  • To run individual requests with a RequestId then do something like this:
  resp = qbo_api.create(:bill, payload: bill_hash, params: { requestid: qbo_api.uuid })
  # Works with .get, .create, .update, .query methods
QboApi.minor_version = 8
  • To run individual requests with a minor version then do something like this:
  resp = qbo_api.get(:item, 8, params: { minorversion: 8 })
  # Works with .get, .create, .update, .query methods

Create

  invoice = {
    "Line": [
      {
        "Amount": 100.00,
        "DetailType": "SalesItemLineDetail",
        "SalesItemLineDetail": {
          "ItemRef": {
            "value": "1",
            "name": "Services"
          }
        }
      }
    ],
    "CustomerRef": {
      "value": "1"
    }
  }
  response = qbo_api.create(:invoice, payload: invoice)
  p response['Id'] # => 65

Update

  customer = { 
    DisplayName: 'Jack Doe',
    PrimaryPhone: {
      FreeFormNumber: "(415) 444-1234"
    }
  }
  response = qbo_api.update(:customer, id: 60, payload: customer)
  p response.fetch('PrimaryPhone').fetch('FreeFormNumber') # => "(415) 444-1234"

Delete (only works for transaction entities)

  response = qbo_api.delete(:invoice, id: 145)
  p response['status'] # => "Deleted"

Deactivate (only works for name list entities)

  response = qbo_api.deactivate(:employee, id: 55)
  p response['Active'] # => false

Get an entity by its id

  response = qbo_api.get(:customer, 5)
  p response['DisplayName'] # => "Dukes Basketball Camp"

Get an entity by one of its filter attributes

  response = qbo_api.get(:customer, ["DisplayName", "Dukes Basketball Camp"])
  p response['Id'] # => 5

Get an entity by one of its filter attributes using a LIKE search

  response = qbo_api.get(:customer, ["DisplayName", "LIKE", "Dukes%"])
  p response['Id'] # => 5

Get an entity by one of its filter attributes using a IN search

  response = qbo_api.get(:vendor, ["DisplayName", "IN", "(true, false)"])
  p response.size # => 28

Search with irregular characters

  # Use the .esc() method
  name = qbo_api.esc "Amy's Bird Sanctuary"
  response = qbo_api.query(%{SELECT * FROM Customer WHERE DisplayName = '#{name}'})
  # OR USE .get() method, which will automatically escape
  response = qbo_api.get(:customer, ["DisplayName", "Amy's Bird Sanctuary"])
  p response['Id'] # => 1

Uploading an attachment

  payload = {"AttachableRef":
              [
                {"EntityRef": 
                  {
                    "type": "Invoice", 
                    "value": "111"
                  }
                }
              ],
             "FileName": "test.txt",
             "ContentType": "text/plain"
            }
  # `attachment` can be either an IO stream or string path to a local file
  response = qbo_api.upload_attachment(payload: payload, attachment: '/tmp/test.txt')
  p response['Id'] # => 5000000000000091308

Be aware that any errors will not raise a QboApi::Error, but will be returned in the following format:

  {"AttachableResponse"=>
    [{"Fault"=>
       {"Error"=>
         [{"Message"=>"Object Not Found",
           "Detail"=>
            "Object Not Found : Something you're trying to use has been made inactive. Check the fields with accounts, customers, items, vendors or employees.",
           "code"=>"610",
           "element"=>""}],
        "type"=>"ValidationFault"}}],
   "time"=>"2018-01-03T13:06:31.406-08:00"}

Change data capture (CDC) query

  response = qbo_api.cdc(entities: 'estimate', changed_since: '2011-10-10T09:00:00-07:00')
  # You can also send in a Time object e.g. changed_since: Time.now 
  expect(response['CDCResponse'].size).to eq 1
  ids = response['CDCResponse'][0]['QueryResponse'][0]['Estimate'].collect{ |e| e['Id'] }
  p ids

Batch operations (limit 30 operations in 1 batch request)

  payload = {
      "BatchItemRequest":
      [
        {
          "bId": "bid1",
          "operation": "create",
          "Vendor": {
            "DisplayName": "Smith Family Store"
          }
        }, {
          "bId": "bid2",
          "operation": "delete",
          "Invoice": {
            "Id": "129",
            "SyncToken": "0"
          }
        }
      ]
  }
  response = api.batch(payload)
  expect(response['BatchItemResponse'].size).to eq 2
  expect(batch_response.detect{ |b| b["bId"] == "bid1" }["Vendor"]["DisplayName"]).to eq "Smith Family Store"

Reports

        params = { start_date: '2015-01-01', end_date: '2015-07-31', customer: 1, summarize_column_by: 'Customers' }
        response = api.reports(name: 'ProfitAndLoss', params: params)
        p response["Header"]["ReportName"]) #=> 'ProfitAndLoss'

Reconnect

See docs

        response = qbo_api.reconnect
        #=> if response['ErrorCode'] == 0
        #=>   p response['OAuthToken'] #=> rewq23423424afadsdfs==
        #=>   p response['OAuthTokenSecret'] #=> ertwwetu12345312005343453yy=Fg

Disconnect

See docs

        response = qbo_api.disconnect
        #=> if response['ErrorCode'] == 0
        #=>   # Successful disconnect

Respond to an error

  customer = { DisplayName: 'Weiskopf Consulting' } 
  begin
    response = qbo_api.create(:customer, payload: customer)
  rescue QboApi::BadRequest => e
    if e.message =~ /Another customer already exists with this name/
      # Query for Id using DisplayName
      # Do an qbo_api.update instead
    end
  end

Import/retrieve all

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.

  # retrieves all active customers
  qbo_api.all(:customers).each do |c|
    p "#{c['Id']} #{c['DisplayName']}"
  end

  # retrieves all active or inactive employees
  qbo_api.all(:employees, inactive: true).each do |e|
    p "#{e['Id']} #{e['DisplayName']}"
  end

  # retrieves all vendors by groups of 5
  qbo_api.all(:vendor, max: 5).each do |v|
    p v['DisplayName']
  end
  
  # retrieves all customers by groups of 2 using a custom select query
  where = "WHERE Id IN ('5', '6', '7', '8', '9', '10')"
  qbo_api.all(:customer, max: 2, select: "SELECT * FROM Customer #{where}").each do |c|
    p c['DisplayName']
  end

What kind of QuickBooks entity?

  p qbo_api.is_transaction_entity?(:invoice) # => true
  # Plural is supported as well
  p qbo_api.is_transaction_entity?(:invoices) # => true
  p qbo_api.is_transaction_entity?(:customer) # => false
  p qbo_api.is_name_list_entity?(:vendors) # => true

If you signed up for a Intuit developer account after July 17th, 2017 follow this example

export QBO_API_CLIENT_ID=<Your QuickBooks Apps Client ID>
export QBO_API_CLIENT_SECRET=<Your QuickBooks Apps Client Secret>
  • Note: the .env file will be automatically loaded after you run the next step.
  • Start up the example app
    • ruby example/app.rb
  • Goto http://localhost:9393/oauth2
  • Use the Connect to QuickBooks button to connect to your QuickBooks sandbox, which you receive when signing up at https://developer.intuit.com.
  • After successfully connecting to your sandbox run:
    • http://localhost:9393/oauth2/customer/5
    • You should see "Dukes Basketball Camp" displayed
  • Checkout example/app.rb to see what is going on under the hood.

OAuth1: Spin up an example

OLD LEGACY - SEE OAUTH2 EXAMPLE ABOVE

export QBO_API_CONSUMER_KEY=<Your QuickBooks apps consumer key>
export QBO_API_CONSUMER_SECRET=<Your QuickBooks apps consumer secret>
  • Note: the .env file will be automatically loaded after you run the next step.
  • Start up the example app
    • ruby example/app.rb
  • Goto http://localhost:9393
  • Use the Connect to QuickBooks button to connect to your QuickBooks sandbox, which you receive when signing up at https://developer.intuit.com.
  • After successfully connecting to your sandbox run:
    • http://localhost:9393/customer/5
    • You should see "Dukes Basketball Camp" displayed
  • Checkout example/app.rb to see what is going on under the hood.

Webhooks

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/minimul/qbo_api.

Running the specs

export QBO_API_CONSUMER_KEY=
export QBO_API_CONSUMER_SECRET=
export QBO_API_ACCESS_TOKEN=
export QBO_API_ACCESS_TOKEN_SECRET=
export QBO_API_OAUTH2_ACCESS_TOKEN=
export QBO_API_COMPANY_ID=12345
  • bundle exec rspec spec/

Creating new specs or modifying existing spec that have been recorded using the VCR gem.

Protip: Once your .env file is completely filled out you can use the console to play around in your sandbox

bin/console test
>> q = QboApi.new(creds.to_h)
>> q = QboApi.new(oauth2_creds.to_h) # FOR OAuth2
>> q.get :customer, 1

License

The gem is available as open source under the terms of the MIT License.

About

Ruby JSON-only client for QuickBooks Online API v3. Built on top of the Faraday gem.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 95.6%
  • HTML 4.2%
  • Shell 0.2%