xero_gateway-n8vision 2.0.20
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 +41 -0
- data/lib/xero_gateway/account.rb +86 -0
- data/lib/xero_gateway/accounts_list.rb +73 -0
- data/lib/xero_gateway/address.rb +96 -0
- data/lib/xero_gateway/bank_transaction.rb +175 -0
- data/lib/xero_gateway/ca-certificates.crt +2560 -0
- data/lib/xero_gateway/contact.rb +203 -0
- data/lib/xero_gateway/credit_note.rb +220 -0
- data/lib/xero_gateway/currency.rb +56 -0
- data/lib/xero_gateway/dates.rb +25 -0
- data/lib/xero_gateway/error.rb +18 -0
- data/lib/xero_gateway/exceptions.rb +51 -0
- data/lib/xero_gateway/gateway.rb +698 -0
- data/lib/xero_gateway/http.rb +135 -0
- data/lib/xero_gateway/http_encoding_helper.rb +49 -0
- data/lib/xero_gateway/invoice.rb +238 -0
- data/lib/xero_gateway/journal_line.rb +102 -0
- data/lib/xero_gateway/line_item.rb +125 -0
- data/lib/xero_gateway/line_item_calculations.rb +51 -0
- data/lib/xero_gateway/manual_journal.rb +163 -0
- data/lib/xero_gateway/money.rb +16 -0
- data/lib/xero_gateway/oauth.rb +92 -0
- data/lib/xero_gateway/organisation.rb +75 -0
- data/lib/xero_gateway/partner_app.rb +30 -0
- data/lib/xero_gateway/payment.rb +43 -0
- data/lib/xero_gateway/phone.rb +77 -0
- data/lib/xero_gateway/private_app.rb +17 -0
- data/lib/xero_gateway/response.rb +43 -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/create_manual_journal_test.rb +35 -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_manual_journal_test.rb +50 -0
- data/test/integration/get_manual_journals_test.rb +88 -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/integration/update_manual_journal_test.rb +31 -0
- data/test/test_helper.rb +217 -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/manual_journal_test.rb +93 -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-n8vision.gemspec +15 -0
- metadata +178 -0
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'account')
|
2
|
+
|
3
|
+
module XeroGateway
|
4
|
+
class LineItem
|
5
|
+
include Money
|
6
|
+
|
7
|
+
TAX_TYPE = Account::TAX_TYPE unless defined?(TAX_TYPE)
|
8
|
+
|
9
|
+
# Any errors that occurred when the #valid? method called.
|
10
|
+
attr_reader :errors
|
11
|
+
|
12
|
+
# All accessible fields
|
13
|
+
attr_accessor :line_item_id, :description, :quantity, :unit_amount, :item_code, :tax_type, :tax_amount, :account_code, :tracking
|
14
|
+
|
15
|
+
def initialize(params = {})
|
16
|
+
@errors ||= []
|
17
|
+
@tracking ||= []
|
18
|
+
@quantity = 1
|
19
|
+
@unit_amount = BigDecimal.new('0')
|
20
|
+
|
21
|
+
params.each do |k,v|
|
22
|
+
self.send("#{k}=", v)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Validate the LineItem record according to what will be valid by the gateway.
|
27
|
+
#
|
28
|
+
# Usage:
|
29
|
+
# line_item.valid? # Returns true/false
|
30
|
+
#
|
31
|
+
# Additionally sets line_item.errors array to an array of field/error.
|
32
|
+
def valid?
|
33
|
+
@errors = []
|
34
|
+
|
35
|
+
if !line_item_id.nil? && line_item_id !~ GUID_REGEX
|
36
|
+
@errors << ['line_item_id', 'must be blank or a valid Xero GUID']
|
37
|
+
end
|
38
|
+
|
39
|
+
unless description
|
40
|
+
@errors << ['description', "can't be blank"]
|
41
|
+
end
|
42
|
+
|
43
|
+
if tax_type && !TAX_TYPE[tax_type]
|
44
|
+
@errors << ['tax_type', "must be one of #{TAX_TYPE.keys.join('/')}"]
|
45
|
+
end
|
46
|
+
|
47
|
+
@errors.size == 0
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_tracking?
|
51
|
+
return false if tracking.nil?
|
52
|
+
|
53
|
+
if tracking.is_a?(Array)
|
54
|
+
return tracking.any?
|
55
|
+
else
|
56
|
+
return tracking.is_a?(TrackingCategory)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Deprecated (but API for setter remains).
|
61
|
+
#
|
62
|
+
# As line_amount must equal quantity * unit_amount for the API call to pass, this is now
|
63
|
+
# automatically calculated in the line_amount method.
|
64
|
+
def line_amount=(value)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Calculate the line_amount as quantity * unit_amount as this value must be correct
|
68
|
+
# for the API call to succeed.
|
69
|
+
def line_amount
|
70
|
+
quantity * unit_amount
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_xml(b = Builder::XmlMarkup.new)
|
74
|
+
b.LineItem {
|
75
|
+
b.Description description
|
76
|
+
b.Quantity quantity if quantity
|
77
|
+
b.UnitAmount LineItem.format_money(unit_amount)
|
78
|
+
b.ItemCode item_code if item_code
|
79
|
+
b.TaxType tax_type if tax_type
|
80
|
+
b.TaxAmount tax_amount if tax_amount
|
81
|
+
b.LineAmount line_amount if line_amount
|
82
|
+
b.AccountCode account_code if account_code
|
83
|
+
if has_tracking?
|
84
|
+
b.Tracking {
|
85
|
+
# Due to strange retardness in the Xero API, the XML structure for a tracking category within
|
86
|
+
# an invoice is different to a standalone tracking category.
|
87
|
+
# This means rather than going category.to_xml we need to call the special category.to_xml_for_invoice_messages
|
88
|
+
(tracking.is_a?(TrackingCategory) ? [tracking] : tracking).each do |category|
|
89
|
+
category.to_xml_for_invoice_messages(b)
|
90
|
+
end
|
91
|
+
}
|
92
|
+
end
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.from_xml(line_item_element)
|
97
|
+
line_item = LineItem.new
|
98
|
+
line_item_element.children.each do |element|
|
99
|
+
case(element.name)
|
100
|
+
when "LineItemID" then line_item.line_item_id = element.text
|
101
|
+
when "Description" then line_item.description = element.text
|
102
|
+
when "Quantity" then line_item.quantity = BigDecimal(element.text)
|
103
|
+
when "UnitAmount" then line_item.unit_amount = BigDecimal.new(element.text)
|
104
|
+
when "ItemCode" then line_item.item_code = element.text
|
105
|
+
when "TaxType" then line_item.tax_type = element.text
|
106
|
+
when "TaxAmount" then line_item.tax_amount = BigDecimal.new(element.text)
|
107
|
+
when "LineAmount" then line_item.line_amount = BigDecimal.new(element.text)
|
108
|
+
when "AccountCode" then line_item.account_code = element.text
|
109
|
+
when "Tracking" then
|
110
|
+
element.children.each do | tracking_element |
|
111
|
+
line_item.tracking << TrackingCategory.from_xml(tracking_element)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
line_item
|
116
|
+
end
|
117
|
+
|
118
|
+
def ==(other)
|
119
|
+
[:description, :quantity, :unit_amount, :tax_type, :tax_amount, :line_amount, :account_code, :item_code].each do |field|
|
120
|
+
return false if send(field) != other.send(field)
|
121
|
+
end
|
122
|
+
return true
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module XeroGateway
|
2
|
+
module LineItemCalculations
|
3
|
+
def add_line_item(params = {})
|
4
|
+
line_item = nil
|
5
|
+
case params
|
6
|
+
when Hash then line_item = LineItem.new(params)
|
7
|
+
when LineItem then line_item = params
|
8
|
+
else raise InvalidLineItemError
|
9
|
+
end
|
10
|
+
@line_items << line_item
|
11
|
+
line_item
|
12
|
+
end
|
13
|
+
|
14
|
+
# Deprecated (but API for setter remains).
|
15
|
+
#
|
16
|
+
# As sub_total must equal SUM(line_item.line_amount) for the API call to pass, this is now
|
17
|
+
# automatically calculated in the sub_total method.
|
18
|
+
def sub_total=(value)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Calculate the sub_total as the SUM(line_item.line_amount).
|
22
|
+
def sub_total
|
23
|
+
line_items.inject(BigDecimal.new('0')) { | sum, line_item | sum + BigDecimal.new(line_item.line_amount.to_s) }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Deprecated (but API for setter remains).
|
27
|
+
#
|
28
|
+
# As total_tax must equal SUM(line_item.tax_amount) for the API call to pass, this is now
|
29
|
+
# automatically calculated in the total_tax method.
|
30
|
+
def total_tax=(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Calculate the total_tax as the SUM(line_item.tax_amount).
|
34
|
+
def total_tax
|
35
|
+
line_items.inject(BigDecimal.new('0')) { | sum, line_item | sum + BigDecimal.new(line_item.tax_amount.to_s) }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Deprecated (but API for setter remains).
|
39
|
+
#
|
40
|
+
# As total must equal sub_total + total_tax for the API call to pass, this is now
|
41
|
+
# automatically calculated in the total method.
|
42
|
+
def total=(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Calculate the toal as sub_total + total_tax.
|
46
|
+
def total
|
47
|
+
sub_total + total_tax
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module XeroGateway
|
2
|
+
class ManualJournal
|
3
|
+
include Dates
|
4
|
+
|
5
|
+
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)
|
6
|
+
|
7
|
+
STATUSES = {
|
8
|
+
'DRAFT' => 'Draft Manual Journal',
|
9
|
+
'POSTED' => 'Posted Manual Journal',
|
10
|
+
'DELETED' => 'Deleted Draft Manual Journal',
|
11
|
+
'VOIDED' => 'Voided Posted Manual Journal'
|
12
|
+
} unless defined?(STATUSES)
|
13
|
+
|
14
|
+
# Xero::Gateway associated with this invoice.
|
15
|
+
attr_accessor :gateway
|
16
|
+
|
17
|
+
# Any errors that occurred when the #valid? method called.
|
18
|
+
attr_reader :errors
|
19
|
+
|
20
|
+
# Represents whether the journal lines have been downloaded when getting from GET /API.XRO/2.0/ManualJournals
|
21
|
+
attr_accessor :journal_lines_downloaded
|
22
|
+
|
23
|
+
# accessible fields
|
24
|
+
attr_accessor :manual_journal_id, :narration, :date, :status, :journal_lines, :url, :show_on_cash_basis_reports
|
25
|
+
|
26
|
+
def initialize(params = {})
|
27
|
+
@errors ||= []
|
28
|
+
@payments ||= []
|
29
|
+
|
30
|
+
# Check if the line items have been downloaded.
|
31
|
+
@journal_lines_downloaded = (params.delete(:journal_lines_downloaded) == true)
|
32
|
+
|
33
|
+
params.each do |k,v|
|
34
|
+
self.send("#{k}=", v)
|
35
|
+
end
|
36
|
+
|
37
|
+
@journal_lines ||= []
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
['narration', 'status', 'journal_lines', 'show_on_cash_basis_reports'].each do |field|
|
42
|
+
return false if send(field) != other.send(field)
|
43
|
+
end
|
44
|
+
|
45
|
+
["date"].each do |field|
|
46
|
+
return false if send(field).to_s != other.send(field).to_s
|
47
|
+
end
|
48
|
+
return true
|
49
|
+
end
|
50
|
+
|
51
|
+
# Validate the ManualJournal record according to what will be valid by the gateway.
|
52
|
+
#
|
53
|
+
# Usage:
|
54
|
+
# manual_journal.valid? # Returns true/false
|
55
|
+
#
|
56
|
+
# Additionally sets manual_journal.errors array to an array of field/error.
|
57
|
+
def valid?
|
58
|
+
@errors = []
|
59
|
+
|
60
|
+
if !manual_journal_id.nil? && manual_journal_id !~ GUID_REGEX
|
61
|
+
@errors << ['manual_journal_id', 'must be blank or a valid Xero GUID']
|
62
|
+
end
|
63
|
+
|
64
|
+
if narration.blank?
|
65
|
+
@errors << ['narration', "can't be blank"]
|
66
|
+
end
|
67
|
+
|
68
|
+
unless date
|
69
|
+
@errors << ['date', "can't be blank"]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Make sure all journal_items are valid.
|
73
|
+
unless journal_lines.all? { | journal_line | journal_line.valid? }
|
74
|
+
@errors << ['journal_lines', "at least one journal line invalid"]
|
75
|
+
end
|
76
|
+
|
77
|
+
# make sure there are at least 2 journal lines
|
78
|
+
unless journal_lines.length > 1
|
79
|
+
@errors << ['journal_lines', "journal must contain at least two individual journal lines"]
|
80
|
+
end
|
81
|
+
|
82
|
+
if journal_lines.length > 100
|
83
|
+
@errors << ['journal_lines', "journal must contain less than one hundred journal lines"]
|
84
|
+
end
|
85
|
+
|
86
|
+
unless journal_lines.sum(&:line_amount).to_f == 0.0
|
87
|
+
@errors << ['journal_lines', "the total debits must be equal to total credits"]
|
88
|
+
end
|
89
|
+
|
90
|
+
@errors.size == 0
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def journal_lines_downloaded?
|
95
|
+
@journal_lines_downloaded
|
96
|
+
end
|
97
|
+
|
98
|
+
# If line items are not downloaded, then attempt a download now (if this record was found to begin with).
|
99
|
+
def journal_lines
|
100
|
+
if journal_lines_downloaded?
|
101
|
+
@journal_lines
|
102
|
+
|
103
|
+
elsif manual_journal_id =~ GUID_REGEX && @gateway
|
104
|
+
# There is a manual_journal_id so we can assume this record was loaded from Xero.
|
105
|
+
# Let's attempt to download the journal_line records (if there is a gateway)
|
106
|
+
|
107
|
+
response = @gateway.get_manual_journal(manual_journal_id)
|
108
|
+
raise ManualJournalNotFoundError, "Manual Journal with ID #{manual_journal_id} not found in Xero." unless response.success? && response.manual_journal.is_a?(XeroGateway::ManualJournal)
|
109
|
+
|
110
|
+
@journal_lines = response.manual_journal.journal_lines
|
111
|
+
@journal_lines_downloaded = true
|
112
|
+
|
113
|
+
@journal_lines
|
114
|
+
|
115
|
+
# Otherwise, this is a new manual journal, so return the journal_lines reference.
|
116
|
+
else
|
117
|
+
@journal_lines
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def to_xml(b = Builder::XmlMarkup.new)
|
122
|
+
b.ManualJournal {
|
123
|
+
b.ManualJournalID manual_journal_id if manual_journal_id
|
124
|
+
b.Narration narration
|
125
|
+
b.JournalLines {
|
126
|
+
self.journal_lines.each do |journal_line|
|
127
|
+
journal_line.to_xml(b)
|
128
|
+
end
|
129
|
+
}
|
130
|
+
b.Date ManualJournal.format_date(date || Date.today)
|
131
|
+
b.Status status if status
|
132
|
+
b.Url url if url
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.from_xml(manual_journal_element, gateway = nil, options = {})
|
137
|
+
manual_journal = ManualJournal.new(options.merge({:gateway => gateway}))
|
138
|
+
manual_journal_element.children.each do |element|
|
139
|
+
case(element.name)
|
140
|
+
when "ManualJournalID" then manual_journal.manual_journal_id = element.text
|
141
|
+
when "Date" then manual_journal.date = parse_date(element.text)
|
142
|
+
when "Status" then manual_journal.status = element.text
|
143
|
+
when "Narration" then manual_journal.narration = element.text
|
144
|
+
when "JournalLines" then element.children.each {|journal_line| manual_journal.journal_lines_downloaded = true; manual_journal.journal_lines << JournalLine.from_xml(journal_line) }
|
145
|
+
when "Url" then manual_journal.url = element.text
|
146
|
+
end
|
147
|
+
end
|
148
|
+
manual_journal
|
149
|
+
end # from_xml
|
150
|
+
|
151
|
+
def add_journal_line(params = {})
|
152
|
+
journal_line = nil
|
153
|
+
case params
|
154
|
+
when Hash then journal_line = JournalLine.new(params)
|
155
|
+
when JournalLine then journal_line = params
|
156
|
+
else raise InvalidLineItemError
|
157
|
+
end
|
158
|
+
@journal_lines << journal_line
|
159
|
+
journal_line
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module XeroGateway
|
2
|
+
module Money
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def format_money(amount)
|
9
|
+
if amount.class == BigDecimal
|
10
|
+
return amount.to_s("F")
|
11
|
+
end
|
12
|
+
return amount
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module XeroGateway
|
2
|
+
|
3
|
+
# Shamelessly based on the Twitter Gem's OAuth implementation by John Nunemaker
|
4
|
+
# Thanks!
|
5
|
+
#
|
6
|
+
# http://twitter.rubyforge.org/
|
7
|
+
# http://github.com/jnunemaker/twitter/
|
8
|
+
|
9
|
+
class OAuth
|
10
|
+
|
11
|
+
class TokenExpired < StandardError; end
|
12
|
+
class TokenInvalid < StandardError; end
|
13
|
+
class RateLimitExceeded < StandardError; end
|
14
|
+
class UnknownError < StandardError; end
|
15
|
+
|
16
|
+
unless defined? XERO_CONSUMER_OPTIONS
|
17
|
+
XERO_CONSUMER_OPTIONS = {
|
18
|
+
:site => "https://api.xero.com",
|
19
|
+
:request_token_path => "/oauth/RequestToken",
|
20
|
+
:access_token_path => "/oauth/AccessToken",
|
21
|
+
:authorize_path => "/oauth/Authorize"
|
22
|
+
}.freeze
|
23
|
+
end
|
24
|
+
|
25
|
+
extend Forwardable
|
26
|
+
def_delegators :access_token, :get, :post, :put, :delete
|
27
|
+
|
28
|
+
attr_reader :ctoken, :csecret, :consumer_options, :session_handle, :expires_at, :authorization_expires_at
|
29
|
+
|
30
|
+
def initialize(ctoken, csecret, options = {})
|
31
|
+
@ctoken, @csecret = ctoken, csecret
|
32
|
+
@consumer_options = XERO_CONSUMER_OPTIONS.merge(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def consumer
|
36
|
+
@consumer ||= ::OAuth::Consumer.new(@ctoken, @csecret, consumer_options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def request_token(params = {})
|
40
|
+
@request_token ||= consumer.get_request_token(params)
|
41
|
+
end
|
42
|
+
|
43
|
+
def authorize_from_request(rtoken, rsecret, params = {})
|
44
|
+
request_token = ::OAuth::RequestToken.new(consumer, rtoken, rsecret)
|
45
|
+
access_token = request_token.get_access_token(params)
|
46
|
+
@atoken, @asecret = access_token.token, access_token.secret
|
47
|
+
|
48
|
+
update_attributes_from_token(access_token)
|
49
|
+
end
|
50
|
+
|
51
|
+
def access_token
|
52
|
+
@access_token ||= ::OAuth::AccessToken.new(consumer, @atoken, @asecret)
|
53
|
+
end
|
54
|
+
|
55
|
+
def authorize_from_access(atoken, asecret)
|
56
|
+
@atoken, @asecret = atoken, asecret
|
57
|
+
end
|
58
|
+
|
59
|
+
# Renewing access tokens only works for Partner applications
|
60
|
+
def renew_access_token(access_token = nil, access_secret = nil, session_handle = nil)
|
61
|
+
access_token ||= @atoken
|
62
|
+
access_secret ||= @asecret
|
63
|
+
session_handle ||= @session_handle
|
64
|
+
|
65
|
+
old_token = ::OAuth::RequestToken.new(consumer, access_token, access_secret)
|
66
|
+
|
67
|
+
access_token = old_token.get_access_token({
|
68
|
+
:oauth_session_handle => session_handle,
|
69
|
+
:token => old_token
|
70
|
+
})
|
71
|
+
|
72
|
+
update_attributes_from_token(access_token)
|
73
|
+
rescue ::OAuth::Unauthorized => e
|
74
|
+
# If the original access token is for some reason invalid an OAuth::Unauthorized could be raised.
|
75
|
+
# In this case raise a XeroGateway::OAuth::TokenInvalid which can be captured by the caller. In this
|
76
|
+
# situation the end user will need to re-authorize the application via the request token authorization URL
|
77
|
+
raise XeroGateway::OAuth::TokenInvalid.new(e.message)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Update instance variables with those from the AccessToken.
|
83
|
+
def update_attributes_from_token(access_token)
|
84
|
+
@expires_at = Time.now + access_token.params[:oauth_expires_in].to_i
|
85
|
+
@authorization_expires_at = Time.now + access_token.params[:oauth_authorization_expires_in].to_i
|
86
|
+
@session_handle = access_token.params[:oauth_session_handle]
|
87
|
+
@atoken, @asecret = access_token.token, access_token.secret
|
88
|
+
@access_token = nil
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|