xero 0.0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/active_support/inflection_config.rb +4 -0
- data/lib/active_support/inflections.rb +3 -0
- data/lib/oauth/consumer.rb +13 -0
- data/lib/xero/associations/belongs_to.rb +24 -0
- data/lib/xero/associations/has_many.rb +40 -0
- data/lib/xero/associations/has_many_proxy.rb +20 -0
- data/lib/xero/associations/has_one.rb +25 -0
- data/lib/xero/associations.rb +11 -0
- data/lib/xero/client.rb +83 -0
- data/lib/xero/clients/partner_application.rb +6 -0
- data/lib/xero/clients/private_application.rb +12 -0
- data/lib/xero/configuration.rb +14 -0
- data/lib/xero/connection.rb +62 -0
- data/lib/xero/models/account.rb +66 -0
- data/lib/xero/models/address.rb +28 -0
- data/lib/xero/models/base_model.rb +52 -0
- data/lib/xero/models/contact.rb +27 -0
- data/lib/xero/models/invoice.rb +37 -0
- data/lib/xero/models/item.rb +26 -0
- data/lib/xero/models/item_detail.rb +14 -0
- data/lib/xero/models/line_item.rb +16 -0
- data/lib/xero/models/payment.rb +21 -0
- data/lib/xero/models/phone.rb +18 -0
- data/lib/xero/models/tracking_category.rb +12 -0
- data/lib/xero/models/tracking_category_option.rb +12 -0
- data/lib/xero/version.rb +3 -0
- data/lib/xero.rb +39 -0
- data/spec/lib/xero/client_spec.rb +4 -0
- data/spec/lib/xero/clients/private_application_spec.rb +216 -0
- data/spec/lib/xero/models/account_spec.rb +38 -0
- data/spec/lib/xero/models/address_spec.rb +21 -0
- data/spec/lib/xero/models/base_model_spec.rb +37 -0
- data/spec/lib/xero/models/contact_spec.rb +4 -0
- data/spec/lib/xero/models/invoice_spec.rb +6 -0
- data/spec/lib/xero/models/item_detail_spec.rb +10 -0
- data/spec/lib/xero/models/item_spec.rb +119 -0
- data/spec/lib/xero/models/line_item_spec.rb +12 -0
- data/spec/lib/xero/models/payment_spec.rb +4 -0
- data/spec/lib/xero/models/phone_spec.rb +15 -0
- data/spec/lib/xero/models/tracking_category_option_spec.rb +4 -0
- data/spec/lib/xero/models/tracking_category_spec.rb +4 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/find_account.xml +13 -0
- data/spec/support/helpers.rb +9 -0
- data/spec/support/vcr.rb +6 -0
- data/spec/vcr_cassettes/contact.yml +66 -0
- data/spec/vcr_cassettes/contacts.yml +66 -0
- data/spec/vcr_cassettes/create_item.yml +67 -0
- data/spec/vcr_cassettes/get_invoice.yml +79 -0
- data/spec/vcr_cassettes/get_item.yml +61 -0
- data/spec/vcr_cassettes/get_items.yml +67 -0
- data/spec/vcr_cassettes/invoices.yml +62 -0
- data/xero.gemspec +30 -0
- metadata +274 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Matt Beedle
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Xero
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'xero'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install xero
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module OAuth
|
2
|
+
class Consumer
|
3
|
+
|
4
|
+
def http_with_ssl_client_certificates(*args)
|
5
|
+
@http ||= http_without_ssl_client_certificates(*args).tap do |http|
|
6
|
+
http.cert = options[:ssl_client_cert]
|
7
|
+
http.key = options[:ssl_client_key]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
alias_method_chain :http, :ssl_client_certificates
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Xero
|
2
|
+
module Associations
|
3
|
+
module BelongsTo
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
def belongs_to(association_name, options = {})
|
9
|
+
|
10
|
+
attr_accessor :"#{association_name}_id"
|
11
|
+
|
12
|
+
define_method association_name do
|
13
|
+
instance_variable_get(:"#{association_name}")
|
14
|
+
end
|
15
|
+
|
16
|
+
define_method "#{association_name}=" do |value|
|
17
|
+
instance_variable_set(:"@#{association_name}", value)
|
18
|
+
send "#{association_name}_id", value.id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Xero
|
2
|
+
module Associations
|
3
|
+
module HasMany
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def has_many(association_name, options = {})
|
8
|
+
|
9
|
+
define_method association_name do
|
10
|
+
var = instance_variable_get(:"@#{association_name}")
|
11
|
+
if var.blank?
|
12
|
+
var = HasManyProxy.new
|
13
|
+
instance_variable_set(:"@#{association_name}", var)
|
14
|
+
end
|
15
|
+
var
|
16
|
+
end
|
17
|
+
|
18
|
+
define_method "#{association_name}=" do |value|
|
19
|
+
if value.is_a?(Hash) && value[value.keys.first].is_a?(Array)
|
20
|
+
klass = options[:class_name] || association_name.to_s.singularize
|
21
|
+
klass = "Xero::Models::#{klass.to_s.classify}".constantize
|
22
|
+
value[value.keys.first].each do |item|
|
23
|
+
self.send(association_name).send :<<, klass.new(item)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# if value.is_a?(Hash)
|
28
|
+
# klass = options[:class_name] || association_name.to_s.singularize
|
29
|
+
# value = "Xero::Models::#{klass.to_s.classify}".constantize.
|
30
|
+
# new(value)
|
31
|
+
# end
|
32
|
+
# instance_variable_set(
|
33
|
+
# :"@#{association_name}", HasManyProxy.new(value)
|
34
|
+
# )
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Xero
|
2
|
+
module Associations
|
3
|
+
class HasManyProxy < BasicObject
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
@target = ::Array.new(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def target
|
12
|
+
@target
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(method, *args, &block)
|
16
|
+
target.send method, *args, &block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Xero
|
2
|
+
module Associations
|
3
|
+
module HasOne
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def has_one(association_name, options = {})
|
8
|
+
|
9
|
+
define_method association_name do
|
10
|
+
instance_variable_get(:"@#{association_name}")
|
11
|
+
end
|
12
|
+
|
13
|
+
define_method "#{association_name}=" do |value|
|
14
|
+
if value.is_a?(Hash)
|
15
|
+
klass = options[:class_name] || association_name
|
16
|
+
value = "Xero::Models::#{klass.to_s.classify}".constantize.
|
17
|
+
new(value)
|
18
|
+
end
|
19
|
+
instance_variable_set(:"@#{association_name}", value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/xero/client.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Xero
|
2
|
+
class Client
|
3
|
+
attr_accessor :client
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
self.client = OAuth::Consumer.new(
|
7
|
+
Xero.configuration.consumer_key,
|
8
|
+
Xero.configuration.consumer_secret, options
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def contacts(options = {})
|
13
|
+
response = self.connection.get(Xero::Models::Contact.path, options)
|
14
|
+
contacts_attributes = hash_from_response(response, 'Contacts')
|
15
|
+
unless contacts_attributes.is_a?(Array)
|
16
|
+
contacts_attributes = [contacts_attributes]
|
17
|
+
end
|
18
|
+
contacts_attributes.map { |attrs| Xero::Models::Contact.new(attrs) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_contact(contact_id)
|
22
|
+
response = self.connection.
|
23
|
+
get_by_id(Xero::Models::Contact.path, contact_id)
|
24
|
+
Xero::Models::Contact.new hash_from_response(response, 'Contacts')
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_item(item_id)
|
28
|
+
response = self.connection.get_by_id(Xero::Models::Item.path, item_id)
|
29
|
+
Xero::Models::Item.new(hash_from_response(response, 'Items'))
|
30
|
+
end
|
31
|
+
|
32
|
+
def items(options = {})
|
33
|
+
response = self.connection.get(Xero::Models::Item.path, options)
|
34
|
+
items = hash_from_response(response, 'Items')
|
35
|
+
items.map { |item| Xero::Models::Item.new(item) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_invoice(invoice_id)
|
39
|
+
response = self.connection.
|
40
|
+
get_by_id(Xero::Models::Invoice.path, invoice_id)
|
41
|
+
Xero::Models::Invoice.new hash_from_response(response, 'Invoices')
|
42
|
+
end
|
43
|
+
|
44
|
+
def invoices(options = {})
|
45
|
+
response = self.connection.get(Xero::Models::Invoice.path, options)
|
46
|
+
invoices_attributes = hash_from_response(response, 'Invoices')
|
47
|
+
unless invoices_attributes.is_a?(Array)
|
48
|
+
invoices_attributes = [invoices_attributes]
|
49
|
+
end
|
50
|
+
invoices_attributes.map { |attrs| Xero::Models::Invoice.new(attrs) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def save(model)
|
54
|
+
model.tap do |item|
|
55
|
+
response = self.connection.post(model.class.path, model.to_xero_xml)
|
56
|
+
attrs = Hash.from_xml(response.body)['Response']['Items']['Item']
|
57
|
+
model.id = attrs["#{model.class.to_s.demodulize}ID"]
|
58
|
+
model.new_record = false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_item(attributes = {})
|
63
|
+
build_model Xero::Models::Item, attributes
|
64
|
+
end
|
65
|
+
|
66
|
+
def build_model(klass, item_attributes = {})
|
67
|
+
klass.new(item_attributes).tap do |item|
|
68
|
+
item.client = self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
protected
|
73
|
+
|
74
|
+
def connection
|
75
|
+
@connection ||= Xero::Connection.new
|
76
|
+
end
|
77
|
+
|
78
|
+
def hash_from_response(response, klass_name)
|
79
|
+
attributes = Hash.from_xml(response.body)['Response']
|
80
|
+
attributes[klass_name][klass_name.singularize]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Xero
|
2
|
+
class Connection
|
3
|
+
|
4
|
+
attr_accessor :client, :consumer_options
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
self.consumer_options = {
|
8
|
+
site: 'https://api.xero.com',
|
9
|
+
request_token_path: '/oauth/RequestToken',
|
10
|
+
access_token_path: '/oauth/AccessToken',
|
11
|
+
authorize_path: '/oauth/Authorize'
|
12
|
+
}.reverse_merge(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def consumer
|
16
|
+
@consumer ||= ::OAuth::Consumer.new(
|
17
|
+
Xero.configuration.consumer_key,
|
18
|
+
Xero.configuration.consumer_secret,
|
19
|
+
self.consumer_options
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def access_token
|
24
|
+
@access_token ||= ::OAuth::AccessToken.new(
|
25
|
+
consumer, Xero.configuration.consumer_key,
|
26
|
+
Xero.configuration.consumer_secret
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_by_id(path, id)
|
31
|
+
make_request(:get, "#{path}/#{id}")
|
32
|
+
end
|
33
|
+
|
34
|
+
def get(path, params = {})
|
35
|
+
path = "#{path}?#{params.to_query}" unless params.blank?
|
36
|
+
make_request(:get, path)
|
37
|
+
end
|
38
|
+
|
39
|
+
def post(path, payload, params = {})
|
40
|
+
make_request(:post, path, { xml: payload })
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def make_request(method, path, params = {})
|
46
|
+
uri = "#{Xero.configuration.xero_url}/#{path}"
|
47
|
+
|
48
|
+
headers = { 'charset' => 'utf-8' }
|
49
|
+
|
50
|
+
if method == :get
|
51
|
+
response = access_token.get(uri, params)
|
52
|
+
else
|
53
|
+
response = access_token.post(uri, params, headers)
|
54
|
+
end
|
55
|
+
handle_response(response)
|
56
|
+
end
|
57
|
+
|
58
|
+
def handle_response(response)
|
59
|
+
response
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Xero
|
2
|
+
module Models
|
3
|
+
|
4
|
+
class Account < BaseModel
|
5
|
+
|
6
|
+
self.path = 'Accounts'
|
7
|
+
|
8
|
+
TYPE = {
|
9
|
+
'CURRENT' => '',
|
10
|
+
'FIXED' => '',
|
11
|
+
'PREPAYMENT' => '',
|
12
|
+
'EQUITY' => '',
|
13
|
+
'DEPRECIATN' => '',
|
14
|
+
'DIRECTCOSTS' => '',
|
15
|
+
'EXPENSE' => '',
|
16
|
+
'OVERHEADS' => '',
|
17
|
+
'CURRLIAB' => '',
|
18
|
+
'LIABILITY' => '',
|
19
|
+
'TERMLIAB' => '',
|
20
|
+
'OTHERINCOME' => '',
|
21
|
+
'REVENUE' => '',
|
22
|
+
'SALES' => ''
|
23
|
+
} unless defined?(TYPE)
|
24
|
+
|
25
|
+
TAX_TYPE = {
|
26
|
+
'NONE' => 'No GST',
|
27
|
+
'EXEMPTINPUT' => 'VAT on expenses exempt from VAT (UK only)',
|
28
|
+
'INPUT' => 'GST on expenses',
|
29
|
+
'SRINPUT' => 'VAT on expenses',
|
30
|
+
'ZERORATEDINPUT' => 'Expense purchased from overseas (UK only)',
|
31
|
+
'RRINPUT' => 'Reduced rate VAT on expenses (UK Only)',
|
32
|
+
'EXEMPTOUTPUT' => 'VAT on sales exempt from VAT (UK only)',
|
33
|
+
'ECZROUTPUT' => 'EC Zero-rated output',
|
34
|
+
'OUTPUT' => 'OUTPUT (old rate)',
|
35
|
+
'OUTPUT2' => 'OUTPUT2',
|
36
|
+
'SROUTPUT' => 'SROUTPUT',
|
37
|
+
'ZERORATEDOUTPUT' => 'Sales made from overseas (UK only)',
|
38
|
+
'RROUTPUT' => 'Reduced rate VAT on sales (UK Only)',
|
39
|
+
'ZERORATED' => 'Zero-rated supplies/sales from overseas (NZ Only)'
|
40
|
+
} unless defined?(TAX_TYPE)
|
41
|
+
|
42
|
+
attribute :id
|
43
|
+
attribute :code
|
44
|
+
attribute :name
|
45
|
+
attribute :account_type
|
46
|
+
attribute :tax_type
|
47
|
+
attribute :description
|
48
|
+
attribute :system_account
|
49
|
+
attribute :enable_payments_to_account, type: Boolean
|
50
|
+
attribute :bank_account_number
|
51
|
+
attribute :currency_code
|
52
|
+
|
53
|
+
# def self.from_xml(xml)
|
54
|
+
# attrs = Hash.from_xml(xml)['Accounts']['Account']
|
55
|
+
|
56
|
+
# attrs['id'] = attrs.delete('AccountID')
|
57
|
+
# attrs['account_type'] = attrs.delete('Type')
|
58
|
+
# attrs.keys.each do |key|
|
59
|
+
# attrs[key.tableize.singularize] = attrs.delete(key)
|
60
|
+
# end
|
61
|
+
|
62
|
+
# self.new(attrs)
|
63
|
+
# end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Xero
|
2
|
+
module Models
|
3
|
+
class Address < BaseModel
|
4
|
+
|
5
|
+
attribute :address_type
|
6
|
+
attribute :attention_to
|
7
|
+
attribute :address_line1
|
8
|
+
attribute :address_line2
|
9
|
+
attribute :address_line3
|
10
|
+
attribute :address_line4
|
11
|
+
attribute :city
|
12
|
+
attribute :region
|
13
|
+
attribute :postal_code
|
14
|
+
attribute :country
|
15
|
+
|
16
|
+
validates :address_type, presence: true
|
17
|
+
validates :attention_to, presence: true
|
18
|
+
validates :address_line1, presence: true
|
19
|
+
validates :city, presence: true
|
20
|
+
validates :region, presence: true
|
21
|
+
validates :postal_code, presence: true
|
22
|
+
validates :country, presence: true
|
23
|
+
|
24
|
+
belongs_to :contact
|
25
|
+
belongs_to :phone
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Xero
|
2
|
+
module Models
|
3
|
+
class BaseModel
|
4
|
+
include ActiveAttr::Model
|
5
|
+
include Xero::Associations
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :path
|
9
|
+
end
|
10
|
+
|
11
|
+
attribute :id
|
12
|
+
|
13
|
+
attr_accessor :new_record, :client
|
14
|
+
|
15
|
+
def initialize(attributes = {})
|
16
|
+
@new_record = true
|
17
|
+
cleanup_hash(attributes).each { |key, value| send("#{key}=", value) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def save
|
21
|
+
raise StandardError if self.client.blank?
|
22
|
+
self.client.save(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def xero_attributes(attrs = nil)
|
26
|
+
attrs ||= attributes.clone
|
27
|
+
attrs.delete('id')
|
28
|
+
attrs.keys.each do |key|
|
29
|
+
value = attrs.delete(key)
|
30
|
+
value = xero_attributes(value) if value.is_a?(Hash)
|
31
|
+
attrs[key.to_s.camelize] = value.to_s
|
32
|
+
end
|
33
|
+
attrs
|
34
|
+
end
|
35
|
+
|
36
|
+
def cleanup_hash(hash)
|
37
|
+
hash.keys.each do |key|
|
38
|
+
value = hash.delete(key)
|
39
|
+
value = cleanup_hash(value) if value.is_a?(Hash)
|
40
|
+
key = key.to_s.underscore
|
41
|
+
key = 'id' if key.match(/_id/)
|
42
|
+
hash[key] = value
|
43
|
+
end
|
44
|
+
hash
|
45
|
+
end
|
46
|
+
|
47
|
+
def persisted?
|
48
|
+
id && !@new_record
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Xero
|
2
|
+
module Models
|
3
|
+
class Contact < Xero::Models::BaseModel
|
4
|
+
|
5
|
+
self.path = 'Contacts'
|
6
|
+
|
7
|
+
attribute :contact_number
|
8
|
+
attribute :name
|
9
|
+
attribute :first_name
|
10
|
+
attribute :last_name
|
11
|
+
attribute :contact_status
|
12
|
+
attribute :skype_user_name
|
13
|
+
attribute :bank_account_details
|
14
|
+
attribute :tax_number
|
15
|
+
attribute :accounts_receivable_tax_type
|
16
|
+
attribute :accounts_payable_tax_type
|
17
|
+
attribute :updated_date_utc, type: DateTime
|
18
|
+
attribute :is_supplier, type: Boolean
|
19
|
+
attribute :is_customer, type: Boolean
|
20
|
+
attribute :default_currency
|
21
|
+
attribute :email_address
|
22
|
+
|
23
|
+
has_many :addresses
|
24
|
+
has_many :phones
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Xero
|
2
|
+
module Models
|
3
|
+
class Invoice < Xero::Models::BaseModel
|
4
|
+
|
5
|
+
self.path = 'Invoices'
|
6
|
+
|
7
|
+
attribute :type
|
8
|
+
attribute :date, type: Date
|
9
|
+
attribute :due_date, type: Date
|
10
|
+
attribute :line_amount_type
|
11
|
+
attribute :invoice_number
|
12
|
+
attribute :reference
|
13
|
+
attribute :url
|
14
|
+
attribute :currency_code
|
15
|
+
attribute :status
|
16
|
+
attribute :line_amount_types
|
17
|
+
attribute :subtotal, type: Float
|
18
|
+
attribute :total_tax, type: Float
|
19
|
+
attribute :total, type: Float
|
20
|
+
attribute :amount_due, type: Float
|
21
|
+
attribute :amount_paid, type: Float
|
22
|
+
attribute :amount_credited, type: Float
|
23
|
+
attribute :total_discount, type: Float
|
24
|
+
attribute :sub_total
|
25
|
+
attribute :updated_date_utc, type: DateTime
|
26
|
+
attribute :has_attachments, type: Boolean
|
27
|
+
attribute :sent_to_contact, type: Boolean
|
28
|
+
attribute :currency_rate
|
29
|
+
|
30
|
+
has_one :contact
|
31
|
+
has_many :line_items
|
32
|
+
has_many :payments
|
33
|
+
|
34
|
+
validates :type, presence: true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Xero
|
2
|
+
module Models
|
3
|
+
class Item < BaseModel
|
4
|
+
|
5
|
+
self.path = 'Items'
|
6
|
+
|
7
|
+
attribute :code
|
8
|
+
attribute :description
|
9
|
+
attribute :updated_date_utc, type: DateTime
|
10
|
+
|
11
|
+
validates :code, presence: true
|
12
|
+
validates :purchase_details, presence: true
|
13
|
+
validates :sales_details, presence: true
|
14
|
+
|
15
|
+
has_one :purchase_details, class_name: :item_detail
|
16
|
+
has_one :sales_details, class_name: :item_detail
|
17
|
+
|
18
|
+
def to_xero_xml
|
19
|
+
xero_attributes(attributes.clone).
|
20
|
+
merge('PurchaseDetails' => self.purchase_details.xero_attributes).
|
21
|
+
merge('SalesDetails' => self.sales_details.xero_attributes).
|
22
|
+
to_xml(root: 'Item')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|