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.
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