Giter Site home page Giter Site logo

quickbooks-ruby's Introduction

Important: Potential Breaking Changes

On Nov 10, 2022 version 2 was released which no longer supports Ruby 2.5.

quickbooks-ruby branch ruby
1 master <= 2.5
2 2-stable >= 2.6.0

Quickbooks-Ruby

Join the chat at https://gitter.im/ruckus/quickbooks-ruby

Build Status

Integration with Quickbooks Online via the Intuit Data Services v3 REST API.

This library communicates with the Quickbooks Data Services v3 API, documented at:

Data Services v3

Changes in 0.1.x from 0.0.x

0.1.0 introduced a backwards-incompatible change in how boolean attributes are handled. As of 0.1.0 any boolean like:

xml_accessor :active?, :from => 'Active'

will be accessible via active?. Thereby eliminating custom code like:

def active?
  active.to_s == 'true'
end

Now a call to active? that is not set will return nil. Otherwise it return true / false. Moreover, there is no longer a getter method e.g. active (without the trailing ?).

Requirements

This has been tested on 2.x

Ruby 1.9.x is not supported.

Dependencies

Gems:

  • oauth2
  • roxml : Workhorse for (de)serializing objects between Ruby & XML
  • nokogiri : XML parsing
  • active_model : For validations

Installation

Add this line to your application's Gemfile:

gem 'quickbooks-ruby'

And then execute:

$ bundle

Or install it yourself as:

$ gem install quickbooks-ruby

Sandbox Mode

An API app provides two sets of OAuth key for production and development. Since October 22, 2014, only Sandbox Companies are allowed to connected to the QBO via the development key. The end-point for sandbox mode is https://sandbox-quickbooks.api.intuit.com.

By default, the gem runs in production mode. If you prefer to develop / test the integration with the development key, you need to config the gem to run in sandbox mode:

Quickbooks.sandbox_mode = true

Getting Started & Initiating Authentication Flow with Intuit

What follows is an example using Rails but the principles can be adapted to any other framework / pure Ruby.

Create a Rails initializer (config/initializers/quickbooks-ruby.rb) with:

oauth_params = {
  site: "https://appcenter.intuit.com/connect/oauth2",
  authorize_url: "https://appcenter.intuit.com/connect/oauth2",
  token_url: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
}
oauth2_client = OAuth2::Client.new(ENV['OAUTH_CLIENT_ID'], ENV['OAUTH_CLIENT_SECRET'], oauth_params)

Your Controller action (the grantUrl above) should look like this:

def authenticate
  redirect_uri = quickbooks_oauth_callback_url
  grant_url = oauth2_client.auth_code.authorize_url(redirect_uri: redirect_uri, response_type: "code", state: SecureRandom.hex(12), scope: "com.intuit.quickbooks.accounting")
  redirect_to grant_url
end

Where quickbooks_oauth_callback_url is the absolute URL of your application that Intuit should send the user when authentication succeeds.

That action should look like:

def oauth_callback
  if params[:state].present?
    # use the state value to retrieve from your backend any information you need to identify the customer in your system
    redirect_uri = quickbooks_oauth_callback_url
    if resp = oauth2_client.auth_code.get_token(params[:code], redirect_uri: redirect_uri)
      # save your tokens here. For example:
      # quickbooks_credentials.update_attributes(access_token: resp.token, refresh_token: resp.refresh_token, realm_id: params[:realmId])
    end
  end
end

Your Redirect URI needs to be publicly accessible. If you are still in development and running everything via localhost you will need to use a tool like Ngrok to expose your localhost to a public URL with HTTPS.

Most likely you will want to persist the OAuth access credentials so that users don't need to re-authorize your application in every session.

An example database table could have fields likes:

access_token text,
access_token_expires_at datetime,
refresh_token text,
refresh_token_expires_at datetime,
realm_id text

Creating an OAuth Access Token

Once you have your user's OAuth access and refresh token string values you can create an access token object to issue requests:

qb_access_token = quickbooks_credentials.access_token
qb_refresh_token = quickbooks_credentials.refresh_token

access_token = OAuth2::AccessToken.new(oauth2_client, qb_access_token, refresh_token: qb_refresh_token)

Access Token Validity and Token Refresh

Each access token is only valid for one hour. The access token and refresh token can be refreshed directly by using OAuth Client:

new_access_token_object = access_token.refresh!

The token must be assigned to a variable to prevent the loss of your new access token, which will void your credentials and a new set of credentials have to be acquired by authorizing the application again. You should then persist it to your storage.

Unauthorized (expired) access to the API will raise a OAuth2::Error error.

For more information on access token expiration and refresh token expiration, please refer to the official documentation.

Refreshing Tokens

You will need to continuously refresh access tokens and ensure token validity. Access Tokens expire after 1 hour.

My personal architecture in a Rails application is similar to this:

# app/models/concerns/quickbooks_oauth.rb
module QuickbooksOauth
  extend ActiveSupport::Concern

  #== Instance Methods

  def perform_authenticated_request(&block)
    attempts = 0
    begin
      yield oauth_access_token
    rescue OAuth2::Error, Quickbooks::AuthorizationFailure => ex
      Rails.logger.info("QuickbooksOauth.perform: #{ex.message}")

      # to prevent an infinite loop here keep a counter and bail out after N times...
      attempts += 1

      raise "QuickbooksOauth:ExceededAuthAttempts" if attempts >= 3

      # check if its an invalid_grant first, but assume it is for now
      refresh_token!

      retry
    end
  end

  def refresh_token!
    t = oauth_access_token
    refreshed = t.refresh!

    if refreshed.params['x_refresh_token_expires_in'].to_i > 0
      oauth2_refresh_token_expires_at = Time.now + refreshed.params['x_refresh_token_expires_in'].to_i.seconds
    else
      oauth2_refresh_token_expires_at = 100.days.from_now
    end

    update!(
      oauth2_access_token: refreshed.token,
      oauth2_access_token_expires_at: Time.at(refreshed.expires_at),
      oauth2_refresh_token: refreshed.refresh_token,
      oauth2_refresh_token_expires_at: oauth2_refresh_token_expires_at
    )
  end

  def oauth_client
    self.class.construct_oauth2_client
  end

  def oauth_access_token
    OAuth2::AccessToken.new(oauth_client, oauth2_access_token, refresh_token: oauth2_refresh_token)
  end

  def consumer
    oauth_access_token
  end

  module ClassMethods

    def construct_oauth2_client
      options = {
        site: "https://appcenter.intuit.com/connect/oauth2",
        authorize_url: "https://appcenter.intuit.com/connect/oauth2",
        token_url: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
      }
      OAuth2::Client.new(ENV['INTUIT_OAUTH2_CLIENT_ID'], ENV['INTUIT_OAUTH2_CLIENT_SECRET'], options)
    end

  end
end

And then I have an IntuitAccount model with attributes:

 oauth2_access_token             | text                        |           |          |
 oauth2_access_token_expires_at  | timestamp without time zone |           |          |
 oauth2_refresh_token            | text                        |           |          |
 oauth2_refresh_token_expires_at | timestamp without time zone |           |          |
 track_purchase_order_quantity   | boolean                     |           | not null | false

And then finally include this concern in the model:

class IntuitAccount < ActiveRecord::Base
  include QuickbooksOauth
end

Pulled together usage is:

intuit_account = IntuitAccount.find(x)
intuit_account.perform_authenticated_request do |access_token|
  # do something here, like
  service = Quickbooks::Service::Customer.new
  service.company_id = "123" # also known as RealmID
  service.access_token = access_token # the OAuth Access Token you have from above
  customers = service.query()
end

Getting Started - Retrieving a list of Customers

The general approach is you first instantiate a Service object based on the entity you would like to retrieve. Lets retrieve a list of Customers:

service = Quickbooks::Service::Customer.new
service.company_id = "123" # also known as RealmID
service.access_token = access_token # the OAuth Access Token you have from above

# Equivalent to Quickbooks::Service::Customer.new(:company_id => "123", :access_token => access_token)

customers = service.query() # Called without args you get the first page of results

# yields

customers.entries = [ .. array of Quickbooks::Model::Customer objects .. ]
customers.start_position = 1 # the current position in the paginated set
customers.max_results = 20 # the maximum number of results in this query set

Under the hood Intuit uses a simple SQL-like dialect for retrieving objects, the above no-arg use of query() issued a Select * From Customer.

You can issue your own query by passing the complete and valid query as the first argument:

customers.query("Select Id, GivenName From Customer")

Each Entity has different fields you can retrieve & filter on. Refer to Intuit documentation for details.

Pagination

Do not pass pagination parameters in your query - pass them as additional options, using :page and :per_page:

# to use the default query
customers.query(nil, :page => 2, :per_page => 25)

# to use a custom query: find customers updated recently and only select a few attributes
query = "Select Id, GivenName From Customer Where Metadata.LastUpdatedTime>'2013-03-13T14:50:22-08:00' Order By Metadata.LastUpdatedTime"
customers.query(query, :page => 2, :per_page => 25)

Querying in Batches

Often one needs to retrieve multiple pages of records of an Entity type and loop over them all. Fortunately there is the query_in_batches collection method:

query = nil
Customer.query_in_batches(query, per_page: 1000) do |batch|
  batch.each do |customer|
    # ...
  end
end

The first argument to query_in_batches is the query (which can be nil to retrieve the default items in that collection). If you're are running a custom Query then pass it instead.

The second argument is the options, which are optional. By default, the options are per_page: 1000.

Retrieving all objects

You may retrieve an array of objects like so:

customers = service.all

Unlike other query functions which return a Quickbooks::Collection object, the all method returns an array of objects.

Retrieving a single object

You can retrieve a specific Intuit object like so:

customer = service.fetch_by_id("99")
puts customer.company_name
=> "Acme Enterprises"

Retrieving objects with matching attributes

The find_by(attribute, value) method allows you to retrieve objects with a simple WHERE query using a single attribute. The attribute may be given as a symbol or a string. Symbols will be automatically camelcased to match the Quickbooks API field names.

customer = service.find_by(:family_name, "Doe")
or
customer = service.find_by("FamilyName", "Doe")

Updating an object

By default updating an object will un-set any attributes that are NOT specified in the update request. That is, the update is NOT sparse by default. Thus, be careful as you might accidentally unset attributes that you did not specify.

Example:

# fetch a Customer to change their name
customer = service.fetch_by_id("99")
customer.company_name = "Neo Pets"
service.update(customer)

In the above example since we retrieved all fields and then just changed a single attribute, we have given the "complete" entity back to Intuit and effectively only the name is changed.

If you don't have the complete object on hand and only want to change a couple of attributes without un-setting what you are not specifying than you want to use a sparse update:

# update a Customer's name when we only know their ID
customer = Quickbooks::Model::Customer.new
customer.id = 99
customer.company_name = "New Company Name"
service.update(customer, :sparse => true)

Reference Setters

Some models require a reference to be set, to a Customer, or an Item, etc. In the Quickbooks API these references are labeled via a property like CustomerRef. In quickbooks-ruby the assignment of these references is done by using the setter on the _id property.

For example, to specify a Customer with ID 99 on an Invoice you would do this:

invoice = Quickbooks::Model::Invoice.new
invoice.customer_id = 99

This will automatically set a CustomerRef XML packet with a value of 99.

SalesReceipts & Ship Methods

The QBO API documentation states that SalesReceipt has a ShipMethodRef attribute. Normally, all attributes of a Ref type take an pseudo-integer argument, representing the foreign ID, which in turn point to a valid object with that ID.

I say pseudo because they look like Integers but Intuit has made it clear they should be handled as strings.

Anyways, its subtle but the value for a SalesReceipt#ShipMethodRef while it is a BaseReference needs to be set manually:

shipping_reference = Quickbooks::Model::BaseReference.new('FedEx', name: 'FedEx')
receipt.ship_method_ref = shipping_reference

Generating an Invoice

A complete example on generating a basic invoice:

# Given a Customer with ID=99 lets invoice them for an Item with ID=500
invoice = Quickbooks::Model::Invoice.new
invoice.customer_id = 99
invoice.txn_date = Date.civil(2013, 11, 20)
invoice.doc_number = "1001" # my custom Invoice # - can leave blank to have Intuit auto-generate it

line_item = Quickbooks::Model::InvoiceLineItem.new
line_item.amount = 50
line_item.description = "Plush Baby Doll"
line_item.sales_item! do |detail|
  detail.unit_price = 50
  detail.quantity = 1
  detail.item_id = 500 # Item ID here
end

invoice.line_items << line_item

service = Quickbooks::Service::Invoice.new
service.company_id = "123"
service.access_token = access_token
created_invoice = service.create(invoice)
puts created_invoice.id
=> 234

Notes: line_item.amount must equal the unit_price * quantity in the sales detail packet - otherwise Intuit will raise an exception.

Generating an Invoice containing a Bundle

Example (code fragments) of adding a bundle line item, to an invoice:

items = service.find_by(:sku, 'AHH_SWEETS')
bundle = items.entries.first
# be sure to check if you found the bundle you want
# ...

line_item = Quickbooks::Model::InvoiceLineItem.new
  line_item.description = bundle.description

  line_item.group_line_detail! do |detail|
    detail.id = bundle.id
    detail.group_item_ref = Quickbooks::Model::BaseReference.new(bundle.name, value: bundle.id)
    detail.quantity = 1

    bundle.item_group_details.line_items.each do |l|
      g_line_item = Quickbooks::Model::InvoiceLineItem.new
      g_line_item.amount = 50

      g_line_item.sales_item! do |gl|
        gl.item_id    = l.id
        gl.quantity   = 1
        gl.unit_price = 50
      end

      detail.line_items << g_line_item
    end
  end

  invoice.line_items << line_item

Emailing Invoices

The Quickbooks API offers a send invoice feature that sends the specified invoice model via email. By default the email is sent to the bill_email on the invoice. This feature returns an invoice model with updated email_status and delivery_info as shown below:

invoice = invoice_service.fetch_by_id("1")
sent_invoice = invoice_service.send(invoice)

puts sent_invoice.email_status
=> EmailSent
puts sent_invoice.delivery_info.delivery_type
=> Email
puts sent_invoice.delivery_info.delivery_time
=> Wed, 25 Feb 2015 18:56:04 UTC +00:00

It is possible to email the invoice to an altermate email address by including the email as a second parameter in the invoice.send method. When a new email address is provided the invoice model that is returned will have the bill_email set to the new email address as show below:

invoice = invoice_service.fetch_by_id("1")
sent_invoice = invoice_service.send(invoice, "[email protected]")

puts send_invoice.bill_email.address
=> name@domain.com

Notes: Quickbooks has global company settings to customize the send invoice email message content and format.

Generating a SalesReceipt

#Invoices, SalesReceipts etc can also be defined in a single command
salesreceipt = Quickbooks::Model::SalesReceipt.new({
  customer_id: 99,
  txn_date: Date.civil(2013, 11, 20),
  payment_ref_number: "111", #optional payment reference number/string - e.g. stripe token
  deposit_to_account_id: 222, #The ID of the Account entity you want the SalesReceipt to be deposited to
  payment_method_id: 333 #The ID of the PaymentMethod entity you want to be used for this transaction
})
salesreceipt.auto_doc_number! #allows Intuit to auto-generate the transaction number

line_item = Quickbooks::Model::Line.new
line_item.amount = 50
line_item.description = "Plush Baby Doll"
line_item.sales_item! do |detail|
  detail.unit_price = 50
  detail.quantity = 1
  detail.item_id = 500 # Item (Product/Service) ID here
end

salesreceipt.line_items << line_item

service = Quickbooks::Service::SalesReceipt.new({access_token: access_token, company_id: "123" })
created_receipt = service.create(salesreceipt)

Notes: In order to auto-generate transaction numbers using salesreceipt.auto_doc_number!, the 'Custom Transaction Numbers' setting under Company Settings>Sales Form Entry must be unchecked within the Quickbooks account you are posting to.

Deleting an Object

Use Service#delete which returns a boolean on whether the delete operation succeeded or not.

service.delete(customer)
=> returns boolean

Email Addresses

Email attributes are not just strings, they are top-level objects, e.g. EmailAddress on a Customer for instance.

A Customer has a setter method to make assigning an email address easier.

customer = Quickbooks::Model::Customer.new
customer.email_address = "[email protected]"

Telephone Numbers

Like Email Addresses, telephone numbers are not just basic strings but are top-level objects.

phone1 = Quickbooks::Model::TelephoneNumber.new
phone1.free_form_number = "97335530394"
customer.mobile_phone = phone1

Physical Addresses

Addresses are also top-level objects, so they must be instantiated and set.

address = Quickbooks::Model::PhysicalAddress.new

address.line1 = "2200 Mission St."
address.line2 = "Suite 201"
address.city = "Santa Cruz"
address.country_sub_division_code = "CA" # State, in United States
address.postal_code = "95060"
customer.billing_address = address

Batch Operations

You can batch operations such creating an Invoice, updating a Customer, etc. The maximum batch size is 25 objects.

How to use:

batch_req = Quickbooks::Model::BatchRequest.new

customer = Quickbooks::Model::Customer.new
# build the customer as needed
...

item = Quickbooks::Model::Item.new
# build the item as needed
...

batch_req.add("bId1", customer, "create")
batch_req.add("bId2", item, "create")

# Add more items to create/update as needed, up to 25

batch_service = Quickbooks::Service::Batch.new
batch_response = batch_service.make_request(batch_req)
batch_response.response_items.each do |res|
  puts res.bId
  puts res.fault? ? "error" : "success"
end

For complete details on Batch Operations see: https://developer.intuit.com/docs/api/accounting/batch

Query Building / Filtering

Intuit requires that complex queries be escaped in a certain way. To make it easier to build queries that will be accepted I have provided a basic Query builder.

util = Quickbooks::Util::QueryBuilder.new

# the method signature is: clause(field, operator, value)
clause1 = util.clause("DisplayName", "LIKE", "%O'Halloran")
clause2 = util.clause("CompanyName", "=", "Smith")

service.query("SELECT * FROM Customer WHERE #{clause1} AND #{clause2}")

Attachments

The Quickbooks API supports two different types of attachments, depending on whether you have an actual file to upload or just want to upload "meta-data" about an operation.

Meta-data only: use the Attachment service

meta = Quickbooks::Model::Attachable.new
meta.file_name = "monkey.jpg"
meta.note = "A note"
meta.content_type = "image/jpeg"
entity = Quickbooks::Model::BaseReference.new(3, type: 'Customer')
meta.attachable_ref = Quickbooks::Model::AttachableRef.new(entity)

Note: No actual file is being attached, we are just describing a file.

Uploading an actual file

upload_service = Quickbooks::Service::Upload.new

# args:
#     local-path to file
#     file mime-type
#     (optional) instance of Quickbooks::Model::Attachable - metadata
result = upload_service.upload("tmp/monkey.jpg", "image/jpeg", attachable_metadata)

If successful result will be an instance of the Attachable model:

puts attach.temp_download_uri

=> "https://intuit-qbo-prod-29.s3.amazonaws.com/12345%2Fattachments%2Fmonkey-1423760870606.jpg?Expires=1423761772&AWSAcc ... snip ..."

Download PDF of an Invoice, SalesReceipt or Payment

To download a PDF of an Invoice:

service = Quickbooks::Service::Invoice.new # or use the SalesReceipt service

# +invoice+ is an instance of Quickbooks::Model::Invoice
raw_pdf_data = service.pdf(invoice)

# write it to disk
File.open("invoice.pdf", "wb") do |file|
  file.write(raw_pdf_data)
end

Change Data Capture

Quickbooks has an api called Change Data Capture that provides a way of finding out which Entities have recently changed, as deleted entities will not be returned by a standard query. It is possible to request changes up to 30 days ago.

The primary method for querying to ChangeDataCapture is through Quickbooks::Service::ChangeDataCapture.

Quickbooks::Model::ChangeDataCapture also supports parsing the XML response into a hash of entity types through the all_types method.

service = Quickbooks::Service::ChangeDataCapture.new
...
# define the list of entities to query
entities = ["Invoice", "Bill", "Payment"] #etc
changed = service.since(entities, Time.now.utc - 5.days)
...
# parse the XML to a list of Quickbooks::Models
changed_as_hash = changed.all_types

Deleted entities can be found in the XML by checking their @status is "Deleted". In the return from the all_types method, deleted items will be of type Quickbooks::Model::ChangeModel.

see: https://developer.intuit.com/docs/0100_quickbooks_online/0200_dev_guides/accounting/change_data_capture for more information.

ChangeModel alternative Change Data Capture For Invoices, Customers, Vendors, Items, Payments, Purchases and Credit Memos

It is possible to get a sparse summary of which Invoice, Customer, Vendor, Item, Payment, Purchase or Credit Memo Entries have recently changed. It is possible to request changes up to 30 days ago.

service = Quickbooks::Service::InvoiceChange.new
...
changed = service.since(Time.now.utc - 5.days)
customer_service = Quickbooks::Service::CustomerChange.new
...
customer_changed = customer_service.since(Time.now.utc - 5.days)
vendor_service = Quickbooks::Service::VendorChange.new
...
vendor_changed = vendor_service.since(Time.now.utc - 5.days)
item_service = Quickbooks::Service::ItemChange.new
...
item_changed = item_service.since(Time.now.utc - 5.days)

see: https://developer.intuit.com/docs/0100_quickbooks_online/0200_dev_guides/accounting/change_data_capture for more information.

Reports API

Quickbooks has an API called the Reports API that provides abilities such as: business and sales overview; vendor and customer balances; review expenses and purchases and more. See the specs for examples of how to leverage.

JSON support

Intuit started the v3 API supporting both XML and JSON. However, new v3 API services such as Tax Service will only support JSON. This gem has roots in the v2 API, which was XML only, and hence was constructed supporting XML only.

Logging

Set the default log enablement:

Quickbooks.log = true

Configure a service instance to log (or not) independently:

customer_service = Quickbooks::Service::Customer.new
customer_service.log = true

By default, logging is directed at STDOUT, but another target may be defined, e.g. in Rails

Quickbooks.logger = Rails.logger
Quickbooks.log = true
# Pretty-printing logged xml is true by default
Quickbooks.log_xml_pretty_print = false

Debugging

While logging is helpful the best debugging (in my opinion) is available by using a HTTP proxy such as Charles Proxy.

To enable HTTP proxying, add something like the following connection_opts when you generate your OAuth Client:

oauth_params = {
  site: "https://appcenter.intuit.com/connect/oauth2",
  authorize_url: "https://appcenter.intuit.com/connect/oauth2",
  token_url: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
  connection_opts: {
    proxy: {uri: "http://127.0.0.1:8888"},
    ssl: {verify: false}  # assuming a self-signed cert is used by your proxy
  }
}
oauth2_client = OAuth2::Client.new(ENV['OAUTH_CLIENT_ID'], ENV['OAUTH_CLIENT_SECRET'], oauth_params)

Entities Implemented

Entity Create Update Query Delete Fetch by ID Other
Account yes yes yes yes yes
Attachable no no no no no
Bill yes yes yes yes yes
Bill Payment yes yes yes yes yes
Class yes yes yes yes yes
Company Info n/a n/a yes n/a yes
Credit Memo yes yes yes yes no
Customer yes yes yes yes yes
Department yes yes yes yes yes
Deposit yes yes yes yes yes
Employee yes yes yes yes yes
Entitlements no no no no no
Estimate yes yes yes yes yes
Invoice yes yes yes yes yes
Item yes yes yes yes yes
Journal Entry yes yes yes yes yes
Payment yes yes yes yes yes
PaymentMethod yes yes yes yes yes
Preferences n/a no yes n/a yes
Purchase yes yes yes yes yes
Purchase Order yes yes yes yes yes
Refund Receipt yes yes yes yes yes
Sales Receipt yes yes yes yes yes
Sales Rep no no no no no
Sales Tax no no no no no
Sales Term no no no no no
Tax Agency yes yes yes yes yes
Tax Code no no yes no no
Tax Rate yes yes yes no no
*Tax Service yes yes no no no
Term yes yes yes yes yes
Time Activity yes yes yes yes yes
Tracking Class no no no no no
Vendor yes yes yes yes yes
Vendor Credit yes yes yes yes yes

*JSON only

Related GEMS

quickbooks-ruby-base: Complements quickbooks-ruby by providing a base class to handle routine tasks like creating a model, service, and displaying information.

qbo_rails: Simple Rails error handling and QuickBooks Online "Id" persistence. Uses quickbooks-ruby.

TODO

  • Implement other Line Item types, e.g. DescriptionLineDetail for Invoices
  • Full JSON support

Author

Cody Caughlan

Contributors

quickbooks-ruby has been a community effort and I am extremely thankful for all the amazing contributors.

License

The MIT License

Copyright (c) 2013

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

quickbooks-ruby's People

Contributors

anaprimawaty avatar arthurchui avatar barelyknown avatar benzittlau avatar cohendvir avatar danielnho22 avatar divya-eligible avatar drewish avatar evanwalsh avatar florinpatrascu avatar gouravmodi avatar huoxito avatar jasondew avatar jimmybaker avatar jordangraft avatar kashif-umair avatar kirley avatar lmatiolis avatar markrickert avatar minimul avatar muhammad-abubakar avatar nathan-mots avatar nikz avatar pachkovsky avatar raksonibs avatar ratbeard avatar ruckus avatar sequielo avatar vanboom avatar whereisciao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quickbooks-ruby's Issues

Invoice Preferences

There doesn't seem to be a way to set the Invoice terms and to_be_email variable to allow email delivery in this version as there were in Quickeebooks.

Can't Access Customer Currency

Hi, I raised 130 - turned out to be an Intuit bug, but I now need the customer currency and it is in the response but doesn't seem to come through the model. I can get it fine (as the name and value hash) for the other entities where I need it i.e. vendors, invoice lines and bill lines.

e.g. fake company below

 ------ QUICKBOOKS-RUBY REQUEST ------
METHOD = get
RESOURCE = https://qb.sbfinance.intuit.com/v3/company/1230511455/customer/5
REQUEST BODY:
{}
REQUEST HEADERS = {"Content-Type"=>"application/xml", "Accept"=>"application/xml",   "Accept-Encoding"=>"gzip, deflate"}
Completed 200 OK in 1545ms (Views: 1.1ms | ActiveRecord: 27.7ms)
 ------ QUICKBOOKS-RUBY RESPONSE ------
 RESPONSE CODE = 200
 RESPONSE BODY:
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <IntuitResponse xmlns="http://schema.intuit.com/finance/v3" time="2014-06-  30T05:00:18.470-07:00">
  <Customer domain="QBO" sparse="false">
    <Id>5</Id>
 <SyncToken>1</SyncToken>
<MetaData>
  <CreateTime>2014-06-23T08:49:53-07:00</CreateTime>
  <LastUpdatedTime>2014-06-23T08:53:04-07:00</LastUpdatedTime>
</MetaData>
<FullyQualifiedName>Delta Services ltd.</FullyQualifiedName>
<CompanyName>Delta Services ltd.</CompanyName>
<DisplayName>Delta Services ltd.</DisplayName>
<PrintOnCheckName>Delta Services ltd.</PrintOnCheckName>
<Active>true</Active>
<Taxable>false</Taxable>
<Job>false</Job>
<BillWithParent>false</BillWithParent>
<Balance>0</Balance>
<BalanceWithJobs>0</BalanceWithJobs>
<CurrencyRef name="British Pound Sterling">GBP</CurrencyRef>
<PreferredDeliveryMethod>Email</PreferredDeliveryMethod>
{"id"=>5, "sync_token"=>1, "meta_data"=>{"create_time"=>2014-06-23 16:49:53 +0100, "last_updated_time"=>2014-06-23 16:53:04 +0100}, "title"=>nil, "given_name"=>nil, "middle_name"=>nil, "family_name"=>nil, "company_name"=>"Delta Services ltd.", "display_name"=>"Delta Services ltd.", "print_on_check_name"=>"Delta Services ltd.", "active?"=>true, "primary_phone"=>nil, "alternate_phone"=>nil, "mobile_phone"=>nil, "fax_phone"=>nil, "primary_email_address"=>nil, "web_site"=>nil, "billing_address"=>nil, "shipping_address"=>nil, "job"=>"false", "bill_with_parent"=>"false", "parent_ref"=>nil, "level"=>nil, "sales_term_ref"=>nil, "payment_method_ref"=>nil, "balance"=>#<BigDecimal:7ff5f1b7edc0,'0.0',9(18)>, "open_balance_date"=>nil, "balance_with_jobs"=>#<BigDecimal:7ff5ed890130,'0.0',9(18)>, "preferred_delivery_method"=>"Email", "resale_num"=>nil, "suffix"=>nil, "fully_qualified_name"=>"Delta Services ltd.", "taxable"=>"false", "notes"=>nil}

Is it possible to set a customer_id while creating a new customer?

Is it possible to set a customer_id (for eg: their unique user_id in the Rails app), so that we can also generate Invoices / Sales Receipt for the customer with the same id?

If we can't, are there any other ways to creating Invoices / Sales receipts for particular customers?

Usecase: I'll be creating customers on QBO only after they initiate a transaction, and later on refer to the recently created customer_id to record payment / generate invoices / sales receipts, etc.

How to add a line item to an invoice?

Hey guys, thank you so much for this library!

I'm trying to figure out how to add a new line item to an existing invoice. Do I use the Invoice Service? Or the Item Service? If you have any reference URLs for me, I'd be most appreciative.

Thanks in advance for your help for rookies like me :)

Add Company

Hi,

I tried create company with name Children's
and got error

Display name :display_name cannot contain a colon (:).

also, can you update gem in rubygems
QueryBuilder not available from there.

Thanks!

Undefined method 'each' for InvoiceLineItem

I keep getting this when it hits: created_invoice = service.create(invoice)

NoMethodError (undefined method 'each' for #<Quickbooks::Model::InvoiceLineItem:0x007ffadb78f310>): lib/quickbooks_api/model/base_model.rb:14:in 'to_xml_inject_ns' lib/quickbooks_api/model/base_model.rb:26:in 'to_xml_ns' lib/quickbooks_api/service/service_crud.rb:20:in 'create'

Support Refund Receipts

Refund receipts were just recently added to the api, docs can be found here.

An app I am working on requires this integration so I have forked the repo and will take a stab at adding support myself.

NameError: uninitialized constant Quickbooks

I am getting following errors, when I am trying to instantiate a customer service:

service = Quickbooks::Service::Customer.new

NameError: uninitialized constant Quickbooks

[NOTE: Quickbooks connection is successful and is able to generate new access_token, access_secret and realmid].

Should the Collection class implement Enumberable.

Either with or without support for pagination?

You can call enumerable methods on #entries, but it seems like the collection should implement it, even if it just delegates 'each' to entries.

It seems easy to add an #each, and get a lot of nice stuff.

Uploading a file (pdf, jpeg, xls....)

I've got a Python script which is supposed to upload files to Quick Books by their API. I've faced into some issues which I couldn't have solved such as "This type can't be consumed" (for application/pdf, xml and others) or when I used "multipart/form-data" it said "Could find no content-disposition header with in a part" or when I'd changed it a bit, it seemed to work well (there were no errors in the response) but the attachments weren't really uploaded.

I'd like to upload a file (pdf, jpeg, xls....) using this gem to make sure it really works well and there is no mistake in the API of Quick Books. I'm familiar with this gem but didn't find a model or service in its source code which looked like the one I was looking for (Attachable, File or something else).

So is there any simple example?

Bad Error message with no company ID

If you make a query without setting the realm, you just get "RuntimeError: HTTP Error Code: 404" with a HTML error message from Intuit. I can imagine a few reasonable things that could happen:

  • Since (I think) each token is only good for the realm, we could wrap the OAuth::AccessToken with something that keeps track of the realm for the token.
  • We could raise a better exception if there is no realm id. I /think/ that every endpoint requires it, so it could check in BaseService.
  • There might be some way to figure out what it should be with an API call, but I don't think so.

If you tell me which you think is best, I'll be happy it implement it.

Unable to query resources using where and operators?

Hi!

Thanks for the gem ๐Ÿป!

I've been trying to query the Item service like this:

item_service.query "select * from Item where Name = 'Something'"

But I always get:

IntuitRequestException: An application error has occurred while processing your request

Regardless of the presence of the record.

This is what the request looks like:

RESOURCE = https://qb.sbfinance.intuit.com/v3/company/<id>/query?query=select%20*%20from%20Item%20where%20Name%20=%20'Something'%20STARTPOSITION%201%20MAXRESULTS%2020
BODY(Hash) = {}
HEADERS = {"Content-Type"=>"application/xml"}

I've managed to successfully perform this request on the APIExplorer, and the request created by your gem looks perfect.

Do you have any suspicion on what might be happening?

Random odd error during invoice generation

Getting this error, even though I'm not invoking the PhysicalAddress model at all.

ArgumentError (lat: invalid value for Float(): "INVALID" for class Quickbooks::Model::PhysicalAddress for class Quickbooks::Model::Invoice):

Possible to create a persistent connection between QBO and a Rails app?

Is there anyway I can create a persistent connection between our app and QBO without requiring the "Connect to QuickBooks" button or the oauth_callback token & secret or atleast persisting it to the DB or saving as constants (realmID, etc) in the app after getting it once or do they have a preset TTL?

Having trouble with apostrophes in queries

I am trying to search a customer with an apostrophe in the name. The query that the query explorer generates is

Select * from customer where companyname %3D'mcgee%5C's'

which returns the correct data. The gem generates the following query which fails

Select+*+from+customer+where+companyname+%3D%27mcgee%255C%27s%27

The query builder uses URI.encode_www_form_component to generate the proper encoded string but i think apostrophes need to be ignored.

Creating SalesReceipt (& SalesItemLineDetail).

I've been trying to create a SalesReceipt unsuccessfully. I've looked at the spec examples, but I keep running into a few errors.

  1. undefined method each' for #<Quickbooks::Model::Line:0x007fac35488558> if I addModel::Line` as given in the specs.
  2. I get various different errors if I opt for Model::SalesItemLineDetail, such as the one above (with a different model name), or this undefined method to_xml for "[email protected]":String`

Sparse update and inactivate name list entities with batch operation

There are 2 related issues:

  1. The interface of BatchRequest#add does not take options (e.g. sparse). Changing that seems non-trivial.
  2. Similar to Customer#delete, the batch operation should be smart enough to inactivate a Name List Entity instead of deleting it. When the operation is set to "delete", BatchRequest#add can covert the operation to "update" and set active = false as a sparse update.

System Failure Error when Updating Purchase Order

Hey Guys:

Not too sure if this error is just specific to my account or not, but when updating a purchase order i get the following error:

System Failure Error: Could not find resource for relative

Has anyone encountered this before?

Issues with updating :track_quantity_on_hand? field in Item Model

Hey Guys:

Seeing an issue when trying to update the :track_quantity_on_hand field in the Item. So for instance, if I want to set that particular field to True, and I assign a date value to the :inv_start_date field in addition to assigning a BigDecimal value to the :quantity_on_hand field, and then when I call the .update on the Item Service, I get the below error. I've done a bit of research and I'm thinking this may be an error on QB's side but not completely positive. Has anyone seen this error before?

Quickbooks::IntuitRequestException: An application error has occurred while processing your request:
System Failure Error: java.lang.NullPointerException
from /Users/sunnyisrani/.bundler/ruby/1.9.1/quickbooks-ruby-141059e9b88b/lib/quickbooks/service/base_service.rb:258:in parse_and_raise_exception' from /Users/sunnyisrani/.bundler/ruby/1.9.1/quickbooks-ruby-141059e9b88b/lib/quickbooks/service/base_service.rb:243:incheck_response'
from /Users/sunnyisrani/.bundler/ruby/1.9.1/quickbooks-ruby-141059e9b88b/lib/quickbooks/service/base_service.rb:212:in do_http' from /Users/sunnyisrani/.bundler/ruby/1.9.1/quickbooks-ruby-141059e9b88b/lib/quickbooks/service/base_service.rb:176:indo_http_post'
from /Users/sunnyisrani/.bundler/ruby/1.9.1/quickbooks-ruby-141059e9b88b/lib/quickbooks/service/service_crud.rb:47:in update' from (irb):17 from /Users/sunnyisrani/.rvm/gems/ruby-1.9.3-p448/gems/railties-4.0.0/lib/rails/commands/console.rb:90:instart'
from /Users/sunnyisrani/.rvm/gems/ruby-1.9.3-p448/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in start' from /Users/sunnyisrani/.rvm/gems/ruby-1.9.3-p448/gems/railties-4.0.0/lib/rails/commands.rb:64:in<top (required)>'
from bin/rails:4:in require' from bin/rails:4:in

'

Drop 1.8.7/REE support?

Hello! While working with the gem, we noticed it is locked to the last version of nokogiri that supports 1.8.7. However, when you do a fresh install of the gem, it grabs the latest activemodel (and activesupport) that only supports 1.9.3.

Is there a reason why REE support is being kept in?

Serialize Collection or Array of objects (entries)?

Hi there. Thanks for a great gem.

A quick question. I would like to serialize and persist the query or query_in_batches result (for debugging purposes). I would normally use Marshal.dump, but Marshal doesn't support singleton_methods (same problem with to_yaml and procs).

Have anyone been able to accomplish something similar?

Query error with quotes

when you try select Customer with Name = 'Children's etc....'
request like this - you get an error
customer = @service.query("SELECT * FROM CUSTOMER WHERE DisplayName = '#{company.name[0..49]}'").entries.first
if you try use gsub("'", "'") for escape quote it's doesn't work correct

System Failure Error: Bad arguments passed

When I try to create an Invoice, I am getting the following error:

/Users/dlindahl/app/qbo/.bundle/gems/quickbooks-ruby-0.0.5/lib/quickbooks/service/base_service.rb:268:in `parse_and_raise_exception': An application error has occurred while processing your request: (IntuitRequestException)
  System Failure Error: Bad arguments passed to public com.intuit.schema.finance.v3.IntuitResponse com.intuit.qbo.servicev3.rest.Customer.create(java.lang.String,com.intuit.schema.finance.v3.Customer,java.lang.String,java.lang.String,java.lang.String) throws com.intuit.qbo.servicev3.FdmException  ( java.lang.String 1032845425, com.intuit.schema.finance.v3.Invoice com.intuit.schema.finance.v3.Invoice@59687eb7, null, null, null )
  from /Users/dlindahl/app/qbo/.bundle/gems/quickbooks-ruby-0.0.5/lib/quickbooks/service/base_service.rb:255:in `check_response'
  from /Users/dlindahl/app/qbo/.bundle/gems/quickbooks-ruby-0.0.5/lib/quickbooks/service/base_service.rb:228:in `do_http'
  from /Users/dlindahl/app/qbo/.bundle/gems/quickbooks-ruby-0.0.5/lib/quickbooks/service/base_service.rb:194:in `do_http_post'
  from /Users/dlindahl/app/qbo/.bundle/gems/quickbooks-ruby-0.0.5/lib/quickbooks/service/service_crud.rb:17:in `create'
  from /Users/dlindahl/app/qbo/lib/qbo/tasks/invoicing.rb:63:in `create'
  from /Users/dlindahl/app/qbo/.bundle/gems/thor-0.18.1/lib/thor/command.rb:27:in `run'
  from /Users/dlindahl/app/qbo/.bundle/gems/thor-0.18.1/lib/thor/invocation.rb:120:in `invoke_command'
  from /Users/dlindahl/app/qbo/.bundle/gems/thor-0.18.1/lib/thor.rb:363:in `dispatch'
  from /Users/dlindahl/app/qbo/.bundle/gems/thor-0.18.1/lib/thor/base.rb:439:in `start'
  from bin/qbo:5:in `<main>'

Any ideas what I'm missing or might be doing wrong?

The invoice and line item validations return true if that helps weed out anything.

Feature: Implement Reports API

It looks like QBO recently exposed a reports API. I'd like to take a stab at implementing some of the more important reports (Balance Sheet, P&L).

Any tips as to approach? I was planning to create a Report base class and inherit for the individual reports, but I'm not sure how much is shared.

Standard way to page through collections

It feels like there should be a standard way to page through a Quickbooks::Collection instance.

I'm currently using something like this pattern most of the time.

page = 1
begin
  results = Vendor.query(nil, page: page, per_page: 1_000)
  results.entries.each do |entry|
    # ...
  end
  page += 1
end until results.count < per_page

I'd be happy to implement the feature but wanted to get thoughts from others about the design before I start. Is this something that others would want to? Are there any thoughts about the design?

Error calculating max_results when using paging options.

IntuitRequestException: Invalid query:
QueryValidationError: value 1500 is too large. Max allowed value is 1000

The relevant line is in base_service.rb line 100. When calculating max_results you shouldn't multiply by the page number. That will keep increasing the max_results value until it overruns the maximum value allowed by Quickbooks online.

I believe the line should be:
max_results = per_page

Getting all results from a given service

Not an issue per se, but I figured I'd post my methodology for getting ALL records from a given service using the drained design pattern.

Lets take customers for instance. I've got more than 1000 customers, so I'm going to have to make more than one API call to get these customers. Here's how I'm doing it:

class QuickbooksHelper
  def self.all_customers
    all('Customer')
  end

  def self.all(model)
    drained = false
    page = 1
    count = 1000
    v = []
    while !drained
      res = new_service(model).query("Select * From #{model}", :page => page, :per_page => count)
      v.concat(res.entries)
      page = page + 1
      drained = true if res.entries.count < count
    end
    v
  end

  def self.new_service(name)
    service_class = "Quickbooks::Service::#{name}".split('::').inject(Object) {|o,c| o.const_get c}
    service_class.new(access_token: access_token, company_id: REALM)
  end
end

# Now I can get all customers by using:
QuickbooksHelper.all_customers

Wondering if this might be something we might want to integrate into the base service class so that we can do something like:

customers_service = Quickbooks::Service::Customer.new
all_customers = customers_service.all

This would provide a more "activerecord" style interface for getting all the results from the api. If we don't integrate it into the base service class, at least this comment is here for people to reference ๐Ÿ˜„

Documentation needs update for Rails 4.1

The Rails 4.1 session api changed a bit, so you'd have to use

session[:qb_request_token] = Marshal.dump(token)
and
at = Marshal.load(session[:qb_request_token]).get_access_token(:oauth_verifier => params[:oauth_verifier])

I'll be happy to make a PR, if you like.

Payment against invoices

Is there anyway I can create a payment against a specific invoice id? I was looking at payment.rb, but wasn't sure where to set the invoice id. Any ideas?

Can't access Bill line item line_num

New to Quickbooks and API-ing it Making good headway with your gem (big Tx) but can't seem to retrieve the line number of bill lines - I can do this for invoices no problem, and I can get various other attributes of the bill line e.g. description.

Still checking my code and not a confident enough developer to be sure but think there may be an issue.

Note. as part of my troubleshoot I checked the intuit API to make sure attributes were mapped OK - it is there. However, I used the API explorer on the Intuit dev site to query a test bill and test invoice - the line numbers do get returned for the invoice but not the bill. Both test records were created in QuickBooks and appear to have line numbers. Is this an Intuit problem?

Nokogirl exception

I get a XPath::SyntaxError on parsing a sales receipt. I don't know xpath too well but looking into it.

The sales receipt is created

Any suggestions?

Exception:

Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: //xmlns:IntuitResponse/xmlns:SalesReceipt
    from /Users/jwils/.rvm/gems/ruby-2.0.0-p353@intuit_clover/gems/nokogiri-1.5.11/lib/nokogiri/xml/node.rb:159:in `evaluate'
    from /Users/jwils/.rvm/gems/ruby-2.0.0-p353@intuit_clover/gems/nokogiri-1.5.11/lib/nokogiri/xml/node.rb:159:in `block in xpath'
    from /Users/jwils/.rvm/gems/ruby-2.0.0-p353@intuit_clover/gems/nokogiri-1.5.11/lib/nokogiri/xml/node.rb:150:in `map'
    from /Users/jwils/.rvm/gems/ruby-2.0.0-p353@intuit_clover/gems/nokogiri-1.5.11/lib/nokogiri/xml/node.rb:150:in `xpath'    

Steps to reproduce

service = Quickbooks::Service::SalesReceipt.new
service.company_id = [relm_id]
service.access_token = [access_token]

line = Quickbooks::Model::Line.new
line.line_num = 1
line.description = "My first order."
line.amount = 4.00
line.detail_type = 'SalesItemLineDetail'
detail = Quickbooks::Model::SalesItemLineDetail.new
line.sales_item_line_detail = detail

detail.unit_price = 4.00
detail.quantity = 1

receipt = Quickbooks::Model::SalesReceipt.new


receipt.line_items = [line]

receipt.placed_on = Time.now

service.create(receipt)

inconsistancy in EmailAddress and Phone number.

To make a new customer, for instance, you (I think) say:

Quickbooks::Model::Customer.new(
...
primary_email_address: Quickbooks::Model::EmailAddress.new("[email protected]"), 
primary_phone: Quickbooks::Model::TelephoneNumber.new(free_form_number: "123.123.1234")

It seems like at the least, either phone number should be able to be initialized with a string, or email address should be able to be initialized with a hash. Perhaps each should take both.

Thoughts?

Nokogiri runtime dependency version

First, thank you for creating this gem. It's a huge help for me!

quickbooks-ruby has a runtime dependency on Nokogiri ~>1.5.9. Is there a reason it can't be bumped to 1.6.1?

The 1.6.0 release of Nokogiri was a big one, as it now "compiles libxml2 and libxslt with the gem. This should fix most installation issues." The 1.5.9 dependency in a Rails Gemfile conflicts with gems with runtime dependencies on more recent versions of Nokogiri - capybara and roo to name two.

I forked, bumped the version, and ran the specs. Everything passes, but I don't know if there are bigger upstream concerns for quickbooks-ruby.

Unable to create an invoice

I'm sure not whether this is bug or not. Here is my code of creating an invoice:

def create_invoice_test
  current_user.invoices do |invoice|
    data = { 
      "Line" => [
        {
          "Amount" => 100.00, 
          "DetailType" => "SalesItemLineDetail", "SalesItemLineDetail" => {"ItemRef" => {value: 1, name: "Services"}}
        }
      ],
      "CustomerRef" => {value: 21}
    }

    consumer = create_consumer
    response = consumer.post "https://quickbooks.api.intuit.com/v3/company/#{my_company_id}/invoice", data
    p "-------response:-------", response
  end
end

def create_consumer
    access_token = current_user.organization.qb_access_token
    access_token_secret = current_user.organization.qb_access_token_secret
    OAuth::AccessToken.new(QuickBooksHelper.oauth_consumer, access_token, access_token_secret)
end

It doesn't print anything. What am I doing wrong? How do I create an invoice?
Yes, I'm using quickbooks-ruby gem.

Hardy Service

Hey there, so I'm working with this gem heavily now and I'm wondering if it would make sense to implement some kind of "hardy service" like the Harvested gem has... essentially instead of throwing an error when the server rate-limits the calls, it would detect the rate limiting and wait the appropriate amount of time before calling the same request over again.

Thoughts on a mechanism like this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.