shipcloud 0.6.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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