freeagent_api 0.1.0 → 0.2.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/.gitignore +1 -1
- data/README.rdoc +194 -22
- data/Rakefile +4 -5
- data/VERSION +1 -1
- data/freeagent_api.gemspec +46 -17
- data/lib/freeagent_api.rb +78 -135
- data/test/authentication_test.rb +13 -0
- data/test/company_test.rb +33 -0
- data/test/contact_test.rb +62 -0
- data/test/invoice_item_test.rb +66 -0
- data/test/invoice_test.rb +70 -0
- data/test/project_test.rb +106 -0
- data/test/stubs/company/invoice_timeline +91 -0
- data/test/stubs/company/tax_timeline +28 -0
- data/test/stubs/contacts/find_all +391 -0
- data/test/stubs/contacts/find_single +29 -0
- data/test/stubs/http/200 +3 -0
- data/test/stubs/http/201 +4 -0
- data/test/stubs/invoice_items/find_all +40 -0
- data/test/stubs/invoice_items/find_single +15 -0
- data/test/stubs/invoices/find_all +239 -0
- data/test/stubs/invoices/find_single +57 -0
- data/test/stubs/projects/find_all +92 -0
- data/test/stubs/projects/find_single +22 -0
- data/test/stubs/projects/invoices +92 -0
- data/test/stubs/projects/timeslips +223 -0
- data/test/stubs/tasks/find_all +42 -0
- data/test/stubs/tasks/find_single +10 -0
- data/test/stubs/timeslips/find_all +52 -0
- data/test/stubs/timeslips/find_single +14 -0
- data/test/task_test.rb +60 -0
- data/test/test_helper.rb +83 -0
- data/test/timeslip_test.rb +62 -0
- metadata +41 -19
- data/test/freeagent_api_test.rb +0 -7
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -1,17 +1,24 @@
|
|
1
1
|
= freeagent_api
|
2
2
|
|
3
|
-
Simple Ruby
|
3
|
+
Simple ActiveResource Ruby wrapper for the Freeagent Central API (http://www.freeagentcentral.com/developers/freeagent-api).
|
4
4
|
|
5
|
-
This
|
5
|
+
This supports all GET, POST, PUT and DELETE ActiveResource calls for the following API resources:
|
6
6
|
|
7
|
+
* Company
|
7
8
|
* Contacts
|
8
|
-
* Invoices
|
9
|
-
* Invoice items
|
10
9
|
* Projects
|
11
10
|
* Tasks
|
11
|
+
* Invoices
|
12
|
+
* Invoice Items
|
12
13
|
* Timeslips
|
13
14
|
|
14
|
-
|
15
|
+
At the moment, the following API resources are NOT supported (although is being worked on):
|
16
|
+
|
17
|
+
* Users
|
18
|
+
* Expenses
|
19
|
+
* Attachments
|
20
|
+
|
21
|
+
Feel free to clone, fork and add tests.
|
15
22
|
|
16
23
|
== Installation
|
17
24
|
|
@@ -19,43 +26,208 @@ To install as a Gem, just run:
|
|
19
26
|
|
20
27
|
$ sudo gem install freeagent_api -s http://gemcutter.org
|
21
28
|
|
29
|
+
Please note: version 0.2 is significantly different from 0.1 so if you are upgrading from the early development version please re-familiarise yourself with the documentation.
|
30
|
+
|
22
31
|
== Usage
|
23
32
|
|
24
33
|
=== Authentication
|
25
34
|
|
26
|
-
Freeagent.
|
27
|
-
|
28
|
-
|
35
|
+
Freeagent.authenticate({
|
36
|
+
:domain => 'yourdomain.freeagentcentral.com',
|
37
|
+
:username => 'your@login.com',
|
38
|
+
:password => 'your_password'})
|
39
|
+
|
40
|
+
=== Company
|
41
|
+
|
42
|
+
<b>Timelines</b>
|
43
|
+
|
44
|
+
@invoice_timeline = Company.invoice_timeline
|
45
|
+
@tax_timeline = Company.tax_timeline
|
29
46
|
|
30
47
|
=== Contacts
|
31
48
|
|
32
|
-
|
33
|
-
@contact = Contact.find(contact_id) # returns specific contact
|
49
|
+
<b>Find contacts</b>
|
34
50
|
|
35
|
-
|
51
|
+
@contacts = Contact.find :all # returns all contacts
|
52
|
+
@contact = Contact.find id # returns specific contact
|
36
53
|
|
37
|
-
|
38
|
-
@invoices = Invoice.find_all(project_id) # returns all invoices for project
|
39
|
-
@invoice = Invoice.find(invoice_id) # returns specific invoice
|
54
|
+
<b>Create contact</b>
|
40
55
|
|
41
|
-
|
56
|
+
# Required attributes
|
57
|
+
# :first_name
|
58
|
+
# :last_name
|
59
|
+
|
60
|
+
@contact = Contact.new params
|
61
|
+
@contact.save
|
62
|
+
|
63
|
+
<b>Update contact</b>
|
64
|
+
|
65
|
+
@contact.first_name = 'Joe'
|
66
|
+
@contact.save
|
42
67
|
|
43
|
-
|
68
|
+
<b>Delete contact</b>
|
69
|
+
|
70
|
+
Contact.delete id
|
71
|
+
# or
|
72
|
+
@contact.destroy
|
44
73
|
|
45
74
|
=== Projects
|
46
75
|
|
47
|
-
|
48
|
-
|
76
|
+
<b>Find projects</b>
|
77
|
+
|
78
|
+
@projects = Project.find :all # returns all projects
|
79
|
+
@project = Project.find id # returns specific project
|
80
|
+
|
81
|
+
<b>Create project</b>
|
82
|
+
|
83
|
+
# Required attribues
|
84
|
+
# :contact_id
|
85
|
+
# :name
|
86
|
+
# :payment_term_in_days
|
87
|
+
# :billing_basis # must be 1, 7, 7.5, or 8
|
88
|
+
# :budget_units # must be Hours, Days, or Monetary
|
89
|
+
# :status # must be Active or Completed
|
90
|
+
|
91
|
+
@project = Project.new params
|
92
|
+
@project.save
|
93
|
+
|
94
|
+
<b>Update project</b>
|
95
|
+
|
96
|
+
@project.name = 'Web design project'
|
97
|
+
@project.save
|
98
|
+
|
99
|
+
<b>Delete project</b>
|
100
|
+
|
101
|
+
Project.delete id
|
102
|
+
# or
|
103
|
+
@project.destroy
|
104
|
+
|
105
|
+
<b>Nested resources</b>
|
106
|
+
|
107
|
+
@invoices = @project.invoices
|
108
|
+
@timeslips = @project.timeslips
|
49
109
|
|
50
110
|
=== Tasks
|
51
111
|
|
52
|
-
|
112
|
+
<b>Find tasks</b>
|
113
|
+
|
114
|
+
@tasks = Task.find :all # returns all tasks
|
115
|
+
@task = Task.find id # returns specific task
|
116
|
+
|
117
|
+
<b>Create task</b>
|
118
|
+
|
119
|
+
# Required attributes
|
120
|
+
# :name
|
121
|
+
|
122
|
+
@task = Task.new params
|
123
|
+
@task.save
|
124
|
+
|
125
|
+
<b>Update task</b>
|
126
|
+
|
127
|
+
@task.name = 'Create wireframes'
|
128
|
+
@task.save
|
129
|
+
|
130
|
+
<b>Delete task</b>
|
131
|
+
|
132
|
+
Task.delete id
|
133
|
+
# or
|
134
|
+
@task.destroy
|
135
|
+
|
136
|
+
=== Invoices
|
137
|
+
|
138
|
+
<b>Find Invoices</b>
|
139
|
+
|
140
|
+
@invoices = Invoice.find :all # returns all invoices
|
141
|
+
@invoice = Invoice.find id # returns specific invoice
|
142
|
+
|
143
|
+
<b>Create invoice</b>
|
144
|
+
|
145
|
+
# Required attributes
|
146
|
+
# :contact_id
|
147
|
+
# :project_id
|
148
|
+
# :dated_on
|
149
|
+
# :reference
|
150
|
+
# :status
|
151
|
+
|
152
|
+
@invoice = Invoice.new params
|
153
|
+
@invoice.save
|
154
|
+
|
155
|
+
<b>Update invoice</b>
|
156
|
+
|
157
|
+
@invoice.status = 'Sent'
|
158
|
+
@invoice.save
|
159
|
+
|
160
|
+
<b>Delete invoice</b>
|
161
|
+
|
162
|
+
Invoice.delete id
|
163
|
+
# or
|
164
|
+
@invoice.destroy
|
165
|
+
|
166
|
+
<b>Changing status</b>
|
167
|
+
|
168
|
+
@invoice.mark_as_draft
|
169
|
+
@invoice.mark_as_sent
|
170
|
+
@invoice.mark_as_cancelled
|
171
|
+
|
172
|
+
=== Invoice items
|
173
|
+
|
174
|
+
<b>Find invoice items</b>
|
175
|
+
|
176
|
+
@invoice_items = InvoiceItem.find :all # returns all invoice items
|
177
|
+
@invoice_item = InvoiceItem.find id # returns specific invoice item
|
178
|
+
|
179
|
+
<b>Create invoice item</b>
|
180
|
+
|
181
|
+
# Required attributes
|
182
|
+
# :item_type # must be Hours, Days, Months, Years, Products, Services, Expenses, Discount, Credit, Comment
|
183
|
+
# :description
|
184
|
+
# :quantity
|
185
|
+
# :price
|
186
|
+
# :sales_tax_rate
|
187
|
+
|
188
|
+
@invoice_item = InvoiceItem.new params
|
189
|
+
@invoice_item.save
|
190
|
+
|
191
|
+
<b>Update invoice item</b>
|
192
|
+
|
193
|
+
@invoice_item.name = 'Create wireframes'
|
194
|
+
@invoice_item.save
|
195
|
+
|
196
|
+
<b>Delete invoice item</b>
|
197
|
+
|
198
|
+
InvoiceItem.delete id
|
199
|
+
# or
|
200
|
+
@invoice_item.destroy
|
53
201
|
|
54
202
|
=== Timeslips
|
55
203
|
|
56
|
-
|
57
|
-
|
58
|
-
@
|
204
|
+
<b>Find timeslips</b>
|
205
|
+
|
206
|
+
@timeslips = Timeslip.find :all, :params => {:from => '2009-10-01', :to => '2009-10-30'}
|
207
|
+
# returns all timeslips (:from and :to dates required)
|
208
|
+
@timeslip = Timeslip.find id # returns specific timeslip
|
209
|
+
|
210
|
+
<b>Create timeslip</b>
|
211
|
+
|
212
|
+
# Required attributes
|
213
|
+
# :user_id
|
214
|
+
# :hours
|
215
|
+
# :dated_on
|
216
|
+
# :task_id OR :new_task
|
217
|
+
|
218
|
+
@timeslip = Timeslip.new params
|
219
|
+
@timeslip.save
|
220
|
+
|
221
|
+
<b>Update timeslip</b>
|
222
|
+
|
223
|
+
@timeslip.hours = '3.5'
|
224
|
+
@timeslip.save
|
225
|
+
|
226
|
+
<b>Delete timeslip</b>
|
227
|
+
|
228
|
+
Timeslip.delete id
|
229
|
+
# or
|
230
|
+
@timeslip.destroy
|
59
231
|
|
60
232
|
== Author
|
61
233
|
|
data/Rakefile
CHANGED
@@ -5,15 +5,14 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "freeagent_api"
|
8
|
-
gem.summary = %Q{
|
9
|
-
gem.description = %Q{This is an
|
8
|
+
gem.summary = %Q{ActiveResource Ruby wrapper for the Freeagent Central API.}
|
9
|
+
gem.description = %Q{This is an ActiveResource Ruby wrapper for the Freeagent API. Currently supports the following API resources: Company, Contacts, Projects, Tasks, Invoices, Invoice Items, Timeslips (more will follow).}
|
10
10
|
gem.email = "aaron@gc4.co.uk"
|
11
11
|
gem.homepage = "http://github.com/aaronrussell/freeagent_api"
|
12
12
|
gem.authors = ["Aaron Russell"]
|
13
13
|
gem.add_development_dependency "thoughtbot-shoulda"
|
14
|
-
gem.
|
15
|
-
gem.add_dependency "
|
16
|
-
gem.add_dependency "api_cache"
|
14
|
+
gem.add_development_dependency "fakeweb"
|
15
|
+
gem.add_dependency "activeresource"
|
17
16
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
17
|
end
|
19
18
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/freeagent_api.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{freeagent_api}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Aaron Russell"]
|
12
|
-
s.date = %q{2009-10-
|
13
|
-
s.description = %q{This is an
|
12
|
+
s.date = %q{2009-10-27}
|
13
|
+
s.description = %q{This is an ActiveResource Ruby wrapper for the Freeagent API. Currently supports the following API resources: Company, Contacts, Projects, Tasks, Invoices, Invoice Items, Timeslips (more will follow).}
|
14
14
|
s.email = %q{aaron@gc4.co.uk}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
@@ -25,17 +25,49 @@ Gem::Specification.new do |s|
|
|
25
25
|
"VERSION",
|
26
26
|
"freeagent_api.gemspec",
|
27
27
|
"lib/freeagent_api.rb",
|
28
|
-
"test/
|
29
|
-
"test/
|
28
|
+
"test/authentication_test.rb",
|
29
|
+
"test/company_test.rb",
|
30
|
+
"test/contact_test.rb",
|
31
|
+
"test/invoice_item_test.rb",
|
32
|
+
"test/invoice_test.rb",
|
33
|
+
"test/project_test.rb",
|
34
|
+
"test/stubs/company/invoice_timeline",
|
35
|
+
"test/stubs/company/tax_timeline",
|
36
|
+
"test/stubs/contacts/find_all",
|
37
|
+
"test/stubs/contacts/find_single",
|
38
|
+
"test/stubs/http/200",
|
39
|
+
"test/stubs/http/201",
|
40
|
+
"test/stubs/invoice_items/find_all",
|
41
|
+
"test/stubs/invoice_items/find_single",
|
42
|
+
"test/stubs/invoices/find_all",
|
43
|
+
"test/stubs/invoices/find_single",
|
44
|
+
"test/stubs/projects/find_all",
|
45
|
+
"test/stubs/projects/find_single",
|
46
|
+
"test/stubs/projects/invoices",
|
47
|
+
"test/stubs/projects/timeslips",
|
48
|
+
"test/stubs/tasks/find_all",
|
49
|
+
"test/stubs/tasks/find_single",
|
50
|
+
"test/stubs/timeslips/find_all",
|
51
|
+
"test/stubs/timeslips/find_single",
|
52
|
+
"test/task_test.rb",
|
53
|
+
"test/test_helper.rb",
|
54
|
+
"test/timeslip_test.rb"
|
30
55
|
]
|
31
56
|
s.homepage = %q{http://github.com/aaronrussell/freeagent_api}
|
32
57
|
s.rdoc_options = ["--charset=UTF-8"]
|
33
58
|
s.require_paths = ["lib"]
|
34
59
|
s.rubygems_version = %q{1.3.5}
|
35
|
-
s.summary = %q{
|
60
|
+
s.summary = %q{ActiveResource Ruby wrapper for the Freeagent Central API.}
|
36
61
|
s.test_files = [
|
37
|
-
"test/
|
38
|
-
"test/
|
62
|
+
"test/authentication_test.rb",
|
63
|
+
"test/company_test.rb",
|
64
|
+
"test/contact_test.rb",
|
65
|
+
"test/invoice_item_test.rb",
|
66
|
+
"test/invoice_test.rb",
|
67
|
+
"test/project_test.rb",
|
68
|
+
"test/task_test.rb",
|
69
|
+
"test/test_helper.rb",
|
70
|
+
"test/timeslip_test.rb"
|
39
71
|
]
|
40
72
|
|
41
73
|
if s.respond_to? :specification_version then
|
@@ -44,19 +76,16 @@ Gem::Specification.new do |s|
|
|
44
76
|
|
45
77
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
46
78
|
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
47
|
-
s.
|
48
|
-
s.add_runtime_dependency(%q<
|
49
|
-
s.add_runtime_dependency(%q<api_cache>, [">= 0"])
|
79
|
+
s.add_development_dependency(%q<fakeweb>, [">= 0"])
|
80
|
+
s.add_runtime_dependency(%q<activeresource>, [">= 0"])
|
50
81
|
else
|
51
82
|
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
52
|
-
s.add_dependency(%q<
|
53
|
-
s.add_dependency(%q<
|
54
|
-
s.add_dependency(%q<api_cache>, [">= 0"])
|
83
|
+
s.add_dependency(%q<fakeweb>, [">= 0"])
|
84
|
+
s.add_dependency(%q<activeresource>, [">= 0"])
|
55
85
|
end
|
56
86
|
else
|
57
87
|
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
58
|
-
s.add_dependency(%q<
|
59
|
-
s.add_dependency(%q<
|
60
|
-
s.add_dependency(%q<api_cache>, [">= 0"])
|
88
|
+
s.add_dependency(%q<fakeweb>, [">= 0"])
|
89
|
+
s.add_dependency(%q<activeresource>, [">= 0"])
|
61
90
|
end
|
62
91
|
end
|
data/lib/freeagent_api.rb
CHANGED
@@ -1,172 +1,115 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require '
|
3
|
-
require 'net/https'
|
4
|
-
require 'api_cache'
|
5
|
-
require 'activesupport'
|
2
|
+
require 'activeresource'
|
6
3
|
|
7
4
|
module Freeagent
|
8
5
|
|
9
6
|
class << self
|
10
|
-
|
11
|
-
|
12
|
-
def self.domain=(domain)
|
13
|
-
@domain = domain
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.username=(username)
|
17
|
-
@username = username
|
7
|
+
def authenticate(options)
|
8
|
+
Base.authenticate(options)
|
18
9
|
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Error < StandardError; end
|
19
13
|
|
20
|
-
|
21
|
-
|
14
|
+
class Base < ActiveResource::Base
|
15
|
+
def self.authenticate(options)
|
16
|
+
self.site = "https://#{options[:domain]}"
|
17
|
+
self.user = options[:username]
|
18
|
+
self.password = options[:password]
|
22
19
|
end
|
23
20
|
end
|
24
21
|
|
25
|
-
|
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
|
22
|
+
# Company
|
33
23
|
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
24
|
+
class Company
|
25
|
+
def self.invoice_timeline
|
26
|
+
InvoiceTimeline.find :all, :from => '/company/invoice_timeline.xml'
|
52
27
|
end
|
53
|
-
|
54
|
-
|
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
|
28
|
+
def self.tax_timeline
|
29
|
+
TaxTimeline.find :all, :from => '/company/tax_timeline.xml'
|
64
30
|
end
|
65
|
-
|
31
|
+
end
|
32
|
+
class InvoiceTimeline < Base
|
33
|
+
self.prefix = '/company/'
|
34
|
+
end
|
35
|
+
class TaxTimeline < Base
|
36
|
+
self.prefix = '/company/'
|
66
37
|
end
|
67
38
|
|
39
|
+
# Contacts
|
40
|
+
|
68
41
|
class Contact < Base
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
42
|
+
end
|
43
|
+
|
44
|
+
# Projects
|
45
|
+
|
46
|
+
class Project < Base
|
47
|
+
|
48
|
+
def invoices
|
49
|
+
Invoice.find :all, :from => "/projects/#{id}/invoices.xml"
|
76
50
|
end
|
77
|
-
|
78
|
-
def
|
79
|
-
|
80
|
-
contacts = parse('contact', @elements)
|
81
|
-
return contacts[0]
|
51
|
+
|
52
|
+
def timeslips
|
53
|
+
Timeslip.find :all, :from => "/projects/#{id}/timeslips.xml"
|
82
54
|
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# Tasks - Complete
|
59
|
+
|
60
|
+
class Task < Base
|
61
|
+
self.prefix = '/projects/:project_id/'
|
83
62
|
end
|
84
63
|
|
64
|
+
# Invoices - Complete
|
65
|
+
|
85
66
|
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
67
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
else
|
93
|
-
get '/invoices'
|
68
|
+
def mark_as_draft
|
69
|
+
connection.put("/invoices/#{id}/mark_as_draft.xml", encode, self.class.headers).tap do |response|
|
70
|
+
load_attributes_from_response(response)
|
94
71
|
end
|
95
|
-
invoices = parse('invoices/invoice', @elements)
|
96
|
-
return invoices.reverse
|
97
72
|
end
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
invoices = parse('invoice', @elements)
|
102
|
-
invoices.each do |i|
|
103
|
-
i.invoice_items = InvoiceItem.find_all(invoice_id)
|
73
|
+
def mark_as_sent
|
74
|
+
connection.put("/invoices/#{id}/mark_as_sent.xml", encode, self.class.headers).tap do |response|
|
75
|
+
load_attributes_from_response(response)
|
104
76
|
end
|
105
|
-
return invoices[0]
|
106
77
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
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
|
78
|
+
def mark_as_cancelled
|
79
|
+
connection.put("/invoices/#{id}/mark_as_cancelled.xml", encode, self.class.headers).tap do |response|
|
80
|
+
load_attributes_from_response(response)
|
81
|
+
end
|
127
82
|
end
|
128
83
|
|
129
|
-
def self.find(project_id)
|
130
|
-
get '/projects/'+project_id
|
131
|
-
projects = parse('project', @elements)
|
132
|
-
return projects[0]
|
133
|
-
end
|
134
84
|
end
|
135
85
|
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|
86
|
+
# Invoice items - Complete
|
87
|
+
|
88
|
+
class InvoiceItem < Base
|
89
|
+
self.prefix = '/invoices/:invoice_id/'
|
145
90
|
end
|
91
|
+
|
92
|
+
# Timeslips
|
146
93
|
|
147
94
|
class Timeslip < Base
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
if
|
153
|
-
|
154
|
-
|
155
|
-
|
95
|
+
|
96
|
+
def self.find(*arguments)
|
97
|
+
scope = arguments.slice!(0)
|
98
|
+
options = arguments.slice!(0) || {}
|
99
|
+
if options[:params] && options[:params][:from] && options[:params][:to]
|
100
|
+
options[:params][:view] = options[:params][:from]+'_'+options[:params][:to]
|
101
|
+
options[:params].delete(:from)
|
102
|
+
options[:params].delete(:to)
|
156
103
|
end
|
157
|
-
|
158
|
-
|
159
|
-
|
104
|
+
|
105
|
+
case scope
|
106
|
+
when :all then find_every(options)
|
107
|
+
when :first then find_every(options).first
|
108
|
+
when :last then find_every(options).last
|
109
|
+
when :one then find_one(options)
|
110
|
+
else find_single(scope, options)
|
160
111
|
end
|
161
|
-
|
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
|
112
|
+
end
|
169
113
|
end
|
170
|
-
|
171
|
-
|
114
|
+
|
172
115
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FreeagentApiTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Authentication details" do
|
6
|
+
should "match what was set" do
|
7
|
+
assert_equal URI.parse('https://testuser.freeagentcentral.com'), Base.site
|
8
|
+
assert_equal 'testuser', Base.user
|
9
|
+
assert_equal 'testpass', Base.password
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CompanyTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
fake_it_all
|
6
|
+
|
7
|
+
context "Invoice timeline" do
|
8
|
+
setup do
|
9
|
+
@inv_timeline = Company.invoice_timeline
|
10
|
+
end
|
11
|
+
should "return an array" do
|
12
|
+
assert @inv_timeline.is_a? Array
|
13
|
+
end
|
14
|
+
should "return invoice timeline items" do
|
15
|
+
assert_equal 12, @inv_timeline.size
|
16
|
+
assert @inv_timeline.first.is_a? InvoiceTimeline
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "Tax timeline" do
|
21
|
+
setup do
|
22
|
+
@tax_timeline = Company.tax_timeline
|
23
|
+
end
|
24
|
+
should "return an array" do
|
25
|
+
assert @tax_timeline.is_a? Array
|
26
|
+
end
|
27
|
+
should "return projects" do
|
28
|
+
assert_equal 3, @tax_timeline.size
|
29
|
+
assert @tax_timeline.first.is_a? TaxTimeline
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|