xeroizer 2.16.4 → 2.16.5

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: 0cc0fe7184f644131b2630c193d88ce469d3109d
4
- data.tar.gz: 3da9e63fe020b3c77224de62c4d3d250e7123958
3
+ metadata.gz: 661b00281b09048f7c58f3bc0e4c12d3401fc9c3
4
+ data.tar.gz: 79db1f4fa930e1deb41f78fd0cee48ee6e30ab95
5
5
  SHA512:
6
- metadata.gz: 266f870812795987caafea77646dc52a52dff4cc9208b3de83e692cf339966b70af9994a226c17891bfbdd92a5791c2c2eb2dca17e3aab6b0e567f61fb92044a
7
- data.tar.gz: 402f1cf46c08333f92d9159896ede4eaa2fb6c73645166d9bdf63f78c12bc6c0bd62e01bd17d815b66ebd3f9a3a107267e2e237bb21b095ec4522d1b4b604cda
6
+ metadata.gz: 5dec38c448515e18f9aad030a0ae05bcd7504133474fcc8b52d06be00947db73556416414bb528483810d894a97785d862540b4d7a4cdd948632b99c5ef0abdf
7
+ data.tar.gz: 091ef6309c0a17f85976b1135eaca233de6b3e7031b972bfbdc14c81b9016c67177f6fdf1ebdca9694047aba232a5f5c6d7e95cf2f1f1f49c13c3cab7b139156
data/README.md CHANGED
@@ -531,7 +531,7 @@ are welcome).
531
531
  Reports are accessed like the following example:
532
532
 
533
533
  ```ruby
534
- trial_balance = xero.TrialBalance.get(:date => '2011-03-21')
534
+ trial_balance = xero.TrialBalance.get(:date => DateTime.new(2011,3,21))
535
535
 
536
536
  # Array containing report headings.
537
537
  trial_balance.header.cells.map { | cell | cell.value }
@@ -588,6 +588,25 @@ client = Xeroizer::PublicApplication.new(YOUR_OAUTH_CONSUMER_KEY,
588
588
  :rate_limit_sleep => 2)
589
589
  ```
590
590
 
591
+ Xero API Nonce Used
592
+ -------------------
593
+
594
+ The Xero API seems to reject requests due to conflicts on occasion.
595
+
596
+ By default, the library will raise a `Xeroizer::OAuth::NonceUsed`
597
+ exception when one of these limits is exceeded.
598
+
599
+ If required, the library can handle these exceptions internally by sleeping 1 second and then repeating the last request.
600
+ You can set this option when initializing an application:
601
+
602
+ ```ruby
603
+ # Sleep for 2 seconds every time the rate limit is exceeded.
604
+ client = Xeroizer::PublicApplication.new(YOUR_OAUTH_CONSUMER_KEY,
605
+ YOUR_OAUTH_CONSUMER_SECRET,
606
+ :nonce_used_max_attempts => 3)
607
+ ```
608
+
609
+
591
610
  Logging
592
611
  ---------------
593
612
 
data/lib/xeroizer.rb CHANGED
@@ -3,6 +3,7 @@ require 'date'
3
3
  require 'forwardable'
4
4
  require 'active_support/inflector'
5
5
  require "active_support/core_ext/array"
6
+ require "active_support/core_ext/big_decimal/conversions"
6
7
  require 'oauth'
7
8
  require 'oauth/signature/rsa/sha1'
8
9
  require 'nokogiri'
@@ -13,7 +14,6 @@ require 'cgi'
13
14
 
14
15
  $: << File.expand_path(File.dirname(__FILE__))
15
16
 
16
- require 'big_decimal_to_s'
17
17
  require 'class_level_inheritable_attributes'
18
18
  require 'xeroizer/oauth'
19
19
  require 'xeroizer/http_encoding_helper'
@@ -51,6 +51,7 @@ require 'xeroizer/models/organisation'
51
51
  require 'xeroizer/models/payment'
52
52
  require 'xeroizer/models/prepayment'
53
53
  require 'xeroizer/models/phone'
54
+ require 'xeroizer/models/purchase_order'
54
55
  require 'xeroizer/models/receipt'
55
56
  require 'xeroizer/models/repeating_invoice'
56
57
  require 'xeroizer/models/schedule'
@@ -7,7 +7,7 @@ module Xeroizer
7
7
  extend Record::ApplicationHelper
8
8
 
9
9
  attr_reader :client, :xero_url, :logger, :rate_limit_sleep, :rate_limit_max_attempts,
10
- :default_headers, :unitdp, :before_request, :after_request
10
+ :default_headers, :unitdp, :before_request, :after_request, :nonce_used_max_attempts
11
11
 
12
12
  extend Forwardable
13
13
  def_delegators :client, :access_token
@@ -29,6 +29,7 @@ module Xeroizer
29
29
  record :Organisation
30
30
  record :Payment
31
31
  record :Prepayment
32
+ record :PurchaseOrder
32
33
  record :Receipt
33
34
  record :RepeatingInvoice
34
35
  record :Schedule
@@ -58,6 +59,7 @@ module Xeroizer
58
59
  @xero_url = options[:xero_url] || "https://api.xero.com/api.xro/2.0"
59
60
  @rate_limit_sleep = options[:rate_limit_sleep] || false
60
61
  @rate_limit_max_attempts = options[:rate_limit_max_attempts] || 5
62
+ @nonce_used_max_attempts = options[:nonce_used_max_attempts] || 1
61
63
  @default_headers = options[:default_headers] || {}
62
64
  @before_request = options.delete(:before_request)
63
65
  @after_request = options.delete(:after_request)
data/lib/xeroizer/http.rb CHANGED
@@ -121,6 +121,11 @@ module Xeroizer
121
121
  else
122
122
  handle_unknown_response_error!(response)
123
123
  end
124
+ rescue Xeroizer::OAuth::NonceUsed => exception
125
+ raise if attempts > nonce_used_max_attempts
126
+ logger.info("Nonce used: " + exception.to_s) if self.logger
127
+ sleep_for(1)
128
+ retry
124
129
  rescue Xeroizer::OAuth::RateLimitExceeded
125
130
  if self.rate_limit_sleep
126
131
  raise if attempts > rate_limit_max_attempts
@@ -157,6 +162,7 @@ module Xeroizer
157
162
  when "token_rejected" then raise OAuth::TokenInvalid.new(description)
158
163
  when "rate limit exceeded" then raise OAuth::RateLimitExceeded.new(description)
159
164
  when "consumer_key_unknown" then raise OAuth::ConsumerKeyUnknown.new(description)
165
+ when "nonce_used" then raise OAuth::NonceUsed.new(description)
160
166
  else raise OAuth::UnknownError.new(problem + ':' + description)
161
167
  end
162
168
  else
@@ -0,0 +1,13 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class AccountsPayableModel < BaseModel
5
+ set_permissions :read
6
+ end
7
+
8
+ class AccountsPayable < Base
9
+ decimal :outstanding
10
+ decimal :overdue
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class AccountsReceivableModel < BaseModel
5
+ set_permissions :read
6
+ end
7
+
8
+ class AccountsReceivable < Base
9
+ decimal :outstanding
10
+ decimal :overdue
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ require "xeroizer/models/accounts_receivable"
2
+ require "xeroizer/models/accounts_payable"
3
+
4
+ module Xeroizer
5
+ module Record
6
+
7
+ class BalancesModel < BaseModel
8
+ set_permissions :read
9
+ end
10
+
11
+ class Balances < Base
12
+ has_one :accounts_receivable
13
+ has_one :accounts_payable
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class BatchPaymentsModel < BaseModel
5
+ set_permissions :read
6
+ end
7
+
8
+ class BatchPayments < Base
9
+ guid :bank_account_number
10
+ string :bank_account_name
11
+ string :details
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class BillsModel < BaseModel
5
+ set_permissions :read
6
+ end
7
+
8
+ class Bills < Base
9
+ string :day
10
+ string :type
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,7 @@
1
1
  require "xeroizer/models/contact_person"
2
+ require "xeroizer/models/balances"
3
+ require "xeroizer/models/batch_payments"
4
+ require "xeroizer/models/payment_terms"
2
5
 
3
6
  module Xeroizer
4
7
  module Record
@@ -36,12 +39,12 @@ module Xeroizer
36
39
  string :skype_user_name
37
40
  string :contact_groups
38
41
  string :default_currency
39
- string :purchases_default_account_code
40
- string :sales_default_account_code
42
+ string :purchases_default_account_code
43
+ string :sales_default_account_code
41
44
  datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
42
45
  boolean :is_supplier
43
46
  boolean :is_customer
44
-
47
+
45
48
  has_many :addresses, :list_complete => true
46
49
  has_many :phones, :list_complete => true
47
50
  has_many :contact_groups
@@ -50,6 +53,10 @@ module Xeroizer
50
53
  has_many :sales_tracking_categories, :model_name => 'ContactSalesTrackingCategory'
51
54
  has_many :purchases_tracking_categories, :model_name => 'ContactPurchasesTrackingCategory'
52
55
 
56
+ has_one :balances ,:model_name => 'Balances', :list_complete => true
57
+ has_one :batch_payments ,:model_name => 'BatchPayments', :list_complete => true
58
+ has_one :payment_terms ,:model_name => 'PaymentTerms', :list_complete => true
59
+
53
60
  validates_presence_of :name, :unless => Proc.new { | contact | contact.contact_id.present?}
54
61
  validates_inclusion_of :contact_status, :in => CONTACT_STATUS.keys, :allow_blanks => true
55
62
 
@@ -0,0 +1,16 @@
1
+ require "xeroizer/models/bills"
2
+ require "xeroizer/models/sales"
3
+
4
+ module Xeroizer
5
+ module Record
6
+
7
+ class PaymentTermsModel < BaseModel
8
+ set_permissions :read
9
+ end
10
+
11
+ class PaymentTerms < Base
12
+ has_one :bills, :model_name => 'Bills'
13
+ has_one :sales, :model_name => 'Sales'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,49 @@
1
+ require "xeroizer/models/attachment"
2
+
3
+ module Xeroizer
4
+ module Record
5
+
6
+ class PurchaseOrderModel < BaseModel
7
+
8
+ set_permissions :read, :write, :update
9
+
10
+ include AttachmentModel::Extensions
11
+ end
12
+
13
+ class PurchaseOrder < Base
14
+ include Attachment::Extensions
15
+
16
+ set_primary_key :purchase_order_id
17
+ set_possible_primary_keys :purchase_order_id
18
+
19
+ guid :purchase_order_id
20
+ string :purchase_order_number
21
+ string :date_string
22
+ date :date
23
+ string :delivery_date_string
24
+ date :delivery_date
25
+ string :delivery_address
26
+ string :attention_to
27
+ string :telephone
28
+ string :delivery_instructions
29
+ boolean :has_errors
30
+ boolean :is_discounted
31
+ string :reference
32
+ string :type
33
+ string :currency_rate
34
+ string :currency_code
35
+ guid :branding_theme_id
36
+ string :status
37
+ string :line_amount_types
38
+ string :sub_total
39
+ string :total_tax
40
+ string :total
41
+ date :updated_date_UTC
42
+ boolean :has_attachments
43
+
44
+ has_many :line_items
45
+ belongs_to :contact, :model_name => 'Contact'
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,13 @@
1
+ module Xeroizer
2
+ module Record
3
+
4
+ class SalesModel < BaseModel
5
+ set_permissions :read
6
+ end
7
+
8
+ class Sales < Base
9
+ string :day
10
+ string :type
11
+ end
12
+ end
13
+ end
@@ -1,9 +1,9 @@
1
1
  # Copyright (c) 2008 Tim Connor <tlconnor@gmail.com>
2
- #
2
+ #
3
3
  # Permission to use, copy, modify, and/or distribute this software for any
4
4
  # purpose with or without fee is hereby granted, provided that the above
5
5
  # copyright notice and this permission notice appear in all copies.
6
- #
6
+ #
7
7
  # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
8
  # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
9
  # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -13,21 +13,22 @@
13
13
  # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
14
 
15
15
  module Xeroizer
16
-
17
- # Shamelessly taken from the XeroGateway library by Tim Connor which is shamelessly
16
+
17
+ # Shamelessly taken from the XeroGateway library by Tim Connor which is shamelessly
18
18
  # based on the Twitter Gem's OAuth implementation by John Nunemaker
19
19
  # Thanks!
20
- #
20
+ #
21
21
  # http://github.com/tlconnor/xero_gateway
22
22
  # http://twitter.rubyforge.org/
23
23
  # http://github.com/jnunemaker/twitter/
24
-
24
+
25
25
  class OAuth
26
-
26
+
27
27
  class TokenExpired < StandardError; end
28
28
  class TokenInvalid < StandardError; end
29
29
  class RateLimitExceeded < StandardError; end
30
30
  class ConsumerKeyUnknown < StandardError; end
31
+ class NonceUsed < StandardError; end
31
32
  class UnknownError < StandardError; end
32
33
 
33
34
  unless defined? XERO_CONSUMER_OPTIONS
@@ -36,20 +37,20 @@ module Xeroizer
36
37
  :request_token_path => "/oauth/RequestToken",
37
38
  :access_token_path => "/oauth/AccessToken",
38
39
  :authorize_path => "/oauth/Authorize",
39
- :ca_file => File.expand_path(File.join(File.dirname(__FILE__), 'ca-certificates.crt'))
40
+ #:ca_file => File.expand_path(File.join(File.dirname(__FILE__), 'ca-certificates.crt'))
40
41
  }.freeze
41
42
  end
42
-
43
+
43
44
  # Mixin real OAuth methods for consumer.
44
45
  extend Forwardable
45
46
  def_delegators :access_token, :get, :post, :put, :delete
46
-
47
+
47
48
  # @attr_reader [String] ctoken consumer key/token from application developer (found at http://api.xero.com for your application).
48
49
  # @attr_reader [String] csecret consumer secret from application developer (found at http://api.xero.com for your application).
49
50
  # @attr_reader [Time] expires_at time the AccessToken expires if using the PartnerApplication mode (usually 30 minutes for Xero).
50
51
  # @attr_reader [Time] authorization_expires_at time the session expires if using the ParnterApplication mode (usually 365 days for Xero).
51
52
  attr_reader :ctoken, :csecret, :consumer_options, :expires_at, :authorization_expires_at
52
-
53
+
53
54
  # @attr_reader [String] session_handle session handle used to renew AccessToken if using the PartnerApplication mode.
54
55
  # @attr_writer [String] session_handle session handle used to renew AccessToken if using the PartnerApplication mode.
55
56
  attr_accessor :session_handle
@@ -72,35 +73,35 @@ module Xeroizer
72
73
  @ctoken, @csecret = ctoken, csecret
73
74
  @consumer_options = XERO_CONSUMER_OPTIONS.merge(options)
74
75
  end
75
-
76
+
76
77
  # OAuth consumer creator.
77
- #
78
+ #
78
79
  # @return [OAuth::Consumer] consumer object for GET/POST/PUT methods.
79
80
  def consumer
80
81
  create_consumer
81
82
  end
82
-
83
- # RequestToken for PUBLIC/PARTNER authorisation
83
+
84
+ # RequestToken for PUBLIC/PARTNER authorisation
84
85
  # (used to redirect to Xero for authentication).
85
86
  #
86
87
  # @option params [String] :oauth_callback URL to redirect user to when they have authenticated your application with Xero. If not specified, the user will be shown an authorisation code on the screen that they need to get into your application.
87
88
  def request_token(params = {})
88
89
  consumer.get_request_token(params, {}, @consumer_options[:default_headers])
89
90
  end
90
-
91
+
91
92
  # Create an AccessToken from a PUBLIC/PARTNER authorisation.
92
93
  def authorize_from_request(rtoken, rsecret, params = {})
93
94
  request_token = ::OAuth::RequestToken.new(consumer, rtoken, rsecret)
94
95
  access_token = request_token.get_access_token(params, {}, @consumer_options[:default_headers])
95
96
  update_attributes_from_token(access_token)
96
97
  end
97
-
98
+
98
99
  # AccessToken created from authorize_from_access method.
99
100
  def access_token
100
101
  ::OAuth::AccessToken.new(consumer, @atoken, @asecret)
101
102
  end
102
-
103
- # Used for PRIVATE applications where the AccessToken uses the
103
+
104
+ # Used for PRIVATE applications where the AccessToken uses the
104
105
  # token/secret from Xero which would normally be used in the request.
105
106
  # No request authorisation necessary.
106
107
  #
@@ -109,13 +110,13 @@ module Xeroizer
109
110
  def authorize_from_access(atoken, asecret)
110
111
  @atoken, @asecret = atoken, asecret
111
112
  end
112
-
113
+
113
114
  # Renew an access token from a previously authorised token for a
114
115
  # PARTNER application.
115
116
  def renew_access_token(atoken = nil, asecret = nil, session_handle = nil)
116
117
  old_token = ::OAuth::RequestToken.new(consumer, atoken || @atoken, asecret || @asecret)
117
118
  access_token = old_token.get_access_token({
118
- :oauth_session_handle => (session_handle || @session_handle),
119
+ :oauth_session_handle => (session_handle || @session_handle),
119
120
  :token => old_token
120
121
  }, {}, @consumer_options[:default_headers])
121
122
  update_attributes_from_token(access_token)
@@ -19,7 +19,7 @@ module Xeroizer
19
19
  class_inheritable_attributes :optional_xml_root_name
20
20
  class_inheritable_attributes :xml_node_name
21
21
 
22
- DEFAULT_RECORDS_PER_BATCH_SAVE = 2000
22
+ DEFAULT_RECORDS_PER_BATCH_SAVE = 50
23
23
 
24
24
  include BaseModelHttpProxy
25
25
 
@@ -29,6 +29,8 @@ module Xeroizer
29
29
  self.attributes[field_name] = record
30
30
  end
31
31
  end
32
+
33
+ alias_method :has_one, :belongs_to
32
34
 
33
35
  def has_many(field_name, options = {})
34
36
  internal_field_name = options[:internal_name] || field_name
@@ -35,7 +35,7 @@ module Xeroizer
35
35
 
36
36
  def klass
37
37
  begin
38
- @_klass_cache ||= Xeroizer::Report.const_get(report_type)
38
+ @_klass_cache ||= Xeroizer::Report.const_get(report_type, false)
39
39
  rescue NameError => ex # use default class
40
40
  Base
41
41
  end
@@ -1,3 +1,3 @@
1
1
  module Xeroizer
2
- VERSION = "2.16.4".freeze
2
+ VERSION = "2.16.5".freeze
3
3
  end
@@ -5,36 +5,50 @@
5
5
  <DateTimeUTC>2010-12-20T04:13:44.7828584Z</DateTimeUTC>
6
6
  <Contacts>
7
7
  <Contact>
8
- <ContactID>f7eca431-5c97-4d24-93fd-004bb8a6c644</ContactID>
8
+ <ContactID>bd2270c3-8706-4c11-9cfb-000b551c3f51</ContactID>
9
9
  <ContactStatus>ACTIVE</ContactStatus>
10
- <Name>Test Company Changed 923099849</Name>
11
- <FirstName>Wayne</FirstName>
12
- <LastName>Robinson</LastName>
10
+ <Name>ABC Limited</Name>
11
+ <FirstName>Andrea</FirstName>
12
+ <LastName>Dutchess</LastName>
13
+ <EmailAddress>a.dutchess@abclimited.com</EmailAddress>
14
+ <SkypeUserName>skype.dutchess@abclimited.com</SkypeUserName>
15
+ <BankAccountDetails>skype.dutchess@abclimited.com</BankAccountDetails>
16
+ <TaxNumber>skype.dutchess@abclimited.com</TaxNumber>
17
+ <AccountsReceivableTaxType>INPUT2</AccountsReceivableTaxType>
18
+ <AccountsPayableTaxType>OUTPUT2</AccountsPayableTaxType>
13
19
  <Addresses>
14
20
  <Address>
15
21
  <AddressType>POBOX</AddressType>
16
- </Address>
22
+ <AddressLine1>P O Box 123</AddressLine1>
23
+ <City>Wellington</City>
24
+ <PostalCode>6011</PostalCode>
25
+ <AttentionTo>Andrea</AttentionTo>
26
+ </Address>
17
27
  <Address>
18
28
  <AddressType>STREET</AddressType>
19
29
  </Address>
20
30
  </Addresses>
21
31
  <Phones>
22
32
  <Phone>
23
- <PhoneType>DDI</PhoneType>
33
+ <PhoneType>DEFAULT</PhoneType>
34
+ <PhoneNumber>1111111</PhoneNumber>
35
+ <PhoneAreaCode>04</PhoneAreaCode>
36
+ <PhoneCountryCode>64</PhoneCountryCode>
24
37
  </Phone>
25
38
  <Phone>
26
- <PhoneType>DEFAULT</PhoneType>
39
+ <PhoneType>FAX</PhoneType>
27
40
  </Phone>
28
41
  <Phone>
29
42
  <PhoneType>MOBILE</PhoneType>
30
43
  </Phone>
31
44
  <Phone>
32
- <PhoneType>FAX</PhoneType>
45
+ <PhoneType>DDI</PhoneType>
33
46
  </Phone>
34
47
  </Phones>
35
- <UpdatedDateUTC>2010-12-16T15:06:41.727</UpdatedDateUTC>
48
+ <UpdatedDateUTC>2009-05-14T01:44:26.747</UpdatedDateUTC>
36
49
  <IsSupplier>false</IsSupplier>
37
- <IsCustomer>false</IsCustomer>
50
+ <IsCustomer>true</IsCustomer>
51
+ <DefaultCurrency>NZD</DefaultCurrency>
38
52
  </Contact>
39
53
  </Contacts>
40
- </Response>
54
+ </Response>
@@ -0,0 +1,79 @@
1
+ <Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
2
+ <Id>1238b00c-2fdd-4a8a-9b84-82cfe78ff34a</Id>
3
+ <Status>OK</Status>
4
+ <ProviderName>Test Provider Name</ProviderName>
5
+ <DateTimeUTC>2010-12-20T04:13:44.7828584Z</DateTimeUTC>
6
+ <Contacts>
7
+ <Contact>
8
+ <ContactID>bd2270c3-8706-4c11-9cfb-000b551c3f51</ContactID>
9
+ <ContactStatus>ACTIVE</ContactStatus>
10
+ <Name>ABC Limited</Name>
11
+ <FirstName>Andrea</FirstName>
12
+ <LastName>Dutchess</LastName>
13
+ <EmailAddress>a.dutchess@abclimited.com</EmailAddress>
14
+ <SkypeUserName>skype.dutchess@abclimited.com</SkypeUserName>
15
+ <BankAccountDetails>skype.dutchess@abclimited.com</BankAccountDetails>
16
+ <TaxNumber>skype.dutchess@abclimited.com</TaxNumber>
17
+ <AccountsReceivableTaxType>INPUT2</AccountsReceivableTaxType>
18
+ <AccountsPayableTaxType>OUTPUT2</AccountsPayableTaxType>
19
+ <Addresses>
20
+ <Address>
21
+ <AddressType>POBOX</AddressType>
22
+ <AddressLine1>P O Box 123</AddressLine1>
23
+ <City>Wellington</City>
24
+ <PostalCode>6011</PostalCode>
25
+ <AttentionTo>Andrea</AttentionTo>
26
+ </Address>
27
+ <Address>
28
+ <AddressType>STREET</AddressType>
29
+ </Address>
30
+ </Addresses>
31
+ <Phones>
32
+ <Phone>
33
+ <PhoneType>DEFAULT</PhoneType>
34
+ <PhoneNumber>1111111</PhoneNumber>
35
+ <PhoneAreaCode>04</PhoneAreaCode>
36
+ <PhoneCountryCode>64</PhoneCountryCode>
37
+ </Phone>
38
+ <Phone>
39
+ <PhoneType>FAX</PhoneType>
40
+ </Phone>
41
+ <Phone>
42
+ <PhoneType>MOBILE</PhoneType>
43
+ </Phone>
44
+ <Phone>
45
+ <PhoneType>DDI</PhoneType>
46
+ </Phone>
47
+ </Phones>
48
+ <UpdatedDateUTC>2009-05-14T01:44:26.747</UpdatedDateUTC>
49
+ <IsSupplier>false</IsSupplier>
50
+ <IsCustomer>true</IsCustomer>
51
+ <DefaultCurrency>NZD</DefaultCurrency>
52
+ <Balances>
53
+ <AccountsReceivable>
54
+ <Outstanding>849.50</Outstanding>
55
+ <Overdue>910.00</Overdue>
56
+ </AccountsReceivable>
57
+ <AccountsPayable>
58
+ <Outstanding>0.00</Outstanding>
59
+ <Overdue>0.00</Overdue>
60
+ </AccountsPayable>
61
+ </Balances>
62
+ <BatchPayments>
63
+ <BankAccountNumber>123456</BankAccountNumber>
64
+ <BankAccountName>bank account</BankAccountName>
65
+ <Details>details</Details>
66
+ </BatchPayments>
67
+ <PaymentTerms>
68
+ <Bills>
69
+ <Day>4</Day>
70
+ <Type>OFFOLLOWINGMONTH</Type>
71
+ </Bills>
72
+ <Sales>
73
+ <Day>2</Day>
74
+ <Type>OFFOLLOWINGMONTH</Type>
75
+ </Sales>
76
+ </PaymentTerms>
77
+ </Contact>
78
+ </Contacts>
79
+ </Response>
@@ -0,0 +1 @@
1
+ oauth_problem=nonce_used&oauth_problem_advice=The%20nonce%20value%20%22potatocakes%22%20has%20already%20been%20used%20
@@ -6,8 +6,8 @@ class BankTransactionTest < Test::Unit::TestCase
6
6
  def setup
7
7
 
8
8
  the_line_items = [
9
- LineItem.build({:quantity => 1, :tax_amount => 0.15, :unit_amount => 1.00, :tax_amount => 0.50}, nil),
10
- LineItem.build({:quantity => 1, :tax_amount => 0.15, :unit_amount => 1.00, :tax_amount => 0.50}, nil)
9
+ LineItem.build({:quantity => 1, :unit_amount => 1.00, :tax_amount => 0.50}, nil),
10
+ LineItem.build({:quantity => 1, :unit_amount => 1.00, :tax_amount => 0.50}, nil)
11
11
  ]
12
12
 
13
13
  @the_bank_transaction = BankTransaction.new(nil)
@@ -2,23 +2,54 @@ require 'test_helper'
2
2
 
3
3
  class ContactTest < Test::Unit::TestCase
4
4
  include TestHelper
5
-
5
+
6
6
  def setup
7
7
  @client = Xeroizer::PublicApplication.new(CONSUMER_KEY, CONSUMER_SECRET)
8
- @contact = @client.Contact.build
9
8
  end
10
-
9
+
11
10
  context "contact validators" do
12
-
13
11
  should "have a name" do
14
- assert_equal(false, @contact.valid?)
15
- blank_error = @contact.errors_for(:name).first
12
+ contact = @client.Contact.build
13
+
14
+ assert_equal(false, contact.valid?)
15
+ blank_error = contact.errors_for(:name).first
16
16
  assert_not_nil(blank_error)
17
17
  assert_equal("can't be blank", blank_error)
18
-
19
- @contact.name = "SOMETHING"
20
- assert_equal(true, @contact.valid?)
21
- assert_equal(0, @contact.errors.size)
18
+
19
+ contact.name = "SOMETHING"
20
+ assert_equal(true, contact.valid?)
21
+ assert_equal(0, contact.errors.size)
22
+ end
23
+ end
24
+
25
+ context "response parsing" do
26
+ it "parses default attributes" do
27
+ @instance = Xeroizer::Record::ContactModel.new(nil, "Contact")
28
+
29
+ some_xml = get_record_xml("contact")
30
+
31
+ result = @instance.parse_response(some_xml)
32
+ contact = result.response_items.first
33
+
34
+ keys = [:contact_id,
35
+ :contact_status,
36
+ :name,
37
+ :first_name,
38
+ :last_name,
39
+ :email_address,
40
+ :skype_user_name,
41
+ :bank_account_details,
42
+ :tax_number,
43
+ :accounts_receivable_tax_type,
44
+ :accounts_payable_tax_type,
45
+ :addresses,
46
+ :phones,
47
+ :updated_date_utc,
48
+ :is_supplier,
49
+ :is_customer,
50
+ :default_currency]
51
+
52
+ assert_equal(contact.attributes.keys, keys)
22
53
  end
23
54
 
24
55
  should "be able to have no name if has a contact_id" do
@@ -28,6 +59,49 @@ class ContactTest < Test::Unit::TestCase
28
59
  assert_equal(0, @contact.errors.size)
29
60
  end
30
61
 
62
+ it "parses extra attributes when present" do
63
+ @instance = Xeroizer::Record::ContactModel.new(nil, "Contact")
64
+ some_xml = get_record_xml("contact_with_details")
65
+
66
+ result = @instance.parse_response(some_xml)
67
+ contact = result.response_items.first
68
+
69
+ keys = [:contact_id,
70
+ :contact_status,
71
+ :name,
72
+ :first_name,
73
+ :last_name,
74
+ :email_address,
75
+ :skype_user_name,
76
+ :bank_account_details,
77
+ :tax_number,
78
+ :accounts_receivable_tax_type,
79
+ :accounts_payable_tax_type,
80
+ :addresses,
81
+ :phones,
82
+ :updated_date_utc,
83
+ :is_supplier,
84
+ :is_customer,
85
+ :default_currency,
86
+ :balances,
87
+ :batch_payments,
88
+ :payment_terms]
89
+
90
+ assert_equal(contact.attributes.keys, keys)
91
+
92
+ assert_equal(contact.balances.accounts_receivable.outstanding, 849.50)
93
+ assert_equal(contact.balances.accounts_receivable.overdue, 910.00)
94
+ assert_equal(contact.balances.accounts_payable.outstanding, 0.00)
95
+ assert_equal(contact.balances.accounts_payable.overdue, 0.00)
96
+
97
+ assert_equal(contact.batch_payments.bank_account_number, "123456")
98
+ assert_equal(contact.batch_payments.bank_account_name, "bank account")
99
+ assert_equal(contact.batch_payments.details, "details")
100
+
101
+ assert_equal(contact.payment_terms.bills.day, "4")
102
+ assert_equal(contact.payment_terms.bills.type, "OFFOLLOWINGMONTH")
103
+ assert_equal(contact.payment_terms.sales.day, "2")
104
+ assert_equal(contact.payment_terms.sales.type, "OFFOLLOWINGMONTH")
105
+ end
31
106
  end
32
-
33
107
  end
@@ -32,7 +32,15 @@ class OAuthTest < Test::Unit::TestCase
32
32
  @client.Organisation.first
33
33
  end
34
34
  end
35
+
36
+ should "handle nonce used" do
37
+ Xeroizer::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("nonce_used"), :code => "401"))
35
38
 
39
+ assert_raises Xeroizer::OAuth::NonceUsed do
40
+ @client.Organisation.first
41
+ end
42
+ end
43
+
36
44
  should "raise rate limit exceeded" do
37
45
  Xeroizer::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("rate_limit_exceeded"), :code => "401"))
38
46
 
@@ -65,7 +73,18 @@ class OAuthTest < Test::Unit::TestCase
65
73
  auto_rate_limit_client.Organisation.first
66
74
  end
67
75
  end
68
-
76
+
77
+ should "retry nonce_used failures a configurable number of times" do
78
+ nonce_used_client = Xeroizer::PublicApplication.new(CONSUMER_KEY, CONSUMER_SECRET, :nonce_used_max_attempts => 4)
79
+ Xeroizer::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("nonce_used"), :code => "401"))
80
+
81
+ nonce_used_client.expects(:sleep_for).with(1).times(4).returns(1)
82
+
83
+ assert_raises Xeroizer::OAuth::NonceUsed do
84
+ nonce_used_client.Organisation.first
85
+ end
86
+ end
87
+
69
88
  should "handle unknown errors" do
70
89
  Xeroizer::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("bogus_oauth_error"), :code => "401"))
71
90
 
@@ -1,5 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
+ class MockNonReportClassDefinition; end
4
+
3
5
  class FactoryTest < Test::Unit::TestCase
4
6
  include TestHelper
5
7
 
@@ -128,7 +130,16 @@ class FactoryTest < Test::Unit::TestCase
128
130
  end
129
131
 
130
132
  end
131
-
133
+
134
+ context "report factory in the dirty real world" do
135
+
136
+ should "not use inheritance to find report class" do
137
+ report = Xeroizer::Report::Factory.new(@client, :MockNonReportClassDefinition).klass
138
+ assert_equal(Xeroizer::Report::Base, report)
139
+ end
140
+
141
+ end
142
+
132
143
  private
133
144
 
134
145
  def check_valid_report_type(row)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xeroizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.16.4
4
+ version: 2.16.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wayne Robinson
@@ -242,7 +242,6 @@ extra_rdoc_files: []
242
242
  files:
243
243
  - LICENSE.txt
244
244
  - README.md
245
- - lib/big_decimal_to_s.rb
246
245
  - lib/class_level_inheritable_attributes.rb
247
246
  - lib/xeroizer.rb
248
247
  - lib/xeroizer/application_http_proxy.rb
@@ -254,11 +253,16 @@ files:
254
253
  - lib/xeroizer/http_encoding_helper.rb
255
254
  - lib/xeroizer/logging.rb
256
255
  - lib/xeroizer/models/account.rb
256
+ - lib/xeroizer/models/accounts_payable.rb
257
+ - lib/xeroizer/models/accounts_receivable.rb
257
258
  - lib/xeroizer/models/address.rb
258
259
  - lib/xeroizer/models/allocation.rb
259
260
  - lib/xeroizer/models/attachment.rb
261
+ - lib/xeroizer/models/balances.rb
260
262
  - lib/xeroizer/models/bank_account.rb
261
263
  - lib/xeroizer/models/bank_transaction.rb
264
+ - lib/xeroizer/models/batch_payments.rb
265
+ - lib/xeroizer/models/bills.rb
262
266
  - lib/xeroizer/models/branding_theme.rb
263
267
  - lib/xeroizer/models/contact.rb
264
268
  - lib/xeroizer/models/contact_group.rb
@@ -285,10 +289,13 @@ files:
285
289
  - lib/xeroizer/models/option.rb
286
290
  - lib/xeroizer/models/organisation.rb
287
291
  - lib/xeroizer/models/payment.rb
292
+ - lib/xeroizer/models/payment_terms.rb
288
293
  - lib/xeroizer/models/phone.rb
289
294
  - lib/xeroizer/models/prepayment.rb
295
+ - lib/xeroizer/models/purchase_order.rb
290
296
  - lib/xeroizer/models/receipt.rb
291
297
  - lib/xeroizer/models/repeating_invoice.rb
298
+ - lib/xeroizer/models/sales.rb
292
299
  - lib/xeroizer/models/schedule.rb
293
300
  - lib/xeroizer/models/tax_component.rb
294
301
  - lib/xeroizer/models/tax_rate.rb
@@ -336,6 +343,7 @@ files:
336
343
  - test/stub_responses/bogus_oauth_error
337
344
  - test/stub_responses/branding_themes.xml
338
345
  - test/stub_responses/contact.xml
346
+ - test/stub_responses/contact_with_details.xml
339
347
  - test/stub_responses/contacts.xml
340
348
  - test/stub_responses/create_credit_note.xml
341
349
  - test/stub_responses/create_invoice.xml
@@ -353,6 +361,7 @@ files:
353
361
  - test/stub_responses/items.xml
354
362
  - test/stub_responses/manual_journal.xml
355
363
  - test/stub_responses/manual_journals.xml
364
+ - test/stub_responses/nonce_used
356
365
  - test/stub_responses/organisation.xml
357
366
  - test/stub_responses/organisations.xml
358
367
  - test/stub_responses/payments.xml
@@ -619,7 +628,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
619
628
  version: '0'
620
629
  requirements: []
621
630
  rubyforge_project:
622
- rubygems_version: 2.4.8
631
+ rubygems_version: 2.5.1
623
632
  signing_key:
624
633
  specification_version: 4
625
634
  summary: Xero library
@@ -634,6 +643,7 @@ test_files:
634
643
  - test/stub_responses/bogus_oauth_error
635
644
  - test/stub_responses/branding_themes.xml
636
645
  - test/stub_responses/contact.xml
646
+ - test/stub_responses/contact_with_details.xml
637
647
  - test/stub_responses/contacts.xml
638
648
  - test/stub_responses/create_credit_note.xml
639
649
  - test/stub_responses/create_invoice.xml
@@ -651,6 +661,7 @@ test_files:
651
661
  - test/stub_responses/items.xml
652
662
  - test/stub_responses/manual_journal.xml
653
663
  - test/stub_responses/manual_journals.xml
664
+ - test/stub_responses/nonce_used
654
665
  - test/stub_responses/organisation.xml
655
666
  - test/stub_responses/organisations.xml
656
667
  - test/stub_responses/payments.xml
@@ -897,4 +908,3 @@ test_files:
897
908
  - test/unit/record_definition_test.rb
898
909
  - test/unit/report_definition_test.rb
899
910
  - test/unit/report_test.rb
900
- has_rdoc:
@@ -1,9 +0,0 @@
1
- class BigDecimal
2
-
3
- def to_s_with_default_format(format = 'F')
4
- to_s_without_default_format(format)
5
- end
6
- alias_method :to_s_without_default_format, :to_s
7
- alias_method :to_s, :to_s_with_default_format
8
-
9
- end