diff --git a/Gemfile.lock b/Gemfile.lock index f3b7ba6..9c5fd3d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -4,6 +4,7 @@ PATH xpm_ruby (0.1.0) activesupport builder + dry-types faraday ox (~> 2.13) @@ -22,6 +23,28 @@ GEM coderay (1.1.2) concurrent-ruby (1.1.6) diff-lcs (1.3) + dry-configurable (0.11.5) + concurrent-ruby (~> 1.0) + dry-core (~> 0.4, >= 0.4.7) + dry-equalizer (~> 0.2) + dry-container (0.7.2) + concurrent-ruby (~> 1.0) + dry-configurable (~> 0.1, >= 0.1.3) + dry-core (0.4.9) + concurrent-ruby (~> 1.0) + dry-equalizer (0.3.0) + dry-inflector (0.2.0) + dry-logic (0.6.1) + concurrent-ruby (~> 1.0) + dry-core (~> 0.2) + dry-equalizer (~> 0.2) + dry-types (0.15.0) + concurrent-ruby (~> 1.0) + dry-container (~> 0.3) + dry-core (~> 0.4, >= 0.4.4) + dry-equalizer (~> 0.2, >= 0.2.2) + dry-inflector (~> 0.1, >= 0.1.2) + dry-logic (~> 0.5, >= 0.5) faraday (1.0.1) multipart-post (>= 1.2, < 3) i18n (1.8.2) diff --git a/lib/xpm_ruby.rb b/lib/xpm_ruby.rb index 491f2b7..bb1b63d 100644 --- a/lib/xpm_ruby.rb +++ b/lib/xpm_ruby.rb @@ -10,6 +10,7 @@ class Unauthorized < Error; end require "xpm_ruby/client" require "xpm_ruby/connection" require "xpm_ruby/job" +require "xpm_ruby/schema/job/add" require "xpm_ruby/staff" require "xpm_ruby/template" require "xpm_ruby/version" diff --git a/lib/xpm_ruby/job.rb b/lib/xpm_ruby/job.rb index a29d9de..cc8e3b5 100644 --- a/lib/xpm_ruby/job.rb +++ b/lib/xpm_ruby/job.rb @@ -17,5 +17,15 @@ def current(access_token:, xero_tenant_id:) response["Jobs"]["Job"] end + + def add(access_token:, xero_tenant_id:, job:) + validated_job = XpmRuby::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 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..22757ca --- /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 + ) + 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/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/xpm_ruby/job_spec.rb b/spec/xpm_ruby/job_spec.rb index 553804a..34da5b7 100644 --- a/spec/xpm_ruby/job_spec.rb +++ b/spec/xpm_ruby/job_spec.rb @@ -29,5 +29,27 @@ module XpmRuby expect(first_job["CompletedDate"]).to be_nil end end + + describe ".add" do + let(:xero_tenant_id) { "0791dc22-8611-4c1c-8df7-1c5453d0795b" } + let(:access_token) { "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE1ODgyMDg3MjksImV4cCI6MTU4ODIxMDUyOSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiNDkyMjZBNjIzMzY0NDVFM0FGQUM5QTQ4MkJGOUUyN0UiLCJzdWIiOiIwY2FmMWU4MWYyZWE1MzdkYWIxYjYzNTY3NTc2ZDk3ZSIsImF1dGhfdGltZSI6MTU4ODIwODU3NSwieGVyb191c2VyaWQiOiJmYzI5MDBjNy0wNjcyLTQzOGItOTNkMS1hOGMyNTBmZDg5MjkiLCJnbG9iYWxfc2Vzc2lvbl9pZCI6IjZmYWRiYTVmYWI3NTQ0NDliNjkwMGE1NzI3OGVlMjc5IiwianRpIjoiZmU2MjUyNzNhNmEwMTI4YjI2N2IxYmI1YWQzMGVkODgiLCJzY29wZSI6WyJlbWFpbCIsInByb2ZpbGUiLCJvcGVuaWQiLCJwcmFjdGljZW1hbmFnZXIiLCJvZmZsaW5lX2FjY2VzcyJdfQ.iL5C3Lcc1KuxTcIMUNUdKfqRoB13flB46dyQ2fUcQesF_lloofR9qWzt1uijc91qQPnkyrgb_Kv2aGvR3YvXXM1naK2Wy87wfAJwonkAGm6IcIIeukgvvJMt3bNZvow-lrk2eb9Wfcz7xt_nJSqL9lr8YV9T5f56IWJzZJzwAiNYz4F1lmqzKMwX5fUU9gYHucgIgQAwDaD3AGPdB-AC71ZNw2Zwsshebv89CbSbpw7rGU9gEhHnI7PjXXYwRn430Zh9k0ruD7IQWNRMh26oS_PR4zIEFDGBn5xBdnm9jLWl9juQUkn0OPQvAwkEuM54AXSWaAgyeasdOtDNjD8JMA" } + 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 "lists adds a job" do + added_job = service.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 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..33cbff2 --- /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::ConstraintError, '{"Name"=>"Joe Bloggs"} violates constraints (:Description is missing in Hash input failed)') + end + end + end + end +end diff --git a/xpm_ruby.gemspec b/xpm_ruby.gemspec index fad5f02..2e4a862 100644 --- a/xpm_ruby.gemspec +++ b/xpm_ruby.gemspec @@ -42,4 +42,6 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency("activesupport") spec.add_runtime_dependency("builder") + + spec.add_runtime_dependency("dry-types") end