xeroizer 2.17.1 → 2.18.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +60 -3
- data/lib/xeroizer.rb +1 -0
- data/lib/xeroizer/exceptions.rb +2 -0
- data/lib/xeroizer/generic_application.rb +1 -0
- data/lib/xeroizer/http.rb +2 -2
- data/lib/xeroizer/models/contact.rb +2 -2
- data/lib/xeroizer/models/credit_note.rb +1 -0
- data/lib/xeroizer/models/currency.rb +14 -2
- data/lib/xeroizer/models/invoice.rb +3 -0
- data/lib/xeroizer/models/item.rb +2 -1
- data/lib/xeroizer/models/item_purchase_details.rb +1 -1
- data/lib/xeroizer/models/online_invoice.rb +37 -0
- data/lib/xeroizer/record/base.rb +10 -1
- data/lib/xeroizer/record/base_model_http_proxy.rb +33 -17
- data/lib/xeroizer/version.rb +1 -1
- data/test/acceptance/about_creating_bank_transactions_test.rb +12 -2
- data/test/acceptance/about_online_invoice_test.rb +29 -0
- data/test/test_helper.rb +1 -1
- data/test/unit/http_tsl_12_upgrade_test.rb +31 -0
- data/test/unit/models/contact_test.rb +18 -9
- data/test/unit/models/line_item_test.rb +11 -17
- data/test/unit/oauth_test.rb +2 -2
- data/test/unit/record/base_test.rb +58 -0
- data/test/unit/record/parse_params_test.rb +59 -0
- metadata +22 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea62d6d6a33c98a88703fe9f1c6b675fcfa6731e
|
4
|
+
data.tar.gz: cf3504a3fafc2b1a8d65e274b03373a7dd466d75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74c217092e28ee42009e40461d99e4b542a09531cba94cfe22f07544dfc5cf7fe35c10d95691a91ffbc152738d67a07470c043b061aa963688b970095db0011e
|
7
|
+
data.tar.gz: 35af4e22733df6241464e95b2a33b7020fbe5590df8e84292ceabdc3f2b0f830174f69d59693af9e09c77cd318c4132767ac2dbd542f7c8c09e9219a45f72cc3
|
data/README.md
CHANGED
@@ -225,7 +225,7 @@ access_secret = client.access_token.secret
|
|
225
225
|
Two other interesting attributes of the PartnerApplication client are:
|
226
226
|
|
227
227
|
> **`#expires_at`**: Time this AccessToken will expire (usually 30 minutes into the future).
|
228
|
-
> **`#authorization_expires_at`**: How long this organisation has authorised you to access their data (usually
|
228
|
+
> **`#authorization_expires_at`**: How long this organisation has authorised you to access their data (usually 10 years into the future).
|
229
229
|
|
230
230
|
#### AccessToken Renewal
|
231
231
|
|
@@ -269,7 +269,7 @@ Retrieves list of all records with matching options.
|
|
269
269
|
**Note:** Some records (Invoice, CreditNote) only return summary information for the contact and no line items
|
270
270
|
when returning them this list operation. This library takes care of automatically retrieving the
|
271
271
|
contact and line items from Xero on first access however, this first access has a large performance penalty
|
272
|
-
and will count as an extra query towards your
|
272
|
+
and will count as an extra query towards your 5,000/day and 60/minute request per organisation limit.
|
273
273
|
|
274
274
|
Valid options are:
|
275
275
|
|
@@ -460,7 +460,7 @@ minimum validation requirements for each of the record types.
|
|
460
460
|
|
461
461
|
### Bulk Creates & Updates
|
462
462
|
|
463
|
-
Xero has a hard daily limit on the number of API requests you can make (currently
|
463
|
+
Xero has a hard daily limit on the number of API requests you can make (currently 5,000 requests
|
464
464
|
per account per day). To save on requests, you can batch creates and updates into a single PUT or
|
465
465
|
POST call, like so:
|
466
466
|
|
@@ -512,6 +512,43 @@ contact.errors_for(:name) # will contain ["can't be blank"]
|
|
512
512
|
If something goes really wrong and the particular validation isn't handled by the internal
|
513
513
|
validators then the library may raise a `Xeroizer::ApiException`.
|
514
514
|
|
515
|
+
Example Use Cases
|
516
|
+
-------
|
517
|
+
|
518
|
+
Creating & Paying an invoice:
|
519
|
+
|
520
|
+
```ruby
|
521
|
+
contact = xero.Contact.first
|
522
|
+
|
523
|
+
# Build the Invoice, add a LineItem and save it
|
524
|
+
invoice = xero.Invoice.build(:type => "ACCREC", :contact => contact, :date => DateTime.new(2017,10,19), :due_date => DateTime.new(2017,11,19))
|
525
|
+
|
526
|
+
invoice.add_line_item(:description => 'test', :unit_amount => '200.00', :quantity => '1', :account_code => '200')
|
527
|
+
|
528
|
+
invoice.save
|
529
|
+
|
530
|
+
# An invoice created without a status will default to 'DRAFT'
|
531
|
+
invoice.approved?
|
532
|
+
|
533
|
+
# Payments can only be created against 'AUTHROISED' invoices
|
534
|
+
invoice.approve!
|
535
|
+
|
536
|
+
# Find the first bank account
|
537
|
+
bank_account = xero.Account.first(:where => {:type => 'BANK'})
|
538
|
+
|
539
|
+
# Create & save the payment
|
540
|
+
payment = xero.Payment.build(:invoice => invoice, :account => bank_account, :amount => '220.00')
|
541
|
+
payment.save
|
542
|
+
|
543
|
+
# Reload the invoice from the Xero API
|
544
|
+
invoice = xero.Invoice.find(invoice.id)
|
545
|
+
|
546
|
+
# Invoice status is now "PAID" & Payment details have been returned as well
|
547
|
+
invoice.status
|
548
|
+
invoice.payments.first
|
549
|
+
invoice.payments.first.date
|
550
|
+
```
|
551
|
+
|
515
552
|
Reports
|
516
553
|
-------
|
517
554
|
|
@@ -646,6 +683,26 @@ client = Xeroizer::PublicApplication.new(YOUR_OAUTH_CONSUMER_KEY,
|
|
646
683
|
|
647
684
|
This option adds the unitdp=4 query string parameter to all requests for models with line items - invoices, credit notes, bank transactions and receipts.
|
648
685
|
|
686
|
+
Tests
|
687
|
+
-----
|
688
|
+
|
689
|
+
The tests within the repository can be run by setting up a [Private App](https://developer.xero.com/documentation/auth-and-limits/private-applications). You can create a Private App in the [developer portal](https://developer.xero.com/myapps/), it's suggested that you create it against the [Demo Company](https://developer.xero.com/documentation/getting-started/development-accounts) (note: the Demo Company expires after 28 days, so you will need to reset it and create a new Private App if you Demo Company has expired).
|
690
|
+
|
691
|
+
Once you have created your Private App, set these environment variables:
|
692
|
+
```
|
693
|
+
EXPORT CONSUMER_KEY="your private app's consumer key"
|
694
|
+
EXPORT CONSUMER_SECRET="your private app's consumer secret"
|
695
|
+
EXPORT PRIVATE_KEY_PATH="the path to your private app's private key"
|
696
|
+
```
|
697
|
+
|
698
|
+
PRIVATE_KEY_PATH is the path to the private key for your Private App (you uploaded the Public Key when you created the Private App)
|
699
|
+
|
700
|
+
Then run the tests
|
701
|
+
```
|
702
|
+
rake test
|
703
|
+
```
|
704
|
+
|
705
|
+
|
649
706
|
### Contributors
|
650
707
|
Xeroizer was inspired by the https://github.com/tlconnor/xero_gateway gem created by Tim Connor
|
651
708
|
and Nik Wakelin and portions of the networking and authentication code are based completely off
|
data/lib/xeroizer.rb
CHANGED
@@ -44,6 +44,7 @@ require 'xeroizer/models/employee'
|
|
44
44
|
require 'xeroizer/models/expense_claim'
|
45
45
|
require 'xeroizer/models/invoice'
|
46
46
|
require 'xeroizer/models/invoice_reminder'
|
47
|
+
require 'xeroizer/models/online_invoice'
|
47
48
|
require 'xeroizer/models/item'
|
48
49
|
require 'xeroizer/models/item_purchase_details'
|
49
50
|
require 'xeroizer/models/item_sales_details'
|
data/lib/xeroizer/exceptions.rb
CHANGED
data/lib/xeroizer/http.rb
CHANGED
@@ -223,9 +223,9 @@ module Xeroizer
|
|
223
223
|
|
224
224
|
# unitdp query string parameter to be added to request params
|
225
225
|
# when the application option has been set and the model has line items
|
226
|
-
#
|
226
|
+
# https://developer.xero.com/documentation/api-guides/rounding-in-xero#unitamount
|
227
227
|
def unitdp_param(request_url)
|
228
|
-
models = [/Invoices/, /CreditNotes/, /BankTransactions/, /Receipts/]
|
228
|
+
models = [/Invoices/, /CreditNotes/, /BankTransactions/, /Receipts/, /Items/, /Overpayments/, /Prepayments/]
|
229
229
|
self.unitdp == 4 && models.any?{ |m| request_url =~ m } ? {:unitdp => 4} : {}
|
230
230
|
end
|
231
231
|
|
@@ -53,7 +53,7 @@ module Xeroizer
|
|
53
53
|
|
54
54
|
has_many :addresses, :list_complete => true
|
55
55
|
has_many :phones, :list_complete => true
|
56
|
-
has_many :contact_groups
|
56
|
+
has_many :contact_groups, :list_complete => true
|
57
57
|
has_many :contact_persons, :internal_name => :contact_people
|
58
58
|
|
59
59
|
has_many :sales_tracking_categories, :model_name => 'ContactSalesTrackingCategory'
|
@@ -63,7 +63,7 @@ module Xeroizer
|
|
63
63
|
has_one :batch_payments, :model_name => 'BatchPayments', :list_complete => true
|
64
64
|
has_one :payment_terms, :model_name => 'PaymentTerms', :list_complete => true
|
65
65
|
|
66
|
-
validates_presence_of :name, :unless => Proc.new { | contact | contact.contact_id.present?}
|
66
|
+
validates_presence_of :name, :unless => Proc.new { | contact | contact.contact_id.present? || contact.contact_number.present? }
|
67
67
|
validates_inclusion_of :contact_status, :in => CONTACT_STATUS.keys, :allow_blanks => true
|
68
68
|
validates_associated :addresses, allow_blanks: true
|
69
69
|
|
@@ -3,14 +3,26 @@ module Xeroizer
|
|
3
3
|
|
4
4
|
class CurrencyModel < BaseModel
|
5
5
|
|
6
|
-
set_permissions :read
|
6
|
+
set_permissions :read, :write
|
7
|
+
|
8
|
+
# Currencies can only be created (added), no update or delete is possible
|
9
|
+
def create_method
|
10
|
+
:http_put
|
11
|
+
end
|
7
12
|
|
8
13
|
end
|
9
14
|
|
10
15
|
class Currency < Base
|
16
|
+
|
17
|
+
# Currency does not have an ID
|
18
|
+
# This method overrides the base model to always treat a Currency as new (so it can be saved)
|
19
|
+
# Attempting to update a currency will result in a validation error.
|
20
|
+
def new_record?
|
21
|
+
true
|
22
|
+
end
|
11
23
|
|
12
24
|
string :code
|
13
|
-
string :description
|
25
|
+
string :description # read only
|
14
26
|
|
15
27
|
end
|
16
28
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "xeroizer/models/attachment"
|
2
|
+
require "xeroizer/models/online_invoice"
|
2
3
|
|
3
4
|
module Xeroizer
|
4
5
|
module Record
|
@@ -14,6 +15,7 @@ module Xeroizer
|
|
14
15
|
set_permissions :read, :write, :update
|
15
16
|
|
16
17
|
include AttachmentModel::Extensions
|
18
|
+
include OnlineInvoiceModel::Extensions
|
17
19
|
|
18
20
|
public
|
19
21
|
|
@@ -51,6 +53,7 @@ module Xeroizer
|
|
51
53
|
INVOICE_STATUSES = INVOICE_STATUS.keys.sort
|
52
54
|
|
53
55
|
include Attachment::Extensions
|
56
|
+
include OnlineInvoice::Extensions
|
54
57
|
|
55
58
|
set_primary_key :invoice_id
|
56
59
|
set_possible_primary_keys :invoice_id, :invoice_number
|
data/lib/xeroizer/models/item.rb
CHANGED
@@ -18,7 +18,6 @@ module Xeroizer
|
|
18
18
|
string :purchase_description
|
19
19
|
string :name
|
20
20
|
|
21
|
-
decimal :unit_price
|
22
21
|
decimal :total_cost_pool # read only
|
23
22
|
decimal :quantity_on_hand # read only
|
24
23
|
|
@@ -27,6 +26,8 @@ module Xeroizer
|
|
27
26
|
boolean :is_tracked_as_inventory # read only, infered from inventory_asset_account_code, cogs_account_code, is_sold and is_purchased
|
28
27
|
string :inventory_asset_account_code
|
29
28
|
|
29
|
+
datetime_utc :updated_date_utc, api_name: 'UpdatedDateUTC'
|
30
|
+
|
30
31
|
belongs_to :purchase_details, :model_name => 'ItemPurchaseDetails'
|
31
32
|
belongs_to :sales_details, :model_name => 'ItemSalesDetails'
|
32
33
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Xeroizer
|
2
|
+
module Record
|
3
|
+
|
4
|
+
class OnlineInvoiceModel < BaseModel
|
5
|
+
|
6
|
+
module Extensions
|
7
|
+
def online_invoice(id)
|
8
|
+
application.OnlineInvoice.online_invoice(url, id)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
set_permissions :read
|
13
|
+
|
14
|
+
def online_invoice(url, id)
|
15
|
+
response_xml = @application.http_get(@application.client, "#{url}/#{CGI.escape(id)}/OnlineInvoice")
|
16
|
+
|
17
|
+
response = parse_response(response_xml)
|
18
|
+
|
19
|
+
response.response_items.first
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class OnlineInvoice < Base
|
25
|
+
|
26
|
+
module Extensions
|
27
|
+
def online_invoice
|
28
|
+
parent.online_invoice(id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
string :online_invoice_url
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/xeroizer/record/base.rb
CHANGED
@@ -105,12 +105,21 @@ module Xeroizer
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def save
|
108
|
-
|
108
|
+
save!
|
109
|
+
true
|
110
|
+
rescue XeroizerError => e
|
111
|
+
log "[ERROR SAVING] (#{__FILE__}:#{__LINE__}) - #{e.message}"
|
112
|
+
false
|
113
|
+
end
|
114
|
+
|
115
|
+
def save!
|
116
|
+
raise RecordInvalid unless valid?
|
109
117
|
if new_record?
|
110
118
|
create
|
111
119
|
else
|
112
120
|
update
|
113
121
|
end
|
122
|
+
|
114
123
|
saved!
|
115
124
|
end
|
116
125
|
|
@@ -1,28 +1,34 @@
|
|
1
|
-
require 'xeroizer/application_http_proxy'
|
1
|
+
require 'xeroizer/application_http_proxy'
|
2
2
|
|
3
3
|
module Xeroizer
|
4
4
|
module Record
|
5
5
|
module BaseModelHttpProxy
|
6
|
-
|
6
|
+
|
7
7
|
def self.included(base)
|
8
8
|
base.send :include, Xeroizer::ApplicationHttpProxy
|
9
9
|
base.send :include, InstanceMethods
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
module InstanceMethods
|
13
|
-
|
13
|
+
|
14
14
|
protected
|
15
|
-
|
15
|
+
|
16
16
|
# Parse parameters for GET requests.
|
17
17
|
def parse_params(options)
|
18
18
|
params = {}
|
19
19
|
params[:ModifiedAfter] = options[:modified_since] if options[:modified_since]
|
20
20
|
params[:includeArchived] = options[:include_archived] if options[:include_archived]
|
21
21
|
params[:order] = options[:order] if options[:order]
|
22
|
+
params[:createdByMyApp] = options[:createdByMyApp] if options[:createdByMyApp]
|
23
|
+
|
24
|
+
params[:IDs] = filterize(options[:IDs]) if options[:IDs]
|
25
|
+
params[:InvoiceNumbers] = filterize(options[:InvoiceNumbers]) if options[:InvoiceNumbers]
|
26
|
+
params[:ContactIDs] = filterize(options[:ContactIDs]) if options[:ContactIDs]
|
27
|
+
params[:Statuses] = filterize(options[:Statuses]) if options[:Statuses]
|
22
28
|
|
23
29
|
if options[:where]
|
24
30
|
params[:where] = case options[:where]
|
25
|
-
when String then options[:where]
|
31
|
+
when String then options[:where]
|
26
32
|
when Hash then parse_where_hash(options[:where])
|
27
33
|
end
|
28
34
|
end
|
@@ -30,7 +36,7 @@ module Xeroizer
|
|
30
36
|
params[:page] = options[:page] if options[:page]
|
31
37
|
params
|
32
38
|
end
|
33
|
-
|
39
|
+
|
34
40
|
# Parse the :where part of the options for GET parameters and construct a valid
|
35
41
|
# .Net version of the criteria to pass to Xero.
|
36
42
|
#
|
@@ -46,14 +52,14 @@ module Xeroizer
|
|
46
52
|
(attribute_name, expression) = extract_expression_from_attribute_name(key)
|
47
53
|
(_, field) = model_class.fields.find { | k, v | v[:internal_name] == attribute_name }
|
48
54
|
if field
|
49
|
-
conditions << where_condition_part(field, expression, value)
|
55
|
+
conditions << where_condition_part(field, expression, value)
|
50
56
|
else
|
51
57
|
raise InvalidAttributeInWhere.new(model_name, attribute_name)
|
52
58
|
end
|
53
59
|
end
|
54
60
|
conditions.map { | (attr, expression, value) | "#{attr}#{expression}#{value}"}.join('&&')
|
55
61
|
end
|
56
|
-
|
62
|
+
|
57
63
|
# Extract the attribute name and expression from the attribute.
|
58
64
|
#
|
59
65
|
# @return [Array] containing [actual_attribute_name, expression]
|
@@ -64,37 +70,37 @@ module Xeroizer
|
|
64
70
|
key.to_s.gsub(/(_is_not|\<\>)$/, '').to_sym,
|
65
71
|
'<>'
|
66
72
|
]
|
67
|
-
|
73
|
+
|
68
74
|
when /(_is_greater_than|\>)$/
|
69
75
|
[
|
70
76
|
key.to_s.gsub(/(_is_greater_than|\>)$/, '').to_sym,
|
71
77
|
'>'
|
72
78
|
]
|
73
|
-
|
79
|
+
|
74
80
|
when /(_is_greater_than_or_equal_to|\>\=)$/
|
75
81
|
[
|
76
82
|
key.to_s.gsub(/(_is_greater_than_or_equal_to|\>\=)$/, '').to_sym,
|
77
83
|
'>='
|
78
84
|
]
|
79
|
-
|
85
|
+
|
80
86
|
when /(_is_less_than|\<)$/
|
81
87
|
[
|
82
88
|
key.to_s.gsub(/(_is_less_than|\<)$/, '').to_sym,
|
83
89
|
'<'
|
84
90
|
]
|
85
|
-
|
91
|
+
|
86
92
|
when /(_is_less_than_or_equal_to|\<\=)$/
|
87
93
|
[
|
88
94
|
key.to_s.gsub(/(_is_less_than_or_equal_to|\<\=)$/, '').to_sym,
|
89
95
|
'<='
|
90
96
|
]
|
91
|
-
|
97
|
+
|
92
98
|
else
|
93
99
|
[key, '==']
|
94
|
-
|
100
|
+
|
95
101
|
end
|
96
102
|
end
|
97
|
-
|
103
|
+
|
98
104
|
# Creates a condition part array containing the:
|
99
105
|
# * Field's API name
|
100
106
|
# * Expression
|
@@ -114,8 +120,18 @@ module Xeroizer
|
|
114
120
|
end
|
115
121
|
end
|
116
122
|
|
123
|
+
private
|
124
|
+
|
125
|
+
# Filtering params expect a comma separated list of strings
|
126
|
+
def filterize(values)
|
127
|
+
case values
|
128
|
+
when String then values
|
129
|
+
when Array then values.join(',')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
117
133
|
end
|
118
|
-
|
134
|
+
|
119
135
|
end
|
120
136
|
end
|
121
137
|
end
|
data/lib/xeroizer/version.rb
CHANGED
@@ -149,14 +149,24 @@ class AboutCreatingBankTransactions < Test::Unit::TestCase
|
|
149
149
|
}]
|
150
150
|
end
|
151
151
|
|
152
|
-
it "fails with ApiException when you try and create a new bank account with missing account type" do
|
152
|
+
it "fails with ApiException when you try and create a new bank account with missing account type with save! method" do
|
153
153
|
new_account = client.Account.build(
|
154
154
|
:name => "Example bank account",
|
155
155
|
:code => "ACC-001"
|
156
156
|
)
|
157
157
|
|
158
158
|
assert_raise Xeroizer::ApiException do
|
159
|
-
new_account.save
|
159
|
+
new_account.save!
|
160
160
|
end
|
161
161
|
end
|
162
|
+
|
163
|
+
it "returns false when you try and create a new bank account with a missing account type with save method" do
|
164
|
+
new_account = client.Account.build(
|
165
|
+
:name => "Example bank account",
|
166
|
+
:code => "ACC-001"
|
167
|
+
)
|
168
|
+
|
169
|
+
assert new_account.save == false, "Account save method expected to return false"
|
170
|
+
|
171
|
+
end
|
162
172
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "acceptance_test"
|
3
|
+
|
4
|
+
class AboutGetOnlineInvoiceUrl < Test::Unit::TestCase
|
5
|
+
include AcceptanceTest
|
6
|
+
|
7
|
+
let :client do
|
8
|
+
Xeroizer::PrivateApplication.new(@consumer_key, @consumer_secret, @key_file)
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
super
|
13
|
+
@invoice = client.Invoice.all(:where => 'Type=="ACCREC"').first
|
14
|
+
@invoice_acc_pay = client.Invoice.all(:where => 'Type=="ACCPAY"').first
|
15
|
+
end
|
16
|
+
|
17
|
+
can "Request OnlineInvoice of an AccRec invoice" do
|
18
|
+
@online_invoice = @invoice.online_invoice
|
19
|
+
|
20
|
+
assert @online_invoice.online_invoice_url, "online_invoice_url not found"
|
21
|
+
assert @online_invoice.online_invoice_url.start_with?('https://in.xero.com/'), "online_invoice_url returned in unexpected format"
|
22
|
+
end
|
23
|
+
|
24
|
+
can "Not request OnlineInvoice of an AccPay invoice" do
|
25
|
+
assert_raise do
|
26
|
+
@online_invoice_acc_pay = @invoice_acc_pay.online_invoice
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -26,7 +26,7 @@ module TestHelper
|
|
26
26
|
|
27
27
|
CONSUMER_KEY = ENV["CONSUMER_KEY"] || "fake_key" unless defined?(CONSUMER_KEY)
|
28
28
|
CONSUMER_SECRET = ENV["CONSUMER_SECRET"] || "fake_secret" unless defined?(CONSUMER_SECRET)
|
29
|
-
|
29
|
+
PRIVATE_KEY_PATH = ENV["PRIVATE_KEY_PATH"] || "fake_key" unless defined?(PRIVATE_KEY_PATH)
|
30
30
|
|
31
31
|
# Helper constant for checking regex
|
32
32
|
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)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class HttpTest < Test::Unit::TestCase
|
5
|
+
include TestHelper
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@application = Xeroizer::PrivateApplication.new(CONSUMER_KEY, CONSUMER_SECRET, PRIVATE_KEY_PATH, {:xero_url => 'https://api-tls.xero.com/', :site => 'https://api-tls.xero.com/'})
|
9
|
+
@applicationExternal = Xeroizer::PrivateApplication.new(CONSUMER_KEY, CONSUMER_SECRET, PRIVATE_KEY_PATH, {:xero_url => 'https://www.howsmyssl.com', :site => 'https://www.howsmyssl.com'})
|
10
|
+
end
|
11
|
+
|
12
|
+
context "Connect to Xero TLS 1.2 Test endpoint" do
|
13
|
+
should "receive a 301 response (endpoint redirects on success)" do
|
14
|
+
begin
|
15
|
+
@application.http_get(@application.client, "https://api-tls.xero.com/")
|
16
|
+
rescue Xeroizer::Http::BadResponse => e
|
17
|
+
assert_equal "Unknown response code: 301", e.message, "Unexpected Response Code (Xero): Check TLS 1.2 is set"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "Connect to external TLS 1.2 Test endpoint" do
|
24
|
+
should "respond with tls version 1.2" do
|
25
|
+
response = @applicationExternal.http_get(@applicationExternal.client, "https://www.howsmyssl.com/a/check")
|
26
|
+
jsonResponse = JSON.parse(response)
|
27
|
+
assert_equal "TLS 1.2", jsonResponse['tls_version'], "Unexpected Response (External): Check TLS 1.2 is set"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -21,6 +21,24 @@ class ContactTest < Test::Unit::TestCase
|
|
21
21
|
assert_equal(0, contact.errors.size)
|
22
22
|
end
|
23
23
|
|
24
|
+
should "be able to have no name if it has a contact_id" do
|
25
|
+
contact = @client.Contact.build
|
26
|
+
|
27
|
+
assert_equal(false, contact.valid?)
|
28
|
+
contact.contact_id = "1-2-3"
|
29
|
+
assert_equal(true, contact.valid?)
|
30
|
+
assert_equal(0, contact.errors.size)
|
31
|
+
end
|
32
|
+
|
33
|
+
should "be able to have no name if it has a contact_number" do
|
34
|
+
contact = @client.Contact.build
|
35
|
+
|
36
|
+
assert_equal(false, contact.valid?)
|
37
|
+
contact.contact_number = "abc123"
|
38
|
+
assert_equal(true, contact.valid?)
|
39
|
+
assert_equal(0, contact.errors.size)
|
40
|
+
end
|
41
|
+
|
24
42
|
should "not allow invalid addresses" do
|
25
43
|
contact = @client.Contact.build(name: "SOMETHING")
|
26
44
|
address = contact.add_address(:type => "INVALID_TYPE")
|
@@ -66,15 +84,6 @@ class ContactTest < Test::Unit::TestCase
|
|
66
84
|
assert_equal(contact.attributes.keys, keys)
|
67
85
|
end
|
68
86
|
|
69
|
-
should "be able to have no name if has a contact_id" do
|
70
|
-
contact = @client.Contact.build
|
71
|
-
|
72
|
-
assert_equal(false, contact.valid?)
|
73
|
-
contact.contact_id = "1-2-3"
|
74
|
-
assert_equal(true, contact.valid?)
|
75
|
-
assert_equal(0, contact.errors.size)
|
76
|
-
end
|
77
|
-
|
78
87
|
it "parses extra attributes when present" do
|
79
88
|
@instance = Xeroizer::Record::ContactModel.new(nil, "Contact")
|
80
89
|
some_xml = get_record_xml("contact_with_details")
|
@@ -24,11 +24,8 @@ class LineItemTest < Test::Unit::TestCase
|
|
24
24
|
|
25
25
|
line_item.quantity = 1
|
26
26
|
line_item.unit_amount = BigDecimal("1337.00")
|
27
|
-
line_item.tax_amount = BigDecimal("0.15")
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
assert_equal expected.to_s, line_item.line_amount.to_s,
|
28
|
+
assert_equal "1337.0", line_item.line_amount.to_s,
|
32
29
|
"expected line_amount to equal unit_amount times quantity"
|
33
30
|
end
|
34
31
|
|
@@ -36,12 +33,9 @@ class LineItemTest < Test::Unit::TestCase
|
|
36
33
|
line_item = LineItem.new(nil)
|
37
34
|
line_item.quantity = 1
|
38
35
|
line_item.unit_amount = BigDecimal("1337.00")
|
39
|
-
line_item.
|
40
|
-
line_item.discount_rate = BigDecimal("10.0")
|
36
|
+
line_item.discount_rate = BigDecimal("12.34")
|
41
37
|
|
42
|
-
|
43
|
-
expected = BigDecimal(((line_item.quantity * line_item.unit_amount) * discount).to_s).round(2)
|
44
|
-
assert_equal expected.to_s, line_item.line_amount.to_s,
|
38
|
+
assert_equal "1172.01", line_item.line_amount.to_s,
|
45
39
|
"expected line_amount to equal unit_amount times quantity minus the discount"
|
46
40
|
end
|
47
41
|
|
@@ -50,20 +44,19 @@ class LineItemTest < Test::Unit::TestCase
|
|
50
44
|
|
51
45
|
line_item.quantity = nil
|
52
46
|
line_item.unit_amount = BigDecimal("1.00")
|
53
|
-
line_item.tax_amount = BigDecimal("0.15")
|
54
47
|
|
55
|
-
assert_equal "0.0", line_item.line_amount.to_s,
|
48
|
+
assert_equal "0.0", line_item.line_amount.to_s,
|
49
|
+
"expected line amount to be zero when quantity is nil"
|
56
50
|
|
57
51
|
line_item.quantity = 0
|
58
|
-
assert_equal "0.0", line_item.line_amount.to_s,
|
52
|
+
assert_equal "0.0", line_item.line_amount.to_s,
|
53
|
+
"expected line amount to be zero when quantity is zero"
|
59
54
|
end
|
60
55
|
|
61
56
|
it "is not possible to set unit_amount to zero" do
|
62
57
|
line_item = LineItem.new(nil)
|
63
58
|
|
64
|
-
line_item.quantity = 1
|
65
59
|
line_item.unit_amount = nil
|
66
|
-
line_item.tax_amount = BigDecimal("0.15")
|
67
60
|
|
68
61
|
assert_equal 0.0, line_item.unit_amount,
|
69
62
|
"Expected setting unit_amount to nil to be ignored, i.e., it should remain zero"
|
@@ -74,11 +67,12 @@ class LineItemTest < Test::Unit::TestCase
|
|
74
67
|
|
75
68
|
line_item.quantity = 1
|
76
69
|
line_item.unit_amount = nil
|
77
|
-
line_item.tax_amount = BigDecimal("0.15")
|
78
70
|
|
79
|
-
assert_equal "0.0", line_item.line_amount.to_s,
|
71
|
+
assert_equal "0.0", line_item.line_amount.to_s,
|
72
|
+
"expected line amount to be zero when unit_amount is nil"
|
80
73
|
|
81
74
|
line_item.unit_amount = BigDecimal("0.00")
|
82
|
-
assert_equal "0.0", line_item.line_amount.to_s,
|
75
|
+
assert_equal "0.0", line_item.line_amount.to_s,
|
76
|
+
"expected line amount to be zero when unit_amount is zero"
|
83
77
|
end
|
84
78
|
end
|
data/test/unit/oauth_test.rb
CHANGED
@@ -99,7 +99,7 @@ class OAuthTest < Test::Unit::TestCase
|
|
99
99
|
|
100
100
|
assert_raises Xeroizer::ApiException do
|
101
101
|
contact = @client.Contact.build(:name => 'Test Contact')
|
102
|
-
contact.save
|
102
|
+
contact.save!
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
@@ -109,7 +109,7 @@ class OAuthTest < Test::Unit::TestCase
|
|
109
109
|
|
110
110
|
assert_raises Xeroizer::UnparseableResponse do
|
111
111
|
contact = @client.Contact.build(:name => 'Test Contact')
|
112
|
-
contact.save
|
112
|
+
contact.save!
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
@@ -103,4 +103,62 @@ class RecordBaseTest < Test::Unit::TestCase
|
|
103
103
|
an_example_instance.save
|
104
104
|
end
|
105
105
|
end
|
106
|
+
|
107
|
+
context 'saving' do
|
108
|
+
context 'invalid record' do
|
109
|
+
setup do
|
110
|
+
@contact.stubs(:valid?).returns(false)
|
111
|
+
end
|
112
|
+
|
113
|
+
must 'raise an exception saving with #save!' do
|
114
|
+
assert_raise(Xeroizer::RecordInvalid) do
|
115
|
+
@contact.save!
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
must 'return false saving with #save' do
|
120
|
+
assert_equal(false, @contact.save)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'api error received' do
|
125
|
+
setup do
|
126
|
+
response = get_file_as_string('api_exception.xml')
|
127
|
+
doc = Nokogiri::XML(response)
|
128
|
+
exception = Xeroizer::ApiException.new(doc.root.xpath("Type").text,
|
129
|
+
doc.root.xpath("Message").text,
|
130
|
+
response,
|
131
|
+
doc,
|
132
|
+
'<FakeRequest />')
|
133
|
+
|
134
|
+
@contact.stubs(:valid?).returns(true)
|
135
|
+
@contact.stubs(:create).raises(exception)
|
136
|
+
@contact.stubs(:update).raises(exception)
|
137
|
+
end
|
138
|
+
|
139
|
+
must 'raise an exception creating records with #save!' do
|
140
|
+
@contact.stubs(:new_record?).returns(true)
|
141
|
+
assert_raise(Xeroizer::ApiException) do
|
142
|
+
@contact.save!
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
must 'raise an exception updating records with #save!' do
|
147
|
+
@contact.stubs(:new_record?).returns(false)
|
148
|
+
assert_raise(Xeroizer::ApiException) do
|
149
|
+
@contact.save!
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
must 'return false creating records with #save' do
|
154
|
+
@contact.stubs(:new_record?).returns(true)
|
155
|
+
assert_equal(false, @contact.save)
|
156
|
+
end
|
157
|
+
|
158
|
+
must 'return false updating records with #save' do
|
159
|
+
@contact.stubs(:new_record?).returns(false)
|
160
|
+
assert_equal(false, @contact.save)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
106
164
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Xeroizer
|
4
|
+
module Record
|
5
|
+
|
6
|
+
class ParseParamTestModel < BaseModel
|
7
|
+
end
|
8
|
+
|
9
|
+
class ParseParamTest < Base
|
10
|
+
|
11
|
+
set_primary_key :primary_key_id
|
12
|
+
|
13
|
+
guid :primary_key_id
|
14
|
+
string :string1
|
15
|
+
boolean :boolean1
|
16
|
+
integer :integer1
|
17
|
+
decimal :decimal1
|
18
|
+
date :date1
|
19
|
+
datetime :datetime1
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class ParseParamsTest < Test::Unit::TestCase
|
27
|
+
include TestHelper
|
28
|
+
|
29
|
+
def setup
|
30
|
+
@client = Xeroizer::PublicApplication.new(CONSUMER_KEY, CONSUMER_SECRET)
|
31
|
+
@model = Xeroizer::Record::ParseParamTestModel.new(@client, "ParseParamTest")
|
32
|
+
end
|
33
|
+
|
34
|
+
context "should return valid and filtered params" do
|
35
|
+
should "filter unsupported keys" do
|
36
|
+
params = @model.send(:parse_params, {
|
37
|
+
:should_be_filtered_out => 'should be filtered',
|
38
|
+
:modified_since => Date.parse("2010-01-05"),
|
39
|
+
:include_archived => true,
|
40
|
+
:order => :order,
|
41
|
+
:where => 'where string',
|
42
|
+
:IDs => ['29ed7958-0466-486d-bf57-3fd966ea37d7', 'd561892a-9023-498c-a28d-c626ed3940d8'],
|
43
|
+
:InvoiceNumbers => 'INV-0034,INV-0035,INV-0036,INV-0037',
|
44
|
+
:ContactIDs => 'b919a496-1a1c-4fc6-b6ef-8c561e0dd8c2,8289cca4-90a9-466b-95f3-f0adf351b2ac',
|
45
|
+
:Statuses => ['DRAFT', nil, 'SUBMITTED'],
|
46
|
+
:offset => 100,
|
47
|
+
:page => 2
|
48
|
+
})
|
49
|
+
|
50
|
+
params.assert_valid_keys(:ModifiedAfter, :includeArchived, :order, :where,
|
51
|
+
:IDs, :InvoiceNumbers, :ContactIDs, :Statuses,
|
52
|
+
:offset, :page)
|
53
|
+
assert_equal(params[:IDs], '29ed7958-0466-486d-bf57-3fd966ea37d7,d561892a-9023-498c-a28d-c626ed3940d8')
|
54
|
+
assert_equal(params[:InvoiceNumbers], 'INV-0034,INV-0035,INV-0036,INV-0037')
|
55
|
+
assert_equal(params[:ContactIDs], 'b919a496-1a1c-4fc6-b6ef-8c561e0dd8c2,8289cca4-90a9-466b-95f3-f0adf351b2ac')
|
56
|
+
assert_equal(params[:Statuses], 'DRAFT,,SUBMITTED')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xeroizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.18.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wayne Robinson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -234,8 +234,11 @@ dependencies:
|
|
234
234
|
- - ">="
|
235
235
|
- !ruby/object:Gem::Version
|
236
236
|
version: '0'
|
237
|
-
description: Ruby library for the Xero accounting
|
238
|
-
|
237
|
+
description: Ruby library for the Xero accounting API. Originally developed by Wayne
|
238
|
+
Robinson, now maintained by the Xero API Team & Xero/Ruby developer community.
|
239
|
+
email:
|
240
|
+
- wayne.robinson@gmail.com
|
241
|
+
- api@xero.com
|
239
242
|
executables: []
|
240
243
|
extensions: []
|
241
244
|
extra_rdoc_files: []
|
@@ -289,6 +292,7 @@ files:
|
|
289
292
|
- lib/xeroizer/models/line_item_sum.rb
|
290
293
|
- lib/xeroizer/models/manual_journal.rb
|
291
294
|
- lib/xeroizer/models/manual_journal_line.rb
|
295
|
+
- lib/xeroizer/models/online_invoice.rb
|
292
296
|
- lib/xeroizer/models/option.rb
|
293
297
|
- lib/xeroizer/models/organisation.rb
|
294
298
|
- lib/xeroizer/models/overpayment.rb
|
@@ -347,6 +351,7 @@ files:
|
|
347
351
|
- test/acceptance/about_creating_bank_transactions_test.rb
|
348
352
|
- test/acceptance/about_creating_prepayment_test.rb
|
349
353
|
- test/acceptance/about_fetching_bank_transactions_test.rb
|
354
|
+
- test/acceptance/about_online_invoice_test.rb
|
350
355
|
- test/acceptance/acceptance_test.rb
|
351
356
|
- test/acceptance/bank_transaction_reference_data.rb
|
352
357
|
- test/acceptance/bank_transfer_test.rb
|
@@ -591,6 +596,7 @@ files:
|
|
591
596
|
- test/test_helper.rb
|
592
597
|
- test/unit/generic_application_test.rb
|
593
598
|
- test/unit/http_test.rb
|
599
|
+
- test/unit/http_tsl_12_upgrade_test.rb
|
594
600
|
- test/unit/models/address_test.rb
|
595
601
|
- test/unit/models/bank_transaction_model_parsing_test.rb
|
596
602
|
- test/unit/models/bank_transaction_test.rb
|
@@ -616,6 +622,7 @@ files:
|
|
616
622
|
- test/unit/record/base_test.rb
|
617
623
|
- test/unit/record/block_validator_test.rb
|
618
624
|
- test/unit/record/model_definition_test.rb
|
625
|
+
- test/unit/record/parse_params_test.rb
|
619
626
|
- test/unit/record/parse_where_hash_test.rb
|
620
627
|
- test/unit/record/record_association_test.rb
|
621
628
|
- test/unit/record/validators_test.rb
|
@@ -625,7 +632,12 @@ files:
|
|
625
632
|
homepage: http://github.com/waynerobinson/xeroizer
|
626
633
|
licenses:
|
627
634
|
- MIT
|
628
|
-
metadata:
|
635
|
+
metadata:
|
636
|
+
bug_tracker_uri: https://github.com/waynerobinson/xeroizer/issues
|
637
|
+
changelog_uri: https://github.com/waynerobinson/xeroizer/releases
|
638
|
+
source_code_uri: https://github.com/waynerobinson/xeroizer
|
639
|
+
documentation_uri: https://developer.xero.com/documentation/
|
640
|
+
mailing_list_uri: https://developer.xero.com/subscribe-to-the-xero-api-developer-mailing-list
|
629
641
|
post_install_message:
|
630
642
|
rdoc_options: []
|
631
643
|
require_paths:
|
@@ -642,14 +654,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
642
654
|
version: '0'
|
643
655
|
requirements: []
|
644
656
|
rubyforge_project:
|
645
|
-
rubygems_version: 2.6.
|
657
|
+
rubygems_version: 2.6.14
|
646
658
|
signing_key:
|
647
659
|
specification_version: 4
|
648
|
-
summary: Xero
|
660
|
+
summary: Ruby Library for Xero accounting API
|
649
661
|
test_files:
|
650
662
|
- test/acceptance/about_creating_bank_transactions_test.rb
|
651
663
|
- test/acceptance/about_creating_prepayment_test.rb
|
652
664
|
- test/acceptance/about_fetching_bank_transactions_test.rb
|
665
|
+
- test/acceptance/about_online_invoice_test.rb
|
653
666
|
- test/acceptance/acceptance_test.rb
|
654
667
|
- test/acceptance/bank_transaction_reference_data.rb
|
655
668
|
- test/acceptance/bank_transfer_test.rb
|
@@ -894,6 +907,7 @@ test_files:
|
|
894
907
|
- test/test_helper.rb
|
895
908
|
- test/unit/generic_application_test.rb
|
896
909
|
- test/unit/http_test.rb
|
910
|
+
- test/unit/http_tsl_12_upgrade_test.rb
|
897
911
|
- test/unit/models/address_test.rb
|
898
912
|
- test/unit/models/bank_transaction_model_parsing_test.rb
|
899
913
|
- test/unit/models/bank_transaction_test.rb
|
@@ -919,6 +933,7 @@ test_files:
|
|
919
933
|
- test/unit/record/base_test.rb
|
920
934
|
- test/unit/record/block_validator_test.rb
|
921
935
|
- test/unit/record/model_definition_test.rb
|
936
|
+
- test/unit/record/parse_params_test.rb
|
922
937
|
- test/unit/record/parse_where_hash_test.rb
|
923
938
|
- test/unit/record/record_association_test.rb
|
924
939
|
- test/unit/record/validators_test.rb
|