xero_gateway 2.0.13 → 2.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -1
- data/README.textile +10 -7
- data/Rakefile +1 -1
- data/lib/xero_gateway.rb +2 -0
- data/lib/xero_gateway/account.rb +5 -5
- data/lib/xero_gateway/address.rb +2 -3
- data/lib/xero_gateway/bank_transaction.rb +175 -0
- data/lib/xero_gateway/contact.rb +1 -1
- data/lib/xero_gateway/credit_note.rb +1 -54
- data/lib/xero_gateway/exceptions.rb +1 -1
- data/lib/xero_gateway/gateway.rb +104 -0
- data/lib/xero_gateway/invoice.rb +8 -61
- data/lib/xero_gateway/line_item_calculations.rb +55 -0
- data/lib/xero_gateway/response.rb +13 -11
- data/test/integration/create_bank_transaction_test.rb +38 -0
- data/test/integration/get_bank_transaction_test.rb +50 -0
- data/test/integration/get_bank_transactions_test.rb +88 -0
- data/test/integration/update_bank_transaction_test.rb +31 -0
- data/test/test_helper.rb +76 -1
- data/test/unit/account_test.rb +15 -3
- data/test/unit/bank_transaction_test.rb +114 -0
- data/test/unit/invoice_test.rb +48 -29
- data/test/unit/oauth_test.rb +13 -4
- data/xero_gateway.gemspec +2 -2
- metadata +48 -75
data/Gemfile
CHANGED
data/README.textile
CHANGED
@@ -222,14 +222,17 @@ Invoice and line item totals are calculated automatically.
|
|
222
222
|
})
|
223
223
|
invoice.contact.name = "THE NAME OF THE CONTACT"
|
224
224
|
invoice.contact.phone.number = "12345"
|
225
|
-
invoice.contact.address.line_1 = "LINE 1 OF THE ADDRESS"
|
226
|
-
|
225
|
+
invoice.contact.address.line_1 = "LINE 1 OF THE ADDRESS"
|
226
|
+
|
227
|
+
line_item = XeroGateway::LineItem.new(
|
227
228
|
:description => "THE DESCRIPTION OF THE LINE ITEM",
|
228
|
-
:
|
229
|
-
:
|
230
|
-
|
231
|
-
|
232
|
-
|
229
|
+
:account_code => 200,
|
230
|
+
:unit_amount => 1000
|
231
|
+
)
|
232
|
+
|
233
|
+
line_item.tracking << XeroGateway::TrackingCategory.new(:name => "tracking category", :options => "tracking option")
|
234
|
+
|
235
|
+
invoice.line_items << line_item
|
233
236
|
|
234
237
|
invoice.create</code></pre>
|
235
238
|
|
data/Rakefile
CHANGED
data/lib/xero_gateway.rb
CHANGED
@@ -15,6 +15,7 @@ require File.join(File.dirname(__FILE__), 'xero_gateway', 'http_encoding_helper'
|
|
15
15
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'http')
|
16
16
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'dates')
|
17
17
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'money')
|
18
|
+
require File.join(File.dirname(__FILE__), 'xero_gateway', 'line_item_calculations')
|
18
19
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'response')
|
19
20
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'account')
|
20
21
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'accounts_list')
|
@@ -23,6 +24,7 @@ require File.join(File.dirname(__FILE__), 'xero_gateway', 'contact')
|
|
23
24
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'line_item')
|
24
25
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'payment')
|
25
26
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'invoice')
|
27
|
+
require File.join(File.dirname(__FILE__), 'xero_gateway', 'bank_transaction')
|
26
28
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'credit_note')
|
27
29
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'address')
|
28
30
|
require File.join(File.dirname(__FILE__), 'xero_gateway', 'phone')
|
data/lib/xero_gateway/account.rb
CHANGED
@@ -35,7 +35,7 @@ module XeroGateway
|
|
35
35
|
'ZERORATED' => 'Zero-rated supplies/sales from overseas (NZ Only)'
|
36
36
|
} unless defined?(TAX_TYPE)
|
37
37
|
|
38
|
-
attr_accessor :account_id, :code, :name, :type, :tax_type, :description, :system_account, :enable_payments_to_account
|
38
|
+
attr_accessor :account_id, :code, :name, :type, :tax_type, :description, :system_account, :enable_payments_to_account, :currency_code
|
39
39
|
|
40
40
|
def initialize(params = {})
|
41
41
|
params.each do |k,v|
|
@@ -50,10 +50,8 @@ module XeroGateway
|
|
50
50
|
return true
|
51
51
|
end
|
52
52
|
|
53
|
-
def to_xml
|
54
|
-
b
|
55
|
-
|
56
|
-
b.Account {
|
53
|
+
def to_xml(b = Builder::XmlMarkup.new, options={})
|
54
|
+
b.tag!(options[:name] ? options[:name] : 'Account') {
|
57
55
|
b.AccountID self.account_id
|
58
56
|
b.Code self.code
|
59
57
|
b.Name self.name
|
@@ -62,6 +60,7 @@ module XeroGateway
|
|
62
60
|
b.Description self.description
|
63
61
|
b.SystemAccount self.system_account unless self.system_account.nil?
|
64
62
|
b.EnablePaymentsToAccount self.enable_payments_to_account
|
63
|
+
b.CurrencyCode currency_code if currency_code
|
65
64
|
}
|
66
65
|
end
|
67
66
|
|
@@ -77,6 +76,7 @@ module XeroGateway
|
|
77
76
|
when "Description" then account.description = element.text
|
78
77
|
when "SystemAccount" then account.system_account = element.text
|
79
78
|
when "EnablePaymentsToAccount" then account.enable_payments_to_account = (element.text == 'true')
|
79
|
+
when "CurrencyCode" then account.currency_code = element.text
|
80
80
|
end
|
81
81
|
end
|
82
82
|
account
|
data/lib/xero_gateway/address.rb
CHANGED
@@ -3,8 +3,7 @@ module XeroGateway
|
|
3
3
|
|
4
4
|
ADDRESS_TYPE = {
|
5
5
|
'STREET' => 'Street',
|
6
|
-
'POBOX' => 'PO Box'
|
7
|
-
'DEFAULT' => 'Default address type'
|
6
|
+
'POBOX' => 'PO Box'
|
8
7
|
} unless defined?(ADDRESS_TYPE)
|
9
8
|
|
10
9
|
# Any errors that occurred when the #valid? method called.
|
@@ -16,7 +15,7 @@ module XeroGateway
|
|
16
15
|
@errors ||= []
|
17
16
|
|
18
17
|
params = {
|
19
|
-
:address_type => "
|
18
|
+
:address_type => "POBOX"
|
20
19
|
}.merge(params)
|
21
20
|
|
22
21
|
params.each do |k,v|
|
@@ -0,0 +1,175 @@
|
|
1
|
+
module XeroGateway
|
2
|
+
class BankTransaction
|
3
|
+
include Dates
|
4
|
+
include LineItemCalculations
|
5
|
+
|
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
|
+
TYPES = {
|
11
|
+
'RECEIVE' => 'Receive Bank Transaction',
|
12
|
+
'SPEND' => 'Spend Bank Transaction',
|
13
|
+
} unless defined?(TYPES)
|
14
|
+
|
15
|
+
STATUSES = {
|
16
|
+
'ACTIVE' => 'Bank Transaction is active',
|
17
|
+
'DELETED' => 'Bank Transaction is deleted',
|
18
|
+
} unless defined?(STATUSES)
|
19
|
+
|
20
|
+
# Xero::Gateway associated with this invoice.
|
21
|
+
attr_accessor :gateway
|
22
|
+
|
23
|
+
# Any errors that occurred when the #valid? method called.
|
24
|
+
attr_reader :errors
|
25
|
+
|
26
|
+
# Represents whether the line_items have been downloaded when getting from GET /API.XRO/2.0/BankTransactions
|
27
|
+
attr_accessor :line_items_downloaded
|
28
|
+
|
29
|
+
# accessible fields
|
30
|
+
attr_accessor :bank_transaction_id, :type, :date, :reference, :status, :contact, :line_items, :bank_account, :url
|
31
|
+
|
32
|
+
def initialize(params = {})
|
33
|
+
@errors ||= []
|
34
|
+
@payments ||= []
|
35
|
+
|
36
|
+
# Check if the line items have been downloaded.
|
37
|
+
@line_items_downloaded = (params.delete(:line_items_downloaded) == true)
|
38
|
+
|
39
|
+
# params = {
|
40
|
+
# :line_amount_types => "Exclusive"
|
41
|
+
# }.merge(params)
|
42
|
+
params.each do |k,v|
|
43
|
+
self.send("#{k}=", v)
|
44
|
+
end
|
45
|
+
|
46
|
+
@line_items ||= []
|
47
|
+
end
|
48
|
+
|
49
|
+
def ==(other)
|
50
|
+
['type', 'reference', 'status', 'contact', 'line_items', 'bank_account'].each do |field|
|
51
|
+
return false if send(field) != other.send(field)
|
52
|
+
end
|
53
|
+
|
54
|
+
["date"].each do |field|
|
55
|
+
return false if send(field).to_s != other.send(field).to_s
|
56
|
+
end
|
57
|
+
return true
|
58
|
+
end
|
59
|
+
|
60
|
+
# Validate the BankTransaction record according to what will be valid by the gateway.
|
61
|
+
#
|
62
|
+
# Usage:
|
63
|
+
# bank_transaction.valid? # Returns true/false
|
64
|
+
#
|
65
|
+
# Additionally sets bank_transaction.errors array to an array of field/error.
|
66
|
+
def valid?
|
67
|
+
@errors = []
|
68
|
+
|
69
|
+
if !bank_transaction_id.nil? && bank_transaction_id !~ GUID_REGEX
|
70
|
+
@errors << ['bank_transaction_id', 'must be blank or a valid Xero GUID']
|
71
|
+
end
|
72
|
+
|
73
|
+
if type && !TYPES[type]
|
74
|
+
@errors << ['type', "must be one of #{TYPES.keys.join('/')}"]
|
75
|
+
end
|
76
|
+
|
77
|
+
if status && !STATUSES[status]
|
78
|
+
@errors << ['status', "must be one of #{STATUSES.keys.join('/')}"]
|
79
|
+
end
|
80
|
+
|
81
|
+
unless date
|
82
|
+
@errors << ['date', "can't be blank"]
|
83
|
+
end
|
84
|
+
|
85
|
+
# Make sure contact is valid.
|
86
|
+
unless @contact && @contact.valid?
|
87
|
+
@errors << ['contact', 'is invalid']
|
88
|
+
end
|
89
|
+
|
90
|
+
# Make sure all line_items are valid.
|
91
|
+
unless line_items.all? { | line_item | line_item.valid? }
|
92
|
+
@errors << ['line_items', "at least one line item invalid"]
|
93
|
+
end
|
94
|
+
|
95
|
+
@errors.size == 0
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def line_items_downloaded?
|
100
|
+
@line_items_downloaded
|
101
|
+
end
|
102
|
+
|
103
|
+
# If line items are not downloaded, then attempt a download now (if this record was found to begin with).
|
104
|
+
def line_items
|
105
|
+
if line_items_downloaded?
|
106
|
+
@line_items
|
107
|
+
|
108
|
+
elsif bank_transaction_id =~ GUID_REGEX && @gateway
|
109
|
+
# There is a bank_transaction_id so we can assume this record was loaded from Xero.
|
110
|
+
# Let's attempt to download the line_item records (if there is a gateway)
|
111
|
+
|
112
|
+
response = @gateway.get_bank_transaction(bank_transaction_id)
|
113
|
+
raise BankTransactionNotFoundError, "Bank Transaction with ID #{bank_transaction_id} not found in Xero." unless response.success? && response.bank_transaction.is_a?(XeroGateway::BankTransaction)
|
114
|
+
|
115
|
+
@line_items = response.bank_transaction.line_items
|
116
|
+
@line_items_downloaded = true
|
117
|
+
|
118
|
+
@line_items
|
119
|
+
|
120
|
+
# Otherwise, this is a new bank transaction, so return the line_items reference.
|
121
|
+
else
|
122
|
+
@line_items
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_xml(b = Builder::XmlMarkup.new)
|
127
|
+
b.BankTransaction {
|
128
|
+
b.BankTransactionID bank_transaction_id if bank_transaction_id
|
129
|
+
b.Type type
|
130
|
+
# b.CurrencyCode self.currency_code if self.currency_code
|
131
|
+
contact.to_xml(b)
|
132
|
+
bank_account.to_xml(b, :name => 'BankAccount')
|
133
|
+
b.Date BankTransaction.format_date(date || Date.today)
|
134
|
+
b.Status status if status
|
135
|
+
b.Reference reference if reference
|
136
|
+
b.LineItems {
|
137
|
+
self.line_items.each do |line_item|
|
138
|
+
line_item.to_xml(b)
|
139
|
+
end
|
140
|
+
}
|
141
|
+
b.Url url if url
|
142
|
+
}
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.from_xml(bank_transaction_element, gateway = nil, options = {})
|
146
|
+
bank_transaction = BankTransaction.new(options.merge({:gateway => gateway}))
|
147
|
+
bank_transaction_element.children.each do |element|
|
148
|
+
case(element.name)
|
149
|
+
when "BankTransactionID" then bank_transaction.bank_transaction_id = element.text
|
150
|
+
when "Type" then bank_transaction.type = element.text
|
151
|
+
# when "CurrencyCode" then invoice.currency_code = element.text
|
152
|
+
when "Contact" then bank_transaction.contact = Contact.from_xml(element)
|
153
|
+
when "BankAccount" then bank_transaction.bank_account = Account.from_xml(element)
|
154
|
+
when "Date" then bank_transaction.date = parse_date(element.text)
|
155
|
+
when "Status" then bank_transaction.status = element.text
|
156
|
+
when "Reference" then bank_transaction.reference = element.text
|
157
|
+
when "LineItems" then element.children.each {|line_item| bank_transaction.line_items_downloaded = true; bank_transaction.line_items << LineItem.from_xml(line_item) }
|
158
|
+
# when "SubTotal" then invoice.sub_total = BigDecimal.new(element.text)
|
159
|
+
# when "TotalTax" then invoice.total_tax = BigDecimal.new(element.text)
|
160
|
+
# when "Total" then invoice.total = BigDecimal.new(element.text)
|
161
|
+
# when "InvoiceID" then invoice.invoice_id = element.text
|
162
|
+
# when "InvoiceNumber" then invoice.invoice_number = element.text
|
163
|
+
# when "Payments" then element.children.each { | payment | invoice.payments << Payment.from_xml(payment) }
|
164
|
+
# when "AmountDue" then invoice.amount_due = BigDecimal.new(element.text)
|
165
|
+
# when "AmountPaid" then invoice.amount_paid = BigDecimal.new(element.text)
|
166
|
+
# when "AmountCredited" then invoice.amount_credited = BigDecimal.new(element.text)
|
167
|
+
# when "SentToContact" then invoice.sent_to_contact = (element.text.strip.downcase == "true")
|
168
|
+
when "Url" then bank_transaction.url = element.text
|
169
|
+
end
|
170
|
+
end
|
171
|
+
bank_transaction
|
172
|
+
end # from_xml
|
173
|
+
|
174
|
+
end
|
175
|
+
end
|
data/lib/xero_gateway/contact.rb
CHANGED
@@ -109,7 +109,7 @@ module XeroGateway
|
|
109
109
|
|
110
110
|
# Make sure all phone numbers are correct.
|
111
111
|
unless phones.all? { | phone | phone.valid? }
|
112
|
-
@errors << ['phones', 'at
|
112
|
+
@errors << ['phones', 'at least one phone is invalid']
|
113
113
|
end
|
114
114
|
|
115
115
|
@errors.size == 0
|
@@ -2,10 +2,9 @@ module XeroGateway
|
|
2
2
|
class CreditNote
|
3
3
|
include Dates
|
4
4
|
include Money
|
5
|
+
include LineItemCalculations
|
5
6
|
|
6
|
-
class Error < RuntimeError; end
|
7
7
|
class NoGatewayError < Error; end
|
8
|
-
class InvalidLineItemError < Error; end
|
9
8
|
|
10
9
|
CREDIT_NOTE_TYPE = {
|
11
10
|
'ACCRECCREDIT' => 'Accounts Receivable',
|
@@ -107,58 +106,6 @@ module XeroGateway
|
|
107
106
|
@contact ||= build_contact
|
108
107
|
end
|
109
108
|
|
110
|
-
# Helper method to create a new associated line_item.
|
111
|
-
# Usage:
|
112
|
-
# credit_note.add_line_item({:description => "Bob's Widgets", :quantity => 1, :unit_amount => 120})
|
113
|
-
def add_line_item(params = {})
|
114
|
-
line_item = nil
|
115
|
-
case params
|
116
|
-
when Hash then line_item = LineItem.new(params)
|
117
|
-
when LineItem then line_item = params
|
118
|
-
else raise InvalidLineItemError
|
119
|
-
end
|
120
|
-
|
121
|
-
@line_items << line_item
|
122
|
-
|
123
|
-
line_item
|
124
|
-
end
|
125
|
-
|
126
|
-
# Deprecated (but API for setter remains).
|
127
|
-
#
|
128
|
-
# As sub_total must equal SUM(line_item.line_amount) for the API call to pass, this is now
|
129
|
-
# automatically calculated in the sub_total method.
|
130
|
-
def sub_total=(value)
|
131
|
-
end
|
132
|
-
|
133
|
-
# Calculate the sub_total as the SUM(line_item.line_amount).
|
134
|
-
def sub_total
|
135
|
-
line_items.inject(BigDecimal.new('0')) { | sum, line_item | sum + BigDecimal.new(line_item.line_amount.to_s) }
|
136
|
-
end
|
137
|
-
|
138
|
-
# Deprecated (but API for setter remains).
|
139
|
-
#
|
140
|
-
# As total_tax must equal SUM(line_item.tax_amount) for the API call to pass, this is now
|
141
|
-
# automatically calculated in the total_tax method.
|
142
|
-
def total_tax=(value)
|
143
|
-
end
|
144
|
-
|
145
|
-
# Calculate the total_tax as the SUM(line_item.tax_amount).
|
146
|
-
def total_tax
|
147
|
-
line_items.inject(BigDecimal.new('0')) { | sum, line_item | sum + BigDecimal.new(line_item.tax_amount.to_s) }
|
148
|
-
end
|
149
|
-
|
150
|
-
# Deprecated (but API for setter remains).
|
151
|
-
#
|
152
|
-
# As total must equal sub_total + total_tax for the API call to pass, this is now
|
153
|
-
# automatically calculated in the total method.
|
154
|
-
def total=(value)
|
155
|
-
end
|
156
|
-
|
157
|
-
# Calculate the toal as sub_total + total_tax.
|
158
|
-
def total
|
159
|
-
sub_total + total_tax
|
160
|
-
end
|
161
|
-
|
162
109
|
# Helper method to check if the credit_note is accounts payable.
|
163
110
|
def accounts_payable?
|
164
111
|
type == 'ACCPAYCREDIT'
|
data/lib/xero_gateway/gateway.rb
CHANGED
@@ -349,6 +349,75 @@ module XeroGateway
|
|
349
349
|
response
|
350
350
|
end
|
351
351
|
|
352
|
+
# Creates a bank transaction in Xero based on a bank transaction object.
|
353
|
+
#
|
354
|
+
# Bank transaction and line item totals are calculated automatically.
|
355
|
+
#
|
356
|
+
# Usage :
|
357
|
+
#
|
358
|
+
# bank_transaction = XeroGateway::BankTransaction.new({
|
359
|
+
# :type => "RECEIVE",
|
360
|
+
# :date => 1.month.from_now,
|
361
|
+
# :reference => "YOUR INVOICE NUMBER",
|
362
|
+
# })
|
363
|
+
# bank_transaction.contact = XeroGateway::Contact.new(:name => "THE NAME OF THE CONTACT")
|
364
|
+
# bank_transaction.contact.phone.number = "12345"
|
365
|
+
# bank_transaction.contact.address.line_1 = "LINE 1 OF THE ADDRESS"
|
366
|
+
# bank_transaction.line_items << XeroGateway::LineItem.new(
|
367
|
+
# :description => "THE DESCRIPTION OF THE LINE ITEM",
|
368
|
+
# :unit_amount => 100,
|
369
|
+
# :tax_amount => 12.5,
|
370
|
+
# :tracking_category => "THE TRACKING CATEGORY FOR THE LINE ITEM",
|
371
|
+
# :tracking_option => "THE TRACKING OPTION FOR THE LINE ITEM"
|
372
|
+
# )
|
373
|
+
# bank_transaction.bank_account = XeroGateway::Account.new(:code => 'BANK-ABC)
|
374
|
+
#
|
375
|
+
# create_bank_transaction(bank_transaction)
|
376
|
+
def create_bank_transaction(bank_transaction)
|
377
|
+
save_bank_transaction(bank_transaction)
|
378
|
+
end
|
379
|
+
|
380
|
+
#
|
381
|
+
# Updates an existing Xero bank transaction
|
382
|
+
#
|
383
|
+
# Usage :
|
384
|
+
#
|
385
|
+
# bank_transaction = xero_gateway.get_bank_transaction(some_bank_transaction_id)
|
386
|
+
# bank_transaction.due_date = Date.today
|
387
|
+
#
|
388
|
+
# xero_gateway.update_bank_transaction(bank_transaction)
|
389
|
+
def update_bank_transaction(bank_transaction)
|
390
|
+
raise "bank_transaction_id is required for updating bank transactions" if bank_transaction.bank_transaction_id.nil?
|
391
|
+
save_bank_transaction(bank_transaction)
|
392
|
+
end
|
393
|
+
|
394
|
+
# Retrieves all bank transactions from Xero
|
395
|
+
#
|
396
|
+
# Usage : get_bank_transactions
|
397
|
+
# get_bank_transactions(:bank_transaction_id => " 297c2dc5-cc47-4afd-8ec8-74990b8761e9")
|
398
|
+
#
|
399
|
+
# Note : modified_since is in UTC format (i.e. Brisbane is UTC+10)
|
400
|
+
def get_bank_transactions(options = {})
|
401
|
+
request_params = {}
|
402
|
+
request_params[:BankTransactionID] = options[:bank_transaction_id] if options[:bank_transaction_id]
|
403
|
+
request_params[:ModifiedAfter] = options[:modified_since] if options[:modified_since]
|
404
|
+
|
405
|
+
response_xml = http_get(@client, "#{@xero_url}/BankTransactions", request_params)
|
406
|
+
|
407
|
+
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/BankTransactions'})
|
408
|
+
end
|
409
|
+
|
410
|
+
# Retrieves a single bank transaction
|
411
|
+
#
|
412
|
+
# Usage : get_bank_transaction("297c2dc5-cc47-4afd-8ec8-74990b8761e9") # By ID
|
413
|
+
# get_bank_transaction("OIT-12345") # By number
|
414
|
+
def get_bank_transaction(bank_transaction_id)
|
415
|
+
request_params = {}
|
416
|
+
url = "#{@xero_url}/BankTransactions/#{URI.escape(bank_transaction_id)}"
|
417
|
+
response_xml = http_get(@client, url, request_params)
|
418
|
+
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/BankTransaction'})
|
419
|
+
end
|
420
|
+
|
352
421
|
#
|
353
422
|
# Gets all accounts for a specific organization in Xero.
|
354
423
|
#
|
@@ -457,6 +526,35 @@ module XeroGateway
|
|
457
526
|
response
|
458
527
|
end
|
459
528
|
|
529
|
+
# Create or update a bank transaction record based on if it has an bank_transaction_id.
|
530
|
+
def save_bank_transaction(bank_transaction)
|
531
|
+
request_xml = bank_transaction.to_xml
|
532
|
+
response_xml = nil
|
533
|
+
create_or_save = nil
|
534
|
+
|
535
|
+
if bank_transaction.bank_transaction_id.nil?
|
536
|
+
# Create new bank transaction record.
|
537
|
+
response_xml = http_put(@client, "#{@xero_url}/BankTransactions", request_xml, {})
|
538
|
+
create_or_save = :create
|
539
|
+
else
|
540
|
+
# Update existing bank transaction record.
|
541
|
+
response_xml = http_post(@client, "#{@xero_url}/BankTransactions", request_xml, {})
|
542
|
+
create_or_save = :save
|
543
|
+
end
|
544
|
+
|
545
|
+
response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => "#{create_or_save == :create ? 'PUT' : 'POST'}/BankTransactions"})
|
546
|
+
|
547
|
+
# Xero returns bank transactions inside an <BankTransactions> tag, even though there's only ever
|
548
|
+
# one for this request
|
549
|
+
response.response_item = response.bank_transactions.first
|
550
|
+
|
551
|
+
if response.success? && response.bank_transaction && response.bank_transaction.bank_transaction_id
|
552
|
+
bank_transaction.bank_transaction_id = response.bank_transaction.bank_transaction_id
|
553
|
+
end
|
554
|
+
|
555
|
+
response
|
556
|
+
end
|
557
|
+
|
460
558
|
def parse_response(raw_response, request = {}, options = {})
|
461
559
|
|
462
560
|
response = XeroGateway::Response.new
|
@@ -476,8 +574,14 @@ module XeroGateway
|
|
476
574
|
when "DateTimeUTC" then response.date_time = element.text
|
477
575
|
when "Contact" then response.response_item = Contact.from_xml(element, self)
|
478
576
|
when "Invoice" then response.response_item = Invoice.from_xml(element, self, {:line_items_downloaded => options[:request_signature] != "GET/Invoices"})
|
577
|
+
when "BankTransaction"
|
578
|
+
response.response_item = BankTransaction.from_xml(element, self, {:line_items_downloaded => options[:request_signature] != "GET/BankTransactions"})
|
479
579
|
when "Contacts" then element.children.each {|child| response.response_item << Contact.from_xml(child, self) }
|
480
580
|
when "Invoices" then element.children.each {|child| response.response_item << Invoice.from_xml(child, self, {:line_items_downloaded => options[:request_signature] != "GET/Invoices"}) }
|
581
|
+
when "BankTransactions"
|
582
|
+
element.children.each do |child|
|
583
|
+
response.response_item << BankTransaction.from_xml(child, self, {:line_items_downloaded => options[:request_signature] != "GET/BankTransactions"})
|
584
|
+
end
|
481
585
|
when "CreditNotes" then element.children.each {|child| response.response_item << CreditNote.from_xml(child, self, {:line_items_downloaded => options[:request_signature] != "GET/CreditNotes"}) }
|
482
586
|
when "Accounts" then element.children.each {|child| response.response_item << Account.from_xml(child) }
|
483
587
|
when "TaxRates" then element.children.each {|child| response.response_item << TaxRate.from_xml(child) }
|