xero_gateway 2.0.2

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 (75) hide show
  1. data/CHANGELOG.textile +51 -0
  2. data/LICENSE +14 -0
  3. data/README.textile +289 -0
  4. data/Rakefile +14 -0
  5. data/examples/oauth.rb +25 -0
  6. data/init.rb +1 -0
  7. data/lib/xero_gateway/account.rb +78 -0
  8. data/lib/xero_gateway/accounts_list.rb +77 -0
  9. data/lib/xero_gateway/address.rb +97 -0
  10. data/lib/xero_gateway/ca-certificates.crt +2560 -0
  11. data/lib/xero_gateway/contact.rb +206 -0
  12. data/lib/xero_gateway/currency.rb +56 -0
  13. data/lib/xero_gateway/dates.rb +25 -0
  14. data/lib/xero_gateway/error.rb +18 -0
  15. data/lib/xero_gateway/exceptions.rb +41 -0
  16. data/lib/xero_gateway/gateway.rb +363 -0
  17. data/lib/xero_gateway/http.rb +128 -0
  18. data/lib/xero_gateway/http_encoding_helper.rb +49 -0
  19. data/lib/xero_gateway/invoice.rb +278 -0
  20. data/lib/xero_gateway/line_item.rb +123 -0
  21. data/lib/xero_gateway/money.rb +16 -0
  22. data/lib/xero_gateway/oauth.rb +56 -0
  23. data/lib/xero_gateway/organisation.rb +61 -0
  24. data/lib/xero_gateway/payment.rb +40 -0
  25. data/lib/xero_gateway/phone.rb +77 -0
  26. data/lib/xero_gateway/private_app.rb +17 -0
  27. data/lib/xero_gateway/response.rb +37 -0
  28. data/lib/xero_gateway/tax_rate.rb +63 -0
  29. data/lib/xero_gateway/tracking_category.rb +62 -0
  30. data/lib/xero_gateway.rb +33 -0
  31. data/test/integration/accounts_list_test.rb +109 -0
  32. data/test/integration/create_contact_test.rb +66 -0
  33. data/test/integration/create_invoice_test.rb +49 -0
  34. data/test/integration/get_accounts_test.rb +23 -0
  35. data/test/integration/get_contact_test.rb +28 -0
  36. data/test/integration/get_contacts_test.rb +40 -0
  37. data/test/integration/get_currencies_test.rb +25 -0
  38. data/test/integration/get_invoice_test.rb +48 -0
  39. data/test/integration/get_invoices_test.rb +90 -0
  40. data/test/integration/get_organisation_test.rb +24 -0
  41. data/test/integration/get_tax_rates_test.rb +25 -0
  42. data/test/integration/get_tracking_categories_test.rb +26 -0
  43. data/test/integration/update_contact_test.rb +31 -0
  44. data/test/stub_responses/accounts.xml +1 -0
  45. data/test/stub_responses/api_exception.xml +153 -0
  46. data/test/stub_responses/contact.xml +1 -0
  47. data/test/stub_responses/contacts.xml +2189 -0
  48. data/test/stub_responses/create_invoice.xml +64 -0
  49. data/test/stub_responses/currencies.xml +16 -0
  50. data/test/stub_responses/invalid_api_key_error.xml +1 -0
  51. data/test/stub_responses/invalid_consumer_key +1 -0
  52. data/test/stub_responses/invalid_request_token +1 -0
  53. data/test/stub_responses/invoice.xml +1 -0
  54. data/test/stub_responses/invoice_not_found_error.xml +1 -0
  55. data/test/stub_responses/invoices.xml +1 -0
  56. data/test/stub_responses/organisation.xml +14 -0
  57. data/test/stub_responses/tax_rates.xml +52 -0
  58. data/test/stub_responses/token_expired +1 -0
  59. data/test/stub_responses/tracking_categories.xml +1 -0
  60. data/test/stub_responses/unknown_error.xml +1 -0
  61. data/test/test_helper.rb +81 -0
  62. data/test/unit/account_test.rb +34 -0
  63. data/test/unit/contact_test.rb +97 -0
  64. data/test/unit/currency_test.rb +31 -0
  65. data/test/unit/gateway_test.rb +79 -0
  66. data/test/unit/invoice_test.rb +302 -0
  67. data/test/unit/oauth_test.rb +110 -0
  68. data/test/unit/organisation_test.rb +34 -0
  69. data/test/unit/tax_rate_test.rb +38 -0
  70. data/test/unit/tracking_category_test.rb +30 -0
  71. data/test/xsd/README +2 -0
  72. data/test/xsd/create_contact.xsd +61 -0
  73. data/test/xsd/create_invoice.xsd +107 -0
  74. data/xero_gateway.gemspec +87 -0
  75. metadata +172 -0
@@ -0,0 +1,62 @@
1
+ module XeroGateway
2
+ class TrackingCategory
3
+ attr_accessor :name, :options
4
+
5
+ def initialize(params = {})
6
+ @options = []
7
+ params.each do |k,v|
8
+ self.send("#{k}=", v)
9
+ end
10
+ end
11
+
12
+ def option
13
+ options[0] if options.size == 1
14
+ end
15
+
16
+ def to_xml(b = Builder::XmlMarkup.new)
17
+ b.TrackingCategory {
18
+ b.Name self.name
19
+ b.Options {
20
+ if self.options.is_a?(Array)
21
+ self.options.each do |option|
22
+ b.Option {
23
+ b.Name option
24
+ }
25
+ end
26
+ else
27
+ b.Option {
28
+ b.Name self.options.to_s
29
+ }
30
+ end
31
+ }
32
+ }
33
+ end
34
+
35
+ # When a tracking category is serialized as part of an invoice it may only have a single
36
+ # option, and the Options tag is omitted
37
+ def to_xml_for_invoice_messages(b = Builder::XmlMarkup.new)
38
+ b.TrackingCategory {
39
+ b.Name self.name
40
+ b.Option self.options.is_a?(Array) ? self.options.first : self.options.to_s
41
+ }
42
+ end
43
+
44
+ def self.from_xml(tracking_category_element)
45
+ tracking_category = TrackingCategory.new
46
+ tracking_category_element.children.each do |element|
47
+ case(element.name)
48
+ when "Name" then tracking_category.name = element.text
49
+ when "Options" then element.children.each {|option| tracking_category.options << option.children.first.text}
50
+ end
51
+ end
52
+ tracking_category
53
+ end
54
+
55
+ def ==(other)
56
+ [:name, :options].each do |field|
57
+ return false if send(field) != other.send(field)
58
+ end
59
+ return true
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,33 @@
1
+ require "cgi"
2
+ require "uri"
3
+ require "net/https"
4
+ require "rexml/document"
5
+ require "builder"
6
+ require "bigdecimal"
7
+ require "oauth"
8
+ require 'oauth/signature/rsa/sha1'
9
+ require "forwardable"
10
+ require "active_support/inflector"
11
+
12
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'http_encoding_helper')
13
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'http')
14
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'dates')
15
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'money')
16
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'response')
17
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'account')
18
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'accounts_list')
19
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'tracking_category')
20
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'contact')
21
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'line_item')
22
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'payment')
23
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'invoice')
24
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'address')
25
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'phone')
26
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'organisation')
27
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'tax_rate')
28
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'currency')
29
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'error')
30
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'oauth')
31
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'exceptions')
32
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'gateway')
33
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'private_app')
@@ -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::AccountsList::AccountsListNotLoadedError) { accounts_list[200] }
25
+ assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list.find_by_code(200) }
26
+ assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list.find_all_by_type('EXPENSE') }
27
+ assert_raise(XeroGateway::AccountsList::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
@@ -0,0 +1,66 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class CreateContactTest < 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 =~ /Contacts$/ }.returns(get_file_as_string("contact.xml"))
13
+ @gateway.stubs(:http_post).with {|client, url, body, params| url =~ /Contacts$/ }.returns(get_file_as_string("contact.xml"))
14
+ end
15
+ end
16
+
17
+ def test_create_contact
18
+ example_contact = dummy_contact.dup
19
+
20
+ result = @gateway.create_contact(example_contact)
21
+ assert_valid_contact_save_response(result, example_contact)
22
+ end
23
+
24
+ def test_create_from_contact
25
+ example_contact = dummy_contact.dup
26
+
27
+ contact = @gateway.build_contact(example_contact)
28
+ result = contact.create
29
+ assert_valid_contact_save_response(result, example_contact)
30
+ end
31
+
32
+ def test_update_from_contact
33
+ example_contact = dummy_contact.dup
34
+
35
+ contact = @gateway.build_contact(example_contact)
36
+ contact.create # need to create first so we have a ContactID
37
+
38
+ result = contact.update
39
+ assert_valid_contact_save_response(result, example_contact)
40
+ end
41
+
42
+ def test_save_from_contact
43
+ example_contact = dummy_contact.dup
44
+
45
+ contact = @gateway.build_contact(example_contact)
46
+ result = contact.save
47
+ assert_valid_contact_save_response(result, example_contact)
48
+ end
49
+
50
+ def test_create_contact_valid
51
+ example_contact = dummy_contact.dup
52
+ assert_equal true, example_contact.valid?, "contact is invalid - errors:\n\t#{example_contact.errors.map { | error | "#{error[0]} #{error[1]}"}.join("\n\t")}"
53
+ end
54
+
55
+ private
56
+
57
+ def assert_valid_contact_save_response(result, example_contact)
58
+ assert_kind_of XeroGateway::Response, result
59
+ assert result.success?
60
+ assert !result.contact.contact_id.nil?
61
+ assert !result.request_xml.nil?
62
+ assert !result.response_xml.nil?
63
+ assert_equal result.contact.name, example_contact.name
64
+ assert example_contact.contact_id =~ GUID_REGEX
65
+ end
66
+ end
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class CreateInvoiceTest < 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 =~ /Invoices$/ }.returns(get_file_as_string("create_invoice.xml"))
13
+ @gateway.stubs(:http_post).with {|client, url, body, params| url =~ /Invoices$/ }.returns(get_file_as_string("invoice.xml"))
14
+ end
15
+ end
16
+
17
+ def test_create_invoice
18
+ example_invoice = dummy_invoice.dup
19
+
20
+ result = @gateway.create_invoice(example_invoice)
21
+ assert_valid_invoice_save_response(result, example_invoice)
22
+ end
23
+
24
+ def test_create_from_invoice
25
+ example_invoice = dummy_invoice.dup
26
+
27
+ invoice = @gateway.build_invoice(example_invoice)
28
+ result = invoice.create
29
+ assert_valid_invoice_save_response(result, example_invoice)
30
+ end
31
+
32
+ def test_create_invoice_valid
33
+ example_invoice = dummy_invoice.dup
34
+ assert_equal true, example_invoice.valid?, "invoice is invalid - errors:\n\t#{example_invoice.errors.map { | error | "#{error[0]} #{error[1]}"}.join("\n\t")}"
35
+ end
36
+
37
+ private
38
+
39
+ def assert_valid_invoice_save_response(result, example_invoice)
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.invoice.invoice_id.nil?
45
+ assert result.invoice.invoice_number == example_invoice.invoice_number
46
+ assert example_invoice.invoice_id =~ GUID_REGEX
47
+ end
48
+
49
+ end
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class GetAccountsTest < 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 =~ /Accounts$/ }.returns(get_file_as_string("accounts.xml"))
13
+ end
14
+ end
15
+
16
+ def test_get_accounts
17
+ result = @gateway.get_accounts
18
+ assert result.success?
19
+ assert !result.response_xml.nil?
20
+ assert result.accounts.size > 0
21
+ assert_equal XeroGateway::Account, result.accounts.first.class
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class GetContactTest < 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 =~ /Contacts\/[^\/]+$/ }.returns(get_file_as_string("contact.xml"))
13
+ @gateway.stubs(:http_put).with {|client, url, body, params| url =~ /Contacts$/ }.returns(get_file_as_string("contact.xml"))
14
+ end
15
+ end
16
+
17
+ def test_get_contact
18
+ # Make sure there is an contact in Xero to retrieve
19
+ contact = @gateway.create_contact(dummy_contact).contact
20
+ flunk "get_contact could not be tested because create_contact failed" if contact.nil?
21
+
22
+ result = @gateway.get_contact_by_id(contact.contact_id)
23
+ assert result.success?
24
+ assert !result.request_params.nil?
25
+ assert !result.response_xml.nil?
26
+ assert_equal result.contact.name, contact.name
27
+ end
28
+ end
@@ -0,0 +1,40 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class GetContactsTest < 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 =~ /Contacts$/ }.returns(get_file_as_string("contacts.xml"))
13
+ @gateway.stubs(:http_put).with {|client, url, body, params| url =~ /Contacts$/ }.returns(get_file_as_string("contact.xml"))
14
+ end
15
+ end
16
+
17
+ def test_get_contacts
18
+ # Make sure there is an contact in Xero to retrieve
19
+ contact = @gateway.create_contact(dummy_contact).contact
20
+ flunk "get_contacts could not be tested because create_contact failed" if contact.nil?
21
+
22
+ result = @gateway.get_contacts
23
+ assert result.success?
24
+ assert !result.request_params.nil?
25
+ assert !result.response_xml.nil?
26
+ assert result.contacts.collect {|c| c.contact_id}.include?(contact.contact_id)
27
+ end
28
+
29
+ # Make sure that a reference to gateway is passed when the get_contacts response is parsed.
30
+ def test_get_contacts_gateway_reference
31
+ result = @gateway.get_contacts
32
+ assert(result.success?)
33
+ assert_not_equal(0, result.contacts.size)
34
+
35
+ result.contacts.each do | contact |
36
+ assert(contact.gateway === @gateway)
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class GetCurrenciesTest < 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 =~ /Currencies$/ }.returns(get_file_as_string("currencies.xml"))
13
+ end
14
+ end
15
+
16
+ def test_get_currencies
17
+ result = @gateway.get_currencies
18
+ assert result.success?
19
+ assert !result.response_xml.nil?
20
+
21
+ assert result.currencies.size > 0
22
+ assert_equal XeroGateway::Currency, result.currencies.first.class
23
+ assert_equal "NZD", result.currencies.first.code
24
+ end
25
+ end