xero_gateway-n8vision 2.0.20

Sign up to get free protection for your applications and to get access to all the features.
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