xero_gateway-float 2.0.18 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|