xero_gateway 2.0.4 → 2.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +57 -5
- data/lib/xero_gateway/account.rb +8 -2
- data/lib/xero_gateway/credit_note.rb +275 -0
- data/lib/xero_gateway/exceptions.rb +3 -1
- data/lib/xero_gateway/gateway.rb +119 -3
- data/lib/xero_gateway/http.rb +10 -6
- data/lib/xero_gateway/oauth.rb +3 -1
- data/lib/xero_gateway/response.rb +2 -0
- data/lib/xero_gateway/tracking_category.rb +5 -2
- data/lib/xero_gateway.rb +1 -0
- data/test/integration/create_credit_note_test.rb +49 -0
- data/test/integration/get_credit_note_test.rb +48 -0
- data/test/integration/get_credit_notes_test.rb +90 -0
- data/test/integration/get_tracking_categories_test.rb +3 -2
- data/test/test_helper.rb +24 -1
- data/test/unit/account_test.rb +3 -2
- data/test/unit/credit_note_test.rb +284 -0
- data/test/unit/gateway_test.rb +17 -1
- data/xero_gateway.gemspec +3 -76
- metadata +13 -29
- data/CHANGELOG.textile +0 -57
- data/test/stub_responses/accounts.xml +0 -1
- data/test/stub_responses/api_exception.xml +0 -153
- data/test/stub_responses/contact.xml +0 -1
- data/test/stub_responses/contacts.xml +0 -2189
- data/test/stub_responses/create_invoice.xml +0 -64
- data/test/stub_responses/currencies.xml +0 -16
- data/test/stub_responses/invalid_api_key_error.xml +0 -1
- data/test/stub_responses/invalid_consumer_key +0 -1
- data/test/stub_responses/invalid_request_token +0 -1
- data/test/stub_responses/invoice.xml +0 -1
- data/test/stub_responses/invoice_not_found_error.xml +0 -1
- data/test/stub_responses/invoices.xml +0 -1
- data/test/stub_responses/organisation.xml +0 -14
- data/test/stub_responses/tax_rates.xml +0 -52
- data/test/stub_responses/token_expired +0 -1
- data/test/stub_responses/tracking_categories.xml +0 -1
- data/test/stub_responses/unknown_error.xml +0 -1
- data/test/xsd/README +0 -2
- data/test/xsd/create_contact.xsd +0 -61
- data/test/xsd/create_invoice.xsd +0 -107
@@ -18,7 +18,7 @@
|
|
18
18
|
#
|
19
19
|
module XeroGateway
|
20
20
|
class TrackingCategory
|
21
|
-
attr_accessor :name, :options
|
21
|
+
attr_accessor :tracking_category_id, :name, :options
|
22
22
|
|
23
23
|
def initialize(params = {})
|
24
24
|
@options = []
|
@@ -33,6 +33,7 @@ module XeroGateway
|
|
33
33
|
|
34
34
|
def to_xml(b = Builder::XmlMarkup.new)
|
35
35
|
b.TrackingCategory {
|
36
|
+
b.TrackingCategoryID self.tracking_category_id
|
36
37
|
b.Name self.name
|
37
38
|
b.Options {
|
38
39
|
if self.options.is_a?(Array)
|
@@ -54,6 +55,7 @@ module XeroGateway
|
|
54
55
|
# option, and the Options tag is omitted
|
55
56
|
def to_xml_for_invoice_messages(b = Builder::XmlMarkup.new)
|
56
57
|
b.TrackingCategory {
|
58
|
+
b.TrackingCategoryID self.tracking_category_id
|
57
59
|
b.Name self.name
|
58
60
|
b.Option self.options.is_a?(Array) ? self.options.first : self.options.to_s
|
59
61
|
}
|
@@ -63,6 +65,7 @@ module XeroGateway
|
|
63
65
|
tracking_category = TrackingCategory.new
|
64
66
|
tracking_category_element.children.each do |element|
|
65
67
|
case(element.name)
|
68
|
+
when "TrackingCategoryID" then tracking_category.tracking_category_id = element.text
|
66
69
|
when "Name" then tracking_category.name = element.text
|
67
70
|
when "Options" then
|
68
71
|
element.children.each do |option_child|
|
@@ -74,7 +77,7 @@ module XeroGateway
|
|
74
77
|
end
|
75
78
|
|
76
79
|
def ==(other)
|
77
|
-
[:name, :options].each do |field|
|
80
|
+
[:tracking_category_id, :name, :options].each do |field|
|
78
81
|
return false if send(field) != other.send(field)
|
79
82
|
end
|
80
83
|
return true
|
data/lib/xero_gateway.rb
CHANGED
@@ -21,6 +21,7 @@ require File.join(File.dirname(__FILE__), 'xero_gateway', 'contact')
|
|
21
21
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'line_item')
|
22
22
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'payment')
|
23
23
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'invoice')
|
24
|
+
require File.join(File.dirname(__FILE__), 'xero_gateway', 'credit_note')
|
24
25
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'address')
|
25
26
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'phone')
|
26
27
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'organisation')
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class CreateCreditNoteTest < Test::Unit::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@gateway = XeroGateway::Gateway.new(CONSUMER_KEY, CONSUMER_SECRET)
|
8
|
+
|
9
|
+
if STUB_XERO_CALLS
|
10
|
+
@gateway.xero_url = "DUMMY_URL"
|
11
|
+
|
12
|
+
@gateway.stubs(:http_put).with {|client, url, body, params| url =~ /CreditNotes$/ }.returns(get_file_as_string("create_credit_note.xml"))
|
13
|
+
@gateway.stubs(:http_post).with {|client, url, body, params| url =~ /CreditNotes$/ }.returns(get_file_as_string("credit_note.xml"))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_create_credit_note
|
18
|
+
example_credit_note = dummy_credit_note.dup
|
19
|
+
|
20
|
+
result = @gateway.create_credit_note(example_credit_note)
|
21
|
+
assert_valid_credit_note_save_response(result, example_credit_note)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_create_from_credit_note
|
25
|
+
example_credit_note = dummy_credit_note.dup
|
26
|
+
|
27
|
+
credit_note = @gateway.build_credit_note(example_credit_note)
|
28
|
+
result = credit_note.create
|
29
|
+
assert_valid_credit_note_save_response(result, example_credit_note)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_create_credit_note_valid
|
33
|
+
example_credit_note = dummy_credit_note.dup
|
34
|
+
assert_equal true, example_credit_note.valid?, "credit_note is invalid - errors:\n\t#{example_credit_note.errors.map { | error | "#{error[0]} #{error[1]}"}.join("\n\t")}"
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def assert_valid_credit_note_save_response(result, example_credit_note)
|
40
|
+
assert_kind_of XeroGateway::Response, result
|
41
|
+
assert result.success?
|
42
|
+
assert !result.request_xml.nil?
|
43
|
+
assert !result.response_xml.nil?
|
44
|
+
assert !result.credit_note.credit_note_id.nil?
|
45
|
+
assert result.credit_note.credit_note_number == example_credit_note.credit_note_number
|
46
|
+
assert result.credit_note.credit_note_id =~ GUID_REGEX
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class GetCreditNoteTest < Test::Unit::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@gateway = XeroGateway::Gateway.new(CONSUMER_KEY, CONSUMER_SECRET)
|
8
|
+
|
9
|
+
if STUB_XERO_CALLS
|
10
|
+
@gateway.xero_url = "DUMMY_URL"
|
11
|
+
|
12
|
+
@gateway.stubs(:http_get).with {|client, url, params| url =~ /CreditNotes(\/[0-9a-z\-]+)?$/i }.returns(get_file_as_string("credit_note.xml"))
|
13
|
+
@gateway.stubs(:http_put).with {|client, url, body, params| url =~ /CreditNotes$/ }.returns(get_file_as_string("create_credit_note.xml"))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_get_credit_note
|
18
|
+
# Make sure there is an credit_note in Xero to retrieve
|
19
|
+
credit_note = @gateway.create_credit_note(dummy_credit_note).credit_note
|
20
|
+
|
21
|
+
result = @gateway.get_credit_note(credit_note.credit_note_id)
|
22
|
+
assert result.success?
|
23
|
+
assert !result.request_params.nil?
|
24
|
+
assert !result.response_xml.nil?
|
25
|
+
assert_equal result.credit_note.credit_note_number, credit_note.credit_note_number
|
26
|
+
|
27
|
+
result = @gateway.get_credit_note(credit_note.credit_note_number)
|
28
|
+
assert result.success?
|
29
|
+
assert !result.request_params.nil?
|
30
|
+
assert !result.response_xml.nil?
|
31
|
+
assert_equal result.credit_note.credit_note_id, credit_note.credit_note_id
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_line_items_downloaded_set_correctly
|
35
|
+
# Make sure there is an credit_note in Xero to retrieve.
|
36
|
+
example_credit_note = @gateway.create_credit_note(dummy_credit_note).credit_note
|
37
|
+
|
38
|
+
# No line items.
|
39
|
+
response = @gateway.get_credit_note(example_credit_note.credit_note_id)
|
40
|
+
assert_equal(true, response.success?)
|
41
|
+
|
42
|
+
credit_note = response.credit_note
|
43
|
+
assert_kind_of(XeroGateway::LineItem, credit_note.line_items.first)
|
44
|
+
assert_kind_of(XeroGateway::CreditNote, credit_note)
|
45
|
+
assert_equal(true, credit_note.line_items_downloaded?)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class GetCreditNotesTest < Test::Unit::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
INVALID_CREDIT_NOTE_ID = "99999999-9999-9999-9999-999999999999" unless defined?(INVALID_CREDIT_NOTE_ID)
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@gateway = XeroGateway::Gateway.new(CONSUMER_KEY, CONSUMER_SECRET)
|
10
|
+
|
11
|
+
if STUB_XERO_CALLS
|
12
|
+
@gateway.xero_url = "DUMMY_URL"
|
13
|
+
|
14
|
+
@gateway.stubs(:http_get).with {|client, url, params| url =~ /CreditNotes/ }.returns(get_file_as_string("credit_notes.xml"))
|
15
|
+
@gateway.stubs(:http_put).with {|client, url, body, params| url =~ /CreditNotes$/ }.returns(get_file_as_string("create_credit_note.xml"))
|
16
|
+
|
17
|
+
# Get an credit_note with an invalid ID number.
|
18
|
+
@gateway.stubs(:http_get).with {|client, url, params| url =~ Regexp.new("CreditNotes/#{INVALID_CREDIT_NOTE_ID}") }.returns(get_file_as_string("credit_note_not_found_error.xml"))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_get_credit_notes
|
23
|
+
# Make sure there is an credit_note in Xero to retrieve
|
24
|
+
credit_note = @gateway.create_credit_note(dummy_credit_note).credit_note
|
25
|
+
|
26
|
+
result = @gateway.get_credit_notes
|
27
|
+
assert result.success?
|
28
|
+
assert !result.request_params.nil?
|
29
|
+
assert !result.response_xml.nil?
|
30
|
+
assert result.credit_notes.collect {|i| i.credit_note_number}.include?(credit_note.credit_note_number)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_get_credit_notes_with_modified_since_date
|
34
|
+
# Create a test credit_note
|
35
|
+
credit_note = dummy_credit_note
|
36
|
+
@gateway.create_credit_note(credit_note)
|
37
|
+
|
38
|
+
# Check that it is returned
|
39
|
+
result = @gateway.get_credit_notes(:modified_since => Date.today - 1)
|
40
|
+
assert result.success?
|
41
|
+
assert !result.request_params.nil?
|
42
|
+
assert !result.response_xml.nil?
|
43
|
+
assert result.request_params.keys.include?(:ModifiedAfter) # make sure the flag was sent
|
44
|
+
assert result.credit_notes.collect {|response_credit_note| response_credit_note.credit_note_number}.include?(credit_note.credit_note_number)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_line_items_downloaded_set_correctly
|
48
|
+
# No line items.
|
49
|
+
response = @gateway.get_credit_notes
|
50
|
+
assert_equal(true, response.success?)
|
51
|
+
|
52
|
+
credit_note = response.credit_notes.first
|
53
|
+
assert_kind_of(XeroGateway::CreditNote, credit_note)
|
54
|
+
assert_equal(false, credit_note.line_items_downloaded?)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Make sure that a reference to gateway is passed when the get_credit_notes response is parsed.
|
58
|
+
def test_get_contacts_gateway_reference
|
59
|
+
result = @gateway.get_credit_notes
|
60
|
+
assert(result.success?)
|
61
|
+
assert_not_equal(0, result.credit_notes.size)
|
62
|
+
|
63
|
+
result.credit_notes.each do | credit_note |
|
64
|
+
assert(credit_note.gateway === @gateway)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Test to make sure that we correctly error when an credit_note doesn't have an ID.
|
69
|
+
# This should usually never be ecountered, but might if a draft credit_note is deleted from Xero.
|
70
|
+
def test_to_ensure_that_an_credit_note_with_invalid_id_errors
|
71
|
+
# Make sure there is an credit_note to retrieve, even though we will mangle it later.
|
72
|
+
credit_note = @gateway.create_credit_note(dummy_credit_note).credit_note
|
73
|
+
|
74
|
+
result = @gateway.get_credit_notes
|
75
|
+
assert_equal(true, result.success?)
|
76
|
+
|
77
|
+
credit_note = result.credit_notes.first
|
78
|
+
assert_equal(false, credit_note.line_items_downloaded?)
|
79
|
+
|
80
|
+
# Mangle credit_note_id to invalid one.
|
81
|
+
credit_note.credit_note_id = INVALID_CREDIT_NOTE_ID
|
82
|
+
|
83
|
+
# Make sure we fail here.
|
84
|
+
line_items = nil
|
85
|
+
assert_raise(XeroGateway::CreditNoteNotFoundError) { line_items = credit_note.line_items }
|
86
|
+
assert_nil(line_items)
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -20,7 +20,8 @@ class GetTrackingCategoriesTest < Test::Unit::TestCase
|
|
20
20
|
if STUB_XERO_CALLS
|
21
21
|
# When operating against the Xero test environment, there may not be any tracking categories present,
|
22
22
|
# so this assertion can only be done when operating against stub responses
|
23
|
-
|
23
|
+
assert_equal 1, result.tracking_categories.size
|
24
|
+
assert_equal 4, result.tracking_categories.first.options.size
|
24
25
|
end
|
25
26
|
end
|
26
|
-
end
|
27
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -51,6 +51,29 @@ module TestHelper
|
|
51
51
|
invoice
|
52
52
|
end
|
53
53
|
|
54
|
+
def dummy_credit_note(with_line_items = true)
|
55
|
+
credit_note = XeroGateway::CreditNote.new({
|
56
|
+
:type => "ACCRECCREDIT",
|
57
|
+
:date => Time.now,
|
58
|
+
:credit_note_number => STUB_XERO_CALLS ? "CN-0153" : "#{Time.now.to_f}",
|
59
|
+
:reference => "YOUR REFERENCE (NOT NECESSARILY UNIQUE!)",
|
60
|
+
:line_items_downloaded => with_line_items
|
61
|
+
})
|
62
|
+
credit_note.contact = dummy_contact
|
63
|
+
if with_line_items
|
64
|
+
credit_note.line_items << XeroGateway::LineItem.new(
|
65
|
+
:description => "THE DESCRIPTION OF THE LINE ITEM",
|
66
|
+
:unit_amount => 1000,
|
67
|
+
:tax_amount => 125,
|
68
|
+
:tracking => [
|
69
|
+
XeroGateway::TrackingCategory.new(:name => "THE FIRST TRACKING CATEGORY FOR THE LINE ITEM", :options => ["a", "b"]),
|
70
|
+
XeroGateway::TrackingCategory.new(:name => "THE SECOND TRACKING CATEGORY FOR THE LINE ITEM", :options => "c")
|
71
|
+
]
|
72
|
+
)
|
73
|
+
end
|
74
|
+
credit_note
|
75
|
+
end
|
76
|
+
|
54
77
|
def dummy_contact
|
55
78
|
unique_id = Time.now.to_f
|
56
79
|
contact = XeroGateway::Contact.new(:name => STUB_XERO_CALLS ? "CONTACT NAME" : "THE NAME OF THE CONTACT #{unique_id}")
|
@@ -78,4 +101,4 @@ module TestHelper
|
|
78
101
|
return data
|
79
102
|
end
|
80
103
|
|
81
|
-
end
|
104
|
+
end
|
data/test/unit/account_test.rb
CHANGED
@@ -22,13 +22,14 @@ class AccountTest < Test::Unit::TestCase
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def create_test_account
|
25
|
-
account = XeroGateway::Account.new
|
25
|
+
account = XeroGateway::Account.new(:account_id => "57cedda9")
|
26
26
|
account.code = "200"
|
27
27
|
account.name = "Sales"
|
28
28
|
account.type = "REVENUE"
|
29
29
|
account.tax_type = "OUTPUT"
|
30
30
|
account.description = "Income from any normal business activity"
|
31
|
+
account.enable_payments_to_account = false
|
31
32
|
|
32
33
|
account
|
33
34
|
end
|
34
|
-
end
|
35
|
+
end
|
@@ -0,0 +1,284 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper.rb')
|
2
|
+
|
3
|
+
class CreditNoteTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
# Tests that a credit note can be converted into XML that Xero can understand, and then converted back to a credit note
|
6
|
+
def test_build_and_parse_xml
|
7
|
+
credit_note = create_test_credit_note
|
8
|
+
|
9
|
+
# Generate the XML message
|
10
|
+
credit_note_as_xml = credit_note.to_xml
|
11
|
+
|
12
|
+
# Parse the XML message and retrieve the credit_note element
|
13
|
+
credit_note_element = REXML::XPath.first(REXML::Document.new(credit_note_as_xml), "/CreditNote")
|
14
|
+
|
15
|
+
# Build a new credit_note from the XML
|
16
|
+
result_credit_note = XeroGateway::CreditNote.from_xml(credit_note_element)
|
17
|
+
|
18
|
+
assert_equal(credit_note, result_credit_note)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Tests the sub_total calculation and that setting it manually doesn't modify the data.
|
22
|
+
def test_credit_note_sub_total_calculation
|
23
|
+
credit_note = create_test_credit_note
|
24
|
+
line_item = credit_note.line_items.first
|
25
|
+
|
26
|
+
# Make sure that everything adds up to begin with.
|
27
|
+
expected_sub_total = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.line_amount }
|
28
|
+
assert_equal(expected_sub_total, credit_note.sub_total)
|
29
|
+
|
30
|
+
# Change the sub_total and check that it doesn't modify anything.
|
31
|
+
credit_note.sub_total = expected_sub_total * 10
|
32
|
+
assert_equal(expected_sub_total, credit_note.sub_total)
|
33
|
+
|
34
|
+
# Change the amount of the first line item and make sure that
|
35
|
+
# everything still continues to add up.
|
36
|
+
line_item.unit_amount = line_item.unit_amount + 10
|
37
|
+
assert_not_equal(expected_sub_total, credit_note.sub_total)
|
38
|
+
expected_sub_total = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.line_amount }
|
39
|
+
assert_equal(expected_sub_total, credit_note.sub_total)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Tests the total_tax calculation and that setting it manually doesn't modify the data.
|
43
|
+
def test_credit_note_sub_total_calculation
|
44
|
+
credit_note = create_test_credit_note
|
45
|
+
line_item = credit_note.line_items.first
|
46
|
+
|
47
|
+
# Make sure that everything adds up to begin with.
|
48
|
+
expected_total_tax = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.tax_amount }
|
49
|
+
assert_equal(expected_total_tax, credit_note.total_tax)
|
50
|
+
|
51
|
+
# Change the total_tax and check that it doesn't modify anything.
|
52
|
+
credit_note.total_tax = expected_total_tax * 10
|
53
|
+
assert_equal(expected_total_tax, credit_note.total_tax)
|
54
|
+
|
55
|
+
# Change the tax_amount of the first line item and make sure that
|
56
|
+
# everything still continues to add up.
|
57
|
+
line_item.tax_amount = line_item.tax_amount + 10
|
58
|
+
assert_not_equal(expected_total_tax, credit_note.total_tax)
|
59
|
+
expected_total_tax = credit_note.line_items.inject(BigDecimal.new('0')) { | sum, line_item | line_item.tax_amount }
|
60
|
+
assert_equal(expected_total_tax, credit_note.total_tax)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Tests the total calculation and that setting it manually doesn't modify the data.
|
64
|
+
def test_credit_note_sub_total_calculation
|
65
|
+
credit_note = create_test_credit_note
|
66
|
+
line_item = credit_note.line_items.first
|
67
|
+
|
68
|
+
# Make sure that everything adds up to begin with.
|
69
|
+
expected_total = credit_note.sub_total + credit_note.total_tax
|
70
|
+
assert_equal(expected_total, credit_note.total)
|
71
|
+
|
72
|
+
# Change the total and check that it doesn't modify anything.
|
73
|
+
credit_note.total = expected_total * 10
|
74
|
+
assert_equal(expected_total, credit_note.total)
|
75
|
+
|
76
|
+
# Change the quantity of the first line item and make sure that
|
77
|
+
# everything still continues to add up.
|
78
|
+
line_item.quantity = line_item.quantity + 5
|
79
|
+
assert_not_equal(expected_total, credit_note.total)
|
80
|
+
expected_total = credit_note.sub_total + credit_note.total_tax
|
81
|
+
assert_equal(expected_total, credit_note.total)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Tests that the LineItem#line_amount calculation is working correctly.
|
85
|
+
def test_line_amount_calculation
|
86
|
+
credit_note = create_test_credit_note
|
87
|
+
line_item = credit_note.line_items.first
|
88
|
+
|
89
|
+
# Make sure that everything adds up to begin with.
|
90
|
+
expected_amount = line_item.quantity * line_item.unit_amount
|
91
|
+
assert_equal(expected_amount, line_item.line_amount)
|
92
|
+
|
93
|
+
# Change the line_amount and check that it doesn't modify anything.
|
94
|
+
line_item.line_amount = expected_amount * 10
|
95
|
+
assert_equal(expected_amount, line_item.line_amount)
|
96
|
+
|
97
|
+
# Change the quantity and check that the line_amount has been updated.
|
98
|
+
quantity = line_item.quantity + 2
|
99
|
+
line_item.quantity = quantity
|
100
|
+
assert_not_equal(expected_amount, line_item.line_amount)
|
101
|
+
assert_equal(quantity * line_item.unit_amount, line_item.line_amount)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Ensure that the totalling methods don't raise exceptions, even when
|
105
|
+
# credit_note.line_items is empty.
|
106
|
+
def test_totalling_methods_when_line_items_empty
|
107
|
+
credit_note = create_test_credit_note
|
108
|
+
credit_note.line_items = []
|
109
|
+
|
110
|
+
assert_nothing_raised(Exception) {
|
111
|
+
assert_equal(BigDecimal.new('0'), credit_note.sub_total)
|
112
|
+
assert_equal(BigDecimal.new('0'), credit_note.total_tax)
|
113
|
+
assert_equal(BigDecimal.new('0'), credit_note.total)
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_type_helper_methods
|
118
|
+
# Test accounts receivable credit_notes.
|
119
|
+
credit_note = create_test_credit_note({:type => 'ACCRECCREDIT'})
|
120
|
+
assert_equal(true, credit_note.accounts_receivable?, "Accounts RECEIVABLE credit_note doesn't think it is.")
|
121
|
+
assert_equal(false, credit_note.accounts_payable?, "Accounts RECEIVABLE credit_note thinks it's payable.")
|
122
|
+
|
123
|
+
# Test accounts payable credit_notes.
|
124
|
+
credit_note = create_test_credit_note({:type => 'ACCPAYCREDIT'})
|
125
|
+
assert_equal(false, credit_note.accounts_receivable?, "Accounts PAYABLE credit_note doesn't think it is.")
|
126
|
+
assert_equal(true, credit_note.accounts_payable?, "Accounts PAYABLE credit_note thinks it's receivable.")
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# Make sure that the create_test_credit_note method is working correctly
|
131
|
+
# with all the defaults and overrides.
|
132
|
+
def test_create_test_credit_note_defaults_working
|
133
|
+
credit_note = create_test_credit_note
|
134
|
+
|
135
|
+
# Test credit_note defaults.
|
136
|
+
assert_equal('ACCRECCREDIT', credit_note.type)
|
137
|
+
assert_kind_of(Date, credit_note.date)
|
138
|
+
assert_equal('12345', credit_note.credit_note_number)
|
139
|
+
assert_equal('MY REFERENCE FOR THIS CREDIT NOTE', credit_note.reference)
|
140
|
+
assert_equal("Exclusive", credit_note.line_amount_types)
|
141
|
+
|
142
|
+
# Test the contact defaults.
|
143
|
+
assert_equal('00000000-0000-0000-0000-000000000000', credit_note.contact.contact_id)
|
144
|
+
assert_equal('CONTACT NAME', credit_note.contact.name)
|
145
|
+
|
146
|
+
# Test address defaults.
|
147
|
+
assert_equal('DEFAULT', credit_note.contact.address.address_type)
|
148
|
+
assert_equal('LINE 1 OF THE ADDRESS', credit_note.contact.address.line_1)
|
149
|
+
|
150
|
+
# Test phone defaults.
|
151
|
+
assert_equal('DEFAULT', credit_note.contact.phone.phone_type)
|
152
|
+
assert_equal('12345678', credit_note.contact.phone.number)
|
153
|
+
|
154
|
+
# Test the line_item defaults.
|
155
|
+
assert_equal('A LINE ITEM', credit_note.line_items.first.description)
|
156
|
+
assert_equal('200', credit_note.line_items.first.account_code)
|
157
|
+
assert_equal(BigDecimal.new('100'), credit_note.line_items.first.unit_amount)
|
158
|
+
assert_equal(BigDecimal.new('12.5'), credit_note.line_items.first.tax_amount)
|
159
|
+
|
160
|
+
# Test overriding an credit_note parameter (assume works for all).
|
161
|
+
credit_note = create_test_credit_note({:type => 'ACCPAYCREDIT'})
|
162
|
+
assert_equal('ACCPAYCREDIT', credit_note.type)
|
163
|
+
|
164
|
+
# Test overriding a contact/address/phone parameter (assume works for all).
|
165
|
+
credit_note = create_test_credit_note({}, {:name => 'OVERRIDDEN NAME', :address => {:line_1 => 'OVERRIDDEN LINE 1'}, :phone => {:number => '999'}})
|
166
|
+
assert_equal('OVERRIDDEN NAME', credit_note.contact.name)
|
167
|
+
assert_equal('OVERRIDDEN LINE 1', credit_note.contact.address.line_1)
|
168
|
+
assert_equal('999', credit_note.contact.phone.number)
|
169
|
+
|
170
|
+
# Test overriding line_items with hash.
|
171
|
+
credit_note = create_test_credit_note({}, {}, {:description => 'OVERRIDDEN LINE ITEM'})
|
172
|
+
assert_equal(1, credit_note.line_items.size)
|
173
|
+
assert_equal('OVERRIDDEN LINE ITEM', credit_note.line_items.first.description)
|
174
|
+
assert_equal(BigDecimal.new('100'), credit_note.line_items.first.unit_amount)
|
175
|
+
|
176
|
+
# Test overriding line_items with array of 2 line_items.
|
177
|
+
credit_note = create_test_credit_note({}, {}, [
|
178
|
+
{:description => 'OVERRIDDEN ITEM 1'},
|
179
|
+
{:description => 'OVERRIDDEN ITEM 2', :account_code => '200', :unit_amount => BigDecimal.new('200'), :tax_amount => '25.0'}
|
180
|
+
])
|
181
|
+
assert_equal(2, credit_note.line_items.size)
|
182
|
+
assert_equal('OVERRIDDEN ITEM 1', credit_note.line_items[0].description)
|
183
|
+
assert_equal(BigDecimal.new('100'), credit_note.line_items[0].unit_amount)
|
184
|
+
assert_equal('OVERRIDDEN ITEM 2', credit_note.line_items[1].description)
|
185
|
+
assert_equal(BigDecimal.new('200'), credit_note.line_items[1].unit_amount)
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_auto_creation_of_associated_contact
|
189
|
+
credit_note = create_test_credit_note({}, nil) # no contact
|
190
|
+
assert_nil(credit_note.instance_variable_get("@contact"))
|
191
|
+
|
192
|
+
new_contact = credit_note.contact
|
193
|
+
assert_kind_of(XeroGateway::Contact, new_contact)
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_add_line_item
|
197
|
+
credit_note = create_test_credit_note({}, {}, nil) # no line_items
|
198
|
+
assert_equal(0, credit_note.line_items.size)
|
199
|
+
|
200
|
+
line_item_params = {:description => "Test Item 1", :unit_amount => 100}
|
201
|
+
|
202
|
+
# Test adding line item by hash
|
203
|
+
line_item = credit_note.add_line_item(line_item_params)
|
204
|
+
assert_kind_of(XeroGateway::LineItem, line_item)
|
205
|
+
assert_equal(line_item_params[:description], line_item.description)
|
206
|
+
assert_equal(line_item_params[:unit_amount], line_item.unit_amount)
|
207
|
+
assert_equal(1, credit_note.line_items.size)
|
208
|
+
|
209
|
+
# Test adding line item by XeroGateway::LineItem
|
210
|
+
line_item = credit_note.add_line_item(line_item_params)
|
211
|
+
assert_kind_of(XeroGateway::LineItem, line_item)
|
212
|
+
assert_equal(line_item_params[:description], line_item.description)
|
213
|
+
assert_equal(line_item_params[:unit_amount], line_item.unit_amount)
|
214
|
+
assert_equal(2, credit_note.line_items.size)
|
215
|
+
|
216
|
+
# Test that pushing anything else into add_line_item fails.
|
217
|
+
["invalid", 100, nil, []].each do | invalid_object |
|
218
|
+
assert_raise(XeroGateway::CreditNote::InvalidLineItemError) { credit_note.add_line_item(invalid_object) }
|
219
|
+
assert_equal(2, credit_note.line_items.size)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
def create_test_credit_note(credit_note_params = {}, contact_params = {}, line_item_params = [])
|
226
|
+
unless credit_note_params.nil?
|
227
|
+
credit_note_params = {
|
228
|
+
:type => 'ACCRECCREDIT',
|
229
|
+
:date => Date.today,
|
230
|
+
:credit_note_number => '12345',
|
231
|
+
:reference => "MY REFERENCE FOR THIS CREDIT NOTE",
|
232
|
+
:line_amount_types => "Exclusive"
|
233
|
+
}.merge(credit_note_params)
|
234
|
+
end
|
235
|
+
credit_note = XeroGateway::CreditNote.new(credit_note_params || {})
|
236
|
+
|
237
|
+
unless contact_params.nil?
|
238
|
+
# Strip out :address key from contact_params to use as the default address.
|
239
|
+
stripped_address = {
|
240
|
+
:address_type => 'DEFAULT',
|
241
|
+
:line_1 => 'LINE 1 OF THE ADDRESS'
|
242
|
+
}.merge(contact_params.delete(:address) || {})
|
243
|
+
|
244
|
+
# Strip out :phone key from contact_params to use at the default phone.
|
245
|
+
stripped_phone = {
|
246
|
+
:phone_type => 'DEFAULT',
|
247
|
+
:number => '12345678'
|
248
|
+
}.merge(contact_params.delete(:phone) || {})
|
249
|
+
|
250
|
+
contact_params = {
|
251
|
+
:contact_id => '00000000-0000-0000-0000-000000000000', # Just any valid GUID
|
252
|
+
:name => "CONTACT NAME",
|
253
|
+
:first_name => "Bob",
|
254
|
+
:last_name => "Builder"
|
255
|
+
}.merge(contact_params)
|
256
|
+
|
257
|
+
# Create credit_note.contact from contact_params.
|
258
|
+
credit_note.contact = XeroGateway::Contact.new(contact_params)
|
259
|
+
credit_note.contact.address = XeroGateway::Address.new(stripped_address)
|
260
|
+
credit_note.contact.phone = XeroGateway::Phone.new(stripped_phone)
|
261
|
+
end
|
262
|
+
|
263
|
+
unless line_item_params.nil?
|
264
|
+
line_item_params = [line_item_params].flatten # always use an array, even if only a single hash passed in
|
265
|
+
|
266
|
+
# At least one line item, make first have some defaults.
|
267
|
+
line_item_params << {} if line_item_params.size == 0
|
268
|
+
line_item_params[0] = {
|
269
|
+
:description => "A LINE ITEM",
|
270
|
+
:account_code => "200",
|
271
|
+
:unit_amount => BigDecimal.new("100"),
|
272
|
+
:tax_amount => BigDecimal.new("12.5"),
|
273
|
+
:tracking => XeroGateway::TrackingCategory.new(:name => "blah", :options => "hello")
|
274
|
+
}.merge(line_item_params[0])
|
275
|
+
|
276
|
+
# Create credit_note.line_items from line_item_params
|
277
|
+
line_item_params.each do | line_item |
|
278
|
+
credit_note.add_line_item(line_item)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
credit_note
|
283
|
+
end
|
284
|
+
end
|
data/test/unit/gateway_test.rb
CHANGED
@@ -32,6 +32,22 @@ class GatewayTest < Test::Unit::TestCase
|
|
32
32
|
@gateway.get_accounts
|
33
33
|
end
|
34
34
|
end
|
35
|
+
|
36
|
+
should "handle rate limit exceeded" do
|
37
|
+
XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("rate_limit_exceeded"), :code => "401"))
|
38
|
+
|
39
|
+
assert_raises XeroGateway::OAuth::RateLimitExceeded do
|
40
|
+
@gateway.get_accounts
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
should "handle unknown errors" do
|
45
|
+
XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("bogus_oauth_error"), :code => "401"))
|
46
|
+
|
47
|
+
assert_raises XeroGateway::OAuth::UnknownError do
|
48
|
+
@gateway.get_accounts
|
49
|
+
end
|
50
|
+
end
|
35
51
|
|
36
52
|
should "handle ApiExceptions" do
|
37
53
|
XeroGateway::OAuth.any_instance.stubs(:put).returns(stub(:plain_body => get_file_as_string("api_exception.xml"), :code => "400"))
|
@@ -76,4 +92,4 @@ class GatewayTest < Test::Unit::TestCase
|
|
76
92
|
assert_equal "Xero.API.Library.Exceptions.ObjectDoesNotExistException", result.errors.first.type
|
77
93
|
assert !result.errors.first.description.nil?
|
78
94
|
end
|
79
|
-
end
|
95
|
+
end
|