freshbooks_client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: