diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..09f9819
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+/lib/ @ignitionapp/back-end
+/spec/ @ignitionapp/back-end
\ No newline at end of file
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..3324aa8
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,7 @@
+**Intent (What)**
+
+**Motivation (Why)**
+
+**Implementation (How)**
+
+**Consequence**
diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml
new file mode 100644
index 0000000..074b4c4
--- /dev/null
+++ b/.github/workflows/ruby.yml
@@ -0,0 +1,25 @@
+name: Ruby
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Ruby 3.1
+ uses: actions/setup-ruby@v1
+ with:
+ ruby-version: 3.1.x
+ - name: Build and test with Rake
+ run: |
+ gem install bundler
+ bundle install --jobs 4 --retry 3
+ bundle exec rubocop
+ bundle exec rake
diff --git a/.rubocop.yml b/.rubocop.yml
index 4414801..771dd4e 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -3,7 +3,7 @@ require:
- rubocop-rspec
AllCops:
- TargetRubyVersion: 2.6
+ TargetRubyVersion: 3.1
Gemspec/OrderedDependencies:
Enabled: false
@@ -47,6 +47,9 @@ Layout/HeredocIndentation:
Layout/LeadingCommentSpace:
Enabled: true
+Layout/LineLength:
+ Enabled: false
+
Layout/MultilineArrayBraceLayout:
Enabled: false
@@ -111,9 +114,6 @@ Metrics/PerceivedComplexity:
Enabled: true
Max: 10
-Metrics/LineLength:
- Enabled: false
-
Metrics/MethodLength:
Enabled: true
Max: 50
@@ -159,18 +159,6 @@ Naming/MethodParameterName:
Naming/VariableNumber:
Enabled: false
-Performance/Count:
- Enabled: false
-
-Performance/Casecmp:
- Enabled: false
-
-Performance/TimesMap:
- Enabled: false
-
-Performance/RegexpMatch:
- Enabled: false
-
RSpec/AnyInstance:
Enabled: false
@@ -354,6 +342,7 @@ Style/GuardClause:
Style/HashSyntax:
Enabled: true
EnforcedStyle: ruby19_no_mixed_keys
+ EnforcedShorthandSyntax: never
Style/IfUnlessModifier:
Enabled: false
@@ -385,9 +374,6 @@ Style/MethodCallWithArgsParentheses:
- to
- not_to
-Style/MethodMissingSuper:
- Enabled: false
-
Style/MissingRespondToMissing:
Enabled: false
@@ -464,3 +450,6 @@ Style/SymbolProc:
Style/ZeroLengthPredicate:
Enabled: false
+
+Style/MutableConstant:
+ Enabled: false
diff --git a/.travis.yml b/.travis.yml
index e91174f..3e78ba7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,5 +2,5 @@
language: ruby
cache: bundler
rvm:
- - 2.6.5
+ - 3.1.3
before_install: gem install bundler -v 2.1.4
diff --git a/Gemfile.lock b/Gemfile.lock
index a610b53..9717cbb 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,57 +1,129 @@
PATH
remote: .
specs:
- xpm_ruby (0.1.0)
+ xpm_ruby (0.4.0)
+ activesupport
+ builder
+ dry-types
faraday
+ faraday-encoding
+ ox (~> 2.13)
GEM
remote: https://rubygems.org/
specs:
- ast (2.4.0)
- diff-lcs (1.3)
- faraday (1.0.1)
- multipart-post (>= 1.2, < 3)
- jaro_winkler (1.5.4)
- multipart-post (2.1.1)
- parallel (1.19.1)
- parser (2.7.0.5)
- ast (~> 2.4.0)
- rainbow (3.0.0)
- rake (13.0.1)
- rspec (3.9.0)
- rspec-core (~> 3.9.0)
- rspec-expectations (~> 3.9.0)
- rspec-mocks (~> 3.9.0)
- rspec-core (3.9.1)
- rspec-support (~> 3.9.1)
- rspec-expectations (3.9.1)
+ activesupport (7.1.1)
+ base64
+ bigdecimal
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ connection_pool (>= 2.2.5)
+ drb
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ mutex_m
+ tzinfo (~> 2.0)
+ ast (2.4.2)
+ base64 (0.1.1)
+ bigdecimal (3.1.4)
+ builder (3.2.4)
+ byebug (11.1.3)
+ coderay (1.1.3)
+ concurrent-ruby (1.2.2)
+ connection_pool (2.4.1)
+ diff-lcs (1.5.0)
+ drb (2.1.1)
+ ruby2_keywords
+ dry-core (1.0.1)
+ concurrent-ruby (~> 1.0)
+ zeitwerk (~> 2.6)
+ dry-inflector (1.0.0)
+ dry-logic (1.5.0)
+ concurrent-ruby (~> 1.0)
+ dry-core (~> 1.0, < 2)
+ zeitwerk (~> 2.6)
+ dry-types (1.7.1)
+ concurrent-ruby (~> 1.0)
+ dry-core (~> 1.0)
+ dry-inflector (~> 1.0)
+ dry-logic (~> 1.4)
+ zeitwerk (~> 2.6)
+ faraday (2.7.11)
+ base64
+ faraday-net_http (>= 2.0, < 3.1)
+ ruby2_keywords (>= 0.0.4)
+ faraday-encoding (0.0.5)
+ faraday
+ faraday-net_http (3.0.2)
+ i18n (1.14.1)
+ concurrent-ruby (~> 1.0)
+ json (2.6.3)
+ method_source (1.0.0)
+ minitest (5.20.0)
+ mutex_m (0.1.2)
+ ox (2.14.17)
+ parallel (1.22.1)
+ parser (3.2.0.0)
+ ast (~> 2.4.1)
+ pry (0.14.2)
+ coderay (~> 1.1)
+ method_source (~> 1.0)
+ pry-byebug (3.10.1)
+ byebug (~> 11.0)
+ pry (>= 0.13, < 0.15)
+ rainbow (3.1.1)
+ rake (13.0.6)
+ regexp_parser (2.6.2)
+ rexml (3.2.5)
+ rspec (3.12.0)
+ rspec-core (~> 3.12.0)
+ rspec-expectations (~> 3.12.0)
+ rspec-mocks (~> 3.12.0)
+ rspec-core (3.12.0)
+ rspec-support (~> 3.12.0)
+ rspec-expectations (3.12.2)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.9.0)
- rspec-mocks (3.9.1)
+ rspec-support (~> 3.12.0)
+ rspec-mocks (3.12.3)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.9.0)
- rspec-support (3.9.2)
- rubocop (0.77.0)
- jaro_winkler (~> 1.5.1)
+ rspec-support (~> 3.12.0)
+ rspec-support (3.12.0)
+ rubocop (1.43.0)
+ json (~> 2.3)
parallel (~> 1.10)
- parser (>= 2.6)
+ parser (>= 3.2.0.0)
rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 1.8, < 3.0)
+ rexml (>= 3.2.5, < 4.0)
+ rubocop-ast (>= 1.24.1, < 2.0)
ruby-progressbar (~> 1.7)
- unicode-display_width (>= 1.4.0, < 1.7)
- rubocop-rspec (1.38.1)
- rubocop (>= 0.68.1)
- ruby-progressbar (1.10.1)
- unicode-display_width (1.6.1)
+ unicode-display_width (>= 2.4.0, < 3.0)
+ rubocop-ast (1.24.1)
+ parser (>= 3.1.1.0)
+ rubocop-capybara (2.17.0)
+ rubocop (~> 1.41)
+ rubocop-rspec (2.18.1)
+ rubocop (~> 1.33)
+ rubocop-capybara (~> 2.17)
+ ruby-progressbar (1.11.0)
+ ruby2_keywords (0.0.5)
+ tzinfo (2.0.6)
+ concurrent-ruby (~> 1.0)
+ unicode-display_width (2.4.2)
+ vcr (6.1.0)
+ zeitwerk (2.6.12)
PLATFORMS
ruby
DEPENDENCIES
- bundler (~> 2.0)
- rake (>= 12.3.3)
- rspec (~> 3.0)
- rubocop (= 0.77.0)
+ bundler
+ byebug (~> 11)
+ pry-byebug (~> 3)
+ rake
+ rspec
+ rubocop
rubocop-rspec
+ vcr
xpm_ruby!
BUNDLED WITH
diff --git a/README.md b/README.md
index d1f489a..2756183 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,67 @@
# XpmRuby
-Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/xpm_ruby`. To experiment with that code, run `bin/console` for an interactive prompt.
+This gem is used to access Xero's XPM api.
-TODO: Delete this and the text above, and describe your gem
+You will need to install and manage the access_tokens with Oauth 2.0 in your own app.
## Installation
Add this line to your application's Gemfile:
```ruby
-gem 'xpm_ruby'
+gem "xpm_ruby", git: "https://github.com/ignitionapp/xpm_ruby"
```
And then execute:
$ bundle install
-Or install it yourself as:
+## Usage
- $ gem install xpm_ruby
+Most of the API calls will require at least the two main following arguments
-## Usage
+1. `access_token` - the oauth2 access token (Oauth2 is not included here)
+1. `xero_tenant_id` - You get this by calling the xero api connection. See https://github.com/ignitionapp/xpm_ruby_demo/blob/master/subdomains/xpm_integration/access_token.rb for more details.
+
+Handling the refresh token and logging into Xero should all take place in the main app. The sample app is available at https://github.com/ignitionapp/xpm_ruby_demo
+
+Most of the time, you will be passing in a hash representation of the object you are working with (with one or two exceptions where it might be an ID or raw XML).
+
+The gem will convert the hash into the XML needed by the XPM api. The data that is returned will automatically be converted from XML to a Ruby Hash or Array.
+
+For example, a call to `XPMRuby::Staff.list(access_token: access_token, xero_tenant_id: xero_tenant_id)` will return an array of hashes representing the staff list.
+
+```ruby
+[
+ { "ID" => "859230", "Name" => "Dev Testing", "Email" => "dev@practiceignition.com", "Phone" => nil, "Mobile" => nil, "Address" => nil, "PayrollCode" => nil },
+ ...
+]
+```
-TODO: Write usage instructions here
+As much as possible, we have tried to keep to the same names as documented here: https://developer.xero.com/documentation/practice-manager/overview-practice-manager-api however we have not as yet added the full API (only the endpoints we are currently using in ignitionapp).
## Development
-After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
+TODO set up this gem to release automatically when merged into master...
+
+Note: This gem is not released yet and is currently for internal use.
+
+Please refer to it via github for now
+e.g.
+`gem "xpm_ruby", git: "https://github.com/ignitionapp/xpm_ruby"`
+
+## Testing
+Rspec is used for testing
+
+`bundle exec rspec`
+
+In addition, rubocop is installed to check formatting and code quality
-To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
+`bundle exec rubocop`
## Contributing
-Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/xpm_ruby.
+Bug reports and pull requests are welcome on GitHub at https://github.com/ignitionapp/xpm_ruby.
## License
diff --git a/lib/xpm_ruby.rb b/lib/xpm_ruby.rb
index 4808228..d18e371 100644
--- a/lib/xpm_ruby.rb
+++ b/lib/xpm_ruby.rb
@@ -1,8 +1,57 @@
-require "xpm_ruby/version"
-
-require "xpm_ruby/connection"
-
module XpmRuby
class Error < StandardError; end
- # Your code goes here...
+
+ class ApiError < Error; end
+
+ class UnknownError < Error; end
+
+ class Unauthorized < Error; end
+
+ class AccessTokenExpired < Unauthorized; end
+
+ class Forbidden < Error; end
+
+ class NotAvailable < Error; end
+
+ class ConnectionFailed < Error; end
+
+ class ConnectionTimeout < Error; end
+
+ class InternalServerError < Error; end
+
+ class RateLimitExceeded < Error
+ attr_reader :details
+
+ def initialize(message, details:)
+ @details = details
+ super(message)
+ end
+ end
end
+
+require "active_support"
+require "active_support/core_ext"
+require "builder"
+
+require "xpm_ruby/category"
+require "xpm_ruby/client"
+require "xpm_ruby/contact"
+require "xpm_ruby/connection"
+require "xpm_ruby/job"
+
+require "xpm_ruby/schema/client/add"
+require "xpm_ruby/schema/client/update"
+require "xpm_ruby/schema/contact/add"
+require "xpm_ruby/schema/contact/update"
+require "xpm_ruby/schema/job/add"
+require "xpm_ruby/schema/job/applytemplate"
+require "xpm_ruby/schema/job/delete"
+require "xpm_ruby/schema/job/state"
+require "xpm_ruby/schema/job/update"
+require "xpm_ruby/schema/staff/add"
+require "xpm_ruby/schema/staff/delete"
+require "xpm_ruby/schema/staff/update"
+
+require "xpm_ruby/staff"
+require "xpm_ruby/template"
+require "xpm_ruby/version"
diff --git a/lib/xpm_ruby/category.rb b/lib/xpm_ruby/category.rb
new file mode 100644
index 0000000..35e78bb
--- /dev/null
+++ b/lib/xpm_ruby/category.rb
@@ -0,0 +1,15 @@
+require "ox"
+
+module XpmRuby
+ module Category
+ extend self
+
+ def list(access_token:, xero_tenant_id:)
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .get(endpoint: "category.api/list")
+
+ Array.wrap(response.dig("Categories", "Category"))
+ end
+ end
+end
diff --git a/lib/xpm_ruby/client.rb b/lib/xpm_ruby/client.rb
new file mode 100644
index 0000000..3ee048e
--- /dev/null
+++ b/lib/xpm_ruby/client.rb
@@ -0,0 +1,57 @@
+module XpmRuby
+ module Client
+ extend self
+
+ def add(access_token:, xero_tenant_id:, client:)
+ validated_client = Schema::Client::Add[client]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .post(endpoint: "client.api/add", data: validated_client.to_xml(root: "Client"))
+
+ response["Client"]
+ end
+
+ def update(access_token:, xero_tenant_id:, client:)
+ validated_client = Schema::Client::Update[client]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .put(endpoint: "client.api/update", data: validated_client.to_xml(root: "Client"))
+
+ response["Client"]
+ end
+
+ def get(access_token:, xero_tenant_id:, client_id:)
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .get(endpoint: "client.api/get/#{client_id}")
+
+ response["Client"]
+ end
+
+ def list(access_token:, xero_tenant_id:, detailed: true, modified_since: nil, url: nil)
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id, url: url)
+ .get(
+ endpoint: "client.api/list",
+ params: {
+ "detailed" => detailed,
+ "modifiedsince" => modified_since }.compact)
+
+ Array.wrap(response.dig("Clients", "Client"))
+ end
+
+ def search(access_token:, xero_tenant_id:, detailed: true, query: nil)
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .get(
+ endpoint: "client.api/search",
+ params: {
+ "detailed" => detailed,
+ "query" => query }.compact)
+
+ Array.wrap(response.dig("Clients", "Client"))
+ end
+ end
+end
diff --git a/lib/xpm_ruby/connection.rb b/lib/xpm_ruby/connection.rb
index 9176617..e9a8c0c 100644
--- a/lib/xpm_ruby/connection.rb
+++ b/lib/xpm_ruby/connection.rb
@@ -1,29 +1,113 @@
require "faraday"
+require "faraday/encoding"
require "base64"
module XpmRuby
class Connection
- attr_accessor :api_url, :account_key, :api_key, :basic_auth
+ attr_accessor :xero_tenant_id, :authorization, :url
- def initialize(account_key:, api_key:, api_url:)
- @api_url = api_url
- @account_key = account_key
- @api_key = api_key
- @basic_auth = "Basic " + Base64.strict_encode64("#{api_key}:#{account_key}")
+ def initialize(access_token:, xero_tenant_id:, url: nil)
+ @xero_tenant_id = xero_tenant_id
+ @authorization = "Bearer #{access_token}"
+ @url = url || xpm_url
end
- def get(endpoint:)
- Faraday.new(url(endpoint: endpoint), headers: headers).get
+ def get(endpoint:, params: nil)
+ response = build_connection(url: url).get(endpoint, params, headers)
+ handle_response(response)
+ rescue Faraday::ConnectionFailed => error
+ raise ConnectionFailed.new(error.message)
+ rescue Faraday::TimeoutError => error
+ raise ConnectionTimeout.new(error.message)
+ end
+
+ def post(endpoint:, data:)
+ response = build_connection(url: url).post(endpoint, data, headers)
+ handle_response(response)
+ rescue Faraday::ConnectionFailed => error
+ raise ConnectionFailed.new(error.message)
+ rescue Faraday::TimeoutError => error
+ raise ConnectionTimeout.new(error.message)
+ end
+
+ def put(endpoint:, data:)
+ response = build_connection(url: url).put(endpoint, data, headers)
+ handle_response(response)
+ rescue Faraday::ConnectionFailed => error
+ raise ConnectionFailed.new(error.message)
+ rescue Faraday::TimeoutError => error
+ raise ConnectionTimeout.new(error.message)
+ end
+
+ def delete(endpoint:, id:, params: {})
+ query_string = CGI.unescape(params.to_query)
+ response = build_connection(url: url).delete("#{endpoint}/#{id}?#{query_string}", nil, headers)
+ handle_response(response)
+ rescue Faraday::ConnectionFailed => error
+ raise ConnectionFailed.new(error.message)
+ rescue Faraday::TimeoutError => error
+ raise ConnectionTimeout.new(error.message)
end
private
+ def build_connection(url:, adapter: Faraday.default_adapter)
+ Faraday.new(url) do |connection|
+ # use Faraday::Encoding middleware to correct the response encoding.
+ connection.response(:encoding)
+
+ connection.adapter(adapter)
+ end
+ end
+
def headers
- { "Authorization" => @basic_auth }
+ { "Authorization" => @authorization, "xero-tenant-id" => @xero_tenant_id, "content_type" => "application/xml" }
+ end
+
+ def xpm_url
+ "https://api.xero.com/practicemanager/3.0/"
end
- def url(endpoint:)
- "https://#{@api_url}/v3/#{endpoint}"
+ def handle_response(response)
+ case response.status
+ when 401
+ detail = JSON.parse(response.body)["Detail"]
+
+ case detail
+ when /TokenExpired: token expired/
+ raise AccessTokenExpired.new(detail)
+ else
+ raise Unauthorized.new(detail)
+ end
+ when 403 # this can happen with a bad xero_tenant_id
+ detail = JSON.parse(response.body)["Detail"]
+ raise Forbidden.new(detail)
+ when 500
+ raise InternalServerError.new(response.reason_phrase)
+ when 503
+ detail = JSON.parse(response.body)["Detail"]
+ raise NotAvailable.new(detail)
+ when 429 # rate limit exceeded
+ details = response.headers.slice(
+ "retry-after",
+ "x-rate-limit-problem",
+ "x-minlimit-remaining",
+ "x-daylimit-remaining",
+ "x-appminlimit-remaining"
+ )
+ raise RateLimitExceeded.new(response.reason_phrase, details: details)
+ when 200
+ xml = Ox.load(response.body, mode: :hash_no_attrs, symbolize_keys: false)
+
+ case xml["Response"]["Status"]
+ when "OK"
+ xml["Response"]
+ when "ERROR"
+ raise ApiError.new(xml["Response"]["ErrorDescription"])
+ end
+ else
+ raise UnknownError.new(response.status)
+ end
end
end
end
diff --git a/lib/xpm_ruby/contact.rb b/lib/xpm_ruby/contact.rb
new file mode 100644
index 0000000..feff20a
--- /dev/null
+++ b/lib/xpm_ruby/contact.rb
@@ -0,0 +1,37 @@
+module XpmRuby
+ module Contact
+ extend self
+
+ def add(access_token:, xero_tenant_id:, contact:)
+ validated_contact = Schema::Contact::Add[contact]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .post(endpoint: "client.api/contact", data: validated_contact.to_xml(root: "Contact"))
+
+ response["Contact"]
+ end
+
+ def update(access_token:, xero_tenant_id:, id:, contact:)
+ validated_contact = Schema::Contact::Update[contact]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .put(
+ endpoint: "client.api/contact/#{id}",
+ data: validated_contact.to_xml(root: "Contact"))
+
+ response["Contact"]
+ end
+
+ def delete(access_token:, xero_tenant_id:, contact_id:, client_id: nil)
+ request_params = { client_id: client_id }.compact
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .delete(endpoint: "client.api/contact", id: contact_id, params: request_params)
+
+ response["Contact"]
+ end
+ end
+end
diff --git a/lib/xpm_ruby/job.rb b/lib/xpm_ruby/job.rb
new file mode 100644
index 0000000..0406274
--- /dev/null
+++ b/lib/xpm_ruby/job.rb
@@ -0,0 +1,85 @@
+require "ox"
+
+module XpmRuby
+ module Job
+ extend self
+
+ class Error < Error; end
+
+ def current(access_token:, xero_tenant_id:)
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .get(endpoint: "job.api/current")
+
+ response["Jobs"]["Job"]
+ end
+
+ def add(access_token:, xero_tenant_id:, job:)
+ validated_job = Schema::Job::Add[job]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .post(endpoint: "job.api/add", data: validated_job.to_xml(root: "Job"))
+
+ response["Job"]
+ end
+
+ def update(access_token:, xero_tenant_id:, job:)
+ validated_job = Schema::Job::Update[job]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .put(endpoint: "job.api/update", data: validated_job.to_xml(root: "Job"))
+
+ response["Job"]
+ end
+
+ def get(access_token:, xero_tenant_id:, job_id:)
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .get(endpoint: "job.api/get/#{job_id}")
+
+ response["Job"]
+ end
+
+ def state(access_token:, xero_tenant_id:, job:)
+ validated_job = Schema::Job::State[job]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .put(endpoint: "job.api/state", data: validated_job.to_xml(root: "Job"))
+
+ response["Status"]
+ end
+
+ def delete(access_token:, xero_tenant_id:, job:)
+ validated_job = Schema::Job::Delete[job]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .post(endpoint: "job.api/delete", data: validated_job.to_xml(root: "Job"))
+
+ response["Status"]
+ end
+
+ # The XML structure for job.assign does not fit in a Hash
+ # so we need to pass in the XML directly
+ def assign(access_token:, xero_tenant_id:, job_xml:)
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .put(endpoint: "job.api/assign", data: job_xml)
+
+ response["Status"]
+ end
+
+ def applytemplate(access_token:, xero_tenant_id:, job:)
+ validated_job = Schema::Job::Applytemplate[job]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .post(endpoint: "job.api/applytemplate", data: validated_job.to_xml(root: "Job"))
+
+ response["Job"]
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/client/add.rb b/lib/xpm_ruby/schema/client/add.rb
new file mode 100644
index 0000000..6acd133
--- /dev/null
+++ b/lib/xpm_ruby/schema/client/add.rb
@@ -0,0 +1,63 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Client
+ Add = Types::Hash.schema(
+ Name: Types::String,
+ Email?: Types::String,
+ Address?: Types::String,
+ City?: Types::String,
+ Region?: Types::String,
+ PostCode?: Types::String,
+ Country?: Types::String,
+ PostalAddress?: Types::String,
+ PostalCity?: Types::String,
+ PostalRegion?: Types::String,
+ PostalPostCode?: Types::String,
+ PostalCountry?: Types::String,
+ Phone?: Types::Coercible::String,
+ Fax?: Types::Coercible::String,
+ WebSite?: Types::String,
+ ReferralSource?: Types::String,
+ ExportCode?: Types::String,
+ AccountManagerID?: Types::String,
+ Contacts?: Types::Array.of(
+ Types::Hash.schema(
+ Name: Types::String,
+ IsPrimary?: Types::String,
+ Salutation?: Types::String,
+ Addressee?: Types::String,
+ Phone?: Types::Coercible::String,
+ Mobile?: Types::Coercible::String,
+ Email?: Types::String,
+ Position?: Types::String
+ ).with_key_transform(&:to_sym)
+ ),
+ BillingClientID?: Types::Coercible::String,
+ FirstName?: Types::String,
+ LastName?: Types::String,
+ OtherName?: Types::String,
+ DateOfBirth?: Types::Coercible::String,
+ JobManagerID?: Types::Coercible::String,
+ TaxNumber?: Types::Coercible::String,
+ CompanyNumber?: Types::Coercible::String,
+ BusinessNumber?: Types::Coercible::String,
+ BusinessStructure?: Types::String,
+ BalanceMonth?: Types::Coercible::String,
+ PrepareGST?: Types::String,
+ GSTRegistered?: Types::String,
+ GSTPeriod?: Types::Coercible::String,
+ GSTBasis?: Types::String,
+ ProvisionalTaxBasis?: Types::String,
+ ProvisionalTaxRatio?: Types::String,
+ SignedTaxAuthority?: Types::String,
+ TaxAgent?: Types::String,
+ AgencyStatus?: Types::String,
+ ReturnType?: Types::String,
+ PrepareActivityStatement?: Types::String,
+ PrepareTaxReturn?: Types::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/client/update.rb b/lib/xpm_ruby/schema/client/update.rb
new file mode 100644
index 0000000..df54f43
--- /dev/null
+++ b/lib/xpm_ruby/schema/client/update.rb
@@ -0,0 +1,64 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Client
+ Update = Types::Hash.schema(
+ ID: Types::Coercible::String,
+ Name?: Types::String,
+ Email?: Types::String,
+ Address?: Types::String,
+ City?: Types::String,
+ Region?: Types::String,
+ PostCode?: Types::String,
+ Country?: Types::String,
+ PostalAddress?: Types::String,
+ PostalCity?: Types::String,
+ PostalRegion?: Types::String,
+ PostalPostCode?: Types::String,
+ PostalCountry?: Types::String,
+ Phone?: Types::Coercible::String,
+ Fax?: Types::Coercible::String,
+ WebSite?: Types::String,
+ ReferralSource?: Types::String,
+ ExportCode?: Types::String,
+ AccountManagerID?: Types::String,
+ Contacts?: Types::Array.of(
+ Types::Hash.schema(
+ Name: Types::String,
+ IsPrimary?: Types::String,
+ Salutation?: Types::String,
+ Addressee?: Types::String,
+ Phone?: Types::Coercible::String,
+ Mobile?: Types::Coercible::String,
+ Email?: Types::String,
+ Position?: Types::String
+ ).with_key_transform(&:to_sym)
+ ),
+ BillingClientID?: Types::Coercible::String,
+ FirstName?: Types::String,
+ LastName?: Types::String,
+ OtherName?: Types::String,
+ DateOfBirth?: Types::Coercible::String,
+ JobManagerID?: Types::Coercible::String,
+ TaxNumber?: Types::Coercible::String,
+ CompanyNumber?: Types::Coercible::String,
+ BusinessNumber?: Types::Coercible::String,
+ BusinessStructure?: Types::String,
+ BalanceMonth?: Types::Coercible::String,
+ PrepareGST?: Types::String,
+ GSTRegistered?: Types::String,
+ GSTPeriod?: Types::Coercible::String,
+ GSTBasis?: Types::String,
+ ProvisionalTaxBasis?: Types::String,
+ ProvisionalTaxRatio?: Types::String,
+ SignedTaxAuthority?: Types::String,
+ TaxAgent?: Types::String,
+ AgencyStatus?: Types::String,
+ ReturnType?: Types::String,
+ PrepareActivityStatement?: Types::String,
+ PrepareTaxReturn?: Types::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/contact/add.rb b/lib/xpm_ruby/schema/contact/add.rb
new file mode 100644
index 0000000..eb731da
--- /dev/null
+++ b/lib/xpm_ruby/schema/contact/add.rb
@@ -0,0 +1,21 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Contact
+ Add = Types::Hash.schema(
+ Client: Types::Hash.schema(
+ ID: Types::Coercible::String
+ ).with_key_transform(&:to_sym),
+ Name?: Types::String,
+ IsPrimary?: Types::String,
+ Salutation?: Types::String,
+ Addressee?: Types::String,
+ Mobile?: Types::String,
+ Email?: Types::String,
+ Phone?: Types::String,
+ Position?: Types::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/contact/update.rb b/lib/xpm_ruby/schema/contact/update.rb
new file mode 100644
index 0000000..9fcc155
--- /dev/null
+++ b/lib/xpm_ruby/schema/contact/update.rb
@@ -0,0 +1,21 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Contact
+ Update = Types::Hash.schema(
+ Client?: Types::Hash.schema(
+ ID: Types::Coercible::String
+ ).with_key_transform(&:to_sym),
+ Name?: Types::String,
+ IsPrimary?: Types::String,
+ Salutation?: Types::String,
+ Addressee?: Types::String,
+ Mobile?: Types::String,
+ Email?: Types::String,
+ Phone?: Types::String,
+ Position?: Types::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/job/add.rb b/lib/xpm_ruby/schema/job/add.rb
new file mode 100644
index 0000000..7b6ae59
--- /dev/null
+++ b/lib/xpm_ruby/schema/job/add.rb
@@ -0,0 +1,21 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Job
+ Add = Types::Hash.schema(
+ Name: Types::String,
+ Description?: Types::String,
+ ClientID: Types::Coercible::String,
+ ContactID?: Types::Coercible::String,
+ StartDate: Types::Coercible::String,
+ DueDate: Types::Coercible::String,
+ ClientNumber?: Types::Coercible::String,
+ ID?: Types::Coercible::String,
+ TemplateID?: Types::Coercible::String,
+ CategoryID?: Types::Coercible::String,
+ Budget?: Types::Coercible::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/job/applytemplate.rb b/lib/xpm_ruby/schema/job/applytemplate.rb
new file mode 100644
index 0000000..6da8a91
--- /dev/null
+++ b/lib/xpm_ruby/schema/job/applytemplate.rb
@@ -0,0 +1,13 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Job
+ Applytemplate = Types::Hash.schema(
+ ID: Types::Coercible::String,
+ TemplateID: Types::Coercible::String,
+ TaskMode?: Types::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/job/delete.rb b/lib/xpm_ruby/schema/job/delete.rb
new file mode 100644
index 0000000..360d696
--- /dev/null
+++ b/lib/xpm_ruby/schema/job/delete.rb
@@ -0,0 +1,11 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Job
+ Delete = Types::Hash.schema(
+ ID: Types::Coercible::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/job/state.rb b/lib/xpm_ruby/schema/job/state.rb
new file mode 100644
index 0000000..e2797a5
--- /dev/null
+++ b/lib/xpm_ruby/schema/job/state.rb
@@ -0,0 +1,12 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Job
+ State = Types::Hash.schema(
+ ID: Types::Coercible::String,
+ State: Types::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/job/update.rb b/lib/xpm_ruby/schema/job/update.rb
new file mode 100644
index 0000000..6def5cd
--- /dev/null
+++ b/lib/xpm_ruby/schema/job/update.rb
@@ -0,0 +1,21 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Job
+ Update = Types::Hash.schema(
+ ID: Types::Coercible::String,
+ Name: Types::String,
+ Description?: Types::String,
+ ContactID?: Types::Coercible::String,
+ StartDate: Types::Coercible::String,
+ DueDate: Types::Coercible::String,
+ ClientNumber?: Types::Coercible::String,
+ ID?: Types::Coercible::String,
+ TemplateID?: Types::Coercible::String,
+ CategoryID?: Types::Coercible::String,
+ Budget?: Types::Coercible::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/staff/add.rb b/lib/xpm_ruby/schema/staff/add.rb
new file mode 100644
index 0000000..1098b5b
--- /dev/null
+++ b/lib/xpm_ruby/schema/staff/add.rb
@@ -0,0 +1,16 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Staff
+ Add = Types::Hash.schema(
+ Name: Types::String,
+ Address?: Types::String,
+ Phone?: Types::String,
+ Mobile?: Types::String,
+ Email?: Types::String,
+ PayrollCode?: Types::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/staff/delete.rb b/lib/xpm_ruby/schema/staff/delete.rb
new file mode 100644
index 0000000..120e9b1
--- /dev/null
+++ b/lib/xpm_ruby/schema/staff/delete.rb
@@ -0,0 +1,11 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Staff
+ Delete = Types::Hash.schema(
+ ID: Types::Coercible::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/schema/staff/update.rb b/lib/xpm_ruby/schema/staff/update.rb
new file mode 100644
index 0000000..18c8939
--- /dev/null
+++ b/lib/xpm_ruby/schema/staff/update.rb
@@ -0,0 +1,17 @@
+require_relative "../../types"
+
+module XpmRuby
+ module Schema
+ module Staff
+ Update = Types::Hash.schema(
+ ID: Types::Coercible::String,
+ Name: Types::String,
+ Address?: Types::String,
+ Phone?: Types::String,
+ Mobile?: Types::String,
+ Email?: Types::String,
+ PayrollCode?: Types::String
+ ).with_key_transform(&:to_sym)
+ end
+ end
+end
diff --git a/lib/xpm_ruby/staff.rb b/lib/xpm_ruby/staff.rb
new file mode 100644
index 0000000..3fbff73
--- /dev/null
+++ b/lib/xpm_ruby/staff.rb
@@ -0,0 +1,51 @@
+require "ox"
+
+module XpmRuby
+ module Staff
+ extend self
+
+ class Error < Error; end
+
+ def list(access_token:, xero_tenant_id:, url: nil)
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id, url: url)
+ .get(endpoint: "staff.api/list")
+
+ Array.wrap(response.dig("StaffList", "Staff"))
+ end
+
+ def add(access_token:, xero_tenant_id:, staff:)
+ validated_contact = Schema::Staff::Add[staff]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .post(endpoint: "staff.api/add", data: validated_contact.to_xml(root: "Staff"))
+
+ response["Staff"]
+ end
+
+ def update(access_token:, xero_tenant_id:, staff:)
+ validated_contact = Schema::Staff::Update[staff]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .put(
+ endpoint: "staff.api/update",
+ data: validated_contact.to_xml(root: "Staff"))
+
+ response["Staff"]
+ end
+
+ def delete(access_token:, xero_tenant_id:, id:)
+ validated_contact = Schema::Staff::Delete[{ "ID" => id }]
+
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .post(
+ endpoint: "staff.api/delete",
+ data: validated_contact.to_xml(root: "Staff"))
+
+ response["Status"] == "OK"
+ end
+ end
+end
diff --git a/lib/xpm_ruby/template.rb b/lib/xpm_ruby/template.rb
new file mode 100644
index 0000000..e676212
--- /dev/null
+++ b/lib/xpm_ruby/template.rb
@@ -0,0 +1,17 @@
+require "ox"
+
+module XpmRuby
+ module Template
+ extend self
+
+ class Error < Error; end
+
+ def list(access_token:, xero_tenant_id:)
+ response = Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .get(endpoint: "template.api/list")
+
+ Array.wrap(response.dig("Templates", "Template"))
+ end
+ end
+end
diff --git a/lib/xpm_ruby/types.rb b/lib/xpm_ruby/types.rb
new file mode 100644
index 0000000..8c95b30
--- /dev/null
+++ b/lib/xpm_ruby/types.rb
@@ -0,0 +1,7 @@
+require "dry-types"
+
+module XpmRuby
+ module Types
+ include Dry.Types()
+ end
+end
diff --git a/lib/xpm_ruby/version.rb b/lib/xpm_ruby/version.rb
index 782b385..5a16376 100644
--- a/lib/xpm_ruby/version.rb
+++ b/lib/xpm_ruby/version.rb
@@ -1,3 +1,3 @@
module XpmRuby
- VERSION = "0.1.0".freeze
+ VERSION = "0.4.0".freeze
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 008a1cf..a9d2e98 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,5 +1,6 @@
require "bundler/setup"
require "xpm_ruby"
+require "vcr"
RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
@@ -12,3 +13,10 @@
c.syntax = :expect
end
end
+
+VCR.configure do |config|
+ config.default_cassette_options = { record: :new_episodes }
+
+ config.cassette_library_dir = "spec/vcr_cassettes"
+ config.hook_into(:faraday)
+end
diff --git a/spec/vcr_cassettes/xpm_ruby/category/list.yml b/spec/vcr_cassettes/xpm_ruby/category/list.yml
new file mode 100644
index 0000000..128fe9b
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/category/list.yml
@@ -0,0 +1,54 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/category.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer access_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ content-length:
+ - '258'
+ server:
+ - nginx
+ xero-correlation-id:
+ - c736aae5-0038-4fec-a83d-915bbb5645d9
+ x-appminlimit-remaining:
+ - '9999'
+ x-minlimit-remaining:
+ - '59'
+ x-daylimit-remaining:
+ - '4992'
+ expires:
+ - Sun, 07 Mar 2021 22:41:49 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Sun, 07 Mar 2021 22:41:49 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK304252Compliance304253Consulting304254Internal
+ http_version: null
+ recorded_at: Sun, 07 Mar 2021 22:41:49 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/category/list_empty_array.yml b/spec/vcr_cassettes/xpm_ruby/category/list_empty_array.yml
new file mode 100644
index 0000000..5f635ce
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/category/list_empty_array.yml
@@ -0,0 +1,54 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/category.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer access_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ content-length:
+ - '258'
+ server:
+ - nginx
+ xero-correlation-id:
+ - c736aae5-0038-4fec-a83d-915bbb5645d9
+ x-appminlimit-remaining:
+ - '9999'
+ x-minlimit-remaining:
+ - '59'
+ x-daylimit-remaining:
+ - '4992'
+ expires:
+ - Sun, 07 Mar 2021 22:41:49 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Sun, 07 Mar 2021 22:41:49 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK
+ http_version: null
+ recorded_at: Sun, 07 Mar 2021 22:41:49 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/add.yml b/spec/vcr_cassettes/xpm_ruby/client/add.yml
new file mode 100644
index 0000000..01b0ed1
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/add.yml
@@ -0,0 +1,60 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/client.api/add
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ Acmer Pty Ltd
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODgxMzA0NzQsImV4cCI6MTU4ODEzMjI3NCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODEzMDQ2NCwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjI5ZTUzOGU0NDBlMTQ3MTZiZjNiMmNkY2QwMWQ5NjFhIiwianRpIjoiOTBmZWVhYzIzNGMwOGVhMzlmYTY1ZGZkZTZhMzI5YmUiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.LVkwLJ1lIjssKoO0tDFZFDV8n0pSEYqYs92E_c4uXwlkJNUZaJJ53PAxlobe9RjpboX1qMnq4ZDrbC6LH2w9ay7PISje-9T_fbGk7YrUKDqVJ_JsfuQruTSfqhrnRw3l_s8uP42HGCV-VoC9rBhiNzxydSvBU0nxAkOSGjuZvSQg75XJhhmTM-uO9bdo4q_V_9tZUgnv7UBVzirrcF6wntYPH2eTSguYON4dxo5FG60BnGa7rKgJjSB9PeJPosoOpHkauLOeWS955tu7ki4_1ANZk0v55MILjyb37vDT4e8fPSbmgr0yHSCXJ56qd0VTkSylFOqEgetLw3QD2WfMGQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-daylimit-remaining:
+ - '4989'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 2fe46aa7-08b1-4084-b7c8-29ef8a69d9a4
+ content-length:
+ - '634'
+ expires:
+ - Wed, 29 Apr 2020 03:22:00 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 29 Apr 2020 03:22:00 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK25698662Acmer
+ Pty LtdNoNoNo39a02ce2-f877-4d40-a5a7-d7355e88025b
+ http_version: null
+ recorded_at: Wed, 29 Apr 2020 03:22:00 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/get.yml b/spec/vcr_cassettes/xpm_ruby/client/get.yml
new file mode 100644
index 0000000..a5dcef6
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/get.yml
@@ -0,0 +1,56 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/client.api/get/32014284
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.6.0
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE2NDI5ODI2OTcsImV4cCI6MTY0Mjk4NDQ5NywiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTY0MjM4NjgwNywieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjY2YmEwYTVlZDFjYjQyNmNhMDNjMzMwMGYwMzgyODFhIiwianRpIjoiOTMzY2VjNGVlY2VkYzBiY2Q3Zjg3YTVmZWYyODA3OTAiLCJhdXRoZW50aWNhdGlvbl9ldmVudF9pZCI6IjRiZDRlMmRhLTA3YWEtNDNlMS1iNWY5LTRmYzc0YWY0MzRlNiIsInNjb3BlIjpbImVtYWlsIiwicHJvZmlsZSIsIm9wZW5pZCIsInByYWN0aWNlbWFuYWdlciIsIm9mZmxpbmVfYWNjZXNzIl19.DaWZy6Iia6p-dhoOYqp3tB9tDaeNIdOWNa-2PJD3uW2Y2-etWIsigjvaKYeC9JJAHN_Mz6m8wWq66igtAJHwHiD2cn1gXs70GakFwkFCr1KaF5Vcak-F6MDgXTP6uCaoOlzHIJGgjHu-KbyOPFie2H-5o7aWpxEGqOyruDxE0jK3h-1TZr7LkvDcGBjk_QRMgFtFNY5N70kpT9NfZejq36Z56h72EntmucdWl_XGNjKklF96LPuhKARywCY13QJGvi-wlGPI_MFvfx4VM1pGkWrr4L_feHj4KlteGlspyb_DbUDPf_4_n9MPKPvyUD50Fiqy0cun62yTpG_bBG0Qiw
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ content-length:
+ - '1281'
+ server:
+ - nginx
+ xero-correlation-id:
+ - e9b9b012-0a30-4141-ae23-a3ec42c0923b
+ x-appminlimit-remaining:
+ - '9999'
+ x-minlimit-remaining:
+ - '59'
+ x-daylimit-remaining:
+ - '4996'
+ expires:
+ - Mon, 24 Jan 2022 00:22:17 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Mon, 24 Jan 2022 00:22:17 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK32014284Get
+ Client TestNEW@EMAIL.COMNoNoNo1NoNoNoUnlinkedNoNoNo18978524contact
+ namecontact@email.com0No0183f65c-08c6-47b7-af05-3da072e901ae
+ recorded_at: Mon, 24 Jan 2022 00:22:17 GMT
+recorded_with: VCR 6.0.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/list.yml b/spec/vcr_cassettes/xpm_ruby/client/list.yml
new file mode 100644
index 0000000..4930dce
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/list.yml
@@ -0,0 +1,100 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/client.api/list?detailed=true&modified_since
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4997'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 4d8227fe-cbdb-441e-b80d-0d95ccfe0931
+ content-length:
+ - '15295'
+ expires:
+ - Mon, 04 May 2020 23:51:23 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Mon, 04 May 2020 23:51:23 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK24097642ABC
+ CoNoNoNoNoNoNoUnlinkedNoNoNo14436062Bobbob@abc.comNoe349fc1b-d92d-4ba2-b9fc-69fdd516e2a225698376Accountants
+ 101NoNoNoNoNoNoUnlinkedNoNoNo15370796Space
+ Rangerisabelle.miller@practiceignition.comNodcc6a649-c7a1-4cde-8e07-a40bde0466ee25698662Acmer
+ Pty LtdNoNoNo39a02ce2-f877-4d40-a5a7-d7355e88025b25697701Acmer
+ Pty LtdNoNoNofca33011-9be0-474c-bd3e-91ca18f74d8123702334Client
+ without contactNoNoNo1NoNoNoUnlinkedNoNoNo14573209Ian
+ testyo@example.comNo14573208Second
+ personme@example.comNo0b63ab7c-23e7-49ed-a9a4-fd053a8cee9723864530Ian
+ Example Client123@123.com123 Main StreetSydneyNew
+ South Wales2041Australia123
+ PostalNoNoNoNoNoNoUnlinkedNoNoNo14346188Ian
+ Contactnewguy@123.comYes14304486Space
+ Ranger123@123.comNo14346189Third
+ Guythree@123.comNo922877Test Group66173c1d-dad7-4b9c-82eb-a3d517bb597523403717Practice
+ Ignition - XPM Product & Development Testing AccountNoNoNoNoNoNoUnlinkedNoNoNo14348419Test
+ Contacttest@123.comNo922877Test Group95554526-e774-4de5-8fd5-0e4b5280c00423702571Space
+ Rangertest@test.com123 Gotham StreetSydneyNew
+ South Wales2041Australia12345678NoNoNo1NoNoNoUnlinkedNoNoNo14494468Batman
+ Personian@example.comNo14213073Contact
+ aianlenehan@gmail.comNo14574280new
+ guyNo14574267Second
+ contactcontact@example.comNo14574372some
+ guyNo14574278Some
+ guyNo14657104Space
+ Rangerluis@practiceignition.comNo04c412be-57d5-41d5-a18d-7077137f91d325116743Space
+ Rangernewuser@test.comNoNoNoNoNoNoUnlinkedNoNoNo15094752Space
+ Rangernewuser@test.comNocc84c96e-853c-4400-96df-ee24912938b325602022Space
+ Rangerpayments@practiceignition.comNoNoNoNoNoNoUnlinkedNoNoNo3571b76d-a568-47b0-a38a-79b26161f37424688375Test
+ Client123 Fake Street123123123123123041234123402
+ 1234 1234NoNoNoNoNoNoUnlinkedNoNoNo14786464Dud
+ Contact04123412340412341234No14786465Mr
+ Test Testermantest@testerman.comasdasdsadNo14922753-95ec-4ad2-99bb-0b58d223074725655881Updated2NoNoNo1NoNoNoUnlinkedNoNoNo9f868ba7-437c-4574-9a17-8c6f4890545b
+ http_version: null
+ recorded_at: Mon, 04 May 2020 23:51:23 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/list/when_detailed_false.yml b/spec/vcr_cassettes/xpm_ruby/client/list/when_detailed_false.yml
new file mode 100644
index 0000000..e8f27ed
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/list/when_detailed_false.yml
@@ -0,0 +1,91 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/client.api/list?detailed=false
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4972'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 07755f0d-dd8e-454c-93e6-916421447d25
+ content-length:
+ - '14977'
+ expires:
+ - Tue, 05 May 2020 06:48:59 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 06:48:59 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK24097642ABC
+ CoNoNoNoNoNoNoUnlinkedNoNoNo14436062Bobbob@abc.comNoe349fc1b-d92d-4ba2-b9fc-69fdd516e2a225698376Accountants
+ 101NoNoNoNoNoNoUnlinkedNoNoNo15370796Space
+ Rangerisabelle.miller@practiceignition.comNodcc6a649-c7a1-4cde-8e07-a40bde0466ee25698662Acmer
+ Pty LtdNoNoNo39a02ce2-f877-4d40-a5a7-d7355e88025b25697701Acmer
+ Pty LtdNoNoNofca33011-9be0-474c-bd3e-91ca18f74d8123702334Client
+ without contactNoNoNo1NoNoNoUnlinkedNoNoNo14573209Ian
+ testyo@example.comNo14573208Second
+ personme@example.comNo0b63ab7c-23e7-49ed-a9a4-fd053a8cee9723864530Ian
+ Example Client123@123.com123 Main StreetSydneyNew
+ South Wales2041Australia123
+ PostalNoNoNoNoNoNoUnlinkedNoNoNo14346188Ian
+ Contactnewguy@123.comYes14304486Space
+ Ranger123@123.comNo14346189Third
+ Guythree@123.comNo66173c1d-dad7-4b9c-82eb-a3d517bb597523403717Practice
+ Ignition - XPM Product & Development Testing AccountNoNoNoNoNoNoUnlinkedNoNoNo14348419Test
+ Contacttest@123.comNo95554526-e774-4de5-8fd5-0e4b5280c00423702571Space
+ Rangertest@test.com123 Gotham StreetSydneyNew
+ South Wales2041Australia12345678NoNoNo1NoNoNoUnlinkedNoNoNo14494468Batman
+ Personian@example.comNo14213073Contact
+ aianlenehan@gmail.comNo14574280new
+ guyNo14574267Second
+ contactcontact@example.comNo14574372some
+ guyNo14574278Some
+ guyNo14657104Space
+ Rangerluis@practiceignition.comNo04c412be-57d5-41d5-a18d-7077137f91d325116743Space
+ Rangernewuser@test.comNoNoNoNoNoNoUnlinkedNoNoNo15094752Space
+ Rangernewuser@test.comNocc84c96e-853c-4400-96df-ee24912938b325602022Space
+ Rangerpayments@practiceignition.comNoNoNoNoNoNoUnlinkedNoNoNo3571b76d-a568-47b0-a38a-79b26161f37424688375Test
+ Client123 Fake Street123123123123123041234123402
+ 1234 1234NoNoNoNoNoNoUnlinkedNoNoNo14786464Dud
+ Contact04123412340412341234No14786465Mr
+ Test Testermantest@testerman.comasdasdsadNo14922753-95ec-4ad2-99bb-0b58d223074725655881Updated2
+ Person NameNoNoNo1NoNoNoUnlinkedNoNoNo15412877Acmer
+ Pty Ltd Updated 3No9f868ba7-437c-4574-9a17-8c6f4890545b
+ http_version: null
+ recorded_at: Tue, 05 May 2020 06:48:59 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/list/when_detailed_true.yml b/spec/vcr_cassettes/xpm_ruby/client/list/when_detailed_true.yml
new file mode 100644
index 0000000..627a8fe
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/list/when_detailed_true.yml
@@ -0,0 +1,102 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/client.api/list?detailed=true
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9998'
+ x-daylimit-remaining:
+ - '4971'
+ x-minlimit-remaining:
+ - '58'
+ xero-correlation-id:
+ - 687c87ec-5995-413d-b83c-6c8ba50f4e8a
+ content-length:
+ - '15529'
+ expires:
+ - Tue, 05 May 2020 06:49:08 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 06:49:08 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK24097642ABC
+ CoNoNoNoNoNoNoUnlinkedNoNoNo14436062Bobbob@abc.comNoe349fc1b-d92d-4ba2-b9fc-69fdd516e2a225698376Accountants
+ 101NoNoNoNoNoNoUnlinkedNoNoNo15370796Space
+ Rangerisabelle.miller@practiceignition.comNodcc6a649-c7a1-4cde-8e07-a40bde0466ee25698662Acmer
+ Pty LtdNoNoNo39a02ce2-f877-4d40-a5a7-d7355e88025b25697701Acmer
+ Pty LtdNoNoNofca33011-9be0-474c-bd3e-91ca18f74d8123702334Client
+ without contactNoNoNo1NoNoNoUnlinkedNoNoNo14573209Ian
+ testyo@example.comNo14573208Second
+ personme@example.comNo0b63ab7c-23e7-49ed-a9a4-fd053a8cee9723864530Ian
+ Example Client123@123.com123 Main StreetSydneyNew
+ South Wales2041Australia123
+ PostalNoNoNoNoNoNoUnlinkedNoNoNo14346188Ian
+ Contactnewguy@123.comYes14304486Space
+ Ranger123@123.comNo14346189Third
+ Guythree@123.comNo922877Test Group66173c1d-dad7-4b9c-82eb-a3d517bb597523403717Practice
+ Ignition - XPM Product & Development Testing AccountNoNoNoNoNoNoUnlinkedNoNoNo14348419Test
+ Contacttest@123.comNo922877Test Group95554526-e774-4de5-8fd5-0e4b5280c00423702571Space
+ Rangertest@test.com123 Gotham StreetSydneyNew
+ South Wales2041Australia12345678NoNoNo1NoNoNoUnlinkedNoNoNo14494468Batman
+ Personian@example.comNo14213073Contact
+ aianlenehan@gmail.comNo14574280new
+ guyNo14574267Second
+ contactcontact@example.comNo14574372some
+ guyNo14574278Some
+ guyNo14657104Space
+ Rangerluis@practiceignition.comNo04c412be-57d5-41d5-a18d-7077137f91d325116743Space
+ Rangernewuser@test.comNoNoNoNoNoNoUnlinkedNoNoNo15094752Space
+ Rangernewuser@test.comNocc84c96e-853c-4400-96df-ee24912938b325602022Space
+ Rangerpayments@practiceignition.comNoNoNoNoNoNoUnlinkedNoNoNo3571b76d-a568-47b0-a38a-79b26161f37424688375Test
+ Client123 Fake Street123123123123123041234123402
+ 1234 1234NoNoNoNoNoNoUnlinkedNoNoNo14786464Dud
+ Contact04123412340412341234No14786465Mr
+ Test Testermantest@testerman.comasdasdsadNo14922753-95ec-4ad2-99bb-0b58d223074725655881Updated2
+ Person NameNoNoNo1NoNoNoUnlinkedNoNoNo15412877Acmer
+ Pty Ltd Updated 3No9f868ba7-437c-4574-9a17-8c6f4890545b
+ http_version: null
+ recorded_at: Tue, 05 May 2020 06:49:08 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/list/when_modified_since.yml b/spec/vcr_cassettes/xpm_ruby/client/list/when_modified_since.yml
new file mode 100644
index 0000000..6d69f97
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/list/when_modified_since.yml
@@ -0,0 +1,57 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/client.api/list?detailed=true&modifiedsince=2020-05-05T06%3A24%3A31
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4973'
+ x-minlimit-remaining:
+ - '58'
+ xero-correlation-id:
+ - a9d5d271-2916-436c-b785-e12db4f0600e
+ content-length:
+ - '1271'
+ expires:
+ - Tue, 05 May 2020 06:47:51 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 06:47:51 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK25655881Updated2
+ Person NameNoNoNo1NoNoNoUnlinkedNoNoNo15412877Acmer
+ Pty Ltd Updated 3No9f868ba7-437c-4574-9a17-8c6f4890545b
+ http_version: null
+ recorded_at: Tue, 05 May 2020 06:47:51 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/list/when_not_modified_since.yml b/spec/vcr_cassettes/xpm_ruby/client/list/when_not_modified_since.yml
new file mode 100644
index 0000000..8a75caa
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/list/when_not_modified_since.yml
@@ -0,0 +1,102 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/client.api/list?detailed=true
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9998'
+ x-daylimit-remaining:
+ - '4974'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - b7b76736-1878-4597-9c29-3fd1a4d4acea
+ content-length:
+ - '15529'
+ expires:
+ - Tue, 05 May 2020 06:47:11 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 06:47:11 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK24097642ABC
+ CoNoNoNoNoNoNoUnlinkedNoNoNo14436062Bobbob@abc.comNoe349fc1b-d92d-4ba2-b9fc-69fdd516e2a225698376Accountants
+ 101NoNoNoNoNoNoUnlinkedNoNoNo15370796Space
+ Rangerisabelle.miller@practiceignition.comNodcc6a649-c7a1-4cde-8e07-a40bde0466ee25698662Acmer
+ Pty LtdNoNoNo39a02ce2-f877-4d40-a5a7-d7355e88025b25697701Acmer
+ Pty LtdNoNoNofca33011-9be0-474c-bd3e-91ca18f74d8123702334Client
+ without contactNoNoNo1NoNoNoUnlinkedNoNoNo14573209Ian
+ testyo@example.comNo14573208Second
+ personme@example.comNo0b63ab7c-23e7-49ed-a9a4-fd053a8cee9723864530Ian
+ Example Client123@123.com123 Main StreetSydneyNew
+ South Wales2041Australia123
+ PostalNoNoNoNoNoNoUnlinkedNoNoNo14346188Ian
+ Contactnewguy@123.comYes14304486Space
+ Ranger123@123.comNo14346189Third
+ Guythree@123.comNo922877Test Group66173c1d-dad7-4b9c-82eb-a3d517bb597523403717Practice
+ Ignition - XPM Product & Development Testing AccountNoNoNoNoNoNoUnlinkedNoNoNo14348419Test
+ Contacttest@123.comNo922877Test Group95554526-e774-4de5-8fd5-0e4b5280c00423702571Space
+ Rangertest@test.com123 Gotham StreetSydneyNew
+ South Wales2041Australia12345678NoNoNo1NoNoNoUnlinkedNoNoNo14494468Batman
+ Personian@example.comNo14213073Contact
+ aianlenehan@gmail.comNo14574280new
+ guyNo14574267Second
+ contactcontact@example.comNo14574372some
+ guyNo14574278Some
+ guyNo14657104Space
+ Rangerluis@practiceignition.comNo04c412be-57d5-41d5-a18d-7077137f91d325116743Space
+ Rangernewuser@test.comNoNoNoNoNoNoUnlinkedNoNoNo15094752Space
+ Rangernewuser@test.comNocc84c96e-853c-4400-96df-ee24912938b325602022Space
+ Rangerpayments@practiceignition.comNoNoNoNoNoNoUnlinkedNoNoNo3571b76d-a568-47b0-a38a-79b26161f37424688375Test
+ Client123 Fake Street123123123123123041234123402
+ 1234 1234NoNoNoNoNoNoUnlinkedNoNoNo14786464Dud
+ Contact04123412340412341234No14786465Mr
+ Test Testermantest@testerman.comasdasdsadNo14922753-95ec-4ad2-99bb-0b58d223074725655881Updated2
+ Person NameNoNoNo1NoNoNoUnlinkedNoNoNo15412877Acmer
+ Pty Ltd Updated 3No9f868ba7-437c-4574-9a17-8c6f4890545b
+ http_version: null
+ recorded_at: Tue, 05 May 2020 06:47:11 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/search/when_detailed_false.yml b/spec/vcr_cassettes/xpm_ruby/client/search/when_detailed_false.yml
new file mode 100644
index 0000000..8f30c9d
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/search/when_detailed_false.yml
@@ -0,0 +1,57 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/client.api/search?detailed=false&query=acme
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v2.7.4
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE2NzQzNjkyNDksImV4cCI6MTY3NDM3MTA0OSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTY3Mjc5NTU2MywieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6Ijk3NDljMzQ4ZmZhMzRkMzI4NDcwZjY0NWIxMGVkMzg5IiwianRpIjoiQzhEMjZDRTE3NEJGNERERTMwNzczRjUyNTUwOTk4RTAiLCJhdXRoZW50aWNhdGlvbl9ldmVudF9pZCI6IjExYWFlNGUyLWEzNDYtNDg4ZC05ZmZiLTkzYzBkM2E3Y2Q5NyIsInNjb3BlIjpbImVtYWlsIiwicHJvZmlsZSIsIm9wZW5pZCIsInByYWN0aWNlbWFuYWdlciIsIm9mZmxpbmVfYWNjZXNzIl0sImFtciI6WyJwd2QiLCJtZmEiLCJvdHAiXX0.Ads4JYjmWnaoV2aGFvnMdsudYyAikh9vY_cyrnhP3vSigbT5-oU8EvX3fLqwMB8fXw10YkPJ-88xeBP-avFAHX5RjW0dX3vWb0lEYFCTx5olt-qNOaxEy7WxrpuR9hQADlgCpyIPTfDwg5BRSfxxfQ766O-sMMeKq-Klr39uKbLUFzbu4x0MN9lJ0y-DqC87mTCU3AGncKVvdILndUcagiiiCBKrCYCoEF_vzY1t9ngP97uDbiKdH73M1b425mL46-3UW8aAEU9hH377rw-B4yMid3TGwB-ETgWr_KPEtd84_VzNTqcc85JQQRoI0ufadBx4laFTMBp--4Ih3iPlUA
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ content-length:
+ - '3030'
+ server:
+ - nginx
+ xero-correlation-id:
+ - 42b282a3-28b4-46ed-b9f8-d0735113ca8b
+ x-appminlimit-remaining:
+ - '9999'
+ x-minlimit-remaining:
+ - '59'
+ x-daylimit-remaining:
+ - '4992'
+ expires:
+ - Sun, 22 Jan 2023 06:35:19 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Sun, 22 Jan 2023 06:35:19 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK25697701Acmer
+ Pty LtdNoNoNoNoNoNoUnlinkedNoNoNo17243461dasdasdads@asdasdasd.comNofca33011-9be0-474c-bd3e-91ca18f74d8125698662Acmer
+ Pty LtdNoNoNoNoNoNoUnlinkedNoNoNo43155897Another
+ Contactasdfds@12312.comNo18476686dasdasdads@asdasdasd.comNo16963243dasdasdads@asdasdasd.comNo43155896Some
+ Contactqwe@123.comYes39a02ce2-f877-4d40-a5a7-d7355e88025b
+ recorded_at: Sun, 22 Jan 2023 06:35:19 GMT
+recorded_with: VCR 6.0.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/search/when_detailed_true.yml b/spec/vcr_cassettes/xpm_ruby/client/search/when_detailed_true.yml
new file mode 100644
index 0000000..8dae4e5
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/search/when_detailed_true.yml
@@ -0,0 +1,59 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/client.api/search?detailed=true&query=acme
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v2.7.4
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE2NzQzNjkyNDksImV4cCI6MTY3NDM3MTA0OSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTY3Mjc5NTU2MywieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6Ijk3NDljMzQ4ZmZhMzRkMzI4NDcwZjY0NWIxMGVkMzg5IiwianRpIjoiQzhEMjZDRTE3NEJGNERERTMwNzczRjUyNTUwOTk4RTAiLCJhdXRoZW50aWNhdGlvbl9ldmVudF9pZCI6IjExYWFlNGUyLWEzNDYtNDg4ZC05ZmZiLTkzYzBkM2E3Y2Q5NyIsInNjb3BlIjpbImVtYWlsIiwicHJvZmlsZSIsIm9wZW5pZCIsInByYWN0aWNlbWFuYWdlciIsIm9mZmxpbmVfYWNjZXNzIl0sImFtciI6WyJwd2QiLCJtZmEiLCJvdHAiXX0.Ads4JYjmWnaoV2aGFvnMdsudYyAikh9vY_cyrnhP3vSigbT5-oU8EvX3fLqwMB8fXw10YkPJ-88xeBP-avFAHX5RjW0dX3vWb0lEYFCTx5olt-qNOaxEy7WxrpuR9hQADlgCpyIPTfDwg5BRSfxxfQ766O-sMMeKq-Klr39uKbLUFzbu4x0MN9lJ0y-DqC87mTCU3AGncKVvdILndUcagiiiCBKrCYCoEF_vzY1t9ngP97uDbiKdH73M1b425mL46-3UW8aAEU9hH377rw-B4yMid3TGwB-ETgWr_KPEtd84_VzNTqcc85JQQRoI0ufadBx4laFTMBp--4Ih3iPlUA
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ content-length:
+ - '3102'
+ server:
+ - nginx
+ xero-correlation-id:
+ - fc407a0a-93bb-496e-b951-386942f8a984
+ x-appminlimit-remaining:
+ - '9998'
+ x-minlimit-remaining:
+ - '58'
+ x-daylimit-remaining:
+ - '4991'
+ expires:
+ - Sun, 22 Jan 2023 06:35:20 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Sun, 22 Jan 2023 06:35:20 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK25697701Acmer
+ Pty LtdNoNoNoNoNoNoUnlinkedNoNoNo17243461dasdasdads@asdasdasd.comNofca33011-9be0-474c-bd3e-91ca18f74d8125698662Acmer
+ Pty LtdNoNoNoNoNoNoUnlinkedNoNoNo43155897Another
+ Contactasdfds@12312.comNo18476686dasdasdads@asdasdasd.comNo16963243dasdasdads@asdasdasd.comNo43155896Some
+ Contactqwe@123.comYes39a02ce2-f877-4d40-a5a7-d7355e88025b
+ recorded_at: Sun, 22 Jan 2023 06:35:20 GMT
+recorded_with: VCR 6.0.0
diff --git a/spec/vcr_cassettes/xpm_ruby/client/update.yml b/spec/vcr_cassettes/xpm_ruby/client/update.yml
new file mode 100644
index 0000000..03471af
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/client/update.yml
@@ -0,0 +1,63 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/client.api/update
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ 25655881
+ Acmer Pty Ltd
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer "access_token"
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4978'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - b8d8cbed-eebb-4a1b-ad08-7268a2995dd4
+ content-length:
+ - '1025'
+ expires:
+ - Mon, 04 May 2020 06:09:44 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Mon, 04 May 2020 06:09:44 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK25655881Acmer
+ Pty LtdNoNoNo1NoNoNoUnlinkedNoNoNo9f868ba7-437c-4574-9a17-8c6f4890545b
+ http_version: null
+ recorded_at: Mon, 04 May 2020 06:09:44 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/delete.yml b/spec/vcr_cassettes/xpm_ruby/connection/delete.yml
new file mode 100644
index 0000000..af8f5f1
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/delete.yml
@@ -0,0 +1,55 @@
+---
+http_interactions:
+- request:
+ method: delete
+ uri: https://api.xero.com/practicemanager/3.0/client.api/contact/14574323
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg1NjM4MjIsImV4cCI6MTU4ODU2NTYyMiwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODU2MzgxNCwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjQ0ODY2YjJkNmMzNzRiYWZhMzM4MjU0YTFhZjIzNDBhIiwianRpIjoiODBjNDMyNzdhYWM5MzVjMzljYTViYjA2ZjE5OWE1OTIiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.fefoKqd3tRoLYlL4Vm9BvfI90ngJ548hzt_Me8_QsJfj_JLU2jRCqXITszpPUDEMWY1rmi3Qgmkgp2rdOdVJlNMYBk_nolPOrxYVSx6H2rMEWSGsMAkDpTuxdzPzuHYQGK5A1u5zHSRJYsHL6Ke-W7XkTv61gcTLoTqbRXRZ6HTvFdHCCKFN89ru0UHzWBi8a2IsVsq0HJOU00mWxK2Gdja1IWlxapWSKpfe16VTZIf7P1ch2HUZg6F2uytxzhYEubh-HYBJtfOnM15F7iWYcdEW9wXP_TtPBkoVFbXnb_J7BXDq5L8nnbKfmxM7Ra23kEvp_kogTwa5m4yEQFzwLQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4984'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 6a30dba0-db14-4489-8eb3-2a0fa6e75828
+ content-length:
+ - '266'
+ expires:
+ - Mon, 04 May 2020 04:06:51 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Mon, 04 May 2020 04:06:51 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK14574323some
+ guy personNo
+ http_version: null
+ recorded_at: Mon, 04 May 2020 04:06:51 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/delete/bad_tenant.yml b/spec/vcr_cassettes/xpm_ruby/connection/delete/bad_tenant.yml
new file mode 100644
index 0000000..336f895
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/delete/bad_tenant.yml
@@ -0,0 +1,50 @@
+---
+http_interactions:
+- request:
+ method: delete
+ uri: https://api.xero.com/practicemanager/3.0/client.api/contact/14574323
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg2NTA2MjEsImV4cCI6MTU4ODY1MjQyMSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODY1MDYwOSwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjJjODE3OTIzZWI3NTQ5Nzk4ODZkNmQyNzNlMDIxOWY4IiwianRpIjoiNGM0NmJmZDA5NjFlYWZhNmFmZjQ1M2M1NjQ0NWEyZGEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.Zsak1BIzRocLPjWb62uVgNaWO3U3o1LKtWrzO2Sj3AoSg-y1Rk5bKxp9PzaAEtE2qmyMQTDGlPHV0jzcqnZOqbbWdLAqyLVDQEeW7nh-9ZWVHmuJ9GG7DKzvHv7Sau_R3i_TlRRcdnQmYdhvZlqg-eUeZXGdzJnFWDk121SuV3dMJV0fJsfg3sfdr7DmbBoWCn-hdcSo2CuYA-IdnIFvlaX2lfZ06i391kYF0YGbWcZ_BX6cUWKMYBuoT_dBZL0wN_6q5KLCgRrLFqgXoR8Eao-h6bXEPTHgx0rW14cVeSrVOeobmJjqnsEd2LyDyn5zWaoie2Xezt5KBtNPtPGr7g
+ xero-tenant-id:
+ - bad_tenant
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 403
+ message: Forbidden
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ xero-correlation-id:
+ - 64fe91e7-a15a-4537-ae70-c2e1c89f47ec
+ content-length:
+ - '150'
+ expires:
+ - Tue, 05 May 2020 04:10:47 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 04:10:47 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Forbidden","Status":403,"Detail":"AuthenticationUnsuccessful","Instance":"64fe91e7-a15a-4537-ae70-c2e1c89f47ec","Extensions":{}}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 04:10:47 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/delete/bad_token.yml b/spec/vcr_cassettes/xpm_ruby/connection/delete/bad_token.yml
new file mode 100644
index 0000000..a10ddb0
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/delete/bad_token.yml
@@ -0,0 +1,50 @@
+---
+http_interactions:
+- request:
+ method: delete
+ uri: https://api.xero.com/practicemanager/3.0/client.api/contact/14574323
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer bad_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 401
+ message: Unauthorized
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ www-authenticate:
+ - Bearer error=invalid_token
+ xero-correlation-id:
+ - 973905d0-d2c7-4689-9d2d-4032c6439ccc
+ content-length:
+ - '153'
+ expires:
+ - Tue, 05 May 2020 04:10:48 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 04:10:48 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Unauthorized","Status":401,"Detail":"AuthenticationUnsuccessful","Instance":"973905d0-d2c7-4689-9d2d-4032c6439ccc","Extensions":{}}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 04:10:48 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/get.yml b/spec/vcr_cassettes/xpm_ruby/connection/get.yml
new file mode 100644
index 0000000..7b09d4d
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/get.yml
@@ -0,0 +1,60 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODgxMTUyMTQsImV4cCI6MTU4ODExNzAxNCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODA1MTE0MywieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjQzMGI0ZmVmMWI0NjQ2MGZiMTgwOWNmNmQ5OWJhODIxIiwianRpIjoiMmI3NGQxZDZhMzcxNDlhN2VjNjkwNmM2NGM0MDFlMjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.EJ5_dU4efS9e2w68A63GQaVWghmcIONEOfkB4Wp0IGNwTbNU441x3vSAMdRY5MShT1jk9cTR-207OKClFJAuwWZbODQcs2bV9YDj5PH9cCtNCULFOClQCn7zfUonkMdZ9FiL4RjJ6xXbWOmfD-vYhQRLbAkKDcZad8HcPIzPyKvyHFuxTDk7FKs-OI3sUPQUqQrBKAcmD2C8PR8al7PNn0kwrug1a2_R0z74Sygg1iKJlShMLMBbaDfq_7zxbMvGrLvW1vLMlJDhxD-sR4_T-B3n6_VDFybFfShQqtkoJwk4-fAqc0S8N0Vmx_kRLqzVEIE8NiouqnTvt6i8Bvc5PQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-daylimit-remaining:
+ - '4999'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - f2154beb-32f3-47aa-8a0a-e327cf7ebb9f
+ content-length:
+ - '1794'
+ expires:
+ - Tue, 28 Apr 2020 23:17:54 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 28 Apr 2020 23:17:54 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK859230Dev
+ Testingdev@practiceignition.com859317Ed
+ Minnluis+edminn@practiceignition.com858949Jana
+ Paulechjana@practiceignition.com859231Nick
+ Daintynick@practiceignition.com863967Nick
+ Daintynick+xpmtest2@practiceignition.com858948Patrick
+ Frigopatrick.frigo@xero.com859319Patty
+ Igneousluis@practiceignition.com859318Some
+ Usersome_user@pattyrocks.com863927Testchris@practiceignition.com866437testadammikulas@gmail.com
+ http_version: null
+ recorded_at: Tue, 28 Apr 2020 23:17:54 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/get/bad_tenant.yml b/spec/vcr_cassettes/xpm_ruby/connection/get/bad_tenant.yml
new file mode 100644
index 0000000..fce36eb
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/get/bad_tenant.yml
@@ -0,0 +1,50 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg2NTA2MjEsImV4cCI6MTU4ODY1MjQyMSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODY1MDYwOSwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjJjODE3OTIzZWI3NTQ5Nzk4ODZkNmQyNzNlMDIxOWY4IiwianRpIjoiNGM0NmJmZDA5NjFlYWZhNmFmZjQ1M2M1NjQ0NWEyZGEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.Zsak1BIzRocLPjWb62uVgNaWO3U3o1LKtWrzO2Sj3AoSg-y1Rk5bKxp9PzaAEtE2qmyMQTDGlPHV0jzcqnZOqbbWdLAqyLVDQEeW7nh-9ZWVHmuJ9GG7DKzvHv7Sau_R3i_TlRRcdnQmYdhvZlqg-eUeZXGdzJnFWDk121SuV3dMJV0fJsfg3sfdr7DmbBoWCn-hdcSo2CuYA-IdnIFvlaX2lfZ06i391kYF0YGbWcZ_BX6cUWKMYBuoT_dBZL0wN_6q5KLCgRrLFqgXoR8Eao-h6bXEPTHgx0rW14cVeSrVOeobmJjqnsEd2LyDyn5zWaoie2Xezt5KBtNPtPGr7g
+ xero-tenant-id:
+ - bad_tenant
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 403
+ message: Forbidden
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ xero-correlation-id:
+ - d2fa1f07-b355-4e08-bc18-24d12f07f2b5
+ content-length:
+ - '150'
+ expires:
+ - Tue, 05 May 2020 03:52:34 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 03:52:34 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Forbidden","Status":403,"Detail":"AuthenticationUnsuccessful","Instance":"d2fa1f07-b355-4e08-bc18-24d12f07f2b5","Extensions":{}}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 03:52:34 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/get/bad_token.yml b/spec/vcr_cassettes/xpm_ruby/connection/get/bad_token.yml
new file mode 100644
index 0000000..b38dc58
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/get/bad_token.yml
@@ -0,0 +1,50 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer bad_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 401
+ message: Unauthorized
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ www-authenticate:
+ - Bearer error=invalid_token
+ xero-correlation-id:
+ - 1f5a84cd-152b-418d-a0b1-e351fa131d05
+ content-length:
+ - '153'
+ expires:
+ - Tue, 05 May 2020 03:52:34 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 03:52:34 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Unauthorized","Status":401,"Detail":"AuthenticationUnsuccessful","Instance":"1f5a84cd-152b-418d-a0b1-e351fa131d05","Extensions":{}}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 03:52:34 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/get/internal_server_error.yml b/spec/vcr_cassettes/xpm_ruby/connection/get/internal_server_error.yml
new file mode 100644
index 0000000..2d7ea7d
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/get/internal_server_error.yml
@@ -0,0 +1,50 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer bad_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 500
+ message: Internal Server Error
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ www-authenticate:
+ - Bearer error=invalid_token
+ xero-correlation-id:
+ - 1f5a84cd-152b-418d-a0b1-e351fa131d05
+ content-length:
+ - '153'
+ expires:
+ - Tue, 05 May 2020 03:52:34 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 03:52:34 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{Status":500}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 03:52:34 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/get/not_available.yml b/spec/vcr_cassettes/xpm_ruby/connection/get/not_available.yml
new file mode 100644
index 0000000..fddf939
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/get/not_available.yml
@@ -0,0 +1,50 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer bad_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 503
+ message: Unavailable
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ www-authenticate:
+ - Bearer error=invalid_token
+ xero-correlation-id:
+ - 1f5a84cd-152b-418d-a0b1-e351fa131d05
+ content-length:
+ - '153'
+ expires:
+ - Tue, 05 May 2020 03:52:34 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 03:52:34 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Unavailable","Status":503,"Detail":"ServiceNotAvailable","Instance":"1f5a84cd-152b-418d-a0b1-e351fa131d05","Extensions":{}}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 03:52:34 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/get/rate_limit_exceeded.yml b/spec/vcr_cassettes/xpm_ruby/connection/get/rate_limit_exceeded.yml
new file mode 100644
index 0000000..a494e8b
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/get/rate_limit_exceeded.yml
@@ -0,0 +1,56 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer access_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 429
+ message: Too Many Requests
+ headers:
+ server:
+ - nginx
+ retry-after:
+ - '22'
+ xero-correlation-id:
+ - fd990f75-0fe2-4c79-bb4f-7aeaef3ec306
+ x-appminlimit-remaining:
+ - '9938'
+ x-minlimit-remaining:
+ - '0'
+ x-daylimit-remaining:
+ - '4539'
+ x-rate-limit-problem:
+ - minute
+ content-length:
+ - '0'
+ expires:
+ - Wed, 23 Jun 2021 13:00:34 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 23 Jun 2021 13:00:34 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: ''
+ http_version: null
+ recorded_at: Wed, 23 Jun 2021 13:00:34 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/post.yml b/spec/vcr_cassettes/xpm_ruby/connection/post.yml
new file mode 100644
index 0000000..97b8fbd
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/post.yml
@@ -0,0 +1,58 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/job.api/add
+ body:
+ encoding: UTF-8
+ string: "Brochure DesignDetailed description
+ of the job240976422029102320291028"
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODgxMTUyMTQsImV4cCI6MTU4ODExNzAxNCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODA1MTE0MywieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjQzMGI0ZmVmMWI0NjQ2MGZiMTgwOWNmNmQ5OWJhODIxIiwianRpIjoiMmI3NGQxZDZhMzcxNDlhN2VjNjkwNmM2NGM0MDFlMjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.EJ5_dU4efS9e2w68A63GQaVWghmcIONEOfkB4Wp0IGNwTbNU441x3vSAMdRY5MShT1jk9cTR-207OKClFJAuwWZbODQcs2bV9YDj5PH9cCtNCULFOClQCn7zfUonkMdZ9FiL4RjJ6xXbWOmfD-vYhQRLbAkKDcZad8HcPIzPyKvyHFuxTDk7FKs-OI3sUPQUqQrBKAcmD2C8PR8al7PNn0kwrug1a2_R0z74Sygg1iKJlShMLMBbaDfq_7zxbMvGrLvW1vLMlJDhxD-sR4_T-B3n6_VDFybFfShQqtkoJwk4-fAqc0S8N0Vmx_kRLqzVEIE8NiouqnTvt6i8Bvc5PQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-daylimit-remaining:
+ - '4996'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - e81ba109-9c33-4457-853b-6d1a17406718
+ content-length:
+ - '441'
+ expires:
+ - Tue, 28 Apr 2020 23:28:07 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 28 Apr 2020 23:28:07 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OKJ000029Brochure
+ DesignDetailed description of the job24097642ABC
+ CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044346180
+ http_version: null
+ recorded_at: Tue, 28 Apr 2020 23:28:07 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/post/bad_tenant.yml b/spec/vcr_cassettes/xpm_ruby/connection/post/bad_tenant.yml
new file mode 100644
index 0000000..828153d
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/post/bad_tenant.yml
@@ -0,0 +1,53 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/job.api/add
+ body:
+ encoding: UTF-8
+ string: "Brochure DesignDetailed description
+ of the job240976422029102320291028"
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg2NTA2MjEsImV4cCI6MTU4ODY1MjQyMSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODY1MDYwOSwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjJjODE3OTIzZWI3NTQ5Nzk4ODZkNmQyNzNlMDIxOWY4IiwianRpIjoiNGM0NmJmZDA5NjFlYWZhNmFmZjQ1M2M1NjQ0NWEyZGEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.Zsak1BIzRocLPjWb62uVgNaWO3U3o1LKtWrzO2Sj3AoSg-y1Rk5bKxp9PzaAEtE2qmyMQTDGlPHV0jzcqnZOqbbWdLAqyLVDQEeW7nh-9ZWVHmuJ9GG7DKzvHv7Sau_R3i_TlRRcdnQmYdhvZlqg-eUeZXGdzJnFWDk121SuV3dMJV0fJsfg3sfdr7DmbBoWCn-hdcSo2CuYA-IdnIFvlaX2lfZ06i391kYF0YGbWcZ_BX6cUWKMYBuoT_dBZL0wN_6q5KLCgRrLFqgXoR8Eao-h6bXEPTHgx0rW14cVeSrVOeobmJjqnsEd2LyDyn5zWaoie2Xezt5KBtNPtPGr7g
+ xero-tenant-id:
+ - bad_tenant
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 403
+ message: Forbidden
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9997'
+ xero-correlation-id:
+ - fa06d08f-8f9c-4607-afac-c583f47abccf
+ content-length:
+ - '150'
+ expires:
+ - Tue, 05 May 2020 04:07:12 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 04:07:12 GMT
+ connection:
+ - close
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Forbidden","Status":403,"Detail":"AuthenticationUnsuccessful","Instance":"fa06d08f-8f9c-4607-afac-c583f47abccf","Extensions":{}}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 04:07:12 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/post/bad_token.yml b/spec/vcr_cassettes/xpm_ruby/connection/post/bad_token.yml
new file mode 100644
index 0000000..896bb66
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/post/bad_token.yml
@@ -0,0 +1,53 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/job.api/add
+ body:
+ encoding: UTF-8
+ string: "Brochure DesignDetailed description
+ of the job240976422029102320291028"
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer bad_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 401
+ message: Unauthorized
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ www-authenticate:
+ - Bearer error=invalid_token
+ xero-correlation-id:
+ - 6b6e378d-c2df-4e97-a22f-fba11ebcac42
+ content-length:
+ - '153'
+ expires:
+ - Tue, 05 May 2020 04:07:12 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 04:07:12 GMT
+ connection:
+ - close
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Unauthorized","Status":401,"Detail":"AuthenticationUnsuccessful","Instance":"6b6e378d-c2df-4e97-a22f-fba11ebcac42","Extensions":{}}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 04:07:12 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/put.yml b/spec/vcr_cassettes/xpm_ruby/connection/put.yml
new file mode 100644
index 0000000..6f67ef1
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/put.yml
@@ -0,0 +1,60 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/update
+ body:
+ encoding: UTF-8
+ string: "J000029Brochure Design UPDATEDDetailed
+ description of the job240976422029102320291028"
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg1NDg0NjAsImV4cCI6MTU4ODU1MDI2MCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODU0ODQ1MSwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjJjODBmMmNhNmU3OTQyYWNiZTBiYTk1NzY0Nzk1NGFhIiwianRpIjoiZTQ5ZWUxODYzNTMzZGQwNDgxOGU0ODM3NTI2N2RjNDIiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.mR6KQeDBi30hNt_turDOgeq9FN3xuJGoaTlcbetP4vRjy-HhkHpUfbWk6oUqU7M1-u_xKwWh2N3saH7xJTbE5T4lnj5FJLLz_GXL3uokhD9Z4TFk7ZjwjrOlg-Y0fvLwYc_DC-BG0m58clYPZnWSBxRtlVvIe7tSEGj0aH5ka9uRpfUTgWznrB-XokRoP2KtHNqY-oP2MqY-qmaX_1tzc3wzYxpAEu8X4anCSqCZan8Qx7q0RvdG8nvnrWWIRNAlZflT3t7oVJR3wNh2QIb85g8i0T92_Fn73zU4p-r7xd0VsWP4npX8DQpBsJNqt03Du3OwiwNyrzS2B6UskYsiEQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4999'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 50048c9e-944d-46a1-bb0a-a38effdaf21a
+ content-length:
+ - '452'
+ expires:
+ - Sun, 03 May 2020 23:28:08 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Sun, 03 May 2020 23:28:08 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OKJ000029Brochure
+ Design UPDATEDDetailed description of the job24097642ABC
+ CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044346180
+ http_version: null
+ recorded_at: Sun, 03 May 2020 23:28:08 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/put/bad_tenant.yml b/spec/vcr_cassettes/xpm_ruby/connection/put/bad_tenant.yml
new file mode 100644
index 0000000..a2d87f1
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/put/bad_tenant.yml
@@ -0,0 +1,53 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/update
+ body:
+ encoding: UTF-8
+ string: "J000029Brochure Design UPDATEDDetailed
+ description of the job240976422029102320291028"
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg2NTA2MjEsImV4cCI6MTU4ODY1MjQyMSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODY1MDYwOSwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjJjODE3OTIzZWI3NTQ5Nzk4ODZkNmQyNzNlMDIxOWY4IiwianRpIjoiNGM0NmJmZDA5NjFlYWZhNmFmZjQ1M2M1NjQ0NWEyZGEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.Zsak1BIzRocLPjWb62uVgNaWO3U3o1LKtWrzO2Sj3AoSg-y1Rk5bKxp9PzaAEtE2qmyMQTDGlPHV0jzcqnZOqbbWdLAqyLVDQEeW7nh-9ZWVHmuJ9GG7DKzvHv7Sau_R3i_TlRRcdnQmYdhvZlqg-eUeZXGdzJnFWDk121SuV3dMJV0fJsfg3sfdr7DmbBoWCn-hdcSo2CuYA-IdnIFvlaX2lfZ06i391kYF0YGbWcZ_BX6cUWKMYBuoT_dBZL0wN_6q5KLCgRrLFqgXoR8Eao-h6bXEPTHgx0rW14cVeSrVOeobmJjqnsEd2LyDyn5zWaoie2Xezt5KBtNPtPGr7g
+ xero-tenant-id:
+ - bad_tenant
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 403
+ message: Forbidden
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ xero-correlation-id:
+ - a959a763-cd16-471d-ba2c-9bdcfc2543d3
+ content-length:
+ - '150'
+ expires:
+ - Tue, 05 May 2020 04:09:28 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 04:09:28 GMT
+ connection:
+ - close
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Forbidden","Status":403,"Detail":"AuthenticationUnsuccessful","Instance":"a959a763-cd16-471d-ba2c-9bdcfc2543d3","Extensions":{}}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 04:09:28 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/connection/put/bad_token.yml b/spec/vcr_cassettes/xpm_ruby/connection/put/bad_token.yml
new file mode 100644
index 0000000..459ef72
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/connection/put/bad_token.yml
@@ -0,0 +1,53 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/update
+ body:
+ encoding: UTF-8
+ string: "J000029Brochure Design UPDATEDDetailed
+ description of the job240976422029102320291028"
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer bad_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 401
+ message: Unauthorized
+ headers:
+ content-type:
+ - application/json
+ server:
+ - Kestrel
+ www-authenticate:
+ - Bearer error=invalid_token
+ xero-correlation-id:
+ - 23986fb7-2c64-463c-9e0f-c24a86f97fd7
+ content-length:
+ - '153'
+ expires:
+ - Tue, 05 May 2020 04:09:28 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 04:09:28 GMT
+ connection:
+ - close
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Unauthorized","Status":401,"Detail":"AuthenticationUnsuccessful","Instance":"23986fb7-2c64-463c-9e0f-c24a86f97fd7","Extensions":{}}'
+ http_version: null
+ recorded_at: Tue, 05 May 2020 04:09:28 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/contact/add.yml b/spec/vcr_cassettes/xpm_ruby/contact/add.yml
new file mode 100644
index 0000000..e2952bd
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/contact/add.yml
@@ -0,0 +1,64 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/client.api/contact
+ body:
+ encoding: UTF-8
+ string: |
+
+
+
+ 25655881
+
+ Acmer Pty Ltd
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4990'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 057d41f1-0e06-4469-b3bf-9eb70b17f447
+ content-length:
+ - '264'
+ expires:
+ - Tue, 05 May 2020 03:30:46 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 03:30:46 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK15412877Acmer
+ Pty LtdNo
+ http_version: null
+ recorded_at: Tue, 05 May 2020 03:30:46 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/contact/delete.yml b/spec/vcr_cassettes/xpm_ruby/contact/delete.yml
new file mode 100644
index 0000000..631f729
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/contact/delete.yml
@@ -0,0 +1,105 @@
+---
+http_interactions:
+- request:
+ method: delete
+ uri: https://api.xero.com/practicemanager/3.0/client.api/contact/14574323
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4983'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - fc3f4eb9-a9e0-456c-8c02-28e9f5aec8c5
+ content-length:
+ - '266'
+ expires:
+ - Mon, 04 May 2020 05:10:25 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Mon, 04 May 2020 05:10:25 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK14574323some
+ guy personNo
+ recorded_at: Mon, 04 May 2020 05:10:25 GMT
+- request:
+ method: delete
+ uri: https://api.xero.com/practicemanager/3.0/client.api/contact/14574323?client_id=25655881
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v2.7.4
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4983'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - fc3f4eb9-a9e0-456c-8c02-28e9f5aec8c5
+ content-length:
+ - '266'
+ expires:
+ - Fri, 14 Apr 2023 11:36:53 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Mon, 04 May 2020 05:10:25 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK14574323some
+ guy personNo
+ recorded_at: Fri, 14 Apr 2023 11:36:53 GMT
+recorded_with: VCR 6.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/contact/update.yml b/spec/vcr_cassettes/xpm_ruby/contact/update.yml
new file mode 100644
index 0000000..35c3748
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/contact/update.yml
@@ -0,0 +1,122 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/client.api/contact/15412877
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ Acmer Pty Ltd Updated 3
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4985'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 1905d74e-32f4-49db-874e-91e08c9938e0
+ content-length:
+ - '274'
+ expires:
+ - Tue, 05 May 2020 04:33:24 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 04:33:24 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK15412877Acmer
+ Pty Ltd Updated 3No
+ http_version: null
+ recorded_at: Tue, 05 May 2020 04:33:24 GMT
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/client.api/contact/15412877
+ body:
+ encoding: UTF-8
+ string: |
+
+
+
+ 25655881
+
+ Acmer Pty Ltd Updated 3
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4985'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 1905d74e-32f4-49db-874e-91e08c9938e0
+ content-length:
+ - '274'
+ expires:
+ - Tue, 05 May 2020 04:33:24 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 04:33:24 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK15412877Acmer
+ Pty Ltd Updated 3No
+ http_version: null
+ recorded_at: Thu, 13 Apr 2023 05:18:03 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/add.yml b/spec/vcr_cassettes/xpm_ruby/job/add.yml
new file mode 100644
index 0000000..867a6cc
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/add.yml
@@ -0,0 +1,65 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/job.api/add
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ Joe Bloggs
+ New Job
+ 24097642
+ 20091023
+ 20091023
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODgyMDg3MjksImV4cCI6MTU4ODIxMDUyOSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODIwODU3NSwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjZmYWRiYTVmYWI3NTQ0NDliNjkwMGE1NzI3OGVlMjc5IiwianRpIjoiZmU2MjUyNzNhNmEwMTI4YjI2N2IxYmI1YWQzMGVkODgiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.iL5C3Lcc1KuxTcIMUNUdKfqRoB13flB46dyQ2fUcQesF_lloofR9qWzt1uijc91qQPnkyrgb_Kv2aGvR3YvXXM1naK2Wy87wfAJwonkAGm6IcIIeukgvvJMt3bNZvow-lrk2eb9Wfcz7xt_nJSqL9lr8YV9T5f56IWJzZJzwAiNYz4F1lmqzKMwX5fUU9gYHucgIgQAwDaD3AGPdB-AC71ZNw2Zwsshebv89CbSbpw7rGU9gEhHnI7PjXXYwRn430Zh9k0ruD7IQWNRMh26oS_PR4zIEFDGBn5xBdnm9jLWl9juQUkn0OPQvAwkEuM54AXSWaAgyeasdOtDNjD8JMA
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-daylimit-remaining:
+ - '4997'
+ x-minlimit-remaining:
+ - '58'
+ xero-correlation-id:
+ - 04e383a3-f80a-4076-b4fa-c5ac40eca5c8
+ content-length:
+ - '412'
+ expires:
+ - Thu, 30 Apr 2020 01:14:38 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Thu, 30 Apr 2020 01:14:38 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OKJ000031Joe
+ BloggsNew Job24097642ABC
+ CoPlanned2009-10-23T00:00:002009-10-23T00:00:0044385850
+ http_version: null
+ recorded_at: Thu, 30 Apr 2020 01:14:38 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/applytemplate.yml b/spec/vcr_cassettes/xpm_ruby/job/applytemplate.yml
new file mode 100644
index 0000000..2676c4d
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/applytemplate.yml
@@ -0,0 +1,71 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/job.api/applytemplate
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ J000032
+ 1254078
+ AddNew
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MzAwNzAsImV4cCI6MTU4ODczMTg3MCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODczMDA2MiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjA2NjA5YTA2M2IwYjRmY2Q5N2Y1NDhjOWJkZDI2Yzc0IiwianRpIjoiMjlkZGFkOGU4YzYxN2I4MmZkMjY5NDQ3MjI5ZmVjMDUiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.JrwjR8adShEJGeJi0WC5j8ADM-3q8RSdLgEDAsZr2GEedIuHCqUVF9QATqpXoL8rrRVnt14QPLXooGXY-mUiGbzgtJSj77ZYG1gbFrd2NgePavlewjiv1S4G4tAcV_L3z2ckB-3gTEEcTO0iqwAFYX5Q_nKdpAH-uHOoVPE2J19CniK_x88Eg9XSPYnBdy-xeAvqB7K3e8ileJdPd106Zoe5rCr9-OhQ0idgZRMk3j3-X9Lz2ogyO0tPRXuIaPDjjBaFHhOuYOyoeDeSovnPci-EsH5N0o3LoG6OKrxxn7mgJYSrr7NX15gCDuh1RmZMQ3pd1kMD_ZjJRRif9Ie7qA
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4986'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 841681dc-49ee-4218-b5f2-72597ecee97d
+ content-length:
+ - '1018'
+ expires:
+ - Wed, 06 May 2020 01:57:34 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 01:57:34 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: |-
+ OKJ000032Accounting services - Basic Company/Trust Annual Accounting Services01 May, 2020
+ https://demo.practiceignition.com/proposals/27447
+ Accounting services - Basic Company/Trust Annual Accounting Services
+
+ ---------------
+
+ 30 April, 2020
+ https://demo.practiceignition.com/proposals/27413
+ Accounting services - Basic Company/Trust Annual Accounting Services23702571Space Ranger27447Planned2019-07-01T00:00:002020-05-09T00:00:0044395039164097190Xero Setup456799100falsetrue
+ http_version: null
+ recorded_at: Wed, 06 May 2020 01:57:34 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/applytemplate/invalidjob.yml b/spec/vcr_cassettes/xpm_ruby/job/applytemplate/invalidjob.yml
new file mode 100644
index 0000000..c17b12b
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/applytemplate/invalidjob.yml
@@ -0,0 +1,63 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/job.api/applytemplate
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ none
+ 1254078
+ AddNew
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MzAwNzAsImV4cCI6MTU4ODczMTg3MCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODczMDA2MiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjA2NjA5YTA2M2IwYjRmY2Q5N2Y1NDhjOWJkZDI2Yzc0IiwianRpIjoiMjlkZGFkOGU4YzYxN2I4MmZkMjY5NDQ3MjI5ZmVjMDUiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.JrwjR8adShEJGeJi0WC5j8ADM-3q8RSdLgEDAsZr2GEedIuHCqUVF9QATqpXoL8rrRVnt14QPLXooGXY-mUiGbzgtJSj77ZYG1gbFrd2NgePavlewjiv1S4G4tAcV_L3z2ckB-3gTEEcTO0iqwAFYX5Q_nKdpAH-uHOoVPE2J19CniK_x88Eg9XSPYnBdy-xeAvqB7K3e8ileJdPd106Zoe5rCr9-OhQ0idgZRMk3j3-X9Lz2ogyO0tPRXuIaPDjjBaFHhOuYOyoeDeSovnPci-EsH5N0o3LoG6OKrxxn7mgJYSrr7NX15gCDuh1RmZMQ3pd1kMD_ZjJRRif9Ie7qA
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4985'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 9ed9daec-1c33-4da6-9202-c3be1c139357
+ content-length:
+ - '129'
+ expires:
+ - Wed, 06 May 2020 02:05:39 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 02:05:39 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: ERRORInvalid
+ job identifier
+ http_version: null
+ recorded_at: Wed, 06 May 2020 02:05:39 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/applytemplate/invalidtemplate.yml b/spec/vcr_cassettes/xpm_ruby/job/applytemplate/invalidtemplate.yml
new file mode 100644
index 0000000..ce9f925
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/applytemplate/invalidtemplate.yml
@@ -0,0 +1,63 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/job.api/applytemplate
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ J000032
+ 1000
+ AddNew
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MzAwNzAsImV4cCI6MTU4ODczMTg3MCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODczMDA2MiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjA2NjA5YTA2M2IwYjRmY2Q5N2Y1NDhjOWJkZDI2Yzc0IiwianRpIjoiMjlkZGFkOGU4YzYxN2I4MmZkMjY5NDQ3MjI5ZmVjMDUiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.JrwjR8adShEJGeJi0WC5j8ADM-3q8RSdLgEDAsZr2GEedIuHCqUVF9QATqpXoL8rrRVnt14QPLXooGXY-mUiGbzgtJSj77ZYG1gbFrd2NgePavlewjiv1S4G4tAcV_L3z2ckB-3gTEEcTO0iqwAFYX5Q_nKdpAH-uHOoVPE2J19CniK_x88Eg9XSPYnBdy-xeAvqB7K3e8ileJdPd106Zoe5rCr9-OhQ0idgZRMk3j3-X9Lz2ogyO0tPRXuIaPDjjBaFHhOuYOyoeDeSovnPci-EsH5N0o3LoG6OKrxxn7mgJYSrr7NX15gCDuh1RmZMQ3pd1kMD_ZjJRRif9Ie7qA
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9998'
+ x-daylimit-remaining:
+ - '4984'
+ x-minlimit-remaining:
+ - '58'
+ xero-correlation-id:
+ - 162a9757-cd00-4064-bb95-43ea16281313
+ content-length:
+ - '138'
+ expires:
+ - Wed, 06 May 2020 02:05:40 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 02:05:40 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: ERRORInvalid
+ job template identifier
+ http_version: null
+ recorded_at: Wed, 06 May 2020 02:05:40 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/assign.yml b/spec/vcr_cassettes/xpm_ruby/job/assign.yml
new file mode 100644
index 0000000..9996717
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/assign.yml
@@ -0,0 +1,65 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/assign
+ body:
+ encoding: UTF-8
+ string: J000032
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MjUwNzUsImV4cCI6MTU4ODcyNjg3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODcyNTA2NiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6ImJjY2UxMTczMDYzMDQyMGNiMzlhODg3ZmFmZGZjNGFkIiwianRpIjoiMTE3M2I2MDhjOGYwZDkzZTQwNmZhNjQ5ZTA2MDk1YjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.GTTldfkds492bIybQqAZgIRtGJU8AfcIMBOhkSwORAbe4qpYBXjgScsZgv_M5bkRnytimH3ERfPMYpcUAbcyW36V2FhWNEQ0gJKqSh3VkwpUOzBHfHvfk5KMcqkYTYd4XslZ19Dr1t8rCdLQ66hfHHQM6ynLmxy34oNBn9WZHk0qb4iQYtZQTHRuAiCkPH0zk2NCbepUyUxAOEfXt_319AruPorSpn_F-xt0gDSN5hRPxOE1x-ttuJIA3wIP4T0ZIyQ3ciJBvFOZY3iSCyXwfneRkv37tm7UpQJTPbj3fYXA4ufDLGG6uwb22A50Xc0bgVDiIfa08-KHYbpOGO8aFQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4996'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 6b770da1-6fc9-422e-9906-768465685b47
+ content-length:
+ - '823'
+ expires:
+ - Wed, 06 May 2020 00:33:56 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 00:33:56 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: |-
+ OKJ000032Accounting services - Basic Company/Trust Annual Accounting Services01 May, 2020
+ https://demo.practiceignition.com/proposals/27447
+ Accounting services - Basic Company/Trust Annual Accounting Services
+
+ ---------------
+
+ 30 April, 2020
+ https://demo.practiceignition.com/proposals/27413
+ Accounting services - Basic Company/Trust Annual Accounting Services23702571Space Ranger27447Planned2019-07-01T00:00:002020-05-09T00:00:0044395039859230Dev Testing
+ http_version: null
+ recorded_at: Wed, 06 May 2020 00:33:56 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/assign/invalidjob.yml b/spec/vcr_cassettes/xpm_ruby/job/assign/invalidjob.yml
new file mode 100644
index 0000000..d9dac1e
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/assign/invalidjob.yml
@@ -0,0 +1,57 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/assign
+ body:
+ encoding: UTF-8
+ string: none
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MjUwNzUsImV4cCI6MTU4ODcyNjg3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODcyNTA2NiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6ImJjY2UxMTczMDYzMDQyMGNiMzlhODg3ZmFmZGZjNGFkIiwianRpIjoiMTE3M2I2MDhjOGYwZDkzZTQwNmZhNjQ5ZTA2MDk1YjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.GTTldfkds492bIybQqAZgIRtGJU8AfcIMBOhkSwORAbe4qpYBXjgScsZgv_M5bkRnytimH3ERfPMYpcUAbcyW36V2FhWNEQ0gJKqSh3VkwpUOzBHfHvfk5KMcqkYTYd4XslZ19Dr1t8rCdLQ66hfHHQM6ynLmxy34oNBn9WZHk0qb4iQYtZQTHRuAiCkPH0zk2NCbepUyUxAOEfXt_319AruPorSpn_F-xt0gDSN5hRPxOE1x-ttuJIA3wIP4T0ZIyQ3ciJBvFOZY3iSCyXwfneRkv37tm7UpQJTPbj3fYXA4ufDLGG6uwb22A50Xc0bgVDiIfa08-KHYbpOGO8aFQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9998'
+ x-daylimit-remaining:
+ - '4995'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 856e3402-bea8-41ec-a68e-1488a6ea6566
+ content-length:
+ - '122'
+ expires:
+ - Wed, 06 May 2020 00:33:59 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 00:33:59 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: ERRORInvalid
+ job identifier
+ http_version: null
+ recorded_at: Wed, 06 May 2020 00:33:59 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/assign/invalidstaff.yml b/spec/vcr_cassettes/xpm_ruby/job/assign/invalidstaff.yml
new file mode 100644
index 0000000..df77e0e
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/assign/invalidstaff.yml
@@ -0,0 +1,57 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/assign
+ body:
+ encoding: UTF-8
+ string: J000032
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MjUwNzUsImV4cCI6MTU4ODcyNjg3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODcyNTA2NiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6ImJjY2UxMTczMDYzMDQyMGNiMzlhODg3ZmFmZGZjNGFkIiwianRpIjoiMTE3M2I2MDhjOGYwZDkzZTQwNmZhNjQ5ZTA2MDk1YjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.GTTldfkds492bIybQqAZgIRtGJU8AfcIMBOhkSwORAbe4qpYBXjgScsZgv_M5bkRnytimH3ERfPMYpcUAbcyW36V2FhWNEQ0gJKqSh3VkwpUOzBHfHvfk5KMcqkYTYd4XslZ19Dr1t8rCdLQ66hfHHQM6ynLmxy34oNBn9WZHk0qb4iQYtZQTHRuAiCkPH0zk2NCbepUyUxAOEfXt_319AruPorSpn_F-xt0gDSN5hRPxOE1x-ttuJIA3wIP4T0ZIyQ3ciJBvFOZY3iSCyXwfneRkv37tm7UpQJTPbj3fYXA4ufDLGG6uwb22A50Xc0bgVDiIfa08-KHYbpOGO8aFQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9997'
+ x-daylimit-remaining:
+ - '4994'
+ x-minlimit-remaining:
+ - '58'
+ xero-correlation-id:
+ - 2e113e20-5620-4d1e-86ce-90873783fd20
+ content-length:
+ - '140'
+ expires:
+ - Wed, 06 May 2020 00:33:59 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 00:33:59 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: ERRORInvalid
+ staff identifier for add request
+ http_version: null
+ recorded_at: Wed, 06 May 2020 00:33:59 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/assign/manager.yml b/spec/vcr_cassettes/xpm_ruby/job/assign/manager.yml
new file mode 100644
index 0000000..042294d
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/assign/manager.yml
@@ -0,0 +1,65 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/assign
+ body:
+ encoding: UTF-8
+ string: J000032
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MjUwNzUsImV4cCI6MTU4ODcyNjg3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODcyNTA2NiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6ImJjY2UxMTczMDYzMDQyMGNiMzlhODg3ZmFmZGZjNGFkIiwianRpIjoiMTE3M2I2MDhjOGYwZDkzZTQwNmZhNjQ5ZTA2MDk1YjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.GTTldfkds492bIybQqAZgIRtGJU8AfcIMBOhkSwORAbe4qpYBXjgScsZgv_M5bkRnytimH3ERfPMYpcUAbcyW36V2FhWNEQ0gJKqSh3VkwpUOzBHfHvfk5KMcqkYTYd4XslZ19Dr1t8rCdLQ66hfHHQM6ynLmxy34oNBn9WZHk0qb4iQYtZQTHRuAiCkPH0zk2NCbepUyUxAOEfXt_319AruPorSpn_F-xt0gDSN5hRPxOE1x-ttuJIA3wIP4T0ZIyQ3ciJBvFOZY3iSCyXwfneRkv37tm7UpQJTPbj3fYXA4ufDLGG6uwb22A50Xc0bgVDiIfa08-KHYbpOGO8aFQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4992'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 95f7adde-2ca9-42a6-9357-8365bffdd0a3
+ content-length:
+ - '818'
+ expires:
+ - Wed, 06 May 2020 00:43:35 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 00:43:35 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: |-
+ OKJ000032Accounting services - Basic Company/Trust Annual Accounting Services01 May, 2020
+ https://demo.practiceignition.com/proposals/27447
+ Accounting services - Basic Company/Trust Annual Accounting Services
+
+ ---------------
+
+ 30 April, 2020
+ https://demo.practiceignition.com/proposals/27413
+ Accounting services - Basic Company/Trust Annual Accounting Services23702571Space Ranger27447Planned2019-07-01T00:00:002020-05-09T00:00:0044395039859230Dev Testing
+ http_version: null
+ recorded_at: Wed, 06 May 2020 00:43:35 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/assign/partner.yml b/spec/vcr_cassettes/xpm_ruby/job/assign/partner.yml
new file mode 100644
index 0000000..760ed6b
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/assign/partner.yml
@@ -0,0 +1,65 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/assign
+ body:
+ encoding: UTF-8
+ string: J000032
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MjUwNzUsImV4cCI6MTU4ODcyNjg3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODcyNTA2NiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6ImJjY2UxMTczMDYzMDQyMGNiMzlhODg3ZmFmZGZjNGFkIiwianRpIjoiMTE3M2I2MDhjOGYwZDkzZTQwNmZhNjQ5ZTA2MDk1YjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.GTTldfkds492bIybQqAZgIRtGJU8AfcIMBOhkSwORAbe4qpYBXjgScsZgv_M5bkRnytimH3ERfPMYpcUAbcyW36V2FhWNEQ0gJKqSh3VkwpUOzBHfHvfk5KMcqkYTYd4XslZ19Dr1t8rCdLQ66hfHHQM6ynLmxy34oNBn9WZHk0qb4iQYtZQTHRuAiCkPH0zk2NCbepUyUxAOEfXt_319AruPorSpn_F-xt0gDSN5hRPxOE1x-ttuJIA3wIP4T0ZIyQ3ciJBvFOZY3iSCyXwfneRkv37tm7UpQJTPbj3fYXA4ufDLGG6uwb22A50Xc0bgVDiIfa08-KHYbpOGO8aFQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9997'
+ x-daylimit-remaining:
+ - '4990'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 74fa5e80-2e94-47dd-9854-970bb68a4e3f
+ content-length:
+ - '818'
+ expires:
+ - Wed, 06 May 2020 00:44:19 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 00:44:19 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: |-
+ OKJ000032Accounting services - Basic Company/Trust Annual Accounting Services01 May, 2020
+ https://demo.practiceignition.com/proposals/27447
+ Accounting services - Basic Company/Trust Annual Accounting Services
+
+ ---------------
+
+ 30 April, 2020
+ https://demo.practiceignition.com/proposals/27413
+ Accounting services - Basic Company/Trust Annual Accounting Services23702571Space Ranger27447Planned2019-07-01T00:00:002020-05-09T00:00:0044395039859230Dev Testing
+ http_version: null
+ recorded_at: Wed, 06 May 2020 00:44:19 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/assign/remove.yml b/spec/vcr_cassettes/xpm_ruby/job/assign/remove.yml
new file mode 100644
index 0000000..273c3d1
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/assign/remove.yml
@@ -0,0 +1,65 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/assign
+ body:
+ encoding: UTF-8
+ string: J000032
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MjUwNzUsImV4cCI6MTU4ODcyNjg3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODcyNTA2NiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6ImJjY2UxMTczMDYzMDQyMGNiMzlhODg3ZmFmZGZjNGFkIiwianRpIjoiMTE3M2I2MDhjOGYwZDkzZTQwNmZhNjQ5ZTA2MDk1YjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.GTTldfkds492bIybQqAZgIRtGJU8AfcIMBOhkSwORAbe4qpYBXjgScsZgv_M5bkRnytimH3ERfPMYpcUAbcyW36V2FhWNEQ0gJKqSh3VkwpUOzBHfHvfk5KMcqkYTYd4XslZ19Dr1t8rCdLQ66hfHHQM6ynLmxy34oNBn9WZHk0qb4iQYtZQTHRuAiCkPH0zk2NCbepUyUxAOEfXt_319AruPorSpn_F-xt0gDSN5hRPxOE1x-ttuJIA3wIP4T0ZIyQ3ciJBvFOZY3iSCyXwfneRkv37tm7UpQJTPbj3fYXA4ufDLGG6uwb22A50Xc0bgVDiIfa08-KHYbpOGO8aFQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4993'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 52f6f9f2-e66e-4402-a85f-01b73e154982
+ content-length:
+ - '760'
+ expires:
+ - Wed, 06 May 2020 00:40:10 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 00:40:10 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: |-
+ OKJ000032Accounting services - Basic Company/Trust Annual Accounting Services01 May, 2020
+ https://demo.practiceignition.com/proposals/27447
+ Accounting services - Basic Company/Trust Annual Accounting Services
+
+ ---------------
+
+ 30 April, 2020
+ https://demo.practiceignition.com/proposals/27413
+ Accounting services - Basic Company/Trust Annual Accounting Services23702571Space Ranger27447Planned2019-07-01T00:00:002020-05-09T00:00:0044395039
+ http_version: null
+ recorded_at: Wed, 06 May 2020 00:40:10 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/assign/removemanager.yml b/spec/vcr_cassettes/xpm_ruby/job/assign/removemanager.yml
new file mode 100644
index 0000000..8013883
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/assign/removemanager.yml
@@ -0,0 +1,65 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/assign
+ body:
+ encoding: UTF-8
+ string: "J000032 "
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MjUwNzUsImV4cCI6MTU4ODcyNjg3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODcyNTA2NiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6ImJjY2UxMTczMDYzMDQyMGNiMzlhODg3ZmFmZGZjNGFkIiwianRpIjoiMTE3M2I2MDhjOGYwZDkzZTQwNmZhNjQ5ZTA2MDk1YjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.GTTldfkds492bIybQqAZgIRtGJU8AfcIMBOhkSwORAbe4qpYBXjgScsZgv_M5bkRnytimH3ERfPMYpcUAbcyW36V2FhWNEQ0gJKqSh3VkwpUOzBHfHvfk5KMcqkYTYd4XslZ19Dr1t8rCdLQ66hfHHQM6ynLmxy34oNBn9WZHk0qb4iQYtZQTHRuAiCkPH0zk2NCbepUyUxAOEfXt_319AruPorSpn_F-xt0gDSN5hRPxOE1x-ttuJIA3wIP4T0ZIyQ3ciJBvFOZY3iSCyXwfneRkv37tm7UpQJTPbj3fYXA4ufDLGG6uwb22A50Xc0bgVDiIfa08-KHYbpOGO8aFQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9998'
+ x-daylimit-remaining:
+ - '4991'
+ x-minlimit-remaining:
+ - '58'
+ xero-correlation-id:
+ - 27f83627-13a3-4e18-bb63-44a45f930582
+ content-length:
+ - '760'
+ expires:
+ - Wed, 06 May 2020 00:43:38 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 00:43:38 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: |-
+ OKJ000032Accounting services - Basic Company/Trust Annual Accounting Services01 May, 2020
+ https://demo.practiceignition.com/proposals/27447
+ Accounting services - Basic Company/Trust Annual Accounting Services
+
+ ---------------
+
+ 30 April, 2020
+ https://demo.practiceignition.com/proposals/27413
+ Accounting services - Basic Company/Trust Annual Accounting Services23702571Space Ranger27447Planned2019-07-01T00:00:002020-05-09T00:00:0044395039
+ http_version: null
+ recorded_at: Wed, 06 May 2020 00:43:38 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/assign/removepartner.yml b/spec/vcr_cassettes/xpm_ruby/job/assign/removepartner.yml
new file mode 100644
index 0000000..88869a9
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/assign/removepartner.yml
@@ -0,0 +1,65 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/assign
+ body:
+ encoding: UTF-8
+ string: "J000032 "
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg3MjUwNzUsImV4cCI6MTU4ODcyNjg3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODcyNTA2NiwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6ImJjY2UxMTczMDYzMDQyMGNiMzlhODg3ZmFmZGZjNGFkIiwianRpIjoiMTE3M2I2MDhjOGYwZDkzZTQwNmZhNjQ5ZTA2MDk1YjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.GTTldfkds492bIybQqAZgIRtGJU8AfcIMBOhkSwORAbe4qpYBXjgScsZgv_M5bkRnytimH3ERfPMYpcUAbcyW36V2FhWNEQ0gJKqSh3VkwpUOzBHfHvfk5KMcqkYTYd4XslZ19Dr1t8rCdLQ66hfHHQM6ynLmxy34oNBn9WZHk0qb4iQYtZQTHRuAiCkPH0zk2NCbepUyUxAOEfXt_319AruPorSpn_F-xt0gDSN5hRPxOE1x-ttuJIA3wIP4T0ZIyQ3ciJBvFOZY3iSCyXwfneRkv37tm7UpQJTPbj3fYXA4ufDLGG6uwb22A50Xc0bgVDiIfa08-KHYbpOGO8aFQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9996'
+ x-daylimit-remaining:
+ - '4989'
+ x-minlimit-remaining:
+ - '58'
+ xero-correlation-id:
+ - ba9e8317-98a6-4b25-bc4a-9e3ee2140489
+ content-length:
+ - '760'
+ expires:
+ - Wed, 06 May 2020 00:44:21 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Wed, 06 May 2020 00:44:21 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: |-
+ OKJ000032Accounting services - Basic Company/Trust Annual Accounting Services01 May, 2020
+ https://demo.practiceignition.com/proposals/27447
+ Accounting services - Basic Company/Trust Annual Accounting Services
+
+ ---------------
+
+ 30 April, 2020
+ https://demo.practiceignition.com/proposals/27413
+ Accounting services - Basic Company/Trust Annual Accounting Services23702571Space Ranger27447Planned2019-07-01T00:00:002020-05-09T00:00:0044395039
+ http_version: null
+ recorded_at: Wed, 06 May 2020 00:44:21 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/current.yml b/spec/vcr_cassettes/xpm_ruby/job/current.yml
new file mode 100644
index 0000000..fcfed12
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/current.yml
@@ -0,0 +1,103 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/job.api/current
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODgxMTUyMTQsImV4cCI6MTU4ODExNzAxNCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODA1MTE0MywieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjQzMGI0ZmVmMWI0NjQ2MGZiMTgwOWNmNmQ5OWJhODIxIiwianRpIjoiMmI3NGQxZDZhMzcxNDlhN2VjNjkwNmM2NGM0MDFlMjEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.EJ5_dU4efS9e2w68A63GQaVWghmcIONEOfkB4Wp0IGNwTbNU441x3vSAMdRY5MShT1jk9cTR-207OKClFJAuwWZbODQcs2bV9YDj5PH9cCtNCULFOClQCn7zfUonkMdZ9FiL4RjJ6xXbWOmfD-vYhQRLbAkKDcZad8HcPIzPyKvyHFuxTDk7FKs-OI3sUPQUqQrBKAcmD2C8PR8al7PNn0kwrug1a2_R0z74Sygg1iKJlShMLMBbaDfq_7zxbMvGrLvW1vLMlJDhxD-sR4_T-B3n6_VDFybFfShQqtkoJwk4-fAqc0S8N0Vmx_kRLqzVEIE8NiouqnTvt6i8Bvc5PQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-daylimit-remaining:
+ - '4995'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - b6f1355d-d2c2-4a7d-86bd-792ebfa6c10f
+ content-length:
+ - '13749'
+ expires:
+ - Tue, 28 Apr 2020 23:39:29 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 28 Apr 2020 23:39:29 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: |-
+ OKJ000014(Sample) Bookkeeping Monthly - Basic28 November, 2019
+ https://demo.practiceignition.com/proposals/23531
+ (Sample) Bookkeeping Monthly - Basic
+
+ ---------------
+
+ 28 November, 2019
+ https://demo.practiceignition.com/proposals/23530
+ (Sample) Bookkeeping Monthly - Basic24097642ABC Co23531Planned2019-11-01T00:00:002019-11-07T00:00:0040615371859317Ed Minn859317Ed MinnJ000013(Sample) Bookkeeping Monthly - Basic28 November, 2019
+ https://demo.practiceignition.com/proposals/23530
+ (Sample) Bookkeeping Monthly - Basic24097642ABC Co23531Planned2019-11-08T00:00:002019-11-14T00:00:0040615370859317Ed Minn859317Ed MinnJ000016(Sample) Bookkeeping Monthly - Basic28 November, 2019
+ https://demo.practiceignition.com/proposals/23530
+ (Sample) Bookkeeping Monthly - Basic24097642ABC Co23531Planned2019-11-15T00:00:002019-11-21T00:00:0040615382859317Ed Minn859317Ed MinnJ000015(Sample) Bookkeeping Monthly - Basic28 November, 2019
+ https://demo.practiceignition.com/proposals/23530
+ (Sample) Bookkeeping Monthly - Basic24097642ABC Co23531Planned2019-11-22T00:00:002019-11-28T00:00:0040615373859317Ed Minn859317Ed MinnJ000012(Sample) Client Review Quarterly27 November, 2019
+ https://demo.practiceignition.com/proposals/23499
+ (Sample) Client Review Quarterly
+
+ ---------------
+
+ 27 November, 2019
+ https://demo.practiceignition.com/proposals/23498
+ (Sample) Client Review Quarterly24097642ABC Co23499Planned2020-01-01T00:00:002020-01-07T00:00:0040590048859317Ed Minn859317Ed MinnJ000022Brochure DesignDetailed description of the job24097642ABC CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044305753J000023Brochure DesignDetailed description of the job24097642ABC CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044306866J000024Brochure DesignDetailed description of the job24097642ABC CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044309157J000025Brochure DesignDetailed description of the job24097642ABC CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044309165J000026Brochure DesignDetailed description of the job24097642ABC CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044310517J000027Brochure DesignDetailed description of the job24097642ABC CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044310566J000028Brochure DesignDetailed description of the job24097642ABC CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044313368J000029Brochure DesignDetailed description of the job24097642ABC CoPlanned2029-10-23T00:00:002029-10-28T00:00:0044346180J000003(Sample) Annual Accounts and Tax Return15 October, 2019
+ https://pi-review-pr-10033.herokuapp.com/proposals/1
+ (Sample) Annual Accounts and Tax Return23526538Client 61Planned2020-01-01T00:00:002020-12-31T00:00:0039501788J000004(Sample) Addon << integration_name >>, Setup and Training07 November, 2019
+ http://localhost:3000/proposals/4
+ (Sample) Addon << integration_name >>, Setup and Training23864530Ian Example Client4Planned2019-07-01T00:00:002020-06-30T00:00:0040150666J000005(Sample) Addon << integration_name >>, Setup and Training11 November, 2019
+ http://localhost:3000/proposals/6
+ (Sample) Addon << integration_name >>, Setup and Training23864530Ian Example Client6Planned2019-07-01T00:00:002020-06-30T00:00:0040229141J000006(Sample) Addon << integration_name >>, Setup and Training11 November, 2019
+ http://localhost:3000/proposals/7
+ (Sample) Addon << integration_name >>, Setup and Training23864530Ian Example Client7Planned2019-07-01T00:00:002020-06-30T00:00:0040232745J000007(Sample) Annual Accounts and Tax Return11 November, 2019
+ http://localhost:3000/proposals/8
+ (Sample) Annual Accounts and Tax Return23864530Ian Example Client8Planned2019-07-01T00:00:002020-06-30T00:00:0040233555J000008(Sample) Addon << integration_name >>, Setup and Training11 November, 2019
+ http://localhost:3000/proposals/9
+ (Sample) Addon << integration_name >>, Setup and Training23864530Ian Example Client9Planned2019-07-01T00:00:002020-06-30T00:00:0040233593J000009(Sample) Bookkeeping Monthly - Basic12 November, 2019
+ http://localhost:3000/proposals/10
+ (Sample) Bookkeeping Monthly - Basic23864530Ian Example Client10Planned2019-07-01T00:00:002020-06-30T00:00:0040306029J000010(Sample) Ledger Conversion, Setup and Training - (Sample) Client Review Quarterly12 November, 2019
+ http://localhost:3000/proposals/11
+ (Sample) Ledger Conversion, Setup and Training - (Sample) Client Review Quarterly23864530Ian Example Client11Planned2019-07-01T00:00:002020-06-30T00:00:0040306035J000011(Sample) Annual Accounts and Tax Return14 November, 2019
+ http://localhost:3000/proposals/13
+ (Sample) Annual Accounts and Tax Return23864530Ian Example Client13Planned2019-07-01T00:00:002020-06-30T00:00:0040317608J000017(Sample) Addon << integration_name >>, Setup and Training07 January, 2020
+ http://localhost:3000/proposals/191
+ (Sample) Addon << integration_name >>, Setup and Training23864530Ian Example Client191Planned2019-07-01T00:00:002020-06-30T00:00:0041443427J000001Internal TimeUse this job to record your internal and non-billable time for activities such as annual leave, sick leave, professional development, staff meetings etc23403717Practice Ignition - XPM Product & Development Testing AccountPlanned2019-09-30T00:00:002020-09-30T00:00:0039186188858948Patrick FrigoJ000002Setup and Conversion Steps23403717Practice Ignition - XPM Product & Development Testing AccountPlanned2019-10-01T00:00:002019-10-15T00:00:0039186189858948Patrick FrigoJ000018(Sample) Addon << integration_name >>, Setup and Training20 January, 2020
+ http://localhost:3000/proposals/194
+ (Sample) Addon << integration_name >>, Setup and Training23702571Space Ranger194Planned2019-07-01T00:00:002020-06-30T00:00:0041684984J000019(Sample) Addon << integration_name >>, Setup and Training20 January, 2020
+ http://localhost:3000/proposals/193
+ (Sample) Addon << integration_name >>, Setup and Training23702571Space Ranger193Planned2019-07-01T00:00:002020-06-30T00:00:0041695592J000020(Sample) Annual Accounts and Tax Return14 February, 2020
+ http://localhost:3000/proposals/189
+ (Sample) Annual Accounts and Tax Return23702571Space Ranger189Planned2019-07-01T00:00:002020-06-30T00:00:0042339558J000021service 124 March, 2020
+ http://localhost:3000/proposals/17
+ service 123702571Space Ranger17Planned2019-07-01T00:00:002020-06-30T00:00:0043375546
+ http_version: null
+ recorded_at: Tue, 28 Apr 2020 23:39:29 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/delete.yml b/spec/vcr_cassettes/xpm_ruby/job/delete.yml
new file mode 100644
index 0000000..346d9b5
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/delete.yml
@@ -0,0 +1,60 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/job.api/delete
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ J000031
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg2NTc4MDIsImV4cCI6MTU4ODY1OTYwMiwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODY1Nzc5MywieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjQxY2U2ODQwYjA1MDRjOWJhNTJlMjZkMmZkZmExMmZhIiwianRpIjoiN2IzYzk1NDc0NDRmNDU3ZDVhNDRiYjEyOGI1M2NiNmYiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.jaYj-iBvzvS0WZXmTOsWPc_KJe0M3Xfrpbvfbn_fb925hwknvv31uup2NCVZWIh8MTBCFmVGu2c2KTqKXjnaEvoReRfRIhNpsqK-dReysgL3KTMrBKouS8a8VjMrOMxso0Q-xp3v6M0CfAf6C4WUiBWkVrMnNd-20aaY9Wv_4vkpa5r4muerm8FZyxHFD6-pOgiZRiEI2OgOT1wceI-ONLI5NhyFtv3eoCCr5ubFRlX5odOT8R-xI2jkePUaBPoGMitKdwZaDkVWEnweUdd7SO-OzD5ErcqARnjCBH3gQFNBKhLQh5XsalugQ9embc2wuOKO9UMj70gkz4oVQbCmcQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4984'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 96cc210d-f392-4448-befb-5f1c792ed82b
+ content-length:
+ - '60'
+ expires:
+ - Tue, 05 May 2020 05:50:50 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 05:50:50 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK
+ http_version: null
+ recorded_at: Tue, 05 May 2020 05:50:50 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/delete/error.yml b/spec/vcr_cassettes/xpm_ruby/job/delete/error.yml
new file mode 100644
index 0000000..71beaf6
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/delete/error.yml
@@ -0,0 +1,61 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/job.api/delete
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ none
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg2NTc4MDIsImV4cCI6MTU4ODY1OTYwMiwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODY1Nzc5MywieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjQxY2U2ODQwYjA1MDRjOWJhNTJlMjZkMmZkZmExMmZhIiwianRpIjoiN2IzYzk1NDc0NDRmNDU3ZDVhNDRiYjEyOGI1M2NiNmYiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.jaYj-iBvzvS0WZXmTOsWPc_KJe0M3Xfrpbvfbn_fb925hwknvv31uup2NCVZWIh8MTBCFmVGu2c2KTqKXjnaEvoReRfRIhNpsqK-dReysgL3KTMrBKouS8a8VjMrOMxso0Q-xp3v6M0CfAf6C4WUiBWkVrMnNd-20aaY9Wv_4vkpa5r4muerm8FZyxHFD6-pOgiZRiEI2OgOT1wceI-ONLI5NhyFtv3eoCCr5ubFRlX5odOT8R-xI2jkePUaBPoGMitKdwZaDkVWEnweUdd7SO-OzD5ErcqARnjCBH3gQFNBKhLQh5XsalugQ9embc2wuOKO9UMj70gkz4oVQbCmcQ
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9998'
+ x-daylimit-remaining:
+ - '4983'
+ x-minlimit-remaining:
+ - '58'
+ xero-correlation-id:
+ - bf5cbbdb-5f18-448c-b9a9-a23a0e8417f2
+ content-length:
+ - '122'
+ expires:
+ - Tue, 05 May 2020 05:50:51 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 05:50:51 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: ERRORInvalid
+ job identifier
+ http_version: null
+ recorded_at: Tue, 05 May 2020 05:50:51 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/get.yml b/spec/vcr_cassettes/xpm_ruby/job/get.yml
new file mode 100644
index 0000000..8361afc
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/get.yml
@@ -0,0 +1,63 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/job.api/get/J000014
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg2MzQ0MTUsImV4cCI6MTU4ODYzNjIxNSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODYzNDQwNSwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjZkNjc2ZGM5ZDFjZDRlMmU5YTExMjEyMTI1ZjYzMzg2IiwianRpIjoiMzk5MGMyZGRjNzQzNTIyZjA3ZjRkNWIwODA2NzA1YWEiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.DKgxE5ynBtFTFvVPUWD8PDMIHmmh5V722gDGkHxN19BZ6WQcuPLoDI-MMma449gCvZ5D8Q95YtyVDqmjOtRni_PzOjMUQ7hNe05dp_YCKMiAwbDKlBC0O0sDNULawxXtqAVrcDuRG7MJ6I4Oru8qFl-KIyYTGRjuHsVezUjJo8tadlUMWr6Vy8Lkjq3lqBPWmraJtgAB81J2omWe4Ipeku7r2-7Gfvabp54WA9iwEvm-FQhNqi9QjOpRgv1eMFlit9qJQZckCEQoIn5fysVlyCm969MfjSLGCoQEiZrx68lv73AHbQhAPhY1PZD8v3ZaoOePu1nR2SeLh5GMGItWlA
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4999'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 7baa6c6a-9b30-4390-acac-8f4c1169c978
+ content-length:
+ - '776'
+ expires:
+ - Mon, 04 May 2020 23:21:25 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Mon, 04 May 2020 23:21:25 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: |-
+ OKJ000014(Sample) Bookkeeping Monthly - Basic28 November, 2019
+ https://demo.practiceignition.com/proposals/23531
+ (Sample) Bookkeeping Monthly - Basic
+
+ ---------------
+
+ 28 November, 2019
+ https://demo.practiceignition.com/proposals/23530
+ (Sample) Bookkeeping Monthly - Basic24097642ABC Co23531Planned2019-11-01T00:00:002019-11-07T00:00:0040615371859317Ed Minn859317Ed Minn
+ http_version: null
+ recorded_at: Mon, 04 May 2020 23:21:25 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/state/fail.yml b/spec/vcr_cassettes/xpm_ruby/job/state/fail.yml
new file mode 100644
index 0000000..869affb
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/state/fail.yml
@@ -0,0 +1,62 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/state
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ J000031
+ NONEXISTENT
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg2NDczMjIsImV4cCI6MTU4ODY0OTEyMiwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODY0NzMxNCwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjJjODE3OTIzZWI3NTQ5Nzk4ODZkNmQyNzNlMDIxOWY4IiwianRpIjoiNjBhZjYyMDJmOGFlZmYzOGUyODgxZmE3MWUyYTEzODciLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.ihigSPTTvjVFeOya1Pv5abPXgpNufswAXnDRm0tWvJYEejkJjG3V0TK2EkPE3L14zI0IfN_hPmT8rWBxKZo9yf_0p2apLIRFWzR4PCqJBMhrvT4ZMvwqb2jyeezODK68scAxImT2si3hU7C6hFOWxUEp6SlkWOxrIO-upNsV6NZrE7HCeAYzLz-mA8490Dkctwxp2OZNke1BW5OT9kqj7dBhWZRjesVOcpr5WgCTSVUnhgWzpV7R35NQl4TQoFxAAT_siAD8AWQCpcuebsLrFhvmxH6sX-Vwt8Gyc_90nxq_o0tmed6Gtv_HOd0lJRD3_251yZfGG14PWIFbpsEIHw
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9998'
+ x-daylimit-remaining:
+ - '4993'
+ x-minlimit-remaining:
+ - '58'
+ xero-correlation-id:
+ - efb60254-fc34-468c-9912-29deaacd6082
+ content-length:
+ - '117'
+ expires:
+ - Tue, 05 May 2020 02:56:10 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 02:56:10 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: ERRORInvalid
+ state code
+ http_version: null
+ recorded_at: Tue, 05 May 2020 02:56:10 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/state/success.yml b/spec/vcr_cassettes/xpm_ruby/job/state/success.yml
new file mode 100644
index 0000000..e311e8e
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/state/success.yml
@@ -0,0 +1,61 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/state
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ J000031
+ COMPLETED
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg2NDczMjIsImV4cCI6MTU4ODY0OTEyMiwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODY0NzMxNCwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjJjODE3OTIzZWI3NTQ5Nzk4ODZkNmQyNzNlMDIxOWY4IiwianRpIjoiNjBhZjYyMDJmOGFlZmYzOGUyODgxZmE3MWUyYTEzODciLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.ihigSPTTvjVFeOya1Pv5abPXgpNufswAXnDRm0tWvJYEejkJjG3V0TK2EkPE3L14zI0IfN_hPmT8rWBxKZo9yf_0p2apLIRFWzR4PCqJBMhrvT4ZMvwqb2jyeezODK68scAxImT2si3hU7C6hFOWxUEp6SlkWOxrIO-upNsV6NZrE7HCeAYzLz-mA8490Dkctwxp2OZNke1BW5OT9kqj7dBhWZRjesVOcpr5WgCTSVUnhgWzpV7R35NQl4TQoFxAAT_siAD8AWQCpcuebsLrFhvmxH6sX-Vwt8Gyc_90nxq_o0tmed6Gtv_HOd0lJRD3_251yZfGG14PWIFbpsEIHw
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4994'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 4325b67d-6986-4376-8870-89d68c2512cc
+ content-length:
+ - '59'
+ expires:
+ - Tue, 05 May 2020 02:56:08 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 05 May 2020 02:56:08 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK
+ http_version: null
+ recorded_at: Tue, 05 May 2020 02:56:08 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/job/update.yml b/spec/vcr_cassettes/xpm_ruby/job/update.yml
new file mode 100644
index 0000000..b25d9f7
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/job/update.yml
@@ -0,0 +1,68 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/job.api/update
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ J000031
+ Joe Bloggs
+ Update Job
+ 24097642
+ 20091023
+ 20091023
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODg1NTIxMjcsImV4cCI6MTU4ODU1MzkyNywiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODU1MjExNywieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjUwYmRlMGYzNTAyMDQ2OWFhYzQ0OTBiYTBlMWMzZDRjIiwianRpIjoiNzhmMDNjMmM1MTIwMGM3Nzg5MTY0NTFlNmFiZjkyZTkiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.FaNHL4LxF1cCsF6-oJ9Ilt4C734rlB5q6Pf66N1NdNCXfllmoWsmiTsA6m0E63U9HVoHhop_hqgA0KnmckxaA4m4gQn3YRtHUktWr_3Zb1-whWhYdAvcSZA3AhOqyIXX2Y9XzrNG61_eRuSY9hdNAfG70X3H72txXDCMGFdz63aycRhNmYAin90dRMr_-cmv51nzDGyihcAc8R3TRn-G9tmTk4YL1EpYKXKh1H4omHq-GpkJQTZ3ndO8wEfl_Me7k-axWKUvmeC6CTy7Pc7MJqUne44TDWvyUWbW7QTlWnF6KgLpXiReHZ3lv6-QG1aETtISHfWu07IW_7PZxd2vaA
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-appminlimit-remaining:
+ - '9999'
+ x-daylimit-remaining:
+ - '4997'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - 00a8e2db-b530-42d6-9f88-22f4d6474f0c
+ content-length:
+ - '418'
+ expires:
+ - Mon, 04 May 2020 00:34:21 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Mon, 04 May 2020 00:34:21 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OKJ000031Joe
+ BloggsUpdate Job24097642ABC
+ CoPlanned2009-10-23T00:00:002009-10-23T00:00:0044385850
+ http_version: null
+ recorded_at: Mon, 04 May 2020 00:34:21 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/staff/add.yml b/spec/vcr_cassettes/xpm_ruby/staff/add.yml
new file mode 100644
index 0000000..008254e
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/staff/add.yml
@@ -0,0 +1,66 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/add
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ Joe Bloggs
+ In your head
+ 123456789
+ joebloggs@foo.com
+ PC123
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer access_token
+ xero-tenant-id:
+ - 'xero_tenant_id'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ content-length:
+ - '247'
+ server:
+ - nginx
+ xero-correlation-id:
+ - e39c3c94-4f4f-41d3-aa85-7b13924b56d9
+ x-appminlimit-remaining:
+ - '9999'
+ x-minlimit-remaining:
+ - '59'
+ x-daylimit-remaining:
+ - '4942'
+ expires:
+ - Fri, 16 Apr 2021 11:09:13 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Fri, 16 Apr 2021 11:09:13 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK1044994Joe
+ Bloggsjoebloggs@foo.com123456789In
+ your headPC123
+ http_version: null
+ recorded_at: Fri, 16 Apr 2021 11:09:13 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/staff/delete.yml b/spec/vcr_cassettes/xpm_ruby/staff/delete.yml
new file mode 100644
index 0000000..55dd403
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/staff/delete.yml
@@ -0,0 +1,60 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/delete
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ 859318
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer access_token
+ xero-tenant-id:
+ - 'xero_tenant_id'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ content-length:
+ - '60'
+ server:
+ - nginx
+ xero-correlation-id:
+ - b3cdf1e3-7491-4665-9aa7-a9509ab2211d
+ x-appminlimit-remaining:
+ - '9999'
+ x-minlimit-remaining:
+ - '59'
+ x-daylimit-remaining:
+ - '4944'
+ expires:
+ - Fri, 16 Apr 2021 11:05:55 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Fri, 16 Apr 2021 11:05:55 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK
+ http_version: null
+ recorded_at: Fri, 16 Apr 2021 11:05:55 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_accepted.yml b/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_accepted.yml
new file mode 100644
index 0000000..521b4ea
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_accepted.yml
@@ -0,0 +1,60 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer a_dummy_secret_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-daylimit-remaining:
+ - '4994'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - e4487879-7b32-4ecf-b340-4483c145be02
+ content-length:
+ - '1794'
+ expires:
+ - Tue, 28 Apr 2020 23:48:01 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 28 Apr 2020 23:48:01 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK859230Dev
+ Testingdev@practiceignition.com859317Ed
+ Minnluis+edminn@practiceignition.com858949Jana
+ Paulechjana@practiceignition.com859231Nick
+ Daintynick@practiceignition.com863967Nick
+ Daintynick+xpmtest2@practiceignition.com858948Patrick
+ Frigopatrick.frigo@xero.com859319Patty
+ Igneousluis@practiceignition.com859318Some
+ Usersome_user@pattyrocks.com863927Testchris@practiceignition.com866437testadammikulas@gmail.com
+ http_version: null
+ recorded_at: Tue, 28 Apr 2020 23:48:01 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_accepted_one_staff.yml b/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_accepted_one_staff.yml
new file mode 100644
index 0000000..f707081
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_accepted_one_staff.yml
@@ -0,0 +1,52 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer a_dummy_secret_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-daylimit-remaining:
+ - '4994'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - e4487879-7b32-4ecf-b340-4483c145be02
+ content-length:
+ - '1794'
+ expires:
+ - Tue, 28 Apr 2020 23:48:01 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 28 Apr 2020 23:48:01 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK859230Adam Silverdev@practiceignition.com
+ http_version: null
+ recorded_at: Tue, 28 Apr 2020 23:48:01 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_expired.yml b/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_expired.yml
new file mode 100644
index 0000000..37cfbcc
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_expired.yml
@@ -0,0 +1,49 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 401
+ message: Unauthorized
+ headers:
+ server:
+ - Kestrel
+ www-authenticate:
+ - Bearer error=invalid_token
+ xero-correlation-id:
+ - 0d6a2ea2-3224-49c5-8995-964997f867af
+ content-length:
+ - '177'
+ expires:
+ - Thu, 30 Apr 2020 00:30:50 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Thu, 30 Apr 2020 00:30:50 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Unauthorized","Status":401,"Detail":"TokenExpired:
+ token expired at 04/29/2020 09:22:02","Instance":"0d6a2ea2-3224-49c5-8995-964997f867af","Extensions":{}}'
+ http_version: null
+ recorded_at: Thu, 30 Apr 2020 00:30:50 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_unauthorized.yml b/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_unauthorized.yml
new file mode 100644
index 0000000..807fc70
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/staff/list/access_token_unauthorized.yml
@@ -0,0 +1,48 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer invalid
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 401
+ message: Unauthorized
+ headers:
+ server:
+ - Kestrel
+ www-authenticate:
+ - Bearer error=invalid_token
+ xero-correlation-id:
+ - 61f11bc2-48ef-483e-9be3-40cc3e38af98
+ content-length:
+ - '153'
+ expires:
+ - Thu, 30 Apr 2020 00:54:44 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Thu, 30 Apr 2020 00:54:44 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: '{"Type":null,"Title":"Unauthorized","Status":401,"Detail":"AuthenticationUnsuccessful","Instance":"61f11bc2-48ef-483e-9be3-40cc3e38af98","Extensions":{}}'
+ http_version: null
+ recorded_at: Thu, 30 Apr 2020 00:54:44 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/staff/update.yml b/spec/vcr_cassettes/xpm_ruby/staff/update.yml
new file mode 100644
index 0000000..9949882
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/staff/update.yml
@@ -0,0 +1,67 @@
+---
+http_interactions:
+- request:
+ method: put
+ uri: https://api.xero.com/practicemanager/3.0/staff.api/update
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ 1044994
+ Joe Bloggs
+ Updated Address
+ 87654321
+ bloggsjoe@foo.com
+ PC456
+
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer access_token
+ xero-tenant-id:
+ - 'xero_tenant_id'
+ content_type:
+ - application/xml
+ Content-Type:
+ - application/x-www-form-urlencoded
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ content-length:
+ - '252'
+ server:
+ - nginx
+ xero-correlation-id:
+ - 848e7b7f-9b99-45e7-8595-b97b40734796
+ x-appminlimit-remaining:
+ - '9999'
+ x-minlimit-remaining:
+ - '59'
+ x-daylimit-remaining:
+ - '4940'
+ expires:
+ - Fri, 16 Apr 2021 11:15:09 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Fri, 16 Apr 2021 11:15:09 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK1044994Joe
+ Bloggsbloggsjoe@foo.com87654321Updated
+ AddressPC456
+ http_version: null
+ recorded_at: Fri, 16 Apr 2021 11:15:09 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/vcr_cassettes/xpm_ruby/template/list.yml b/spec/vcr_cassettes/xpm_ruby/template/list.yml
new file mode 100644
index 0000000..48eba45
--- /dev/null
+++ b/spec/vcr_cassettes/xpm_ruby/template/list.yml
@@ -0,0 +1,61 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.xero.com/practicemanager/3.0/template.api/list
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Faraday v1.0.1
+ Authorization:
+ - Bearer a_dummy_secret_token
+ xero-tenant-id:
+ - '0791dc22-8611-4c1c-8df7-1c5453d0795b'
+ content_type:
+ - application/xml
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ content-type:
+ - text/xml; charset=utf-8
+ server:
+ - Kestrel
+ x-daylimit-remaining:
+ - '4993'
+ x-minlimit-remaining:
+ - '59'
+ xero-correlation-id:
+ - b39cac4b-26ce-4fea-a65e-89804077699d
+ content-length:
+ - '819'
+ akamai-age-ms:
+ - '1588118029828'
+ expires:
+ - Tue, 28 Apr 2020 23:53:49 GMT
+ cache-control:
+ - max-age=0, no-cache, no-store
+ pragma:
+ - no-cache
+ date:
+ - Tue, 28 Apr 2020 23:53:49 GMT
+ connection:
+ - keep-alive
+ x-client-tls-ver:
+ - tls1.3
+ body:
+ encoding: UTF-8
+ string: OK1254074Activity
+ Statement1254068Annual Accounts1254069ASIC
+ Annual Review1254071Consulting1254072FBT
+ Nil Return1254073FBT Return1254070SMSF
+ Annual Accounts1254075Tax Return
+ - Company NIL1254076Tax Return
+ - Individual1254077Xero Consulting1254078Xero
+ Setup/Conversion
+ http_version: null
+ recorded_at: Tue, 28 Apr 2020 23:53:49 GMT
+recorded_with: VCR 5.1.0
diff --git a/spec/xpm_ruby/category_spec.rb b/spec/xpm_ruby/category_spec.rb
new file mode 100644
index 0000000..3e5a2b9
--- /dev/null
+++ b/spec/xpm_ruby/category_spec.rb
@@ -0,0 +1,45 @@
+require "spec_helper"
+
+module XpmRuby
+ RSpec.describe(Category) do
+ subject(:service) { described_class }
+
+ describe ".list" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "access_token" }
+
+ context "when API returns an array of categories" do
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/category/list") do
+ example.run
+ end
+ end
+
+ it "lists categories" do
+ categories_list = service.list(access_token: access_token, xero_tenant_id: xero_tenant_id)
+
+ expect(categories_list.length).to eq(3)
+
+ category = categories_list.first
+
+ expect(category["Name"]).to eql("Compliance")
+ expect(category["ID"]).to eql("304252")
+ end
+ end
+
+ context "when API doesn't return an array" do
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/category/list_empty_array") do
+ example.run
+ end
+ end
+
+ it "returns an empty array" do
+ categories_list = service.list(access_token: access_token, xero_tenant_id: xero_tenant_id)
+
+ expect(categories_list).to eq([])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/client_spec.rb b/spec/xpm_ruby/client_spec.rb
new file mode 100644
index 0000000..4f2e02e
--- /dev/null
+++ b/spec/xpm_ruby/client_spec.rb
@@ -0,0 +1,176 @@
+require "spec_helper"
+
+module XpmRuby
+ RSpec.describe(Client) do
+ describe ".add" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+
+ let(:client) { { "Name" => "Acmer Pty Ltd" } }
+
+ it "adds client" do
+ VCR.use_cassette("xpm_ruby/client/add") do
+ created_client = Client.add(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ client: client)
+
+ expect(created_client["ID"]).not_to be_nil
+ expect(created_client["Name"]).to eql(client["Name"])
+ end
+ end
+ end
+
+ describe ".update" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "access_token" }
+
+ let(:client) { { "ID" => 25655881, "Name" => "Acmer Pty Ltd" } }
+
+ it "updates client" do
+ VCR.use_cassette("xpm_ruby/client/update") do
+ updated_client = Client.update(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ client: client)
+
+ expect(updated_client["ID"]).not_to be_nil
+ expect(updated_client["Name"]).to eql(client["Name"])
+ end
+ end
+ end
+
+ describe ".get" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "access_token" }
+ let(:client_id) { "32014284" }
+
+ it "gets client information" do
+ VCR.use_cassette("xpm_ruby/client/get") do
+ client = Client.get(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ client_id: client_id
+ )
+
+ expect(client["ID"]).not_to be_nil
+ expect(client["Name"]).to eql("Get Client Test")
+ end
+ end
+ end
+
+ describe ".list" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+
+ context "when not modified since" do
+ it "list all clients" do
+ VCR.use_cassette("xpm_ruby/client/list/when_not_modified_since") do
+ clients = Client.list(access_token: access_token, xero_tenant_id: xero_tenant_id)
+
+ expect(clients.count).to eq(12)
+ end
+ end
+ end
+
+ context "when modified since" do
+ let(:modified_since) { "2020-05-05T06:24:31" }
+
+ it "list clients modified since" do
+ VCR.use_cassette("xpm_ruby/client/list/when_modified_since") do
+ clients_list = Client.list(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ modified_since: modified_since)
+
+ expect(clients_list.size).to eq(1)
+
+ client = clients_list.first
+
+ expect(client["ID"]).to eq("25655881")
+ end
+ end
+ end
+
+ context "when detailed false" do
+ it "list clients without details" do
+ VCR.use_cassette("xpm_ruby/client/list/when_detailed_false") do
+ clients = Client.list(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ detailed: false)
+
+ clients.each do |client|
+ expect(client).not_to have_key("Notes")
+ expect(client).not_to have_key("Groups")
+ expect(client).not_to have_key("Relationships")
+ end
+ end
+ end
+ end
+
+ context "when detailed true" do
+ it "list clients with details" do
+ VCR.use_cassette("xpm_ruby/client/list/when_detailed_true") do
+ clients = Client.list(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ detailed: true)
+
+ clients.each do |client|
+ expect(client).to have_key("Notes")
+ expect(client).to have_key("Groups")
+ expect(client).to have_key("Relationships")
+ end
+ end
+ end
+ end
+ end
+
+ describe ".search" do
+ subject(:search) do
+ Client.search(access_token: access_token, xero_tenant_id: xero_tenant_id, query: query, detailed: detailed)
+ end
+
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+ let(:query) { "acme" }
+
+ context "when detailed false" do
+ let(:detailed) { false }
+
+ it "returns client search results without details" do
+ VCR.use_cassette("xpm_ruby/client/search/when_detailed_false") do
+ clients = search
+
+ expect(clients.map { |client| client["Name"] }).to eq(["Acmer Pty Ltd", "Acmer Pty Ltd"])
+
+ clients.each do |client|
+ expect(client).not_to have_key("Notes")
+ expect(client).not_to have_key("Groups")
+ expect(client).not_to have_key("Relationships")
+ end
+ end
+ end
+ end
+
+ context "when detailed true" do
+ let(:detailed) { true }
+
+ it "returns client search results with details" do
+ VCR.use_cassette("xpm_ruby/client/search/when_detailed_true") do
+ clients = search
+
+ expect(clients.map { |client| client["Name"] }).to eq(["Acmer Pty Ltd", "Acmer Pty Ltd"])
+
+ clients.each do |client|
+ expect(client).to have_key("Notes")
+ expect(client).to have_key("Groups")
+ expect(client).to have_key("Relationships")
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/connection_spec.rb b/spec/xpm_ruby/connection_spec.rb
index 6fc1707..d3ca60c 100644
--- a/spec/xpm_ruby/connection_spec.rb
+++ b/spec/xpm_ruby/connection_spec.rb
@@ -2,28 +2,197 @@
module XpmRuby
RSpec.describe(Connection) do
- subject(:service) { described_class }
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "access_token" }
- let(:api_url) { "api.workflowmax.com" }
- let(:api_key) { "test" }
- let(:account_key) { "test" }
+ describe "#get" do
+ context "with a valid tenant id and access token" do
+ it "should return a status of ok" do
+ VCR.use_cassette("xpm_ruby/connection/get") do
+ connection = Connection.new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ response = connection.get(endpoint: "staff.api/list")
+
+ expect(response["Status"]).to eq("OK")
+ end
+ end
+ end
+
+ context "with an invalid xero_tenant_id" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/get/bad_tenant") do
+ connection = Connection.new(access_token: access_token, xero_tenant_id: "bad_tenant")
+
+ expect { connection.get(endpoint: "staff.api/list") }.to raise_error(XpmRuby::Forbidden, /AuthenticationUnsuccessful/)
+ end
+ end
+ end
+
+ context "with an invalid access_token" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/get/bad_token") do
+ connection = Connection.new(access_token: "bad_token", xero_tenant_id: xero_tenant_id)
+ expect { connection.get(endpoint: "staff.api/list") }.to raise_error(XpmRuby::Unauthorized, /AuthenticationUnsuccessful/)
+ end
+ end
+ end
+
+ context "when connection to API failed" do
+ before(:each) do
+ allow_any_instance_of(Faraday::Connection).to receive(:get).and_raise(Faraday::ConnectionFailed.new("connection failed"))
+ end
+
+ it "should raise an error" do
+ connection = Connection.new(access_token: "bad_token", xero_tenant_id: xero_tenant_id)
+ expect { connection.get(endpoint: "staff.api/list") }.to raise_error(XpmRuby::ConnectionFailed)
+ end
+ end
+
+ context "when connection to API timeout" do
+ before(:each) do
+ allow_any_instance_of(Faraday::Connection).to receive(:get).and_raise(Faraday::TimeoutError.new("timeout"))
+ end
- describe "#initialize" do
- it "should set the basic auth" do
- connection = service.new(api_key: api_key, api_url: api_url, account_key: account_key)
- expect(connection.basic_auth).to eq("Basic dGVzdDp0ZXN0")
+ it "should raise an error" do
+ connection = Connection.new(access_token: "bad_token", xero_tenant_id: xero_tenant_id)
+ expect { connection.get(endpoint: "staff.api/list") }.to raise_error(XpmRuby::ConnectionTimeout)
+ end
+ end
+
+ context "with XPM API is unavailable" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/get/not_available") do
+ connection = Connection.new(access_token: "bad_token", xero_tenant_id: xero_tenant_id)
+ expect { connection.get(endpoint: "staff.api/list") }.to raise_error(XpmRuby::NotAvailable)
+ end
+ end
+ end
+
+ context "with XPM API returns internal server error" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/get/internal_server_error") do
+ connection = Connection.new(access_token: "bad_token", xero_tenant_id: xero_tenant_id)
+ expect { connection.get(endpoint: "staff.api/list") }.to raise_error(XpmRuby::InternalServerError)
+ end
+ end
+ end
+
+ context "when API rate limit is exceeded" do
+ it "should raise an error with details" do
+ VCR.use_cassette("xpm_ruby/connection/get/rate_limit_exceeded") do
+ connection = Connection.new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ expect { connection.get(endpoint: "staff.api/list") }.to raise_error(an_instance_of(XpmRuby::RateLimitExceeded).and(having_attributes(details: {
+ "retry-after" => "22",
+ "x-rate-limit-problem" => "minute",
+ "x-minlimit-remaining" => "0",
+ "x-daylimit-remaining" => "4539",
+ "x-appminlimit-remaining" => "9938"
+ })))
+ end
+ end
end
end
- describe "#get" do
- let(:faraday_connection) { instance_double("Faraday::Connection", get: nil) }
+ describe "#post" do
+ let(:xml_string) do
+ "Brochure DesignDetailed description of the job240976422029102320291028"
+ end
+
+ context "with a valid tenant id and access token" do
+ it "should post to Faraday with the right endpoint, data and headers" do
+ VCR.use_cassette("xpm_ruby/connection/post") do
+ connection = Connection.new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ response = connection.post(endpoint: "job.api/add", data: xml_string)
+
+ expect(response["Status"]).to eq("OK")
+ end
+ end
+ end
- it "should do a get via Faraday" do
- connection = service.new(api_key: api_key, api_url: api_url, account_key: account_key)
+ context "with an invalid xero_tenant_id" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/post/bad_tenant") do
+ connection = Connection.new(access_token: access_token, xero_tenant_id: "bad_tenant")
- expect(Faraday).to receive(:new).with("https://api.workflowmax.com/v3/staff.api/list", headers: { "Authorization" => "Basic dGVzdDp0ZXN0" }).and_return(faraday_connection)
+ expect { connection.post(endpoint: "job.api/add", data: xml_string) }.to raise_error(XpmRuby::Forbidden, /AuthenticationUnsuccessful/)
+ end
+ end
+ end
+
+ context "with an invalid access_token" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/post/bad_token") do
+ connection = Connection.new(access_token: "bad_token", xero_tenant_id: xero_tenant_id)
+ expect { connection.post(endpoint: "job.api/add", data: xml_string) }.to raise_error(XpmRuby::Unauthorized, /AuthenticationUnsuccessful/)
+ end
+ end
+ end
+ end
+
+ describe "#put" do
+ let(:xml_string) do
+ "J000029Brochure Design UPDATEDDetailed description of the job240976422029102320291028"
+ end
+
+ context "with a valid tenant id and access token" do
+ it "should post to Faraday with the right endpoint, data and headers" do
+ VCR.use_cassette("xpm_ruby/connection/put") do
+ connection = Connection.new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ response = connection.put(endpoint: "job.api/update", data: xml_string)
+
+ expect(response["Status"]).to eq("OK")
+ end
+ end
+ end
+
+ context "with an invalid xero_tenant_id" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/put/bad_tenant") do
+ connection = Connection.new(access_token: access_token, xero_tenant_id: "bad_tenant")
+
+ expect { connection.put(endpoint: "job.api/update", data: xml_string) }.to raise_error(XpmRuby::Forbidden, /AuthenticationUnsuccessful/)
+ end
+ end
+ end
+
+ context "with an invalid access_token" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/put/bad_token") do
+ connection = Connection.new(access_token: "bad_token", xero_tenant_id: xero_tenant_id)
+ expect { connection.put(endpoint: "job.api/update", data: xml_string) }.to raise_error(XpmRuby::Unauthorized, /AuthenticationUnsuccessful/)
+ end
+ end
+ end
+ end
+
+ describe "#delete" do
+ let(:contact_id) { "14574323" }
+
+ it "should delete to Faraday with the right endpoint" do
+ VCR.use_cassette("xpm_ruby/connection/delete") do
+ connection = Connection.new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ response = connection.delete(endpoint: "client.api/contact", id: contact_id)
+
+ expect(response["Status"]).to eq("OK")
+ end
+ end
+
+ context "with an invalid xero_tenant_id" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/delete/bad_tenant") do
+ connection = Connection.new(access_token: access_token, xero_tenant_id: "bad_tenant")
+
+ expect { connection.delete(endpoint: "client.api/contact", id: contact_id) }.to raise_error(XpmRuby::Forbidden, /AuthenticationUnsuccessful/)
+ end
+ end
+ end
- connection.get(endpoint: "staff.api/list")
+ context "with an invalid access_token" do
+ it "should raise an error" do
+ VCR.use_cassette("xpm_ruby/connection/delete/bad_token") do
+ connection = Connection.new(access_token: "bad_token", xero_tenant_id: xero_tenant_id)
+ expect { connection.delete(endpoint: "client.api/contact", id: contact_id) }.to raise_error(XpmRuby::Unauthorized, /AuthenticationUnsuccessful/)
+ end
+ end
end
end
end
diff --git a/spec/xpm_ruby/contact_spec.rb b/spec/xpm_ruby/contact_spec.rb
new file mode 100644
index 0000000..9fd407d
--- /dev/null
+++ b/spec/xpm_ruby/contact_spec.rb
@@ -0,0 +1,112 @@
+require "spec_helper"
+
+module XpmRuby
+ RSpec.describe(Contact) do
+ describe ".add" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+
+ let(:contact) do
+ {
+ "Client" => { "ID" => 25655881 },
+ "Name" => "Acmer Pty Ltd"
+ }
+ end
+
+ it "adds contact" do
+ VCR.use_cassette("xpm_ruby/contact/add") do
+ created_contact = Contact.add(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ contact: contact)
+
+ expect(created_contact["ID"]).not_to be_nil
+ expect(created_contact["Name"]).to eql(created_contact["Name"])
+ end
+ end
+ end
+
+ describe ".update" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+
+ context "without Client ID" do
+ let(:contact) do
+ {
+ "Name" => "Acmer Pty Ltd Updated 3"
+ }
+ end
+
+ it "updates contact" do
+ VCR.use_cassette("xpm_ruby/contact/update") do
+ updated_contact = Contact.update(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ id: 15412877,
+ contact: contact)
+
+ expect(updated_contact["ID"]).not_to be_nil
+ expect(updated_contact["Name"]).to eql(updated_contact["Name"])
+ end
+ end
+ end
+
+ context "with Client ID" do
+ let(:contact) do
+ {
+ "Client" => { "ID" => 25655881 },
+ "Name" => "Acmer Pty Ltd Updated 3"
+ }
+ end
+
+ it "updates contact" do
+ VCR.use_cassette("xpm_ruby/contact/update") do
+ updated_contact = Contact.update(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ id: 15412877,
+ contact: contact)
+
+ expect(updated_contact["ID"]).not_to be_nil
+ expect(updated_contact["Name"]).to eql(updated_contact["Name"])
+ end
+ end
+ end
+ end
+
+ describe ".delete" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+ let(:contact_id) { "14574323" }
+
+ context "without Client ID" do
+ it "deletes the contact" do
+ VCR.use_cassette("xpm_ruby/contact/delete") do
+ deleted_contact = Contact.delete(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ contact_id: contact_id)
+
+ expect(deleted_contact["ID"]).to eql(contact_id)
+ expect(deleted_contact["Name"]).to eql("some guy person")
+ end
+ end
+ end
+
+ context "with Client ID" do
+ it "deletes the contact" do
+ VCR.use_cassette("xpm_ruby/contact/delete") do
+ deleted_contact = Contact.delete(
+ access_token: access_token,
+ xero_tenant_id: xero_tenant_id,
+ contact_id: contact_id,
+ client_id: 25655881)
+
+ expect(deleted_contact["ID"]).to eql(contact_id)
+ expect(deleted_contact["Name"]).to eql("some guy person")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/job_spec.rb b/spec/xpm_ruby/job_spec.rb
new file mode 100644
index 0000000..c5411f9
--- /dev/null
+++ b/spec/xpm_ruby/job_spec.rb
@@ -0,0 +1,292 @@
+require "spec_helper"
+
+module XpmRuby
+ RSpec.describe(Job) do
+ describe ".current" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/job/current") do
+ example.run
+ end
+ end
+
+ it "lists current jobs" do
+ current_jobs = Job.current(access_token: access_token, xero_tenant_id: xero_tenant_id)
+
+ expect(current_jobs.length).to eq(29)
+
+ first_job = current_jobs.first
+
+ expect(first_job["Name"]).to eql("(Sample) Bookkeeping Monthly - Basic")
+ expect(first_job["ID"]).to eql("J000014")
+ expect(first_job["State"]).to eql("Planned")
+ expect(first_job["StartDate"]).to eql("2019-11-01T00:00:00")
+ expect(first_job["DueDate"]).to eql("2019-11-07T00:00:00")
+ expect(first_job["CompletedDate"]).to be_nil
+ end
+ end
+
+ describe ".add" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+ let(:job) { { "Name" => "Joe Bloggs", "Description" => "New Job", "ClientID" => "24097642", "StartDate" => "20091023", "DueDate" => "20091023" } }
+
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/job/add") do
+ example.run
+ end
+ end
+
+ it "adds a job" do
+ added_job = Job.add(access_token: access_token, xero_tenant_id: xero_tenant_id, job: job)
+
+ expect(added_job["Name"]).to eql(job["Name"])
+ expect(added_job["Description"]).to eql(job["Description"])
+ expect(added_job["Client"]["ID"]).to eql(job["ClientID"])
+ expect(added_job["StartDate"]).to eql("2009-10-23T00:00:00")
+ expect(added_job["DueDate"]).to eql("2009-10-23T00:00:00")
+ end
+ end
+
+ describe ".update" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+ let(:job) { { "ID" => "J000031", "Name" => "Joe Bloggs", "Description" => "Update Job", "ClientID" => "24097642", "StartDate" => "20091023", "DueDate" => "20091023" } }
+
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/job/update") do
+ example.run
+ end
+ end
+
+ it "updates a job" do
+ updated_job = Job.update(access_token: access_token, xero_tenant_id: xero_tenant_id, job: job)
+
+ expect(updated_job["ID"]).to eql(job["ID"])
+ expect(updated_job["Name"]).to eql(job["Name"])
+ expect(updated_job["Description"]).to eql(job["Description"])
+ expect(updated_job["Client"]["ID"]).to eql(job["ClientID"])
+ expect(updated_job["StartDate"]).to eql("2009-10-23T00:00:00")
+ expect(updated_job["DueDate"]).to eql("2009-10-23T00:00:00")
+ end
+ end
+
+ describe ".get" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+ let(:job_id) { "J000014" }
+
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/job/get") do
+ example.run
+ end
+ end
+
+ it "gets the job details" do
+ job = Job.get(access_token: access_token, xero_tenant_id: xero_tenant_id, job_id: job_id)
+
+ expect(job["Name"]).to eql("(Sample) Bookkeeping Monthly - Basic")
+ expect(job["ID"]).to eql("J000014")
+ expect(job["State"]).to eql("Planned")
+ expect(job["StartDate"]).to eql("2019-11-01T00:00:00")
+ expect(job["DueDate"]).to eql("2019-11-07T00:00:00")
+ expect(job["CompletedDate"]).to be_nil
+ end
+ end
+
+ describe ".state" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+
+ context "when the job state is successful" do
+ let(:job) { { "ID" => "J000031", "State" => "COMPLETED" } }
+
+ it "sets the state on the job" do
+ VCR.use_cassette("xpm_ruby/job/state/success") do
+ response = Job.state(access_token: access_token, xero_tenant_id: xero_tenant_id, job: job)
+ expect(response).to eq("OK")
+ end
+ end
+ end
+
+ context "when it is not successful" do
+ let(:job) { { "ID" => "J000031", "State" => "NONEXISTENT" } }
+
+ it "reports the error" do
+ VCR.use_cassette("xpm_ruby/job/state/fail") do
+ expect { Job.state(access_token: access_token, xero_tenant_id: xero_tenant_id, job: job) }.to raise_error(XpmRuby::Error, /Invalid state code/)
+ end
+ end
+ end
+ end
+
+ describe ".delete" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+
+ context "with a valid job id" do
+ let(:job) { { "ID" => "J000031" } }
+
+ it "updates a job" do
+ VCR.use_cassette("xpm_ruby/job/delete") do
+ response = Job.delete(access_token: access_token, xero_tenant_id: xero_tenant_id, job: job)
+
+ expect(response).to eq("OK")
+ end
+ end
+ end
+
+ context "with an invalid job id" do
+ let(:job) { { "ID" => "none" } }
+
+ it "returns an error" do
+ VCR.use_cassette("xpm_ruby/job/delete/error") do
+ expect { Job.delete(access_token: access_token, xero_tenant_id: xero_tenant_id, job: job) }.to raise_error(XpmRuby::Error, /Invalid job identifier/)
+ end
+ end
+ end
+ end
+
+ describe ".assign" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+
+ context "add and remove staff" do
+ context "with a valid job id and staff id" do
+ let(:job_xml) { 'J000032 ' }
+
+ it "updates a job" do
+ VCR.use_cassette("xpm_ruby/job/assign") do
+ response = Job.assign(access_token: access_token, xero_tenant_id: xero_tenant_id, job_xml: job_xml)
+
+ expect(response).to eq("OK")
+ end
+ end
+ end
+
+ context "remove with a valid job id and staff id" do
+ let(:job_xml) { 'J000032 ' }
+
+ it "updates a job" do
+ VCR.use_cassette("xpm_ruby/job/assign/remove") do
+ response = Job.assign(access_token: access_token, xero_tenant_id: xero_tenant_id, job_xml: job_xml)
+
+ expect(response).to eq("OK")
+ end
+ end
+ end
+ end
+
+ context "add and remove manager" do
+ context "with a valid job id and staff id" do
+ let(:job_xml) { 'J000032 ' }
+
+ it "updates a job" do
+ VCR.use_cassette("xpm_ruby/job/assign/manager") do
+ response = Job.assign(access_token: access_token, xero_tenant_id: xero_tenant_id, job_xml: job_xml)
+
+ expect(response).to eq("OK")
+ end
+ end
+ end
+
+ context "remove with a valid job id and staff id" do
+ let(:job_xml) { "J000032 " }
+
+ it "updates a job" do
+ VCR.use_cassette("xpm_ruby/job/assign/removemanager") do
+ response = Job.assign(access_token: access_token, xero_tenant_id: xero_tenant_id, job_xml: job_xml)
+
+ expect(response).to eq("OK")
+ end
+ end
+ end
+ end
+
+ context "add and remove partner" do
+ context "with a valid job id and staff id" do
+ let(:job_xml) { 'J000032 ' }
+
+ it "updates a job" do
+ VCR.use_cassette("xpm_ruby/job/assign/partner") do
+ response = Job.assign(access_token: access_token, xero_tenant_id: xero_tenant_id, job_xml: job_xml)
+
+ expect(response).to eq("OK")
+ end
+ end
+ end
+
+ context "remove with a valid job id and staff id" do
+ let(:job_xml) { "J000032 " }
+
+ it "updates a job" do
+ VCR.use_cassette("xpm_ruby/job/assign/removepartner") do
+ response = Job.assign(access_token: access_token, xero_tenant_id: xero_tenant_id, job_xml: job_xml)
+
+ expect(response).to eq("OK")
+ end
+ end
+ end
+ end
+
+ context "with an invalid job id" do
+ let(:job_xml) { 'none ' }
+
+ it "returns an error" do
+ VCR.use_cassette("xpm_ruby/job/assign/invalidjob") do
+ expect { Job.assign(access_token: access_token, xero_tenant_id: xero_tenant_id, job_xml: job_xml) }.to raise_error(XpmRuby::Error, /Invalid job identifier/)
+ end
+ end
+ end
+
+ context "with an invalid staff id" do
+ let(:job_xml) { 'J000032 ' }
+
+ it "returns an error" do
+ VCR.use_cassette("xpm_ruby/job/assign/invalidstaff") do
+ expect { Job.assign(access_token: access_token, xero_tenant_id: xero_tenant_id, job_xml: job_xml) }.to raise_error(XpmRuby::Error, /Invalid staff identifier for add request/)
+ end
+ end
+ end
+ end
+
+ describe ".applytemplate" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "token" }
+
+ context "with valid job and template" do
+ let(:job) { { "ID" => "J000032", "TemplateID" => 1254078, "TaskMode" => "AddNew" } }
+
+ it "applies the template to a job" do
+ VCR.use_cassette("xpm_ruby/job/applytemplate") do
+ applied_job = Job.applytemplate(access_token: access_token, xero_tenant_id: xero_tenant_id, job: job)
+
+ expect(applied_job["ID"]).to eql(job["ID"])
+ end
+ end
+ end
+
+ context "with invalid job" do
+ let(:job) { { "ID" => "none", "TemplateID" => 1254078, "TaskMode" => "AddNew" } }
+
+ it "throws invalid job error" do
+ VCR.use_cassette("xpm_ruby/job/applytemplate/invalidjob") do
+ expect { Job.applytemplate(access_token: access_token, xero_tenant_id: xero_tenant_id, job: job) }.to raise_error(XpmRuby::Error, /Invalid job identifier/)
+ end
+ end
+ end
+
+ context "with invalid template" do
+ let(:job) { { "ID" => "J000032", "TemplateID" => 1000, "TaskMode" => "AddNew" } }
+
+ it "throws invalid job error" do
+ VCR.use_cassette("xpm_ruby/job/applytemplate/invalidtemplate") do
+ expect { Job.applytemplate(access_token: access_token, xero_tenant_id: xero_tenant_id, job: job) }.to raise_error(XpmRuby::Error, /Invalid job template identifier/)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/client/add_spec.rb b/spec/xpm_ruby/schema/client/add_spec.rb
new file mode 100644
index 0000000..e275486
--- /dev/null
+++ b/spec/xpm_ruby/schema/client/add_spec.rb
@@ -0,0 +1,41 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Client) do
+ context "with a valid Add schema" do
+ context "with contacts" do
+ it "should not raise an error" do
+ hash = { "Name" => "Joe Bloggs Consulting", "Contacts" => [{ "Name" => "Joe Bloggs" }] }
+ expect { Client::Add[hash] }.not_to raise_error
+ end
+ end
+
+ context "without contacts" do
+ it "should not raise an error" do
+ hash = { "Name" => "Joe Bloggs Consulting" }
+ expect { Client::Add[hash] }.not_to raise_error
+ end
+ end
+
+ it "should coerce the types" do
+ hash = { "Name" => "Joe Bloggs", "Phone" => "88880000" }
+ add = Client::Add[hash]
+ expect(add[:Phone]).to eql("88880000")
+ end
+ end
+
+ context "with an invalid Add schema" do
+ it "should raise an error" do
+ hash = { "Email" => "Joe Bloggs" }
+ expect { Client::Add[hash] }.to raise_error(Dry::Types::MissingKeyError, /Name is missing in Hash input/)
+ end
+
+ it "should raise an error on contacts" do
+ hash = { "Name" => "Joe Bloggs Consulting", "Contacts" => [{ "Email" => "Joe Bloggs" }] }
+ expect { Client::Add[hash] }.to raise_error(Dry::Types::SchemaError, /Name is missing in Hash input/)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/client/update_spec.rb b/spec/xpm_ruby/schema/client/update_spec.rb
new file mode 100644
index 0000000..ef32e95
--- /dev/null
+++ b/spec/xpm_ruby/schema/client/update_spec.rb
@@ -0,0 +1,41 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Client) do
+ context "with a valid Update schema" do
+ context "with contacts" do
+ it "should not raise an error" do
+ hash = { "ID" => 25655881, "Name" => "Joe Bloggs Consulting", "Contacts" => [{ "Name" => "Joe Bloggs" }] }
+ expect { Client::Update[hash] }.not_to raise_error
+ end
+ end
+
+ context "without contacts" do
+ it "should not raise an error" do
+ hash = { "ID" => 25655881, "Name" => "Joe Bloggs Consulting" }
+ expect { Client::Update[hash] }.not_to raise_error
+ end
+ end
+
+ it "should coerce the types" do
+ hash = { "ID" => 25655881, "Name" => "Joe Bloggs", "Phone" => "88880000" }
+ add = Client::Update[hash]
+ expect(add[:Phone]).to eql("88880000")
+ end
+ end
+
+ context "with an invalid Update schema" do
+ it "should raise an error" do
+ hash = { "Email" => "Joe Bloggs" }
+ expect { Client::Update[hash] }.to raise_error(Dry::Types::MissingKeyError, /ID is missing in Hash input/)
+ end
+
+ it "should raise an error on contacts" do
+ hash = { "ID" => 25655881, "Name" => "Joe Bloggs Consulting", "Contacts" => [{ "Email" => "Joe Bloggs" }] }
+ expect { Client::Update[hash] }.to raise_error(Dry::Types::SchemaError, /Name is missing in Hash input/)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/contact/add_spec.rb b/spec/xpm_ruby/schema/contact/add_spec.rb
new file mode 100644
index 0000000..7c25635
--- /dev/null
+++ b/spec/xpm_ruby/schema/contact/add_spec.rb
@@ -0,0 +1,23 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Contact) do
+ context "with a valid Add schema" do
+ it "should not raise an error" do
+ hash = {
+ "Client" => { "ID" => 25655881 },
+ "Name" => "Joe Bloggs" }
+ expect { Contact::Add[hash] }.not_to raise_error
+ end
+ end
+
+ context "with an invalid Add schema" do
+ it "should raise an error" do
+ hash = { "Name" => "Joe Bloggs" }
+ expect { Contact::Add[hash] }.to raise_error(Dry::Types::MissingKeyError, /Client is missing in Hash input/)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/contact/update_spec.rb b/spec/xpm_ruby/schema/contact/update_spec.rb
new file mode 100644
index 0000000..9c46e72
--- /dev/null
+++ b/spec/xpm_ruby/schema/contact/update_spec.rb
@@ -0,0 +1,21 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Contact) do
+ context "with a valid Update schema" do
+ it "should not raise an error" do
+ hash = { "Name" => "Joe Bloggs" }
+ expect { Contact::Update[hash] }.not_to raise_error
+ end
+
+ context "with a client ID" do
+ it "should not raise an error" do
+ hash = { "Client" => { "ID" => "123" }, "Name" => "Joe Bloggs" }
+ expect { Contact::Update[hash] }.not_to raise_error
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/job/add_spec.rb b/spec/xpm_ruby/schema/job/add_spec.rb
new file mode 100644
index 0000000..6017fdd
--- /dev/null
+++ b/spec/xpm_ruby/schema/job/add_spec.rb
@@ -0,0 +1,27 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Job) do
+ context "with a valid Add schema" do
+ it "should not raise an error" do
+ hash = { "Name" => "Joe Bloggs", "Description" => "New Job", "ClientID" => 1234, "StartDate" => 20091023, "DueDate" => 20091023 }
+ expect { Job::Add[hash] }.not_to raise_error
+ end
+
+ it "should coerce the types" do
+ hash = { "Name" => "Joe Bloggs", "Description" => "New Job", "ClientID" => 1234, "StartDate" => 20091023, "DueDate" => 20091023 }
+ add = Job::Add[hash]
+ expect(add[:ClientID]).to eql("1234")
+ end
+ end
+
+ context "with an invalid Add schema" do
+ it "should raise an error" do
+ hash = { "Name" => "Joe Bloggs" }
+ expect { Job::Add[hash] }.to raise_error(Dry::Types::MissingKeyError, ":ClientID is missing in Hash input")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/job/applytemplate_spec.rb b/spec/xpm_ruby/schema/job/applytemplate_spec.rb
new file mode 100644
index 0000000..bff723e
--- /dev/null
+++ b/spec/xpm_ruby/schema/job/applytemplate_spec.rb
@@ -0,0 +1,27 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Job) do
+ context "with a valid Applytemplate schema" do
+ it "should not raise an error" do
+ hash = { "ID" => "J230498", "TemplateID" => 1234, "TaskMode" => "AddNew" }
+ expect { Job::Applytemplate[hash] }.not_to raise_error
+ end
+
+ it "should coerce the types" do
+ hash = { "ID" => "J230498", "TemplateID" => 1234, "TaskMode" => "AddNew" }
+ applytemplate = Job::Applytemplate[hash]
+ expect(applytemplate[:TemplateID]).to eql("1234")
+ end
+ end
+
+ context "with an invalid Applytemplate schema" do
+ it "should raise an error" do
+ hash = { "TemplateID" => 1234, "TaskMode" => "AddNew" }
+ expect { Job::Applytemplate[hash] }.to raise_error(Dry::Types::MissingKeyError, /ID is missing in Hash input/)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/job/delete_spec.rb b/spec/xpm_ruby/schema/job/delete_spec.rb
new file mode 100644
index 0000000..158b77a
--- /dev/null
+++ b/spec/xpm_ruby/schema/job/delete_spec.rb
@@ -0,0 +1,21 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Job) do
+ context "with a valid Delete schema" do
+ it "should not raise an error" do
+ hash = { "ID" => "J230498" }
+ expect { Job::Delete[hash] }.not_to raise_error
+ end
+ end
+
+ context "with an invalid Delete schema" do
+ it "should raise an error" do
+ hash = {}
+ expect { Job::Delete[hash] }.to raise_error(Dry::Types::MissingKeyError, /ID is missing in Hash input/)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/job/state_spec.rb b/spec/xpm_ruby/schema/job/state_spec.rb
new file mode 100644
index 0000000..5f01850
--- /dev/null
+++ b/spec/xpm_ruby/schema/job/state_spec.rb
@@ -0,0 +1,21 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Job) do
+ context "with a valid State schema" do
+ it "should not raise an error" do
+ hash = { "ID" => "J230498", "State" => "CONFIRMED" }
+ expect { Job::State[hash] }.not_to raise_error
+ end
+ end
+
+ context "with an invalid State schema" do
+ it "should raise an error" do
+ hash = { "ID" => "J230498" }
+ expect { Job::State[hash] }.to raise_error(Dry::Types::MissingKeyError, /State is missing in Hash input/)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/job/update_spec.rb b/spec/xpm_ruby/schema/job/update_spec.rb
new file mode 100644
index 0000000..edd1a13
--- /dev/null
+++ b/spec/xpm_ruby/schema/job/update_spec.rb
@@ -0,0 +1,27 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Job) do
+ context "with a valid Update schema" do
+ it "should not raise an error" do
+ hash = { "ID" => "J230498", "Name" => "Joe Bloggs", "Description" => "New Job", "StartDate" => 20091023, "DueDate" => 20091023 }
+ expect { Job::Update[hash] }.not_to raise_error
+ end
+
+ it "should coerce the types" do
+ hash = { "ID" => "J230498", "Name" => "Joe Bloggs", "Description" => "New Job", "StartDate" => 20091023, "DueDate" => 20091023 }
+ add = Job::Update[hash]
+ expect(add[:ID]).to eql("J230498")
+ end
+ end
+
+ context "with an invalid Update schema" do
+ it "should raise an error" do
+ hash = { "Name" => "Joe Bloggs", "Description" => "New Job", "StartDate" => 20091023, "DueDate" => 20091023 }
+ expect { Job::Update[hash] }.to raise_error(Dry::Types::MissingKeyError, /ID is missing in Hash input/)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/staff/add_spec.rb b/spec/xpm_ruby/schema/staff/add_spec.rb
new file mode 100644
index 0000000..d273b4f
--- /dev/null
+++ b/spec/xpm_ruby/schema/staff/add_spec.rb
@@ -0,0 +1,21 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Staff) do
+ context "with a valid Add schema" do
+ it "should not raise an error" do
+ hash = { "Name" => "Joe Bloggs", "Email" => "staff@foo.com" }
+ expect { Staff::Add[hash] }.not_to raise_error
+ end
+ end
+
+ context "with an invalid Add schema" do
+ it "should raise an error" do
+ hash = { "Email" => "staff@foo.com" }
+ expect { Staff::Add[hash] }.to raise_error(Dry::Types::MissingKeyError, ":Name is missing in Hash input")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/schema/staff/update_spec.rb b/spec/xpm_ruby/schema/staff/update_spec.rb
new file mode 100644
index 0000000..18bc16e
--- /dev/null
+++ b/spec/xpm_ruby/schema/staff/update_spec.rb
@@ -0,0 +1,21 @@
+require "spec_helper"
+
+module XpmRuby
+ module Schema
+ RSpec.describe(Staff) do
+ context "with a valid Update schema" do
+ it "should not raise an error" do
+ hash = { "ID" => "S000123", "Name" => "Joe Bloggs", "Email" => "staff@foo.com" }
+ expect { Staff::Update[hash] }.not_to raise_error
+ end
+ end
+
+ context "with an invalid Update schema" do
+ it "should raise an error" do
+ hash = { "Name" => "joe Bloggs", "Email" => "staff@foo.com" }
+ expect { Staff::Update[hash] }.to raise_error(Dry::Types::MissingKeyError, ":ID is missing in Hash input")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/staff_spec.rb b/spec/xpm_ruby/staff_spec.rb
new file mode 100644
index 0000000..1c1840b
--- /dev/null
+++ b/spec/xpm_ruby/staff_spec.rb
@@ -0,0 +1,126 @@
+require "spec_helper"
+
+module XpmRuby
+ RSpec.describe(Staff) do
+ describe ".list" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+
+ context "when access token expired" do
+ let(:access_token) { "expired" }
+
+ it "raises access token expired exception" do
+ VCR.use_cassette("xpm_ruby/staff/list/access_token_expired") do
+ expect do
+ Connection
+ .new(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ .get(endpoint: "staff.api/list")
+ end.to raise_error(XpmRuby::AccessTokenExpired)
+ end
+ end
+ end
+
+ context "when access token unauthorized" do
+ let(:access_token) { "unauthorized" }
+
+ it "raises access token expired exception" do
+ VCR.use_cassette("xpm_ruby/staff/list/access_token_unauthorized") do
+ expect do
+ Staff.list(access_token: access_token, xero_tenant_id: xero_tenant_id)
+ end.to raise_error(XpmRuby::Unauthorized)
+ end
+ end
+ end
+
+ context "when access token accepted" do
+ let(:access_token) { "accepted" }
+
+ context "when multiple Staff returned" do
+ it "lists staff", :aggregate_failure do
+ VCR.use_cassette("xpm_ruby/staff/list/access_token_accepted") do
+ staff_list = Staff.list(access_token: access_token, xero_tenant_id: xero_tenant_id)
+
+ staff = staff_list.last
+
+ expect(staff["Name"]).to eql("test")
+ expect(staff["Email"]).to eql("adammikulas@gmail.com")
+ # expect(staff.uuid).to eql("1cc99c1e-8cf7-4248-ab84-3e11126facbc")
+ end
+ end
+ end
+
+ context "when a single Staff is returned" do
+ it "returns an Array of Staff", :aggregate_failure do
+ VCR.use_cassette("xpm_ruby/staff/list/access_token_accepted_one_staff") do
+ staff_list = Staff.list(access_token: access_token, xero_tenant_id: xero_tenant_id)
+
+ expect(staff_list).to be_a(Array)
+ expect(staff_list.first["Name"]).to eql("Adam Silver")
+ end
+ end
+ end
+ end
+ end
+
+ describe ".add" do
+ let(:xero_tenant_id) { "xero_tenant_id" }
+ let(:access_token) { "access_token" }
+ let(:staff) { { "Name" => "Joe Bloggs", "Address" => "In your head", "Phone" => "123456789", "Email" => "joebloggs@foo.com", "PayrollCode" => "PC123" } }
+
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/staff/add") do
+ example.run
+ end
+ end
+
+ it "adds a staff" do
+ added_staff = Staff.add(access_token: access_token, xero_tenant_id: xero_tenant_id, staff: staff)
+
+ expect(added_staff["Name"]).to eql(staff["Name"])
+ expect(added_staff["Address"]).to eql(staff["Address"])
+ expect(added_staff["Phone"]).to eql(staff["Phone"])
+ expect(added_staff["Email"]).to eql(staff["Email"])
+ expect(added_staff["PayrollCode"]).to eql(staff["PayrollCode"])
+ end
+ end
+
+ describe ".update" do
+ let(:xero_tenant_id) { "xero_tenant_id" }
+ let(:access_token) { "access_token" }
+ let(:staff) { { "ID" => "1044994", "Name" => "Joe Bloggs", "Address" => "Updated Address", "Phone" => "87654321", "Email" => "bloggsjoe@foo.com", "PayrollCode" => "PC456" } }
+
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/staff/update") do
+ example.run
+ end
+ end
+
+ it "updates a staff" do
+ updated_staff = Staff.update(access_token: access_token, xero_tenant_id: xero_tenant_id, staff: staff)
+
+ expect(updated_staff["ID"]).to eql(staff["ID"])
+ expect(updated_staff["Name"]).to eql(staff["Name"])
+ expect(updated_staff["Address"]).to eql(staff["Address"])
+ expect(updated_staff["Phone"]).to eql(staff["Phone"])
+ expect(updated_staff["Email"]).to eql(staff["Email"])
+ expect(updated_staff["PayrollCode"]).to eql(staff["PayrollCode"])
+ end
+ end
+
+ describe ".delete" do
+ let(:xero_tenant_id) { "xero_tenant_id" }
+ let(:access_token) { "access_token" }
+
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/staff/delete") do
+ example.run
+ end
+ end
+
+ it "deletes a staff" do
+ deleted_staff = Staff.delete(access_token: access_token, xero_tenant_id: xero_tenant_id, id: "859318")
+
+ expect(deleted_staff).to be(true)
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby/template_spec.rb b/spec/xpm_ruby/template_spec.rb
new file mode 100644
index 0000000..62de10b
--- /dev/null
+++ b/spec/xpm_ruby/template_spec.rb
@@ -0,0 +1,29 @@
+require "spec_helper"
+
+module XpmRuby
+ RSpec.describe(Template) do
+ subject(:service) { described_class }
+
+ describe ".list" do
+ let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" }
+ let(:access_token) { "a_dummy_secret_token" }
+
+ around(:each) do |example|
+ VCR.use_cassette("xpm_ruby/template/list") do
+ example.run
+ end
+ end
+
+ it "lists templates" do
+ template_list = service.list(access_token: access_token, xero_tenant_id: xero_tenant_id)
+
+ expect(template_list.length).to eq(11)
+
+ template = template_list.first
+
+ expect(template["Name"]).to eql("Activity Statement")
+ expect(template["ID"]).to eql("1254074")
+ end
+ end
+ end
+end
diff --git a/spec/xpm_ruby_spec.rb b/spec/xpm_ruby_spec.rb
index 7eee8e5..17a71b5 100644
--- a/spec/xpm_ruby_spec.rb
+++ b/spec/xpm_ruby_spec.rb
@@ -2,8 +2,4 @@
it "has a version number" do
expect(XpmRuby::VERSION).not_to be(nil)
end
-
- it "does something useful" do
- expect(true).to eq(true)
- end
end
diff --git a/xpm_ruby.gemspec b/xpm_ruby.gemspec
index 26bc43d..891803f 100644
--- a/xpm_ruby.gemspec
+++ b/xpm_ruby.gemspec
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
spec.summary = "Ruby gem for accessing the XPM API"
spec.homepage = "https://github.com/ignitionapp/xpm_ruby"
spec.license = "MIT"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.1.3")
spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
@@ -25,12 +25,23 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
- spec.add_development_dependency("bundler", "~> 2.0")
- spec.add_development_dependency("rake", ">= 12.3.3")
- spec.add_development_dependency("rspec", "~> 3.0")
+ spec.add_development_dependency("bundler")
+ spec.add_development_dependency("rake")
+ spec.add_development_dependency("rspec")
- spec.add_development_dependency("rubocop", "0.77.0")
+ spec.add_development_dependency("rubocop")
spec.add_development_dependency("rubocop-rspec")
+ spec.add_development_dependency("byebug", "~> 11")
+ spec.add_development_dependency("pry-byebug", "~> 3")
+ spec.add_development_dependency("vcr")
+
spec.add_runtime_dependency("faraday")
+ spec.add_runtime_dependency("faraday-encoding")
+ spec.add_runtime_dependency("ox", "~> 2.13")
+
+ spec.add_runtime_dependency("activesupport")
+ spec.add_runtime_dependency("builder")
+
+ spec.add_runtime_dependency("dry-types")
end