tlconnor-xero_gateway 1.0.0
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/CHANGELOG.textile +14 -0
- data/LICENSE +14 -0
- data/README.textile +119 -0
- data/Rakefile +14 -0
- data/lib/xero_gateway.rb +35 -0
- data/lib/xero_gateway/account.rb +34 -0
- data/lib/xero_gateway/address.rb +47 -0
- data/lib/xero_gateway/contact.rb +54 -0
- data/lib/xero_gateway/dates.rb +31 -0
- data/lib/xero_gateway/gateway.rb +283 -0
- data/lib/xero_gateway/http.rb +73 -0
- data/lib/xero_gateway/invoice.rb +48 -0
- data/lib/xero_gateway/line_item.rb +40 -0
- data/lib/xero_gateway/messages/account_message.rb +59 -0
- data/lib/xero_gateway/messages/contact_message.rb +107 -0
- data/lib/xero_gateway/messages/invoice_message.rb +136 -0
- data/lib/xero_gateway/money.rb +30 -0
- data/lib/xero_gateway/phone.rb +38 -0
- data/lib/xero_gateway/response.rb +44 -0
- data/test/integration/gateway_test.rb +166 -0
- data/test/integration/stub_responses/accounts.xml +1 -0
- data/test/integration/stub_responses/contact.xml +1 -0
- data/test/integration/stub_responses/contacts.xml +1 -0
- data/test/integration/stub_responses/invoice.xml +1 -0
- data/test/integration/stub_responses/invoices.xml +1 -0
- data/test/test_helper.rb +22 -0
- data/test/unit/messages/contact_message_test.rb +66 -0
- data/test/unit/messages/invoice_message_test.rb +76 -0
- data/test/xsd/README +2 -0
- data/test/xsd/create_contact.xsd +50 -0
- data/test/xsd/create_invoice.xsd +98 -0
- data/xero_gateway.gemspec +44 -0
- metadata +92 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
# Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
module XeroGateway
|
16
|
+
module Http
|
17
|
+
OPEN_TIMEOUT = 10
|
18
|
+
READ_TIMEOUT = 60
|
19
|
+
|
20
|
+
def http_get(url, extra_params = {})
|
21
|
+
params = {:apiKey => @api_key, :xeroKey => @customer_key}
|
22
|
+
params = params.merge(extra_params).map {|key,value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&")
|
23
|
+
|
24
|
+
uri = URI.parse(url + "?" + params)
|
25
|
+
|
26
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
27
|
+
http.open_timeout = OPEN_TIMEOUT
|
28
|
+
http.read_timeout = READ_TIMEOUT
|
29
|
+
http.use_ssl = true
|
30
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
31
|
+
|
32
|
+
http.get(uri.request_uri).body
|
33
|
+
end
|
34
|
+
|
35
|
+
def http_post(url, body, extra_params = {})
|
36
|
+
headers = {}
|
37
|
+
headers['Content-Type'] ||= "application/x-www-form-urlencoded"
|
38
|
+
|
39
|
+
params = {:apiKey => @api_key, :xeroKey => @customer_key}
|
40
|
+
params = params.merge(extra_params).map {|key,value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&")
|
41
|
+
|
42
|
+
uri = URI.parse(url + "?" + params)
|
43
|
+
|
44
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
45
|
+
http.open_timeout = OPEN_TIMEOUT
|
46
|
+
http.read_timeout = READ_TIMEOUT
|
47
|
+
http.use_ssl = true
|
48
|
+
|
49
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
50
|
+
|
51
|
+
http.post(uri.request_uri, body, headers).body
|
52
|
+
end
|
53
|
+
|
54
|
+
def http_put(url, body, extra_params = {})
|
55
|
+
headers = {}
|
56
|
+
headers['Content-Type'] ||= "application/x-www-form-urlencoded"
|
57
|
+
|
58
|
+
params = {:apiKey => @api_key, :xeroKey => @customer_key}
|
59
|
+
params = params.merge(extra_params).map {|key,value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&")
|
60
|
+
|
61
|
+
uri = URI.parse(url + "?" + params)
|
62
|
+
|
63
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
64
|
+
http.open_timeout = OPEN_TIMEOUT
|
65
|
+
http.read_timeout = READ_TIMEOUT
|
66
|
+
http.use_ssl = true
|
67
|
+
|
68
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
69
|
+
|
70
|
+
http.put(uri.request_uri, body, headers).body
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
module XeroGateway
|
16
|
+
class Invoice
|
17
|
+
# All accessible fields
|
18
|
+
attr_accessor :id, :invoice_number, :invoice_type, :invoice_status, :date, :due_date, :reference, :tax_inclusive, :includes_tax, :sub_total, :total_tax, :total, :line_items, :contact
|
19
|
+
|
20
|
+
def initialize(params = {})
|
21
|
+
params = {
|
22
|
+
:contact => Contact.new,
|
23
|
+
:date => Time.now,
|
24
|
+
:includes_tax => true,
|
25
|
+
:tax_inclusive => true
|
26
|
+
}.merge(params)
|
27
|
+
|
28
|
+
params.each do |k,v|
|
29
|
+
self.instance_variable_set("@#{k}", v) ## create and initialize an instance variable for this key/value pair
|
30
|
+
self.send("#{k}=", v)
|
31
|
+
end
|
32
|
+
|
33
|
+
@line_items ||= []
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(other)
|
37
|
+
equal = true
|
38
|
+
["invoice_number", "invoice_type", "invoice_status", "reference", "tax_inclusive", "includes_tax", "sub_total", "total_tax", "total", "contact", "line_items"].each do |field|
|
39
|
+
equal &&= (send(field) == other.send(field))
|
40
|
+
end
|
41
|
+
["date", "due_date"].each do |field|
|
42
|
+
equal &&= (send(field).to_s == other.send(field).to_s)
|
43
|
+
end
|
44
|
+
|
45
|
+
return equal
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
module XeroGateway
|
16
|
+
class LineItem
|
17
|
+
# All accessible fields
|
18
|
+
attr_accessor :id, :description, :quantity, :unit_amount, :tax_type, :tax_amount, :line_amount, :account_code, :tracking_category, :tracking_option
|
19
|
+
|
20
|
+
def initialize(params = {})
|
21
|
+
params = {
|
22
|
+
:quantity => 1
|
23
|
+
}.merge(params)
|
24
|
+
|
25
|
+
params.each do |k,v|
|
26
|
+
self.instance_variable_set("@#{k}", v) ## create and initialize an instance variable for this key/value pair
|
27
|
+
self.send("#{k}=", v)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def ==(other)
|
32
|
+
return true
|
33
|
+
equal = true
|
34
|
+
[:description, :quantity, :unit_amount, :tax_type, :tax_amount, :line_amount, :account_code, :tracking_category, :tracking_option].each do |field|
|
35
|
+
equal &&= (send(field) == other.send(field))
|
36
|
+
end
|
37
|
+
return equal
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
module XeroGateway
|
16
|
+
module Messages
|
17
|
+
class AccountMessage
|
18
|
+
|
19
|
+
# Take an Account element and convert it into an Account object
|
20
|
+
def self.from_xml(account_element)
|
21
|
+
account = Account.new
|
22
|
+
account_element.children.each do |element|
|
23
|
+
case(element.name)
|
24
|
+
when "Code" then account.code = element.text
|
25
|
+
when "Name" then account.name = element.text
|
26
|
+
when "Type" then account.type = element.text
|
27
|
+
when "TaxType" then account.tax_type = element.text
|
28
|
+
when "Description" then account.description = element.text
|
29
|
+
end
|
30
|
+
end
|
31
|
+
account
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def self.parse_line_item(line_item_element)
|
37
|
+
line_item = LineItem.new
|
38
|
+
line_item_element.children.each do |element|
|
39
|
+
case(element.name)
|
40
|
+
when "LineItemID" then line_item.id = element.text
|
41
|
+
when "Description" then line_item.description = element.text
|
42
|
+
when "Quantity" then line_item.quantity = element.text.to_i
|
43
|
+
when "UnitAmount" then line_item.unit_amount = BigDecimal.new(element.text)
|
44
|
+
when "TaxType" then line_item.tax_type = element.text
|
45
|
+
when "TaxAmount" then line_item.tax_amount = BigDecimal.new(element.text)
|
46
|
+
when "LineAmount" then line_item.line_amount = BigDecimal.new(element.text)
|
47
|
+
when "AccountCode" then line_item.account_code = element.text
|
48
|
+
when "Tracking" then
|
49
|
+
if element.elements['TrackingCategory']
|
50
|
+
line_item.tracking_category = element.elements['TrackingCategory/Name'].text
|
51
|
+
line_item.tracking_option = element.elements['TrackingCategory/Option'].text
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
line_item
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
module XeroGateway
|
16
|
+
module Messages
|
17
|
+
class ContactMessage
|
18
|
+
include Dates
|
19
|
+
|
20
|
+
def self.build_xml(contact)
|
21
|
+
b = Builder::XmlMarkup.new
|
22
|
+
|
23
|
+
b.Contact {
|
24
|
+
b.ContactID contact.id if contact.id
|
25
|
+
b.ContactNumber contact.contact_number if contact.contact_number
|
26
|
+
b.Name contact.name
|
27
|
+
b.EmailAddress contact.email if contact.email
|
28
|
+
b.Addresses {
|
29
|
+
contact.addresses.each do |address|
|
30
|
+
b.Address {
|
31
|
+
b.AddressType address.address_type
|
32
|
+
b.AddressLine1 address.line_1 if address.line_1
|
33
|
+
b.AddressLine2 address.line_2 if address.line_2
|
34
|
+
b.AddressLine3 address.line_3 if address.line_3
|
35
|
+
b.AddressLine4 address.line_4 if address.line_4
|
36
|
+
b.City address.city if address.city
|
37
|
+
b.Region address.region if address.region
|
38
|
+
b.PostalCode address.post_code if address.post_code
|
39
|
+
b.Country address.country if address.country
|
40
|
+
}
|
41
|
+
end
|
42
|
+
}
|
43
|
+
b.Phones {
|
44
|
+
contact.phones.each do |phone|
|
45
|
+
b.Phone {
|
46
|
+
b.PhoneType phone.phone_type
|
47
|
+
b.PhoneNumber phone.number
|
48
|
+
b.PhoneAreaCode phone.area_code if phone.area_code
|
49
|
+
b.PhoneCountryCode phone.country_code if phone.country_code
|
50
|
+
}
|
51
|
+
end
|
52
|
+
}
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
# Take a Contact element and convert it into an Contact object
|
57
|
+
def self.from_xml(contact_element)
|
58
|
+
contact = Contact.new
|
59
|
+
contact_element.children.each do |element|
|
60
|
+
case(element.name)
|
61
|
+
when "ContactID" then contact.id = element.text
|
62
|
+
when "ContactNumber" then contact.contact_number = element.text
|
63
|
+
when "ContactStatus" then contact.status = element.text
|
64
|
+
when "Name" then contact.name = element.text
|
65
|
+
when "EmailAddress" then contact.email = element.text
|
66
|
+
when "Addresses" then element.children.each {|address| contact.addresses << parse_address(address)}
|
67
|
+
when "Phones" then element.children.each {|phone| contact.phones << parse_phone(phone)}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
contact
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def self.parse_address(address_element)
|
76
|
+
address = Address.new
|
77
|
+
address_element.children.each do |element|
|
78
|
+
case(element.name)
|
79
|
+
when "AddressType" then address.address_type = element.text
|
80
|
+
when "AddressLine1" then address.line_1 = element.text
|
81
|
+
when "AddressLine2" then address.line_2 = element.text
|
82
|
+
when "AddressLine3" then address.line_3 = element.text
|
83
|
+
when "AddressLine4" then address.line_4 = element.text
|
84
|
+
when "City" then address.city = element.text
|
85
|
+
when "Region" then address.region = element.text
|
86
|
+
when "PostalCode" then address.post_code = element.text
|
87
|
+
when "Country" then address.country = element.text
|
88
|
+
end
|
89
|
+
end
|
90
|
+
address
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.parse_phone(phone_element)
|
94
|
+
phone = Phone.new
|
95
|
+
phone_element.children.each do |element|
|
96
|
+
case(element.name)
|
97
|
+
when "PhoneType" then phone.phone_type = element.text
|
98
|
+
when "PhoneNumber" then phone.number = element.text
|
99
|
+
when "PhoneAreaCode" then phone.area_code = element.text
|
100
|
+
when "PhoneCountryCode" then phone.country_code = element.text
|
101
|
+
end
|
102
|
+
end
|
103
|
+
phone
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
module XeroGateway
|
16
|
+
module Messages
|
17
|
+
class InvoiceMessage
|
18
|
+
include Dates
|
19
|
+
include Money
|
20
|
+
|
21
|
+
def self.build_xml(invoice)
|
22
|
+
b = Builder::XmlMarkup.new
|
23
|
+
|
24
|
+
b.Invoice {
|
25
|
+
b.InvoiceType invoice.invoice_type
|
26
|
+
b.Contact {
|
27
|
+
b.ContactID invoice.contact.id if invoice.contact.id
|
28
|
+
b.Name invoice.contact.name
|
29
|
+
b.EmailAddress invoice.contact.email if invoice.contact.email
|
30
|
+
b.Addresses {
|
31
|
+
invoice.contact.addresses.each do |address|
|
32
|
+
b.Address {
|
33
|
+
b.AddressType address.address_type
|
34
|
+
b.AddressLine1 address.line_1 if address.line_1
|
35
|
+
b.AddressLine2 address.line_2 if address.line_2
|
36
|
+
b.AddressLine3 address.line_3 if address.line_3
|
37
|
+
b.AddressLine4 address.line_4 if address.line_4
|
38
|
+
b.City address.city if address.city
|
39
|
+
b.Region address.region if address.region
|
40
|
+
b.PostalCode address.post_code if address.post_code
|
41
|
+
b.Country address.country if address.country
|
42
|
+
}
|
43
|
+
end
|
44
|
+
}
|
45
|
+
b.Phones {
|
46
|
+
invoice.contact.phones.each do |phone|
|
47
|
+
b.Phone {
|
48
|
+
b.PhoneType phone.phone_type
|
49
|
+
b.PhoneNumber phone.number
|
50
|
+
b.PhoneAreaCode phone.area_code if phone.area_code
|
51
|
+
b.PhoneCountryCode phone.country_code if phone.country_code
|
52
|
+
}
|
53
|
+
end
|
54
|
+
}
|
55
|
+
}
|
56
|
+
b.InvoiceDate format_date_time(invoice.date)
|
57
|
+
b.DueDate format_date_time(invoice.due_date) if invoice.due_date
|
58
|
+
b.InvoiceNumber invoice.invoice_number
|
59
|
+
b.Reference invoice.reference if invoice.reference
|
60
|
+
b.TaxInclusive invoice.tax_inclusive if invoice.tax_inclusive
|
61
|
+
b.IncludesTax invoice.includes_tax
|
62
|
+
b.SubTotal format_money(invoice.sub_total) if invoice.sub_total
|
63
|
+
b.TotalTax format_money(invoice.total_tax) if invoice.total_tax
|
64
|
+
b.Total format_money(invoice.total) if invoice.total
|
65
|
+
b.LineItems {
|
66
|
+
invoice.line_items.each do |line_item|
|
67
|
+
b.LineItem {
|
68
|
+
b.Description line_item.description
|
69
|
+
b.Quantity line_item.quantity if line_item.quantity
|
70
|
+
b.UnitAmount format_money(line_item.unit_amount)
|
71
|
+
b.TaxType line_item.tax_type if line_item.tax_type
|
72
|
+
b.TaxAmount format_money(line_item.tax_amount) if line_item.tax_amount
|
73
|
+
b.LineAmount format_money(line_item.line_amount)
|
74
|
+
b.AccountCode line_item.account_code || 200
|
75
|
+
b.Tracking {
|
76
|
+
b.TrackingCategory {
|
77
|
+
b.Name line_item.tracking_category
|
78
|
+
b.Option line_item.tracking_option
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
end
|
83
|
+
}
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
# Take an Invoice element and convert it into an Invoice object
|
88
|
+
def self.from_xml(invoice_element)
|
89
|
+
invoice = Invoice.new
|
90
|
+
invoice_element.children.each do |element|
|
91
|
+
case(element.name)
|
92
|
+
when "InvoiceStatus" then invoice.invoice_status = element.text
|
93
|
+
when "InvoiceID" then invoice.id = element.text
|
94
|
+
when "InvoiceNumber" then invoice.invoice_number = element.text
|
95
|
+
when "InvoiceType" then invoice.invoice_type = element.text
|
96
|
+
when "InvoiceDate" then invoice.date = parse_date_time(element.text)
|
97
|
+
when "DueDate" then invoice.due_date = parse_date_time(element.text)
|
98
|
+
when "Reference" then invoice.reference = element.text
|
99
|
+
when "TaxInclusive" then invoice.tax_inclusive = (element.text == "true")
|
100
|
+
when "IncludesTax" then invoice.includes_tax = (element.text == "true")
|
101
|
+
when "SubTotal" then invoice.sub_total = BigDecimal.new(element.text)
|
102
|
+
when "TotalTax" then invoice.total_tax = BigDecimal.new(element.text)
|
103
|
+
when "Total" then invoice.total = BigDecimal.new(element.text)
|
104
|
+
when "Contact" then invoice.contact = ContactMessage.from_xml(element)
|
105
|
+
when "LineItems" then element.children.each {|line_item| invoice.line_items << parse_line_item(line_item)}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
invoice
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def self.parse_line_item(line_item_element)
|
114
|
+
line_item = LineItem.new
|
115
|
+
line_item_element.children.each do |element|
|
116
|
+
case(element.name)
|
117
|
+
when "LineItemID" then line_item.id = element.text
|
118
|
+
when "Description" then line_item.description = element.text
|
119
|
+
when "Quantity" then line_item.quantity = element.text.to_i
|
120
|
+
when "UnitAmount" then line_item.unit_amount = BigDecimal.new(element.text)
|
121
|
+
when "TaxType" then line_item.tax_type = element.text
|
122
|
+
when "TaxAmount" then line_item.tax_amount = BigDecimal.new(element.text)
|
123
|
+
when "LineAmount" then line_item.line_amount = BigDecimal.new(element.text)
|
124
|
+
when "AccountCode" then line_item.account_code = element.text
|
125
|
+
when "Tracking" then
|
126
|
+
if element.elements['TrackingCategory']
|
127
|
+
line_item.tracking_category = element.elements['TrackingCategory/Name'].text
|
128
|
+
line_item.tracking_option = element.elements['TrackingCategory/Option'].text
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
line_item
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|