xero_gateway-float 2.0.15
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/Gemfile +12 -0
- data/LICENSE +14 -0
- data/README.textile +357 -0
- data/Rakefile +14 -0
- data/examples/oauth.rb +25 -0
- data/examples/partner_app.rb +36 -0
- data/init.rb +1 -0
- data/lib/oauth/oauth_consumer.rb +14 -0
- data/lib/xero_gateway.rb +39 -0
- data/lib/xero_gateway/account.rb +95 -0
- data/lib/xero_gateway/accounts_list.rb +87 -0
- data/lib/xero_gateway/address.rb +96 -0
- data/lib/xero_gateway/bank_transaction.rb +178 -0
- data/lib/xero_gateway/ca-certificates.crt +2560 -0
- data/lib/xero_gateway/contact.rb +206 -0
- data/lib/xero_gateway/credit_note.rb +222 -0
- data/lib/xero_gateway/currency.rb +56 -0
- data/lib/xero_gateway/dates.rb +30 -0
- data/lib/xero_gateway/error.rb +18 -0
- data/lib/xero_gateway/exceptions.rb +46 -0
- data/lib/xero_gateway/gateway.rb +622 -0
- data/lib/xero_gateway/http.rb +138 -0
- data/lib/xero_gateway/http_encoding_helper.rb +49 -0
- data/lib/xero_gateway/invoice.rb +236 -0
- data/lib/xero_gateway/line_item.rb +125 -0
- data/lib/xero_gateway/line_item_calculations.rb +55 -0
- data/lib/xero_gateway/money.rb +16 -0
- data/lib/xero_gateway/oauth.rb +87 -0
- data/lib/xero_gateway/organisation.rb +75 -0
- data/lib/xero_gateway/partner_app.rb +30 -0
- data/lib/xero_gateway/payment.rb +40 -0
- data/lib/xero_gateway/phone.rb +77 -0
- data/lib/xero_gateway/private_app.rb +17 -0
- data/lib/xero_gateway/response.rb +41 -0
- data/lib/xero_gateway/tax_rate.rb +63 -0
- data/lib/xero_gateway/tracking_category.rb +87 -0
- data/test/integration/accounts_list_test.rb +109 -0
- data/test/integration/create_bank_transaction_test.rb +38 -0
- data/test/integration/create_contact_test.rb +66 -0
- data/test/integration/create_credit_note_test.rb +49 -0
- data/test/integration/create_invoice_test.rb +49 -0
- data/test/integration/get_accounts_test.rb +23 -0
- data/test/integration/get_bank_transaction_test.rb +51 -0
- data/test/integration/get_bank_transactions_test.rb +88 -0
- data/test/integration/get_contact_test.rb +28 -0
- data/test/integration/get_contacts_test.rb +40 -0
- data/test/integration/get_credit_note_test.rb +48 -0
- data/test/integration/get_credit_notes_test.rb +90 -0
- data/test/integration/get_currencies_test.rb +25 -0
- data/test/integration/get_invoice_test.rb +48 -0
- data/test/integration/get_invoices_test.rb +92 -0
- data/test/integration/get_organisation_test.rb +24 -0
- data/test/integration/get_tax_rates_test.rb +25 -0
- data/test/integration/get_tracking_categories_test.rb +27 -0
- data/test/integration/update_bank_transaction_test.rb +31 -0
- data/test/integration/update_contact_test.rb +31 -0
- data/test/integration/update_invoice_test.rb +31 -0
- data/test/test_helper.rb +179 -0
- data/test/unit/account_test.rb +47 -0
- data/test/unit/bank_transaction_test.rb +126 -0
- data/test/unit/contact_test.rb +97 -0
- data/test/unit/credit_note_test.rb +284 -0
- data/test/unit/currency_test.rb +31 -0
- data/test/unit/gateway_test.rb +119 -0
- data/test/unit/invoice_test.rb +326 -0
- data/test/unit/oauth_test.rb +116 -0
- data/test/unit/organisation_test.rb +38 -0
- data/test/unit/tax_rate_test.rb +38 -0
- data/test/unit/tracking_category_test.rb +52 -0
- data/xero_gateway.gemspec +15 -0
- metadata +164 -0
@@ -0,0 +1,206 @@
|
|
1
|
+
module XeroGateway
|
2
|
+
class Contact
|
3
|
+
include Dates
|
4
|
+
|
5
|
+
class Error < RuntimeError; end
|
6
|
+
class NoGatewayError < Error; end
|
7
|
+
|
8
|
+
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)
|
9
|
+
|
10
|
+
CONTACT_STATUS = {
|
11
|
+
'ACTIVE' => 'Active',
|
12
|
+
'DELETED' => 'Deleted'
|
13
|
+
} unless defined?(CONTACT_STATUS)
|
14
|
+
|
15
|
+
# Xero::Gateway associated with this contact.
|
16
|
+
attr_accessor :gateway
|
17
|
+
|
18
|
+
# Any errors that occurred when the #valid? method called.
|
19
|
+
attr_reader :errors
|
20
|
+
|
21
|
+
attr_accessor :contact_id, :contact_number, :status, :name, :first_name, :last_name, :email, :addresses, :phones, :updated_at,
|
22
|
+
:bank_account_details, :tax_number, :accounts_receivable_tax_type, :accounts_payable_tax_type, :is_customer, :is_supplier,
|
23
|
+
:default_currency, :contact_groups
|
24
|
+
|
25
|
+
|
26
|
+
def initialize(params = {})
|
27
|
+
@errors ||= []
|
28
|
+
|
29
|
+
params = {}.merge(params)
|
30
|
+
params.each do |k,v|
|
31
|
+
self.send("#{k}=", v)
|
32
|
+
end
|
33
|
+
|
34
|
+
@phones ||= []
|
35
|
+
@addresses ||= []
|
36
|
+
end
|
37
|
+
|
38
|
+
def address=(address)
|
39
|
+
self.addresses = [address]
|
40
|
+
end
|
41
|
+
|
42
|
+
def address
|
43
|
+
self.addresses[0] ||= Address.new
|
44
|
+
end
|
45
|
+
|
46
|
+
# Helper method to add a new address object to this contact.
|
47
|
+
#
|
48
|
+
# Usage:
|
49
|
+
# contact.add_address({
|
50
|
+
# :address_type => 'STREET',
|
51
|
+
# :line_1 => '100 Queen Street',
|
52
|
+
# :city => 'Brisbane',
|
53
|
+
# :region => 'QLD',
|
54
|
+
# :post_code => '4000',
|
55
|
+
# :country => 'Australia'
|
56
|
+
# })
|
57
|
+
def add_address(address_params)
|
58
|
+
self.addresses << Address.new(address_params)
|
59
|
+
end
|
60
|
+
|
61
|
+
def phone=(phone)
|
62
|
+
self.phones = [phone]
|
63
|
+
end
|
64
|
+
|
65
|
+
def phone
|
66
|
+
if @phones.size > 1
|
67
|
+
@phones.detect {|p| p.phone_type == 'DEFAULT'} || phones[0]
|
68
|
+
else
|
69
|
+
@phones[0] ||= Phone.new
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Helper method to add a new phone object to this contact.
|
74
|
+
#
|
75
|
+
# Usage:
|
76
|
+
# contact.add_phone({
|
77
|
+
# :phone_type => 'MOBILE',
|
78
|
+
# :number => '0400123123'
|
79
|
+
# })
|
80
|
+
def add_phone(phone_params = {})
|
81
|
+
self.phones << Phone.new(phone_params)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Validate the Contact record according to what will be valid by the gateway.
|
85
|
+
#
|
86
|
+
# Usage:
|
87
|
+
# contact.valid? # Returns true/false
|
88
|
+
#
|
89
|
+
# Additionally sets contact.errors array to an array of field/error.
|
90
|
+
def valid?
|
91
|
+
@errors = []
|
92
|
+
|
93
|
+
if !contact_id.nil? && contact_id !~ GUID_REGEX
|
94
|
+
@errors << ['contact_id', 'must be blank or a valid Xero GUID']
|
95
|
+
end
|
96
|
+
|
97
|
+
if status && !CONTACT_STATUS[status]
|
98
|
+
@errors << ['status', "must be one of #{CONTACT_STATUS.keys.join('/')}"]
|
99
|
+
end
|
100
|
+
|
101
|
+
unless name
|
102
|
+
@errors << ['name', "can't be blank"]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Make sure all addresses are correct.
|
106
|
+
unless addresses.all? { | address | address.valid? }
|
107
|
+
@errors << ['addresses', 'at least one address is invalid']
|
108
|
+
end
|
109
|
+
|
110
|
+
# Make sure all phone numbers are correct.
|
111
|
+
unless phones.all? { | phone | phone.valid? }
|
112
|
+
@errors << ['phones', 'at least one phone is invalid']
|
113
|
+
end
|
114
|
+
|
115
|
+
@errors.size == 0
|
116
|
+
end
|
117
|
+
|
118
|
+
# General purpose create/save method.
|
119
|
+
# If contact_id and contact_number are nil then create, otherwise, attempt to save.
|
120
|
+
def save
|
121
|
+
if contact_id.nil? && contact_number.nil?
|
122
|
+
create
|
123
|
+
else
|
124
|
+
update
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Creates this contact record (using gateway.create_contact) with the associated gateway.
|
129
|
+
# If no gateway set, raise a Xero::Contact::NoGatewayError exception.
|
130
|
+
def create
|
131
|
+
raise NoGatewayError unless gateway
|
132
|
+
gateway.create_contact(self)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Creates this contact record (using gateway.update_contact) with the associated gateway.
|
136
|
+
# If no gateway set, raise a Xero::Contact::NoGatewayError exception.
|
137
|
+
def update
|
138
|
+
raise NoGatewayError unless gateway
|
139
|
+
gateway.update_contact(self)
|
140
|
+
end
|
141
|
+
|
142
|
+
def to_xml(b = Builder::XmlMarkup.new)
|
143
|
+
b.Contact {
|
144
|
+
b.ContactID self.contact_id if self.contact_id
|
145
|
+
b.ContactNumber self.contact_number if self.contact_number
|
146
|
+
b.Name self.name
|
147
|
+
b.EmailAddress self.email if self.email
|
148
|
+
b.FirstName self.first_name if self.first_name
|
149
|
+
b.LastName self.last_name if self.last_name
|
150
|
+
b.BankAccountDetails self.bank_account_details if self.bank_account_details
|
151
|
+
b.TaxNumber self.tax_number if self.tax_number
|
152
|
+
b.AccountsReceivableTaxType self.accounts_receivable_tax_type if self.accounts_receivable_tax_type
|
153
|
+
b.AccountsPayableTaxType self.accounts_payable_tax_type if self.accounts_payable_tax_type
|
154
|
+
b.ContactGroups if self.contact_groups
|
155
|
+
b.IsCustomer true if self.is_customer
|
156
|
+
b.IsSupplier true if self.is_supplier
|
157
|
+
b.DefaultCurrency if self.default_currency
|
158
|
+
b.Addresses {
|
159
|
+
addresses.each { |address| address.to_xml(b) }
|
160
|
+
}
|
161
|
+
b.Phones {
|
162
|
+
phones.each { |phone| phone.to_xml(b) }
|
163
|
+
}
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
# Take a Contact element and convert it into an Contact object
|
168
|
+
def self.from_xml(contact_element, gateway = nil)
|
169
|
+
contact = Contact.new(:gateway => gateway)
|
170
|
+
contact_element.children.each do |element|
|
171
|
+
case(element.name)
|
172
|
+
when "ContactID" then contact.contact_id = element.text
|
173
|
+
when "ContactNumber" then contact.contact_number = element.text
|
174
|
+
when "ContactStatus" then contact.status = element.text
|
175
|
+
when "Name" then contact.name = element.text
|
176
|
+
when "FirstName" then contact.first_name = element.text
|
177
|
+
when "LastName" then contact.last_name = element.text
|
178
|
+
when "EmailAddress" then contact.email = element.text
|
179
|
+
when "Addresses" then element.children.each {|address_element| contact.addresses << Address.from_xml(address_element)}
|
180
|
+
when "Phones" then element.children.each {|phone_element| contact.phones << Phone.from_xml(phone_element)}
|
181
|
+
when "FirstName" then contact.first_name = element.text
|
182
|
+
when "LastName" then contact.last_name = element.text
|
183
|
+
when "BankAccountDetails" then contact.bank_account_details = element.text
|
184
|
+
when "TaxNumber" then contact.tax_number = element.text
|
185
|
+
when "AccountsReceivableTaxType" then contact.accounts_receivable_tax_type = element.text
|
186
|
+
when "AccountsPayableTaxType" then contact.accounts_payable_tax_type = element.text
|
187
|
+
when "ContactGroups" then contact.contact_groups = element.text
|
188
|
+
when "IsCustomer" then contact.is_customer = (element.text == "true")
|
189
|
+
when "IsSupplier" then contact.is_supplier = (element.text == "true")
|
190
|
+
when "DefaultCurrency" then contact.default_currency = element.text
|
191
|
+
end
|
192
|
+
end
|
193
|
+
contact
|
194
|
+
end
|
195
|
+
|
196
|
+
def ==(other)
|
197
|
+
[ :contact_id, :contact_number, :status, :name, :first_name, :last_name, :email, :addresses, :phones, :updated_at,
|
198
|
+
:bank_account_details, :tax_number, :accounts_receivable_tax_type, :accounts_payable_tax_type, :is_customer, :is_supplier,
|
199
|
+
:default_currency, :contact_groups ].each do |field|
|
200
|
+
return false if send(field) != other.send(field)
|
201
|
+
end
|
202
|
+
return true
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
module XeroGateway
|
2
|
+
class CreditNote
|
3
|
+
include Dates
|
4
|
+
include Money
|
5
|
+
include LineItemCalculations
|
6
|
+
|
7
|
+
class NoGatewayError < Error; end
|
8
|
+
|
9
|
+
CREDIT_NOTE_TYPE = {
|
10
|
+
'ACCRECCREDIT' => 'Accounts Receivable',
|
11
|
+
'ACCPAYCREDIT' => 'Accounts Payable'
|
12
|
+
} unless defined?(CREDIT_NOTE_TYPE)
|
13
|
+
|
14
|
+
LINE_AMOUNT_TYPES = {
|
15
|
+
"Inclusive" => 'CreditNote lines are inclusive tax',
|
16
|
+
"Exclusive" => 'CreditNote lines are exclusive of tax (default)',
|
17
|
+
"NoTax" => 'CreditNotes lines have no tax'
|
18
|
+
} unless defined?(LINE_AMOUNT_TYPES)
|
19
|
+
|
20
|
+
CREDIT_NOTE_STATUS = {
|
21
|
+
'AUTHORISED' => 'Approved credit_notes awaiting payment',
|
22
|
+
'DELETED' => 'Draft credit_notes that are deleted',
|
23
|
+
'DRAFT' => 'CreditNotes saved as draft or entered via API',
|
24
|
+
'PAID' => 'CreditNotes approved and fully paid',
|
25
|
+
'SUBMITTED' => 'CreditNotes entered by an employee awaiting approval',
|
26
|
+
'VOID' => 'Approved credit_notes that are voided'
|
27
|
+
} unless defined?(CREDIT_NOTE_STATUS)
|
28
|
+
|
29
|
+
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)
|
30
|
+
|
31
|
+
# Xero::Gateway associated with this credit_note.
|
32
|
+
attr_accessor :gateway
|
33
|
+
|
34
|
+
# Any errors that occurred when the #valid? method called.
|
35
|
+
attr_reader :errors
|
36
|
+
|
37
|
+
# Represents whether the line_items have been downloaded when getting from GET /API.XRO/2.0/CreditNotes
|
38
|
+
attr_accessor :line_items_downloaded
|
39
|
+
|
40
|
+
# All accessible fields
|
41
|
+
attr_accessor :credit_note_id, :credit_note_number, :type, :status, :date, :reference, :line_amount_types, :currency_code, :line_items, :contact, :payments, :fully_paid_on, :amount_credited
|
42
|
+
|
43
|
+
|
44
|
+
def initialize(params = {})
|
45
|
+
@errors ||= []
|
46
|
+
@payments ||= []
|
47
|
+
|
48
|
+
# Check if the line items have been downloaded.
|
49
|
+
@line_items_downloaded = (params.delete(:line_items_downloaded) == true)
|
50
|
+
|
51
|
+
params = {
|
52
|
+
:line_amount_types => "Inclusive"
|
53
|
+
}.merge(params)
|
54
|
+
|
55
|
+
params.each do |k,v|
|
56
|
+
self.send("#{k}=", v)
|
57
|
+
end
|
58
|
+
|
59
|
+
@line_items ||= []
|
60
|
+
end
|
61
|
+
|
62
|
+
# Validate the Address record according to what will be valid by the gateway.
|
63
|
+
#
|
64
|
+
# Usage:
|
65
|
+
# address.valid? # Returns true/false
|
66
|
+
#
|
67
|
+
# Additionally sets address.errors array to an array of field/error.
|
68
|
+
def valid?
|
69
|
+
@errors = []
|
70
|
+
|
71
|
+
if !credit_note_id.nil? && credit_note_id !~ GUID_REGEX
|
72
|
+
@errors << ['credit_note_id', 'must be blank or a valid Xero GUID']
|
73
|
+
end
|
74
|
+
|
75
|
+
if status && !CREDIT_NOTE_STATUS[status]
|
76
|
+
@errors << ['status', "must be one of #{CREDIT_NOTE_STATUS.keys.join('/')}"]
|
77
|
+
end
|
78
|
+
|
79
|
+
if line_amount_types && !LINE_AMOUNT_TYPES[line_amount_types]
|
80
|
+
@errors << ['line_amount_types', "must be one of #{LINE_AMOUNT_TYPES.keys.join('/')}"]
|
81
|
+
end
|
82
|
+
|
83
|
+
unless date
|
84
|
+
@errors << ['credit_note_date', "can't be blank"]
|
85
|
+
end
|
86
|
+
|
87
|
+
# Make sure contact is valid.
|
88
|
+
unless @contact && @contact.valid?
|
89
|
+
@errors << ['contact', 'is invalid']
|
90
|
+
end
|
91
|
+
|
92
|
+
# Make sure all line_items are valid.
|
93
|
+
unless line_items.all? { | line_item | line_item.valid? }
|
94
|
+
@errors << ['line_items', "at least one line item invalid"]
|
95
|
+
end
|
96
|
+
|
97
|
+
@errors.size == 0
|
98
|
+
end
|
99
|
+
|
100
|
+
# Helper method to create the associated contact object.
|
101
|
+
def build_contact(params = {})
|
102
|
+
self.contact = gateway ? gateway.build_contact(params) : Contact.new(params)
|
103
|
+
end
|
104
|
+
|
105
|
+
def contact
|
106
|
+
@contact ||= build_contact
|
107
|
+
end
|
108
|
+
|
109
|
+
# Helper method to check if the credit_note is accounts payable.
|
110
|
+
def accounts_payable?
|
111
|
+
type == 'ACCPAYCREDIT'
|
112
|
+
end
|
113
|
+
|
114
|
+
# Helper method to check if the credit_note is accounts receivable.
|
115
|
+
def accounts_receivable?
|
116
|
+
type == 'ACCRECCREDIT'
|
117
|
+
end
|
118
|
+
|
119
|
+
# Whether or not the line_items have been downloaded (GET/credit_notes does not download line items).
|
120
|
+
def line_items_downloaded?
|
121
|
+
@line_items_downloaded
|
122
|
+
end
|
123
|
+
|
124
|
+
# If line items are not downloaded, then attempt a download now (if this record was found to begin with).
|
125
|
+
def line_items
|
126
|
+
if line_items_downloaded?
|
127
|
+
@line_items
|
128
|
+
|
129
|
+
# There is an credit_note_is so we can assume this record was loaded from Xero.
|
130
|
+
# attempt to download the line_item records.
|
131
|
+
elsif credit_note_id =~ GUID_REGEX
|
132
|
+
raise NoGatewayError unless @gateway
|
133
|
+
|
134
|
+
response = @gateway.get_credit_note(credit_note_id)
|
135
|
+
raise CreditNoteNotFoundError, "CreditNote with ID #{credit_note_id} not found in Xero." unless response.success? && response.credit_note.is_a?(XeroGateway::CreditNote)
|
136
|
+
|
137
|
+
@line_items = response.credit_note.line_items
|
138
|
+
@line_items_downloaded = true
|
139
|
+
|
140
|
+
@line_items
|
141
|
+
|
142
|
+
# Otherwise, this is a new credit_note, so return the line_items reference.
|
143
|
+
else
|
144
|
+
@line_items
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def ==(other)
|
149
|
+
["credit_note_number", "type", "status", "reference", "currency_code", "line_amount_types", "contact", "line_items"].each do |field|
|
150
|
+
return false if send(field) != other.send(field)
|
151
|
+
end
|
152
|
+
|
153
|
+
["date"].each do |field|
|
154
|
+
return false if send(field).to_s != other.send(field).to_s
|
155
|
+
end
|
156
|
+
return true
|
157
|
+
end
|
158
|
+
|
159
|
+
# General purpose createsave method.
|
160
|
+
# If contact_id and contact_number are nil then create, otherwise, attempt to save.
|
161
|
+
def save
|
162
|
+
create
|
163
|
+
end
|
164
|
+
|
165
|
+
# Creates this credit_note record (using gateway.create_credit_note) with the associated gateway.
|
166
|
+
# If no gateway set, raise a Xero::CreditNote::NoGatewayError exception.
|
167
|
+
def create
|
168
|
+
raise NoGatewayError unless gateway
|
169
|
+
gateway.create_credit_note(self)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Alias create as save as this is currently the only write action.
|
173
|
+
alias_method :save, :create
|
174
|
+
|
175
|
+
def to_xml(b = Builder::XmlMarkup.new)
|
176
|
+
b.CreditNote {
|
177
|
+
b.Type self.type
|
178
|
+
contact.to_xml(b)
|
179
|
+
b.Date CreditNote.format_date(self.date || Date.today)
|
180
|
+
b.Status self.status if self.status
|
181
|
+
b.CreditNoteNumber self.credit_note_number if credit_note_number
|
182
|
+
b.Reference self.reference if self.reference
|
183
|
+
b.CurrencyCode self.currency_code if self.currency_code
|
184
|
+
b.LineAmountTypes self.line_amount_types
|
185
|
+
b.LineItems {
|
186
|
+
self.line_items.each do |line_item|
|
187
|
+
line_item.to_xml(b)
|
188
|
+
end
|
189
|
+
}
|
190
|
+
}
|
191
|
+
end
|
192
|
+
|
193
|
+
#TODO UpdatedDateUTC
|
194
|
+
def self.from_xml(credit_note_element, gateway = nil, options = {})
|
195
|
+
credit_note = CreditNote.new(options.merge({:gateway => gateway}))
|
196
|
+
credit_note_element.children.each do |element|
|
197
|
+
case(element.name)
|
198
|
+
when "CreditNoteID" then credit_note.credit_note_id = element.text
|
199
|
+
when "CreditNoteNumber" then credit_note.credit_note_number = element.text
|
200
|
+
when "Type" then credit_note.type = element.text
|
201
|
+
when "CurrencyCode" then credit_note.currency_code = element.text
|
202
|
+
when "Contact" then credit_note.contact = Contact.from_xml(element)
|
203
|
+
when "Date" then credit_note.date = parse_date(element.text)
|
204
|
+
when "Status" then credit_note.status = element.text
|
205
|
+
when "Reference" then credit_note.reference = element.text
|
206
|
+
when "LineAmountTypes" then credit_note.line_amount_types = element.text
|
207
|
+
when "LineItems" then element.children.each {|line_item| credit_note.line_items_downloaded = true; credit_note.line_items << LineItem.from_xml(line_item) }
|
208
|
+
when "SubTotal" then credit_note.sub_total = BigDecimal.new(element.text)
|
209
|
+
when "TotalTax" then credit_note.total_tax = BigDecimal.new(element.text)
|
210
|
+
when "Total" then credit_note.total = BigDecimal.new(element.text)
|
211
|
+
when "CreditNoteID" then credit_note.credit_note_id = element.text
|
212
|
+
when "CreditNoteNumber" then credit_note.credit_note_number = element.text
|
213
|
+
when "Payments" then element.children.each { | payment | credit_note.payments << Payment.from_xml(payment) }
|
214
|
+
when "AmountDue" then credit_note.amount_due = BigDecimal.new(element.text)
|
215
|
+
when "AmountPaid" then credit_note.amount_paid = BigDecimal.new(element.text)
|
216
|
+
when "AmountCredited" then credit_note.amount_credited = BigDecimal.new(element.text)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
credit_note
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module XeroGateway
|
2
|
+
class Currency
|
3
|
+
|
4
|
+
unless defined? ATTRS
|
5
|
+
ATTRS = {
|
6
|
+
"Code" => :string, # 3 letter alpha code for the currency – see list of currency codes
|
7
|
+
"Description" => :string, # Name of Currency
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor *ATTRS.keys.map(&:underscore)
|
12
|
+
|
13
|
+
def initialize(params = {})
|
14
|
+
params.each do |k,v|
|
15
|
+
self.send("#{k}=", v)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def ==(other)
|
20
|
+
ATTRS.keys.map(&:underscore).each do |field|
|
21
|
+
return false if send(field) != other.send(field)
|
22
|
+
end
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_xml
|
27
|
+
b = Builder::XmlMarkup.new
|
28
|
+
|
29
|
+
b.Currency do
|
30
|
+
ATTRS.keys.each do |attr|
|
31
|
+
eval("b.#{attr} '#{self.send(attr.underscore.to_sym)}'")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_xml(currency_element)
|
37
|
+
Currency.new.tap do |currency|
|
38
|
+
currency_element.children.each do |element|
|
39
|
+
|
40
|
+
attribute = element.name
|
41
|
+
underscored_attribute = element.name.underscore
|
42
|
+
|
43
|
+
raise "Unknown attribute: #{attribute}" unless ATTRS.keys.include?(attribute)
|
44
|
+
|
45
|
+
case (ATTRS[attribute])
|
46
|
+
when :boolean then currency.send("#{underscored_attribute}=", (element.text == "true"))
|
47
|
+
when :float then currency.send("#{underscored_attribute}=", element.text.to_f)
|
48
|
+
else currency.send("#{underscored_attribute}=", element.text)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|