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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b4149d832f1cb36887a460f7f8258d049fdd991
4
- data.tar.gz: c8ea7a95afb25ee8f41f7a1f15f9f6ce4ae3914e
3
+ metadata.gz: ea62d6d6a33c98a88703fe9f1c6b675fcfa6731e
4
+ data.tar.gz: cf3504a3fafc2b1a8d65e274b03373a7dd466d75
5
5
  SHA512:
6
- metadata.gz: bbaef5a37d2b986f9e81f7b2cd229f501d711563f5634f2cc50125f541cca510386e5110dae6a483fd4782db4213641cc827ab6a6cab43b33bc43deaeb68c6ea
7
- data.tar.gz: e37566c54ffddbc031712a08ff0c3179ea26f8def7f75c709d9430ed01a185f70f639976741599bef4307ac9846034c533c060e982129311f23f7f0aaf60b884
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 365 days into the future).
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 1,000/day and 60/minute request per organisation limit.
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 1,000 requests
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
@@ -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'
@@ -97,6 +97,8 @@ module Xeroizer
97
97
 
98
98
  end
99
99
 
100
+ class RecordInvalid < XeroizerError; end
101
+
100
102
  class SettingTotalDirectlyNotSupported < XeroizerError
101
103
 
102
104
  def initialize(attribute_name)
@@ -25,6 +25,7 @@ module Xeroizer
25
25
  record :ExpenseClaim
26
26
  record :Invoice
27
27
  record :InvoiceReminder
28
+ record :OnlineInvoice
28
29
  record :Item
29
30
  record :Journal
30
31
  record :LineItem
@@ -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
- # http://developer.xero.com/documentation/advanced-docs/rounding-in-xero/#unitamount
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
 
@@ -51,6 +51,7 @@ module Xeroizer
51
51
  guid :credit_note_id
52
52
  string :credit_note_number
53
53
  string :reference
54
+ guid :branding_theme_id
54
55
  string :type
55
56
  date :date
56
57
  date :due_date
@@ -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
@@ -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
 
@@ -12,7 +12,7 @@ module Xeroizer
12
12
  decimal :unit_price
13
13
  string :account_code
14
14
  string :tax_type
15
- decimal :cogs_account_code
15
+ string :cogs_account_code, api_name: 'COGSAccountCode'
16
16
 
17
17
  end
18
18
 
@@ -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
@@ -105,12 +105,21 @@ module Xeroizer
105
105
  end
106
106
 
107
107
  def save
108
- return false unless valid?
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
@@ -1,3 +1,3 @@
1
1
  module Xeroizer
2
- VERSION = "2.17.1".freeze
2
+ VERSION = "2.18.1".freeze
3
3
  end
@@ -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
@@ -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
- KEY_FILE = ENV["KEY_FILE"] || "fake_key" unless defined?(KEY_FILE)
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
- expected = BigDecimal((line_item.quantity * (line_item.unit_amount)).to_s).round(2)
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.tax_amount = BigDecimal("0.15")
40
- line_item.discount_rate = BigDecimal("10.0")
36
+ line_item.discount_rate = BigDecimal("12.34")
41
37
 
42
- discount = (100 - line_item.discount_rate) / 100
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, "expected line amount zero when quantity is nil"
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, "expected line amount zero when quantity is zero"
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, "expected line amount zero when unit_amount is nil"
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, "expected line amount zero when unit_amount is zero"
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
@@ -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.17.1
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: 2017-10-19 00:00:00.000000000 Z
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 system API.
238
- email: wayne.robinson@gmail.com
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.12
657
+ rubygems_version: 2.6.14
646
658
  signing_key:
647
659
  specification_version: 4
648
- summary: Xero library
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