xeroizer 2.15.9 → 2.16.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +59 -1
- data/lib/xeroizer/exceptions.rb +14 -11
- data/lib/xeroizer/generic_application.rb +8 -1
- data/lib/xeroizer/http.rb +19 -10
- data/lib/xeroizer/models/attachment.rb +15 -13
- data/lib/xeroizer/models/bank_transaction.rb +3 -1
- data/lib/xeroizer/models/branding_theme.rb +1 -1
- data/lib/xeroizer/models/contact.rb +3 -1
- data/lib/xeroizer/models/credit_note.rb +26 -2
- data/lib/xeroizer/models/employee.rb +49 -4
- data/lib/xeroizer/models/invoice.rb +1 -1
- data/lib/xeroizer/models/journal.rb +3 -1
- data/lib/xeroizer/models/journal_line.rb +1 -0
- data/lib/xeroizer/models/journal_line_tracking_category.rb +2 -1
- data/lib/xeroizer/models/line_item.rb +1 -0
- data/lib/xeroizer/models/manual_journal.rb +1 -1
- data/lib/xeroizer/models/organisation.rb +41 -1
- data/lib/xeroizer/models/phone.rb +2 -1
- data/lib/xeroizer/models/prepayment.rb +39 -0
- data/lib/xeroizer/models/repeating_invoice.rb +80 -0
- data/lib/xeroizer/models/schedule.rb +33 -0
- data/lib/xeroizer/record/base.rb +6 -0
- data/lib/xeroizer/record/base_model.rb +41 -26
- data/lib/xeroizer/record/record_association_helper.rb +1 -1
- data/lib/xeroizer/record/validation_helper.rb +6 -2
- data/lib/xeroizer/record/validators/length_of_validator.rb +23 -0
- data/lib/xeroizer/record/xml_helper.rb +10 -2
- data/lib/xeroizer/version.rb +1 -1
- data/lib/xeroizer.rb +3 -0
- data/test/stub_responses/prepayments.xml +27 -0
- data/test/stub_responses/records/prepayment-7d3619b1-82cc-405b-8f44-9d4f9a787a8a.xml +92 -0
- data/test/stub_responses/records/repeating_invoice-ad3550bc-1ae0-45c0-a782-48c6d2061127.xml +43 -0
- data/test/stub_responses/repeating_invoices.xml +43 -0
- data/test/unit/models/contact_test.rb +1 -1
- data/test/unit/models/employee_test.rb +43 -0
- data/test/unit/models/invoice_test.rb +21 -1
- data/test/unit/models/journal_test.rb +44 -0
- data/test/unit/models/manual_journal_test.rb +25 -0
- data/test/unit/models/organisation_test.rb +38 -0
- data/test/unit/models/phone_test.rb +31 -0
- data/test/unit/models/prepayment_test.rb +21 -0
- data/test/unit/models/repeating_invoice_test.rb +36 -0
- data/test/unit/record/base_test.rb +4 -2
- metadata +27 -1
data/README.md
CHANGED
@@ -183,7 +183,7 @@ Partner applications are only in beta testing via the Xero API and you will need
|
|
183
183
|
get permission to create a partner application and for them to send you information on obtaining your client-side SSL
|
184
184
|
certificate.
|
185
185
|
|
186
|
-
Ruby's OpenSSL library
|
186
|
+
Ruby's OpenSSL library requires the certificate and private key to be extracted from the `entrust-client.p12` file
|
187
187
|
downloaded via Xero's instructions. To extract:
|
188
188
|
|
189
189
|
openssl pkcs12 -in entrust-client.p12 -clcerts -nokeys -out entrust-cert.pem
|
@@ -391,6 +391,36 @@ invoice = xero.Invoice.find('cd09aa49-134d-40fb-a52b-b63c6a91d712')
|
|
391
391
|
puts "Invoice Contact Name: #{invoice.contact.name}"
|
392
392
|
```
|
393
393
|
|
394
|
+
Attachments
|
395
|
+
------------
|
396
|
+
Files or raw data can be attached to record types
|
397
|
+
**attach\_data examples:**
|
398
|
+
```ruby
|
399
|
+
invoice = xero.Invoice.find('cd09aa49-134d-40fb-a52b-b63c6a91d712')
|
400
|
+
invoice.attach_data("example.txt", "This is raw data", "txt")
|
401
|
+
```
|
402
|
+
|
403
|
+
```ruby
|
404
|
+
attach_data('cd09aa49-134d-40fb-a52b-b63c6a91d712', "example.txt", "This is raw data", "txt")
|
405
|
+
```
|
406
|
+
|
407
|
+
**attach\_file examples:**
|
408
|
+
```ruby
|
409
|
+
invoice = xero.Invoice.find('cd09aa49-134d-40fb-a52b-b63c6a91d712')
|
410
|
+
invoice.attach_file("example.png", "/path/to/image.png", "image/png")
|
411
|
+
```
|
412
|
+
|
413
|
+
```ruby
|
414
|
+
attach_file('cd09aa49-134d-40fb-a52b-b63c6a91d712', "example.png", "/path/to/image.png", "image/png")
|
415
|
+
```
|
416
|
+
|
417
|
+
**include with online invoice**
|
418
|
+
To include an attachment with an invoice set include_online parameter to true within the options hash
|
419
|
+
```ruby
|
420
|
+
invoice = xero.Invoice.find('cd09aa49-134d-40fb-a52b-b63c6a91d712')
|
421
|
+
invoice.attach_file("example.png", "/path/to/image.png", "image/png", { include_online: true })
|
422
|
+
```
|
423
|
+
|
394
424
|
Creating/Updating Data
|
395
425
|
----------------------
|
396
426
|
|
@@ -456,6 +486,15 @@ unsaved records aren't valid, it'll return `false` before sending anything acros
|
|
456
486
|
otherwise, it returns `true`. `batch_save` takes one optional argument: the number of records to
|
457
487
|
create/update per request. (Defaults to 2,000.)
|
458
488
|
|
489
|
+
If you'd rather build and send the records manually, there's a `save_records` method:
|
490
|
+
```ruby
|
491
|
+
contact1 = xero.Contact.build(some_attributes)
|
492
|
+
contact2 = xero.Contact.build(some_other_attributes)
|
493
|
+
contact3 = xero.Contact.build(some_more_attributes)
|
494
|
+
xero.Contact.save_records([contact1, contact2, contact3])
|
495
|
+
```
|
496
|
+
It has the same return values as `batch_save`.
|
497
|
+
|
459
498
|
### Errors
|
460
499
|
|
461
500
|
If a record doesn't match its internal validation requirements, the `#save` method will return
|
@@ -561,6 +600,25 @@ client = Xeroizer::PublicApplication.new(YOUR_OAUTH_CONSUMER_KEY,
|
|
561
600
|
:logger => XeroLogger)
|
562
601
|
```
|
563
602
|
|
603
|
+
HTTP Callbacks
|
604
|
+
--------------------
|
605
|
+
|
606
|
+
You can provide "before" and "after" callbacks which will be invoked every
|
607
|
+
time Xeroizer makes an HTTP request, which is potentially useful for both
|
608
|
+
throttling and logging:
|
609
|
+
|
610
|
+
```ruby
|
611
|
+
Xeroizer::PublicApplication.new(
|
612
|
+
credentials[:key], credentials[:secret],
|
613
|
+
before_request: ->(request) { puts "Hitting this URL: #{request.url}" },
|
614
|
+
after_request: ->(request, response) { puts "Got this response: #{response.code}" }
|
615
|
+
)
|
616
|
+
```
|
617
|
+
|
618
|
+
The `request` parameter is a custom Struct with `url`, `headers`, `body`,
|
619
|
+
and `params` methods. The `response` parameter is a Net::HTTPResponse object.
|
620
|
+
|
621
|
+
|
564
622
|
Unit Price Precision
|
565
623
|
--------------------
|
566
624
|
|
data/lib/xeroizer/exceptions.rb
CHANGED
@@ -13,7 +13,10 @@
|
|
13
13
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
14
|
|
15
15
|
module Xeroizer
|
16
|
-
|
16
|
+
|
17
|
+
class XeroizerError < StandardError; end
|
18
|
+
|
19
|
+
class ApiException < XeroizerError
|
17
20
|
|
18
21
|
attr_reader :type, :message, :xml, :parsed_xml, :request_body
|
19
22
|
|
@@ -41,7 +44,7 @@ module Xeroizer
|
|
41
44
|
|
42
45
|
end
|
43
46
|
|
44
|
-
class UnparseableResponse <
|
47
|
+
class UnparseableResponse < XeroizerError
|
45
48
|
|
46
49
|
def initialize(root_element_name)
|
47
50
|
@root_element_name = root_element_name
|
@@ -53,7 +56,7 @@ module Xeroizer
|
|
53
56
|
|
54
57
|
end
|
55
58
|
|
56
|
-
class ObjectNotFound <
|
59
|
+
class ObjectNotFound < XeroizerError
|
57
60
|
|
58
61
|
def initialize(api_endpoint)
|
59
62
|
@api_endpoint = api_endpoint
|
@@ -65,11 +68,11 @@ module Xeroizer
|
|
65
68
|
|
66
69
|
end
|
67
70
|
|
68
|
-
class InvoiceNotFoundError <
|
71
|
+
class InvoiceNotFoundError < XeroizerError; end
|
69
72
|
|
70
|
-
class CreditNoteNotFoundError <
|
73
|
+
class CreditNoteNotFoundError < XeroizerError; end
|
71
74
|
|
72
|
-
class MethodNotAllowed <
|
75
|
+
class MethodNotAllowed < XeroizerError
|
73
76
|
|
74
77
|
def initialize(klass, method)
|
75
78
|
@klass = klass
|
@@ -82,7 +85,7 @@ module Xeroizer
|
|
82
85
|
|
83
86
|
end
|
84
87
|
|
85
|
-
class RecordKeyMustBeDefined <
|
88
|
+
class RecordKeyMustBeDefined < XeroizerError
|
86
89
|
|
87
90
|
def initialize(possible_keys)
|
88
91
|
@possible_keys = possible_keys
|
@@ -94,7 +97,7 @@ module Xeroizer
|
|
94
97
|
|
95
98
|
end
|
96
99
|
|
97
|
-
class SettingTotalDirectlyNotSupported <
|
100
|
+
class SettingTotalDirectlyNotSupported < XeroizerError
|
98
101
|
|
99
102
|
def initialize(attribute_name)
|
100
103
|
@attribute_name = attribute_name
|
@@ -106,7 +109,7 @@ module Xeroizer
|
|
106
109
|
|
107
110
|
end
|
108
111
|
|
109
|
-
class InvalidAttributeInWhere <
|
112
|
+
class InvalidAttributeInWhere < XeroizerError
|
110
113
|
|
111
114
|
def initialize(model_name, attribute_name)
|
112
115
|
@model_name = model_name
|
@@ -119,7 +122,7 @@ module Xeroizer
|
|
119
122
|
|
120
123
|
end
|
121
124
|
|
122
|
-
class AssociationTypeMismatch <
|
125
|
+
class AssociationTypeMismatch < XeroizerError
|
123
126
|
|
124
127
|
def initialize(model_class, actual_class)
|
125
128
|
@model_class = model_class
|
@@ -132,7 +135,7 @@ module Xeroizer
|
|
132
135
|
|
133
136
|
end
|
134
137
|
|
135
|
-
class CannotChangeInvoiceStatus <
|
138
|
+
class CannotChangeInvoiceStatus < XeroizerError
|
136
139
|
|
137
140
|
def initialize(invoice, new_status)
|
138
141
|
@invoice = invoice
|
@@ -6,12 +6,14 @@ module Xeroizer
|
|
6
6
|
include Http
|
7
7
|
extend Record::ApplicationHelper
|
8
8
|
|
9
|
-
attr_reader :client, :xero_url, :logger, :rate_limit_sleep, :rate_limit_max_attempts,
|
9
|
+
attr_reader :client, :xero_url, :logger, :rate_limit_sleep, :rate_limit_max_attempts,
|
10
|
+
:default_headers, :unitdp, :before_request, :after_request
|
10
11
|
|
11
12
|
extend Forwardable
|
12
13
|
def_delegators :client, :access_token
|
13
14
|
|
14
15
|
record :Account
|
16
|
+
record :Allocation
|
15
17
|
record :Attachment
|
16
18
|
record :BrandingTheme
|
17
19
|
record :Contact
|
@@ -26,7 +28,10 @@ module Xeroizer
|
|
26
28
|
record :ManualJournal
|
27
29
|
record :Organisation
|
28
30
|
record :Payment
|
31
|
+
record :Prepayment
|
29
32
|
record :Receipt
|
33
|
+
record :RepeatingInvoice
|
34
|
+
record :Schedule
|
30
35
|
record :TaxRate
|
31
36
|
record :TrackingCategory
|
32
37
|
record :TrackingCategoryChild
|
@@ -54,6 +59,8 @@ module Xeroizer
|
|
54
59
|
@rate_limit_sleep = options[:rate_limit_sleep] || false
|
55
60
|
@rate_limit_max_attempts = options[:rate_limit_max_attempts] || 5
|
56
61
|
@default_headers = options[:default_headers] || {}
|
62
|
+
@before_request = options.delete(:before_request)
|
63
|
+
@after_request = options.delete(:after_request)
|
57
64
|
@client = OAuth.new(consumer_key, consumer_secret, options.merge({default_headers: default_headers}))
|
58
65
|
@logger = options[:logger] || false
|
59
66
|
@unitdp = options[:unitdp] || 2
|
data/lib/xeroizer/http.rb
CHANGED
@@ -15,6 +15,7 @@
|
|
15
15
|
module Xeroizer
|
16
16
|
module Http
|
17
17
|
class BadResponse < StandardError; end
|
18
|
+
RequestInfo = Struct.new(:url, :headers, :params, :body)
|
18
19
|
|
19
20
|
ACCEPT_MIME_MAP = {
|
20
21
|
:pdf => 'application/pdf',
|
@@ -57,9 +58,9 @@ module Xeroizer
|
|
57
58
|
|
58
59
|
headers = self.default_headers.merge({ 'charset' => 'utf-8' })
|
59
60
|
|
60
|
-
# include the unitdp query string parameter
|
61
|
+
# include the unitdp query string parameter
|
61
62
|
params.merge!(unitdp_param(url))
|
62
|
-
|
63
|
+
|
63
64
|
if method != :get
|
64
65
|
headers['Content-Type'] ||= "application/x-www-form-urlencoded"
|
65
66
|
end
|
@@ -84,10 +85,13 @@ module Xeroizer
|
|
84
85
|
url += "?" + params.map {|key,value| "#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}"}.join("&")
|
85
86
|
end
|
86
87
|
|
87
|
-
uri
|
88
|
+
uri = URI.parse(url)
|
88
89
|
|
89
90
|
attempts = 0
|
90
91
|
|
92
|
+
request_info = RequestInfo.new(url, headers, params, body)
|
93
|
+
before_request.call(request_info) if before_request
|
94
|
+
|
91
95
|
begin
|
92
96
|
attempts += 1
|
93
97
|
logger.info("XeroGateway Request: #{method.to_s.upcase} #{uri.request_uri}") if self.logger
|
@@ -100,12 +104,8 @@ module Xeroizer
|
|
100
104
|
when :put then client.put(uri.request_uri, raw_body, headers)
|
101
105
|
end
|
102
106
|
|
103
|
-
|
104
|
-
|
105
|
-
unless response.code.to_i == 200
|
106
|
-
logger.info("#{uri.request_uri}\n== Response Body\n\n#{response.plain_body}\n== End Response Body")
|
107
|
-
end
|
108
|
-
end
|
107
|
+
log_response(response, uri)
|
108
|
+
after_request.call(request_info, response) if after_request
|
109
109
|
|
110
110
|
case response.code.to_i
|
111
111
|
when 200
|
@@ -133,7 +133,16 @@ module Xeroizer
|
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
-
|
136
|
+
def log_response(response, uri)
|
137
|
+
if self.logger
|
138
|
+
logger.info("XeroGateway Response (#{response.code})")
|
139
|
+
logger.add(response.code.to_i == 200 ? Logger::DEBUG : Logger::INFO) {
|
140
|
+
"#{uri.request_uri}\n== Response Body\n\n#{response.plain_body}\n== End Response Body"
|
141
|
+
}
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def handle_oauth_error!(response)
|
137
146
|
error_details = CGI.parse(response.plain_body)
|
138
147
|
description = error_details["oauth_problem_advice"].first
|
139
148
|
problem = error_details["oauth_problem"].first
|
@@ -4,12 +4,12 @@ module Xeroizer
|
|
4
4
|
class AttachmentModel < BaseModel
|
5
5
|
|
6
6
|
module Extensions
|
7
|
-
def attach_data(id, filename, data, content_type = "application/octet-stream")
|
8
|
-
application.Attachment.attach_data(url, id, filename, data, content_type)
|
7
|
+
def attach_data(id, filename, data, content_type = "application/octet-stream", options = {})
|
8
|
+
application.Attachment.attach_data(url, id, filename, data, content_type, options)
|
9
9
|
end
|
10
10
|
|
11
|
-
def attach_file(id, filename, path, content_type = "application/octet-stream")
|
12
|
-
application.Attachment.attach_file(url, id, filename, path, content_type)
|
11
|
+
def attach_file(id, filename, path, content_type = "application/octet-stream", options = {})
|
12
|
+
application.Attachment.attach_file(url, id, filename, path, content_type, options)
|
13
13
|
end
|
14
14
|
|
15
15
|
def attachments(id)
|
@@ -19,11 +19,13 @@ module Xeroizer
|
|
19
19
|
|
20
20
|
set_permissions :read
|
21
21
|
|
22
|
-
def attach_data(url, id, filename, data, content_type)
|
22
|
+
def attach_data(url, id, filename, data, content_type, options = {})
|
23
|
+
options = { include_online: false }.merge(options)
|
24
|
+
|
23
25
|
response_xml = @application.http_put(@application.client,
|
24
26
|
"#{url}/#{CGI.escape(id)}/Attachments/#{CGI.escape(filename)}",
|
25
27
|
data,
|
26
|
-
:raw_body => true, :content_type => content_type
|
28
|
+
:raw_body => true, :content_type => content_type, "IncludeOnline" => options[:include_online]
|
27
29
|
)
|
28
30
|
response = parse_response(response_xml)
|
29
31
|
if (response_items = response.response_items) && response_items.size > 0
|
@@ -33,8 +35,8 @@ module Xeroizer
|
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
|
-
def attach_file(url, id, filename, path, content_type)
|
37
|
-
attach_data(url, id, filename, File.read(path), content_type)
|
38
|
+
def attach_file(url, id, filename, path, content_type, options = {})
|
39
|
+
attach_data(url, id, filename, File.read(path), content_type, options)
|
38
40
|
end
|
39
41
|
|
40
42
|
def attachments_for(url, id)
|
@@ -54,12 +56,12 @@ module Xeroizer
|
|
54
56
|
class Attachment < Base
|
55
57
|
|
56
58
|
module Extensions
|
57
|
-
def attach_file(filename, path, content_type = "application/octet-stream")
|
58
|
-
parent.attach_file(id, filename, path, content_type)
|
59
|
+
def attach_file(filename, path, content_type = "application/octet-stream", options = {})
|
60
|
+
parent.attach_file(id, filename, path, content_type, options)
|
59
61
|
end
|
60
62
|
|
61
|
-
def attach_data(filename, data, content_type = "application/octet-stream")
|
62
|
-
parent.attach_data(id, filename, data, content_type)
|
63
|
+
def attach_data(filename, data, content_type = "application/octet-stream", options = {})
|
64
|
+
parent.attach_data(id, filename, data, content_type, options)
|
63
65
|
end
|
64
66
|
|
65
67
|
def attachments
|
@@ -90,4 +92,4 @@ module Xeroizer
|
|
90
92
|
end
|
91
93
|
|
92
94
|
end
|
93
|
-
end
|
95
|
+
end
|
@@ -38,12 +38,14 @@ module Xeroizer
|
|
38
38
|
string :bank_transaction_id, :api_name => "BankTransactionID"
|
39
39
|
boolean :is_reconciled
|
40
40
|
string :status
|
41
|
+
string :currency_code
|
42
|
+
decimal :currency_rate
|
41
43
|
|
42
44
|
alias_method :reconciled?, :is_reconciled
|
43
45
|
|
44
46
|
belongs_to :contact, :model_name => 'Contact'
|
45
47
|
string :line_amount_types
|
46
|
-
has_many :line_items, :model_name => 'LineItem'
|
48
|
+
has_many :line_items, :model_name => 'LineItem', :complete_on_page => true
|
47
49
|
belongs_to :bank_account, :model_name => 'BankAccount'
|
48
50
|
|
49
51
|
validates_inclusion_of :line_amount_types,
|
@@ -36,10 +36,12 @@ module Xeroizer
|
|
36
36
|
string :skype_user_name
|
37
37
|
string :contact_groups
|
38
38
|
string :default_currency
|
39
|
+
string :purchases_default_account_code
|
40
|
+
string :sales_default_account_code
|
39
41
|
datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
|
40
42
|
boolean :is_supplier
|
41
43
|
boolean :is_customer
|
42
|
-
|
44
|
+
|
43
45
|
has_many :addresses, :list_complete => true
|
44
46
|
has_many :phones, :list_complete => true
|
45
47
|
has_many :contact_groups
|
@@ -126,8 +126,32 @@ module Xeroizer
|
|
126
126
|
def pdf(filename = nil)
|
127
127
|
parent.pdf(id, filename)
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
|
+
def save
|
131
|
+
# Calling parse_save_response() on the credit note will wipe out
|
132
|
+
# the allocations, so we have to manually preserve them.
|
133
|
+
allocations_backup = self.allocations
|
134
|
+
if super
|
135
|
+
self.allocations = allocations_backup
|
136
|
+
allocate unless self.allocations.empty?
|
137
|
+
true
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def allocate
|
142
|
+
if self.class.possible_primary_keys && self.class.possible_primary_keys.all? { | possible_key | self[possible_key].nil? }
|
143
|
+
raise RecordKeyMustBeDefined.new(self.class.possible_primary_keys)
|
144
|
+
end
|
145
|
+
|
146
|
+
request = association_to_xml(:allocations)
|
147
|
+
allocations_url = "#{parent.url}/#{CGI.escape(id)}/Allocations"
|
148
|
+
|
149
|
+
log "[ALLOCATION SENT] (#{__FILE__}:#{__LINE__}) \r\n#{request}"
|
150
|
+
response = parent.application.http_put(parent.application.client, allocations_url, request)
|
151
|
+
log "[ALLOCATION RECEIVED] (#{__FILE__}:#{__LINE__}) \r\n#{response}"
|
152
|
+
parse_save_response(response)
|
153
|
+
end
|
130
154
|
end
|
131
|
-
|
155
|
+
|
132
156
|
end
|
133
157
|
end
|
@@ -17,12 +17,57 @@ module Xeroizer
|
|
17
17
|
string :status
|
18
18
|
string :first_name
|
19
19
|
string :last_name
|
20
|
+
date :date_of_birth
|
20
21
|
|
21
|
-
|
22
|
+
# Optional attributes
|
23
|
+
string :gender # M or F
|
24
|
+
string :email
|
25
|
+
string :phone # (max length = 50, but AU only?)
|
26
|
+
string :mobile # (max length = 50)
|
27
|
+
date :start_date
|
28
|
+
date :termination_date
|
29
|
+
boolean :is_authorised_to_approve_timesheets
|
30
|
+
string :employee_group_name
|
22
31
|
|
23
|
-
|
32
|
+
datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
|
24
33
|
|
34
|
+
belongs_to :external_link
|
35
|
+
|
36
|
+
validates_presence_of :first_name, :last_name, :date_of_birth
|
37
|
+
|
25
38
|
end
|
26
|
-
|
39
|
+
|
40
|
+
# # AU Only API
|
41
|
+
# class EmployeeAU < Employee
|
42
|
+
# string :occupation
|
43
|
+
# string :classification # length: 100
|
44
|
+
# string :ordinary_earnings_rate_id
|
45
|
+
# boolean :is_authorised_to_approve_leave
|
46
|
+
|
47
|
+
# string :title # (max length = 10)
|
48
|
+
# string :twitter_user_name # (max length = 50)
|
49
|
+
# # PayrollCalendarID Xero unique identifier for payroll calendar for the employee
|
50
|
+
# # BankAccounts See BankAccount
|
51
|
+
# # SuperMemberships See SuperMemberships
|
52
|
+
# end
|
53
|
+
|
54
|
+
# # US Only API
|
55
|
+
# class EmployeeUS < Employee
|
56
|
+
# string :middle_names #max length = 35
|
57
|
+
# string :job_title
|
58
|
+
# string :employee_number
|
59
|
+
# string :social_security_number # (xxx-xx-xxxx)
|
60
|
+
# string :holiday_group_id
|
61
|
+
# string :pay_schedule_id
|
62
|
+
# string :employment_basis # One of http://developer.xero.com/documentation/payroll-api-us/Types-Codes/#EmploymentBasis
|
63
|
+
# boolean :is_authorised_to_approve_time_off
|
64
|
+
|
65
|
+
# # MailingAddress - US only, has_one relationship
|
66
|
+
# # SalaryAndWages See SalaryAndWages
|
67
|
+
# # WorkLocations See WorkLocations
|
68
|
+
# # PaymentMethod See PaymentMethods
|
69
|
+
# # PayTemplate See PayTemplate
|
70
|
+
# # OpeningBalances See OpeningBalances
|
71
|
+
# end
|
27
72
|
end
|
28
|
-
end
|
73
|
+
end
|
@@ -14,8 +14,10 @@ module Xeroizer
|
|
14
14
|
guid :journal_id
|
15
15
|
date :journal_date, :internal_name => :date
|
16
16
|
string :journal_number
|
17
|
-
|
17
|
+
datetime_utc :created_date_utc, :api_name => 'CreatedDateUTC'
|
18
18
|
string :reference
|
19
|
+
guid :source_id
|
20
|
+
string :source_type
|
19
21
|
|
20
22
|
has_many :journal_lines
|
21
23
|
|
@@ -29,7 +29,7 @@ module Xeroizer
|
|
29
29
|
boolean :show_on_cash_basis_reports
|
30
30
|
datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
|
31
31
|
|
32
|
-
has_many :journal_lines, :model_name => 'ManualJournalLine'
|
32
|
+
has_many :journal_lines, :model_name => 'ManualJournalLine', :complete_on_page => true
|
33
33
|
|
34
34
|
validates_presence_of :narration
|
35
35
|
validates_associated :journal_lines
|
@@ -10,6 +10,28 @@ module Xeroizer
|
|
10
10
|
|
11
11
|
class Organisation < Base
|
12
12
|
|
13
|
+
SALES_TAX_BASIS = {
|
14
|
+
'NZ' =>
|
15
|
+
{'PAYMENTS' => 'Payments Basis',
|
16
|
+
'INVOICE' => 'Invoice Basis',
|
17
|
+
'NONE' => 'None'},
|
18
|
+
'GB' =>
|
19
|
+
{
|
20
|
+
'CASH' => 'Cash Scheme',
|
21
|
+
'ACCRUAL' => 'Accrual Scheme',
|
22
|
+
'FLATRATECASH' => 'Flate Rate Cash Scheme',
|
23
|
+
'NONE' => 'None'
|
24
|
+
},
|
25
|
+
'GLOBAL' =>
|
26
|
+
{
|
27
|
+
'CASH' => 'Cash Basis',
|
28
|
+
'ACCRUALS' => 'Accruals Basis',
|
29
|
+
'NONE' => 'None'
|
30
|
+
}
|
31
|
+
} unless defined?(SALES_TAX_BASES)
|
32
|
+
|
33
|
+
SALES_TAX_BASES = SALES_TAX_BASIS.values.map(&:keys).flatten.sort
|
34
|
+
|
13
35
|
string :api_key, :api_name => 'APIKey'
|
14
36
|
string :name
|
15
37
|
string :legal_name
|
@@ -23,16 +45,34 @@ module Xeroizer
|
|
23
45
|
string :organisation_status
|
24
46
|
integer :financial_year_end_day
|
25
47
|
integer :financial_year_end_month
|
48
|
+
string :sales_tax_basis
|
49
|
+
string :sales_tax_period
|
26
50
|
date :period_lock_date
|
27
51
|
date :end_of_year_lock_date
|
28
52
|
string :tax_number
|
29
53
|
string :registration_number
|
30
54
|
string :timezone
|
31
|
-
|
55
|
+
datetime_utc :created_date_utc, :api_name => 'CreatedDateUTC'
|
56
|
+
string :sales_tax_basis
|
57
|
+
string :sales_tax_period
|
32
58
|
|
33
59
|
has_many :addresses
|
34
60
|
has_many :phones
|
35
61
|
|
62
|
+
validates :sales_tax_basis, :message => "is not a valid option" do
|
63
|
+
valid = true
|
64
|
+
if sales_tax_basis
|
65
|
+
|
66
|
+
valid_bases = (SALES_TAX_BASIS[country_code] || SALES_TAX_BASIS['GLOBAL']).keys
|
67
|
+
|
68
|
+
unless valid_bases.include?(sales_tax_basis)
|
69
|
+
valid = false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
valid
|
74
|
+
end
|
75
|
+
|
36
76
|
end
|
37
77
|
|
38
78
|
end
|
@@ -18,7 +18,8 @@ module Xeroizer
|
|
18
18
|
string :phone_number, :internal_name => :number
|
19
19
|
string :phone_area_code, :internal_name => :area_code
|
20
20
|
string :phone_country_code, :internal_name => :country_code
|
21
|
-
|
21
|
+
|
22
|
+
validates_length_of :phone_number, :max => 50
|
22
23
|
end
|
23
24
|
|
24
25
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Xeroizer
|
2
|
+
module Record
|
3
|
+
|
4
|
+
class PrepaymentModel < BaseModel
|
5
|
+
|
6
|
+
set_xml_root_name 'Prepayments'
|
7
|
+
set_permissions :read
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
class Prepayment < Base
|
12
|
+
set_primary_key :prepayment_id
|
13
|
+
|
14
|
+
guid :prepayment_id
|
15
|
+
date :date
|
16
|
+
string :status
|
17
|
+
string :line_amount_types
|
18
|
+
decimal :sub_total
|
19
|
+
decimal :total_tax
|
20
|
+
decimal :total
|
21
|
+
datetime_utc :updated_date_utc, :api_name => 'UpdatedDateUTC'
|
22
|
+
string :currency_code
|
23
|
+
datetime_utc :fully_paid_on_date
|
24
|
+
string :type
|
25
|
+
string :reference
|
26
|
+
decimal :currency_rate
|
27
|
+
decimal :remaining_credit
|
28
|
+
boolean :has_attachments
|
29
|
+
|
30
|
+
belongs_to :contact
|
31
|
+
has_many :line_items
|
32
|
+
|
33
|
+
def contact_id
|
34
|
+
contact.id if contact
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|