xero_gateway 2.0.4 → 2.0.5

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.
Files changed (41) hide show
  1. data/README.textile +57 -5
  2. data/lib/xero_gateway/account.rb +8 -2
  3. data/lib/xero_gateway/credit_note.rb +275 -0
  4. data/lib/xero_gateway/exceptions.rb +3 -1
  5. data/lib/xero_gateway/gateway.rb +119 -3
  6. data/lib/xero_gateway/http.rb +10 -6
  7. data/lib/xero_gateway/oauth.rb +3 -1
  8. data/lib/xero_gateway/response.rb +2 -0
  9. data/lib/xero_gateway/tracking_category.rb +5 -2
  10. data/lib/xero_gateway.rb +1 -0
  11. data/test/integration/create_credit_note_test.rb +49 -0
  12. data/test/integration/get_credit_note_test.rb +48 -0
  13. data/test/integration/get_credit_notes_test.rb +90 -0
  14. data/test/integration/get_tracking_categories_test.rb +3 -2
  15. data/test/test_helper.rb +24 -1
  16. data/test/unit/account_test.rb +3 -2
  17. data/test/unit/credit_note_test.rb +284 -0
  18. data/test/unit/gateway_test.rb +17 -1
  19. data/xero_gateway.gemspec +3 -76
  20. metadata +13 -29
  21. data/CHANGELOG.textile +0 -57
  22. data/test/stub_responses/accounts.xml +0 -1
  23. data/test/stub_responses/api_exception.xml +0 -153
  24. data/test/stub_responses/contact.xml +0 -1
  25. data/test/stub_responses/contacts.xml +0 -2189
  26. data/test/stub_responses/create_invoice.xml +0 -64
  27. data/test/stub_responses/currencies.xml +0 -16
  28. data/test/stub_responses/invalid_api_key_error.xml +0 -1
  29. data/test/stub_responses/invalid_consumer_key +0 -1
  30. data/test/stub_responses/invalid_request_token +0 -1
  31. data/test/stub_responses/invoice.xml +0 -1
  32. data/test/stub_responses/invoice_not_found_error.xml +0 -1
  33. data/test/stub_responses/invoices.xml +0 -1
  34. data/test/stub_responses/organisation.xml +0 -14
  35. data/test/stub_responses/tax_rates.xml +0 -52
  36. data/test/stub_responses/token_expired +0 -1
  37. data/test/stub_responses/tracking_categories.xml +0 -1
  38. data/test/stub_responses/unknown_error.xml +0 -1
  39. data/test/xsd/README +0 -2
  40. data/test/xsd/create_contact.xsd +0 -61
  41. 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
- assert result.tracking_categories.size == 2
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
@@ -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
@@ -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