active_shipping 1.6.1 → 1.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/lib/active_shipping/carriers/fedex.rb +25 -10
- data/lib/active_shipping/carriers/ups.rb +40 -5
- data/lib/active_shipping/carriers/usps.rb +1 -1
- data/lib/active_shipping/version.rb +1 -1
- data/test/remote/ups_test.rb +39 -0
- data/test/remote/usps_test.rb +3 -3
- data/test/test_helper.rb +9 -0
- data/test/unit/carriers/fedex_test.rb +37 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 838209b9accf6cfb537ac16786e8683d18155073
|
4
|
+
data.tar.gz: 75036f0188503179ddb089ee25f99dc8b9fa4538
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d3e7c5b1b9cf6a46986c02725ebda6324724cd0d1c073f7fcded221314bf1ec6ebe360105f60c39e72f3612143d1749e0be36b648b135dc03eef97857098577
|
7
|
+
data.tar.gz: fd34ef65e9404b1255c04a4e4867e6ad1fa3e0089ddbf1e73e4ff7b43209dae66f3f9e4e71d171d117fe2718c2cff406500fc9506dc3331d478af2668384eafb
|
data/.gitignore
CHANGED
@@ -143,7 +143,7 @@ module ActiveShipping
|
|
143
143
|
end
|
144
144
|
|
145
145
|
def find_rates(origin, destination, packages, options = {})
|
146
|
-
options = @options.
|
146
|
+
options = @options.merge(options)
|
147
147
|
packages = Array(packages)
|
148
148
|
|
149
149
|
rate_request = build_rate_request(origin, destination, packages, options)
|
@@ -154,7 +154,7 @@ module ActiveShipping
|
|
154
154
|
end
|
155
155
|
|
156
156
|
def find_tracking_info(tracking_number, options = {})
|
157
|
-
options = @options.
|
157
|
+
options = @options.merge(options)
|
158
158
|
|
159
159
|
tracking_request = build_tracking_request(tracking_number, options)
|
160
160
|
xml = commit(save_request(tracking_request), (options[:test] || false))
|
@@ -164,7 +164,7 @@ module ActiveShipping
|
|
164
164
|
|
165
165
|
# Get Shipping labels
|
166
166
|
def create_shipment(origin, destination, packages, options = {})
|
167
|
-
options = @options.
|
167
|
+
options = @options.merge(options)
|
168
168
|
packages = Array(packages)
|
169
169
|
raise Error, "Multiple packages are not supported yet." if packages.length > 1
|
170
170
|
|
@@ -298,7 +298,11 @@ module ActiveShipping
|
|
298
298
|
xml.VariableOptions('SATURDAY_DELIVERY')
|
299
299
|
|
300
300
|
xml.RequestedShipment do
|
301
|
-
|
301
|
+
if options[:pickup_date]
|
302
|
+
xml.ShipTimestamp(options[:pickup_date].to_time.iso8601(0))
|
303
|
+
else
|
304
|
+
xml.ShipTimestamp(ship_timestamp(options[:turn_around_time]).iso8601(0))
|
305
|
+
end
|
302
306
|
|
303
307
|
freight = has_freight?(options)
|
304
308
|
|
@@ -479,8 +483,7 @@ module ActiveShipping
|
|
479
483
|
max_transit_time = rated_shipment.at('MaximumTransitTime').try(:text) if service_code == "FEDEX_GROUND"
|
480
484
|
|
481
485
|
delivery_timestamp = rated_shipment.at('DeliveryTimestamp').try(:text)
|
482
|
-
|
483
|
-
delivery_range = delivery_range_from(transit_time, max_transit_time, delivery_timestamp, options)
|
486
|
+
delivery_range = delivery_range_from(transit_time, max_transit_time, delivery_timestamp, (service_code == "GROUND_HOME_DELIVERY"), options)
|
484
487
|
|
485
488
|
currency = rated_shipment.at('RatedShipmentDetails/ShipmentRateDetail/TotalNetCharge/Currency').text
|
486
489
|
RateEstimate.new(origin, destination, @@name,
|
@@ -503,13 +506,15 @@ module ActiveShipping
|
|
503
506
|
RateResponse.new(success, message, Hash.from_xml(response), :rates => rate_estimates, :xml => response, :request => last_request, :log_xml => options[:log_xml])
|
504
507
|
end
|
505
508
|
|
506
|
-
def delivery_range_from(transit_time, max_transit_time, delivery_timestamp, options)
|
509
|
+
def delivery_range_from(transit_time, max_transit_time, delivery_timestamp, is_home_delivery, options)
|
507
510
|
delivery_range = [delivery_timestamp, delivery_timestamp]
|
508
511
|
|
509
512
|
# if there's no delivery timestamp but we do have a transit time, use it
|
510
513
|
if delivery_timestamp.blank? && transit_time.present?
|
511
514
|
transit_range = parse_transit_times([transit_time, max_transit_time.presence || transit_time])
|
512
|
-
|
515
|
+
pickup_date = options[:pickup_date] || ship_date(options[:turn_around_time])
|
516
|
+
|
517
|
+
delivery_range = transit_range.map { |days| business_days_from(pickup_date, days, is_home_delivery) }
|
513
518
|
end
|
514
519
|
|
515
520
|
delivery_range
|
@@ -528,22 +533,32 @@ module ActiveShipping
|
|
528
533
|
LabelResponse.new(success, message, response_info, {labels: labels})
|
529
534
|
end
|
530
535
|
|
531
|
-
def business_days_from(date, days)
|
536
|
+
def business_days_from(date, days, is_home_delivery=false)
|
532
537
|
future_date = date
|
533
538
|
count = 0
|
534
539
|
|
535
540
|
while count < days
|
536
541
|
future_date += 1.day
|
537
|
-
|
542
|
+
if is_home_delivery
|
543
|
+
count += 1 if home_delivery_business_day?(future_date)
|
544
|
+
else
|
545
|
+
count += 1 if business_day?(future_date)
|
546
|
+
end
|
538
547
|
end
|
539
548
|
|
540
549
|
future_date
|
541
550
|
end
|
542
551
|
|
552
|
+
#Transit times for FedEx® Ground do not include Saturdays, Sundays, or holidays.
|
543
553
|
def business_day?(date)
|
544
554
|
(1..5).include?(date.wday)
|
545
555
|
end
|
546
556
|
|
557
|
+
#Transit times for FedEx® Home Delivery, do not include Sundays, Mondays, or holidays.
|
558
|
+
def home_delivery_business_day?(date)
|
559
|
+
(2..6).include?(date.wday)
|
560
|
+
end
|
561
|
+
|
547
562
|
def parse_tracking_response(response, options)
|
548
563
|
xml = build_document(response, 'TrackReply')
|
549
564
|
|
@@ -93,6 +93,25 @@ module ActiveShipping
|
|
93
93
|
"07" => "UPS Express"
|
94
94
|
}
|
95
95
|
|
96
|
+
RETURN_SERVICE_CODES = {
|
97
|
+
"2" => "UPS Print and Mail (PNM)",
|
98
|
+
"3" => "UPS Return Service 1-Attempt (RS1)",
|
99
|
+
"5" => "UPS Return Service 3-Attempt (RS3)",
|
100
|
+
"8" => "UPS Electronic Return Label (ERL)",
|
101
|
+
"9" => "UPS Print Return Label (PRL)",
|
102
|
+
"10" => "UPS Exchange Print Return Label",
|
103
|
+
"11" => "UPS Pack & Collect Service 1-Attempt Box 1",
|
104
|
+
"12" => "UPS Pack & Collect Service 1-Attempt Box 2",
|
105
|
+
"13" => "UPS Pack & Collect Service 1-Attempt Box 3",
|
106
|
+
"14" => "UPS Pack & Collect Service 1-Attempt Box 4",
|
107
|
+
"15" => "UPS Pack & Collect Service 1-Attempt Box 5",
|
108
|
+
"16" => "UPS Pack & Collect Service 3-Attempt Box 1",
|
109
|
+
"17" => "UPS Pack & Collect Service 3-Attempt Box 2",
|
110
|
+
"18" => "UPS Pack & Collect Service 3-Attempt Box 3",
|
111
|
+
"19" => "UPS Pack & Collect Service 3-Attempt Box 4",
|
112
|
+
"20" => "UPS Pack & Collect Service 3-Attempt Box 5",
|
113
|
+
}
|
114
|
+
|
96
115
|
TRACKING_STATUS_CODES = HashWithIndifferentAccess.new(
|
97
116
|
'I' => :in_transit,
|
98
117
|
'D' => :delivered,
|
@@ -111,6 +130,7 @@ module ActiveShipping
|
|
111
130
|
DEFAULT_SERVICE_NAME_TO_CODE = Hash[UPS::DEFAULT_SERVICES.to_a.map(&:reverse)]
|
112
131
|
DEFAULT_SERVICE_NAME_TO_CODE['UPS 2nd Day Air'] = "02"
|
113
132
|
DEFAULT_SERVICE_NAME_TO_CODE['UPS 3 Day Select'] = "12"
|
133
|
+
DEFAULT_SERVICE_NAME_TO_CODE['UPS Next Day Air Early'] = "14"
|
114
134
|
|
115
135
|
SHIPMENT_DELIVERY_CONFIRMATION_CODES = {
|
116
136
|
delivery_confirmation_signature_required: 1,
|
@@ -313,8 +333,11 @@ module ActiveShipping
|
|
313
333
|
# * delivery_confirmation: Can be set to any key from SHIPMENT_DELIVERY_CONFIRMATION_CODES. Can also be set on package level via package.options
|
314
334
|
def build_shipment_request(origin, destination, packages, options={})
|
315
335
|
packages = Array(packages)
|
336
|
+
shipper = options[:shipper] || origin
|
316
337
|
options[:international] = origin.country.name != destination.country.name
|
317
|
-
options[:imperial] ||= IMPERIAL_COUNTRIES.include?(
|
338
|
+
options[:imperial] ||= IMPERIAL_COUNTRIES.include?(shipper.country_code(:alpha2))
|
339
|
+
options[:return] = options[:return_service_code].present?
|
340
|
+
options[:reason_for_export] ||= ("RETURN" if options[:return])
|
318
341
|
|
319
342
|
if allow_package_level_reference_numbers(origin, destination)
|
320
343
|
if options[:reference_numbers]
|
@@ -349,7 +372,7 @@ module ActiveShipping
|
|
349
372
|
build_location_node(xml, 'ShipTo', destination, options)
|
350
373
|
build_location_node(xml, 'ShipFrom', origin, options)
|
351
374
|
# Required element. The company whose account is responsible for the label(s).
|
352
|
-
build_location_node(xml, 'Shipper',
|
375
|
+
build_location_node(xml, 'Shipper', shipper, options)
|
353
376
|
|
354
377
|
if options[:saturday_delivery]
|
355
378
|
xml.ShipmentServiceOptions do
|
@@ -416,7 +439,9 @@ module ActiveShipping
|
|
416
439
|
end
|
417
440
|
|
418
441
|
if options[:international]
|
419
|
-
|
442
|
+
unless options[:return]
|
443
|
+
build_location_node(xml, 'SoldTo', options[:sold_to] || destination, options)
|
444
|
+
end
|
420
445
|
|
421
446
|
if origin.country_code(:alpha2) == 'US' && ['CA', 'PR'].include?(destination.country_code(:alpha2))
|
422
447
|
# Required for shipments from the US to Puerto Rico or Canada
|
@@ -432,6 +457,12 @@ module ActiveShipping
|
|
432
457
|
end
|
433
458
|
end
|
434
459
|
|
460
|
+
if options[:return]
|
461
|
+
xml.ReturnService do
|
462
|
+
xml.Code(options[:return_service_code])
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
435
466
|
xml.ShipmentServiceOptions do
|
436
467
|
if delivery_confirmation = options[:delivery_confirmation]
|
437
468
|
xml.DeliveryConfirmation do
|
@@ -631,9 +662,13 @@ module ActiveShipping
|
|
631
662
|
|
632
663
|
def build_package_node(xml, package, options = {})
|
633
664
|
xml.Package do
|
634
|
-
|
635
665
|
# not implemented: * Shipment/Package/PackagingType element
|
636
|
-
|
666
|
+
|
667
|
+
#return requires description
|
668
|
+
if options[:return]
|
669
|
+
contents_description = package.options[:description]
|
670
|
+
xml.Description(contents_description) if contents_description
|
671
|
+
end
|
637
672
|
|
638
673
|
xml.PackagingType do
|
639
674
|
xml.Code('02')
|
@@ -171,7 +171,7 @@ module ActiveShipping
|
|
171
171
|
SERVICE_NAME_SUBSTITUTIONS = /#{ESCAPING_AND_SYMBOLS}|#{LEADING_USPS}|#{TRAILING_ASTERISKS}/
|
172
172
|
|
173
173
|
def find_tracking_info(tracking_number, options = {})
|
174
|
-
options = @options.
|
174
|
+
options = @options.merge(options)
|
175
175
|
tracking_request = build_tracking_request(tracking_number, options)
|
176
176
|
response = commit(:track, tracking_request, options[:test] || false)
|
177
177
|
parse_tracking_response(response).first
|
data/test/remote/ups_test.rb
CHANGED
@@ -359,4 +359,43 @@ class RemoteUPSTest < Minitest::Test
|
|
359
359
|
def test_maximum_address_field_length
|
360
360
|
assert_equal 35, @carrier.maximum_address_field_length
|
361
361
|
end
|
362
|
+
|
363
|
+
def test_obtain_return_label
|
364
|
+
response = @carrier.create_shipment(
|
365
|
+
location_fixtures[:beverly_hills_with_name],
|
366
|
+
location_fixtures[:real_google_as_commercial],
|
367
|
+
#package descriptions are required for returns
|
368
|
+
package_fixtures.values_at(:books),
|
369
|
+
{
|
370
|
+
:shipper => location_fixtures[:new_york],
|
371
|
+
:return_service_code => '9',
|
372
|
+
:test => true
|
373
|
+
}
|
374
|
+
)
|
375
|
+
|
376
|
+
assert response.success?
|
377
|
+
|
378
|
+
assert_instance_of ActiveShipping::LabelResponse, response
|
379
|
+
end
|
380
|
+
|
381
|
+
def test_obtain_international_return_label
|
382
|
+
response = @carrier.create_shipment(
|
383
|
+
location_fixtures[:ottawa_with_name],
|
384
|
+
#international return requires destination to have: phone number, name
|
385
|
+
location_fixtures[:real_google_with_name_phone],
|
386
|
+
#package descriptions are required for returns
|
387
|
+
package_fixtures.values_at(:books),
|
388
|
+
{
|
389
|
+
#international return requires shipper to have: phone, name
|
390
|
+
:shipper => location_fixtures[:new_york_with_name],
|
391
|
+
:service_code => '07',
|
392
|
+
:return_service_code => '9',
|
393
|
+
:test => true,
|
394
|
+
}
|
395
|
+
)
|
396
|
+
|
397
|
+
assert response.success?
|
398
|
+
|
399
|
+
assert_instance_of ActiveShipping::LabelResponse, response
|
400
|
+
end
|
362
401
|
end
|
data/test/remote/usps_test.rb
CHANGED
@@ -12,11 +12,11 @@ class RemoteUSPSTest < Minitest::Test
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_tracking
|
15
|
-
response = @carrier.find_tracking_info('
|
15
|
+
response = @carrier.find_tracking_info('LN757696446US', test: false)
|
16
16
|
assert response.success?, response.message
|
17
|
-
assert_equal
|
17
|
+
assert_equal 13,response.shipment_events.size
|
18
18
|
assert_equal 'DELIVERED', response.shipment_events.last.message
|
19
|
-
assert_equal Time.parse('2015-
|
19
|
+
assert_equal Time.parse('2015-11-30 13:02:00 UTC'), response.actual_delivery_date
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_tracking_with_bad_number
|
data/test/test_helper.rb
CHANGED
@@ -152,6 +152,15 @@ module ActiveShipping::Test
|
|
152
152
|
:address1 => '1600 Amphitheatre Parkway',
|
153
153
|
:zip => '94043',
|
154
154
|
:address_type => 'commercial'),
|
155
|
+
:real_google_with_name_phone => Location.new(
|
156
|
+
:name => 'Sergey Brin',
|
157
|
+
:country => 'US',
|
158
|
+
:city => 'Mountain View',
|
159
|
+
:state => 'CA',
|
160
|
+
:address1 => '1600 Amphitheatre Parkway',
|
161
|
+
:zip => '94043',
|
162
|
+
:phone => '1-650-253-0000',
|
163
|
+
:address_type => 'commercial'),
|
155
164
|
:real_google_as_residential => Location.new(
|
156
165
|
:country => 'US',
|
157
166
|
:city => 'Mountain View',
|
@@ -15,19 +15,31 @@ class FedExTest < Minitest::Test
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def test_business_days
|
18
|
-
today = DateTime.civil(2013, 3, 12, 0, 0, 0, "-4")
|
18
|
+
today = DateTime.civil(2013, 3, 12, 0, 0, 0, "-4") #Tuesday
|
19
19
|
|
20
20
|
Timecop.freeze(today) do
|
21
21
|
assert_equal DateTime.civil(2013, 3, 13, 0, 0, 0, "-4"), @carrier.send(:business_days_from, today, 1)
|
22
22
|
assert_equal DateTime.civil(2013, 3, 15, 0, 0, 0, "-4"), @carrier.send(:business_days_from, today, 3)
|
23
|
+
assert_equal DateTime.civil(2013, 3, 18, 0, 0, 0, "-4"), @carrier.send(:business_days_from, today, 4)
|
23
24
|
assert_equal DateTime.civil(2013, 3, 19, 0, 0, 0, "-4"), @carrier.send(:business_days_from, today, 5)
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
28
|
+
def test_home_delivery_business_days
|
29
|
+
today = DateTime.civil(2013, 3, 12, 0, 0, 0, "-4") #Tuesday
|
30
|
+
|
31
|
+
Timecop.freeze(today) do
|
32
|
+
assert_equal DateTime.civil(2013, 3, 13, 0, 0, 0, "-4"), @carrier.send(:business_days_from, today, 1, true)
|
33
|
+
assert_equal DateTime.civil(2013, 3, 15, 0, 0, 0, "-4"), @carrier.send(:business_days_from, today, 3, true)
|
34
|
+
assert_equal DateTime.civil(2013, 3, 16, 0, 0, 0, "-4"), @carrier.send(:business_days_from, today, 4, true)
|
35
|
+
assert_equal DateTime.civil(2013, 3, 19, 0, 0, 0, "-4"), @carrier.send(:business_days_from, today, 5, true)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
27
39
|
def test_turn_around_time_default
|
28
40
|
mock_response = xml_fixture('fedex/ottawa_to_beverly_hills_rate_response').gsub('<v6:DeliveryTimestamp>2011-07-29</v6:DeliveryTimestamp>', '')
|
29
41
|
|
30
|
-
today = DateTime.civil(2013, 3, 11, 0, 0, 0, "-4")
|
42
|
+
today = DateTime.civil(2013, 3, 11, 0, 0, 0, "-4") #Monday
|
31
43
|
|
32
44
|
Timecop.freeze(today) do
|
33
45
|
delivery_date = Date.today + 7.days # FIVE_DAYS in fixture response, plus weekend
|
@@ -240,19 +252,39 @@ class FedExTest < Minitest::Test
|
|
240
252
|
|
241
253
|
@carrier.expects(:commit).returns(mock_response)
|
242
254
|
|
243
|
-
today = DateTime.civil(2015, 06,
|
255
|
+
today = DateTime.civil(2015, 06, 04, 0, 0, 0, "-4") #Thursday
|
244
256
|
|
245
257
|
Timecop.freeze(today) do
|
246
258
|
rate_estimates = @carrier.find_rates( location_fixtures[:ottawa],
|
247
259
|
location_fixtures[:beverly_hills],
|
248
260
|
package_fixtures.values_at(:book, :wii), :test => true)
|
249
261
|
|
250
|
-
# the above fixture will specify a transit time of 3 days
|
251
|
-
|
262
|
+
# the above fixture will specify a transit time of 3 days
|
263
|
+
# for ground home, sunday and monday are non-biz days
|
264
|
+
# so it is delivered on Tuesday
|
265
|
+
delivery_date = Date.today + 3 + 2
|
252
266
|
assert_equal delivery_date, rate_estimates.rates.first.delivery_date
|
253
267
|
end
|
254
268
|
end
|
255
269
|
|
270
|
+
def test_delivery_date_from_ground_home_transit_time_on_saturday
|
271
|
+
mock_response = xml_fixture('fedex/raterequest_response_with_ground_home_delivery')
|
272
|
+
|
273
|
+
@carrier.expects(:commit).returns(mock_response)
|
274
|
+
|
275
|
+
today = DateTime.civil(2015, 06, 03, 0, 0, 0, "-4") #Wednesday
|
276
|
+
|
277
|
+
Timecop.freeze(today) do
|
278
|
+
rate_estimates = @carrier.find_rates( location_fixtures[:ottawa],
|
279
|
+
location_fixtures[:beverly_hills],
|
280
|
+
package_fixtures.values_at(:book, :wii), :test => true)
|
281
|
+
|
282
|
+
# the above fixture will specify a transit time of 3 days
|
283
|
+
# since ground home delivers on Saturday, there is no delay
|
284
|
+
delivery_date = Date.today + 3
|
285
|
+
assert_equal delivery_date, rate_estimates.rates.first.delivery_date
|
286
|
+
end
|
287
|
+
end
|
256
288
|
|
257
289
|
def test_failure_to_parse_invalid_xml_results_in_a_useful_error
|
258
290
|
mock_response = xml_fixture('fedex/invalid_fedex_reply')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_shipping
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James MacAulay
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2015-
|
14
|
+
date: 2015-12-03 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: quantified
|