freeagent_api 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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Aaron Russell
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,66 @@
1
+ = freeagent_api
2
+
3
+ Simple Ruby interface to the Freeagent Central API (http://www.freeagentcentral.com/developers/freeagent-api).
4
+
5
+ This is an early development version of a Ruby wrapper for the Freeagent API. Currently this only supports GET requests (POST will follow shortly) and only the following API methods are supported (more will follow):
6
+
7
+ * Contacts
8
+ * Invoices
9
+ * Invoice items
10
+ * Projects
11
+ * Tasks
12
+ * Timeslips
13
+
14
+ There is no test suite yet. If you feel brave, then feel free to clone, fork and play around.
15
+
16
+ == Installation
17
+
18
+ To install as a Gem, just run:
19
+
20
+ $ sudo gem install freeagent_api -s http://gemcutter.org
21
+
22
+ == Usage
23
+
24
+ === Authentication
25
+
26
+ Freeagent.domain = 'yourdomain.freeagentcentral.com'
27
+ Freeagent.username = 'your@login.com'
28
+ Freeagent.password = 'your_password'
29
+
30
+ === Contacts
31
+
32
+ @contacts = Contact.find_all # returns all contacts
33
+ @contact = Contact.find(contact_id) # returns specific contact
34
+
35
+ === Invoice
36
+
37
+ @invoices = Invoice.find_all # returns all invoices
38
+ @invoices = Invoice.find_all(project_id) # returns all invoices for project
39
+ @invoice = Invoice.find(invoice_id) # returns specific invoice
40
+
41
+ === Invoice items
42
+
43
+ @items = InvoiceItem.find_all(invoice_id) # returns all items for invoice
44
+
45
+ === Projects
46
+
47
+ @projects = Project.find_all # returns all projects
48
+ @project = Project.find(project_id) # returns specific project
49
+
50
+ === Tasks
51
+
52
+ @task = Task.find(project_id, task_id) # returns specific task for project
53
+
54
+ === Timeslips
55
+
56
+ @timeslips = Timeslip.find_all # returns all timeslips
57
+ @timeslips = Timeslip.find_all(project_id) # returns all timeslips for project
58
+ @timeslip = Timeslip.find(timeslip_id) # returns specific timeslip
59
+
60
+ == Author
61
+
62
+ * Aaron Russell - (www.aaronrussell.co.uk)
63
+
64
+ == Copyright
65
+
66
+ Copyright (c) 2009 Aaron Russell. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "freeagent_api"
8
+ gem.summary = %Q{Simple Ruby interface to the Freeagent Central API.}
9
+ gem.description = %Q{This is an early development version of a Ruby wrapper for the Freeagent API. Currently this only supports GET requests (POST will follow shortly) and not all API methods are currently supported (more will follow).}
10
+ gem.email = "aaron@gc4.co.uk"
11
+ gem.homepage = "http://github.com/aaronrussell/freeagent_api"
12
+ gem.authors = ["Aaron Russell"]
13
+ gem.add_development_dependency "thoughtbot-shoulda"
14
+ gem.add_dependency "activesupport"
15
+ gem.add_dependency "nokogiri"
16
+ gem.add_dependency "api_cache"
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
22
+ end
23
+
24
+ require 'rake/testtask'
25
+ Rake::TestTask.new(:test) do |test|
26
+ test.libs << 'lib' << 'test'
27
+ test.pattern = 'test/**/*_test.rb'
28
+ test.verbose = true
29
+ end
30
+
31
+ begin
32
+ require 'rcov/rcovtask'
33
+ Rcov::RcovTask.new do |test|
34
+ test.libs << 'test'
35
+ test.pattern = 'test/**/*_test.rb'
36
+ test.verbose = true
37
+ end
38
+ rescue LoadError
39
+ task :rcov do
40
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
+ end
42
+ end
43
+
44
+ task :test => :check_dependencies
45
+
46
+ task :default => :test
47
+
48
+ require 'rake/rdoctask'
49
+ Rake::RDocTask.new do |rdoc|
50
+ if File.exist?('VERSION')
51
+ version = File.read('VERSION')
52
+ else
53
+ version = ""
54
+ end
55
+
56
+ rdoc.rdoc_dir = 'rdoc'
57
+ rdoc.title = "freeagent_api #{version}"
58
+ rdoc.rdoc_files.include('README*')
59
+ rdoc.rdoc_files.include('lib/**/*.rb')
60
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,62 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{freeagent_api}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Aaron Russell"]
12
+ s.date = %q{2009-10-14}
13
+ s.description = %q{This is an early development version of a Ruby wrapper for the Freeagent API. Currently this only supports GET requests (POST will follow shortly) and not all API methods are currently supported (more will follow).}
14
+ s.email = %q{aaron@gc4.co.uk}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "freeagent_api.gemspec",
27
+ "lib/freeagent_api.rb",
28
+ "test/freeagent_api_test.rb",
29
+ "test/test_helper.rb"
30
+ ]
31
+ s.homepage = %q{http://github.com/aaronrussell/freeagent_api}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.5}
35
+ s.summary = %q{Simple Ruby interface to the Freeagent Central API.}
36
+ s.test_files = [
37
+ "test/freeagent_api_test.rb",
38
+ "test/test_helper.rb"
39
+ ]
40
+
41
+ if s.respond_to? :specification_version then
42
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
46
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
47
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
48
+ s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
49
+ s.add_runtime_dependency(%q<api_cache>, [">= 0"])
50
+ else
51
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
52
+ s.add_dependency(%q<activesupport>, [">= 0"])
53
+ s.add_dependency(%q<nokogiri>, [">= 0"])
54
+ s.add_dependency(%q<api_cache>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
58
+ s.add_dependency(%q<activesupport>, [">= 0"])
59
+ s.add_dependency(%q<nokogiri>, [">= 0"])
60
+ s.add_dependency(%q<api_cache>, [">= 0"])
61
+ end
62
+ end
@@ -0,0 +1,172 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+ require 'net/https'
4
+ require 'api_cache'
5
+ require 'activesupport'
6
+
7
+ module Freeagent
8
+
9
+ class << self
10
+ attr_accessor :domain, :username, :password
11
+
12
+ def self.domain=(domain)
13
+ @domain = domain
14
+ end
15
+
16
+ def self.username=(username)
17
+ @username = username
18
+ end
19
+
20
+ def self.password=(password)
21
+ @password = password
22
+ end
23
+ end
24
+
25
+ class Base
26
+
27
+ def initialize(attributes={})
28
+ attributes.each do |key, value|
29
+ raise "no attr_accessor set for #{key} on #{self.class}" if !respond_to?("#{key}=")
30
+ self.send("#{key}=", value)
31
+ end
32
+ end
33
+
34
+ def self.get(path)
35
+ @@resp = APICache.get(path) do
36
+ http = Net::HTTP.new(Freeagent.domain, 443)
37
+ http.use_ssl = true
38
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
39
+ http.start do |http|
40
+ request = Net::HTTP::Get.new(path, {'Content-Type' => 'application/xml', 'Accept' => 'application/xml'})
41
+ request.basic_auth(Freeagent.username, Freeagent.password)
42
+ response = http.request(request)
43
+ case response
44
+ when Net::HTTPSuccess
45
+ @@resp = response.body
46
+ else
47
+ response.error!
48
+ raise APICache::InvalidResponse
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def self.parse(path, options)
55
+ response = []
56
+ Nokogiri::XML(@@resp).xpath(path).each do |ts|
57
+ res = {}
58
+ options.each do |key|
59
+ res[key.underscore.to_sym] = ts.xpath(key).text
60
+ end
61
+ response << self.new(res)
62
+ end
63
+ return response
64
+ end
65
+
66
+ end
67
+
68
+ class Contact < Base
69
+ @elements = ['id', 'organisation-name', 'first-name', 'last-name', 'address1', 'address2', 'address3', 'town', 'region', 'country', 'postcode', 'phone-number', 'email', 'contact-name-on-invoices', 'sales-tax-registration_number', 'uses-contact-invoice-sequence']
70
+ @elements.each {|t| attr_accessor t.underscore.to_sym}
71
+
72
+ def self.find_all
73
+ get '/contacts'
74
+ contacts = parse('contacts/contact', @elements)
75
+ return contacts
76
+ end
77
+
78
+ def self.find(contact_id)
79
+ get '/contacts/'+contact_id
80
+ contacts = parse('contact', @elements)
81
+ return contacts[0]
82
+ end
83
+ end
84
+
85
+ class Invoice < Base
86
+ @elements = ['id', 'contact-id', 'project-id', 'dated-on', 'due-on', 'reference', 'net-value', 'sales-tax-value', 'status', 'comments', 'discount-percent', 'omit-header', 'payment-terms', 'written-off-date', 'invoice-items']
87
+ @elements.each {|t| attr_accessor t.underscore.to_sym}
88
+
89
+ def self.find_all(project_id = false)
90
+ if project_id
91
+ get '/projects/'+project_id+'/invoices'
92
+ else
93
+ get '/invoices'
94
+ end
95
+ invoices = parse('invoices/invoice', @elements)
96
+ return invoices.reverse
97
+ end
98
+
99
+ def self.find(invoice_id)
100
+ get '/invoices/'+invoice_id
101
+ invoices = parse('invoice', @elements)
102
+ invoices.each do |i|
103
+ i.invoice_items = InvoiceItem.find_all(invoice_id)
104
+ end
105
+ return invoices[0]
106
+ end
107
+ end
108
+
109
+ class InvoiceItem < Invoice
110
+ @elements = ['id', 'invoice-id', 'project-id', 'item-type', 'price', 'quantity', 'description', 'sales-tax-rate']
111
+ @elements.each {|t| attr_accessor t.underscore.to_sym}
112
+
113
+ def self.find_all(invoice_id)
114
+ items = parse('invoice/invoice-items/invoice-item', @elements)
115
+ return items
116
+ end
117
+ end
118
+
119
+ class Project < Base
120
+ @elements = ['id', 'contact-id', 'name', 'billing-basis', 'budget', 'budget-units', 'invoicing-reference', 'is-ir35', 'normal-billing-rate', 'payment-terms-in-days', 'starts-on', 'ends-on', 'status', 'uses-project-invoice-sequence']
121
+ @elements.each {|t| attr_accessor t.underscore.to_sym}
122
+
123
+ def self.find_all
124
+ get '/projects'
125
+ projects = parse('projects/project', @elements)
126
+ return projects
127
+ end
128
+
129
+ def self.find(project_id)
130
+ get '/projects/'+project_id
131
+ projects = parse('project', @elements)
132
+ return projects[0]
133
+ end
134
+ end
135
+
136
+ class Task < Base
137
+ @elements = ['id', 'project-id', 'name']
138
+ @elements.each {|t| attr_accessor t.underscore.to_sym}
139
+
140
+ def self.find(project_id, task_id)
141
+ get '/projects/'+project_id+'/tasks/'+task_id
142
+ tasks = parse('task', @elements)
143
+ return tasks[0]
144
+ end
145
+ end
146
+
147
+ class Timeslip < Base
148
+ @elements = ['id', 'dated-on', 'project-id', 'task-id', 'task', 'user-id', 'hours', 'comment']
149
+ @elements.each {|t| attr_accessor t.underscore.to_sym}
150
+
151
+ def self.find_all(project_id = false)
152
+ if project_id
153
+ get '/projects/'+project_id+'/timeslips'
154
+ else
155
+ get '/timeslips'
156
+ end
157
+ timeslips = parse('timeslips/timeslip', @elements)
158
+ timeslips.each do |t|
159
+ t.task = Task.find(project_id, t.task_id)
160
+ end
161
+ return timeslips.reverse
162
+ end
163
+
164
+ def self.find(timeslip_id)
165
+ get '/timeslips'+timeslip_id
166
+ timeslips = parse('timeslip', @elements)
167
+ return timeslips[0]
168
+ end
169
+ end
170
+
171
+
172
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class FreeagentApiTest < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'freeagent_api'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: freeagent_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Russell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-14 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: thoughtbot-shoulda
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: nokogiri
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: api_cache
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ description: This is an early development version of a Ruby wrapper for the Freeagent API. Currently this only supports GET requests (POST will follow shortly) and not all API methods are currently supported (more will follow).
56
+ email: aaron@gc4.co.uk
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - LICENSE
63
+ - README.rdoc
64
+ files:
65
+ - .document
66
+ - .gitignore
67
+ - LICENSE
68
+ - README.rdoc
69
+ - Rakefile
70
+ - VERSION
71
+ - freeagent_api.gemspec
72
+ - lib/freeagent_api.rb
73
+ - test/freeagent_api_test.rb
74
+ - test/test_helper.rb
75
+ has_rdoc: true
76
+ homepage: http://github.com/aaronrussell/freeagent_api
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --charset=UTF-8
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: "0"
89
+ version:
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ version:
96
+ requirements: []
97
+
98
+ rubyforge_project:
99
+ rubygems_version: 1.3.5
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: Simple Ruby interface to the Freeagent Central API.
103
+ test_files:
104
+ - test/freeagent_api_test.rb
105
+ - test/test_helper.rb