active_shipping 1.7.1 → 1.7.2
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.
- checksums.yaml +4 -4
- data/dev.yml +2 -2
- data/lib/active_shipping/carrier.rb +15 -0
- data/lib/active_shipping/carriers/fedex.rb +3 -1
- data/lib/active_shipping/carriers/ups.rb +28 -26
- data/lib/active_shipping/location.rb +4 -0
- data/lib/active_shipping/shipment_event.rb +5 -0
- data/lib/active_shipping/tracking_response.rb +16 -1
- data/lib/active_shipping/version.rb +1 -1
- data/test/remote/ups_test.rb +29 -0
- data/test/unit/carriers/fedex_test.rb +26 -0
- data/test/unit/carriers/ups_test.rb +5 -4
- data/test/unit/location_test.rb +7 -0
- data/test/unit/shipment_event_test.rb +20 -0
- data/test/unit/tracking_response_test.rb +41 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a721187cba1984ab9a456dea8c660c81d2a1aa68
|
4
|
+
data.tar.gz: 4b6ba4b2a8bedd5434f611d81d2ba74df92fab5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fecbfa0feaf36671db206bb30fb3e981b5c079183d45ebd8a2c096a41ba4d66f516b69d443ed3e08b54c1af4fa070ce618fb9f3fc89ce48bf2e19fafcec0d2b
|
7
|
+
data.tar.gz: 80a224c59f08ba748989a2aacc4ddcacd529296c43c4d0caa370339a26d60d1d2c29d860ce4e0c1d5719e2f791aef2b05589b44055b45228400fd47fef24fae7
|
data/dev.yml
CHANGED
@@ -7,6 +7,7 @@ module ActiveShipping
|
|
7
7
|
#
|
8
8
|
# @see #find_rates
|
9
9
|
# @see #create_shipment
|
10
|
+
# @see #cancel_shipment
|
10
11
|
# @see #find_tracking_info
|
11
12
|
#
|
12
13
|
# @!attribute test_mode
|
@@ -67,6 +68,20 @@ module ActiveShipping
|
|
67
68
|
raise NotImplementedError, "#create_shipment is not supported by #{self.class.name}."
|
68
69
|
end
|
69
70
|
|
71
|
+
# Cancels a shipment with a carrier.
|
72
|
+
#
|
73
|
+
# @note Override with whatever you need to cancel a shipping label
|
74
|
+
#
|
75
|
+
# @param shipment_id [String] The unique identifier of the shipment to cancel.
|
76
|
+
# This can be shipment_id or tracking number depending on carrier. Up to you and
|
77
|
+
# the carrier
|
78
|
+
# @param options [Hash] Carrier-specific parameters.
|
79
|
+
# @return [ActiveShipping::ShipmentResponse] The response from the carrier. This
|
80
|
+
# response in most cases has a cancellation id.
|
81
|
+
def cancel_shipment(shipment_id, options = {})
|
82
|
+
raise NotImplementedError, "#cancel_shipment is not supported by #{self.class.name}."
|
83
|
+
end
|
84
|
+
|
70
85
|
# Retrieves tracking information for a previous shipment
|
71
86
|
#
|
72
87
|
# @note Override with whatever you need to get a shipping label
|
@@ -134,6 +134,8 @@ module ActiveShipping
|
|
134
134
|
'TR' => :transfer
|
135
135
|
)
|
136
136
|
|
137
|
+
DEFAULT_LABEL_STOCK_TYPE = 'PAPER_7X4.75'
|
138
|
+
|
137
139
|
def self.service_name_for_code(service_code)
|
138
140
|
SERVICE_TYPES[service_code] || "FedEx #{service_code.titleize.sub(/Fedex /, '')}"
|
139
141
|
end
|
@@ -218,7 +220,7 @@ module ActiveShipping
|
|
218
220
|
xml.LabelSpecification do
|
219
221
|
xml.LabelFormatType('COMMON2D')
|
220
222
|
xml.ImageType('PNG')
|
221
|
-
xml.LabelStockType(
|
223
|
+
xml.LabelStockType(options[:label_stock_type] || DEFAULT_LABEL_STOCK_TYPE)
|
222
224
|
end
|
223
225
|
|
224
226
|
xml.RateRequestTypes('ACCOUNT')
|
@@ -318,7 +318,7 @@ module ActiveShipping
|
|
318
318
|
# Build XML node to request a shipping label for the given packages.
|
319
319
|
#
|
320
320
|
# options:
|
321
|
-
# * origin_account:
|
321
|
+
# * origin_account: account number for the shipper
|
322
322
|
# * customer_context: a "guid like substance" -- according to UPS
|
323
323
|
# * shipper: who is sending the package and where it should be returned
|
324
324
|
# if it is undeliverable.
|
@@ -332,6 +332,7 @@ module ActiveShipping
|
|
332
332
|
# * prepay: if truthy the shipper will be bill immediatly. Otherwise the shipper is billed when the label is used.
|
333
333
|
# * negotiated_rates: if truthy negotiated rates will be requested from ups. Only valid if shipper account has negotiated rates.
|
334
334
|
# * delivery_confirmation: Can be set to any key from SHIPMENT_DELIVERY_CONFIRMATION_CODES. Can also be set on package level via package.options
|
335
|
+
# * bill_third_party: When truthy, bill an account other than the shipper's. Specified by billing_(account, zip and country)
|
335
336
|
def build_shipment_request(origin, destination, packages, options={})
|
336
337
|
packages = Array(packages)
|
337
338
|
shipper = options[:shipper] || origin
|
@@ -381,7 +382,7 @@ module ActiveShipping
|
|
381
382
|
end
|
382
383
|
end
|
383
384
|
|
384
|
-
if options[:
|
385
|
+
if options[:negotiated_rates]
|
385
386
|
xml.RateInformation do
|
386
387
|
xml.NegotiatedRatesIndicator
|
387
388
|
end
|
@@ -397,23 +398,7 @@ module ActiveShipping
|
|
397
398
|
if options[:prepay]
|
398
399
|
xml.PaymentInformation do
|
399
400
|
xml.Prepaid do
|
400
|
-
xml
|
401
|
-
xml.AccountNumber(options[:origin_account])
|
402
|
-
end
|
403
|
-
end
|
404
|
-
end
|
405
|
-
elsif options[:bill_third_party]
|
406
|
-
xml.PaymentInformation do
|
407
|
-
xml.BillThirdParty do
|
408
|
-
xml.BillThirdPartyShipper do
|
409
|
-
xml.AccountNumber(options[:billing_account])
|
410
|
-
xml.ThirdParty do
|
411
|
-
xml.Address do
|
412
|
-
xml.PostalCode(options[:billing_zip])
|
413
|
-
xml.CountryCode(options[:billing_country])
|
414
|
-
end
|
415
|
-
end
|
416
|
-
end
|
401
|
+
build_billing_info_node(xml, options)
|
417
402
|
end
|
418
403
|
end
|
419
404
|
else
|
@@ -422,18 +407,14 @@ module ActiveShipping
|
|
422
407
|
# Type '01' means 'Transportation'
|
423
408
|
# This node specifies who will be billed for transportation.
|
424
409
|
xml.Type('01')
|
425
|
-
xml
|
426
|
-
xml.AccountNumber(options[:origin_account])
|
427
|
-
end
|
410
|
+
build_billing_info_node(xml, options)
|
428
411
|
end
|
429
|
-
if options[:terms_of_shipment] == 'DDP'
|
412
|
+
if options[:terms_of_shipment] == 'DDP' && options[:international]
|
430
413
|
# DDP stands for delivery duty paid and means the shipper will cover duties and taxes
|
431
414
|
# Otherwise UPS will charge the receiver
|
432
415
|
xml.ShipmentCharge do
|
433
416
|
xml.Type('02') # Type '02' means 'Duties and Taxes'
|
434
|
-
xml.
|
435
|
-
xml.AccountNumber(options[:origin_account])
|
436
|
-
end
|
417
|
+
build_billing_info_node(xml, options.merge(bill_to_consignee: true))
|
437
418
|
end
|
438
419
|
end
|
439
420
|
end
|
@@ -762,6 +743,27 @@ module ActiveShipping
|
|
762
743
|
end
|
763
744
|
end
|
764
745
|
|
746
|
+
def build_billing_info_node(xml, options={})
|
747
|
+
if options[:bill_third_party]
|
748
|
+
xml.BillThirdParty do
|
749
|
+
node_type = options[:bill_to_consignee] ? :BillThirdPartyConsignee : :BillThirdPartyShipper
|
750
|
+
xml.public_send(node_type) do
|
751
|
+
xml.AccountNumber(options[:billing_account])
|
752
|
+
xml.ThirdParty do
|
753
|
+
xml.Address do
|
754
|
+
xml.PostalCode(options[:billing_zip])
|
755
|
+
xml.CountryCode(options[:billing_country])
|
756
|
+
end
|
757
|
+
end
|
758
|
+
end
|
759
|
+
end
|
760
|
+
else
|
761
|
+
xml.BillShipper do
|
762
|
+
xml.AccountNumber(options[:origin_account])
|
763
|
+
end
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
765
767
|
def build_document(xml, expected_root_tag)
|
766
768
|
document = Nokogiri.XML(xml)
|
767
769
|
if document.root.nil? || document.root.name != expected_root_tag
|
@@ -13,5 +13,10 @@ module ActiveShipping
|
|
13
13
|
def status
|
14
14
|
@status ||= name.downcase.gsub("\s", "_").to_sym
|
15
15
|
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
attributes = %i(name time location message type_code)
|
19
|
+
attributes.all? { |attr| self.public_send(attr) == other.public_send(attr) }
|
20
|
+
end
|
16
21
|
end
|
17
22
|
end
|
@@ -31,7 +31,7 @@ module ActiveShipping
|
|
31
31
|
#
|
32
32
|
# @!attribute attempted_delivery_date
|
33
33
|
# @return [Date, Time]
|
34
|
-
#
|
34
|
+
#
|
35
35
|
# @!attribute delivery_signature
|
36
36
|
# @return [String]
|
37
37
|
#
|
@@ -101,5 +101,20 @@ module ActiveShipping
|
|
101
101
|
alias_method :scheduled_delivery_time, :scheduled_delivery_date
|
102
102
|
alias_method :actual_delivery_time, :actual_delivery_date
|
103
103
|
alias_method :attempted_delivery_time, :attempted_delivery_date
|
104
|
+
|
105
|
+
def ==(other)
|
106
|
+
attributes = %i(carrier carrier_name status status_code status_description ship_time scheduled_delivery_date
|
107
|
+
actual_delivery_date attempted_delivery_date delivery_signature tracking_number shipper_address
|
108
|
+
origin destination
|
109
|
+
)
|
110
|
+
|
111
|
+
attributes.all? { |attr| self.public_send(attr) == other.public_send(attr) } && compare_shipment_events(other)
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
# Ensure order doesn't matter when comparing shipment_events
|
116
|
+
def compare_shipment_events(other)
|
117
|
+
shipment_events.sort_by(&:time) == other.shipment_events.sort_by(&:time)
|
118
|
+
end
|
104
119
|
end
|
105
120
|
end
|
data/test/remote/ups_test.rb
CHANGED
@@ -267,6 +267,35 @@ class RemoteUPSTest < Minitest::Test
|
|
267
267
|
assert_instance_of ActiveShipping::LabelResponse, response
|
268
268
|
end
|
269
269
|
|
270
|
+
def test_obtain_international_shipping_label_with_bill_third_party
|
271
|
+
begin
|
272
|
+
bill_third_party_credentials = credentials(:ups_third_party_billing)
|
273
|
+
rescue NoCredentialsFound => e
|
274
|
+
skip(e.message)
|
275
|
+
end
|
276
|
+
|
277
|
+
response = @carrier.create_shipment(
|
278
|
+
location_fixtures[:new_york_with_name],
|
279
|
+
location_fixtures[:ottawa_with_name],
|
280
|
+
package_fixtures.values_at(:books),
|
281
|
+
{
|
282
|
+
:service_code => '07',
|
283
|
+
:bill_third_party => true,
|
284
|
+
:billing_account => bill_third_party_credentials[:account],
|
285
|
+
:billing_zip => bill_third_party_credentials[:zip],
|
286
|
+
:billing_country => bill_third_party_credentials[:country_code],
|
287
|
+
:test => true,
|
288
|
+
}
|
289
|
+
)
|
290
|
+
assert response.success?
|
291
|
+
|
292
|
+
# All behavior specific to how a LabelResponse behaves in the
|
293
|
+
# context of UPS label data is a matter for unit tests. If
|
294
|
+
# the data changes substantially, the create_shipment
|
295
|
+
# ought to raise an exception and this test will fail.
|
296
|
+
assert_instance_of ActiveShipping::LabelResponse, response
|
297
|
+
end
|
298
|
+
|
270
299
|
def test_delivery_date_estimates_within_zip
|
271
300
|
today = Date.current
|
272
301
|
|
@@ -601,6 +601,32 @@ class FedExTest < Minitest::Test
|
|
601
601
|
assert_equal result.search('RequestedPackageLineItems/CustomerReferences/Value').text, "FOO-123"
|
602
602
|
end
|
603
603
|
|
604
|
+
def test_create_shipment_default_label_stock_type
|
605
|
+
packages = package_fixtures.values_at(:wii)
|
606
|
+
|
607
|
+
result = Nokogiri::XML(@carrier.send(:build_shipment_request,
|
608
|
+
location_fixtures[:beverly_hills],
|
609
|
+
location_fixtures[:annapolis],
|
610
|
+
packages,
|
611
|
+
:test => true))
|
612
|
+
|
613
|
+
assert_equal result.search('RequestedShipment/LabelSpecification/LabelStockType').text, FedEx::DEFAULT_LABEL_STOCK_TYPE
|
614
|
+
end
|
615
|
+
|
616
|
+
def test_create_shipment_label_stock_type
|
617
|
+
label_stock_type = 'PAPER_4X6'
|
618
|
+
packages = package_fixtures.values_at(:wii)
|
619
|
+
|
620
|
+
result = Nokogiri::XML(@carrier.send(:build_shipment_request,
|
621
|
+
location_fixtures[:beverly_hills],
|
622
|
+
location_fixtures[:annapolis],
|
623
|
+
packages,
|
624
|
+
:test => true,
|
625
|
+
:label_stock_type => label_stock_type))
|
626
|
+
|
627
|
+
assert_equal result.search('RequestedShipment/LabelSpecification/LabelStockType').text, label_stock_type
|
628
|
+
end
|
629
|
+
|
604
630
|
def test_maximum_address_field_length
|
605
631
|
assert_equal 35, @carrier.maximum_address_field_length
|
606
632
|
end
|
@@ -365,9 +365,9 @@ class UPSTest < Minitest::Test
|
|
365
365
|
:billing_zip => expected_postal_code_number,
|
366
366
|
:billing_country => expected_country_code)
|
367
367
|
|
368
|
-
assert_equal expected_account_number, response.search('ShipmentConfirmRequest/Shipment/
|
369
|
-
assert_equal expected_postal_code_number, response.search('/ShipmentConfirmRequest/Shipment/
|
370
|
-
assert_equal expected_country_code, response.search('/ShipmentConfirmRequest/Shipment/
|
368
|
+
assert_equal expected_account_number, response.search('ShipmentConfirmRequest/Shipment/ItemizedPaymentInformation/ShipmentCharge/BillThirdParty/BillThirdPartyShipper/AccountNumber').text
|
369
|
+
assert_equal expected_postal_code_number, response.search('/ShipmentConfirmRequest/Shipment/ItemizedPaymentInformation/ShipmentCharge/BillThirdParty/BillThirdPartyShipper/ThirdParty/Address/PostalCode').text
|
370
|
+
assert_equal expected_country_code, response.search('/ShipmentConfirmRequest/Shipment/ItemizedPaymentInformation/ShipmentCharge/BillThirdParty/BillThirdPartyShipper/ThirdParty/Address/CountryCode').text
|
371
371
|
end
|
372
372
|
|
373
373
|
def test_label_request_negotiated_rates_presence
|
@@ -377,7 +377,8 @@ class UPSTest < Minitest::Test
|
|
377
377
|
package_fixtures.values_at(:chocolate_stuff),
|
378
378
|
:test => true,
|
379
379
|
:saturday_delivery => true,
|
380
|
-
:origin_account => 'A01B23' # without this option, a negotiated rate will not be requested
|
380
|
+
:origin_account => 'A01B23', # without this option, a negotiated rate will not be requested
|
381
|
+
:negotiated_rates => true,
|
381
382
|
)
|
382
383
|
|
383
384
|
negotiated_rates = response.search '/ShipmentConfirmRequest/Shipment/RateInformation/NegotiatedRatesIndicator'
|
data/test/unit/location_test.rb
CHANGED
@@ -125,4 +125,11 @@ class LocationTest < Minitest::Test
|
|
125
125
|
location = Location.from(:address3 => address3)
|
126
126
|
assert_equal 'Victory Lane', location.address2_and_3
|
127
127
|
end
|
128
|
+
|
129
|
+
def test_equality
|
130
|
+
location_1 = location_fixtures[:ottawa]
|
131
|
+
location_2 = Location.from(location_1.to_hash)
|
132
|
+
|
133
|
+
assert_equal location_1, location_2
|
134
|
+
end
|
128
135
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ShipmentEventTest < Minitest::Test
|
4
|
+
def test_equality
|
5
|
+
options1 = [
|
6
|
+
'ARRIVED AT UNIT',
|
7
|
+
DateTime.new(2016, 5, 12, 5, 45),
|
8
|
+
Location.new(city: 'SAN JOSE', state: 'CA', postal_code: '90001', country: 'US'),
|
9
|
+
'ARRIVED AT UNIT',
|
10
|
+
'07'
|
11
|
+
]
|
12
|
+
# Copies options to create new DateTime and Location objects to check for similar distinct objects
|
13
|
+
options2 = options1.dup
|
14
|
+
|
15
|
+
shipment_event_1 = ShipmentEvent.new(*options1)
|
16
|
+
shipment_event_2 = ShipmentEvent.new(*options2)
|
17
|
+
|
18
|
+
assert_equal shipment_event_1, shipment_event_2
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TrackingResponseTest < Minitest::Test
|
4
|
+
def test_equality
|
5
|
+
options1 = {
|
6
|
+
carrier: 'usps',
|
7
|
+
status: 'DELIVERED',
|
8
|
+
status_code: 'I0',
|
9
|
+
status_description: 'DELIVERED',
|
10
|
+
actual_delivery_date: DateTime.new(2016, 5, 14, 13, 20),
|
11
|
+
tracking_number: 'TRACKINGNUMBER1234ABC',
|
12
|
+
shipment_events: [
|
13
|
+
ShipmentEvent.new(
|
14
|
+
'DELIVERED',
|
15
|
+
DateTime.new(2016, 5, 14, 13, 20),
|
16
|
+
Location.new(city: 'LOS ANGELES', state: 'CA', postal_code: '90210', country: 'US'),
|
17
|
+
'DELIVERED',
|
18
|
+
'I0'
|
19
|
+
),
|
20
|
+
ShipmentEvent.new(
|
21
|
+
'ARRIVED AT UNIT',
|
22
|
+
DateTime.new(2016, 5, 12, 5, 45),
|
23
|
+
Location.new(city: 'SAN JOSE', state: 'CA', postal_code: '90001', country: 'US'),
|
24
|
+
'ARRIVED AT UNIT',
|
25
|
+
'07'
|
26
|
+
)
|
27
|
+
],
|
28
|
+
destination: Location.new(postal_code: '90210'),
|
29
|
+
origin: Location.new(postal_code: '00001')
|
30
|
+
}
|
31
|
+
# Deep copies options1 to create new ShipmentEvent, Location, etc. objects to check for similar distinct objects
|
32
|
+
options2 = Marshal.load(Marshal.dump(options1))
|
33
|
+
options2[:shipment_events][0], options2[:shipment_events][1] =
|
34
|
+
options2[:shipment_events][1], options2[:shipment_events][0]
|
35
|
+
|
36
|
+
tracking_response_1 = TrackingResponse.new(true, nil, {}, options1)
|
37
|
+
tracking_response_2 = TrackingResponse.new(true, nil, {}, options2)
|
38
|
+
|
39
|
+
assert_equal tracking_response_1, tracking_response_2
|
40
|
+
end
|
41
|
+
end
|
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.7.
|
4
|
+
version: 1.7.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: 2016-
|
14
|
+
date: 2016-05-19 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: quantified
|
@@ -399,7 +399,9 @@ files:
|
|
399
399
|
- test/unit/package_test.rb
|
400
400
|
- test/unit/rate_estimate_test.rb
|
401
401
|
- test/unit/response_test.rb
|
402
|
+
- test/unit/shipment_event_test.rb
|
402
403
|
- test/unit/shipment_packer_test.rb
|
404
|
+
- test/unit/tracking_response_test.rb
|
403
405
|
homepage: http://github.com/shopify/active_shipping
|
404
406
|
licenses:
|
405
407
|
- MIT
|
@@ -606,4 +608,6 @@ test_files:
|
|
606
608
|
- test/unit/package_test.rb
|
607
609
|
- test/unit/rate_estimate_test.rb
|
608
610
|
- test/unit/response_test.rb
|
611
|
+
- test/unit/shipment_event_test.rb
|
609
612
|
- test/unit/shipment_packer_test.rb
|
613
|
+
- test/unit/tracking_response_test.rb
|