xeroizer 0.3.4 → 0.3.5
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.
- data/README.md +5 -5
- data/VERSION +1 -1
- data/lib/xeroizer/models/invoice.rb +11 -5
- data/lib/xeroizer/models/manual_journal.rb +1 -1
- data/lib/xeroizer/models/manual_journal_line.rb +3 -0
- data/lib/xeroizer/partner_application.rb +9 -7
- data/lib/xeroizer/record/base.rb +1 -0
- data/lib/xeroizer/record/record_association_helper.rb +6 -0
- data/lib/xeroizer/record/xml_helper.rb +3 -4
- data/test/stub_responses/invoices.xml +46 -0
- data/test/stub_responses/records/invoice-762aa45d-4632-45b5-8087-b4f47690665e.xml +54 -0
- data/test/unit/models/invoice_test.rb +35 -0
- data/test/unit/record/record_association_test.rb +26 -2
- data/xeroizer.gemspec +3 -2
- metadata +5 -4
data/README.md
CHANGED
@@ -58,12 +58,12 @@ Authentication occcurs in 3 steps:
|
|
58
58
|
|
59
59
|
client = Xeroizer::PublicApplication.new(YOUR_OAUTH_CONSUMER_KEY, YOUR_OAUTH_CONSUMER_SECRET)
|
60
60
|
|
61
|
-
# 1. Get a RequestToken from Xero.
|
61
|
+
# 1. Get a RequestToken from Xero. :oauth_callback is the URL the user will be redirected to
|
62
62
|
# after they have authenticated your application.
|
63
63
|
#
|
64
64
|
# Note: The callback URL's domain must match that listed for your application in http://api.xero.com
|
65
65
|
# otherwise the user will not be redirected and only be shown the authentication code.
|
66
|
-
request_token = client.request_token(:
|
66
|
+
request_token = client.request_token(:oauth_callback => 'http://yourapp.com/oauth/callback')
|
67
67
|
|
68
68
|
# 2. Redirect the user to the URL specified by the RequestToken.
|
69
69
|
#
|
@@ -90,7 +90,7 @@ You can now use the client to access the Xero API methods, e.g.
|
|
90
90
|
public
|
91
91
|
|
92
92
|
def new
|
93
|
-
request_token = @xero_client.request_token(:
|
93
|
+
request_token = @xero_client.request_token(:oauth_callback => 'http://yourapp.com/xero_session/create')
|
94
94
|
session[:request_token] = request_token.token
|
95
95
|
session[:request_secret] = request_token.secret
|
96
96
|
|
@@ -194,12 +194,12 @@ Authentication occcurs in 3 steps:
|
|
194
194
|
"/path/to/entrust-private-nopass.pem"
|
195
195
|
)
|
196
196
|
|
197
|
-
# 1. Get a RequestToken from Xero.
|
197
|
+
# 1. Get a RequestToken from Xero. :oauth_callback is the URL the user will be redirected to
|
198
198
|
# after they have authenticated your application.
|
199
199
|
#
|
200
200
|
# Note: The callback URL's domain must match that listed for your application in http://api.xero.com
|
201
201
|
# otherwise the user will not be redirected and only be shown the authentication code.
|
202
|
-
request_token = client.request_token(:
|
202
|
+
request_token = client.request_token(:oauth_callback => 'http://yourapp.com/oauth/callback')
|
203
203
|
|
204
204
|
# 2. Redirect the user to the URL specified by the RequestToken.
|
205
205
|
#
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.5
|
@@ -77,15 +77,21 @@ module Xeroizer
|
|
77
77
|
has_many :payments
|
78
78
|
has_many :credit_notes
|
79
79
|
|
80
|
-
validates_presence_of :date, :due_date
|
80
|
+
validates_presence_of :date, :due_date, :unless => proc { |invoice| invoice.new_record? }
|
81
81
|
validates_inclusion_of :type, :in => INVOICE_TYPES
|
82
|
-
validates_inclusion_of :status, :in => INVOICE_STATUSES
|
83
|
-
validates_inclusion_of :line_amount_types, :in => LINE_AMOUNT_TYPES
|
82
|
+
validates_inclusion_of :status, :in => INVOICE_STATUSES, :unless => proc { |invoice| invoice.new_record? }
|
83
|
+
validates_inclusion_of :line_amount_types, :in => LINE_AMOUNT_TYPES, :unless => proc { |invoice| invoice.new_record? }
|
84
84
|
validates_associated :contact
|
85
|
-
validates_associated :line_items
|
85
|
+
validates_associated :line_items, :allow_blanks => true, :unless => proc { |invoice| invoice.approved? }
|
86
|
+
validates_associated :line_items, :if => proc { |invoice| invoice.approved? }
|
86
87
|
|
87
88
|
public
|
88
|
-
|
89
|
+
|
90
|
+
# Helper method to check if the invoice has been approved.
|
91
|
+
def approved?
|
92
|
+
[ 'AUTHORISED', 'PAID', 'VOIDED' ].include? status
|
93
|
+
end
|
94
|
+
|
89
95
|
# Helper method to check if the invoice is accounts payable.
|
90
96
|
def accounts_payable?
|
91
97
|
type == 'ACCPAY'
|
@@ -18,14 +18,16 @@ module Xeroizer
|
|
18
18
|
# @param [Hash] options other options to pass to the GenericApplication constructor
|
19
19
|
# @return [PartnerApplication] instance of PrivateApplication
|
20
20
|
def initialize(consumer_key, consumer_secret, path_to_private_key, path_to_ssl_client_cert, path_to_ssl_client_key, options = {})
|
21
|
-
|
22
|
-
:xero_url
|
23
|
-
:site
|
24
|
-
:authorize_url
|
25
|
-
:signature_method => 'RSA-SHA1'
|
21
|
+
default_options = {
|
22
|
+
:xero_url => 'https://api-partner.network.xero.com/api.xro/2.0',
|
23
|
+
:site => 'https://api-partner.network.xero.com',
|
24
|
+
:authorize_url => 'https://api.xero.com/oauth/Authorize',
|
25
|
+
:signature_method => 'RSA-SHA1'
|
26
|
+
}
|
27
|
+
options = default_options.merge(options).merge(
|
26
28
|
:private_key_file => path_to_private_key,
|
27
|
-
:ssl_client_cert
|
28
|
-
:ssl_client_key
|
29
|
+
:ssl_client_cert => OpenSSL::X509::Certificate.new(File.read(path_to_ssl_client_cert)),
|
30
|
+
:ssl_client_key => OpenSSL::PKey::RSA.new(File.read(path_to_ssl_client_key))
|
29
31
|
)
|
30
32
|
super(consumer_key, consumer_secret, options)
|
31
33
|
|
data/lib/xeroizer/record/base.rb
CHANGED
@@ -61,6 +61,9 @@ module Xeroizer
|
|
61
61
|
raise StandardError.new("Invalid arguments for #{self.class.name}#add_#{internal_singular_field_name}(#{args.inspect}).")
|
62
62
|
end
|
63
63
|
|
64
|
+
# Ensure that complete record is downloaded before adding new records
|
65
|
+
self.send(field_name)
|
66
|
+
|
64
67
|
# Add each record.
|
65
68
|
record = nil
|
66
69
|
records.each do | record |
|
@@ -109,6 +112,9 @@ module Xeroizer
|
|
109
112
|
when record_class
|
110
113
|
self.attributes[field_name] = ((association_type == :has_many) ? [value] : value)
|
111
114
|
|
115
|
+
when NilClass
|
116
|
+
self.attributes[field_name] = []
|
117
|
+
|
112
118
|
else
|
113
119
|
raise AssociationTypeMismatch.new(record_class, value.class)
|
114
120
|
end
|
@@ -58,10 +58,9 @@ module Xeroizer
|
|
58
58
|
def to_xml(b = Builder::XmlMarkup.new(:indent => 2))
|
59
59
|
b.tag!(parent.class.xml_node_name || parent.model_name) {
|
60
60
|
attributes.each do | key, value |
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
61
|
+
field = self.class.fields[key]
|
62
|
+
value = self.send(key) if field[:calculated]
|
63
|
+
xml_value_from_field(b, field, value) unless value.nil?
|
65
64
|
end
|
66
65
|
}
|
67
66
|
end
|
@@ -1849,5 +1849,51 @@
|
|
1849
1849
|
<AmountDue>0.00</AmountDue>
|
1850
1850
|
<AmountPaid>1500.00</AmountPaid>
|
1851
1851
|
</Invoice>
|
1852
|
+
<Invoice>
|
1853
|
+
<Contact>
|
1854
|
+
<ContactID>9601cac0-db41-4255-8cc6-f38b555ce53f</ContactID>
|
1855
|
+
<ContactStatus>ACTIVE</ContactStatus>
|
1856
|
+
<Name>ABC</Name>
|
1857
|
+
<Addresses>
|
1858
|
+
<Address>
|
1859
|
+
<AddressType>STREET</AddressType>
|
1860
|
+
</Address>
|
1861
|
+
<Address>
|
1862
|
+
<AddressType>POBOX</AddressType>
|
1863
|
+
</Address>
|
1864
|
+
</Addresses>
|
1865
|
+
<Phones>
|
1866
|
+
<Phone>
|
1867
|
+
<PhoneType>MOBILE</PhoneType>
|
1868
|
+
</Phone>
|
1869
|
+
<Phone>
|
1870
|
+
<PhoneType>DEFAULT</PhoneType>
|
1871
|
+
</Phone>
|
1872
|
+
<Phone>
|
1873
|
+
<PhoneType>DDI</PhoneType>
|
1874
|
+
</Phone>
|
1875
|
+
<Phone>
|
1876
|
+
<PhoneType>FAX</PhoneType>
|
1877
|
+
</Phone>
|
1878
|
+
</Phones>
|
1879
|
+
<UpdatedDateUTC>2011-06-21T09:22:54.097</UpdatedDateUTC>
|
1880
|
+
<IsSupplier>false</IsSupplier>
|
1881
|
+
<IsCustomer>true</IsCustomer>
|
1882
|
+
</Contact>
|
1883
|
+
<Date>2011-06-21T00:00:00</Date>
|
1884
|
+
<Status>DRAFT</Status>
|
1885
|
+
<LineAmountTypes>Exclusive</LineAmountTypes>
|
1886
|
+
<SubTotal>0.00</SubTotal>
|
1887
|
+
<TotalTax>0.00</TotalTax>
|
1888
|
+
<Total>0.00</Total>
|
1889
|
+
<UpdatedDateUTC>2011-06-21T09:22:54.143</UpdatedDateUTC>
|
1890
|
+
<CurrencyCode>NZD</CurrencyCode>
|
1891
|
+
<Type>ACCREC</Type>
|
1892
|
+
<InvoiceID>762aa45d-4632-45b5-8087-b4f47690665e</InvoiceID>
|
1893
|
+
<InvoiceNumber>INV-0039</InvoiceNumber>
|
1894
|
+
<AmountDue>0.00</AmountDue>
|
1895
|
+
<AmountPaid>0.00</AmountPaid>
|
1896
|
+
<SentToContact>false</SentToContact>
|
1897
|
+
</Invoice>
|
1852
1898
|
</Invoices>
|
1853
1899
|
</Response>
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<Response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
2
|
+
<Id>8837eff8-5b9d-4788-a735-d61dd5d56a56</Id>
|
3
|
+
<Status>OK</Status>
|
4
|
+
<ProviderName>Xero API Previewer</ProviderName>
|
5
|
+
<DateTimeUTC>2011-06-21T09:22:54.1911951Z</DateTimeUTC>
|
6
|
+
<Invoices>
|
7
|
+
<Invoice>
|
8
|
+
<Contact>
|
9
|
+
<ContactID>9601cac0-db41-4255-8cc6-f38b555ce53f</ContactID>
|
10
|
+
<ContactStatus>ACTIVE</ContactStatus>
|
11
|
+
<Name>ABC</Name>
|
12
|
+
<Addresses>
|
13
|
+
<Address>
|
14
|
+
<AddressType>STREET</AddressType>
|
15
|
+
</Address>
|
16
|
+
<Address>
|
17
|
+
<AddressType>POBOX</AddressType>
|
18
|
+
</Address>
|
19
|
+
</Addresses>
|
20
|
+
<Phones>
|
21
|
+
<Phone>
|
22
|
+
<PhoneType>MOBILE</PhoneType>
|
23
|
+
</Phone>
|
24
|
+
<Phone>
|
25
|
+
<PhoneType>DEFAULT</PhoneType>
|
26
|
+
</Phone>
|
27
|
+
<Phone>
|
28
|
+
<PhoneType>DDI</PhoneType>
|
29
|
+
</Phone>
|
30
|
+
<Phone>
|
31
|
+
<PhoneType>FAX</PhoneType>
|
32
|
+
</Phone>
|
33
|
+
</Phones>
|
34
|
+
<UpdatedDateUTC>2011-06-21T09:22:54.097</UpdatedDateUTC>
|
35
|
+
<IsSupplier>false</IsSupplier>
|
36
|
+
<IsCustomer>true</IsCustomer>
|
37
|
+
</Contact>
|
38
|
+
<Date>2011-06-21T00:00:00</Date>
|
39
|
+
<Status>DRAFT</Status>
|
40
|
+
<LineAmountTypes>Exclusive</LineAmountTypes>
|
41
|
+
<SubTotal>0.00</SubTotal>
|
42
|
+
<TotalTax>0.00</TotalTax>
|
43
|
+
<Total>0.00</Total>
|
44
|
+
<UpdatedDateUTC>2011-06-21T09:22:54.143</UpdatedDateUTC>
|
45
|
+
<CurrencyCode>NZD</CurrencyCode>
|
46
|
+
<Type>ACCREC</Type>
|
47
|
+
<InvoiceID>762aa45d-4632-45b5-8087-b4f47690665e</InvoiceID>
|
48
|
+
<InvoiceNumber>INV-0039</InvoiceNumber>
|
49
|
+
<AmountDue>0.00</AmountDue>
|
50
|
+
<AmountPaid>0.00</AmountPaid>
|
51
|
+
<SentToContact>false</SentToContact>
|
52
|
+
</Invoice>
|
53
|
+
</Invoices>
|
54
|
+
</Response>
|
@@ -48,4 +48,39 @@ class InvoiceTest < Test::Unit::TestCase
|
|
48
48
|
|
49
49
|
end
|
50
50
|
|
51
|
+
context "invoice validations" do
|
52
|
+
|
53
|
+
should "build an invalid invoice if there are no attributes" do
|
54
|
+
assert_equal(false, @client.Invoice.build.valid?)
|
55
|
+
end
|
56
|
+
|
57
|
+
should "build a valid DRAFT invoice with minimal attributes" do
|
58
|
+
invoice = @client.Invoice.build :type => "ACCREC", :contact => { :name => "ABC Limited" }
|
59
|
+
assert_equal(true, invoice.valid?)
|
60
|
+
end
|
61
|
+
|
62
|
+
should "build a invalid AUTHORISED invoice with minimal attributes" do
|
63
|
+
invoice = @client.Invoice.build :type => "ACCREC", :contact => { :name => "ABC Limited" }, :status => "AUTHORISED"
|
64
|
+
assert_equal(false, invoice.valid?)
|
65
|
+
end
|
66
|
+
|
67
|
+
should "build a valid AUTHORISED invoice with complete attributes" do
|
68
|
+
invoice = @client.Invoice.build({
|
69
|
+
:type => "ACCREC",
|
70
|
+
:contact => { :name => "ABC Limited" },
|
71
|
+
:status => "AUTHORISED",
|
72
|
+
:date => Date.today,
|
73
|
+
:due_date => Date.today,
|
74
|
+
:line_items => [{
|
75
|
+
:description => "Consulting services as agreed",
|
76
|
+
:quantity => 5,
|
77
|
+
:unit_amount => 120,
|
78
|
+
:account_code => 200
|
79
|
+
}]
|
80
|
+
})
|
81
|
+
assert_equal(true, invoice.valid?)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
51
86
|
end
|
@@ -5,8 +5,8 @@ class RecordAssociationTest < Test::Unit::TestCase
|
|
5
5
|
|
6
6
|
def setup
|
7
7
|
@client = Xeroizer::PublicApplication.new(CONSUMER_KEY, CONSUMER_SECRET)
|
8
|
-
|
9
|
-
@client.stubs(:
|
8
|
+
mock_api('Invoices')
|
9
|
+
@client.stubs(:http_put).returns(get_record_xml(:invoice, "762aa45d-4632-45b5-8087-b4f47690665e"))
|
10
10
|
end
|
11
11
|
|
12
12
|
context "belongs_to association" do
|
@@ -64,6 +64,30 @@ class RecordAssociationTest < Test::Unit::TestCase
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
+
should "retain unsaved items after create" do
|
68
|
+
invoice = @client.Invoice.build :type => "ACCREC", :contact => { :name => "A" }
|
69
|
+
invoice.save
|
70
|
+
invoice.add_line_item :description => "1"
|
71
|
+
assert_equal(1, invoice.line_items.size, "There should be one line item.")
|
72
|
+
end
|
73
|
+
|
74
|
+
should "retain unsaved items after find" do
|
75
|
+
invoice = @client.Invoice.find "762aa45d-4632-45b5-8087-b4f47690665e"
|
76
|
+
invoice.add_line_item :description => "1"
|
77
|
+
assert_equal(1, invoice.line_items.size, "There should be one line item.")
|
78
|
+
end
|
79
|
+
|
80
|
+
should "retain unsaved items after summary find" do
|
81
|
+
invoice = @client.Invoice.all.last
|
82
|
+
invoice.add_line_item :description => "1"
|
83
|
+
assert_equal(1, invoice.line_items.size, "There should be one line item.")
|
84
|
+
end
|
85
|
+
|
86
|
+
should "retain unsaved items when set explicitly" do
|
87
|
+
invoice = @client.Invoice.all.last
|
88
|
+
invoice.line_items = [{ :description => "1" }]
|
89
|
+
assert_equal(1, invoice.line_items.size, "There should be one line item.")
|
90
|
+
end
|
67
91
|
end
|
68
92
|
|
69
93
|
end
|
data/xeroizer.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{xeroizer}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Wayne Robinson"]
|
12
|
-
s.date = %q{2011-06-
|
12
|
+
s.date = %q{2011-06-27}
|
13
13
|
s.description = %q{Ruby library for the Xero accounting system API.}
|
14
14
|
s.email = %q{wayne.robinson@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -257,6 +257,7 @@ Gem::Specification.new do |s|
|
|
257
257
|
"test/stub_responses/records/invoice-673dd7cc-beb7-4697-83d4-0c47cb400cc2.xml",
|
258
258
|
"test/stub_responses/records/invoice-69fc971e-9b37-41c5-9c87-174330f22343.xml",
|
259
259
|
"test/stub_responses/records/invoice-70e6db69-e5a4-42c7-a397-aa3212c2945f.xml",
|
260
|
+
"test/stub_responses/records/invoice-762aa45d-4632-45b5-8087-b4f47690665e.xml",
|
260
261
|
"test/stub_responses/records/invoice-766d1289-b440-4675-a656-1a0612ecac77.xml",
|
261
262
|
"test/stub_responses/records/invoice-76bcb361-f93b-4513-b312-5a4af306d276.xml",
|
262
263
|
"test/stub_responses/records/invoice-76e3f056-479f-417c-a72b-f3d767899b87.xml",
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xeroizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 5
|
10
|
+
version: 0.3.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Wayne Robinson
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-06-
|
18
|
+
date: 2011-06-27 00:00:00 +10:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -416,6 +416,7 @@ files:
|
|
416
416
|
- test/stub_responses/records/invoice-673dd7cc-beb7-4697-83d4-0c47cb400cc2.xml
|
417
417
|
- test/stub_responses/records/invoice-69fc971e-9b37-41c5-9c87-174330f22343.xml
|
418
418
|
- test/stub_responses/records/invoice-70e6db69-e5a4-42c7-a397-aa3212c2945f.xml
|
419
|
+
- test/stub_responses/records/invoice-762aa45d-4632-45b5-8087-b4f47690665e.xml
|
419
420
|
- test/stub_responses/records/invoice-766d1289-b440-4675-a656-1a0612ecac77.xml
|
420
421
|
- test/stub_responses/records/invoice-76bcb361-f93b-4513-b312-5a4af306d276.xml
|
421
422
|
- test/stub_responses/records/invoice-76e3f056-479f-417c-a72b-f3d767899b87.xml
|