after_ship 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +69 -32
- data/after_ship.gemspec +4 -4
- data/lib/after_ship/checkpoint.rb +35 -28
- data/lib/after_ship/core/attributes.rb +14 -0
- data/lib/after_ship/core/date_utils.rb +76 -0
- data/lib/after_ship/core/error.rb +29 -0
- data/lib/after_ship/core/error_handler.rb +67 -0
- data/lib/after_ship/core/request.rb +131 -0
- data/lib/after_ship/core/version.rb +4 -0
- data/lib/after_ship/courier.rb +45 -0
- data/lib/after_ship/tracking.rb +78 -6
- data/lib/after_ship.rb +158 -214
- data/spec/integration/after_ship_spec.rb +40 -0
- data/spec/request_stubs.rb +30 -97
- data/spec/requests/couriers.json +50 -0
- data/spec/requests/tracking/created.json +53 -0
- data/spec/requests/tracking/{delivered_ok.json → delivered.json} +79 -65
- data/spec/requests/trackings.json +654 -0
- data/spec/units/after_ship_spec.rb +104 -0
- data/spec/units/checkpoint_spec.rb +135 -0
- data/spec/units/courier_spec.rb +41 -0
- data/spec/{lib → units}/date_utils_spec.rb +17 -9
- data/spec/units/error_handler_spec.rb +168 -0
- data/spec/units/request_spec.rb +190 -0
- data/spec/units/tracking_spec.rb +276 -0
- metadata +39 -25
- data/lib/after_ship/version.rb +0 -3
- data/lib/attributes.rb +0 -12
- data/lib/date_utils.rb +0 -61
- data/spec/lib/after_ship_spec.rb +0 -137
- data/spec/lib/checkpoint_spec.rb +0 -139
- data/spec/lib/tracking_spec.rb +0 -89
- data/spec/requests/tracking/delivered_wild.json +0 -653
- data/spec/requests/tracking/in_transit.json +0 -443
@@ -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
|
data/lib/after_ship/tracking.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class AfterShip
|
2
2
|
# Wrapper object for AfterShip tracking:
|
3
|
-
# https://www.aftership.com/docs/api/
|
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
|
58
|
+
# +false+ when tag (status) is +Delivered+, +Expired+, or further updates
|
59
|
+
# for 30 days since last update.
|
34
60
|
#
|
35
|
-
# @return [
|
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
|
-
#
|
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
|
-
|
5
|
-
require '
|
6
|
-
require 'after_ship/
|
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
|
-
#
|
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
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
# client.tracking('1ZA2207X6790326683', 'ups') # Delivered, ok
|
31
|
+
# Some test trackings:
|
32
|
+
#
|
33
|
+
# client.tracking('1ZA2207X0444990982', 'ups')
|
101
34
|
class AfterShip
|
102
|
-
|
103
|
-
|
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
|
-
|
113
|
-
TRACKINGS_ENDPOINT
|
38
|
+
# The trackings endpoint URL.
|
39
|
+
TRACKINGS_ENDPOINT = "#{ DEFAULT_API_ADDRESS }/trackings"
|
114
40
|
|
115
|
-
|
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
|
-
#
|
79
|
+
# @option options api_key [String]
|
143
80
|
def initialize(options)
|
144
|
-
|
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/
|
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
|
-
|
157
|
-
|
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/
|
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
|
-
|
171
|
-
|
172
|
-
|
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/
|
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
|
-
|
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
|
-
|
199
|
-
|
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
|
-
#
|
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
|
-
|
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
|
-
|
220
|
-
|
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
|
-
|
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
|
-
#
|
246
|
-
#
|
240
|
+
# Get a list of activated couriers.
|
241
|
+
# https://www.aftership.com/docs/api/4/couriers/get-couriers
|
247
242
|
#
|
248
|
-
#
|
249
|
-
# @param body_hash [Hash]
|
250
|
-
# @param method [Symbol]
|
243
|
+
# client.couriers
|
251
244
|
#
|
252
|
-
#
|
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
|
-
#
|
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
|
-
|
290
|
-
|
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
|
-
|
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
|