xero 0.0.1.1

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 (61) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +4 -0
  4. data/Guardfile +8 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/lib/active_support/inflection_config.rb +4 -0
  9. data/lib/active_support/inflections.rb +3 -0
  10. data/lib/oauth/consumer.rb +13 -0
  11. data/lib/xero/associations/belongs_to.rb +24 -0
  12. data/lib/xero/associations/has_many.rb +40 -0
  13. data/lib/xero/associations/has_many_proxy.rb +20 -0
  14. data/lib/xero/associations/has_one.rb +25 -0
  15. data/lib/xero/associations.rb +11 -0
  16. data/lib/xero/client.rb +83 -0
  17. data/lib/xero/clients/partner_application.rb +6 -0
  18. data/lib/xero/clients/private_application.rb +12 -0
  19. data/lib/xero/configuration.rb +14 -0
  20. data/lib/xero/connection.rb +62 -0
  21. data/lib/xero/models/account.rb +66 -0
  22. data/lib/xero/models/address.rb +28 -0
  23. data/lib/xero/models/base_model.rb +52 -0
  24. data/lib/xero/models/contact.rb +27 -0
  25. data/lib/xero/models/invoice.rb +37 -0
  26. data/lib/xero/models/item.rb +26 -0
  27. data/lib/xero/models/item_detail.rb +14 -0
  28. data/lib/xero/models/line_item.rb +16 -0
  29. data/lib/xero/models/payment.rb +21 -0
  30. data/lib/xero/models/phone.rb +18 -0
  31. data/lib/xero/models/tracking_category.rb +12 -0
  32. data/lib/xero/models/tracking_category_option.rb +12 -0
  33. data/lib/xero/version.rb +3 -0
  34. data/lib/xero.rb +39 -0
  35. data/spec/lib/xero/client_spec.rb +4 -0
  36. data/spec/lib/xero/clients/private_application_spec.rb +216 -0
  37. data/spec/lib/xero/models/account_spec.rb +38 -0
  38. data/spec/lib/xero/models/address_spec.rb +21 -0
  39. data/spec/lib/xero/models/base_model_spec.rb +37 -0
  40. data/spec/lib/xero/models/contact_spec.rb +4 -0
  41. data/spec/lib/xero/models/invoice_spec.rb +6 -0
  42. data/spec/lib/xero/models/item_detail_spec.rb +10 -0
  43. data/spec/lib/xero/models/item_spec.rb +119 -0
  44. data/spec/lib/xero/models/line_item_spec.rb +12 -0
  45. data/spec/lib/xero/models/payment_spec.rb +4 -0
  46. data/spec/lib/xero/models/phone_spec.rb +15 -0
  47. data/spec/lib/xero/models/tracking_category_option_spec.rb +4 -0
  48. data/spec/lib/xero/models/tracking_category_spec.rb +4 -0
  49. data/spec/spec_helper.rb +28 -0
  50. data/spec/support/find_account.xml +13 -0
  51. data/spec/support/helpers.rb +9 -0
  52. data/spec/support/vcr.rb +6 -0
  53. data/spec/vcr_cassettes/contact.yml +66 -0
  54. data/spec/vcr_cassettes/contacts.yml +66 -0
  55. data/spec/vcr_cassettes/create_item.yml +67 -0
  56. data/spec/vcr_cassettes/get_invoice.yml +79 -0
  57. data/spec/vcr_cassettes/get_item.yml +61 -0
  58. data/spec/vcr_cassettes/get_items.yml +67 -0
  59. data/spec/vcr_cassettes/invoices.yml +62 -0
  60. data/xero.gemspec +30 -0
  61. metadata +274 -0
@@ -0,0 +1,14 @@
1
+ module Xero
2
+ module Models
3
+ class ItemDetail < BaseModel
4
+
5
+ attribute :unit_price, type: Float
6
+ attribute :account_code
7
+ attribute :tax_type
8
+
9
+ validates :unit_price, presence: true
10
+ validates :account_code, presence: true
11
+ validates :tax_type, presence: true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ module Xero
2
+ module Models
3
+ class LineItem < Xero::Models::BaseModel
4
+
5
+ attribute :description
6
+ attribute :quantity, type: Float
7
+ attribute :unit_amount, type: Float
8
+ attribute :account_code
9
+
10
+ validates :description, presence: true
11
+ validates :quantity, presence: true
12
+ validates :unit_amount, presence: true
13
+ validates :account_code, presence: true
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module Xero
2
+ module Models
3
+ class Payment < Xero::Models::BaseModel
4
+
5
+ self.path = 'Payments'
6
+
7
+ attribute :date, type: Date
8
+ attribute :currency_rate, type: Float
9
+ attribute :amount, type: Float
10
+ attribute :reference
11
+
12
+ belongs_to :invoice
13
+ belongs_to :account
14
+
15
+ validates :amount, presence: true
16
+ validates :date, presence: true
17
+ validates :invoice, presence: true
18
+ validates :account, presence: true
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module Xero
2
+ module Models
3
+ class Phone < BaseModel
4
+
5
+ attribute :phone_type
6
+ attribute :number
7
+ attribute :area_code
8
+ attribute :country_code
9
+
10
+ validates :phone_type, presence: true
11
+ validates :number, presence: true
12
+ validates :area_code, presence: true
13
+ validates :country_code, presence: true
14
+
15
+ belongs_to :invoice
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ module Xero
2
+ module Models
3
+ class TrackingCategory < Xero::Models::BaseModel
4
+
5
+ self.path = 'TrackingCategories'
6
+
7
+ attribute :name
8
+
9
+ has_many :tracking_category_options
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Xero
2
+ module Models
3
+ class TrackingCategoryOption < Xero::Models::BaseModel
4
+
5
+ attribute :name
6
+
7
+ validates :name, presence: true
8
+
9
+ belongs_to :tracking_category
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Xero
2
+ VERSION = "0.0.1.1"
3
+ end
data/lib/xero.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'active_attr'
2
+ require 'active_support/core_ext'
3
+ require 'active_support/inflection_config'
4
+ require 'oauth'
5
+ require 'xero/associations/belongs_to'
6
+ require 'xero/associations/has_many'
7
+ require 'xero/associations/has_many_proxy'
8
+ require 'xero/associations/has_one'
9
+ require 'xero/associations'
10
+ require 'xero/client'
11
+ require 'xero/clients/partner_application'
12
+ require 'xero/clients/private_application'
13
+ require 'xero/configuration'
14
+ require 'xero/connection'
15
+ require 'xero/models/base_model'
16
+ require 'xero/models/account'
17
+ require 'xero/models/address'
18
+ require 'xero/models/contact'
19
+ require 'xero/models/invoice'
20
+ require 'xero/models/item'
21
+ require 'xero/models/item_detail'
22
+ require 'xero/models/line_item'
23
+ require 'xero/models/payment'
24
+ require 'xero/models/phone'
25
+ require 'xero/models/tracking_category'
26
+ require 'xero/models/tracking_category_option'
27
+ require 'xero/version'
28
+
29
+ module Xero
30
+ class << self
31
+ attr_accessor :configuration
32
+ end
33
+
34
+ def self.configure
35
+ self.configuration = Xero::Configuration.new
36
+ yield(configuration)
37
+ return self.configuration
38
+ end
39
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Client do
4
+ end
@@ -0,0 +1,216 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Clients::PrivateApplication do
4
+
5
+ let(:client) { Xero::Clients::PrivateApplication.new }
6
+
7
+ describe '#contacts' do
8
+ before { configure }
9
+
10
+ let(:contacts) do
11
+ VCR.use_cassette('contacts') { client.contacts }
12
+ end
13
+
14
+ it 'should return an array' do
15
+ contacts.should be_a(Array)
16
+ end
17
+
18
+ it 'should contain contacts' do
19
+ contacts.first.should be_a(Xero::Models::Contact)
20
+ end
21
+
22
+ it 'should populate the contacts id' do
23
+ contacts.first.id.should_not be_blank
24
+ end
25
+ end
26
+
27
+ describe '#get_contact' do
28
+ before { configure }
29
+
30
+ let(:contacts) do
31
+ VCR.use_cassette('contacts') { client.contacts }
32
+ end
33
+
34
+ let(:contact) do
35
+ VCR.use_cassette('contact') do
36
+ client.get_contact(contacts.first.id)
37
+ end
38
+ end
39
+
40
+ it 'should return a contact' do
41
+ contact.should be_a(Xero::Models::Contact)
42
+ end
43
+
44
+ it 'should populate the contact id' do
45
+ contact.id.should_not be_blank
46
+ end
47
+
48
+ it 'should populate the contact addresses' do
49
+ contact.addresses.first.should be_a(Xero::Models::Address)
50
+ end
51
+ end
52
+
53
+ describe '#get_invoice' do
54
+ before { configure }
55
+
56
+ let(:invoice) do
57
+ VCR.use_cassette('get_invoice') do
58
+ client.get_invoice('7f9e9823-f6d7-4302-90a1-ba59f6884ce9')
59
+ end
60
+ end
61
+
62
+ it 'should return an invoice' do
63
+ invoice.should be_a(Xero::Models::Invoice)
64
+ end
65
+
66
+ it 'should populate the type' do
67
+ invoice.type.should_not be_blank
68
+ end
69
+
70
+ it 'should populate the date' do
71
+ invoice.date.should_not be_blank
72
+ end
73
+
74
+ it 'should populate the due date' do
75
+ invoice.due_date.should_not be_blank
76
+ end
77
+
78
+ it 'should populate the invoice number' do
79
+ invoice.invoice_number.should_not be_blank
80
+ end
81
+
82
+ it 'should populate the total' do
83
+ invoice.total.should_not be_blank
84
+ end
85
+
86
+ it 'should populate the currency code' do
87
+ invoice.currency_code.should_not be_blank
88
+ end
89
+
90
+ it 'should populate the id' do
91
+ invoice.id.should_not be_blank
92
+ end
93
+
94
+ it 'should populate the total tax' do
95
+ invoice.total_tax.should_not be_blank
96
+ end
97
+
98
+ it 'should populate the invoice status' do
99
+ invoice.status.should eql('AUTHORISED')
100
+ end
101
+
102
+ it 'should populate the invoice contact' do
103
+ invoice.contact.should be_a(Xero::Models::Contact)
104
+ end
105
+
106
+ it 'should populate the contact data' do
107
+ invoice.contact.id.should_not be_blank
108
+ end
109
+ end
110
+
111
+ describe '#invoices' do
112
+ before { configure }
113
+
114
+ let(:invoices) do
115
+ VCR.use_cassette('invoices') { client.invoices }
116
+ end
117
+
118
+ it 'should return an array' do
119
+ invoices.should be_a(Array)
120
+ end
121
+
122
+ it 'should contain invoices' do
123
+ invoices.first.should be_a(Xero::Models::Invoice)
124
+ end
125
+
126
+ it 'should populate the invoice data' do
127
+ invoices.first.id.should_not be_blank
128
+ end
129
+ end
130
+
131
+ describe '#save' do
132
+ before { configure }
133
+
134
+ let(:item) do
135
+ Xero::Models::Item.new code: 'test-product',
136
+ description: 'just testing',
137
+ purchase_details: purchase_detail_attributes,
138
+ sales_details: sales_detail_attributes
139
+ end
140
+
141
+ let(:purchase_detail_attributes) do
142
+ { unit_price: 100, account_code: '620', tax_type: 'NONE' }
143
+ end
144
+
145
+ let(:sales_detail_attributes) do
146
+ { unit_price: 550, account_code: '200', tax_type: 'NONE' }
147
+ end
148
+
149
+ before do
150
+ VCR.use_cassette('create_item') { client.save(item) }
151
+ end
152
+
153
+ it 'should populate the item id' do
154
+ item.id.should_not be_blank
155
+ end
156
+
157
+ it 'should be persisted' do
158
+ item.should be_persisted
159
+ end
160
+ end
161
+
162
+ describe '#get_item' do
163
+
164
+ before { configure }
165
+
166
+ let(:item) do
167
+ client.get_item '99213658-83c4-438a-b104-1172b1e69790'
168
+ end
169
+
170
+ it 'should return an item' do
171
+ VCR.use_cassette('get_item') do
172
+ item.should be_a(Xero::Models::Item)
173
+ end
174
+ end
175
+ end
176
+
177
+ describe '#items' do
178
+ before { configure }
179
+
180
+ let(:items) do
181
+ VCR.use_cassette('get_items') { client.items }
182
+ end
183
+
184
+ it 'should return an array' do
185
+ items.should be_a(Array)
186
+ end
187
+
188
+ it 'should contain items' do
189
+ items.first.should be_a(Xero::Models::Item)
190
+ end
191
+
192
+ it 'should populate the id' do
193
+ items.first.id.should_not be_blank
194
+ end
195
+
196
+ it 'should populate the item code' do
197
+ items.first.code.should_not be_blank
198
+ end
199
+
200
+ it 'should populate the item description' do
201
+ items.first.description.should_not be_blank
202
+ end
203
+
204
+ it 'should populate the item purchase detail' do
205
+ items.first.purchase_details.should be_a(Xero::Models::ItemDetail)
206
+ end
207
+
208
+ it 'should populate the item sales detail' do
209
+ items.first.sales_details.should be_a(Xero::Models::ItemDetail)
210
+ end
211
+
212
+ it 'should populate the item purchase detail account code' do
213
+ items.first.purchase_details.account_code.should_not be_blank
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::Account do
4
+
5
+ # describe '.from_xml' do
6
+ # let(:account) do
7
+ # Xero::Models::Account.from_xml(File.read('spec/support/find_account.xml'))
8
+ # end
9
+
10
+ # it 'should populate the account id' do
11
+ # account.id.should eql('297c2dc5-cc47-4afd-8ec8-74990b8761e9')
12
+ # end
13
+
14
+ # it 'should populate the name' do
15
+ # account.name.should eql('BNZ Cheque Account')
16
+ # end
17
+
18
+ # it 'should populate the account type' do
19
+ # account.account_type.should eql('BANK')
20
+ # end
21
+
22
+ # it 'should populate the tax type' do
23
+ # account.tax_type.should eql('NONE')
24
+ # end
25
+
26
+ # it 'should populate enable payments to account' do
27
+ # account.enable_payments_to_account.should eql(false)
28
+ # end
29
+
30
+ # it 'should populate bank account number' do
31
+ # account.bank_account_number.should eql('3809087654321500')
32
+ # end
33
+
34
+ # it 'should populate the currency code' do
35
+ # account.currency_code.should eql('NZD')
36
+ # end
37
+ # end
38
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::Address do
4
+
5
+ describe 'validations' do
6
+
7
+ it { should validate_presence_of(:address_type) }
8
+
9
+ it { should validate_presence_of(:attention_to) }
10
+
11
+ it { should validate_presence_of(:address_line1) }
12
+
13
+ it { should validate_presence_of(:city) }
14
+
15
+ it { should validate_presence_of(:region) }
16
+
17
+ it { should validate_presence_of(:postal_code) }
18
+
19
+ it { should validate_presence_of(:country) }
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::BaseModel do
4
+
5
+ describe '#initialize' do
6
+ let(:model) { Xero::Models::BaseModel.new }
7
+
8
+ it 'should set new_record to true' do
9
+ model.new_record.should be_true
10
+ end
11
+ end
12
+
13
+ describe '#save' do
14
+ context 'when client is blank' do
15
+ let(:model) { Xero::Models::BaseModel.new }
16
+
17
+ it 'should raise an error' do
18
+ expect { model.save }.to raise_error
19
+ end
20
+ end
21
+ end
22
+
23
+ describe '#xero_attributes' do
24
+ let(:model) do
25
+ Xero::Models::BaseModel.new id: 'asdf'
26
+ end
27
+
28
+
29
+ it 'should not include the id' do
30
+ model.xero_attributes['BaseModelId'].should be_blank
31
+ end
32
+
33
+ it 'should camelize the attributes' do
34
+ model.xero_attributes(x_attr: 'something')['XAttr'].should eql('something')
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::Contact do
4
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::Invoice do
4
+
5
+ it { should validate_presence_of(:type) }
6
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::ItemDetail do
4
+
5
+ it { should validate_presence_of(:unit_price) }
6
+
7
+ it { should validate_presence_of(:account_code) }
8
+
9
+ it { should validate_presence_of(:tax_type) }
10
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::Item do
4
+
5
+ describe 'validations' do
6
+ it { should validate_presence_of(:code) }
7
+ end
8
+
9
+ describe 'to_xero_xml' do
10
+ let(:item) do
11
+ Xero::Models::Item.new(
12
+ purchase_details: purchase_detail_attributes,
13
+ sales_details: sales_detail_attributes,
14
+ id: '34b3fc86-483e-4112-8106-9b23d36f925c',
15
+ code: 'Monster',
16
+ description: 'Test description'
17
+ )
18
+ end
19
+
20
+ let(:purchase_detail_attributes) do
21
+ { unit_price: 100, account_code: '620', tax_type: 'NONE' }
22
+ end
23
+
24
+ let(:sales_detail_attributes) do
25
+ { unit_price: 550, account_code: '200', tax_type: 'NONE' }
26
+ end
27
+
28
+ subject { item.to_xero_xml }
29
+
30
+ it 'should include the purchase detail' do
31
+ subject.should match(/PurchaseDetails/)
32
+ end
33
+
34
+ it 'should include the sales detail' do
35
+ subject.should match(/SalesDetails/)
36
+ end
37
+
38
+ it 'should not include the id' do
39
+ subject.should_not match(/ItemId/)
40
+ end
41
+
42
+ it 'should not include the id value' do
43
+ subject.should_not match(/34b3fc86\-483e\-4112\-8106\-9b23d36f925c/)
44
+ end
45
+
46
+ it 'should include the code' do
47
+ subject.should match(/Code/)
48
+ end
49
+
50
+ it 'should include the code value' do
51
+ subject.should match(/Monster/)
52
+ end
53
+
54
+ it 'should include the unit price' do
55
+ subject.should match(/UnitPrice/)
56
+ end
57
+
58
+ it 'should include the description' do
59
+ subject.should match(/Description/)
60
+ end
61
+
62
+ it 'should include the description value' do
63
+ subject.should match(/Test description/)
64
+ end
65
+ end
66
+
67
+ describe '#purchase_details=' do
68
+
69
+ let(:item) { Xero::Models::Item.new }
70
+
71
+ before do
72
+ item.purchase_details = {
73
+ unit_price: 100, account_code: '620', tax_type: 'NONE'
74
+ }
75
+ end
76
+
77
+ it 'should add a new item detail to the item' do
78
+ item.purchase_details.should be_a(Xero::Models::ItemDetail)
79
+ end
80
+
81
+ it 'should set the unit price' do
82
+ item.purchase_details.unit_price.should eql(100.0)
83
+ end
84
+
85
+ it 'should set the account code' do
86
+ item.purchase_details.account_code.should eql('620')
87
+ end
88
+
89
+ it 'should set the tax type' do
90
+ item.purchase_details.tax_type.should eql('NONE')
91
+ end
92
+ end
93
+
94
+ describe '#sales_details=' do
95
+ let(:item) { Xero::Models::Item.new }
96
+
97
+ before do
98
+ item.sales_details = {
99
+ unit_price: 550, account_code: '200', tax_type: 'NONE'
100
+ }
101
+ end
102
+
103
+ it 'should add a new item detail to the item' do
104
+ item.sales_details.should be_a(Xero::Models::ItemDetail)
105
+ end
106
+
107
+ it 'should set the unit price' do
108
+ item.sales_details.unit_price.should eql(550.0)
109
+ end
110
+
111
+ it 'should set the account code' do
112
+ item.sales_details.account_code.should eql('200')
113
+ end
114
+
115
+ it 'should set the tax type' do
116
+ item.sales_details.tax_type.should eql('NONE')
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::LineItem do
4
+
5
+ it { should validate_presence_of(:description) }
6
+
7
+ it { should validate_presence_of(:quantity) }
8
+
9
+ it { should validate_presence_of(:unit_amount) }
10
+
11
+ it { should validate_presence_of(:account_code) }
12
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::Payment do
4
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::Phone do
4
+
5
+ describe 'validations' do
6
+
7
+ it { should validate_presence_of(:phone_type) }
8
+
9
+ it { should validate_presence_of(:number) }
10
+
11
+ it { should validate_presence_of(:area_code) }
12
+
13
+ it { should validate_presence_of(:country_code) }
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::TrackingCategoryOption do
4
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xero::Models::TrackingCategory do
4
+ end
@@ -0,0 +1,28 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require 'active_attr/rspec'
9
+ require 'bundler/setup'
10
+ require 'xero'
11
+ require 'rubygems'
12
+ require 'shoulda-matchers'
13
+ require 'support/helpers'
14
+ require 'support/vcr'
15
+
16
+ RSpec.configure do |config|
17
+ config.treat_symbols_as_metadata_keys_with_true_values = true
18
+ config.run_all_when_everything_filtered = true
19
+ config.filter_run :focus
20
+
21
+ # Run specs in random order to surface order dependencies. If you find an
22
+ # order dependency and want to debug it, you can fix the order by providing
23
+ # the seed, which is printed after each run.
24
+ # --seed 1234
25
+ config.order = 'random'
26
+
27
+ config.include Helpers
28
+ end