mirror42-freshbooks.rb 3.0.25
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.
- checksums.yaml +15 -0
- data/History.txt +8 -0
- data/LICENSE +10 -0
- data/Manifest.txt +45 -0
- data/README +58 -0
- data/Rakefile +27 -0
- data/lib/freshbooks.rb +95 -0
- data/lib/freshbooks/base.rb +176 -0
- data/lib/freshbooks/category.rb +11 -0
- data/lib/freshbooks/client.rb +23 -0
- data/lib/freshbooks/connection.rb +162 -0
- data/lib/freshbooks/estimate.rb +15 -0
- data/lib/freshbooks/expense.rb +12 -0
- data/lib/freshbooks/invoice.rb +22 -0
- data/lib/freshbooks/item.rb +11 -0
- data/lib/freshbooks/line.rb +11 -0
- data/lib/freshbooks/links.rb +7 -0
- data/lib/freshbooks/list_proxy.rb +80 -0
- data/lib/freshbooks/payment.rb +13 -0
- data/lib/freshbooks/project.rb +12 -0
- data/lib/freshbooks/recurring.rb +16 -0
- data/lib/freshbooks/response.rb +25 -0
- data/lib/freshbooks/schema/definition.rb +20 -0
- data/lib/freshbooks/schema/mixin.rb +40 -0
- data/lib/freshbooks/staff.rb +13 -0
- data/lib/freshbooks/task.rb +12 -0
- data/lib/freshbooks/time_entry.rb +12 -0
- data/lib/freshbooks/xml_serializer.rb +17 -0
- data/lib/freshbooks/xml_serializer/serializers.rb +116 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/fixtures/freshbooks_credentials.sample.yml +3 -0
- data/test/fixtures/invoice_create_response.xml +4 -0
- data/test/fixtures/invoice_get_response.xml +54 -0
- data/test/fixtures/invoice_list_response.xml +109 -0
- data/test/fixtures/success_response.xml +2 -0
- data/test/mock_connection.rb +13 -0
- data/test/schema/test_definition.rb +36 -0
- data/test/schema/test_mixin.rb +39 -0
- data/test/test_base.rb +151 -0
- data/test/test_connection.rb +145 -0
- data/test/test_helper.rb +48 -0
- data/test/test_invoice.rb +125 -0
- data/test/test_list_proxy.rb +60 -0
- data/test/test_page.rb +50 -0
- metadata +157 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper.rb'
|
2
|
+
|
3
|
+
module Schema
|
4
|
+
class TestDefinition < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@definition = FreshBooks::Schema::Definition.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_method_missing
|
10
|
+
# Empty
|
11
|
+
assert_equal 0, @definition.members.size
|
12
|
+
|
13
|
+
# One type
|
14
|
+
@definition.string :name
|
15
|
+
assert_equal 1, @definition.members.size
|
16
|
+
assert_equal({ :type => :string, :read_only => false }, @definition.members["name"])
|
17
|
+
|
18
|
+
# Multiple attributes
|
19
|
+
@definition.fixnum :version, :po_number
|
20
|
+
assert_equal 3, @definition.members.size
|
21
|
+
assert_equal({ :type => :fixnum, :read_only => false }, @definition.members["version"])
|
22
|
+
assert_equal({ :type => :fixnum, :read_only => false }, @definition.members["po_number"])
|
23
|
+
|
24
|
+
# Multiple times
|
25
|
+
@definition.fixnum :lock_number
|
26
|
+
assert_equal 4, @definition.members.size
|
27
|
+
assert_equal({ :type => :fixnum, :read_only => false }, @definition.members["lock_number"])
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_method_missing_extra_options
|
31
|
+
@definition.fixnum :version, :po_number, :read_only => true
|
32
|
+
assert_equal({ :type => :fixnum, :read_only => true }, @definition.members["version"])
|
33
|
+
assert_equal({ :type => :fixnum, :read_only => true }, @definition.members["po_number"])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper.rb'
|
2
|
+
|
3
|
+
module Schema
|
4
|
+
class TestMixin < Test::Unit::TestCase
|
5
|
+
def test_define_schema__unique_definition_per_class
|
6
|
+
assert MyItem.schema_definition.members.include?("name")
|
7
|
+
assert !MyItem.schema_definition.members.include?("name2")
|
8
|
+
|
9
|
+
assert MyItem2.schema_definition.members.include?("name2")
|
10
|
+
assert !MyItem2.schema_definition.members.include?("name")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_define_schema__creates_attr_accessors
|
14
|
+
assert MyItem.public_method_defined?("name")
|
15
|
+
assert MyItem.public_method_defined?("name=")
|
16
|
+
|
17
|
+
assert MyItem2.public_method_defined?("name2")
|
18
|
+
assert MyItem2.public_method_defined?("name2=")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_define_schema__creates_read_only_attr_accessors
|
22
|
+
assert MyItem.public_method_defined?("read_only_name")
|
23
|
+
assert MyItem.protected_method_defined?("read_only_name=")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class MyItem < FreshBooks::Base
|
28
|
+
define_schema do |s|
|
29
|
+
s.string :name
|
30
|
+
s.string :read_only_name, :read_only => true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class MyItem2 < FreshBooks::Base
|
35
|
+
define_schema do |s|
|
36
|
+
s.string :name2
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/test/test_base.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestBase < Test::Unit::TestCase
|
4
|
+
def test_establish_connection
|
5
|
+
assert_nil FreshBooks::Base.connection
|
6
|
+
|
7
|
+
FreshBooks::Base.establish_connection("company.freshbooks.com", "auth_token")
|
8
|
+
connection = FreshBooks::Base.connection
|
9
|
+
assert_not_nil connection
|
10
|
+
assert_equal "company.freshbooks.com", connection.account_url
|
11
|
+
assert_equal "auth_token", connection.auth_token
|
12
|
+
|
13
|
+
FreshBooks::Base.establish_connection("company2.freshbooks.com", "auth_token2")
|
14
|
+
connection = FreshBooks::Base.connection
|
15
|
+
assert_not_nil connection
|
16
|
+
assert_equal "company2.freshbooks.com", connection.account_url
|
17
|
+
assert_equal "auth_token2", connection.auth_token
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_new_from_xml_to_xml__round_trip
|
21
|
+
xml = <<-EOS
|
22
|
+
<my_item>
|
23
|
+
<name>name1</name>
|
24
|
+
<amount>4.5</amount>
|
25
|
+
<read_only_number>5</read_only_number>
|
26
|
+
<number>6</number>
|
27
|
+
<visible>1</visible>
|
28
|
+
<date>2008-02-01</date>
|
29
|
+
<created_at>2008-10-22 13:57:00</created_at>
|
30
|
+
<my_address>
|
31
|
+
<street1>street1</street1>
|
32
|
+
</my_address>
|
33
|
+
<my_lines>
|
34
|
+
<my_line>
|
35
|
+
<description>description</description>
|
36
|
+
</my_line>
|
37
|
+
</my_lines>
|
38
|
+
</my_item>
|
39
|
+
EOS
|
40
|
+
doc = REXML::Document.new(xml)
|
41
|
+
|
42
|
+
item = FreshBooks::MyItem.new_from_xml(doc.root)
|
43
|
+
assert_equal "name1", item.name
|
44
|
+
assert_equal 5, item.read_only_number
|
45
|
+
assert_equal 6, item.number
|
46
|
+
assert_equal 4.5, item.amount
|
47
|
+
assert_equal true, item.visible
|
48
|
+
assert_equal Date.new(2008, 2, 1), item.date
|
49
|
+
assert_equal DateTime.parse("2008-10-22 13:57:00 -04:00"), item.created_at
|
50
|
+
assert_equal "street1", item.my_address.street1
|
51
|
+
assert_equal 1, item.my_lines.size
|
52
|
+
assert_equal "description", item.my_lines.first.description
|
53
|
+
|
54
|
+
# If someone knows a good way to compare xml docs where ordering doesn't matter
|
55
|
+
# let me know. This can be refactored and improved greatly.
|
56
|
+
xml_out = item.to_xml.to_s.strip
|
57
|
+
assert_equal "<my_item>", xml_out.first(9)
|
58
|
+
assert xml_out.include?("<name>name1</name>")
|
59
|
+
assert xml_out.include?("<amount>4.5</amount>")
|
60
|
+
assert xml_out.include?("<visible>1</visible>")
|
61
|
+
assert !xml_out.include?("<read_only_number>5</read_only_number>") # this is read only
|
62
|
+
assert xml_out.include?("<number>6</number>")
|
63
|
+
assert xml_out.include?("<date>2008-02-01</date>")
|
64
|
+
assert xml_out.include?("<created_at>2008-10-22 13:57:00</created_at>")
|
65
|
+
assert xml_out.include?("<my_address><street1>street1</street1></my_address>")
|
66
|
+
assert xml_out.include?("<my_lines><my_line><description>description</description></my_line></my_lines>")
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_create_objects_with_initializer_arguments
|
70
|
+
invoice_1 = FreshBooks::Invoice.new
|
71
|
+
invoice_1.client_id = 1
|
72
|
+
invoice_1.lines = [FreshBooks::Line.new, FreshBooks::Line.new]
|
73
|
+
invoice_1.lines[0].name = "Awesomeness"
|
74
|
+
invoice_1.lines[0].unit_cost = 9999
|
75
|
+
invoice_1.lines[0].quantity = 42
|
76
|
+
invoice_1.lines[1].name = "Ninja skills"
|
77
|
+
invoice_1.lines[1].unit_cost = 349
|
78
|
+
invoice_1.lines[1].quantity = 100
|
79
|
+
|
80
|
+
invoice_2 = FreshBooks::Invoice.new(
|
81
|
+
:client_id => 1,
|
82
|
+
:lines => [
|
83
|
+
FreshBooks::Line.new(
|
84
|
+
:name => "Awesomeness",
|
85
|
+
:unit_cost => 9999,
|
86
|
+
:quantity => 42
|
87
|
+
),
|
88
|
+
FreshBooks::Line.new(
|
89
|
+
:name => "Ninja skills",
|
90
|
+
:unit_cost => 349,
|
91
|
+
:quantity => 100
|
92
|
+
)
|
93
|
+
]
|
94
|
+
)
|
95
|
+
|
96
|
+
assert_equal invoice_1.to_xml, invoice_2.to_xml
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_can_handle_all_zero_updated_at
|
100
|
+
xml = <<-END_XML
|
101
|
+
<my_client>
|
102
|
+
<client_id>3</client_id>
|
103
|
+
<first_name>Test</first_name>
|
104
|
+
<last_name>User</last_name>
|
105
|
+
<organization>User Testing</organization>
|
106
|
+
<updated>0000-00-00 00:00:00</updated>
|
107
|
+
</my_client>
|
108
|
+
END_XML
|
109
|
+
doc = REXML::Document.new(xml)
|
110
|
+
|
111
|
+
item = FreshBooks::MyClient.new_from_xml(doc.root)
|
112
|
+
assert_equal nil, item.updated
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
module FreshBooks
|
118
|
+
class MyItem < FreshBooks::Base
|
119
|
+
define_schema do |s|
|
120
|
+
s.string :name
|
121
|
+
s.fixnum :read_only_number, :read_only => true
|
122
|
+
s.fixnum :number
|
123
|
+
s.float :amount
|
124
|
+
s.boolean :visible
|
125
|
+
s.date :date
|
126
|
+
s.date_time :created_at
|
127
|
+
s.object :my_address
|
128
|
+
s.array :my_lines
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class MyClient < FreshBooks::Base
|
133
|
+
define_schema do |s|
|
134
|
+
s.string :first_name, :last_name, :organization
|
135
|
+
s.fixnum :client_id
|
136
|
+
s.date_time :updated
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class MyAddress < FreshBooks::Base
|
141
|
+
define_schema do |s|
|
142
|
+
s.string :street1
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class MyLine < FreshBooks::Base
|
147
|
+
define_schema do |s|
|
148
|
+
s.string :description
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestConnection < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@connection = FreshBooks::Connection.new("company.freshbooks.com", "auth_token")
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_connection_accessors
|
9
|
+
assert_equal "company.freshbooks.com", @connection.account_url
|
10
|
+
assert_equal "auth_token", @connection.auth_token
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_connection_request_headers
|
14
|
+
request_headers = { "key" => "value" }
|
15
|
+
connection = FreshBooks::Connection.new("company.freshbooks.com", "auth_token", request_headers)
|
16
|
+
assert_equal request_headers, connection.request_headers
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def test_create_request__array_of_elements
|
21
|
+
request = @connection.send(:create_request, 'mymethod', [['element1', 'value1'], [:element2, :value2]])
|
22
|
+
assert_equal "<?xml version='1.0' encoding='UTF-8'?><request method='mymethod'><element1>value1</element1><element2>value2</element2></request>", request
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_create_request__base_object_element
|
26
|
+
invoice = FreshBooks::Invoice.new
|
27
|
+
invoice.expects(:to_xml).with().returns("<invoice><number>23</number></invoice>")
|
28
|
+
|
29
|
+
request = @connection.send(:create_request, 'mymethod', 'invoice' => invoice)
|
30
|
+
assert_equal "<?xml version='1.0' encoding='UTF-8'?><request method='mymethod'><invoice><number>23</number></invoice></request>", request
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_check_for_api_error__success
|
34
|
+
body = "body xml"
|
35
|
+
response = Net::HTTPSuccess.new("1.1", "200", "message")
|
36
|
+
response.expects(:body).with().returns(body)
|
37
|
+
assert_equal body, @connection.send(:check_for_api_error, response)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_check_for_api_error__unknown_system
|
41
|
+
response = Net::HTTPMovedPermanently.new("1.1", "301", "message")
|
42
|
+
response.stubs(:[]).with("location").returns("loginSearch")
|
43
|
+
assert_raise(FreshBooks::UnknownSystemError) do
|
44
|
+
@connection.send(:check_for_api_error, response)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_check_for_api_error__deactivated
|
49
|
+
response = Net::HTTPMovedPermanently.new("1.1", "301", "message")
|
50
|
+
response.stubs(:[]).with("location").returns("deactivated")
|
51
|
+
assert_raise(FreshBooks::AccountDeactivatedError) do
|
52
|
+
@connection.send(:check_for_api_error, response)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_check_for_api_error__unauthorized
|
57
|
+
response = Net::HTTPUnauthorized.new("1.1", "401", "message")
|
58
|
+
assert_raise(FreshBooks::AuthenticationError) do
|
59
|
+
@connection.send(:check_for_api_error, response)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_check_for_api_error__bad_request
|
64
|
+
response = Net::HTTPBadRequest.new("1.1", "401", "message")
|
65
|
+
assert_raise(FreshBooks::ApiAccessNotEnabledError) do
|
66
|
+
@connection.send(:check_for_api_error, response)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_check_for_api_error__internal_error
|
71
|
+
response = Net::HTTPBadGateway.new("1.1", "502", "message")
|
72
|
+
assert_raise(FreshBooks::InternalError) do
|
73
|
+
@connection.send(:check_for_api_error, response)
|
74
|
+
end
|
75
|
+
|
76
|
+
response = Net::HTTPMovedPermanently.new("1.1", "301", "message")
|
77
|
+
response.stubs(:[]).with("location").returns("somePage")
|
78
|
+
assert_raise(FreshBooks::InternalError) do
|
79
|
+
@connection.send(:check_for_api_error, response)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_close_is_only_called_once_in_ntexted_start_sessions
|
84
|
+
@connection.expects(:obtain_connection)
|
85
|
+
@connection.expects(:close)
|
86
|
+
|
87
|
+
@connection.start_session { @connection.start_session { } }
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_reconnect
|
91
|
+
connection = stub()
|
92
|
+
|
93
|
+
@connection.expects(:close).with()
|
94
|
+
@connection.expects(:obtain_connection).with(true).returns(connection)
|
95
|
+
|
96
|
+
assert_equal connection, @connection.send(:reconnect)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_post_request_successfull_request
|
100
|
+
request = "<request></request>"
|
101
|
+
response = "<response></response>"
|
102
|
+
|
103
|
+
http_connection = stub()
|
104
|
+
http_connection.expects(:request).with(request).returns(response)
|
105
|
+
@connection.expects(:start_session).with().yields(http_connection)
|
106
|
+
|
107
|
+
assert_equal response, @connection.send(:post_request, request)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_post_request_eof_error_retry
|
111
|
+
request = "<request></request>"
|
112
|
+
response = "<response></response>"
|
113
|
+
eof_error = EOFError.new("End of file error")
|
114
|
+
|
115
|
+
bad_http_connection = stub()
|
116
|
+
bad_http_connection.expects(:request).with(request).raises(eof_error)
|
117
|
+
|
118
|
+
new_http_connection = stub()
|
119
|
+
new_http_connection.expects(:request).with(request).returns(response)
|
120
|
+
|
121
|
+
@connection.expects(:start_session).with().yields(bad_http_connection)
|
122
|
+
@connection.expects(:reconnect).with().returns(new_http_connection)
|
123
|
+
|
124
|
+
assert_equal response, @connection.send(:post_request, request)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_post_request_eof_error_retry_only_retry_once
|
128
|
+
request = "<request></request>"
|
129
|
+
response = "<response></response>"
|
130
|
+
eof_error = EOFError.new("End of file error")
|
131
|
+
|
132
|
+
bad_http_connection = stub()
|
133
|
+
bad_http_connection.expects(:request).with(request).raises(eof_error)
|
134
|
+
|
135
|
+
new_http_connection = stub()
|
136
|
+
new_http_connection.expects(:request).with(request).raises(eof_error)
|
137
|
+
|
138
|
+
@connection.expects(:start_session).with().yields(bad_http_connection)
|
139
|
+
@connection.expects(:reconnect).with().returns(new_http_connection)
|
140
|
+
|
141
|
+
assert_raises(EOFError, eof_error.message) do
|
142
|
+
@connection.send(:post_request, request)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/freshbooks'
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
require 'test/unit'
|
5
|
+
require File.dirname(__FILE__) + '/mock_connection'
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'mocha'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rubygems'
|
11
|
+
gem 'mocha'
|
12
|
+
require 'mocha'
|
13
|
+
end
|
14
|
+
|
15
|
+
class Test::Unit::TestCase
|
16
|
+
|
17
|
+
@@fixtures = {}
|
18
|
+
def self.fixtures list
|
19
|
+
[list].flatten.each do |fixture|
|
20
|
+
self.class_eval do
|
21
|
+
# add a method name for this fixture type
|
22
|
+
define_method(fixture) do |item|
|
23
|
+
# load and cache the YAML
|
24
|
+
@@fixtures[fixture] ||= YAML::load_file(self.fixture_dir + "/#{fixture.to_s}.yml")
|
25
|
+
@@fixtures[fixture][item.to_s]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def mock_connection(file_name)
|
33
|
+
mock_connection = MockConnection.new(fixture_xml_content(file_name))
|
34
|
+
FreshBooks::Base.stubs(:connection).with().returns(mock_connection)
|
35
|
+
mock_connection
|
36
|
+
end
|
37
|
+
|
38
|
+
def fixture_xml_content(file_name)
|
39
|
+
# Quick way to remove white space and newlines from xml. Makes it easier to compare in tests
|
40
|
+
open(File.join(fixture_dir, "#{file_name}.xml"), "r").readlines.inject("") do |contents, line|
|
41
|
+
contents + line.strip
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def fixture_dir
|
46
|
+
File.join(File.dirname(__FILE__), "fixtures")
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestInvoice < Test::Unit::TestCase
|
4
|
+
def test_list
|
5
|
+
mock_call_api("invoice.list", { "page" => 1 }, "invoice_list_response")
|
6
|
+
|
7
|
+
invoices = FreshBooks::Invoice.list
|
8
|
+
assert_equal 3, invoices.size
|
9
|
+
assert_invoice invoices[0], 0
|
10
|
+
assert_invoice invoices[1], 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_get
|
14
|
+
invoice_id = 2
|
15
|
+
mock_call_api("invoice.get", { "invoice_id" => invoice_id }, "invoice_get_response")
|
16
|
+
|
17
|
+
invoice = FreshBooks::Invoice.get(invoice_id)
|
18
|
+
assert_invoice invoice, 0, true
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_create
|
22
|
+
invoice = FreshBooks::Invoice.new
|
23
|
+
assert_nil invoice.invoice_id
|
24
|
+
|
25
|
+
mock_call_api("invoice.create", { "invoice" => invoice }, "invoice_create_response")
|
26
|
+
assert invoice.create
|
27
|
+
assert_equal 1, invoice.invoice_id
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_update
|
31
|
+
invoice = FreshBooks::Invoice.new
|
32
|
+
invoice.invoice_id = 1
|
33
|
+
|
34
|
+
mock_call_api("invoice.update", { "invoice" => invoice }, "success_response")
|
35
|
+
assert invoice.update
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_delete
|
39
|
+
invoice = FreshBooks::Invoice.new
|
40
|
+
invoice.invoice_id = 2
|
41
|
+
mock_call_api("invoice.delete", { "invoice_id" => invoice.invoice_id }, "success_response")
|
42
|
+
|
43
|
+
assert invoice.delete
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_send_by_email
|
47
|
+
invoice = FreshBooks::Invoice.new
|
48
|
+
invoice.invoice_id = 2
|
49
|
+
mock_call_api("invoice.sendByEmail", { "invoice_id" => invoice.invoice_id }, "success_response")
|
50
|
+
|
51
|
+
assert invoice.send_by_email
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_send_by_snail_mail
|
55
|
+
invoice = FreshBooks::Invoice.new
|
56
|
+
invoice.invoice_id = 2
|
57
|
+
mock_call_api("invoice.sendBySnailMail", { "invoice_id" => invoice.invoice_id }, "success_response")
|
58
|
+
|
59
|
+
assert invoice.send_by_snail_mail
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def mock_call_api(method, options, response_fixture)
|
65
|
+
FreshBooks::Base.connection.
|
66
|
+
expects(:call_api).
|
67
|
+
with(method, options).
|
68
|
+
returns(FreshBooks::Response.new(fixture_xml_content(response_fixture)))
|
69
|
+
end
|
70
|
+
|
71
|
+
def assert_invoice(invoice, number, expanded_form = false)
|
72
|
+
number = number + 1
|
73
|
+
|
74
|
+
assert_equal number, invoice.invoice_id
|
75
|
+
assert_equal "number#{number}", invoice.number
|
76
|
+
assert_equal number, invoice.client_id
|
77
|
+
assert_equal number, invoice.recurring_id
|
78
|
+
assert_equal "draft", invoice.status
|
79
|
+
assert_equal (number * 100), invoice.amount
|
80
|
+
assert_equal (number * 100) / 2, invoice.amount_outstanding
|
81
|
+
assert_equal Date.parse("2009-02-0#{number}"), invoice.date
|
82
|
+
|
83
|
+
assert_equal number, invoice.po_number
|
84
|
+
assert_equal number.to_f, invoice.discount
|
85
|
+
assert_equal "notes#{number}", invoice.notes
|
86
|
+
assert_equal "terms#{number}", invoice.terms
|
87
|
+
assert_equal "first_name#{number}", invoice.first_name
|
88
|
+
assert_equal "last_name#{number}", invoice.last_name
|
89
|
+
assert_equal "p_street1#{number}", invoice.p_street1
|
90
|
+
assert_equal "p_street2#{number}", invoice.p_street2
|
91
|
+
assert_equal "p_city#{number}", invoice.p_city
|
92
|
+
assert_equal "p_state#{number}", invoice.p_state
|
93
|
+
assert_equal "p_country#{number}", invoice.p_country
|
94
|
+
assert_equal "p_code#{number}", invoice.p_code
|
95
|
+
|
96
|
+
assert_equal "return_uri#{number}", invoice.return_uri
|
97
|
+
assert_equal DateTime.parse("2009-08-#{number} 0#{number}:00:00 -04:00"), invoice.updated
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
assert_equal "client_view#{number}", invoice.links.client_view
|
102
|
+
assert_equal "view#{number}", invoice.links.view
|
103
|
+
assert_equal "edit#{number}", invoice.links.edit
|
104
|
+
|
105
|
+
lines = invoice.lines
|
106
|
+
assert_equal 1, lines.size
|
107
|
+
lines.each_with_index do |line, index|
|
108
|
+
assert_line(line, index)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def assert_line(line, number)
|
113
|
+
number = number + 1
|
114
|
+
|
115
|
+
assert_equal number.to_f, line.amount
|
116
|
+
assert_equal "name#{number}", line.name
|
117
|
+
assert_equal "description#{number}", line.description
|
118
|
+
assert_equal number.to_f, line.unit_cost
|
119
|
+
assert_equal number, line.quantity
|
120
|
+
assert_equal "tax1_name#{number}", line.tax1_name
|
121
|
+
assert_equal "tax2_name#{number}", line.tax2_name
|
122
|
+
assert_equal number.to_f, line.tax1_percent
|
123
|
+
assert_equal number.to_f, line.tax2_percent
|
124
|
+
end
|
125
|
+
end
|