xero_gateway-float 2.0.15

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 (71) 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 +39 -0
  10. data/lib/xero_gateway/account.rb +95 -0
  11. data/lib/xero_gateway/accounts_list.rb +87 -0
  12. data/lib/xero_gateway/address.rb +96 -0
  13. data/lib/xero_gateway/bank_transaction.rb +178 -0
  14. data/lib/xero_gateway/ca-certificates.crt +2560 -0
  15. data/lib/xero_gateway/contact.rb +206 -0
  16. data/lib/xero_gateway/credit_note.rb +222 -0
  17. data/lib/xero_gateway/currency.rb +56 -0
  18. data/lib/xero_gateway/dates.rb +30 -0
  19. data/lib/xero_gateway/error.rb +18 -0
  20. data/lib/xero_gateway/exceptions.rb +46 -0
  21. data/lib/xero_gateway/gateway.rb +622 -0
  22. data/lib/xero_gateway/http.rb +138 -0
  23. data/lib/xero_gateway/http_encoding_helper.rb +49 -0
  24. data/lib/xero_gateway/invoice.rb +236 -0
  25. data/lib/xero_gateway/line_item.rb +125 -0
  26. data/lib/xero_gateway/line_item_calculations.rb +55 -0
  27. data/lib/xero_gateway/money.rb +16 -0
  28. data/lib/xero_gateway/oauth.rb +87 -0
  29. data/lib/xero_gateway/organisation.rb +75 -0
  30. data/lib/xero_gateway/partner_app.rb +30 -0
  31. data/lib/xero_gateway/payment.rb +40 -0
  32. data/lib/xero_gateway/phone.rb +77 -0
  33. data/lib/xero_gateway/private_app.rb +17 -0
  34. data/lib/xero_gateway/response.rb +41 -0
  35. data/lib/xero_gateway/tax_rate.rb +63 -0
  36. data/lib/xero_gateway/tracking_category.rb +87 -0
  37. data/test/integration/accounts_list_test.rb +109 -0
  38. data/test/integration/create_bank_transaction_test.rb +38 -0
  39. data/test/integration/create_contact_test.rb +66 -0
  40. data/test/integration/create_credit_note_test.rb +49 -0
  41. data/test/integration/create_invoice_test.rb +49 -0
  42. data/test/integration/get_accounts_test.rb +23 -0
  43. data/test/integration/get_bank_transaction_test.rb +51 -0
  44. data/test/integration/get_bank_transactions_test.rb +88 -0
  45. data/test/integration/get_contact_test.rb +28 -0
  46. data/test/integration/get_contacts_test.rb +40 -0
  47. data/test/integration/get_credit_note_test.rb +48 -0
  48. data/test/integration/get_credit_notes_test.rb +90 -0
  49. data/test/integration/get_currencies_test.rb +25 -0
  50. data/test/integration/get_invoice_test.rb +48 -0
  51. data/test/integration/get_invoices_test.rb +92 -0
  52. data/test/integration/get_organisation_test.rb +24 -0
  53. data/test/integration/get_tax_rates_test.rb +25 -0
  54. data/test/integration/get_tracking_categories_test.rb +27 -0
  55. data/test/integration/update_bank_transaction_test.rb +31 -0
  56. data/test/integration/update_contact_test.rb +31 -0
  57. data/test/integration/update_invoice_test.rb +31 -0
  58. data/test/test_helper.rb +179 -0
  59. data/test/unit/account_test.rb +47 -0
  60. data/test/unit/bank_transaction_test.rb +126 -0
  61. data/test/unit/contact_test.rb +97 -0
  62. data/test/unit/credit_note_test.rb +284 -0
  63. data/test/unit/currency_test.rb +31 -0
  64. data/test/unit/gateway_test.rb +119 -0
  65. data/test/unit/invoice_test.rb +326 -0
  66. data/test/unit/oauth_test.rb +116 -0
  67. data/test/unit/organisation_test.rb +38 -0
  68. data/test/unit/tax_rate_test.rb +38 -0
  69. data/test/unit/tracking_category_test.rb +52 -0
  70. data/xero_gateway.gemspec +15 -0
  71. metadata +164 -0
@@ -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::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,38 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class CreateBankTransactionTest < 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 =~ /BankTransactions$/ }.returns(get_file_as_string("create_bank_transaction.xml"))
13
+ @gateway.stubs(:http_post).with {|client, url, body, params| url =~ /BankTransactions$/ }.returns(get_file_as_string("bank_transaction.xml"))
14
+ end
15
+ end
16
+
17
+ def test_create_bank_transaction
18
+ example_bank_transaction = create_test_bank_transaction.dup
19
+
20
+ result = @gateway.create_bank_transaction(example_bank_transaction)
21
+ assert_kind_of XeroGateway::Response, result
22
+ assert result.success?
23
+ assert !result.request_xml.nil?
24
+ assert !result.response_xml.nil?
25
+ assert !result.bank_transaction.bank_transaction_id.nil?
26
+ assert example_bank_transaction.bank_transaction_id =~ GUID_REGEX
27
+ end
28
+
29
+ def test_create_bank_transaction_valid
30
+ example_bank_transaction = create_test_bank_transaction.dup
31
+ assert_equal true, example_bank_transaction.valid?,
32
+ "bank_transaction is invalid - errors:\n\t#{example_bank_transaction.errors.map { | error | "#{error[0]} #{error[1]}"}.join("\n\t")}"
33
+ end
34
+
35
+ private
36
+
37
+
38
+ 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 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,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