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 CHANGED
@@ -2,4 +2,4 @@
2
2
  .DS_Store
3
3
  coverage
4
4
  rdoc
5
- pkg
5
+ pkg
data/README.rdoc CHANGED
@@ -1,17 +1,24 @@
1
1
  = freeagent_api
2
2
 
3
- Simple Ruby interface to the Freeagent Central API (http://www.freeagentcentral.com/developers/freeagent-api).
3
+ Simple ActiveResource Ruby wrapper for the Freeagent Central API (http://www.freeagentcentral.com/developers/freeagent-api).
4
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):
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
- There is no test suite yet. If you feel brave, then feel free to clone, fork and play around.
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.domain = 'yourdomain.freeagentcentral.com'
27
- Freeagent.username = 'your@login.com'
28
- Freeagent.password = 'your_password'
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
- @contacts = Contact.find_all # returns all contacts
33
- @contact = Contact.find(contact_id) # returns specific contact
49
+ <b>Find contacts</b>
34
50
 
35
- === Invoice
51
+ @contacts = Contact.find :all # returns all contacts
52
+ @contact = Contact.find id # returns specific contact
36
53
 
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
54
+ <b>Create contact</b>
40
55
 
41
- === Invoice items
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
- @items = InvoiceItem.find_all(invoice_id) # returns all items for invoice
68
+ <b>Delete contact</b>
69
+
70
+ Contact.delete id
71
+ # or
72
+ @contact.destroy
44
73
 
45
74
  === Projects
46
75
 
47
- @projects = Project.find_all # returns all projects
48
- @project = Project.find(project_id) # returns specific project
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
- @task = Task.find(project_id, task_id) # returns specific task for project
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
- @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
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{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).}
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.add_dependency "activesupport"
15
- gem.add_dependency "nokogiri"
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
1
+ 0.2.0
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{freeagent_api}
8
- s.version = "0.1.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-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).}
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/freeagent_api_test.rb",
29
- "test/test_helper.rb"
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{Simple Ruby interface to the Freeagent Central API.}
60
+ s.summary = %q{ActiveResource Ruby wrapper for the Freeagent Central API.}
36
61
  s.test_files = [
37
- "test/freeagent_api_test.rb",
38
- "test/test_helper.rb"
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.add_runtime_dependency(%q<activesupport>, [">= 0"])
48
- s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
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<activesupport>, [">= 0"])
53
- s.add_dependency(%q<nokogiri>, [">= 0"])
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<activesupport>, [">= 0"])
59
- s.add_dependency(%q<nokogiri>, [">= 0"])
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 'nokogiri'
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
- 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
7
+ def authenticate(options)
8
+ Base.authenticate(options)
18
9
  end
10
+ end
11
+
12
+ class Error < StandardError; end
19
13
 
20
- def self.password=(password)
21
- @password = password
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
- 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
22
+ # Company
33
23
 
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
24
+ class Company
25
+ def self.invoice_timeline
26
+ InvoiceTimeline.find :all, :from => '/company/invoice_timeline.xml'
52
27
  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
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
- @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
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 self.find(contact_id)
79
- get '/contacts/'+contact_id
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 self.find_all(project_id = false)
90
- if project_id
91
- get '/projects/'+project_id+'/invoices'
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
- 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)
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
- 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
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
- 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
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
- @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'
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
- timeslips = parse('timeslips/timeslip', @elements)
158
- timeslips.each do |t|
159
- t.task = Task.find(project_id, t.task_id)
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
- 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
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