after_ship 0.0.2 → 0.0.4

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.
@@ -0,0 +1,45 @@
1
+ class AfterShip
2
+ # Wrapper object for AfterShip courier:
3
+ # https://www.aftership.com/docs/api/4/couriers/get-couriers
4
+ class Courier
5
+ include Attributes
6
+
7
+ # Unique code of courier.
8
+ #
9
+ # @return [String]
10
+ attr_accessor :slug
11
+
12
+ # Name of courier.
13
+ #
14
+ # @return [String]
15
+ attr_accessor :name
16
+
17
+ # Contact phone number of courier.
18
+ #
19
+ # @return [String]
20
+ attr_accessor :phone
21
+
22
+ # Other name of courier.
23
+ #
24
+ # @return [String]
25
+ attr_accessor :other_name
26
+
27
+ # Website link of courier.
28
+ #
29
+ # @return [String]
30
+ attr_accessor :web_url
31
+
32
+ # The extra fields need for tracking, such as `tracking_account_number`,
33
+ # `tracking_postal_code`, `tracking_ship_date`.
34
+ #
35
+ # @return [Array]
36
+ attr_accessor :required_fields
37
+
38
+ # Better interface for a courier.
39
+ #
40
+ # @param data [Hash] tracking hash
41
+ def initialize(data)
42
+ load_attributes(data)
43
+ end
44
+ end
45
+ end
@@ -1,6 +1,6 @@
1
1
  class AfterShip
2
2
  # Wrapper object for AfterShip tracking:
3
- # https://www.aftership.com/docs/api/3.0/tracking/get-trackings-slug-tracking_number
3
+ # https://www.aftership.com/docs/api/4/trackings/get-trackings-slug-tracking_number
4
4
  class Tracking
5
5
  include Attributes
6
6
 
@@ -14,27 +14,59 @@ class AfterShip
14
14
  # @return [DateTime]
15
15
  attr_reader :updated_at
16
16
 
17
+ # A unique identifier generated by AfterShip for the tracking.
18
+ #
19
+ # @return [String]
20
+ attr_accessor :id
21
+
17
22
  # Tracking number, e.g. +1ZA2207X6794165804+.
18
23
  #
19
24
  # @return [String]
20
25
  attr_accessor :tracking_number
21
26
 
27
+ # The postal code of receiver's address. Required by some couriers, such
28
+ # as +deutsch-post+.
29
+ #
30
+ # @return [String]
31
+ attr_accessor :tracking_postal_code
32
+
33
+ # Shipping date in +YYYYMMDD+ format. Required by some couriers, such as
34
+ # +deutsch-post+.
35
+ #
36
+ # @return [String]
37
+ attr_reader :tracking_ship_date
38
+
39
+ # Account number of the shipper for a specific courier. Required by some
40
+ # couriers, such as +dynamic-logistics+.
41
+ #
42
+ # @return [String]
43
+ attr_accessor :tracking_account_number
44
+
22
45
  # Unique code of courier.
23
46
  #
24
47
  # @return [String]
25
48
  attr_reader :slug
26
49
 
27
- # Courier name
50
+ # Courier name.
51
+ #
52
+ # Custom method!
28
53
  #
29
54
  # @return [String]
30
55
  attr_accessor :courier
31
56
 
32
57
  # Whether or not AfterShip will continue tracking the shipments. Value is
33
- # +false+ when status is +Delivered+ or +Expired+.
58
+ # +false+ when tag (status) is +Delivered+, +Expired+, or further updates
59
+ # for 30 days since last update.
34
60
  #
35
- # @return [Boolean]
61
+ # @return [Bool]
36
62
  attr_accessor :active
37
63
 
64
+ # Google cloud message registration IDs to receive the push notifications.
65
+ # Accept either array or Comma comma separated as input.
66
+ #
67
+ # @return [Array, String]
68
+ attr_accessor :android
69
+
38
70
  # Custom fields of the tracking.
39
71
  #
40
72
  # @return [Hash]
@@ -45,6 +77,19 @@ class AfterShip
45
77
  # @return [String]
46
78
  attr_accessor :customer_name
47
79
 
80
+ # Total delivery time in days.
81
+ #
82
+ # * Difference of 1st checkpoint time and delivered time for delivered
83
+ # shipments.
84
+ # * Difference of 1st checkpoint time and current time for non-delivered
85
+ # shipments.
86
+ #
87
+ # Value as +0+ for pending shipments or delivered shipment with only one
88
+ # checkpoint.
89
+ #
90
+ # @return [Fixnum]
91
+ attr_accessor :delivery_time
92
+
48
93
  # Destination country of the tracking. ISO Alpha-3 (three letters). If you
49
94
  # use postal service to send international shipments, AfterShip will
50
95
  # automatically get tracking results from destination postal service based
@@ -69,6 +114,12 @@ class AfterShip
69
114
  # @return [DateTime]
70
115
  attr_reader :expected_delivery
71
116
 
117
+ # Apple iOS device IDs to receive the push notificaitons.
118
+ # Accept either array or Comma comma separated as input.
119
+ #
120
+ # @return [Array, String]
121
+ attr_accessor :ios
122
+
72
123
  # Text field for order ID.
73
124
  #
74
125
  # @return [String]
@@ -84,8 +135,9 @@ class AfterShip
84
135
  # @return [String]
85
136
  attr_accessor :origin_country_iso3
86
137
 
87
- # You can use the value, to direct access the tracking result at this url:
88
- # https://yourusername.aftership.com/unique_token
138
+ # The token to generate the direct tracking link:
139
+ # https://yourusername.aftership.com/unique_token or
140
+ # https://www.aftership.com/unique_token.
89
141
  #
90
142
  # @return [String]
91
143
  attr_accessor :unique_token
@@ -100,6 +152,16 @@ class AfterShip
100
152
  # @return [String]
101
153
  attr_accessor :shipment_type
102
154
 
155
+ # Shipment weight provied by carrier (if any).
156
+ #
157
+ # @return [Fixnum]
158
+ attr_accessor :shipment_weight
159
+
160
+ # Weight unit provied by carrier, either in +kg+ or +lb+ (if any).
161
+ #
162
+ # @return [String]
163
+ attr_accessor :shipment_weight_unit
164
+
103
165
  # Signed by information for delivered shipment (if any).
104
166
  #
105
167
  # @return [String]
@@ -129,6 +191,8 @@ class AfterShip
129
191
 
130
192
  # Same as tag, except human-friendly:
131
193
  #
194
+ # Custom method!
195
+ #
132
196
  # * +Pending+ => +Pending+
133
197
  # * +InfoReceived+ => +Info Received+
134
198
  # * +InTransit+ => +In Transit+
@@ -178,6 +242,14 @@ class AfterShip
178
242
  @updated_at = DateTime.parse(value)
179
243
  end
180
244
 
245
+ # Shipping date in +YYYYMMDD+ format. Required by some couriers, such as
246
+ # +deutsch-post+.
247
+ #
248
+ # @return [DateTime]
249
+ def tracking_ship_date=(value)
250
+ @tracking_ship_date = DateUtils.parse(value)
251
+ end
252
+
181
253
  # Unique code of courier.
182
254
  #
183
255
  # @return [String]
data/lib/after_ship.rb CHANGED
@@ -1,118 +1,48 @@
1
+ # Gems.
1
2
  require 'typhoeus'
2
3
  require 'multi_json'
3
4
 
4
- require 'attributes'
5
- require 'date_utils'
6
- require 'after_ship/version'
5
+ # Core classes.
6
+ require 'after_ship/core/version'
7
+ require 'after_ship/core/attributes'
8
+ require 'after_ship/core/date_utils'
9
+ require 'after_ship/core/request'
10
+ require 'after_ship/core/error'
11
+ require 'after_ship/core/error_handler'
12
+
13
+ # AfterShip classes.
7
14
  require 'after_ship/tracking'
8
15
  require 'after_ship/checkpoint'
16
+ require 'after_ship/courier'
9
17
 
10
- # Init the client:
18
+ # Quick rundown, check individual methods for more info:
11
19
  #
12
20
  # client = AfterShip.new(api_key: 'your-aftership-api-key')
13
- #
14
- # Get a list of trackings
15
- # https://www.aftership.com/docs/api/3.0/tracking/get-trackings
16
- #
17
21
  # client.trackings
18
- #
19
- # # Will return list of Tracking objects:
20
- #
21
- # [
22
- # #<AfterShip::Tracking ...>,
23
- # #<AfterShip::Tracking ...>,
24
- # ...
25
- # ]
26
- #
27
- # Get a tracking
28
- # https://www.aftership.com/docs/api/3.0/tracking/get-trackings-slug-tracking_number
29
- #
30
22
  # client.tracking('tracking-number', 'ups')
31
- #
32
- # # Will return Tracking object or raise AfterShip::ResourceNotFoundError
33
- # # if not exists:
34
- #
35
- # #<AfterShip::Tracking:0x007fe555bd9560
36
- # @active=false,
37
- # @courier="UPS",
38
- # @created_at=#<DateTime: 2014-05-08T15:25:01+00:00 ...>,
39
- # @updated_at=#<DateTime: 2014-07-18T09:00:47+00:00 ...>>
40
- # @custom_fields={},
41
- # @customer_name=nil,
42
- # @destination_country_iso3="USA",
43
- # @emails=[],
44
- # @expected_delivery=nil,
45
- # @order_id="PL-12480166",
46
- # @order_id_path=nil,
47
- # @origin_country_iso3="IND",
48
- # @shipment_package_count=0,
49
- # @shipment_type="EXPEDITED",
50
- # @signed_by="FRONT DOOR",
51
- # @slug="ups",
52
- # @smses=[],
53
- # @source="api",
54
- # @status="Delivered",
55
- # @tag="Delivered",
56
- # @title="1ZA2207X6790326683",
57
- # @tracked_count=47,
58
- # @tracking_number="1ZA2207X6790326683",
59
- # @unique_token="ly9ueXUJC",
60
- # @checkpoints=[
61
- # #<AfterShip::Checkpoint:0x007fe555bb0340
62
- # @checkpoint_time=#<DateTime: 2014-05-12T14:07:00+00:00 ...>,
63
- # @city="NEW YORK",
64
- # @country_iso3=nil,
65
- # @country_name="US",
66
- # @courier="UPS",
67
- # @created_at=#<DateTime: 2014-05-12T18:34:32+00:00 ...>,
68
- # @message="DELIVERED",
69
- # @slug="ups",
70
- # @state="NY",
71
- # @status="Delivered",
72
- # @tag="Delivered",
73
- # @zip="10075">
74
- # #<AfterShip::Checkpoint ...>,
75
- # ...
76
- # ]>
77
- #
78
- # Create a new tracking
79
- # https://www.aftership.com/docs/api/3.0/tracking/post-trackings
80
- #
81
23
  # client.create_tracking('tracking-number', 'ups', order_id: 'external-id')
82
- #
83
- # # Will return Tracking object or raise AfterShip::InvalidArgumentError
84
- # # if it exists:
85
- #
86
- # #<AfterShip::Tracking ...>
87
- #
88
- # Update a tracking
89
- # https://www.aftership.com/docs/api/3.0/tracking/put-trackings-slug-tracking_number
90
- #
91
24
  # client.update_tracking('tracking-number', 'ups', order_id: 'external-id')
25
+ # client.couriers
92
26
  #
93
27
  # To debug:
94
28
  #
95
29
  # AfterShip.debug = true
96
30
  #
97
- # client.tracking('9405903699300211343566', 'usps') # In transit
98
- # client.tracking('1ZA2207X6794165804', 'ups') # Delivered, wild
99
- # client.tracking('1ZA2207X6791425225', 'ups') # Delivered, ok
100
- # client.tracking('1ZA2207X6790326683', 'ups') # Delivered, ok
31
+ # Some test trackings:
32
+ #
33
+ # client.tracking('1ZA2207X0444990982', 'ups')
101
34
  class AfterShip
102
- class Error < StandardError; end
103
- class InvalidJSONDataError < Error; end # 400
104
- class InvalidCredentialsError < Error; end # 401
105
- class RequestFailedError < Error; end # 402
106
- class ResourceNotFoundError < Error; end # 404
107
- class InvalidArgumentError < Error; end # 409
108
- class TooManyRequestsError < Error; end # 429
109
- class ServerError < Error; end # 500, 502, 503, 504
110
- class UnknownError < Error; end
35
+ # The API root URL.
36
+ DEFAULT_API_ADDRESS = 'https://api.aftership.com/v4'
111
37
 
112
- DEFAULT_API_ADDRESS = 'https://api.aftership.com/v3'
113
- TRACKINGS_ENDPOINT = "#{ DEFAULT_API_ADDRESS }/trackings"
38
+ # The trackings endpoint URL.
39
+ TRACKINGS_ENDPOINT = "#{ DEFAULT_API_ADDRESS }/trackings"
114
40
 
115
- JSON_OPTIONS = {
41
+ # The activated couriers endpoint URL.
42
+ COURIERS_ENDPOINT = "#{ DEFAULT_API_ADDRESS }/couriers"
43
+
44
+ # Common JSON loading/dumping options.
45
+ JSON_OPTIONS = {
116
46
  symbolize_keys: true # Symbol keys to string keys
117
47
  }
118
48
 
@@ -136,49 +66,127 @@ class AfterShip
136
66
  attr_accessor :debug
137
67
  end
138
68
 
69
+ # The API key required for the AfterShip service.
70
+ #
71
+ # @return [String]
139
72
  attr_reader :api_key
140
73
 
74
+ # Init the client:
75
+ #
76
+ # client = AfterShip.new(api_key: 'your-aftership-api-key')
77
+ #
141
78
  # @param options [Hash]
142
- # api_key [String]
79
+ # @option options api_key [String]
143
80
  def initialize(options)
144
- require_arguments(
145
- api_key: options[:api_key]
146
- )
147
-
148
- @api_key = options.delete(:api_key)
81
+ @api_key = options.fetch(:api_key)
149
82
  end
150
83
 
151
84
  # Get a list of trackings.
152
- # https://www.aftership.com/docs/api/3.0/tracking/get-trackings
85
+ # https://www.aftership.com/docs/api/4/trackings/get-trackings
86
+ #
87
+ # client.trackings
88
+ #
89
+ # # Will return list of Tracking objects:
90
+ #
91
+ # [
92
+ # #<AfterShip::Tracking ...>,
93
+ # #<AfterShip::Tracking ...>,
94
+ # ...
95
+ # ]
153
96
  #
154
97
  # @return [Hash]
155
98
  def trackings
156
- response = request_response(TRACKINGS_ENDPOINT, {}, :get)
157
- data = response.fetch(:data).fetch(:trackings)
99
+ data = Request.get(url: TRACKINGS_ENDPOINT, api_key: api_key) do |response|
100
+ response.fetch(:data).fetch(:trackings)
101
+ end
158
102
 
159
103
  data.map { |datum| Tracking.new(datum) }
160
104
  end
161
105
 
162
106
  # Get a single tracking. Raises an error if not found.
163
- # https://www.aftership.com/docs/api/3.0/tracking/get-trackings-slug-tracking_number
107
+ # https://www.aftership.com/docs/api/4/trackings/get-trackings-slug-tracking_number
108
+ #
109
+ # client.tracking('tracking-number', 'ups')
110
+ #
111
+ # # Will return Tracking object or raise AfterShip::Error::NotFound:
112
+ #
113
+ # #<AfterShip::Tracking:0x007f838ef44e58
114
+ # @active=false,
115
+ # @android=[],
116
+ # @courier="UPS",
117
+ # @created_at=#<DateTime: 2014-11-19T15:16:17+00:00 ...>,
118
+ # @custom_fields={},
119
+ # @customer_name=nil,
120
+ # @delivery_time=8,
121
+ # @destination_country_iso3="USA",
122
+ # @emails=[],
123
+ # @expected_delivery=nil,
124
+ # @id="546cb4414a1a2097122ae7b1",
125
+ # @ios=[],
126
+ # @order_id="PL-66448782",
127
+ # @order_id_path=nil,
128
+ # @origin_country_iso3="IND",
129
+ # @shipment_package_count=1,
130
+ # @shipment_type="UPS SAVER",
131
+ # @shipment_weight=0.5,
132
+ # @shipment_weight_unit="kg",
133
+ # @signed_by="MET CUSTOM",
134
+ # @slug="ups",
135
+ # @smses=[],
136
+ # @source="api",
137
+ # @status="Delivered",
138
+ # @tag="Delivered",
139
+ # @title="1ZA2207X0490715335",
140
+ # @tracked_count=6,
141
+ # @tracking_account_number=nil,
142
+ # @tracking_number="1ZA2207X0490715335",
143
+ # @tracking_postal_code=nil,
144
+ # @tracking_ship_date=nil,
145
+ # @unique_token="-y6ziF438",
146
+ # @updated_at=#<DateTime: 2014-11-19T22:12:32+00:00 ...>,
147
+ # @checkpoints=[
148
+ # #<AfterShip::Checkpoint:0x007f838ef57d50
149
+ # @checkpoint_time=
150
+ # #<DateTime: 2014-11-11T19:12:00+00:00 ...>,
151
+ # @city="MUMBAI",
152
+ # @country_iso3=nil,
153
+ # @country_name="IN",
154
+ # @courier="UPS",
155
+ # @created_at=
156
+ # #<DateTime: 2014-11-19T15:16:17+00:00 ...>,
157
+ # @message="PICKUP SCAN",
158
+ # @slug="ups",
159
+ # @state=nil,
160
+ # @status="In Transit",
161
+ # @tag="InTransit",
162
+ # @zip=nil>,
163
+ # #<AfterShip::Checkpoint ...>,
164
+ # ...
165
+ # ]
166
+ # >
164
167
  #
165
168
  # @param tracking_number [String]
166
169
  # @param courier [String]
167
170
  #
168
171
  # @return [Hash]
169
172
  def tracking(tracking_number, courier)
170
- require_arguments(tracking_number: tracking_number, courier: courier)
171
-
172
- url = "#{ TRACKINGS_ENDPOINT }/#{ courier }/#{ tracking_number }"
173
-
174
- response = request_response(url, {}, :get)
175
- data = response.fetch(:data).fetch(:tracking)
173
+ url = "#{ TRACKINGS_ENDPOINT }/#{ courier }/#{ tracking_number }"
174
+ data = Request.get(url: url, api_key: api_key) do |response|
175
+ response.fetch(:data).fetch(:tracking)
176
+ end
176
177
 
177
178
  Tracking.new(data)
178
179
  end
179
180
 
180
181
  # Create a new tracking.
181
- # https://www.aftership.com/docs/api/3.0/tracking/post-trackings
182
+ # https://www.aftership.com/docs/api/4/trackings/post-trackings
183
+ #
184
+ # client.create_tracking('tracking-number', 'ups', order_id: 'external-id')
185
+ #
186
+ # # Will return Tracking object or raise
187
+ # # AfterShip::Error::TrackingAlreadyExists:
188
+ #
189
+ # #<AfterShip::Tracking ...>
182
190
  #
183
191
  # @param tracking_number [String]
184
192
  # @param courier [String]
@@ -186,22 +194,30 @@ class AfterShip
186
194
  #
187
195
  # @return [Hash]
188
196
  def create_tracking(tracking_number, courier, options = {})
189
- require_arguments(tracking_number: tracking_number, courier: courier)
190
-
191
- params = {
197
+ body = {
192
198
  tracking: {
193
199
  tracking_number: tracking_number,
194
200
  slug: courier
195
201
  }.merge(options)
196
202
  }
197
203
 
198
- response = request_response(TRACKINGS_ENDPOINT, params, :post)
199
- data = response.fetch(:data).fetch(:tracking)
204
+ data = Request.post(url: TRACKINGS_ENDPOINT, api_key: api_key,
205
+ body: body) do |response|
206
+ response.fetch(:data).fetch(:tracking)
207
+ end
200
208
 
201
209
  Tracking.new(data)
202
210
  end
203
211
 
204
- # https://www.aftership.com/docs/api/3.0/tracking/put-trackings-slug-tracking_number
212
+ # Update a tracking.
213
+ # https://www.aftership.com/docs/api/4/trackings/put-trackings-slug-tracking_number
214
+ #
215
+ # client.update_tracking('tracking-number', 'ups', order_id: 'external-id')
216
+ #
217
+ # # Will return Tracking object or raise
218
+ # # AfterShip::Error::TrackingAlreadyExists:
219
+ #
220
+ # #<AfterShip::Tracking ...>
205
221
  #
206
222
  # @param tracking_number [String]
207
223
  # @param courier [String]
@@ -209,115 +225,43 @@ class AfterShip
209
225
  #
210
226
  # @return [Hash]
211
227
  def update_tracking(tracking_number, courier, options = {})
212
- require_arguments(tracking_number: tracking_number, courier: courier)
213
-
214
- url = "#{ TRACKINGS_ENDPOINT }/#{ courier }/#{ tracking_number }"
215
- params = {
228
+ url = "#{ TRACKINGS_ENDPOINT }/#{ courier }/#{ tracking_number }"
229
+ body = {
216
230
  tracking: options
217
231
  }
218
232
 
219
- response = request_response(url, params, :put)
220
- data = response.fetch(:data).fetch(:tracking)
221
-
222
- Tracking.new(data)
223
- end
224
-
225
- # Raises an ArgumentError if any of the args is empty or nil.
226
- #
227
- # @param hash [Hash] arguments needed in options
228
- def require_arguments(hash)
229
- hash.each do |name, value|
230
- if value.respond_to?(:empty?)
231
- invalid_argument!(name) if value.empty?
232
- else
233
- invalid_argument!(name)
234
- end
233
+ data = Request.put(url: url, api_key: api_key, body: body) do |response|
234
+ response.fetch(:data).fetch(:tracking)
235
235
  end
236
- end
237
236
 
238
- protected
239
-
240
- # @param name [Symbol]
241
- def invalid_argument!(name)
242
- fail ArgumentError, "Argument #{ name } cannot be empty"
237
+ Tracking.new(data)
243
238
  end
244
239
 
245
- # Prepare a `Typhoeus::Request`, send it over the net and deal
246
- # with te response by either returning a Hash or raising an error.
240
+ # Get a list of activated couriers.
241
+ # https://www.aftership.com/docs/api/4/couriers/get-couriers
247
242
  #
248
- # @param url [String]
249
- # @param body_hash [Hash]
250
- # @param method [Symbol]
243
+ # client.couriers
251
244
  #
252
- # @return [Hash]
253
- def request_response(url, body_hash, method = :get)
254
- body_json = MultiJson.dump(body_hash)
255
-
256
- request = Typhoeus::Request.new(
257
- url,
258
- method: method,
259
- verbose: self.class.debug,
260
- body: body_json,
261
- headers: {
262
- 'aftership-api-key' => @api_key,
263
- 'Content-Type' => 'application/json'
264
- }
265
- )
266
-
267
- if self.class.debug
268
- request.on_complete do |response|
269
- puts
270
- puts 'Request body:'
271
- puts request.options[:body]
272
- puts
273
- puts 'Response body:'
274
- puts response.body
275
- puts
276
- end
277
- end
278
-
279
- response = request.run
280
- response_to_json(response)
281
- end
282
-
283
- # Deal with API response, either return a Hash or raise an error.
245
+ # # Will return list of Courier objects:
284
246
  #
285
- # @param response [Typhoeus::Response]
247
+ # [
248
+ # #<AfterShip::Courier:0x007fa2771d4bf8
249
+ # @name="USPS",
250
+ # @other_name="United States Postal Service",
251
+ # @phone="+1 800-275-8777",
252
+ # @required_fields=[],
253
+ # @slug="usps",
254
+ # @web_url="https://www.usps.com">,
255
+ # #<AfterShip::Courier ...>
256
+ # ...
257
+ # ]
286
258
  #
287
259
  # @return [Hash]
288
- #
289
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
290
- def response_to_json(response)
291
- json_response = parse_response(response)
292
-
293
- case json_response[:meta][:code]
294
- when 200, 201
295
- return json_response
296
- when 400
297
- fail InvalidJSONDataError, json_response[:meta][:error_message]
298
- when 401
299
- fail InvalidCredentialsError, json_response[:meta][:error_message]
300
- when 402
301
- fail RequestFailedError, json_response[:meta][:error_message]
302
- when 404
303
- fail ResourceNotFoundError, json_response[:meta][:error_message]
304
- when 409
305
- fail InvalidArgumentError, json_response[:meta][:error_message]
306
- when 429
307
- fail TooManyRequestsError, json_response[:meta][:error_message]
308
- when 500, 502, 503, 504
309
- fail ServerError, json_response[:meta][:error_message]
310
- else
311
- fail UnknownError, json_response[:meta][:error_message]
260
+ def couriers
261
+ data = Request.get(url: COURIERS_ENDPOINT, api_key: api_key) do |response|
262
+ response.fetch(:data).fetch(:couriers)
312
263
  end
313
- end
314
264
 
315
- # Parse response body into a Hash.
316
- #
317
- # @param response [Typhoeus::Response]
318
- #
319
- # @return [Hash]
320
- def parse_response(response)
321
- MultiJson.load(response.body, JSON_OPTIONS)
265
+ data.map { |datum| Courier.new(datum) }
322
266
  end
323
267
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe AfterShip do
4
+ let(:client) { AfterShip.new(api_key: 'key') }
5
+
6
+ it 'trackings' do
7
+ trackings = client.trackings
8
+ expect(trackings.size).to eq(2)
9
+ end
10
+
11
+ it 'trackings with debug' do
12
+ AfterShip.debug = true
13
+
14
+ trackings = client.trackings
15
+ expect(trackings.size).to eq(2)
16
+
17
+ AfterShip.debug = nil
18
+ end
19
+
20
+ it 'tracking' do
21
+ tracking = client.tracking('delivered', 'ups')
22
+ expect(tracking.tracking_number).to eq('1ZA2207X0444990982')
23
+ expect(tracking.checkpoints.size).to eq(15)
24
+ end
25
+
26
+ it 'create_tracking' do
27
+ tracking = client.create_tracking('created', 'ups', order_id: 'external-id')
28
+ expect(tracking.tracking_number).to eq('1Z0659120300549388')
29
+ end
30
+
31
+ it 'update_tracking' do
32
+ tracking = client.update_tracking('updated', 'ups', order_id: 'external-id')
33
+ expect(tracking.tracking_number).to eq('1Z0659120300549388')
34
+ end
35
+
36
+ it 'couriers' do
37
+ couriers = client.couriers
38
+ expect(couriers.size).to eq(4)
39
+ end
40
+ end