shipcloud 0.6.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +1 -0
  3. data/.hound.yml +1 -1
  4. data/.rubocop.yml +713 -2
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +18 -6
  7. data/CHANGELOG.md +70 -0
  8. data/README.md +76 -8
  9. data/bin/rubocop +29 -0
  10. data/install-cc-test-reporter.sh +4 -0
  11. data/lib/shipcloud.rb +28 -14
  12. data/lib/shipcloud/address.rb +2 -1
  13. data/lib/shipcloud/operations/all.rb +12 -2
  14. data/lib/shipcloud/operations/create.rb +10 -2
  15. data/lib/shipcloud/operations/delete.rb +10 -2
  16. data/lib/shipcloud/operations/find.rb +10 -2
  17. data/lib/shipcloud/operations/update.rb +12 -4
  18. data/lib/shipcloud/pickup_request.rb +12 -0
  19. data/lib/shipcloud/request/base.rb +14 -10
  20. data/lib/shipcloud/request/connection.rb +18 -12
  21. data/lib/shipcloud/request/info.rb +7 -5
  22. data/lib/shipcloud/shipcloud_error.rb +70 -0
  23. data/lib/shipcloud/shipment.rb +3 -2
  24. data/lib/shipcloud/tracker.rb +13 -0
  25. data/lib/shipcloud/version.rb +1 -1
  26. data/lib/shipcloud/webhook.rb +2 -1
  27. data/shipcloud.gemspec +9 -8
  28. data/spec/shipcloud/address_spec.rb +114 -43
  29. data/spec/shipcloud/carrier_spec.rb +12 -5
  30. data/spec/shipcloud/pickup_request_spec.rb +136 -0
  31. data/spec/shipcloud/request/base_spec.rb +51 -13
  32. data/spec/shipcloud/request/connection_spec.rb +3 -3
  33. data/spec/shipcloud/request/info_spec.rb +34 -0
  34. data/spec/shipcloud/shipcloud_error_spec.rb +125 -0
  35. data/spec/shipcloud/shipment_quote_spec.rb +14 -1
  36. data/spec/shipcloud/shipment_spec.rb +126 -11
  37. data/spec/shipcloud/tracker_spec.rb +141 -0
  38. data/spec/shipcloud/webhooks_spec.rb +70 -6
  39. data/spec/shipcloud_spec.rb +82 -20
  40. data/spec/spec_helper.rb +2 -2
  41. metadata +55 -43
  42. data/.ruby-style.yml +0 -240
  43. data/lib/shipcloud/request/validator.rb +0 -33
  44. data/spec/shipcloud/request/validator_spec.rb +0 -24
@@ -5,9 +5,17 @@ module Shipcloud
5
5
  # Finds a given object
6
6
  #
7
7
  # @param [String] id The id of the object that should be found
8
+ # @param \[String\] optional api_key The api key. If no api key is given, Shipcloud.api_key
9
+ # will be used for the request
8
10
  # @return [Shipcloud::Base] The found object
9
- def find(id)
10
- response = Shipcloud.request(:get, "#{base_url}/#{id}", {})
11
+ def find(id, api_key: nil, affiliate_id: nil)
12
+ response = Shipcloud.request(
13
+ :get,
14
+ "#{base_url}/#{id}",
15
+ {},
16
+ api_key: api_key,
17
+ affiliate_id: affiliate_id,
18
+ )
11
19
  self.new(response)
12
20
  end
13
21
  end
@@ -6,8 +6,12 @@ module Shipcloud
6
6
  # Updates a object
7
7
  # @param [String] id The id of the object that should be updated
8
8
  # @param [Hash] attributes The attributes that should be updated
9
- def update(id, attributes)
10
- response = Shipcloud.request(:put, "#{base_url}/#{id}", attributes)
9
+ # @param \[String\] optional api_key The api key. If no api key is given, Shipcloud.api_key
10
+ # will be used for the request
11
+ def update(id, attributes, api_key: nil, affiliate_id: nil)
12
+ response = Shipcloud.request(
13
+ :put, "#{base_url}/#{id}", attributes, api_key: api_key, affiliate_id: affiliate_id
14
+ )
11
15
  self.new(response)
12
16
  end
13
17
  end
@@ -19,8 +23,12 @@ module Shipcloud
19
23
  # Updates a object
20
24
  #
21
25
  # @param [Hash] attributes The attributes that should be updated
22
- def update(attributes)
23
- response = Shipcloud.request(:put, "#{base_url}/#{id}", attributes)
26
+ # @param \[String\] optional api_key The api key. If no api key is given, Shipcloud.api_key
27
+ # will be used for the request
28
+ def update(attributes, api_key: nil, affiliate_id: nil)
29
+ response = Shipcloud.request(
30
+ :put, "#{base_url}/#{id}", attributes, api_key: api_key, affiliate_id: affiliate_id
31
+ )
24
32
  set_attributes(response)
25
33
  end
26
34
  end
@@ -0,0 +1,12 @@
1
+ module Shipcloud
2
+ class PickupRequest < Base
3
+ include Shipcloud::Operations::Create
4
+
5
+ attr_accessor :carrier, :pickup_time, :shipments, :pickup_address
6
+ attr_reader :id, :carrier_pickup_number
7
+
8
+ def self.base_url
9
+ "pickup_requests"
10
+ end
11
+ end
12
+ end
@@ -2,32 +2,36 @@ module Shipcloud
2
2
  module Request
3
3
  class Base
4
4
  attr_reader :info
5
- attr_accessor :response
6
5
 
7
6
  def initialize(info)
8
7
  @info = info
9
8
  end
10
9
 
11
10
  def perform
12
- raise AuthenticationError if Shipcloud.api_key.nil?
11
+ raise AuthenticationError unless @info.api_key
12
+
13
13
  connection.setup_https
14
- send_request
15
- validator.validated_data_for(response)
14
+ response = connection.request
15
+ validate_response(response)
16
+ JSON.parse(response.body) unless response.body.nil?
17
+ rescue JSON::ParserError
18
+ raise ShipcloudError.new(response)
16
19
  end
17
20
 
18
21
  protected
19
22
 
20
- def send_request
21
- self.response = connection.request
23
+ def validate_response(response)
24
+ error = ShipcloudError.from_response(response)
25
+ if error
26
+ raise error
27
+ end
22
28
  end
23
29
 
30
+ # rubocop:disable Naming/MemoizedInstanceVariableName
24
31
  def connection
25
32
  @connection ||= Connection.new(info)
26
33
  end
27
-
28
- def validator
29
- @validator ||= Validator.new(info)
30
- end
34
+ # rubocop:enable Naming/MemoizedInstanceVariableName
31
35
  end
32
36
  end
33
37
  end
@@ -20,7 +20,7 @@ module Shipcloud
20
20
  end
21
21
 
22
22
  def request
23
- https.start do |connection|
23
+ https.start do
24
24
  https.request(https_request)
25
25
  end
26
26
  end
@@ -28,17 +28,23 @@ module Shipcloud
28
28
  protected
29
29
 
30
30
  def https_request
31
- https_request = case @info.http_method
32
- when :post
33
- Net::HTTP::Post.new(@info.url, API_HEADERS)
34
- when :put
35
- Net::HTTP::Put.new(@info.url, API_HEADERS)
36
- when :delete
37
- Net::HTTP::Delete.new(@info.url, API_HEADERS)
38
- else
39
- Net::HTTP::Get.new(@info.path_with_params(@info.url, @info.data), API_HEADERS)
40
- end
41
- https_request.basic_auth(Shipcloud.api_key, "")
31
+ headers = Shipcloud.api_headers.merge("Affiliate-ID" => @info.affiliate_id)
32
+ https_request =
33
+ case @info.http_method
34
+ when :post
35
+ Net::HTTP::Post.new(@info.url, headers)
36
+ when :put
37
+ Net::HTTP::Put.new(@info.url, headers)
38
+ when :delete
39
+ Net::HTTP::Delete.new(@info.url, headers)
40
+ else
41
+ Net::HTTP::Get.new(
42
+ @info.path_with_params(@info.url, @info.data),
43
+ headers,
44
+ )
45
+ end
46
+
47
+ https_request.basic_auth(@info.api_key, "")
42
48
  https_request.body = @info.data.to_json if [:post, :put].include?(@info.http_method)
43
49
  https_request
44
50
  end
@@ -1,12 +1,14 @@
1
1
  module Shipcloud
2
2
  module Request
3
3
  class Info
4
- attr_accessor :http_method, :api_url, :data
4
+ attr_accessor :http_method, :api_url, :api_key, :data, :affiliate_id
5
5
 
6
- def initialize(http_method, api_url, data)
7
- @http_method = http_method
8
- @api_url = api_url
9
- @data = data
6
+ def initialize(http_method, api_url, api_key, data, affiliate_id)
7
+ @api_key = api_key
8
+ @http_method = http_method
9
+ @api_url = api_url
10
+ @data = data
11
+ @affiliate_id = affiliate_id
10
12
  end
11
13
 
12
14
  def url
@@ -0,0 +1,70 @@
1
+ module Shipcloud
2
+ class ShipcloudError < StandardError
3
+ attr_reader :errors, :response
4
+
5
+ def initialize(response = nil)
6
+ @response = response
7
+ @errors = parse_errors
8
+ error_message = errors.empty? ? response_body : errors
9
+ super(error_message)
10
+ end
11
+
12
+ # Returns the appropriate Shipcloud::ShipcloudError subclass based
13
+ # on status code
14
+ #
15
+ # @param [HTTPResponse] response HTTP response
16
+ # @return [Shipcloud::ShipcloudError]
17
+ def self.from_response(response)
18
+ response_code = response.code.to_i
19
+ if error_class = error_class_for(response_code)
20
+ error_class.new(response)
21
+ end
22
+ end
23
+
24
+ def self.error_class_for(response_code)
25
+ case response_code
26
+ when 400, 422 then InvalidRequestError
27
+ when 401 then AuthenticationError
28
+ when 402 then TooManyRequests
29
+ when 403 then ForbiddenError
30
+ when 404 then NotFoundError
31
+ when 400..499 then ClientError
32
+ when 500..599 then ServerError
33
+ end
34
+ end
35
+
36
+ private_class_method :error_class_for
37
+
38
+ private
39
+
40
+ def parse_errors
41
+ return [] unless response_body
42
+
43
+ data = JSON.parse(response_body)
44
+ if data.is_a?(Hash) && data["errors"]
45
+ data["errors"]
46
+ else
47
+ []
48
+ end
49
+ rescue JSON::ParserError
50
+ []
51
+ end
52
+
53
+ def response_body
54
+ return unless @response
55
+
56
+ @response.body
57
+ end
58
+ end
59
+
60
+ # Raised on errors in the 400-499 range
61
+ class ClientError < ShipcloudError; end
62
+ class AuthenticationError < ClientError; end
63
+ class ForbiddenError < ClientError; end
64
+ class InvalidRequestError < ClientError; end
65
+ class TooManyRequests < ClientError; end
66
+ class NotFoundError < ClientError; end
67
+
68
+ # Raised on errors in the 500-599 range
69
+ class ServerError < ShipcloudError; end
70
+ end
@@ -4,8 +4,9 @@ module Shipcloud
4
4
  include Shipcloud::Operations::Update
5
5
  include Shipcloud::Operations::All
6
6
 
7
- attr_accessor :from, :to, :carrier, :package, :reference_number
8
- attr_reader :id, :created_at, :carrier_tracking_no, :tracking_url, :label_url, :packages, :price
7
+ attr_accessor :from, :to, :carrier, :package, :reference_number, :metadata
8
+ attr_reader :id, :created_at, :carrier_tracking_no, :tracking_url, :label_url,
9
+ :packages, :price, :customs_declaration, :pickup
9
10
 
10
11
  def self.index_response_root
11
12
  "#{class_name.downcase}s"
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ module Shipcloud
3
+ class Tracker < Base
4
+ include Shipcloud::Operations::All
5
+
6
+ attr_accessor :carrier, :carrier_tracking_no
7
+ attr_reader :id
8
+
9
+ def self.index_response_root
10
+ "#{class_name.downcase}s"
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module Shipcloud
2
- VERSION = "0.6.0"
2
+ VERSION = "0.11.0".freeze
3
3
  end
@@ -1,8 +1,9 @@
1
1
  module Shipcloud
2
2
  class Webhook < Base
3
3
  include Shipcloud::Operations::All
4
+ include Shipcloud::Operations::Delete
4
5
 
5
- attr_reader :url, :event_types
6
+ attr_reader :id, :url, :event_types, :deactivated
6
7
 
7
8
  def self.index_response_root
8
9
  "webhooks"
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
2
+ lib = File.expand_path("lib", __dir__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require "shipcloud/version"
5
5
 
@@ -19,13 +19,14 @@ Gem::Specification.new do |spec|
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.required_ruby_version = ">= 2.0"
22
+ spec.required_ruby_version = ">= 2.3"
23
23
 
24
- spec.add_runtime_dependency "json", "~> 1.8", ">= 1.8.0"
25
- spec.add_development_dependency "bundler", ">= 1.3.0", "< 2.0"
26
- spec.add_development_dependency "rake", "~> 10.3"
27
- spec.add_development_dependency "rspec", "~> 2.99"
28
- spec.add_development_dependency "webmock", "~> 1.18"
24
+ spec.add_runtime_dependency "json", ">= 1.8.0"
29
25
  spec.add_development_dependency "pry", "~> 0.10"
30
- spec.add_development_dependency "codeclimate-test-reporter"
26
+ spec.add_development_dependency "rake", "~> 12.0"
27
+ spec.add_development_dependency "rspec", "~> 3.6"
28
+ spec.add_development_dependency "rubocop", "~> 0.71.0"
29
+ spec.add_development_dependency "rubocop-performance"
30
+ spec.add_development_dependency "simplecov"
31
+ spec.add_development_dependency "webmock", "~> 3.0"
31
32
  end
@@ -13,7 +13,8 @@ describe Shipcloud::Address do
13
13
  city: 'Hamburg',
14
14
  state: 'Hamburg',
15
15
  country: 'DE',
16
- phone: '040/123456789'
16
+ phone: '040/123456789',
17
+ email: 'max@mustermail.com',
17
18
  }
18
19
 
19
20
  describe '#initialize' do
@@ -30,36 +31,79 @@ describe Shipcloud::Address do
30
31
  expect(address.state).to eq 'Hamburg'
31
32
  expect(address.country).to eq 'DE'
32
33
  expect(address.phone).to eq '040/123456789'
34
+ expect(address.email).to eq 'max@mustermail.com'
33
35
  end
34
36
  end
35
37
 
36
38
  describe '.create' do
37
39
  it 'makes a new POST request using the correct API endpoint' do
38
- Shipcloud.should_receive(:request).with(:post, 'addresses', valid_attributes).and_return('data' => {})
40
+ expect(Shipcloud).to receive(:request).
41
+ with(:post, "addresses", valid_attributes, api_key: nil, affiliate_id: nil).
42
+ and_return("data" => {})
43
+
39
44
  Shipcloud::Address.create(valid_attributes)
40
45
  end
46
+
47
+ it "returns an address containing an id" do
48
+ expect(Shipcloud).to receive(:request).
49
+ with(:post, "addresses", valid_attributes, api_key: nil, affiliate_id: nil).
50
+ and_return(returned_address)
51
+
52
+ address = Shipcloud::Address.create(valid_attributes)
53
+
54
+ expect(address.id).to eq("1c81efb7-9b95-4dd8-92e3-cac1bca3df6f")
55
+ end
56
+
57
+ it "use the affiliate ID provided for the request" do
58
+ expect(Shipcloud).to receive(:request).
59
+ with(:post, "addresses", valid_attributes, api_key: nil, affiliate_id: "affiliate_id").
60
+ and_return(returned_address)
61
+
62
+ address = Shipcloud::Address.create(valid_attributes, affiliate_id: "affiliate_id")
63
+
64
+ expect(address.id).to eq("1c81efb7-9b95-4dd8-92e3-cac1bca3df6f")
65
+ end
41
66
  end
42
67
 
43
68
  describe '.find' do
44
69
  it 'makes a new GET request using the correct API endpoint to receive a specific address' do
45
- Shipcloud.should_receive(:request).with(
46
- :get, 'addresses/123', {}).and_return('id' => '123')
47
- Shipcloud::Address.find('123')
70
+ expect(Shipcloud).to receive(:request).with(
71
+ :get, "addresses/123", {}, api_key: nil, affiliate_id: nil).and_return("id" => "123")
72
+
73
+ Shipcloud::Address.find("123")
74
+ end
75
+
76
+ it "use the affiliate ID provided for the request" do
77
+ expect(Shipcloud).to receive(:request).with(
78
+ :get, "addresses/123", {}, api_key: nil, affiliate_id: "affiliate_id"
79
+ ).and_return("id" => "123")
80
+
81
+ Shipcloud::Address.find("123", affiliate_id: "affiliate_id")
48
82
  end
49
83
  end
50
84
 
51
85
  describe '.update' do
52
86
  it 'makes a new PUT request using the correct API endpoint' do
53
- Shipcloud.should_receive(:request).with(
54
- :put, 'addresses/123', {:street => 'Mittelweg' }).and_return('data' => {})
55
- Shipcloud::Address.update('123', {:street => 'Mittelweg' })
87
+ expect(Shipcloud).to receive(:request).with(
88
+ :put, "addresses/123", { street: "Mittelweg" }, api_key: nil, affiliate_id: nil
89
+ ).and_return("data" => {})
90
+
91
+ Shipcloud::Address.update("123", street: "Mittelweg")
92
+ end
93
+
94
+ it "use the affiliate ID provided for the request" do
95
+ expect(Shipcloud).to receive(:request).with(
96
+ :put, "addresses/123", { street: "Mittelweg" }, api_key: nil, affiliate_id: "affiliate_id"
97
+ ).and_return("data" => {})
98
+
99
+ Shipcloud::Address.update("123", { street: "Mittelweg" }, affiliate_id: "affiliate_id")
56
100
  end
57
101
  end
58
102
 
59
103
  describe '.all' do
60
104
  it 'makes a new Get request using the correct API endpoint' do
61
105
  expect(Shipcloud).to receive(:request).
62
- with(:get, 'addresses', {}).and_return([])
106
+ with(:get, "addresses", {}, api_key: nil, affiliate_id: nil).and_return([])
63
107
 
64
108
  Shipcloud::Address.all
65
109
  end
@@ -73,42 +117,69 @@ describe Shipcloud::Address do
73
117
  expect(address).to be_a Shipcloud::Address
74
118
  end
75
119
  end
120
+
121
+ it "use the affiliate ID provided for the request" do
122
+ stub_addresses_request(affiliate_id: "affiliate_id")
123
+
124
+ addresses = Shipcloud::Address.all(affiliate_id: "affiliate_id")
125
+
126
+ addresses.each do |address|
127
+ expect(address).to be_a Shipcloud::Address
128
+ end
129
+ end
76
130
  end
77
131
 
78
- def stub_addresses_request
132
+ def stub_addresses_request(affiliate_id: nil)
79
133
  allow(Shipcloud).to receive(:request).
80
- with(:get, 'addresses', {}).
81
- and_return(
82
- [
83
- {
84
- 'id' => '1c81efb7-9b95-4dd8-92e3-cac1bca3df6f',
85
- 'company' => '',
86
- 'first_name' => 'Max',
87
- 'last_name' => 'Mustermann',
88
- 'care_of' => '',
89
- 'street' => 'Musterstraße',
90
- 'street_no' => '42',
91
- 'zip_code' => '12345',
92
- 'city' => 'Musterstadt',
93
- 'state' => '',
94
- 'country' => 'DE',
95
- 'phone' => ''
96
- },
97
- {
98
- 'id' => '7ea2a290-b456-4ecf-9010-e82b3da298f0',
99
- 'company' => 'Muster-Company',
100
- 'first_name' => 'Max',
101
- 'last_name' => 'Mustermann',
102
- 'care_of' => '',
103
- 'street' => 'Musterstraße',
104
- 'street_no' => '42',
105
- 'zip_code' => '54321',
106
- 'city' => 'Musterstadt',
107
- 'state' => '',
108
- 'country' => 'DE',
109
- 'phone' => ''
110
- }
111
- ]
112
- )
134
+ with(:get, "addresses", {}, api_key: nil, affiliate_id: affiliate_id).
135
+ and_return(
136
+ [
137
+ {
138
+ "id" => "1c81efb7-9b95-4dd8-92e3-cac1bca3df6f",
139
+ "company" => "",
140
+ "first_name" => "Max",
141
+ "last_name" => "Mustermann",
142
+ "care_of" => "",
143
+ "street" => "Musterstraße",
144
+ "street_no" => "42",
145
+ "zip_code" => "12345",
146
+ "city" => "Musterstadt",
147
+ "state" => "",
148
+ "country" => "DE",
149
+ "phone" => ""
150
+ },
151
+ {
152
+ "id" => "7ea2a290-b456-4ecf-9010-e82b3da298f0",
153
+ "company" => "Muster-Company",
154
+ "first_name" => "Max",
155
+ "last_name" => "Mustermann",
156
+ "care_of" => "",
157
+ "street" => "Musterstraße",
158
+ "street_no" => "42",
159
+ "zip_code" => "54321",
160
+ "city" => "Musterstadt",
161
+ "state" => "",
162
+ "country" => "DE",
163
+ "phone" => ""
164
+ }
165
+ ]
166
+ )
167
+ end
168
+
169
+ def returned_address
170
+ {
171
+ "id" => "1c81efb7-9b95-4dd8-92e3-cac1bca3df6f",
172
+ "company" => "shipcloud GmbH",
173
+ "first_name" => "Maxi",
174
+ "last_name" => "Musterfrau",
175
+ "care_of" => "Mustermann",
176
+ "street" => "Musterstraße",
177
+ "street_no" => "123",
178
+ "zip_code" => "12345",
179
+ "city" => "Hamburg",
180
+ "state" => "Hamburg",
181
+ "country" => "DE",
182
+ "phone" => "040/123456789",
183
+ }
113
184
  end
114
185
  end