freshbooks_client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +10 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +4 -0
  6. data/README.md +8 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +23 -0
  9. data/bin/setup +7 -0
  10. data/freshbooks_client.gemspec +32 -0
  11. data/lib/freshbooks.rb +30 -0
  12. data/lib/freshbooks/api/callback.rb +23 -0
  13. data/lib/freshbooks/api/category.rb +8 -0
  14. data/lib/freshbooks/api/client.rb +8 -0
  15. data/lib/freshbooks/api/contractor.rb +8 -0
  16. data/lib/freshbooks/api/crud.rb +61 -0
  17. data/lib/freshbooks/api/currency.rb +8 -0
  18. data/lib/freshbooks/api/default_term.rb +21 -0
  19. data/lib/freshbooks/api/email_template.rb +8 -0
  20. data/lib/freshbooks/api/estimate.rb +34 -0
  21. data/lib/freshbooks/api/expense.rb +8 -0
  22. data/lib/freshbooks/api/gateway.rb +8 -0
  23. data/lib/freshbooks/api/invoice.rb +41 -0
  24. data/lib/freshbooks/api/item.rb +8 -0
  25. data/lib/freshbooks/api/language.rb +8 -0
  26. data/lib/freshbooks/api/methods.rb +119 -0
  27. data/lib/freshbooks/api/no_cd.rb +15 -0
  28. data/lib/freshbooks/api/no_crud.rb +18 -0
  29. data/lib/freshbooks/api/no_crudl.rb +15 -0
  30. data/lib/freshbooks/api/payment.rb +8 -0
  31. data/lib/freshbooks/api/project.rb +8 -0
  32. data/lib/freshbooks/api/receipt.rb +12 -0
  33. data/lib/freshbooks/api/recurring.rb +26 -0
  34. data/lib/freshbooks/api/report.rb +33 -0
  35. data/lib/freshbooks/api/staff.rb +13 -0
  36. data/lib/freshbooks/api/system.rb +14 -0
  37. data/lib/freshbooks/api/task.rb +8 -0
  38. data/lib/freshbooks/api/tax.rb +8 -0
  39. data/lib/freshbooks/api/time_entry.rb +8 -0
  40. data/lib/freshbooks/client.rb +169 -0
  41. data/lib/freshbooks/version.rb +3 -0
  42. metadata +252 -0
@@ -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
@@ -0,0 +1 @@
1
+ service_name: travis-ci
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .env
@@ -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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in freshbooks.gemspec
4
+ gemspec
@@ -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)
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -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
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -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
@@ -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,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/categories
4
+ class Category < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/clients
4
+ class Client < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/contractors
4
+ class Contractor < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ end
@@ -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,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/currency
4
+ class Currency < Freshbooks::Client
5
+ include Freshbooks::API::NoCRUD
6
+ end
7
+ end
8
+ 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,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/email_templates
4
+ class EmailTemplate < Freshbooks::Client
5
+ include NoCD
6
+ end
7
+ end
8
+ 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,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/expenses
4
+ class Expense < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/gateway
4
+ class Gateway < Freshbooks::Client
5
+ include Freshbooks::API::NoCRUD
6
+ end
7
+ end
8
+ 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,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/items
4
+ class Item < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/languages
4
+ class Language < Freshbooks::Client
5
+ include Freshbooks::API::NoCRUD
6
+ end
7
+ end
8
+ 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,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/payments
4
+ class Payment < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/projects
4
+ class Project < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ 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,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/tasks
4
+ class Task < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/taxes
4
+ class Tax < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Freshbooks
2
+ module API
3
+ # http://www.freshbooks.com/developers/docs/time-entries
4
+ class TimeEntry < Freshbooks::Client
5
+ # CRUD
6
+ end
7
+ end
8
+ 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
@@ -0,0 +1,3 @@
1
+ module Freshbooks
2
+ VERSION = "0.1.0"
3
+ 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: