xero_gateway 2.0.2

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