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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 19c7f898c4fae3541f44b1652a80084385b3b6ca
4
- data.tar.gz: a7349bb2781c99c97196978e7dd378a3c2273519
3
+ metadata.gz: 838209b9accf6cfb537ac16786e8683d18155073
4
+ data.tar.gz: 75036f0188503179ddb089ee25f99dc8b9fa4538
5
5
  SHA512:
6
- metadata.gz: 0714de5ac8bd86737faee62a0a31190ced5961f6124a9c429c94a1faa7560770fc96159debc8ee059a2ecdd3a875c03f6e29e674e36e5952ace60d70cc236ebd
7
- data.tar.gz: d92d587f63be9ec16d81a3e43ef4e9ebf26fb599c4e99f58140e94419d64ba341270ed5441661aef525a536ae4d02f3f889f969d0e6d3694db8e1fa3310cd2a2
6
+ metadata.gz: 8d3e7c5b1b9cf6a46986c02725ebda6324724cd0d1c073f7fcded221314bf1ec6ebe360105f60c39e72f3612143d1749e0be36b648b135dc03eef97857098577
7
+ data.tar.gz: fd34ef65e9404b1255c04a4e4867e6ad1fa3e0089ddbf1e73e4ff7b43209dae66f3f9e4e71d171d117fe2718c2cff406500fc9506dc3331d478af2668384eafb
data/.gitignore CHANGED
@@ -10,3 +10,4 @@ test/fixtures/live_credentials.yml
10
10
  .rbenv-version
11
11
  .yardoc/
12
12
  doc/
13
+ .idea
@@ -143,7 +143,7 @@ module ActiveShipping
143
143
  end
144
144
 
145
145
  def find_rates(origin, destination, packages, options = {})
146
- options = @options.update(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.update(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.update(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
- xml.ShipTimestamp(ship_timestamp(options[:turn_around_time]).iso8601(0))
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
- delivery_range = transit_range.map { |days| business_days_from(ship_date(options[:turn_around_time]), days) }
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
- count += 1 if business_day?(future_date)
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?(origin.country_code(:alpha2))
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', options[:shipper] || origin, options)
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
- build_location_node(xml, 'SoldTo', options[:sold_to] || destination, options)
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
- # * Shipment/Package/Description element
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.update(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
@@ -1,3 +1,3 @@
1
1
  module ActiveShipping
2
- VERSION = "1.6.1"
2
+ VERSION = "1.6.2"
3
3
  end
@@ -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
@@ -12,11 +12,11 @@ class RemoteUSPSTest < Minitest::Test
12
12
  end
13
13
 
14
14
  def test_tracking
15
- response = @carrier.find_tracking_info('LN284529912US', test: false)
15
+ response = @carrier.find_tracking_info('LN757696446US', test: false)
16
16
  assert response.success?, response.message
17
- assert_equal 9,response.shipment_events.size
17
+ assert_equal 13,response.shipment_events.size
18
18
  assert_equal 'DELIVERED', response.shipment_events.last.message
19
- assert_equal Time.parse('2015-06-01 13:36:00 UTC'), response.actual_delivery_date
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, 03, 0, 0, 0, "-4")
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, with 2 weekend days accounted for
251
- delivery_date = Date.today + 5
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.1
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-11-11 00:00:00.000000000 Z
14
+ date: 2015-12-03 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: quantified