xero_gateway-n8vision 2.0.20

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 (78) hide show
  1. data/Gemfile +12 -0
  2. data/LICENSE +14 -0
  3. data/README.textile +357 -0
  4. data/Rakefile +14 -0
  5. data/examples/oauth.rb +25 -0
  6. data/examples/partner_app.rb +36 -0
  7. data/init.rb +1 -0
  8. data/lib/oauth/oauth_consumer.rb +14 -0
  9. data/lib/xero_gateway.rb +41 -0
  10. data/lib/xero_gateway/account.rb +86 -0
  11. data/lib/xero_gateway/accounts_list.rb +73 -0
  12. data/lib/xero_gateway/address.rb +96 -0
  13. data/lib/xero_gateway/bank_transaction.rb +175 -0
  14. data/lib/xero_gateway/ca-certificates.crt +2560 -0
  15. data/lib/xero_gateway/contact.rb +203 -0
  16. data/lib/xero_gateway/credit_note.rb +220 -0
  17. data/lib/xero_gateway/currency.rb +56 -0
  18. data/lib/xero_gateway/dates.rb +25 -0
  19. data/lib/xero_gateway/error.rb +18 -0
  20. data/lib/xero_gateway/exceptions.rb +51 -0
  21. data/lib/xero_gateway/gateway.rb +698 -0
  22. data/lib/xero_gateway/http.rb +135 -0
  23. data/lib/xero_gateway/http_encoding_helper.rb +49 -0
  24. data/lib/xero_gateway/invoice.rb +238 -0
  25. data/lib/xero_gateway/journal_line.rb +102 -0
  26. data/lib/xero_gateway/line_item.rb +125 -0
  27. data/lib/xero_gateway/line_item_calculations.rb +51 -0
  28. data/lib/xero_gateway/manual_journal.rb +163 -0
  29. data/lib/xero_gateway/money.rb +16 -0
  30. data/lib/xero_gateway/oauth.rb +92 -0
  31. data/lib/xero_gateway/organisation.rb +75 -0
  32. data/lib/xero_gateway/partner_app.rb +30 -0
  33. data/lib/xero_gateway/payment.rb +43 -0
  34. data/lib/xero_gateway/phone.rb +77 -0
  35. data/lib/xero_gateway/private_app.rb +17 -0
  36. data/lib/xero_gateway/response.rb +43 -0
  37. data/lib/xero_gateway/tax_rate.rb +63 -0
  38. data/lib/xero_gateway/tracking_category.rb +87 -0
  39. data/test/integration/accounts_list_test.rb +109 -0
  40. data/test/integration/create_bank_transaction_test.rb +38 -0
  41. data/test/integration/create_contact_test.rb +66 -0
  42. data/test/integration/create_credit_note_test.rb +49 -0
  43. data/test/integration/create_invoice_test.rb +49 -0
  44. data/test/integration/create_manual_journal_test.rb +35 -0
  45. data/test/integration/get_accounts_test.rb +23 -0
  46. data/test/integration/get_bank_transaction_test.rb +51 -0
  47. data/test/integration/get_bank_transactions_test.rb +88 -0
  48. data/test/integration/get_contact_test.rb +28 -0
  49. data/test/integration/get_contacts_test.rb +40 -0
  50. data/test/integration/get_credit_note_test.rb +48 -0
  51. data/test/integration/get_credit_notes_test.rb +90 -0
  52. data/test/integration/get_currencies_test.rb +25 -0
  53. data/test/integration/get_invoice_test.rb +48 -0
  54. data/test/integration/get_invoices_test.rb +92 -0
  55. data/test/integration/get_manual_journal_test.rb +50 -0
  56. data/test/integration/get_manual_journals_test.rb +88 -0
  57. data/test/integration/get_organisation_test.rb +24 -0
  58. data/test/integration/get_tax_rates_test.rb +25 -0
  59. data/test/integration/get_tracking_categories_test.rb +27 -0
  60. data/test/integration/update_bank_transaction_test.rb +31 -0
  61. data/test/integration/update_contact_test.rb +31 -0
  62. data/test/integration/update_invoice_test.rb +31 -0
  63. data/test/integration/update_manual_journal_test.rb +31 -0
  64. data/test/test_helper.rb +217 -0
  65. data/test/unit/account_test.rb +47 -0
  66. data/test/unit/bank_transaction_test.rb +126 -0
  67. data/test/unit/contact_test.rb +97 -0
  68. data/test/unit/credit_note_test.rb +284 -0
  69. data/test/unit/currency_test.rb +31 -0
  70. data/test/unit/gateway_test.rb +119 -0
  71. data/test/unit/invoice_test.rb +326 -0
  72. data/test/unit/manual_journal_test.rb +93 -0
  73. data/test/unit/oauth_test.rb +116 -0
  74. data/test/unit/organisation_test.rb +38 -0
  75. data/test/unit/tax_rate_test.rb +38 -0
  76. data/test/unit/tracking_category_test.rb +52 -0
  77. data/xero_gateway-n8vision.gemspec +15 -0
  78. metadata +178 -0
@@ -0,0 +1,75 @@
1
+ module XeroGateway
2
+ class Organisation
3
+
4
+ unless defined? ATTRS
5
+ ATTRS = {
6
+ "Name" => :string, # Display name of organisation shown in Xero
7
+ "LegalName" => :string, # Organisation name shown on Reports
8
+ "PaysTax" => :boolean, # Boolean to describe if organisation is registered with a local tax authority i.e. true, false
9
+ "Version" => :string, # See Version Types
10
+ "BaseCurrency" => :string, # Default currency for organisation. See Currency types
11
+ "OrganisationType" => :string, # UNDOCUMENTED parameter, only returned for "real" (i.e non-demo) companies
12
+ "OrganisationStatus" => :string, # UNDOCUMENTED parameter
13
+ "IsDemoCompany" => :boolean, # UNDOCUMENTED parameter
14
+ "APIKey" => :string, # UNDOCUMENTED paramater, returned if organisations are linked via Xero Network
15
+ "CountryCode" => :string, # UNDOCUMENTED parameter
16
+ "TaxNumber" => :string,
17
+ "FinancialYearEndDay" => :string,
18
+ "FinancialYearEndMonth" => :string,
19
+ "PeriodLockDate" => :string,
20
+ "CreatedDateUTC" => :string
21
+ }
22
+ end
23
+
24
+ attr_accessor *ATTRS.keys.map(&:underscore)
25
+
26
+ def initialize(params = {})
27
+ params.each do |k,v|
28
+ self.send("#{k}=", v)
29
+ end
30
+ end
31
+
32
+ def ==(other)
33
+ ATTRS.keys.map(&:underscore).each do |field|
34
+ return false if send(field) != other.send(field)
35
+ end
36
+ return true
37
+ end
38
+
39
+ def to_xml
40
+ b = Builder::XmlMarkup.new
41
+
42
+ b.Organisation do
43
+ ATTRS.keys.each do |attr|
44
+ eval("b.#{attr} '#{self.send(attr.underscore.to_sym)}'")
45
+ end
46
+ end
47
+ end
48
+
49
+ def self.from_xml(organisation_element)
50
+ Organisation.new.tap do |org|
51
+ organisation_element.children.each do |element|
52
+
53
+ attribute = element.name
54
+ underscored_attribute = element.name.underscore
55
+
56
+ if ATTRS.keys.include?(attribute)
57
+
58
+ case (ATTRS[attribute])
59
+ when :boolean then org.send("#{underscored_attribute}=", (element.text == "true"))
60
+ when :float then org.send("#{underscored_attribute}=", element.text.to_f)
61
+ else org.send("#{underscored_attribute}=", element.text)
62
+ end
63
+
64
+ else
65
+
66
+ warn "Ignoring unknown attribute: #{attribute}"
67
+
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,30 @@
1
+ module XeroGateway
2
+ class PartnerApp < Gateway
3
+
4
+ class CertificateRequired < StandardError; end
5
+
6
+ NO_SSL_CLIENT_CERT_MESSAGE = "You need to provide a client ssl certificate and key pair (these are the ones you got from Entrust and should not be password protected) as :ssl_client_cert and :ssl_client_key (should be .crt or .pem files)"
7
+ NO_PRIVATE_KEY_ERROR_MESSAGE = "You need to provide your private key (corresponds to the public key you uploaded at api.xero.com) as :private_key_file (should be .crt or .pem files)"
8
+
9
+ def_delegators :client, :session_handle, :renew_access_token
10
+
11
+ def initialize(consumer_key, consumer_secret, options = {})
12
+
13
+ raise CertificateRequired.new(NO_SSL_CLIENT_CERT_MESSAGE) unless options[:ssl_client_cert]
14
+ raise CertificateRequired.new(NO_SSL_CLIENT_CERT_MESSAGE) unless options[:ssl_client_key]
15
+ raise CertificateRequired.new(NO_PRIVATE_KEY_ERROR_MESSAGE) unless options[:private_key_file]
16
+
17
+ options.merge!(
18
+ :site => "https://api-partner.network.xero.com",
19
+ :authorize_url => 'https://api.xero.com/oauth/Authorize',
20
+ :signature_method => 'RSA-SHA1',
21
+ :ssl_client_cert => OpenSSL::X509::Certificate.new(File.read(options[:ssl_client_cert])),
22
+ :ssl_client_key => OpenSSL::PKey::RSA.new(File.read(options[:ssl_client_key])),
23
+ :private_key_file => options[:private_key_file]
24
+ )
25
+
26
+ @xero_url = options[:xero_url] || "https://api-partner.xero.com/api.xro/2.0"
27
+ @client = OAuth.new(consumer_key, consumer_secret, options)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,43 @@
1
+ module XeroGateway
2
+ class Payment
3
+ include Money
4
+ include Dates
5
+
6
+ # Any errors that occurred when the #valid? method called.
7
+ attr_reader :errors
8
+
9
+ # All accessible fields
10
+ attr_accessor :payment_id, :date, :amount, :reference, :currency_rate
11
+
12
+ def initialize(params = {})
13
+ @errors ||= []
14
+
15
+ params.each do |k,v|
16
+ self.send("#{k}=", v)
17
+ end
18
+ end
19
+
20
+ def self.from_xml(payment_element)
21
+ payment = Payment.new
22
+ payment_element.children.each do | element |
23
+ case element.name
24
+ when 'PaymentID' then payment.payment_id = element.text
25
+ when 'Date' then payment.date = parse_date_time(element.text)
26
+ when 'Amount' then payment.amount = BigDecimal.new(element.text)
27
+ when 'Reference' then payment.reference = element.text
28
+ when 'CurrencyRate' then payment.currency_rate = BigDecimal.new(element.text)
29
+ end
30
+ end
31
+ payment
32
+ end
33
+
34
+ def ==(other)
35
+ [:payment_id, :date, :amount].each do |field|
36
+ return false if send(field) != other.send(field)
37
+ end
38
+ return true
39
+ end
40
+
41
+
42
+ end
43
+ end
@@ -0,0 +1,77 @@
1
+ module XeroGateway
2
+ class Phone
3
+
4
+ PHONE_TYPE = {
5
+ 'DEFAULT' => 'Default',
6
+ 'DDI' => 'Direct Dial-In',
7
+ 'MOBILE' => 'Mobile',
8
+ 'FAX' => 'Fax'
9
+ } unless defined?(PHONE_TYPE)
10
+
11
+ # Any errors that occurred when the #valid? method called.
12
+ attr_reader :errors
13
+
14
+ attr_accessor :phone_type, :number, :area_code, :country_code
15
+
16
+ def initialize(params = {})
17
+ @errors ||= []
18
+
19
+ params = {
20
+ :phone_type => "DEFAULT"
21
+ }.merge(params)
22
+
23
+ params.each do |k,v|
24
+ self.send("#{k}=", v)
25
+ end
26
+ end
27
+
28
+ # Validate the Phone record according to what will be valid by the gateway.
29
+ #
30
+ # Usage:
31
+ # phone.valid? # Returns true/false
32
+ #
33
+ # Additionally sets phone.errors array to an array of field/error.
34
+ def valid?
35
+ @errors = []
36
+
37
+ unless number
38
+ @errors << ['number', "can't be blank"]
39
+ end
40
+
41
+ if phone_type && !PHONE_TYPE[phone_type]
42
+ @errors << ['phone_type', "must be one of #{PHONE_TYPE.keys.join('/')}"]
43
+ end
44
+
45
+ @errors.size == 0
46
+ end
47
+
48
+ def to_xml(b = Builder::XmlMarkup.new)
49
+ b.Phone {
50
+ b.PhoneType phone_type
51
+ b.PhoneNumber number
52
+ b.PhoneAreaCode area_code if area_code
53
+ b.PhoneCountryCode country_code if country_code
54
+ }
55
+ end
56
+
57
+ def self.from_xml(phone_element)
58
+ phone = Phone.new
59
+ phone_element.children.each do |element|
60
+ case(element.name)
61
+ when "PhoneType" then phone.phone_type = element.text
62
+ when "PhoneNumber" then phone.number = element.text
63
+ when "PhoneAreaCode" then phone.area_code = element.text
64
+ when "PhoneCountryCode" then phone.country_code = element.text
65
+ end
66
+ end
67
+ phone
68
+ end
69
+
70
+ def ==(other)
71
+ [:phone_type, :number, :area_code, :country_code].each do |field|
72
+ return false if send(field) != other.send(field)
73
+ end
74
+ return true
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,17 @@
1
+ module XeroGateway
2
+ class PrivateApp < Gateway
3
+ #
4
+ # The consumer key and secret here correspond to those provided
5
+ # to you by Xero inside the API Previewer.
6
+ def initialize(consumer_key, consumer_secret, path_to_private_key, options = {})
7
+ options.merge!(
8
+ :signature_method => 'RSA-SHA1',
9
+ :private_key_file => path_to_private_key
10
+ )
11
+
12
+ @xero_url = options[:xero_url] || "https://api.xero.com/api.xro/2.0"
13
+ @client = OAuth.new(consumer_key, consumer_secret, options)
14
+ @client.authorize_from_access(consumer_key, consumer_secret)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ module XeroGateway
2
+ class Response
3
+ attr_accessor :response_id, :status, :errors, :provider, :date_time, :response_item, :request_params, :request_xml, :response_xml
4
+
5
+ def array_wrapped_response_item
6
+ Array(response_item)
7
+ end
8
+
9
+ alias_method :invoice, :response_item
10
+ alias_method :credit_note, :response_item
11
+ alias_method :bank_transaction, :response_item
12
+ alias_method :manual_journal, :response_item
13
+ alias_method :contact, :response_item
14
+ alias_method :organisation, :response_item
15
+ alias_method :invoices, :array_wrapped_response_item
16
+ alias_method :credit_notes, :array_wrapped_response_item
17
+ alias_method :bank_transactions, :array_wrapped_response_item
18
+ alias_method :manual_journals, :array_wrapped_response_item
19
+ alias_method :contacts, :array_wrapped_response_item
20
+ alias_method :accounts, :array_wrapped_response_item
21
+ alias_method :tracking_categories, :array_wrapped_response_item
22
+ alias_method :tax_rates, :array_wrapped_response_item
23
+ alias_method :currencies, :array_wrapped_response_item
24
+
25
+ def initialize(params = {})
26
+ params.each do |k,v|
27
+ self.send("#{k}=", v)
28
+ end
29
+
30
+ @errors ||= []
31
+ @response_item ||= []
32
+ end
33
+
34
+
35
+ def success?
36
+ status == "OK"
37
+ end
38
+
39
+ def error
40
+ errors.blank? ? nil : errors[0]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,63 @@
1
+ module XeroGateway
2
+ class TaxRate
3
+
4
+ unless defined? ATTRS
5
+ ATTRS = {
6
+ "Name" => :string,
7
+ "TaxType" => :string,
8
+ "CanApplyToAssets" => :boolean,
9
+ "CanApplyToEquity" => :boolean,
10
+ "CanApplyToExpenses" => :boolean,
11
+ "CanApplyToLiabilities" => :boolean,
12
+ "CanApplyToRevenue" => :boolean,
13
+ "DisplayTaxRate" => :float,
14
+ "EffectiveRate" => :float
15
+ }
16
+ end
17
+
18
+ attr_accessor *ATTRS.keys.map(&:underscore)
19
+
20
+ def initialize(params = {})
21
+ params.each do |k,v|
22
+ self.send("#{k}=", v)
23
+ end
24
+ end
25
+
26
+ def ==(other)
27
+ ATTRS.keys.map(&:underscore).each do |field|
28
+ return false if send(field) != other.send(field)
29
+ end
30
+ return true
31
+ end
32
+
33
+ def to_xml
34
+ b = Builder::XmlMarkup.new
35
+
36
+ b.TaxRate do
37
+ ATTRS.keys.each do |attr|
38
+ eval("b.#{attr} '#{self.send(attr.underscore.to_sym)}'")
39
+ end
40
+ end
41
+ end
42
+
43
+ def self.from_xml(tax_rate_element)
44
+ TaxRate.new.tap do |tax_rate|
45
+ tax_rate_element.children.each do |element|
46
+
47
+ attribute = element.name
48
+ underscored_attribute = element.name.underscore
49
+
50
+ raise "Unknown attribute: #{attribute}" unless ATTRS.keys.include?(attribute)
51
+
52
+ case (ATTRS[attribute])
53
+ when :boolean then tax_rate.send("#{underscored_attribute}=", (element.text == "true"))
54
+ when :float then tax_rate.send("#{underscored_attribute}=", element.text.to_f)
55
+ else tax_rate.send("#{underscored_attribute}=", element.text)
56
+ end
57
+
58
+ end
59
+ end
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,87 @@
1
+ # Tacking categories look like:
2
+ #
3
+ # <TrackingCategory>
4
+ # <Name>Region</Name>
5
+ # <Status>ACTIVE</Status>
6
+ # <TrackingCategoryID>e4a95e64-ebaa-401e-81cf-b625c7532d01</TrackingCategoryID>
7
+ # <Options>
8
+ # <Option>
9
+ # <TrackingOptionID>ea7f7b6a-0d22-4d5c-9317-54542a10215e</TrackingOptionID>
10
+ # <Name>North</Name>
11
+ # </Option>
12
+ # <Option>
13
+ # <TrackingOptionID>8e8b8d7b-fa75-4b24-b429-8cbc1a21af23</TrackingOptionID>
14
+ # <Name>South</Name>
15
+ # </Option>
16
+ # </Options>
17
+ # </TrackingCategory>
18
+ #
19
+ module XeroGateway
20
+ class TrackingCategory
21
+ attr_accessor :tracking_category_id, :name, :options
22
+
23
+ def initialize(params = {})
24
+ @options = []
25
+ params.each do |k,v|
26
+ self.send("#{k}=", v)
27
+ end
28
+ end
29
+
30
+ def option
31
+ options[0] if options.size == 1
32
+ end
33
+
34
+ def to_xml(b = Builder::XmlMarkup.new)
35
+ b.TrackingCategory {
36
+ b.TrackingCategoryID tracking_category_id unless tracking_category_id.nil?
37
+ b.Name self.name
38
+ b.Options {
39
+ if self.options.is_a?(Array)
40
+ self.options.each do |option|
41
+ b.Option {
42
+ b.Name option
43
+ }
44
+ end
45
+ else
46
+ b.Option {
47
+ b.Name self.options.to_s
48
+ }
49
+ end
50
+ }
51
+ }
52
+ end
53
+
54
+ # When a tracking category is serialized as part of an invoice it may only have a single
55
+ # option, and the Options tag is omitted
56
+ def to_xml_for_invoice_messages(b = Builder::XmlMarkup.new)
57
+ b.TrackingCategory {
58
+ b.TrackingCategoryID self.tracking_category_id unless tracking_category_id.nil?
59
+ b.Name self.name
60
+ b.Option self.options.is_a?(Array) ? self.options.first : self.options.to_s
61
+ }
62
+ end
63
+
64
+ def self.from_xml(tracking_category_element)
65
+ tracking_category = TrackingCategory.new
66
+ tracking_category_element.children.each do |element|
67
+ case(element.name)
68
+ when "TrackingCategoryID" then tracking_category.tracking_category_id = element.text
69
+ when "Name" then tracking_category.name = element.text
70
+ when "Options" then
71
+ element.children.each do |option_child|
72
+ tracking_category.options << option_child.children.detect {|c| c.name == "Name"}.text
73
+ end
74
+ when "Option" then tracking_category.options << element.text
75
+ end
76
+ end
77
+ tracking_category
78
+ end
79
+
80
+ def ==(other)
81
+ [:tracking_category_id, :name, :options].each do |field|
82
+ return false if send(field) != other.send(field)
83
+ end
84
+ return true
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,109 @@
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(CONSUMER_KEY, CONSUMER_SECRET)
8
+
9
+ # Always stub out calls for this integration test as we need to be able to control the data.
10
+ @gateway.xero_url = "DUMMY_URL"
11
+
12
+ @gateway.stubs(:http_get).with {|client, url, params| url =~ /Accounts$/ }.returns(get_file_as_string("accounts.xml"))
13
+ end
14
+
15
+ def test_get_accounts_list
16
+ accounts_list = @gateway.get_accounts_list
17
+ assert_not_equal(0, accounts_list.accounts.size)
18
+ end
19
+
20
+ # Make sure that the list is loaded when finding things.
21
+ def test_raise_error_on_not_loaded
22
+ accounts_list = @gateway.get_accounts_list(false)
23
+ assert_equal(false, accounts_list.loaded?)
24
+ assert_raise(XeroGateway::AccountsListNotLoadedError) { accounts_list[200] }
25
+ assert_raise(XeroGateway::AccountsListNotLoadedError) { accounts_list.find_by_code(200) }
26
+ assert_raise(XeroGateway::AccountsListNotLoadedError) { accounts_list.find_all_by_type('EXPENSE') }
27
+ assert_raise(XeroGateway::AccountsListNotLoadedError) { accounts_list.find_all_by_tax_type('OUTPUT') }
28
+ end
29
+
30
+ # Test simple lookup by account code (from cache).
31
+ def test_simple_lookup_by_account_code
32
+ accounts_list = @gateway.get_accounts_list
33
+ assert_equal(true, accounts_list.loaded?)
34
+
35
+ # Load data in the stubbed response.
36
+ expected_accounts = accounts_as_array
37
+
38
+ # Make sure that every single expected account exists in the cached lookup hash.
39
+ expected_accounts.each do | expected_account |
40
+ found_account = accounts_list.find_by_code(expected_account.code)
41
+ assert_kind_of(XeroGateway::Account, found_account)
42
+ assert(expected_account == found_account, "Found account does not match expected account.")
43
+
44
+ found_account_shortcut = accounts_list[expected_account.code]
45
+ assert_kind_of(XeroGateway::Account, found_account_shortcut)
46
+ assert(expected_account == found_account_shortcut, "Found account does not match expected account (shortcut).")
47
+ end
48
+ end
49
+
50
+ # Test finding accounts by their account type (from cache).
51
+ def test_lookup_by_account_type
52
+ accounts_list = @gateway.get_accounts_list
53
+ assert_equal(true, accounts_list.loaded?)
54
+
55
+ # Load data in the stubbed response.
56
+ expected_accounts = accounts_as_array
57
+
58
+ # Get all the unique account types present in the expected accounts data along with their counts.
59
+ unique_types = expected_accounts.inject({}) do | list, account |
60
+ list[account.type] = 0 if list[account.type].nil?
61
+ list[account.type] += 1
62
+ list
63
+ end
64
+
65
+ assert_not_equal(0, unique_types)
66
+ unique_types.each do | account_type, count |
67
+ found_accounts = accounts_list.find_all_by_type(account_type)
68
+ assert_equal(count, found_accounts.size)
69
+ found_accounts.each do | found_account |
70
+ assert_kind_of(XeroGateway::Account, found_account)
71
+ assert_equal(account_type, found_account.type)
72
+ end
73
+ end
74
+ end
75
+
76
+ # Test finding accounts by their tax type (from cache).
77
+ def test_lookup_by_tax_type
78
+ accounts_list = @gateway.get_accounts_list
79
+ assert_equal(true, accounts_list.loaded?)
80
+
81
+ # Load data in the stubbed response.
82
+ expected_accounts = accounts_as_array
83
+
84
+ # Get all the unique tax types present in the expected accounts data along with their counts.
85
+ unique_types = expected_accounts.inject({}) do | list, account |
86
+ list[account.tax_type] = 0 if list[account.tax_type].nil?
87
+ list[account.tax_type] += 1
88
+ list
89
+ end
90
+
91
+ assert_not_equal(0, unique_types)
92
+ unique_types.each do | tax_type, count |
93
+ found_accounts = accounts_list.find_all_by_tax_type(tax_type)
94
+ assert_equal(count, found_accounts.size)
95
+ found_accounts.each do | found_account |
96
+ assert_kind_of(XeroGateway::Account, found_account)
97
+ assert_equal(tax_type, found_account.tax_type)
98
+ end
99
+ end
100
+ end
101
+
102
+ private
103
+
104
+ def accounts_as_array
105
+ response = @gateway.__send__(:parse_response, get_file_as_string("accounts.xml"))
106
+ response.accounts
107
+ end
108
+
109
+ end