xero_gateway-float 2.0.18 → 2.1.1
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/Rakefile +7 -1
- data/examples/partner_app.rb +2 -2
- data/lib/xero_gateway/accounts_list.rb +0 -4
- data/lib/xero_gateway/bank_transaction.rb +0 -2
- data/lib/xero_gateway/contact.rb +6 -9
- data/lib/xero_gateway/credit_note.rb +1 -3
- data/lib/xero_gateway/error.rb +16 -0
- data/lib/xero_gateway/exceptions.rb +5 -0
- data/lib/xero_gateway/gateway.rb +184 -82
- data/lib/xero_gateway/http.rb +38 -32
- data/lib/xero_gateway/invoice.rb +17 -9
- data/lib/xero_gateway/journal_line.rb +102 -0
- data/lib/xero_gateway/line_item_calculations.rb +0 -4
- data/lib/xero_gateway/manual_journal.rb +163 -0
- data/lib/xero_gateway/oauth.rb +29 -23
- data/lib/xero_gateway/partner_app.rb +6 -1
- data/lib/xero_gateway/response.rb +2 -0
- data/lib/xero_gateway/tax_rate.rb +1 -1
- data/lib/xero_gateway.rb +3 -0
- data/test/integration/accounts_list_test.rb +4 -4
- data/test/integration/create_invoice_test.rb +6 -0
- data/test/integration/create_manual_journal_test.rb +35 -0
- data/test/integration/create_payments_test.rb +35 -0
- data/test/integration/get_invoice_test.rb +27 -12
- data/test/integration/get_manual_journal_test.rb +50 -0
- data/test/integration/get_manual_journals_test.rb +88 -0
- data/test/integration/update_manual_journal_test.rb +31 -0
- data/test/test_helper.rb +39 -1
- data/test/unit/bank_transaction_test.rb +1 -1
- data/test/unit/credit_note_test.rb +1 -1
- data/test/unit/gateway_test.rb +15 -15
- data/test/unit/invoice_test.rb +3 -2
- data/test/unit/manual_journal_test.rb +93 -0
- data/test/unit/payment_test.rb +34 -0
- data/xero_gateway.gemspec +2 -2
- metadata +11 -2
data/lib/xero_gateway/gateway.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
module XeroGateway
|
2
|
-
|
2
|
+
|
3
3
|
class Gateway
|
4
4
|
include Http
|
5
5
|
include Dates
|
6
|
-
|
6
|
+
|
7
7
|
attr_accessor :client, :xero_url, :logger
|
8
|
-
|
8
|
+
|
9
9
|
extend Forwardable
|
10
|
-
def_delegators :client, :request_token, :access_token, :authorize_from_request, :authorize_from_access, :authorization_expires_at
|
10
|
+
def_delegators :client, :request_token, :access_token, :authorize_from_request, :authorize_from_access, :expires_at, :authorization_expires_at
|
11
11
|
|
12
12
|
#
|
13
13
|
# The consumer key and secret here correspond to those provided
|
14
|
-
# to you by Xero inside the API Previewer.
|
14
|
+
# to you by Xero inside the API Previewer.
|
15
15
|
def initialize(consumer_key, consumer_secret, options = {})
|
16
16
|
@xero_url = options[:xero_url] || "https://api.xero.com/api.xro/2.0"
|
17
17
|
@client = OAuth.new(consumer_key, consumer_secret, options)
|
@@ -34,27 +34,27 @@ module XeroGateway
|
|
34
34
|
|
35
35
|
request_params[:ContactID] = options[:contact_id] if options[:contact_id]
|
36
36
|
request_params[:ContactNumber] = options[:contact_number] if options[:contact_number]
|
37
|
-
request_params[:OrderBy] = options[:order] if options[:order]
|
37
|
+
request_params[:OrderBy] = options[:order] if options[:order]
|
38
38
|
request_params[:ModifiedAfter] = options[:modified_since] if options[:modified_since]
|
39
39
|
request_params[:where] = options[:where] if options[:where]
|
40
|
-
|
40
|
+
|
41
41
|
response_xml = http_get(@client, "#{@xero_url}/Contacts", request_params)
|
42
|
-
|
42
|
+
|
43
43
|
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/contacts'})
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
# Retrieve a contact from Xero
|
47
|
-
# Usage get_contact_by_id(contact_id)
|
47
|
+
# Usage get_contact_by_id(contact_id)
|
48
48
|
def get_contact_by_id(contact_id)
|
49
49
|
get_contact(contact_id)
|
50
50
|
end
|
51
51
|
|
52
52
|
# Retrieve a contact from Xero
|
53
|
-
# Usage get_contact_by_id(contact_id)
|
53
|
+
# Usage get_contact_by_id(contact_id)
|
54
54
|
def get_contact_by_number(contact_number)
|
55
55
|
get_contact(nil, contact_number)
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
# Factory method for building new Contact objects associated with this gateway.
|
59
59
|
def build_contact(contact = {})
|
60
60
|
case contact
|
@@ -63,11 +63,11 @@ module XeroGateway
|
|
63
63
|
end
|
64
64
|
contact
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
#
|
68
68
|
# Creates a contact in Xero
|
69
69
|
#
|
70
|
-
# Usage :
|
70
|
+
# Usage :
|
71
71
|
#
|
72
72
|
# contact = XeroGateway::Contact.new(:name => "THE NAME OF THE CONTACT #{Time.now.to_i}")
|
73
73
|
# contact.email = "whoever@something.com"
|
@@ -85,24 +85,24 @@ module XeroGateway
|
|
85
85
|
def create_contact(contact)
|
86
86
|
save_contact(contact)
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
#
|
90
90
|
# Updates an existing Xero contact
|
91
91
|
#
|
92
|
-
# Usage :
|
92
|
+
# Usage :
|
93
93
|
#
|
94
94
|
# contact = xero_gateway.get_contact(some_contact_id)
|
95
95
|
# contact.email = "a_new_email_ddress"
|
96
96
|
#
|
97
|
-
# xero_gateway.update_contact(contact)
|
97
|
+
# xero_gateway.update_contact(contact)
|
98
98
|
def update_contact(contact)
|
99
99
|
raise "contact_id or contact_number is required for updating contacts" if contact.contact_id.nil? and contact.contact_number.nil?
|
100
100
|
save_contact(contact)
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
#
|
104
104
|
# Updates an array of contacts in a single API operation.
|
105
|
-
#
|
105
|
+
#
|
106
106
|
# Usage :
|
107
107
|
# contacts = [XeroGateway::Contact.new(:name => 'Joe Bloggs'), XeroGateway::Contact.new(:name => 'Jane Doe')]
|
108
108
|
# result = gateway.update_contacts(contacts)
|
@@ -116,7 +116,7 @@ module XeroGateway
|
|
116
116
|
contact.to_xml(b)
|
117
117
|
end
|
118
118
|
}
|
119
|
-
|
119
|
+
|
120
120
|
response_xml = http_post(@client, "#{@xero_url}/Contacts", request_xml, {})
|
121
121
|
|
122
122
|
response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => 'POST/contacts'})
|
@@ -125,7 +125,7 @@ module XeroGateway
|
|
125
125
|
end
|
126
126
|
response
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
# Retrieves all invoices from Xero
|
130
130
|
#
|
131
131
|
# Usage : get_invoices
|
@@ -133,12 +133,12 @@ module XeroGateway
|
|
133
133
|
#
|
134
134
|
# Note : modified_since is in UTC format (i.e. Brisbane is UTC+10)
|
135
135
|
def get_invoices(options = {})
|
136
|
-
|
136
|
+
|
137
137
|
request_params = {}
|
138
|
-
|
138
|
+
|
139
139
|
request_params[:InvoiceID] = options[:invoice_id] if options[:invoice_id]
|
140
140
|
request_params[:InvoiceNumber] = options[:invoice_number] if options[:invoice_number]
|
141
|
-
request_params[:OrderBy] = options[:order] if options[:order]
|
141
|
+
request_params[:OrderBy] = options[:order] if options[:order]
|
142
142
|
request_params[:ModifiedAfter] = options[:modified_since] if options[:modified_since]
|
143
143
|
|
144
144
|
request_params[:where] = options[:where] if options[:where]
|
@@ -147,21 +147,33 @@ module XeroGateway
|
|
147
147
|
|
148
148
|
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/Invoices'})
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
# Retrieves a single invoice
|
152
152
|
#
|
153
|
+
# You can get a PDF-formatted invoice by specifying :pdf as the format argument
|
154
|
+
#
|
153
155
|
# Usage : get_invoice("297c2dc5-cc47-4afd-8ec8-74990b8761e9") # By ID
|
154
156
|
# get_invoice("OIT-12345") # By number
|
155
|
-
def get_invoice(invoice_id_or_number)
|
157
|
+
def get_invoice(invoice_id_or_number, format = :xml)
|
156
158
|
request_params = {}
|
157
|
-
|
159
|
+
headers = {}
|
160
|
+
|
161
|
+
headers.merge!("Accept" => "application/pdf") if format == :pdf
|
162
|
+
|
158
163
|
url = "#{@xero_url}/Invoices/#{URI.escape(invoice_id_or_number)}"
|
159
|
-
|
160
|
-
response_xml = http_get(@client, url, request_params)
|
161
164
|
|
162
|
-
|
165
|
+
response = http_get(@client, url, request_params, headers)
|
166
|
+
|
167
|
+
if format == :pdf
|
168
|
+
Tempfile.open(invoice_id_or_number) do |f|
|
169
|
+
f.write(response)
|
170
|
+
f
|
171
|
+
end
|
172
|
+
else
|
173
|
+
parse_response(response, {:request_params => request_params}, {:request_signature => 'GET/Invoice'})
|
174
|
+
end
|
163
175
|
end
|
164
|
-
|
176
|
+
|
165
177
|
# Factory method for building new Invoice objects associated with this gateway.
|
166
178
|
def build_invoice(invoice = {})
|
167
179
|
case invoice
|
@@ -170,12 +182,12 @@ module XeroGateway
|
|
170
182
|
end
|
171
183
|
invoice
|
172
184
|
end
|
173
|
-
|
185
|
+
|
174
186
|
# Creates an invoice in Xero based on an invoice object.
|
175
187
|
#
|
176
188
|
# Invoice and line item totals are calculated automatically.
|
177
189
|
#
|
178
|
-
# Usage :
|
190
|
+
# Usage :
|
179
191
|
#
|
180
192
|
# invoice = XeroGateway::Invoice.new({
|
181
193
|
# :invoice_type => "ACCREC",
|
@@ -186,7 +198,7 @@ module XeroGateway
|
|
186
198
|
# })
|
187
199
|
# invoice.contact = XeroGateway::Contact.new(:name => "THE NAME OF THE CONTACT")
|
188
200
|
# invoice.contact.phone.number = "12345"
|
189
|
-
# invoice.contact.address.line_1 = "LINE 1 OF THE ADDRESS"
|
201
|
+
# invoice.contact.address.line_1 = "LINE 1 OF THE ADDRESS"
|
190
202
|
# invoice.line_items << XeroGateway::LineItem.new(
|
191
203
|
# :description => "THE DESCRIPTION OF THE LINE ITEM",
|
192
204
|
# :unit_amount => 100,
|
@@ -203,12 +215,12 @@ module XeroGateway
|
|
203
215
|
#
|
204
216
|
# Updates an existing Xero invoice
|
205
217
|
#
|
206
|
-
# Usage :
|
218
|
+
# Usage :
|
207
219
|
#
|
208
220
|
# invoice = xero_gateway.get_invoice(some_invoice_id)
|
209
221
|
# invoice.due_date = Date.today
|
210
222
|
#
|
211
|
-
# xero_gateway.update_invoice(invoice)
|
223
|
+
# xero_gateway.update_invoice(invoice)
|
212
224
|
|
213
225
|
def update_invoice(invoice)
|
214
226
|
raise "invoice_id is required for updating invoices" if invoice.invoice_id.nil?
|
@@ -217,7 +229,7 @@ module XeroGateway
|
|
217
229
|
|
218
230
|
#
|
219
231
|
# Creates an array of invoices with a single API request.
|
220
|
-
#
|
232
|
+
#
|
221
233
|
# Usage :
|
222
234
|
# invoices = [XeroGateway::Invoice.new(...), XeroGateway::Invoice.new(...)]
|
223
235
|
# result = gateway.create_invoices(invoices)
|
@@ -229,8 +241,8 @@ module XeroGateway
|
|
229
241
|
invoice.to_xml(b)
|
230
242
|
end
|
231
243
|
}
|
232
|
-
|
233
|
-
response_xml = http_put(@client, "#{@xero_url}/Invoices", request_xml, {})
|
244
|
+
|
245
|
+
response_xml = http_put(@client, "#{@xero_url}/Invoices?SummarizeErrors=false", request_xml, {})
|
234
246
|
|
235
247
|
response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => 'PUT/invoices'})
|
236
248
|
response.invoices.each_with_index do | response_invoice, index |
|
@@ -246,12 +258,12 @@ module XeroGateway
|
|
246
258
|
#
|
247
259
|
# Note : modified_since is in UTC format (i.e. Brisbane is UTC+10)
|
248
260
|
def get_credit_notes(options = {})
|
249
|
-
|
261
|
+
|
250
262
|
request_params = {}
|
251
|
-
|
263
|
+
|
252
264
|
request_params[:CreditNoteID] = options[:credit_note_id] if options[:credit_note_id]
|
253
265
|
request_params[:CreditNoteNumber] = options[:credit_note_number] if options[:credit_note_number]
|
254
|
-
request_params[:OrderBy] = options[:order] if options[:order]
|
266
|
+
request_params[:OrderBy] = options[:order] if options[:order]
|
255
267
|
request_params[:ModifiedAfter] = options[:modified_since] if options[:modified_since]
|
256
268
|
|
257
269
|
request_params[:where] = options[:where] if options[:where]
|
@@ -260,21 +272,21 @@ module XeroGateway
|
|
260
272
|
|
261
273
|
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/CreditNotes'})
|
262
274
|
end
|
263
|
-
|
275
|
+
|
264
276
|
# Retrieves a single credit_note
|
265
277
|
#
|
266
278
|
# Usage : get_credit_note("297c2dc5-cc47-4afd-8ec8-74990b8761e9") # By ID
|
267
279
|
# get_credit_note("OIT-12345") # By number
|
268
280
|
def get_credit_note(credit_note_id_or_number)
|
269
281
|
request_params = {}
|
270
|
-
|
282
|
+
|
271
283
|
url = "#{@xero_url}/CreditNotes/#{URI.escape(credit_note_id_or_number)}"
|
272
|
-
|
284
|
+
|
273
285
|
response_xml = http_get(@client, url, request_params)
|
274
286
|
|
275
287
|
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/CreditNote'})
|
276
288
|
end
|
277
|
-
|
289
|
+
|
278
290
|
# Factory method for building new CreditNote objects associated with this gateway.
|
279
291
|
def build_credit_note(credit_note = {})
|
280
292
|
case credit_note
|
@@ -283,12 +295,12 @@ module XeroGateway
|
|
283
295
|
end
|
284
296
|
credit_note
|
285
297
|
end
|
286
|
-
|
298
|
+
|
287
299
|
# Creates an credit_note in Xero based on an credit_note object.
|
288
300
|
#
|
289
301
|
# CreditNote and line item totals are calculated automatically.
|
290
302
|
#
|
291
|
-
# Usage :
|
303
|
+
# Usage :
|
292
304
|
#
|
293
305
|
# credit_note = XeroGateway::CreditNote.new({
|
294
306
|
# :credit_note_type => "ACCREC",
|
@@ -299,7 +311,7 @@ module XeroGateway
|
|
299
311
|
# })
|
300
312
|
# credit_note.contact = XeroGateway::Contact.new(:name => "THE NAME OF THE CONTACT")
|
301
313
|
# credit_note.contact.phone.number = "12345"
|
302
|
-
# credit_note.contact.address.line_1 = "LINE 1 OF THE ADDRESS"
|
314
|
+
# credit_note.contact.address.line_1 = "LINE 1 OF THE ADDRESS"
|
303
315
|
# credit_note.line_items << XeroGateway::LineItem.new(
|
304
316
|
# :description => "THE DESCRIPTION OF THE LINE ITEM",
|
305
317
|
# :unit_amount => 100,
|
@@ -313,21 +325,21 @@ module XeroGateway
|
|
313
325
|
request_xml = credit_note.to_xml
|
314
326
|
response_xml = http_put(@client, "#{@xero_url}/CreditNotes", request_xml)
|
315
327
|
response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => 'PUT/credit_note'})
|
316
|
-
|
328
|
+
|
317
329
|
# Xero returns credit_notes inside an <CreditNotes> tag, even though there's only ever
|
318
330
|
# one for this request
|
319
331
|
response.response_item = response.credit_notes.first
|
320
|
-
|
332
|
+
|
321
333
|
if response.success? && response.credit_note && response.credit_note.credit_note_id
|
322
|
-
credit_note.credit_note_id = response.credit_note.credit_note_id
|
334
|
+
credit_note.credit_note_id = response.credit_note.credit_note_id
|
323
335
|
end
|
324
|
-
|
336
|
+
|
325
337
|
response
|
326
338
|
end
|
327
|
-
|
339
|
+
|
328
340
|
#
|
329
341
|
# Creates an array of credit_notes with a single API request.
|
330
|
-
#
|
342
|
+
#
|
331
343
|
# Usage :
|
332
344
|
# credit_notes = [XeroGateway::CreditNote.new(...), XeroGateway::CreditNote.new(...)]
|
333
345
|
# result = gateway.create_credit_notes(credit_notes)
|
@@ -339,7 +351,7 @@ module XeroGateway
|
|
339
351
|
credit_note.to_xml(b)
|
340
352
|
end
|
341
353
|
}
|
342
|
-
|
354
|
+
|
343
355
|
response_xml = http_put(@client, "#{@xero_url}/CreditNotes", request_xml, {})
|
344
356
|
|
345
357
|
response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => 'PUT/credit_notes'})
|
@@ -419,6 +431,56 @@ module XeroGateway
|
|
419
431
|
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/BankTransaction'})
|
420
432
|
end
|
421
433
|
|
434
|
+
# Creates a manual journal in Xero based on a manual journal object.
|
435
|
+
#
|
436
|
+
# Manual journal and line item totals are calculated automatically.
|
437
|
+
#
|
438
|
+
# Usage : # TODO
|
439
|
+
|
440
|
+
def create_manual_journal(manual_journal)
|
441
|
+
save_manual_journal(manual_journal)
|
442
|
+
end
|
443
|
+
|
444
|
+
#
|
445
|
+
# Updates an existing Xero manual journal
|
446
|
+
#
|
447
|
+
# Usage :
|
448
|
+
#
|
449
|
+
# manual_journal = xero_gateway.get_manual_journal(some_manual_journal_id)
|
450
|
+
#
|
451
|
+
# xero_gateway.update_manual_journal(manual_journal)
|
452
|
+
def update_manual_journal(manual_journal)
|
453
|
+
raise "manual_journal_id is required for updating manual journals" if manual_journal.manual_journal_id.nil?
|
454
|
+
save_manual_journal(manual_journal)
|
455
|
+
end
|
456
|
+
|
457
|
+
# Retrieves all manual journals from Xero
|
458
|
+
#
|
459
|
+
# Usage : get_manual_journal
|
460
|
+
# getmanual_journal(:manual_journal_id => " 297c2dc5-cc47-4afd-8ec8-74990b8761e9")
|
461
|
+
#
|
462
|
+
# Note : modified_since is in UTC format (i.e. Brisbane is UTC+10)
|
463
|
+
def get_manual_journals(options = {})
|
464
|
+
request_params = {}
|
465
|
+
request_params[:ManualJournalID] = options[:manual_journal_id] if options[:manual_journal_id]
|
466
|
+
request_params[:ModifiedAfter] = options[:modified_since] if options[:modified_since]
|
467
|
+
|
468
|
+
response_xml = http_get(@client, "#{@xero_url}/ManualJournals", request_params)
|
469
|
+
|
470
|
+
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/ManualJournals'})
|
471
|
+
end
|
472
|
+
|
473
|
+
# Retrieves a single manual journal
|
474
|
+
#
|
475
|
+
# Usage : get_manual_journal("297c2dc5-cc47-4afd-8ec8-74990b8761e9") # By ID
|
476
|
+
# get_manual_journal("OIT-12345") # By number
|
477
|
+
def get_manual_journal(manual_journal_id)
|
478
|
+
request_params = {}
|
479
|
+
url = "#{@xero_url}/ManualJournals/#{URI.escape(manual_journal_id)}"
|
480
|
+
response_xml = http_get(@client, url, request_params)
|
481
|
+
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/ManualJournal'})
|
482
|
+
end
|
483
|
+
|
422
484
|
#
|
423
485
|
# Gets all accounts for a specific organization in Xero.
|
424
486
|
#
|
@@ -426,7 +488,7 @@ module XeroGateway
|
|
426
488
|
response_xml = http_get(@client, "#{xero_url}/Accounts")
|
427
489
|
parse_response(response_xml, {}, {:request_signature => 'GET/accounts'})
|
428
490
|
end
|
429
|
-
|
491
|
+
|
430
492
|
#
|
431
493
|
# Returns a XeroGateway::AccountsList object that makes working with
|
432
494
|
# the Xero list of accounts easier and allows caching the results.
|
@@ -451,7 +513,7 @@ module XeroGateway
|
|
451
513
|
response_xml = http_get(@client, "#{xero_url}/Organisation")
|
452
514
|
parse_response(response_xml, {}, {:request_signature => 'GET/organisation'})
|
453
515
|
end
|
454
|
-
|
516
|
+
|
455
517
|
#
|
456
518
|
# Gets all currencies for a specific organisation in Xero
|
457
519
|
#
|
@@ -459,7 +521,7 @@ module XeroGateway
|
|
459
521
|
response_xml = http_get(@client, "#{xero_url}/Currencies")
|
460
522
|
parse_response(response_xml, {}, {:request_signature => 'GET/currencies'})
|
461
523
|
end
|
462
|
-
|
524
|
+
|
463
525
|
#
|
464
526
|
# Gets all Tax Rates for a specific organisation in Xero
|
465
527
|
#
|
@@ -468,25 +530,40 @@ module XeroGateway
|
|
468
530
|
parse_response(response_xml, {}, {:request_signature => 'GET/tax_rates'})
|
469
531
|
end
|
470
532
|
|
533
|
+
#
|
534
|
+
# Get report for a specific organisation in Xero
|
535
|
+
#
|
471
536
|
def get_report(report_name, request_params = {})
|
472
537
|
response_xml = http_get(@client, "#{@xero_url}/Reports/#{report_name}", request_params)
|
473
538
|
end
|
474
539
|
|
540
|
+
#
|
541
|
+
# Create Payment record in Xero
|
542
|
+
#
|
543
|
+
def create_payment(payment)
|
544
|
+
b = Builder::XmlMarkup.new
|
545
|
+
|
546
|
+
request_xml = b.Payments do
|
547
|
+
payment.to_xml(b)
|
548
|
+
end
|
549
|
+
|
550
|
+
response_xml = http_put(@client, "#{xero_url}/Payments", request_xml)
|
551
|
+
parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => 'PUT/payments'})
|
552
|
+
end
|
475
553
|
|
476
554
|
private
|
477
555
|
|
478
|
-
def get_contact(contact_id = nil, contact_number = nil)
|
556
|
+
def get_contact(contact_id = nil, contact_number = nil)
|
479
557
|
request_params = contact_id ? { :contactID => contact_id } : { :contactNumber => contact_number }
|
480
558
|
response_xml = http_get(@client, "#{@xero_url}/Contacts/#{URI.escape(contact_id||contact_number)}", request_params)
|
481
559
|
|
482
560
|
parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/contact'})
|
483
561
|
end
|
484
562
|
|
485
|
-
|
486
563
|
# Create or update a contact record based on if it has a contact_id or contact_number.
|
487
564
|
def save_contact(contact)
|
488
565
|
request_xml = contact.to_xml
|
489
|
-
|
566
|
+
|
490
567
|
response_xml = nil
|
491
568
|
create_or_save = nil
|
492
569
|
if contact.contact_id.nil? && contact.contact_number.nil?
|
@@ -507,7 +584,7 @@ module XeroGateway
|
|
507
584
|
# Create or update an invoice record based on if it has an invoice_id.
|
508
585
|
def save_invoice(invoice)
|
509
586
|
request_xml = invoice.to_xml
|
510
|
-
|
587
|
+
|
511
588
|
response_xml = nil
|
512
589
|
create_or_save = nil
|
513
590
|
if invoice.invoice_id.nil?
|
@@ -521,15 +598,15 @@ module XeroGateway
|
|
521
598
|
end
|
522
599
|
|
523
600
|
response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => "#{create_or_save == :create ? 'PUT' : 'POST'}/invoice"})
|
524
|
-
|
601
|
+
|
525
602
|
# Xero returns invoices inside an <Invoices> tag, even though there's only ever
|
526
603
|
# one for this request
|
527
604
|
response.response_item = response.invoices.first
|
528
|
-
|
605
|
+
|
529
606
|
if response.success? && response.invoice && response.invoice.invoice_id
|
530
|
-
invoice.invoice_id = response.invoice.invoice_id
|
607
|
+
invoice.invoice_id = response.invoice.invoice_id
|
531
608
|
end
|
532
|
-
|
609
|
+
|
533
610
|
response
|
534
611
|
end
|
535
612
|
|
@@ -562,17 +639,44 @@ module XeroGateway
|
|
562
639
|
response
|
563
640
|
end
|
564
641
|
|
642
|
+
# Create or update a manual journal record based on if it has an manual_journal_id.
|
643
|
+
def save_manual_journal(manual_journal)
|
644
|
+
request_xml = manual_journal.to_xml
|
645
|
+
response_xml = nil
|
646
|
+
create_or_save = nil
|
647
|
+
|
648
|
+
if manual_journal.manual_journal_id.nil?
|
649
|
+
# Create new manual journal record.
|
650
|
+
response_xml = http_put(@client, "#{@xero_url}/ManualJournals", request_xml, {})
|
651
|
+
create_or_save = :create
|
652
|
+
else
|
653
|
+
# Update existing manual journal record.
|
654
|
+
response_xml = http_post(@client, "#{@xero_url}/ManualJournals", request_xml, {})
|
655
|
+
create_or_save = :save
|
656
|
+
end
|
657
|
+
|
658
|
+
response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => "#{create_or_save == :create ? 'PUT' : 'POST'}/ManualJournals"})
|
659
|
+
|
660
|
+
# Xero returns manual journals inside an <ManualJournals> tag, even though there's only ever
|
661
|
+
# one for this request
|
662
|
+
response.response_item = response.manual_journals.first
|
663
|
+
|
664
|
+
manual_journal.manual_journal_id = response.manual_journal.manual_journal_id if response.success? && response.manual_journal && response.manual_journal.manual_journal_id
|
665
|
+
|
666
|
+
response
|
667
|
+
end
|
668
|
+
|
565
669
|
def parse_response(raw_response, request = {}, options = {})
|
566
670
|
|
567
671
|
response = XeroGateway::Response.new
|
568
672
|
|
569
673
|
doc = REXML::Document.new(raw_response, :ignore_whitespace_nodes => :all)
|
570
|
-
|
674
|
+
|
571
675
|
# check for responses we don't understand
|
572
676
|
raise UnparseableResponse.new(doc.root.name) unless doc.root.name == "Response"
|
573
677
|
|
574
678
|
response_element = REXML::XPath.first(doc, "/Response")
|
575
|
-
|
679
|
+
|
576
680
|
response_element.children.reject { |e| e.is_a? REXML::Text }.each do |element|
|
577
681
|
case(element.name)
|
578
682
|
when "ID" then response.response_id = element.text
|
@@ -583,40 +687,38 @@ module XeroGateway
|
|
583
687
|
when "Invoice" then response.response_item = Invoice.from_xml(element, self, {:line_items_downloaded => options[:request_signature] != "GET/Invoices"})
|
584
688
|
when "BankTransaction"
|
585
689
|
response.response_item = BankTransaction.from_xml(element, self, {:line_items_downloaded => options[:request_signature] != "GET/BankTransactions"})
|
690
|
+
when "ManualJournal"
|
691
|
+
response.response_item = ManualJournal.from_xml(element, self, {:journal_lines_downloaded => options[:request_signature] != "GET/ManualJournals"})
|
586
692
|
when "Contacts" then element.children.each {|child| response.response_item << Contact.from_xml(child, self) }
|
587
693
|
when "Invoices" then element.children.each {|child| response.response_item << Invoice.from_xml(child, self, {:line_items_downloaded => options[:request_signature] != "GET/Invoices"}) }
|
588
694
|
when "BankTransactions"
|
589
695
|
element.children.each do |child|
|
590
696
|
response.response_item << BankTransaction.from_xml(child, self, {:line_items_downloaded => options[:request_signature] != "GET/BankTransactions"})
|
591
697
|
end
|
698
|
+
when "ManualJournals"
|
699
|
+
element.children.each do |child|
|
700
|
+
response.response_item << ManualJournal.from_xml(child, self, {:journal_lines_downloaded => options[:request_signature] != "GET/ManualJournals"})
|
701
|
+
end
|
592
702
|
when "CreditNotes" then element.children.each {|child| response.response_item << CreditNote.from_xml(child, self, {:line_items_downloaded => options[:request_signature] != "GET/CreditNotes"}) }
|
593
703
|
when "Accounts" then element.children.each {|child| response.response_item << Account.from_xml(child) }
|
594
704
|
when "TaxRates" then element.children.each {|child| response.response_item << TaxRate.from_xml(child) }
|
595
705
|
when "Currencies" then element.children.each {|child| response.response_item << Currency.from_xml(child) }
|
596
706
|
when "Organisations" then response.response_item = Organisation.from_xml(element.children.first) # Xero only returns the Authorized Organisation
|
597
707
|
when "TrackingCategories" then element.children.each {|child| response.response_item << TrackingCategory.from_xml(child) }
|
598
|
-
when "Errors" then element.children.
|
708
|
+
when "Errors" then response.errors = element.children.map { |error| Error.parse(error) }
|
599
709
|
end
|
600
710
|
end if response_element
|
601
|
-
|
711
|
+
|
602
712
|
# If a single result is returned don't put it in an array
|
603
713
|
if response.response_item.is_a?(Array) && response.response_item.size == 1
|
604
714
|
response.response_item = response.response_item.first
|
605
715
|
end
|
606
|
-
|
716
|
+
|
607
717
|
response.request_params = request[:request_params]
|
608
718
|
response.request_xml = request[:request_xml]
|
609
719
|
response.response_xml = raw_response
|
610
720
|
response
|
611
|
-
end
|
612
|
-
|
613
|
-
def parse_error(error_element, response)
|
614
|
-
response.errors << Error.new(
|
615
|
-
:description => REXML::XPath.first(error_element, "Description").text,
|
616
|
-
:date_time => REXML::XPath.first(error_element, "//DateTime").text,
|
617
|
-
:type => REXML::XPath.first(error_element, "//ExceptionType").text,
|
618
|
-
:message => REXML::XPath.first(error_element, "//Message").text
|
619
|
-
)
|
620
721
|
end
|
621
|
-
|
722
|
+
|
723
|
+
end
|
622
724
|
end
|