xero_gateway 2.1.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -11
  3. data/README.md +212 -0
  4. data/Rakefile +0 -1
  5. data/lib/oauth/oauth_consumer.rb +25 -9
  6. data/lib/xero_gateway.rb +5 -1
  7. data/lib/xero_gateway/address.rb +29 -27
  8. data/lib/xero_gateway/bank_transaction.rb +11 -3
  9. data/lib/xero_gateway/base_record.rb +97 -0
  10. data/lib/xero_gateway/contact_group.rb +87 -0
  11. data/lib/xero_gateway/currency.rb +8 -54
  12. data/lib/xero_gateway/dates.rb +4 -0
  13. data/lib/xero_gateway/exceptions.rb +14 -13
  14. data/lib/xero_gateway/gateway.rb +90 -5
  15. data/lib/xero_gateway/http.rb +16 -8
  16. data/lib/xero_gateway/invoice.rb +9 -3
  17. data/lib/xero_gateway/item.rb +27 -0
  18. data/lib/xero_gateway/line_item_calculations.rb +3 -3
  19. data/lib/xero_gateway/manual_journal.rb +5 -2
  20. data/lib/xero_gateway/organisation.rb +22 -73
  21. data/lib/xero_gateway/payment.rb +22 -9
  22. data/lib/xero_gateway/phone.rb +2 -0
  23. data/lib/xero_gateway/report.rb +95 -0
  24. data/lib/xero_gateway/response.rb +12 -7
  25. data/lib/xero_gateway/tax_rate.rb +13 -61
  26. data/lib/xero_gateway/tracking_category.rb +39 -13
  27. data/lib/xero_gateway/version.rb +3 -0
  28. data/test/integration/get_items_test.rb +25 -0
  29. data/test/integration/get_payments_test.rb +54 -0
  30. data/test/test_helper.rb +51 -16
  31. data/test/unit/address_test.rb +34 -0
  32. data/test/unit/bank_transaction_test.rb +7 -0
  33. data/test/unit/contact_group_test.rb +47 -0
  34. data/test/unit/contact_test.rb +35 -16
  35. data/test/unit/credit_note_test.rb +2 -2
  36. data/test/unit/gateway_test.rb +170 -1
  37. data/test/unit/invoice_test.rb +27 -7
  38. data/test/unit/item_test.rb +51 -0
  39. data/test/unit/organisation_test.rb +1 -0
  40. data/test/unit/payment_test.rb +18 -11
  41. data/test/unit/report_test.rb +78 -0
  42. data/xero_gateway.gemspec +29 -13
  43. metadata +176 -89
  44. data/README.textile +0 -357
  45. data/init.rb +0 -1
@@ -1,63 +1,15 @@
1
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
- next if !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
-
2
+ class TaxRate < BaseRecord
3
+ attributes({
4
+ "Name" => :string,
5
+ "TaxType" => :string,
6
+ "CanApplyToAssets" => :boolean,
7
+ "CanApplyToEquity" => :boolean,
8
+ "CanApplyToExpenses" => :boolean,
9
+ "CanApplyToLiabilities" => :boolean,
10
+ "CanApplyToRevenue" => :boolean,
11
+ "DisplayTaxRate" => :float,
12
+ "EffectiveRate" => :float
13
+ })
62
14
  end
63
- end
15
+ end
@@ -18,19 +18,43 @@
18
18
  #
19
19
  module XeroGateway
20
20
  class TrackingCategory
21
- attr_accessor :tracking_category_id, :name, :options
22
-
21
+ attr_accessor :tracking_category_id, :name, :status, :options
22
+ attr_accessor :all_options
23
+
24
+ class Option
25
+ attr_accessor :tracking_option_id, :name, :status
26
+
27
+ def initialize(params = {})
28
+ params.each do |k,v|
29
+ self.send("#{k}=", v)
30
+ end
31
+ end
32
+
33
+ def self.from_xml(option_element)
34
+ option = Option.new
35
+ option_element.children.each do |element|
36
+ case(element.name)
37
+ when "TrackingOptionID" then option.tracking_option_id = element.text
38
+ when "Name" then option.name = element.text
39
+ when "Status" then option.status = element.text
40
+ end
41
+ end
42
+ option
43
+ end
44
+ end
45
+
23
46
  def initialize(params = {})
24
47
  @options = []
48
+ @all_options = []
25
49
  params.each do |k,v|
26
50
  self.send("#{k}=", v)
27
51
  end
28
52
  end
29
-
53
+
30
54
  def option
31
55
  options[0] if options.size == 1
32
56
  end
33
-
57
+
34
58
  def to_xml(b = Builder::XmlMarkup.new)
35
59
  b.TrackingCategory {
36
60
  b.TrackingCategoryID tracking_category_id unless tracking_category_id.nil?
@@ -45,43 +69,45 @@ module XeroGateway
45
69
  else
46
70
  b.Option {
47
71
  b.Name self.options.to_s
48
- }
72
+ }
49
73
  end
50
74
  }
51
75
  }
52
76
  end
53
-
77
+
54
78
  # When a tracking category is serialized as part of an invoice it may only have a single
55
79
  # option, and the Options tag is omitted
56
80
  def to_xml_for_invoice_messages(b = Builder::XmlMarkup.new)
57
81
  b.TrackingCategory {
58
82
  b.TrackingCategoryID self.tracking_category_id unless tracking_category_id.nil?
59
83
  b.Name self.name
60
- b.Option self.options.is_a?(Array) ? self.options.first : self.options.to_s
61
- }
84
+ b.Option self.options.is_a?(Array) ? self.options.first : self.options.to_s
85
+ }
62
86
  end
63
-
87
+
64
88
  def self.from_xml(tracking_category_element)
65
89
  tracking_category = TrackingCategory.new
66
90
  tracking_category_element.children.each do |element|
67
91
  case(element.name)
68
92
  when "TrackingCategoryID" then tracking_category.tracking_category_id = element.text
69
93
  when "Name" then tracking_category.name = element.text
94
+ when "Status" then tracking_category.status = element.text
70
95
  when "Options" then
71
96
  element.children.each do |option_child|
72
97
  tracking_category.options << option_child.children.detect {|c| c.name == "Name"}.text
98
+ tracking_category.all_options << Option.from_xml(option_child)
73
99
  end
74
100
  when "Option" then tracking_category.options << element.text
75
101
  end
76
102
  end
77
- tracking_category
78
- end
79
-
103
+ tracking_category
104
+ end
105
+
80
106
  def ==(other)
81
107
  [:tracking_category_id, :name, :options].each do |field|
82
108
  return false if send(field) != other.send(field)
83
109
  end
84
110
  return true
85
- end
111
+ end
86
112
  end
87
113
  end
@@ -0,0 +1,3 @@
1
+ module XeroGateway
2
+ VERSION = "2.3.0"
3
+ end
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class GetItemsTest < 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 =~ /Items$/ }.returns(get_file_as_string("items.xml"))
13
+ end
14
+ end
15
+
16
+ def test_get_items
17
+ result = @gateway.get_items
18
+ assert result.success?
19
+ assert !result.response_xml.nil?
20
+
21
+ assert result.items.size > 0
22
+ assert_equal XeroGateway::Item, result.items.first.class
23
+ assert_equal "An Untracked Item", result.items.first.name
24
+ end
25
+ end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class GetPaymentsTest < 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 =~ /Payments(\/[0-9a-z\-]+)?$/i }.returns(get_file_as_string("payments.xml"))
13
+ @gateway.stubs(:http_put).with {|client, url, body, params| url =~ /Payments$/ }.returns(get_file_as_string("create_payments.xml"))
14
+ end
15
+ end
16
+
17
+ def test_get_payments
18
+ # Make sure there is a bank transaction in Xero to retrieve
19
+ payment = @gateway.create_payment(create_test_payment).payments
20
+
21
+ result = @gateway.get_payments
22
+ assert result.success?
23
+ assert !result.request_params.nil?
24
+ assert !result.response_xml.nil?
25
+ assert result.payments.collect {|i| i.reference}.include?(payment.first.reference)
26
+ assert result.payments.collect {|i| i.payment_id}.include?(payment.first.payment_id)
27
+ assert_kind_of(XeroGateway::Payment, payment.first)
28
+ end
29
+
30
+ def test_get_payments_modified_since_date
31
+ # Create a test payment
32
+ @gateway.create_payment(create_test_payment)
33
+
34
+ # Check that it is returned
35
+ result = @gateway.get_payments(:modified_since => Date.today - 1)
36
+ assert result.success?
37
+ assert !result.request_params.nil?
38
+ assert !result.response_xml.nil?
39
+ assert result.request_params.keys.include?(:ModifiedAfter) # make sure the flag was sent
40
+ end
41
+
42
+ def test_get_payments_find_by_id
43
+ # Create a test payment
44
+ @gateway.create_payment(create_test_payment)
45
+
46
+ # Check that it is returned
47
+ result = @gateway.get_payments(:payment_id => create_test_payment.payment_id)
48
+ assert result.success?
49
+ assert !result.request_params.nil?
50
+ assert !result.response_xml.nil?
51
+ assert result.request_params.keys.include?(:PaymentID) # make sure the flag was sent
52
+ end
53
+
54
+ end
data/test/test_helper.rb CHANGED
@@ -1,32 +1,32 @@
1
- require "rubygems"
1
+ require 'bundler/setup'
2
2
 
3
3
  require 'test/unit'
4
- require 'mocha'
4
+ require 'mocha/setup'
5
5
  require 'shoulda'
6
6
 
7
7
  require 'libxml'
8
8
 
9
- require File.dirname(__FILE__) + '/../lib/xero_gateway.rb' unless defined?(XeroGateway)
9
+ require File.dirname(__FILE__) + '/../lib/xero_gateway.rb'
10
10
 
11
11
  module TestHelper
12
12
  # The integration tests can be run against the Xero test environment. You mush have a company set up in the test
13
13
  # environment, and you must have set up a customer key for that account.
14
14
  #
15
15
  # You can then run the tests against the test environment using the commands (linux or mac):
16
- # export STUB_XERO_CALLS=false
16
+ # export STUB_XERO_CALLS=false
17
17
  # rake test
18
18
  # (this probably won't work under OAuth?)
19
19
  #
20
-
20
+
21
21
  STUB_XERO_CALLS = ENV["STUB_XERO_CALLS"].nil? ? true : (ENV["STUB_XERO_CALLS"] == "true") unless defined? STUB_XERO_CALLS
22
-
22
+
23
23
  CONSUMER_KEY = ENV["CONSUMER_KEY"] || "fake_key" unless defined?(CONSUMER_KEY)
24
24
  CONSUMER_SECRET = ENV["CONSUMER_SECRET"] || "fake_secret" unless defined?(CONSUMER_SECRET)
25
-
25
+
26
26
  # Helper constant for checking regex
27
27
  GUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ unless defined?(GUID_REGEX)
28
28
 
29
-
29
+
30
30
  def dummy_invoice(with_line_items = true)
31
31
  invoice = XeroGateway::Invoice.new({
32
32
  :invoice_type => "ACCREC",
@@ -50,7 +50,7 @@ module TestHelper
50
50
  end
51
51
  invoice
52
52
  end
53
-
53
+
54
54
  def dummy_credit_note(with_line_items = true)
55
55
  credit_note = XeroGateway::CreditNote.new({
56
56
  :type => "ACCRECCREDIT",
@@ -73,7 +73,7 @@ module TestHelper
73
73
  end
74
74
  credit_note
75
75
  end
76
-
76
+
77
77
  def dummy_contact
78
78
  unique_id = Time.now.to_f
79
79
  contact = XeroGateway::Contact.new(:name => STUB_XERO_CALLS ? "CONTACT NAME" : "THE NAME OF THE CONTACT #{unique_id}")
@@ -90,15 +90,19 @@ module TestHelper
90
90
 
91
91
  contact
92
92
  end
93
-
93
+
94
94
  def get_file_as_string(filename)
95
95
  data = ''
96
- f = File.open(File.dirname(__FILE__) + "/stub_responses/" + filename, "r")
96
+ f = File.open(File.dirname(__FILE__) + "/stub_responses/" + filename, "r")
97
97
  f.each_line do |line|
98
98
  data += line
99
99
  end
100
100
  f.close
101
- return data
101
+ data
102
+ end
103
+
104
+ def get_file(filename)
105
+ data = File.read( File.dirname(__FILE__) + "/stub_responses/" + filename)
102
106
  end
103
107
 
104
108
  def create_test_bank_transaction(params={}, contact_params={}, line_item_params={})
@@ -117,6 +121,37 @@ module TestHelper
117
121
  bank_transaction
118
122
  end
119
123
 
124
+ def create_test_payment(params={}, contact_params={})
125
+ params = {
126
+ :payment_id => 'a99a9aaa-9999-99a9-9aa9-aaaaaa9a9999',
127
+ :payment_type => 'ACCRECPAYMENT',
128
+ :updated_at => Time.now,
129
+ :reference => '12345',
130
+ :account_id => 'o99o9ooo-9999-99o9-9oo9-oooooo9o9999',
131
+ :amount => 1000.0,
132
+ :currency_rate => 1.0,
133
+ :date => Date.today.to_time,
134
+ :invoice_id => 'i99i9iii-9999-99i9-9ii9-iiiiii9i9999',
135
+ :invoice_number => 'INV-0001',
136
+ :reconciled => true,
137
+ }.merge(params)
138
+ XeroGateway::Payment.new(params)
139
+ end
140
+
141
+ def create_test_report_bank_statement(params={}, body_params={})
142
+ params = {
143
+ :report_id => 'BankStatement',
144
+ :report_name => 'BankStatement',
145
+ :report_type => 'BankStatement',
146
+ :report_titles => [],
147
+ :report_date => Date.today,
148
+ :updated_at => Time.now-3.days,
149
+ :column_names => [],
150
+ :body => []
151
+ }.merge(params)
152
+ XeroGateway::Report.new(params)
153
+ end
154
+
120
155
  def add_test_line_items(bank_transaction, line_item_params={})
121
156
  if line_item_params
122
157
  line_item_params = [line_item_params].flatten # always use an array, even if only a single hash passed in
@@ -177,7 +212,7 @@ module TestHelper
177
212
  end
178
213
 
179
214
  def create_test_manual_journal(params={}, journal_line_params={})
180
- params = {
215
+ params = {
181
216
  :date => Date.today,
182
217
  :narration => 'test narration',
183
218
  :status => 'POSTED'
@@ -202,9 +237,9 @@ module TestHelper
202
237
  journal_line_params[1] = {
203
238
  :description => "SECOND LINE",
204
239
  :account_code => "200",
205
- :line_amount => BigDecimal.new("-100"),
240
+ :line_amount => BigDecimal.new("-100"),
206
241
  :tracking => XeroGateway::TrackingCategory.new(:name => "blah2", :options => "hello2")
207
- }.merge(params_line_1)
242
+ }.merge(params_line_1)
208
243
 
209
244
  # Create line_items from line_item_params
210
245
  journal_line_params.each do |journal_line|
@@ -0,0 +1,34 @@
1
+ require File.join(File.dirname(__FILE__), '../test_helper.rb')
2
+
3
+ class AddressTest < Test::Unit::TestCase
4
+
5
+ test "build and parse XML" do
6
+ address = create_test_address
7
+
8
+ # Generate the XML message
9
+ address_xml = address.to_xml
10
+
11
+ # Parse the XML message and retrieve the address element
12
+ address_element = REXML::XPath.first(REXML::Document.new(address_xml), "/Address")
13
+
14
+ # Build a new contact from the XML
15
+ result_address = XeroGateway::Address.from_xml(address_element)
16
+
17
+ # Check the contact details
18
+ assert_equal address, result_address
19
+ end
20
+
21
+ private
22
+
23
+ def create_test_address
24
+ XeroGateway::Address.new(
25
+ line_1: "25 Taranaki St",
26
+ line_2: "Te Aro",
27
+ city: "Wellington",
28
+ post_code: "6011",
29
+ country: "New Zealand",
30
+ attention_to: "Hashigo Zake"
31
+ )
32
+ end
33
+
34
+ end
@@ -97,8 +97,15 @@ class BankTransactionTest < Test::Unit::TestCase
97
97
 
98
98
  assert_xml_field bank_transaction_element, 'Url', :value => 'http://example.com\?with=params&amp;and=more'
99
99
 
100
+ # test total without downloading each line items
101
+ total_elem = REXML::Element.new('Total')
102
+ total_elem.text = '1000'
103
+ bank_transaction_element.add_element(total_elem)
104
+
105
+ XeroGateway::BankTransaction.any_instance.stubs(:line_items_downloaded?).returns(false)
100
106
  parsed_bank_transaction = XeroGateway::BankTransaction.from_xml(bank_transaction_element)
101
107
  assert_equal 'http://example.com?with=params&and=more', parsed_bank_transaction.url
108
+ assert_equal BigDecimal.new('1000'), parsed_bank_transaction.total
102
109
  end
103
110
 
104
111
  should "ignore missing contact" do