tlconnor-xero_gateway 1.0.3 → 1.0.4
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/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
|