tlconnor-xero_gateway 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.textile +11 -0
- data/README.textile +21 -8
- data/lib/xero_gateway.rb +14 -13
- data/lib/xero_gateway/account.rb +17 -2
- data/lib/xero_gateway/accounts_list.rb +77 -0
- data/lib/xero_gateway/address.rb +62 -3
- data/lib/xero_gateway/ca-certificates.crt +2560 -0
- data/lib/xero_gateway/contact.rb +110 -62
- data/lib/xero_gateway/error.rb +1 -2
- data/lib/xero_gateway/gateway.rb +55 -17
- data/lib/xero_gateway/http.rb +42 -46
- data/lib/xero_gateway/invoice.rb +132 -75
- data/lib/xero_gateway/line_item.rb +93 -7
- data/lib/xero_gateway/phone.rb +56 -2
- data/lib/xero_gateway/response.rb +1 -2
- data/lib/xero_gateway/tracking_category.rb +13 -12
- data/test/integration/accounts_list_test.rb +111 -0
- data/test/integration/create_contact_test.rb +46 -6
- data/test/integration/create_invoice_test.rb +29 -6
- data/test/test_helper.rb +4 -5
- data/test/unit/contact_test.rb +43 -0
- data/test/unit/invoice_test.rb +215 -22
- data/xero_gateway.gemspec +5 -2
- metadata +8 -3
@@ -13,7 +13,6 @@ module XeroGateway
|
|
13
13
|
|
14
14
|
def initialize(params = {})
|
15
15
|
params.each do |k,v|
|
16
|
-
self.instance_variable_set("@#{k}", v) ## create and initialize an instance variable for this key/value pair
|
17
16
|
self.send("#{k}=", v)
|
18
17
|
end
|
19
18
|
|
@@ -29,4 +28,4 @@ module XeroGateway
|
|
29
28
|
errors.blank? ? nil : errors[0]
|
30
29
|
end
|
31
30
|
end
|
32
|
-
end
|
31
|
+
end
|
@@ -5,21 +5,15 @@ module XeroGateway
|
|
5
5
|
def initialize(params = {})
|
6
6
|
@options = []
|
7
7
|
params.each do |k,v|
|
8
|
-
self.instance_variable_set("@#{k}", v) ## create and initialize an instance variable for this key/value pair
|
9
8
|
self.send("#{k}=", v)
|
10
9
|
end
|
11
10
|
end
|
12
11
|
|
13
|
-
def
|
14
|
-
|
15
|
-
return false if send(field) != other.send(field)
|
16
|
-
end
|
17
|
-
return true
|
12
|
+
def option
|
13
|
+
options[0] if options.size == 1
|
18
14
|
end
|
19
|
-
|
20
|
-
def to_xml
|
21
|
-
b = Builder::XmlMarkup.new
|
22
|
-
|
15
|
+
|
16
|
+
def to_xml(b = Builder::XmlMarkup.new)
|
23
17
|
b.TrackingCategory {
|
24
18
|
b.Name self.name
|
25
19
|
b.Options {
|
@@ -41,6 +35,13 @@ module XeroGateway
|
|
41
35
|
end
|
42
36
|
end
|
43
37
|
tracking_category
|
44
|
-
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
[:name, :options].each do |field|
|
42
|
+
return false if send(field) != other.send(field)
|
43
|
+
end
|
44
|
+
return true
|
45
|
+
end
|
45
46
|
end
|
46
|
-
end
|
47
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class AccountsListTest < Test::Unit::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@gateway = XeroGateway::Gateway.new(
|
8
|
+
:customer_key => CUSTOMER_KEY,
|
9
|
+
:api_key => API_KEY
|
10
|
+
)
|
11
|
+
|
12
|
+
# Always stub out calls for this integration test as we need to be able to control the data.
|
13
|
+
@gateway.xero_url = "DUMMY_URL"
|
14
|
+
@gateway.stubs(:http_get).with {|url, params| url =~ /accounts$/ }.returns(get_file_as_string("accounts.xml"))
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_get_accounts_list
|
18
|
+
accounts_list = @gateway.get_accounts_list
|
19
|
+
assert_not_equal(0, accounts_list.accounts.size)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Make sure that the list is loaded when finding things.
|
23
|
+
def test_raise_error_on_not_loaded
|
24
|
+
accounts_list = @gateway.get_accounts_list(false)
|
25
|
+
assert_equal(false, accounts_list.loaded?)
|
26
|
+
assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list[200] }
|
27
|
+
assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list.find_by_code(200) }
|
28
|
+
assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list.find_all_by_type('EXPENSE') }
|
29
|
+
assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list.find_all_by_tax_type('OUTPUT') }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Test simple lookup by account code (from cache).
|
33
|
+
def test_simple_lookup_by_account_code
|
34
|
+
accounts_list = @gateway.get_accounts_list
|
35
|
+
assert_equal(true, accounts_list.loaded?)
|
36
|
+
|
37
|
+
# Load data in the stubbed response.
|
38
|
+
expected_accounts = accounts_as_array
|
39
|
+
|
40
|
+
# Make sure that every single expected account exists in the cached lookup hash.
|
41
|
+
expected_accounts.each do | expected_account |
|
42
|
+
found_account = accounts_list.find_by_code(expected_account.code)
|
43
|
+
assert_kind_of(XeroGateway::Account, found_account)
|
44
|
+
assert(expected_account == found_account, "Found account does not match expected account.")
|
45
|
+
|
46
|
+
found_account_shortcut = accounts_list[expected_account.code]
|
47
|
+
assert_kind_of(XeroGateway::Account, found_account_shortcut)
|
48
|
+
assert(expected_account == found_account_shortcut, "Found account does not match expected account (shortcut).")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Test finding accounts by their account type (from cache).
|
53
|
+
def test_lookup_by_account_type
|
54
|
+
accounts_list = @gateway.get_accounts_list
|
55
|
+
assert_equal(true, accounts_list.loaded?)
|
56
|
+
|
57
|
+
# Load data in the stubbed response.
|
58
|
+
expected_accounts = accounts_as_array
|
59
|
+
|
60
|
+
# Get all the unique account types present in the expected accounts data along with their counts.
|
61
|
+
unique_types = expected_accounts.inject({}) do | list, account |
|
62
|
+
list[account.type] = 0 if list[account.type].nil?
|
63
|
+
list[account.type] += 1
|
64
|
+
list
|
65
|
+
end
|
66
|
+
|
67
|
+
assert_not_equal(0, unique_types)
|
68
|
+
unique_types.each do | account_type, count |
|
69
|
+
found_accounts = accounts_list.find_all_by_type(account_type)
|
70
|
+
assert_equal(count, found_accounts.size)
|
71
|
+
found_accounts.each do | found_account |
|
72
|
+
assert_kind_of(XeroGateway::Account, found_account)
|
73
|
+
assert_equal(account_type, found_account.type)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Test finding accounts by their tax type (from cache).
|
79
|
+
def test_lookup_by_tax_type
|
80
|
+
accounts_list = @gateway.get_accounts_list
|
81
|
+
assert_equal(true, accounts_list.loaded?)
|
82
|
+
|
83
|
+
# Load data in the stubbed response.
|
84
|
+
expected_accounts = accounts_as_array
|
85
|
+
|
86
|
+
# Get all the unique tax types present in the expected accounts data along with their counts.
|
87
|
+
unique_types = expected_accounts.inject({}) do | list, account |
|
88
|
+
list[account.tax_type] = 0 if list[account.tax_type].nil?
|
89
|
+
list[account.tax_type] += 1
|
90
|
+
list
|
91
|
+
end
|
92
|
+
|
93
|
+
assert_not_equal(0, unique_types)
|
94
|
+
unique_types.each do | tax_type, count |
|
95
|
+
found_accounts = accounts_list.find_all_by_tax_type(tax_type)
|
96
|
+
assert_equal(count, found_accounts.size)
|
97
|
+
found_accounts.each do | found_account |
|
98
|
+
assert_kind_of(XeroGateway::Account, found_account)
|
99
|
+
assert_equal(tax_type, found_account.tax_type)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def accounts_as_array
|
107
|
+
response = @gateway.__send__(:parse_response, get_file_as_string("accounts.xml"))
|
108
|
+
response.accounts
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -13,17 +13,57 @@ class CreateContactTest < Test::Unit::TestCase
|
|
13
13
|
@gateway.xero_url = "DUMMY_URL"
|
14
14
|
|
15
15
|
@gateway.stubs(:http_put).with {|url, body, params| url =~ /contact$/ }.returns(get_file_as_string("contact.xml"))
|
16
|
+
@gateway.stubs(:http_post).with {|url, body, params| url =~ /contact$/ }.returns(get_file_as_string("contact.xml"))
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
20
|
def test_create_contact
|
20
|
-
example_contact = dummy_contact
|
21
|
+
example_contact = dummy_contact.dup
|
21
22
|
|
22
23
|
result = @gateway.create_contact(example_contact)
|
23
|
-
|
24
|
-
assert !result.contact.contact_id.nil?
|
25
|
-
assert !result.request_xml.nil?
|
26
|
-
assert !result.response_xml.nil?
|
27
|
-
assert_equal result.contact.name, example_contact.name
|
24
|
+
assert_valid_contact_save_response(result, example_contact)
|
28
25
|
end
|
26
|
+
|
27
|
+
def test_create_from_contact
|
28
|
+
example_contact = dummy_contact.dup
|
29
|
+
|
30
|
+
contact = @gateway.build_contact(example_contact)
|
31
|
+
result = contact.create
|
32
|
+
assert_valid_contact_save_response(result, example_contact)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_update_from_contact
|
36
|
+
example_contact = dummy_contact.dup
|
37
|
+
|
38
|
+
contact = @gateway.build_contact(example_contact)
|
39
|
+
contact.create # need to create first so we have a ContactID
|
40
|
+
|
41
|
+
result = contact.update
|
42
|
+
assert_valid_contact_save_response(result, example_contact)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_save_from_contact
|
46
|
+
example_contact = dummy_contact.dup
|
47
|
+
|
48
|
+
contact = @gateway.build_contact(example_contact)
|
49
|
+
result = contact.save
|
50
|
+
assert_valid_contact_save_response(result, example_contact)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_create_contact_valid
|
54
|
+
example_contact = dummy_contact.dup
|
55
|
+
assert_equal true, example_contact.valid?, "contact is invalid - errors:\n\t#{example_contact.errors.map { | error | "#{error[0]} #{error[1]}"}.join("\n\t")}"
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def assert_valid_contact_save_response(result, example_contact)
|
61
|
+
assert_kind_of XeroGateway::Response, result
|
62
|
+
assert result.success?
|
63
|
+
assert !result.contact.contact_id.nil?
|
64
|
+
assert !result.request_xml.nil?
|
65
|
+
assert !result.response_xml.nil?
|
66
|
+
assert_equal result.contact.name, example_contact.name
|
67
|
+
assert example_contact.contact_id =~ GUID_REGEX
|
68
|
+
end
|
29
69
|
end
|
@@ -13,17 +13,40 @@ class CreateInvoiceTest < Test::Unit::TestCase
|
|
13
13
|
@gateway.xero_url = "DUMMY_URL"
|
14
14
|
|
15
15
|
@gateway.stubs(:http_put).with {|url, body, params| url =~ /invoice$/ }.returns(get_file_as_string("invoice.xml"))
|
16
|
+
@gateway.stubs(:http_post).with {|url, body, params| url =~ /invoice$/ }.returns(get_file_as_string("invoice.xml"))
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
20
|
def test_create_invoice
|
20
|
-
example_invoice = dummy_invoice
|
21
|
+
example_invoice = dummy_invoice.dup
|
21
22
|
|
22
23
|
result = @gateway.create_invoice(example_invoice)
|
23
|
-
|
24
|
-
assert !result.request_xml.nil?
|
25
|
-
assert !result.response_xml.nil?
|
26
|
-
assert !result.invoice.invoice_id.nil?
|
27
|
-
assert result.invoice.invoice_number == example_invoice.invoice_number
|
24
|
+
assert_valid_invoice_save_response(result, example_invoice)
|
28
25
|
end
|
26
|
+
|
27
|
+
def test_create_from_invoice
|
28
|
+
example_invoice = dummy_invoice.dup
|
29
|
+
|
30
|
+
invoice = @gateway.build_invoice(example_invoice)
|
31
|
+
result = invoice.create
|
32
|
+
assert_valid_invoice_save_response(result, example_invoice)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_create_invoice_valid
|
36
|
+
example_invoice = dummy_invoice.dup
|
37
|
+
assert_equal true, example_invoice.valid?, "invoice is invalid - errors:\n\t#{example_invoice.errors.map { | error | "#{error[0]} #{error[1]}"}.join("\n\t")}"
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def assert_valid_invoice_save_response(result, example_invoice)
|
43
|
+
assert_kind_of XeroGateway::Response, result
|
44
|
+
assert result.success?
|
45
|
+
assert !result.request_xml.nil?
|
46
|
+
assert !result.response_xml.nil?
|
47
|
+
assert !result.invoice.invoice_id.nil?
|
48
|
+
assert result.invoice.invoice_number == example_invoice.invoice_number
|
49
|
+
assert example_invoice.invoice_id =~ GUID_REGEX
|
50
|
+
end
|
51
|
+
|
29
52
|
end
|
data/test/test_helper.rb
CHANGED
@@ -20,6 +20,9 @@ module TestHelper
|
|
20
20
|
|
21
21
|
API_KEY = ENV["API_KEY"] unless defined? API_KEY
|
22
22
|
CUSTOMER_KEY = ENV["CUSTOMER_KEY"] unless defined? CUSTOMER_KEY
|
23
|
+
|
24
|
+
# Helper constant for checking regex
|
25
|
+
GUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ unless defined?(GUID_REGEX)
|
23
26
|
|
24
27
|
|
25
28
|
def dummy_invoice
|
@@ -28,22 +31,18 @@ module TestHelper
|
|
28
31
|
:due_date => Date.today + 20,
|
29
32
|
:invoice_number => STUB_XERO_CALLS ? "INV-0001" : "#{Time.now.to_f}",
|
30
33
|
:reference => "YOUR REFERENCE (NOT NECESSARILY UNIQUE!)",
|
31
|
-
:sub_total => 1000,
|
32
|
-
:total_tax => 125,
|
33
|
-
:total => 1125
|
34
34
|
})
|
35
35
|
invoice.contact = dummy_contact
|
36
36
|
invoice.line_items << XeroGateway::LineItem.new(
|
37
37
|
:description => "THE DESCRIPTION OF THE LINE ITEM",
|
38
38
|
:unit_amount => 1000,
|
39
39
|
:tax_amount => 125,
|
40
|
-
:line_amount => 1000,
|
41
40
|
:tracking_category => "THE TRACKING CATEGORY FOR THE LINE ITEM",
|
42
41
|
:tracking_option => "THE TRACKING OPTION FOR THE LINE ITEM"
|
43
42
|
)
|
44
43
|
invoice
|
45
44
|
end
|
46
|
-
|
45
|
+
|
47
46
|
def dummy_contact
|
48
47
|
unique_id = Time.now.to_f
|
49
48
|
contact = XeroGateway::Contact.new(:name => STUB_XERO_CALLS ? "CONTACT NAME" : "THE NAME OF THE CONTACT #{unique_id}")
|
data/test/unit/contact_test.rb
CHANGED
@@ -32,6 +32,49 @@ class ContactTest < Test::Unit::TestCase
|
|
32
32
|
assert_equal contact, result_contact
|
33
33
|
end
|
34
34
|
|
35
|
+
# Test Contact#add_address helper creates a valid XeroGateway::Contact object with the passed in values
|
36
|
+
# and appends it to the Contact#addresses attribute.
|
37
|
+
def test_add_address_helper
|
38
|
+
contact = create_test_contact
|
39
|
+
assert_equal(1, contact.addresses.size)
|
40
|
+
|
41
|
+
new_values = {
|
42
|
+
:address_type => 'POBOX',
|
43
|
+
:line_1 => 'NEW LINE 1',
|
44
|
+
:line_2 => 'NEW LINE 2',
|
45
|
+
:line_3 => 'NEW LINE 3',
|
46
|
+
:line_4 => 'NEW LINE 4',
|
47
|
+
:city => 'NEW CITY',
|
48
|
+
:region => 'NEW REGION',
|
49
|
+
:post_code => '5555',
|
50
|
+
:country => 'Australia'
|
51
|
+
}
|
52
|
+
contact.add_address(new_values)
|
53
|
+
|
54
|
+
assert_equal(2, contact.addresses.size)
|
55
|
+
assert_kind_of(XeroGateway::Address, contact.addresses.last)
|
56
|
+
new_values.each { |k,v| assert_equal(v, contact.addresses.last.send("#{k}")) }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Test Contact#add_phone helper creates a valid XeroGateway::Phone object with the passed in values
|
60
|
+
# and appends it to the Contact#phones attribute.
|
61
|
+
def test_add_address_helper
|
62
|
+
contact = create_test_contact
|
63
|
+
assert_equal(1, contact.phones.size)
|
64
|
+
|
65
|
+
new_values = {
|
66
|
+
:phone_type => 'MOBILE',
|
67
|
+
:country_code => '61',
|
68
|
+
:area_code => '406',
|
69
|
+
:number => '123456'
|
70
|
+
}
|
71
|
+
contact.add_phone(new_values)
|
72
|
+
|
73
|
+
assert_equal(2, contact.phones.size)
|
74
|
+
assert_kind_of(XeroGateway::Phone, contact.phones.last)
|
75
|
+
new_values.each { |k,v| assert_equal(v, contact.phones.last.send("#{k}")) }
|
76
|
+
end
|
77
|
+
|
35
78
|
|
36
79
|
private
|
37
80
|
|
data/test/unit/invoice_test.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '../test_helper.rb')
|
2
2
|
|
3
3
|
class InvoiceTest < Test::Unit::TestCase
|
4
|
+
|
4
5
|
def setup
|
5
6
|
@schema = LibXML::XML::Schema.document(LibXML::XML::Document.file(File.join(File.dirname(__FILE__), '../xsd/create_invoice.xsd')))
|
6
7
|
end
|
@@ -31,33 +32,225 @@ class InvoiceTest < Test::Unit::TestCase
|
|
31
32
|
assert_equal(invoice, result_invoice)
|
32
33
|
end
|
33
34
|
|
35
|
+
# Tests the sub_total calculation and that setting it manually doesn't modify the data.
|
36
|
+
def test_invoice_sub_total_calculation
|
37
|
+
invoice = create_test_invoice
|
38
|
+
line_item = invoice.line_items.first
|
39
|
+
|
40
|
+
# Make sure that everything adds up to begin with.
|
41
|
+
expected_sub_total = invoice.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.line_amount }
|
42
|
+
assert_equal(expected_sub_total, invoice.sub_total)
|
43
|
+
|
44
|
+
# Change the sub_total and check that it doesn't modify anything.
|
45
|
+
invoice.sub_total = expected_sub_total * 10
|
46
|
+
assert_equal(expected_sub_total, invoice.sub_total)
|
47
|
+
|
48
|
+
# Change the amount of the first line item and make sure that
|
49
|
+
# everything still continues to add up.
|
50
|
+
line_item.unit_amount = line_item.unit_amount + 10
|
51
|
+
assert_not_equal(expected_sub_total, invoice.sub_total)
|
52
|
+
expected_sub_total = invoice.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.line_amount }
|
53
|
+
assert_equal(expected_sub_total, invoice.sub_total)
|
54
|
+
end
|
34
55
|
|
35
|
-
|
56
|
+
# Tests the total_tax calculation and that setting it manually doesn't modify the data.
|
57
|
+
def test_invoice_sub_total_calculation
|
58
|
+
invoice = create_test_invoice
|
59
|
+
line_item = invoice.line_items.first
|
60
|
+
|
61
|
+
# Make sure that everything adds up to begin with.
|
62
|
+
expected_total_tax = invoice.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.tax_amount }
|
63
|
+
assert_equal(expected_total_tax, invoice.total_tax)
|
64
|
+
|
65
|
+
# Change the total_tax and check that it doesn't modify anything.
|
66
|
+
invoice.total_tax = expected_total_tax * 10
|
67
|
+
assert_equal(expected_total_tax, invoice.total_tax)
|
68
|
+
|
69
|
+
# Change the tax_amount of the first line item and make sure that
|
70
|
+
# everything still continues to add up.
|
71
|
+
line_item.tax_amount = line_item.tax_amount + 10
|
72
|
+
assert_not_equal(expected_total_tax, invoice.total_tax)
|
73
|
+
expected_total_tax = invoice.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.tax_amount }
|
74
|
+
assert_equal(expected_total_tax, invoice.total_tax)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Tests the total calculation and that setting it manually doesn't modify the data.
|
78
|
+
def test_invoice_sub_total_calculation
|
79
|
+
invoice = create_test_invoice
|
80
|
+
line_item = invoice.line_items.first
|
81
|
+
|
82
|
+
# Make sure that everything adds up to begin with.
|
83
|
+
expected_total = invoice.sub_total + invoice.total_tax
|
84
|
+
assert_equal(expected_total, invoice.total)
|
85
|
+
|
86
|
+
# Change the total and check that it doesn't modify anything.
|
87
|
+
invoice.total = expected_total * 10
|
88
|
+
assert_equal(expected_total, invoice.total)
|
89
|
+
|
90
|
+
# Change the quantity of the first line item and make sure that
|
91
|
+
# everything still continues to add up.
|
92
|
+
line_item.quantity = line_item.quantity + 5
|
93
|
+
assert_not_equal(expected_total, invoice.total)
|
94
|
+
expected_total = invoice.sub_total + invoice.total_tax
|
95
|
+
assert_equal(expected_total, invoice.total)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Tests that the LineItem#line_amount calculation is working correctly.
|
99
|
+
def test_line_amount_calculation
|
100
|
+
invoice = create_test_invoice
|
101
|
+
line_item = invoice.line_items.first
|
102
|
+
|
103
|
+
# Make sure that everything adds up to begin with.
|
104
|
+
expected_amount = line_item.quantity * line_item.unit_amount
|
105
|
+
assert_equal(expected_amount, line_item.line_amount)
|
106
|
+
|
107
|
+
# Change the line_amount and check that it doesn't modify anything.
|
108
|
+
line_item.line_amount = expected_amount * 10
|
109
|
+
assert_equal(expected_amount, line_item.line_amount)
|
110
|
+
|
111
|
+
# Change the quantity and check that the line_amount has been updated.
|
112
|
+
quantity = line_item.quantity + 2
|
113
|
+
line_item.quantity = quantity
|
114
|
+
assert_not_equal(expected_amount, line_item.line_amount)
|
115
|
+
assert_equal(quantity * line_item.unit_amount, line_item.line_amount)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Ensure that the totalling methods don't raise exceptions, even when
|
119
|
+
# invoice.line_items is empty.
|
120
|
+
def test_totalling_methods_when_line_items_empty
|
121
|
+
invoice = create_test_invoice
|
122
|
+
invoice.line_items = []
|
123
|
+
|
124
|
+
assert_nothing_raised(Exception) {
|
125
|
+
assert_equal(BigDecimal.new('0'), invoice.sub_total)
|
126
|
+
assert_equal(BigDecimal.new('0'), invoice.total_tax)
|
127
|
+
assert_equal(BigDecimal.new('0'), invoice.total)
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_invoice_type_helper_methods
|
132
|
+
# Test accounts receivable invoices.
|
133
|
+
invoice = create_test_invoice({:invoice_type => 'ACCREC'})
|
134
|
+
assert_equal(true, invoice.accounts_receivable?, "Accounts RECEIVABLE invoice doesn't think it is.")
|
135
|
+
assert_equal(false, invoice.accounts_payable?, "Accounts RECEIVABLE invoice thinks it's payable.")
|
136
|
+
|
137
|
+
# Test accounts payable invoices.
|
138
|
+
invoice = create_test_invoice({:invoice_type => 'ACCPAY'})
|
139
|
+
assert_equal(false, invoice.accounts_receivable?, "Accounts PAYABLE invoice doesn't think it is.")
|
140
|
+
assert_equal(true, invoice.accounts_payable?, "Accounts PAYABLE invoice thinks it's receivable.")
|
141
|
+
end
|
36
142
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
invoice
|
42
|
-
|
43
|
-
invoice.
|
44
|
-
invoice.
|
45
|
-
invoice.
|
46
|
-
invoice.
|
47
|
-
|
48
|
-
|
49
|
-
invoice.
|
50
|
-
|
51
|
-
|
52
|
-
invoice.contact.
|
53
|
-
|
54
|
-
|
143
|
+
|
144
|
+
# Make sure that the create_test_invoice method is working correctly
|
145
|
+
# with all the defaults and overrides.
|
146
|
+
def test_create_test_invoice_defaults_working
|
147
|
+
invoice = create_test_invoice
|
148
|
+
|
149
|
+
# Test invoice defaults.
|
150
|
+
assert_equal('ACCREC', invoice.invoice_type)
|
151
|
+
assert_kind_of(Time, invoice.date)
|
152
|
+
assert_kind_of(Time, invoice.due_date)
|
153
|
+
assert_equal('12345', invoice.invoice_number)
|
154
|
+
assert_equal('MY REFERENCE FOR THIS INVOICE', invoice.reference)
|
155
|
+
assert_equal(false, invoice.includes_tax)
|
156
|
+
|
157
|
+
# Test the contact defaults.
|
158
|
+
assert_equal('00000000-0000-0000-0000-000000000000', invoice.contact.contact_id)
|
159
|
+
assert_equal('CONTACT NAME', invoice.contact.name)
|
160
|
+
|
161
|
+
# Test address defaults.
|
162
|
+
assert_equal('DEFAULT', invoice.contact.address.address_type)
|
163
|
+
assert_equal('LINE 1 OF THE ADDRESS', invoice.contact.address.line_1)
|
164
|
+
|
165
|
+
# Test phone defaults.
|
166
|
+
assert_equal('DEFAULT', invoice.contact.phone.phone_type)
|
167
|
+
assert_equal('12345678', invoice.contact.phone.number)
|
168
|
+
|
169
|
+
# Test the line_item defaults.
|
170
|
+
assert_equal('A LINE ITEM', invoice.line_items.first.description)
|
171
|
+
assert_equal('200', invoice.line_items.first.account_code)
|
172
|
+
assert_equal(BigDecimal.new('100'), invoice.line_items.first.unit_amount)
|
173
|
+
assert_equal(BigDecimal.new('12.5'), invoice.line_items.first.tax_amount)
|
174
|
+
|
175
|
+
# Test overriding an invoice parameter (assume works for all).
|
176
|
+
invoice = create_test_invoice({:invoice_type => 'ACCPAY'})
|
177
|
+
assert_equal('ACCPAY', invoice.invoice_type)
|
178
|
+
|
179
|
+
# Test overriding a contact/address/phone parameter (assume works for all).
|
180
|
+
invoice = create_test_invoice({}, {:name => 'OVERRIDDEN NAME', :address => {:line_1 => 'OVERRIDDEN LINE 1'}, :phone => {:number => '999'}})
|
181
|
+
assert_equal('OVERRIDDEN NAME', invoice.contact.name)
|
182
|
+
assert_equal('OVERRIDDEN LINE 1', invoice.contact.address.line_1)
|
183
|
+
assert_equal('999', invoice.contact.phone.number)
|
184
|
+
|
185
|
+
# Test overriding line_items with hash.
|
186
|
+
invoice = create_test_invoice({}, {}, {:description => 'OVERRIDDEN LINE ITEM'})
|
187
|
+
assert_equal(1, invoice.line_items.size)
|
188
|
+
assert_equal('OVERRIDDEN LINE ITEM', invoice.line_items.first.description)
|
189
|
+
assert_equal(BigDecimal.new('100'), invoice.line_items.first.unit_amount)
|
190
|
+
|
191
|
+
# Test overriding line_items with array of 2 line_items.
|
192
|
+
invoice = create_test_invoice({}, {}, [
|
193
|
+
{:description => 'OVERRIDDEN ITEM 1'},
|
194
|
+
{:description => 'OVERRIDDEN ITEM 2', :account_code => '200', :unit_amount => BigDecimal.new('200'), :tax_amount => '25.0'}
|
195
|
+
])
|
196
|
+
assert_equal(2, invoice.line_items.size)
|
197
|
+
assert_equal('OVERRIDDEN ITEM 1', invoice.line_items[0].description)
|
198
|
+
assert_equal(BigDecimal.new('100'), invoice.line_items[0].unit_amount)
|
199
|
+
assert_equal('OVERRIDDEN ITEM 2', invoice.line_items[1].description)
|
200
|
+
assert_equal(BigDecimal.new('200'), invoice.line_items[1].unit_amount)
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
|
205
|
+
def create_test_invoice(invoice_params = {}, contact_params = {}, line_item_params = [])
|
206
|
+
invoice_params = {
|
207
|
+
:invoice_type => 'ACCREC',
|
208
|
+
:date => Time.now,
|
209
|
+
:due_date => Time.now + (10 * 24 * 3600), # 10 days in the future
|
210
|
+
:invoice_number => '12345',
|
211
|
+
:reference => "MY REFERENCE FOR THIS INVOICE",
|
212
|
+
:includes_tax => false
|
213
|
+
}.merge(invoice_params)
|
214
|
+
invoice = XeroGateway::Invoice.new(invoice_params)
|
215
|
+
|
216
|
+
# Strip out :address key from contact_params to use as the default address.
|
217
|
+
stripped_address = {
|
218
|
+
:address_type => 'DEFAULT',
|
219
|
+
:line_1 => 'LINE 1 OF THE ADDRESS'
|
220
|
+
}.merge(contact_params.delete(:address) || {})
|
221
|
+
|
222
|
+
# Strip out :phone key from contact_params to use at the default phone.
|
223
|
+
stripped_phone = {
|
224
|
+
:phone_type => 'DEFAULT',
|
225
|
+
:number => '12345678'
|
226
|
+
}.merge(contact_params.delete(:phone) || {})
|
227
|
+
|
228
|
+
contact_params = {
|
229
|
+
:contact_id => '00000000-0000-0000-0000-000000000000', # Just any valid GUID
|
230
|
+
:name => "CONTACT NAME"
|
231
|
+
}.merge(contact_params)
|
232
|
+
|
233
|
+
# Create invoice.contact from contact_params.
|
234
|
+
invoice.contact = XeroGateway::Contact.new(contact_params)
|
235
|
+
invoice.contact.address = XeroGateway::Address.new(stripped_address)
|
236
|
+
invoice.contact.phone = XeroGateway::Phone.new(stripped_phone)
|
237
|
+
|
238
|
+
line_item_params = [line_item_params].flatten # always use an array, even if only a single hash passed in
|
239
|
+
|
240
|
+
# At least one line item, make first have some defaults.
|
241
|
+
line_item_params << {} if line_item_params.size == 0
|
242
|
+
line_item_params[0] = {
|
55
243
|
:description => "A LINE ITEM",
|
56
244
|
:account_code => "200",
|
57
245
|
:unit_amount => BigDecimal.new("100"),
|
58
|
-
:tax_amount => BigDecimal.new("12.5")
|
59
|
-
|
60
|
-
|
246
|
+
:tax_amount => BigDecimal.new("12.5")
|
247
|
+
}.merge(line_item_params[0])
|
248
|
+
|
249
|
+
# Create invoice.line_items from line_item_params
|
250
|
+
line_item_params.each do | line_item |
|
251
|
+
invoice.line_items << XeroGateway::LineItem.new(line_item)
|
252
|
+
end
|
253
|
+
|
61
254
|
invoice
|
62
255
|
end
|
63
256
|
end
|