freshbooks_client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +10 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/README.md +8 -0
- data/Rakefile +10 -0
- data/bin/console +23 -0
- data/bin/setup +7 -0
- data/freshbooks_client.gemspec +32 -0
- data/lib/freshbooks.rb +30 -0
- data/lib/freshbooks/api/callback.rb +23 -0
- data/lib/freshbooks/api/category.rb +8 -0
- data/lib/freshbooks/api/client.rb +8 -0
- data/lib/freshbooks/api/contractor.rb +8 -0
- data/lib/freshbooks/api/crud.rb +61 -0
- data/lib/freshbooks/api/currency.rb +8 -0
- data/lib/freshbooks/api/default_term.rb +21 -0
- data/lib/freshbooks/api/email_template.rb +8 -0
- data/lib/freshbooks/api/estimate.rb +34 -0
- data/lib/freshbooks/api/expense.rb +8 -0
- data/lib/freshbooks/api/gateway.rb +8 -0
- data/lib/freshbooks/api/invoice.rb +41 -0
- data/lib/freshbooks/api/item.rb +8 -0
- data/lib/freshbooks/api/language.rb +8 -0
- data/lib/freshbooks/api/methods.rb +119 -0
- data/lib/freshbooks/api/no_cd.rb +15 -0
- data/lib/freshbooks/api/no_crud.rb +18 -0
- data/lib/freshbooks/api/no_crudl.rb +15 -0
- data/lib/freshbooks/api/payment.rb +8 -0
- data/lib/freshbooks/api/project.rb +8 -0
- data/lib/freshbooks/api/receipt.rb +12 -0
- data/lib/freshbooks/api/recurring.rb +26 -0
- data/lib/freshbooks/api/report.rb +33 -0
- data/lib/freshbooks/api/staff.rb +13 -0
- data/lib/freshbooks/api/system.rb +14 -0
- data/lib/freshbooks/api/task.rb +8 -0
- data/lib/freshbooks/api/tax.rb +8 -0
- data/lib/freshbooks/api/time_entry.rb +8 -0
- data/lib/freshbooks/client.rb +169 -0
- data/lib/freshbooks/version.rb +3 -0
- metadata +252 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 748fc62390ccbf1098d43cd5fb6d90fd02a99b6f
|
4
|
+
data.tar.gz: 377f8cb452c673762cf61764b2e3d06e83f48294
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 27b485e8a759689419a28cce1a15399f896dc8e61e53034b83ddfbe29aa62bf2f833e311917937f68ef6b4c64dc607b8e37720770252a2f4ac506bec9600c70a
|
7
|
+
data.tar.gz: 9194fef7e8739d2d04590583fee7e0895d3bf078255863d773832a44b203cf7a1b8d7bd24cbfb5e7b345d5e0d8e14d91cf9d81b21bebbe9b54670e325dba977a
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.2.2
|
4
|
+
before_install: gem install bundler -v 1.10.5
|
5
|
+
env:
|
6
|
+
global:
|
7
|
+
- secure: Cj3e9OkrWcIUvjW7hsVwMlBOPdZaiVw163xig0gIi/L5V7wQXj3cDj2V0kHBuo9NGGp18E91TBOhhWFuYLRCnsE/1K3YLB7B9zvyvw/ZB9Sy2EovlieJksd8c5kf5mM4hip68Aer9v7VuC5WMB/NfDWgPfVy5n8G+Uu1Dtdw9fHEouIthExubGW7f/gZ+L5/VHfWZkaC2Rqb+3UVIYjpNre/+8ihOdWI0LVd1Xz3n7mKmKNzu/CZlE1QkP25q2OQ9dEvxX3+Y6NtBLdDk5V6y7/pbB3+JfuAF3hgio2KKp7BnLimMbip3tQ3ZyhVYRrnLVjOJnHsIYHacgb5h9Hs4wcN77WUX/RvjyAIbdXMxa4ubJJeLK2zeo+1Eo6bJs2FQ/O8qi9VBSIEsXEyclv8DH2k3ODTjBVxF+GJNES9LCNqXVnPhKC2/klTcyS5DXm2GiTgxicgreqj/wuI1NoxSvGINp58u/TAoyNZ03W7Xu+IAISgCFQtoRxuEM7S2AIJ4SkQnYUwAFXz3JU5uy16X1o+i0UI26YQN8eYN7tQ/P7LXQW2FHtGxL+7I2KgCgSkF0OY87y087Ppi3F0fDl/kzCOuJKFVo7Wpk3Y18Ha/H87OC4A8uKxeONfVAo7gV2/MR8Ii+paN9sZzyl/tg4Lldj2vR9PZy4b06ziw7/2XVU=
|
8
|
+
- secure: CEJSSVJyjJZJYv3rSkxZdv+XkeQYFB8Wdi7r7qVA2+pbefcNirRJdwD3/qeiZyzMUri1wY5Sbj9FkgFzXHpM7QH4/2OKylWu59y/QdWqS3Ad0DGhfZ/eu56qYIpRfHekkQSLCrnSkDzgDWc4Q1L9/izY6kS872lkJS+guZ3FVgxc/As7+aPJh4hcVfZfUcJakLN12dl7fgf6SWRKj00MYbpvQPGaK2pcQhTsjVOqcC/R3wSKCDvTb4W1eDY1mTtNP2NFjvPX7yQMlkSyDQMNP95jcD0i1/mE2dmPDBqzs1qgrCYEyGR1SVgUtzpJOm1jc/ff4wohtQVEFNym9sensTOXx7JxPORNBGcxN3K0mjoymHTO+hKzGxU8HcVE1oJ4C2XNitaO4vFFss3LugDpBR5zC4Pk/jYaCIH+hqtUtMpUawLjqsW1JBrFiRRNXHF8xlKd04PlAk5i6CTJRKkDPsifNFwxkwE2AYfa7hDyuTqOdC7G97tb+8Jwbgzj/paMj6YOoBnZNgC697emAtA9QHhxPXVN5S+29aPrkqAtqeuDRR5sNWai5oTZZ88U0VBrvLCcwomLGMgLhensN9cGWcpVlFcEL6gJyCLRaxm1tcKPc9NiAUrSClaks4yI278XpDqyYwzTqrgH863bg+OSqqwZYVNTofqJL9SGbbdQv9Y=
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# Freshbooks API Client
|
2
|
+
|
3
|
+
![Inch
|
4
|
+
Documentation](http://inch-ci.org/github/littlelines/freshbooks_client.svg?branch=master)
|
5
|
+
[![Build Status](http://img.shields.io/travis/littlelines/freshbooks_client.svg)](https://travis-ci.org/littlelines/freshbooks_client)
|
6
|
+
[![Dependency Status](http://img.shields.io/gemnasium/littlelines/freshbooks_client.svg)](https://gemnasium.com/littlelines/freshbooks_client)
|
7
|
+
[![Code Climate](http://img.shields.io/codeclimate/github/littlelines/freshbooks_client.svg)](https://codeclimate.com/github/littlelines/freshbooks_client)
|
8
|
+
[![Gem Version](http://img.shields.io/gem/v/freshbooks_client.svg)](https://rubygems.org/gems/freshbooks_client)
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "freshbooks"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "pry"
|
14
|
+
require "dotenv"
|
15
|
+
|
16
|
+
Dotenv.load
|
17
|
+
|
18
|
+
@client = Freshbooks::Client.new do |config|
|
19
|
+
config.api_url = ENV['BASE_URL']
|
20
|
+
config.token = ENV['TOKEN']
|
21
|
+
end
|
22
|
+
|
23
|
+
Pry.start
|
data/bin/setup
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'freshbooks/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "freshbooks_client"
|
8
|
+
spec.version = Freshbooks::VERSION
|
9
|
+
spec.authors = ["Jesse Herrick"]
|
10
|
+
spec.email = ["jesse@littlelines.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{An awesome API client for Freshbooks.}
|
13
|
+
spec.description = spec.summary
|
14
|
+
spec.homepage = "https://github.com/littlelines/freshbooks_client"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_runtime_dependency "multi_xml", "~> 0.5.5"
|
20
|
+
spec.add_runtime_dependency "nokogiri", "~> 1.6.6"
|
21
|
+
spec.add_runtime_dependency "hashie", "~> 3.4.2"
|
22
|
+
spec.add_runtime_dependency "faraday_middleware", "~> 0.10.0"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
25
|
+
spec.add_development_dependency "coveralls"
|
26
|
+
spec.add_development_dependency "dotenv"
|
27
|
+
spec.add_development_dependency "minitest"
|
28
|
+
spec.add_development_dependency "minitest-reporters"
|
29
|
+
spec.add_development_dependency "pry"
|
30
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
31
|
+
spec.add_development_dependency "simplecov"
|
32
|
+
end
|
data/lib/freshbooks.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'freshbooks/version'
|
2
|
+
require 'freshbooks/api/methods'
|
3
|
+
require 'freshbooks/api/crud'
|
4
|
+
require 'freshbooks/api/no_crud'
|
5
|
+
require 'freshbooks/api/no_cd'
|
6
|
+
require 'freshbooks/api/no_crudl'
|
7
|
+
require 'freshbooks/client'
|
8
|
+
require 'freshbooks/api/callback'
|
9
|
+
require 'freshbooks/api/category'
|
10
|
+
require 'freshbooks/api/client'
|
11
|
+
require 'freshbooks/api/estimate'
|
12
|
+
require 'freshbooks/api/expense'
|
13
|
+
require 'freshbooks/api/gateway'
|
14
|
+
require 'freshbooks/api/invoice'
|
15
|
+
require 'freshbooks/api/item'
|
16
|
+
require 'freshbooks/api/language'
|
17
|
+
require 'freshbooks/api/payment'
|
18
|
+
require 'freshbooks/api/project'
|
19
|
+
require 'freshbooks/api/receipt'
|
20
|
+
require 'freshbooks/api/recurring'
|
21
|
+
require 'freshbooks/api/staff'
|
22
|
+
require 'freshbooks/api/system'
|
23
|
+
require 'freshbooks/api/task'
|
24
|
+
require 'freshbooks/api/tax'
|
25
|
+
require 'freshbooks/api/time_entry'
|
26
|
+
require 'freshbooks/api/contractor'
|
27
|
+
require 'freshbooks/api/default_term'
|
28
|
+
require 'freshbooks/api/report'
|
29
|
+
require 'freshbooks/api/currency'
|
30
|
+
require 'freshbooks/api/email_template'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
# A namespace for all classes and methods making direct calls to the
|
3
|
+
# Freshbooks API.
|
4
|
+
module API
|
5
|
+
# http://www.freshbooks.com/developers/docs/callbacks
|
6
|
+
class Callback < Freshbooks::Client
|
7
|
+
# Verifies a callback using a unique verification code.
|
8
|
+
#
|
9
|
+
# @param params [Hash] a hash of params to verify a callback
|
10
|
+
def verify(params = {})
|
11
|
+
call('callback.verify', callback: params)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Resends a verification code to an unverified callback.
|
15
|
+
#
|
16
|
+
# @param params [Hash] a hash of params to resend a callback token
|
17
|
+
def resend_token(params = {})
|
18
|
+
call('callback.resendToken', params)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# Methods for CRUD in [Freshbooks::Client].
|
4
|
+
module CRUD
|
5
|
+
# Creates something based on params.
|
6
|
+
#
|
7
|
+
# @example Create a new project.
|
8
|
+
# @clients.projects.create(name: "Some Project", bill_method: "project-rate")
|
9
|
+
# # => { "project_id" => "1234" }
|
10
|
+
#
|
11
|
+
# @param params [Hash] A hash of params to create something.
|
12
|
+
def create(params = {})
|
13
|
+
call("#{@endpoint}.create", { @endpoint => params })
|
14
|
+
end
|
15
|
+
|
16
|
+
# Updates something based on params.
|
17
|
+
#
|
18
|
+
# @example Update an existing project.
|
19
|
+
# @client.projects.update(project_id: 1234, bill_method: "credit-card")
|
20
|
+
# # => { "project_id" => "1234" }
|
21
|
+
#
|
22
|
+
# @param params [Hash] A hash of params to update something.
|
23
|
+
def update(params = {})
|
24
|
+
call("#{@endpoint}.update", { @endpoint => params })
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get something's details based on the `<something>_id`.
|
28
|
+
#
|
29
|
+
# @example Get a project by `project_id`.
|
30
|
+
# @client.projects.get(project_id: 1234)
|
31
|
+
# # => {"projects" => [...]}
|
32
|
+
#
|
33
|
+
# @param params [Hash] A hash of params to get something's details.
|
34
|
+
def get(params = {})
|
35
|
+
call("#{@endpoint}.get", params)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Delete something based on its `<something>_id`.
|
39
|
+
#
|
40
|
+
# @example Delete a project.
|
41
|
+
# @client.projects.delete(project_id: 1234)
|
42
|
+
# # => 200 OK
|
43
|
+
#
|
44
|
+
# @param params [Hash] A hash of params to delete something.
|
45
|
+
def delete(params = {})
|
46
|
+
call("#{@endpoint}.delete", params)
|
47
|
+
end
|
48
|
+
|
49
|
+
# List a bunch of somethings.
|
50
|
+
#
|
51
|
+
# @example List all projects.
|
52
|
+
# @client.projects.list
|
53
|
+
# # => {"projects" => [...]}
|
54
|
+
#
|
55
|
+
# @param params [Hash] A hash of params ot filter the listing.
|
56
|
+
def list(params = {})
|
57
|
+
call("#{@endpoint}.list", params)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# http://www.freshbooks.com/developers/docs/default_terms
|
4
|
+
class DefaultTerm < Freshbooks::Client
|
5
|
+
include NoCD
|
6
|
+
|
7
|
+
# List/Get/Update
|
8
|
+
def list(params = {})
|
9
|
+
call('default_terms.list', params)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(params = {})
|
13
|
+
call('default_terms.get', params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(params = {})
|
17
|
+
call('default_terms.update', params)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# http://www.freshbooks.com/developers/docs/estimates
|
4
|
+
class Estimate < Freshbooks::Client
|
5
|
+
# Send an estimate to the associated client via e-mail.
|
6
|
+
#
|
7
|
+
# @param params [Hash] A hash of params to send an estimate via email.
|
8
|
+
def send_by_email(params = {})
|
9
|
+
call('estimate.sendByEmail', params)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns the specified estimate in PDF format.
|
13
|
+
#
|
14
|
+
# @param params [Hash] A hash of params to get an estimate's PDF.
|
15
|
+
def get_pdf(params = {})
|
16
|
+
call('estimate.getPDF', params)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Change an existing estimate's status to "Accepted".
|
20
|
+
#
|
21
|
+
# @param params [Hash] A hash of params to accept an estimate.
|
22
|
+
def accept(params = {})
|
23
|
+
call('estimate.accept', params)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Move a draft estimate into "Sent" status without issuing the estimate.
|
27
|
+
#
|
28
|
+
# @param params [Hash] A hash of params to mark a draft estimate as sent.
|
29
|
+
def mark_as_sent(params = {})
|
30
|
+
call('markAsSent', params)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# http://www.freshbooks.com/developers/docs/invoices#invoice.getPDF
|
4
|
+
class Invoice < Freshbooks::Client
|
5
|
+
# CRUD
|
6
|
+
|
7
|
+
# Returns the specified invoice in PDF format.
|
8
|
+
def get_pdf(params = {})
|
9
|
+
call('invoice.getPDF', params)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Send an existing invoice to your client via e-mail.
|
13
|
+
def send_by_email(params = {})
|
14
|
+
call('invoice.sendByEmail', params)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Send an existing invoice to your client via snail mail.
|
18
|
+
def send_by_snail_mail(params = {})
|
19
|
+
call('invoice.sendBySnailMail', params)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Adds a new line/lines to an existing invoice.
|
23
|
+
def add_lines(params = {})
|
24
|
+
call('invoice.lines.add', params)
|
25
|
+
end
|
26
|
+
alias_method :add_line, :add_lines
|
27
|
+
|
28
|
+
# Deletes a line from an existing invoice.
|
29
|
+
def delete_lines(params = {})
|
30
|
+
call('invoice.lines.delete', params)
|
31
|
+
end
|
32
|
+
alias_method :delete_line, :delete_lines
|
33
|
+
|
34
|
+
# Updates a line on an existing invoice.
|
35
|
+
def update_lines(params = {})
|
36
|
+
call('invoice.lines.update', params)
|
37
|
+
end
|
38
|
+
alias_method :update_line, :update_lines
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Freshbooks::API
|
2
|
+
# Defines methods for accessing API endpoints from the main [Freshbooks::Client] class.
|
3
|
+
module Methods
|
4
|
+
# @return [Freshbooks::API::Callback]
|
5
|
+
def callbacks
|
6
|
+
Freshbooks::API::Callback.new(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return [Freshbooks::API::Category]
|
10
|
+
def categories
|
11
|
+
Freshbooks::API::Category.new(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Freshbooks::API::Client]
|
15
|
+
def clients
|
16
|
+
Freshbooks::API::Client.new(options)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Freshbooks::API::Estimate]
|
20
|
+
def estimates
|
21
|
+
Freshbooks::API::Estimate.new(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Freshbooks::API::Expense]
|
25
|
+
def expenses
|
26
|
+
Freshbooks::API::Expense.new(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Freshbooks::API::Gateway]
|
30
|
+
def gateways
|
31
|
+
Freshbooks::API::Gateway.new(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Freshbooks::API::Invoice]
|
35
|
+
def invoices
|
36
|
+
Freshbooks::API::Invoice.new(options)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Freshbooks::API::Item]
|
40
|
+
def items
|
41
|
+
Freshbooks::API::Item.new(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Freshbooks::API::Language]
|
45
|
+
def languages
|
46
|
+
Freshbooks::API::Language.new(options)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Freshbooks::API::Payment]
|
50
|
+
def payments
|
51
|
+
Freshbooks::API::Payment.new(options)
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Freshbooks::API::Project]
|
55
|
+
def projects
|
56
|
+
Freshbooks::API::Project.new(options)
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Freshbooks::API::Receipt]
|
60
|
+
def receipts
|
61
|
+
Freshbooks::API::Receipt.new(options)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Freshbooks::API::Recurring]
|
65
|
+
def recurring
|
66
|
+
Freshbooks::API::Recurring.new(options)
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Freshbooks::API::Staff]
|
70
|
+
def staff
|
71
|
+
Freshbooks::API::Staff.new(options)
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [Freshbooks::API::System]
|
75
|
+
def systems
|
76
|
+
Freshbooks::API::System.new(options)
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Freshbooks::API::Task]
|
80
|
+
def tasks
|
81
|
+
Freshbooks::API::Task.new(options)
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [Freshbooks::API::Tax]
|
85
|
+
def taxes
|
86
|
+
Freshbooks::API::Tax.new(options)
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [Freshbooks::API::TimeEntry]
|
90
|
+
def time_entries
|
91
|
+
Freshbooks::API::TimeEntry.new(options)
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [Freshbooks::API::Contractor]
|
95
|
+
def contractors
|
96
|
+
Freshbooks::API::Contractor.new(options)
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [Freshbooks::API::DefaultTerm]
|
100
|
+
def default_terms
|
101
|
+
Freshbooks::API::DefaultTerm.new(options)
|
102
|
+
end
|
103
|
+
|
104
|
+
# @return [Freshbooks::API::Report]
|
105
|
+
def reports
|
106
|
+
Freshbooks::API::Report.new(options)
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [Freshbooks::API::Currency]
|
110
|
+
def currencies
|
111
|
+
Freshbooks::API::Currency.new(options)
|
112
|
+
end
|
113
|
+
|
114
|
+
# @return [Freshbooks::API::EmailTemplate]
|
115
|
+
def email_templates
|
116
|
+
Freshbooks::API::EmailTemplate.new(options)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# Prevents default create and delete ability in [Freshbooks::Client].
|
4
|
+
module NoCD
|
5
|
+
def self.included(_)
|
6
|
+
[:create, :delete].each do |method|
|
7
|
+
define_method method do
|
8
|
+
abort "Sorry, this endpoint has no CRUD or listing actions."
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# Prevents default CRUD ability in [Freshbooks::Client].
|
4
|
+
module NoCRUD
|
5
|
+
def self.included(_)
|
6
|
+
no_crud
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.no_crud
|
10
|
+
[:create, :get, :update, :delete].each do |method|
|
11
|
+
define_method method do
|
12
|
+
abort "Sorry, this endpoint only has a listing action."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# Prevents default CRUD and listing ability in [Freshbooks::Client].
|
4
|
+
module NoCRUDL
|
5
|
+
def self.included(_)
|
6
|
+
include NoCRUD
|
7
|
+
|
8
|
+
define_method :list do
|
9
|
+
abort "Sorry, this endpoint has no CRUD or listing actions."
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# http://www.freshbooks.com/developers/docs/receipts
|
4
|
+
class Receipt < Freshbooks::Client
|
5
|
+
# CRUD (no index)
|
6
|
+
|
7
|
+
def list(params = {})
|
8
|
+
abort "Sorry, this endpoint doesn't have a listing action."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# http://www.freshbooks.com/developers/docs/recurring
|
4
|
+
class Recurring < Freshbooks::Client
|
5
|
+
# CRUD
|
6
|
+
|
7
|
+
# Add a new line/lines to an existing recurring profile.
|
8
|
+
def add_lines(params = {})
|
9
|
+
call('recurring.lines.add', params)
|
10
|
+
end
|
11
|
+
alias_method :add_line, :add_lines
|
12
|
+
|
13
|
+
# Deletes a single line from an existing recurring profile.
|
14
|
+
def delete_lines(params = {})
|
15
|
+
call('recurring.lines.delete', params)
|
16
|
+
end
|
17
|
+
alias_method :delete_line, :delete_lines
|
18
|
+
|
19
|
+
# Updates an existing line/lines on an existing recurring profile.
|
20
|
+
def update_lines(params = {})
|
21
|
+
call('recurring.lines.update', params)
|
22
|
+
end
|
23
|
+
alias_method :update_line, :update_lines
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# http://www.freshbooks.com/developers/docs/reports
|
4
|
+
class Report < Freshbooks::Client
|
5
|
+
include Freshbooks::API::NoCRUDL
|
6
|
+
|
7
|
+
# Returns profit and account standing details for the specified client.
|
8
|
+
def get_client_details(params = {})
|
9
|
+
call('report.getClientDetails', params)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns total estimated, accepted and invoiced values for invoices; broken down by currency.
|
13
|
+
def get_estimate_details(params = {})
|
14
|
+
call('report.getEstimateDetails', params)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns information about all, or a filtered set of expenses.
|
18
|
+
def get_expense_details(params = {})
|
19
|
+
call('report.getExpenseDetails', params)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns information about all, or a filtered set of invoices.
|
23
|
+
def get_invoice_details(params = {})
|
24
|
+
call('report.getInvoiceDetails', params)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Reports profit and loss details.
|
28
|
+
def get_profit_details(params = {})
|
29
|
+
call('report.getProfitDetails', params)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Freshbooks
|
2
|
+
module API
|
3
|
+
# http://www.freshbooks.com/developers/docs/staff
|
4
|
+
class Staff < Freshbooks::Client
|
5
|
+
# CRUD
|
6
|
+
|
7
|
+
# Returns the current user's details.
|
8
|
+
def current(params = {})
|
9
|
+
call('staff.current', params)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Freshbooks
|
3
|
+
module API
|
4
|
+
# http://www.freshbooks.com/developers/docs/system
|
5
|
+
class System < Freshbooks::Client
|
6
|
+
include Freshbooks::API::NoCRUDL
|
7
|
+
|
8
|
+
# Returns the current system’s information (beta).
|
9
|
+
def current(params = {})
|
10
|
+
call('system.current', params)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'multi_xml'
|
2
|
+
require 'faraday'
|
3
|
+
require 'faraday_middleware'
|
4
|
+
require 'hashie'
|
5
|
+
|
6
|
+
# Namespace for all methods, attributes, and classes used to
|
7
|
+
# wrap the Freshbooks API.
|
8
|
+
module Freshbooks
|
9
|
+
# Superclass that contains all logic and methods needed to send
|
10
|
+
# and parse XML from the Freshbooks API.
|
11
|
+
#
|
12
|
+
# @author Jesse Herrick
|
13
|
+
# @abstract
|
14
|
+
# @since 0.1.0
|
15
|
+
#
|
16
|
+
# @attr [String] token auth token provided by Freshbooks
|
17
|
+
# @attr [String] api_url the base URL of the API endpoint provided
|
18
|
+
# by Freshbooks
|
19
|
+
class Client
|
20
|
+
attr_accessor :token
|
21
|
+
attr_accessor :api_url
|
22
|
+
|
23
|
+
def initialize(options = {})
|
24
|
+
options.each do |key, value|
|
25
|
+
instance_variable_set("@#{key}", value)
|
26
|
+
end
|
27
|
+
|
28
|
+
@endpoint = underscore(self.class.to_s.split('::').last)
|
29
|
+
|
30
|
+
yield(self) if block_given?
|
31
|
+
end
|
32
|
+
|
33
|
+
include Freshbooks::API::Methods
|
34
|
+
include Freshbooks::API::CRUD
|
35
|
+
|
36
|
+
# Makes an API call via the #post method.
|
37
|
+
#
|
38
|
+
# @param method [String] The API method as defined in the Freshbooks API docs.
|
39
|
+
# @param struct [Array] All required parameters for the request.
|
40
|
+
# @param params [Hash] The parameters passed to the request.
|
41
|
+
#
|
42
|
+
# @example Create a callback.
|
43
|
+
# call('callback.create', [:event, :uri], {event: 'Foo', uri: 'https://jesse.codes/'})
|
44
|
+
# # => {...}
|
45
|
+
#
|
46
|
+
# @example List projects.
|
47
|
+
# call('project.list')
|
48
|
+
# # => {...}
|
49
|
+
#
|
50
|
+
# @return [Hash] An API request hash.
|
51
|
+
def call(method, params = {})
|
52
|
+
# unless params.empty?
|
53
|
+
# # ensure that params definied in the struct exist
|
54
|
+
# struct.each do |p|
|
55
|
+
# body[p] = params.fetch(p)
|
56
|
+
# params.delete(p)
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# body.merge(params) unless params.empty?
|
60
|
+
# end
|
61
|
+
|
62
|
+
post_body = {method: method}
|
63
|
+
post_body = post_body.merge(params) unless params.empty?
|
64
|
+
|
65
|
+
post(post_body)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Send post request to the API.
|
69
|
+
#
|
70
|
+
# @return HTTP request
|
71
|
+
def post(body)
|
72
|
+
@connection = Faraday.new(@api_url) do |conn|
|
73
|
+
conn.use FaradayMiddleware::Mashify
|
74
|
+
conn.response :xml
|
75
|
+
conn.basic_auth @token, 'X'
|
76
|
+
conn.adapter Faraday.default_adapter
|
77
|
+
end
|
78
|
+
|
79
|
+
resp = @connection.post do |req|
|
80
|
+
req.url '/api/2.1/xml-in'
|
81
|
+
req.headers['Content-Type'] = 'application/xml'
|
82
|
+
req.body = to_request(body)
|
83
|
+
end
|
84
|
+
|
85
|
+
body = resp.body.response
|
86
|
+
if body.empty?
|
87
|
+
resp.status
|
88
|
+
else
|
89
|
+
body
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Parses XML response into a hash.
|
94
|
+
#
|
95
|
+
# @param xml_content [String] A string of XML to be parsed.
|
96
|
+
#
|
97
|
+
# @return [Hash] A hash of the converted XML response.
|
98
|
+
def parse(xml_content)
|
99
|
+
MultiXml.parser = :nokogiri
|
100
|
+
MultiXml.parse(xml_content)['response']
|
101
|
+
end
|
102
|
+
|
103
|
+
# Converts a data hash into a usable Freshbooks API XML request.
|
104
|
+
#
|
105
|
+
# It parses the hash and removes relevant request attributes. Then
|
106
|
+
# it uses the method, #hash_to_raw_xml to convert it into XML.
|
107
|
+
#
|
108
|
+
# @param data_hash [Hash] a hash to build the request from
|
109
|
+
#
|
110
|
+
def to_request(data_hash)
|
111
|
+
req_method = data_hash.delete(:method)
|
112
|
+
'<?xml version="1.0" encoding="utf-8"?>' +
|
113
|
+
"<request method=\"#{req_method}\">" +
|
114
|
+
hash_to_raw_xml(data_hash) +
|
115
|
+
'</request>'
|
116
|
+
end
|
117
|
+
|
118
|
+
# Converts a raw hash into raw XML.
|
119
|
+
#
|
120
|
+
# @param object [Hash] a hash to build the XML from
|
121
|
+
# @param built [String] a string of built XML added recursively by the method
|
122
|
+
#
|
123
|
+
# @example convert hash to XML
|
124
|
+
# data = {foo: {bar: {this: 'that'}}}
|
125
|
+
# hash_to_raw_xml(data)
|
126
|
+
# # => "<foo><bar><this>that</this></bar></foo>"
|
127
|
+
#
|
128
|
+
# @return [String] a raw XML string
|
129
|
+
def hash_to_raw_xml(object, built = '')
|
130
|
+
case object
|
131
|
+
when Hash
|
132
|
+
case
|
133
|
+
when object.count > 1
|
134
|
+
object.each { |h| built += "<#{h.first.to_s}>#{hash_to_raw_xml(h.last)}</#{h.first.to_s}>" }
|
135
|
+
when object.count == 1
|
136
|
+
object.each { |h| built += "<#{h.first.to_s}>#{hash_to_raw_xml(h.last, built)}</#{h.first.to_s}>" }
|
137
|
+
end
|
138
|
+
when String
|
139
|
+
built += object
|
140
|
+
when Integer
|
141
|
+
built += object.to_s
|
142
|
+
end
|
143
|
+
built
|
144
|
+
end
|
145
|
+
|
146
|
+
# Generates a hash of options to pass to {Freshbooks::Client}.
|
147
|
+
#
|
148
|
+
# @return [Hash] a hash of options.
|
149
|
+
def options
|
150
|
+
{
|
151
|
+
api_url: @api_url,
|
152
|
+
token: @token
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
156
|
+
# Converts a CamelCased word with an underscored_one.
|
157
|
+
#
|
158
|
+
# @param camel_cased_word [String] A string to underscore.
|
159
|
+
#
|
160
|
+
# @return An underscored string.
|
161
|
+
def underscore(camel_cased_word)
|
162
|
+
camel_cased_word.gsub(/::/, '/').
|
163
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
164
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
165
|
+
tr("-", "_").
|
166
|
+
downcase
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
metadata
ADDED
@@ -0,0 +1,252 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: freshbooks_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jesse Herrick
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: multi_xml
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.5.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.5.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.6.6
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.6.6
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: hashie
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.4.2
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.4.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: faraday_middleware
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.10.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.10.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: coveralls
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: dotenv
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: minitest-reporters
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pry
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rake
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '10.0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '10.0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: simplecov
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
description: An awesome API client for Freshbooks.
|
182
|
+
email:
|
183
|
+
- jesse@littlelines.com
|
184
|
+
executables: []
|
185
|
+
extensions: []
|
186
|
+
extra_rdoc_files: []
|
187
|
+
files:
|
188
|
+
- ".coveralls.yml"
|
189
|
+
- ".gitignore"
|
190
|
+
- ".travis.yml"
|
191
|
+
- Gemfile
|
192
|
+
- README.md
|
193
|
+
- Rakefile
|
194
|
+
- bin/console
|
195
|
+
- bin/setup
|
196
|
+
- freshbooks_client.gemspec
|
197
|
+
- lib/freshbooks.rb
|
198
|
+
- lib/freshbooks/api/callback.rb
|
199
|
+
- lib/freshbooks/api/category.rb
|
200
|
+
- lib/freshbooks/api/client.rb
|
201
|
+
- lib/freshbooks/api/contractor.rb
|
202
|
+
- lib/freshbooks/api/crud.rb
|
203
|
+
- lib/freshbooks/api/currency.rb
|
204
|
+
- lib/freshbooks/api/default_term.rb
|
205
|
+
- lib/freshbooks/api/email_template.rb
|
206
|
+
- lib/freshbooks/api/estimate.rb
|
207
|
+
- lib/freshbooks/api/expense.rb
|
208
|
+
- lib/freshbooks/api/gateway.rb
|
209
|
+
- lib/freshbooks/api/invoice.rb
|
210
|
+
- lib/freshbooks/api/item.rb
|
211
|
+
- lib/freshbooks/api/language.rb
|
212
|
+
- lib/freshbooks/api/methods.rb
|
213
|
+
- lib/freshbooks/api/no_cd.rb
|
214
|
+
- lib/freshbooks/api/no_crud.rb
|
215
|
+
- lib/freshbooks/api/no_crudl.rb
|
216
|
+
- lib/freshbooks/api/payment.rb
|
217
|
+
- lib/freshbooks/api/project.rb
|
218
|
+
- lib/freshbooks/api/receipt.rb
|
219
|
+
- lib/freshbooks/api/recurring.rb
|
220
|
+
- lib/freshbooks/api/report.rb
|
221
|
+
- lib/freshbooks/api/staff.rb
|
222
|
+
- lib/freshbooks/api/system.rb
|
223
|
+
- lib/freshbooks/api/task.rb
|
224
|
+
- lib/freshbooks/api/tax.rb
|
225
|
+
- lib/freshbooks/api/time_entry.rb
|
226
|
+
- lib/freshbooks/client.rb
|
227
|
+
- lib/freshbooks/version.rb
|
228
|
+
homepage: https://github.com/littlelines/freshbooks_client
|
229
|
+
licenses: []
|
230
|
+
metadata: {}
|
231
|
+
post_install_message:
|
232
|
+
rdoc_options: []
|
233
|
+
require_paths:
|
234
|
+
- lib
|
235
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
236
|
+
requirements:
|
237
|
+
- - ">="
|
238
|
+
- !ruby/object:Gem::Version
|
239
|
+
version: '0'
|
240
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
241
|
+
requirements:
|
242
|
+
- - ">="
|
243
|
+
- !ruby/object:Gem::Version
|
244
|
+
version: '0'
|
245
|
+
requirements: []
|
246
|
+
rubyforge_project:
|
247
|
+
rubygems_version: 2.4.5
|
248
|
+
signing_key:
|
249
|
+
specification_version: 4
|
250
|
+
summary: An awesome API client for Freshbooks.
|
251
|
+
test_files: []
|
252
|
+
has_rdoc:
|