xeroizer 2.15.3 → 2.15.5
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 +1 -0
- data/Gemfile.lock +2 -0
- data/LICENSE.txt +22 -1
- data/README.md +29 -2
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/lib/xeroizer.rb +0 -1
- data/lib/xeroizer/exceptions.rb +17 -2
- data/lib/xeroizer/http.rb +21 -4
- data/lib/xeroizer/models/bank_transaction.rb +17 -5
- data/lib/xeroizer/models/contact.rb +17 -17
- data/lib/xeroizer/models/credit_note.rb +18 -18
- data/lib/xeroizer/models/invoice.rb +54 -32
- data/lib/xeroizer/models/line_item.rb +6 -4
- data/lib/xeroizer/models/manual_journal.rb +12 -12
- data/lib/xeroizer/models/payment.rb +11 -11
- data/lib/xeroizer/models/tax_rate.rb +1 -0
- data/lib/xeroizer/oauth.rb +24 -5
- data/lib/xeroizer/record/base.rb +25 -1
- data/lib/xeroizer/record/base_model.rb +84 -11
- data/lib/xeroizer/record/base_model_http_proxy.rb +2 -1
- data/lib/xeroizer/record/model_definition_helper.rb +3 -0
- data/lib/xeroizer/record/xml_helper.rb +6 -2
- data/lib/xeroizer/response.rb +14 -0
- data/test/acceptance/acceptance_test.rb +1 -1
- data/test/acceptance/bulk_operations_test.rb +48 -0
- data/test/unit/models/bank_transaction_model_parsing_test.rb +3 -1
- data/test/unit/models/invoice_test.rb +13 -12
- data/test/unit/record/base_model_test.rb +8 -0
- data/xeroizer.gemspec +7 -3
- metadata +63 -48
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/LICENSE.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c)
|
|
1
|
+
Copyright (c) 2013 Wayne Robinson
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
4
|
a copy of this software and associated documentation files (the
|
|
@@ -18,3 +18,24 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
20
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
|
|
22
|
+
-----------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
Part of the HTTP communication and OAuth authentication library were
|
|
25
|
+
provided by the https://github.com/tlconnor/xero_gateway gem created by
|
|
26
|
+
Tim Connor (github.com/tlconnor) and Nik Wakelin (github.com/nikz).
|
|
27
|
+
The license for this Gem is included below:
|
|
28
|
+
|
|
29
|
+
Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
|
|
30
|
+
|
|
31
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
32
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
33
|
+
copyright notice and this permission notice appear in all copies.
|
|
34
|
+
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
36
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
37
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
38
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
39
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
40
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
41
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Xeroizer API Library 
|
|
7
7
|
**Author**: Wayne Robinson [http://www.wayne-robinson.com](http://www.wayne-robinson.com)
|
|
8
8
|
**Contributors**: See Contributors section below
|
|
9
|
-
**Copyright**: 2007-
|
|
9
|
+
**Copyright**: 2007-2013
|
|
10
10
|
**License**: MIT License
|
|
11
11
|
|
|
12
12
|
Introduction
|
|
@@ -435,9 +435,30 @@ contact.save
|
|
|
435
435
|
Have a look at the models in `lib/xeroizer/models/` to see the valid attributes, associations and
|
|
436
436
|
minimum validation requirements for each of the record types.
|
|
437
437
|
|
|
438
|
+
### Bulk Creates & Updates
|
|
439
|
+
|
|
440
|
+
Xero has a hard daily limit on the number of API requests you can make (currently 1,000 requests
|
|
441
|
+
per account per day). To save on requests, you can batch creates and updates into a single PUT or
|
|
442
|
+
POST call, like so:
|
|
443
|
+
|
|
444
|
+
```ruby
|
|
445
|
+
contact1 = xero.Contact.create(some_attributes)
|
|
446
|
+
xero.Contact.batch_save do
|
|
447
|
+
contact1.email_address = "foo@bar.com"
|
|
448
|
+
contact2 = xero.Contact.build(some_other_attributes)
|
|
449
|
+
contact3 = xero.Contact.build(some_more_attributes)
|
|
450
|
+
end
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
`batch_save` will issue one PUT request for every 2,000 unsaved records built within its block, and one
|
|
454
|
+
POST request for evert 2,000 existing records that have been altered within its block. If any of the
|
|
455
|
+
unsaved records aren't valid, it'll return `false` before sending anything across the wire;
|
|
456
|
+
otherwise, it returns `true`. `batch_save` takes one optional argument: the number of records to
|
|
457
|
+
create/update per request. (Defaults to 2,000.)
|
|
458
|
+
|
|
438
459
|
### Errors
|
|
439
460
|
|
|
440
|
-
If a record doesn't match
|
|
461
|
+
If a record doesn't match its internal validation requirements, the `#save` method will return
|
|
441
462
|
`false` and the `#errors` attribute will be populated with what went wrong.
|
|
442
463
|
|
|
443
464
|
For example:
|
|
@@ -527,3 +548,9 @@ client = Xeroizer::PublicApplication.new(YOUR_OAUTH_CONSUMER_KEY,
|
|
|
527
548
|
YOUR_OAUTH_CONSUMER_SECRET,
|
|
528
549
|
:rate_limit_sleep => 2)
|
|
529
550
|
```
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
### Contributors
|
|
554
|
+
Xeroizer was inspired by the https://github.com/tlconnor/xero_gateway gem created by Tim Connor
|
|
555
|
+
and Nik Wakelin and portions of the networking and authentication code are based completely off
|
|
556
|
+
this project. Copyright for these components remains held in the name of Tim Connor.
|
data/Rakefile
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'rake'
|
|
2
2
|
require 'rake/testtask'
|
|
3
|
-
require '
|
|
3
|
+
require 'rdoc/task'
|
|
4
4
|
require 'rubygems'
|
|
5
5
|
require 'yard'
|
|
6
6
|
|
|
@@ -52,4 +52,4 @@ end
|
|
|
52
52
|
YARD::Rake::YardocTask.new do |t|
|
|
53
53
|
# t.files = ['lib/**/*.rb', OTHER_PATHS] # optional
|
|
54
54
|
# t.options = ['--any', '--extra', '--opts'] # optional
|
|
55
|
-
end
|
|
55
|
+
end
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.15.
|
|
1
|
+
2.15.5
|
data/lib/xeroizer.rb
CHANGED
data/lib/xeroizer/exceptions.rb
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
|
+
# Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
|
|
2
|
+
#
|
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
|
6
|
+
#
|
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
14
|
+
|
|
1
15
|
module Xeroizer
|
|
2
16
|
class ApiException < StandardError
|
|
3
17
|
|
|
4
|
-
attr_reader :type, :message, :xml, :request_body
|
|
18
|
+
attr_reader :type, :message, :xml, :parsed_xml, :request_body
|
|
5
19
|
|
|
6
|
-
def initialize(type, message, xml, request_body)
|
|
20
|
+
def initialize(type, message, xml, parsed_xml, request_body)
|
|
7
21
|
@type = type
|
|
8
22
|
@message = message
|
|
9
23
|
@xml = xml
|
|
24
|
+
@parsed_xml = parsed_xml
|
|
10
25
|
@request_body = request_body
|
|
11
26
|
end
|
|
12
27
|
|
data/lib/xeroizer/http.rb
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
|
|
2
|
+
#
|
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
|
6
|
+
#
|
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
14
|
+
|
|
1
15
|
module Xeroizer
|
|
2
16
|
module Http
|
|
3
17
|
|
|
@@ -69,7 +83,7 @@ module Xeroizer
|
|
|
69
83
|
|
|
70
84
|
begin
|
|
71
85
|
attempts += 1
|
|
72
|
-
logger.info("\n== [#{Time.now.to_s}] XeroGateway Request: #{uri.request_uri} ") if self.logger
|
|
86
|
+
logger.info("\n== [#{Time.now.to_s}] XeroGateway Request: #{method.to_s.upcase} #{uri.request_uri} ") if self.logger
|
|
73
87
|
|
|
74
88
|
response = case method
|
|
75
89
|
when :get then client.get(uri.request_uri, headers)
|
|
@@ -94,6 +108,8 @@ module Xeroizer
|
|
|
94
108
|
handle_oauth_error!(response)
|
|
95
109
|
when 404
|
|
96
110
|
handle_object_not_found!(response, url)
|
|
111
|
+
when 503
|
|
112
|
+
handle_oauth_error!(response)
|
|
97
113
|
else
|
|
98
114
|
raise "Unknown response code: #{response.code.to_i}"
|
|
99
115
|
end
|
|
@@ -131,16 +147,17 @@ module Xeroizer
|
|
|
131
147
|
|
|
132
148
|
# XeroGenericApplication API Exceptions *claim* to be UTF-16 encoded, but fail REXML/Iconv parsing...
|
|
133
149
|
# So let's ignore that :)
|
|
134
|
-
|
|
150
|
+
raw_response.gsub! '<?xml version="1.0" encoding="utf-16"?>', ''
|
|
135
151
|
|
|
136
152
|
# doc = REXML::Document.new(raw_response, :ignore_whitespace_nodes => :all)
|
|
137
153
|
doc = Nokogiri::XML(raw_response)
|
|
138
154
|
|
|
139
155
|
if doc && doc.root && doc.root.name == "ApiException"
|
|
140
156
|
|
|
141
|
-
raise ApiException.new(doc.root.xpath("Type").text,
|
|
142
|
-
doc.root.xpath("Message").text,
|
|
157
|
+
raise ApiException.new(doc.root.xpath("Type").text,
|
|
158
|
+
doc.root.xpath("Message").text,
|
|
143
159
|
raw_response,
|
|
160
|
+
doc,
|
|
144
161
|
request_body)
|
|
145
162
|
|
|
146
163
|
else
|
|
@@ -8,20 +8,31 @@ module Xeroizer
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
class BankTransaction < Base
|
|
11
|
+
|
|
12
|
+
BANK_TRANSACTION_STATUS = {
|
|
13
|
+
'ACTIVE' => 'Active bank transactions',
|
|
14
|
+
'DELETED' => 'Deleted bank transactions',
|
|
15
|
+
} unless defined?(BANK_TRANSACTION_STATUS)
|
|
16
|
+
BANK_TRANSACTION_STATUSES = BANK_TRANSACTION_STATUS.keys.sort
|
|
17
|
+
|
|
18
|
+
|
|
11
19
|
def initialize(parent)
|
|
12
20
|
super parent
|
|
13
21
|
self.line_amount_types = "Exclusive"
|
|
14
22
|
end
|
|
15
23
|
|
|
16
24
|
set_primary_key :bank_transaction_id
|
|
25
|
+
list_contains_summary_only true
|
|
26
|
+
|
|
17
27
|
string :type
|
|
18
28
|
date :date
|
|
19
29
|
|
|
20
|
-
|
|
21
|
-
date
|
|
22
|
-
string
|
|
23
|
-
string
|
|
24
|
-
boolean
|
|
30
|
+
datetime_utc :updated_date_utc, :api_name => "UpdatedDateUTC"
|
|
31
|
+
date :fully_paid_on_date
|
|
32
|
+
string :reference
|
|
33
|
+
string :bank_transaction_id, :api_name => "BankTransactionID"
|
|
34
|
+
boolean :is_reconciled
|
|
35
|
+
string :status
|
|
25
36
|
|
|
26
37
|
alias_method :reconciled?, :is_reconciled
|
|
27
38
|
|
|
@@ -36,6 +47,7 @@ module Xeroizer
|
|
|
36
47
|
validates_inclusion_of :type,
|
|
37
48
|
:in => %w{SPEND RECEIVE}, :allow_blanks => false,
|
|
38
49
|
:message => "Invalid type. Expected either SPEND or RECEIVE."
|
|
50
|
+
validates_inclusion_of :status, :in => BANK_TRANSACTION_STATUSES, :unless => :new_record?
|
|
39
51
|
|
|
40
52
|
validates_presence_of :contact, :bank_account, :allow_blanks => false
|
|
41
53
|
|
|
@@ -18,23 +18,23 @@ module Xeroizer
|
|
|
18
18
|
set_possible_primary_keys :contact_id, :contact_number
|
|
19
19
|
list_contains_summary_only true
|
|
20
20
|
|
|
21
|
-
guid
|
|
22
|
-
string
|
|
23
|
-
string
|
|
24
|
-
string
|
|
25
|
-
string
|
|
26
|
-
string
|
|
27
|
-
string
|
|
28
|
-
string
|
|
29
|
-
string
|
|
30
|
-
string
|
|
31
|
-
string
|
|
32
|
-
string
|
|
33
|
-
string
|
|
34
|
-
string
|
|
35
|
-
|
|
36
|
-
boolean
|
|
37
|
-
boolean
|
|
21
|
+
guid :contact_id
|
|
22
|
+
string :contact_number
|
|
23
|
+
string :contact_status
|
|
24
|
+
string :name
|
|
25
|
+
string :tax_number
|
|
26
|
+
string :bank_account_details
|
|
27
|
+
string :accounts_receivable_tax_type
|
|
28
|
+
string :accounts_payable_tax_type
|
|
29
|
+
string :first_name
|
|
30
|
+
string :last_name
|
|
31
|
+
string :email_address
|
|
32
|
+
string :skype_user_name
|
|
33
|
+
string :contact_groups
|
|
34
|
+
string :default_currency
|
|
35
|
+
datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
|
|
36
|
+
boolean :is_supplier
|
|
37
|
+
boolean :is_customer
|
|
38
38
|
|
|
39
39
|
has_many :addresses, :list_complete => true
|
|
40
40
|
has_many :phones, :list_complete => true
|
|
@@ -44,24 +44,24 @@ module Xeroizer
|
|
|
44
44
|
set_possible_primary_keys :credit_note_id, :credit_note_number
|
|
45
45
|
list_contains_summary_only true
|
|
46
46
|
|
|
47
|
-
guid
|
|
48
|
-
string
|
|
49
|
-
string
|
|
50
|
-
string
|
|
51
|
-
date
|
|
52
|
-
date
|
|
53
|
-
string
|
|
54
|
-
string
|
|
55
|
-
decimal
|
|
56
|
-
decimal
|
|
57
|
-
decimal
|
|
58
|
-
|
|
59
|
-
string
|
|
60
|
-
datetime
|
|
61
|
-
boolean
|
|
47
|
+
guid :credit_note_id
|
|
48
|
+
string :credit_note_number
|
|
49
|
+
string :reference
|
|
50
|
+
string :type
|
|
51
|
+
date :date
|
|
52
|
+
date :due_date
|
|
53
|
+
string :status
|
|
54
|
+
string :line_amount_types
|
|
55
|
+
decimal :sub_total, :calculated => true
|
|
56
|
+
decimal :total_tax, :calculated => true
|
|
57
|
+
decimal :total, :calculated => true
|
|
58
|
+
datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
|
|
59
|
+
string :currency_code
|
|
60
|
+
datetime :fully_paid_on_date
|
|
61
|
+
boolean :sent_to_contact
|
|
62
62
|
|
|
63
|
-
belongs_to
|
|
64
|
-
has_many
|
|
63
|
+
belongs_to :contact
|
|
64
|
+
has_many :line_items
|
|
65
65
|
|
|
66
66
|
validates_inclusion_of :type, :in => CREDIT_NOTE_TYPES
|
|
67
67
|
validates_inclusion_of :status, :in => CREDIT_NOTE_STATUSES, :allow_blanks => true
|
|
@@ -127,4 +127,4 @@ module Xeroizer
|
|
|
127
127
|
end
|
|
128
128
|
|
|
129
129
|
end
|
|
130
|
-
end
|
|
130
|
+
end
|
|
@@ -2,7 +2,10 @@ module Xeroizer
|
|
|
2
2
|
module Record
|
|
3
3
|
|
|
4
4
|
class InvoiceModel < BaseModel
|
|
5
|
-
|
|
5
|
+
# To create a new invoice, use the folowing
|
|
6
|
+
# $xero_client.Invoice.build(type: 'ACCREC', ..., contact: {name: 'Foo Bar'},...)
|
|
7
|
+
# Note that we are not making an api request to xero just to get the contact
|
|
8
|
+
|
|
6
9
|
set_permissions :read, :write, :update
|
|
7
10
|
|
|
8
11
|
public
|
|
@@ -44,31 +47,31 @@ module Xeroizer
|
|
|
44
47
|
set_possible_primary_keys :invoice_id, :invoice_number
|
|
45
48
|
list_contains_summary_only true
|
|
46
49
|
|
|
47
|
-
guid
|
|
48
|
-
string
|
|
49
|
-
string
|
|
50
|
-
guid
|
|
51
|
-
string
|
|
52
|
-
string
|
|
53
|
-
date
|
|
54
|
-
date
|
|
55
|
-
string
|
|
56
|
-
string
|
|
57
|
-
decimal
|
|
58
|
-
decimal
|
|
59
|
-
decimal
|
|
60
|
-
decimal
|
|
61
|
-
decimal
|
|
62
|
-
decimal
|
|
63
|
-
|
|
64
|
-
string
|
|
65
|
-
datetime
|
|
66
|
-
boolean
|
|
50
|
+
guid :invoice_id
|
|
51
|
+
string :invoice_number
|
|
52
|
+
string :reference
|
|
53
|
+
guid :branding_theme_id
|
|
54
|
+
string :url
|
|
55
|
+
string :type
|
|
56
|
+
date :date
|
|
57
|
+
date :due_date
|
|
58
|
+
string :status
|
|
59
|
+
string :line_amount_types
|
|
60
|
+
decimal :sub_total, :calculated => true
|
|
61
|
+
decimal :total_tax, :calculated => true
|
|
62
|
+
decimal :total, :calculated => true
|
|
63
|
+
decimal :amount_due
|
|
64
|
+
decimal :amount_paid
|
|
65
|
+
decimal :amount_credited
|
|
66
|
+
datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
|
|
67
|
+
string :currency_code
|
|
68
|
+
datetime :fully_paid_on_date
|
|
69
|
+
boolean :sent_to_contact
|
|
67
70
|
|
|
68
|
-
belongs_to
|
|
69
|
-
has_many
|
|
70
|
-
has_many
|
|
71
|
-
has_many
|
|
71
|
+
belongs_to :contact
|
|
72
|
+
has_many :line_items
|
|
73
|
+
has_many :payments
|
|
74
|
+
has_many :credit_notes
|
|
72
75
|
|
|
73
76
|
validates_presence_of :date, :due_date, :unless => :new_record?
|
|
74
77
|
validates_inclusion_of :type, :in => INVOICE_TYPES
|
|
@@ -107,14 +110,24 @@ module Xeroizer
|
|
|
107
110
|
type == 'ACCREC'
|
|
108
111
|
end
|
|
109
112
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
def sub_total=(sub_total)
|
|
114
|
+
@sub_total_is_set = true
|
|
115
|
+
attributes[:sub_total] = sub_total
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def total_tax=(total_tax)
|
|
119
|
+
@total_tax_is_set = true
|
|
120
|
+
attributes[:total_tax] = total_tax
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def total=(total)
|
|
124
|
+
@total_is_set = true
|
|
125
|
+
attributes[:total] = total
|
|
126
|
+
end
|
|
114
127
|
|
|
115
128
|
# Calculate sub_total from line_items.
|
|
116
129
|
def sub_total(always_summary = false)
|
|
117
|
-
if
|
|
130
|
+
if !@sub_total_is_set && not_summary_or_loaded_record(always_summary)
|
|
118
131
|
sum = (line_items || []).inject(BigDecimal.new('0')) { | sum, line_item | sum + line_item.line_amount }
|
|
119
132
|
|
|
120
133
|
# If the default amount types are inclusive of 'tax' then remove the tax amount from this sub-total.
|
|
@@ -127,7 +140,7 @@ module Xeroizer
|
|
|
127
140
|
|
|
128
141
|
# Calculate total_tax from line_items.
|
|
129
142
|
def total_tax(always_summary = false)
|
|
130
|
-
if
|
|
143
|
+
if !@total_tax_is_set && not_summary_or_loaded_record(always_summary)
|
|
131
144
|
(line_items || []).inject(BigDecimal.new('0')) { | sum, line_item | sum + line_item.tax_amount }
|
|
132
145
|
else
|
|
133
146
|
attributes[:total_tax]
|
|
@@ -136,13 +149,22 @@ module Xeroizer
|
|
|
136
149
|
|
|
137
150
|
# Calculate the total from line_items.
|
|
138
151
|
def total(always_summary = false)
|
|
139
|
-
|
|
152
|
+
if !@total_is_set && not_summary_or_loaded_record(always_summary)
|
|
140
153
|
sub_total + total_tax
|
|
141
154
|
else
|
|
142
155
|
attributes[:total]
|
|
143
156
|
end
|
|
144
157
|
end
|
|
145
158
|
|
|
159
|
+
def not_summary_or_loaded_record(always_summary)
|
|
160
|
+
!always_summary && loaded_record?
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def loaded_record?
|
|
164
|
+
new_record? ||
|
|
165
|
+
(!new_record? && line_items && line_items.size > 0)
|
|
166
|
+
end
|
|
167
|
+
|
|
146
168
|
# Retrieve the PDF version of this invoice.
|
|
147
169
|
# @param [String] filename optional filename to store the PDF in instead of returning the data.
|
|
148
170
|
def pdf(filename = nil)
|