active_shipping 0.12.4 → 0.12.5
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/lib/active_shipping.rb +2 -1
- data/lib/active_shipping/shipping/base.rb +2 -2
- data/lib/active_shipping/shipping/carrier.rb +16 -13
- data/lib/active_shipping/shipping/carriers/benchmark_carrier.rb +3 -4
- data/lib/active_shipping/shipping/carriers/bogus_carrier.rb +1 -3
- data/lib/active_shipping/shipping/carriers/canada_post.rb +33 -44
- data/lib/active_shipping/shipping/carriers/canada_post_pws.rb +72 -81
- data/lib/active_shipping/shipping/carriers/fedex.rb +118 -109
- data/lib/active_shipping/shipping/carriers/kunaki.rb +33 -32
- data/lib/active_shipping/shipping/carriers/new_zealand_post.rb +9 -16
- data/lib/active_shipping/shipping/carriers/shipwire.rb +36 -35
- data/lib/active_shipping/shipping/carriers/stamps.rb +39 -51
- data/lib/active_shipping/shipping/carriers/ups.rb +280 -116
- data/lib/active_shipping/shipping/carriers/ups.rb.orig +456 -0
- data/lib/active_shipping/shipping/carriers/usps.rb +145 -100
- data/lib/active_shipping/shipping/carriers/usps.rb.orig +616 -0
- data/lib/active_shipping/shipping/errors.rb +1 -1
- data/lib/active_shipping/shipping/label_response.rb +25 -0
- data/lib/active_shipping/shipping/location.rb +18 -16
- data/lib/active_shipping/shipping/package.rb +51 -54
- data/lib/active_shipping/shipping/rate_estimate.rb +10 -12
- data/lib/active_shipping/shipping/rate_response.rb +3 -7
- data/lib/active_shipping/shipping/response.rb +6 -9
- data/lib/active_shipping/shipping/shipment_event.rb +2 -4
- data/lib/active_shipping/shipping/shipment_packer.rb +32 -17
- data/lib/active_shipping/shipping/shipping_response.rb +2 -4
- data/lib/active_shipping/shipping/tracking_response.rb +3 -5
- data/lib/active_shipping/version.rb +1 -1
- data/lib/vendor/quantified/lib/quantified/attribute.rb +79 -80
- data/lib/vendor/quantified/lib/quantified/length.rb +5 -5
- data/lib/vendor/quantified/lib/quantified/mass.rb +4 -4
- data/lib/vendor/quantified/test/length_test.rb +19 -15
- data/lib/vendor/quantified/test/mass_test.rb +14 -14
- data/lib/vendor/quantified/test/test_helper.rb +1 -2
- data/lib/vendor/test_helper.rb +0 -1
- data/lib/vendor/xml_node/benchmark/bench_generation.rb +2 -4
- data/lib/vendor/xml_node/lib/xml_node.rb +54 -55
- data/lib/vendor/xml_node/test/test_generating.rb +23 -28
- data/lib/vendor/xml_node/test/test_parsing.rb +5 -8
- metadata +6 -25
- checksums.yaml.gz.sig +0 -1
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
@@ -3,7 +3,6 @@ require 'cgi'
|
|
3
3
|
|
4
4
|
module ActiveMerchant
|
5
5
|
module Shipping
|
6
|
-
|
7
6
|
# After getting an API login from USPS (looks like '123YOURNAME456'),
|
8
7
|
# run the following test:
|
9
8
|
#
|
@@ -26,7 +25,7 @@ module ActiveMerchant
|
|
26
25
|
LIVE_DOMAIN = 'production.shippingapis.com'
|
27
26
|
LIVE_RESOURCE = 'ShippingAPI.dll'
|
28
27
|
|
29
|
-
TEST_DOMAINS = { #indexed by security; e.g. TEST_DOMAINS[USE_SSL[:rates]]
|
28
|
+
TEST_DOMAINS = { # indexed by security; e.g. TEST_DOMAINS[USE_SSL[:rates]]
|
30
29
|
true => 'secure.shippingapis.com',
|
31
30
|
false => 'testing.shippingapis.com'
|
32
31
|
}
|
@@ -45,10 +44,23 @@ module ActiveMerchant
|
|
45
44
|
:test => true,
|
46
45
|
:track => false
|
47
46
|
}
|
47
|
+
|
48
48
|
CONTAINERS = {
|
49
|
-
:
|
50
|
-
:
|
49
|
+
rectangular: 'RECTANGULAR',
|
50
|
+
variable: 'VARIABLE',
|
51
|
+
box: 'FLAT RATE BOX',
|
52
|
+
box_large: 'LG FLAT RATE BOX',
|
53
|
+
box_medium: 'MD FLAT RATE BOX',
|
54
|
+
box_small: 'SM FLAT RATE BOX',
|
55
|
+
envelope: 'FLAT RATE ENVELOPE',
|
56
|
+
envelope_legal: 'LEGAL FLAT RATE ENVELOPE',
|
57
|
+
envelope_padded: 'PADDED FLAT RATE ENVELOPE',
|
58
|
+
envelope_gift_card: 'GIFT CARD FLAT RATE ENVELOPE',
|
59
|
+
envelope_window: 'WINDOW FLAT RATE ENVELOPE',
|
60
|
+
envelope_small: 'SM FLAT RATE ENVELOPE',
|
61
|
+
package_service: 'PACKAGE SERVICE'
|
51
62
|
}
|
63
|
+
|
52
64
|
MAIL_TYPES = {
|
53
65
|
:package => 'Package',
|
54
66
|
:postcard => 'Postcards or aerogrammes',
|
@@ -81,8 +93,25 @@ module ActiveMerchant
|
|
81
93
|
:media => 'MEDIA',
|
82
94
|
:library => 'LIBRARY',
|
83
95
|
:online => 'ONLINE',
|
96
|
+
:plus => 'PLUS',
|
84
97
|
:all => 'ALL'
|
85
98
|
}
|
99
|
+
DEFAULT_SERVICE = Hash.new(:all).update(
|
100
|
+
:base => :online,
|
101
|
+
:plus => :plus
|
102
|
+
)
|
103
|
+
DOMESTIC_RATE_FIELD = Hash.new('Rate').update(
|
104
|
+
:base => 'CommercialRate',
|
105
|
+
:plus => 'CommercialPlusRate'
|
106
|
+
)
|
107
|
+
INTERNATIONAL_RATE_FIELD = Hash.new('Postage').update(
|
108
|
+
:base => 'CommercialPostage',
|
109
|
+
:plus => 'CommercialPlusPostage'
|
110
|
+
)
|
111
|
+
COMMERCIAL_FLAG_NAME = {
|
112
|
+
:base => 'CommercialFlag',
|
113
|
+
:plus => 'CommercialPlusFlag'
|
114
|
+
}
|
86
115
|
FIRST_CLASS_MAIL_TYPES = {
|
87
116
|
:letter => 'LETTER',
|
88
117
|
:flat => 'FLAT',
|
@@ -92,7 +121,7 @@ module ActiveMerchant
|
|
92
121
|
}
|
93
122
|
|
94
123
|
# Array of U.S. possessions according to USPS: https://www.usps.com/ship/official-abbreviations.htm
|
95
|
-
US_POSSESSIONS =
|
124
|
+
US_POSSESSIONS = %w(AS FM GU MH MP PW PR VI)
|
96
125
|
|
97
126
|
# TODO: figure out how USPS likes to say "Ivory Coast"
|
98
127
|
#
|
@@ -141,7 +170,12 @@ module ActiveMerchant
|
|
141
170
|
/Delivery status information is not available/
|
142
171
|
]
|
143
172
|
|
144
|
-
|
173
|
+
ESCAPING_AND_SYMBOLS = /<\S*>/
|
174
|
+
LEADING_USPS = /^USPS/
|
175
|
+
TRAILING_ASTERISKS = /\*+$/
|
176
|
+
SERVICE_NAME_SUBSTITUTIONS = /#{ESCAPING_AND_SYMBOLS}|#{LEADING_USPS}|#{TRAILING_ASTERISKS}/
|
177
|
+
|
178
|
+
def find_tracking_info(tracking_number, options = {})
|
145
179
|
options = @options.update(options)
|
146
180
|
tracking_request = build_tracking_request(tracking_number, options)
|
147
181
|
response = commit(:track, tracking_request, (options[:test] || false))
|
@@ -160,7 +194,7 @@ module ActiveMerchant
|
|
160
194
|
#
|
161
195
|
# package.options[:books] -- 25 lb. limit instead of 35 for books or other printed matter.
|
162
196
|
# Defaults to false.
|
163
|
-
def self.package_machinable?(package, options={})
|
197
|
+
def self.package_machinable?(package, options = {})
|
164
198
|
at_least_minimum = package.inches(:length) >= 6.0 &&
|
165
199
|
package.inches(:width) >= 3.0 &&
|
166
200
|
package.inches(:height) >= 0.25 &&
|
@@ -183,12 +217,8 @@ module ActiveMerchant
|
|
183
217
|
destination = Location.from(destination)
|
184
218
|
packages = Array(packages)
|
185
219
|
|
186
|
-
#raise ArgumentError.new("USPS packages must originate in the U.S.") unless ['US',nil].include?(origin.country_code(:alpha2))
|
187
|
-
|
188
|
-
# domestic or international?
|
189
|
-
|
190
220
|
domestic_codes = US_POSSESSIONS + ['US', nil]
|
191
|
-
|
221
|
+
if domestic_codes.include?(destination.country_code(:alpha2))
|
192
222
|
us_rates(origin, destination, packages, options)
|
193
223
|
else
|
194
224
|
world_rates(origin, destination, packages, options)
|
@@ -205,7 +235,7 @@ module ActiveMerchant
|
|
205
235
|
end
|
206
236
|
|
207
237
|
def extract_event_details(message)
|
208
|
-
return EventDetails.new unless EVENT_MESSAGE_PATTERNS.any?{|pattern| message =~ pattern}
|
238
|
+
return EventDetails.new unless EVENT_MESSAGE_PATTERNS.any? { |pattern| message =~ pattern }
|
209
239
|
description = $1.upcase
|
210
240
|
timestamp = $2
|
211
241
|
city = $3
|
@@ -215,66 +245,77 @@ module ActiveMerchant
|
|
215
245
|
time = Time.parse(timestamp)
|
216
246
|
zoneless_time = Time.utc(time.year, time.month, time.mday, time.hour, time.min, time.sec)
|
217
247
|
location = Location.new(city: city, state: state, postal_code: zip_code, country: 'USA')
|
218
|
-
EventDetails.new(
|
248
|
+
EventDetails.new(description, time, zoneless_time, location)
|
219
249
|
end
|
220
250
|
|
221
251
|
protected
|
222
252
|
|
223
|
-
def build_tracking_request(tracking_number, options={})
|
253
|
+
def build_tracking_request(tracking_number, options = {})
|
224
254
|
xml_request = XmlNode.new('TrackRequest', 'USERID' => @options[:login]) do |root_node|
|
225
255
|
root_node << XmlNode.new('TrackID', :ID => tracking_number)
|
226
256
|
end
|
227
257
|
URI.encode(xml_request.to_s)
|
228
258
|
end
|
229
259
|
|
230
|
-
def us_rates(origin, destination, packages, options={})
|
260
|
+
def us_rates(origin, destination, packages, options = {})
|
231
261
|
request = build_us_rate_request(packages, origin.zip, destination.zip, options)
|
232
|
-
|
233
|
-
parse_rate_response origin, destination, packages, commit(:us_rates,request,false), options
|
262
|
+
# never use test mode; rate requests just won't work on test servers
|
263
|
+
parse_rate_response origin, destination, packages, commit(:us_rates, request, false), options
|
234
264
|
end
|
235
265
|
|
236
|
-
def world_rates(origin, destination, packages, options={})
|
237
|
-
request = build_world_rate_request(packages, destination)
|
238
|
-
|
239
|
-
parse_rate_response origin, destination, packages, commit(:world_rates,request,false), options
|
266
|
+
def world_rates(origin, destination, packages, options = {})
|
267
|
+
request = build_world_rate_request(packages, destination, options)
|
268
|
+
# never use test mode; rate requests just won't work on test servers
|
269
|
+
parse_rate_response origin, destination, packages, commit(:world_rates, request, false), options
|
240
270
|
end
|
241
271
|
|
242
272
|
# Once the address verification API is implemented, remove this and have valid_credentials? build the request using that instead.
|
243
273
|
def canned_address_verification_works?
|
244
274
|
return false unless @options[:login]
|
245
|
-
request =
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
275
|
+
request = <<-EOF
|
276
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
277
|
+
<CarrierPickupAvailabilityRequest USERID="#{URI.encode(@options[:login])}">
|
278
|
+
<FirmName>Shopifolk</FirmName>
|
279
|
+
<SuiteOrApt>Suite 0</SuiteOrApt>
|
280
|
+
<Address2>18 Fair Ave</Address2>
|
281
|
+
<Urbanization />
|
282
|
+
<City>San Francisco</City>
|
283
|
+
<State>CA</State>
|
284
|
+
<ZIP5>94110</ZIP5>
|
285
|
+
<ZIP4>9411</ZIP4>
|
286
|
+
</CarrierPickupAvailabilityRequest>
|
287
|
+
EOF
|
288
|
+
xml = REXML::Document.new(commit(:test, URI.encode(request), true))
|
289
|
+
xml.get_text('/CarrierPickupAvailabilityResponse/City').to_s == 'SAN FRANCISCO' && xml.get_text('/CarrierPickupAvailabilityResponse/Address2').to_s == '18 FAIR AVE'
|
250
290
|
end
|
251
291
|
|
252
292
|
# options[:service] -- One of [:first_class, :priority, :express, :bpm, :parcel,
|
253
|
-
# :media, :library, :all]. defaults to :all.
|
254
|
-
# options[:container] -- One of [:envelope, :box]. defaults to neither (this field has
|
255
|
-
# special meaning in the USPS API).
|
293
|
+
# :media, :library, :online, :plus, :all]. defaults to :all.
|
256
294
|
# options[:books] -- Either true or false. Packages of books or other printed matter
|
257
295
|
# have a lower weight limit to be considered machinable.
|
296
|
+
# package.options[:container] -- Can be :rectangular, :variable, or a flat rate container
|
297
|
+
# defined in CONTAINERS.
|
258
298
|
# package.options[:machinable] -- Either true or false. Overrides the detection of
|
259
299
|
# "machinability" entirely.
|
260
|
-
def build_us_rate_request(packages, origin_zip, destination_zip, options={})
|
300
|
+
def build_us_rate_request(packages, origin_zip, destination_zip, options = {})
|
261
301
|
packages = Array(packages)
|
262
302
|
request = XmlNode.new('RateV4Request', :USERID => @options[:login]) do |rate_request|
|
263
|
-
packages.each_with_index do |p,id|
|
303
|
+
packages.each_with_index do |p, id|
|
264
304
|
rate_request << XmlNode.new('Package', :ID => id.to_s) do |package|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
305
|
+
commercial_type = commercial_type(options)
|
306
|
+
default_service = DEFAULT_SERVICE[commercial_type]
|
307
|
+
service = options.fetch(:service, default_service).to_sym
|
308
|
+
|
309
|
+
if commercial_type && service != default_service
|
310
|
+
raise ArgumentError, "Commercial #{commercial_type} rates are only provided with the #{default_service.inspect} service."
|
270
311
|
end
|
271
312
|
|
272
|
-
package << XmlNode.new('Service', US_SERVICES[
|
273
|
-
package << XmlNode.new('FirstClassMailType', FIRST_CLASS_MAIL_TYPES[options[:first_class_mail_type]])
|
313
|
+
package << XmlNode.new('Service', US_SERVICES[service])
|
314
|
+
package << XmlNode.new('FirstClassMailType', FIRST_CLASS_MAIL_TYPES[options[:first_class_mail_type].try(:to_sym)])
|
274
315
|
package << XmlNode.new('ZipOrigination', strip_zip(origin_zip))
|
275
316
|
package << XmlNode.new('ZipDestination', strip_zip(destination_zip))
|
276
317
|
package << XmlNode.new('Pounds', 0)
|
277
|
-
package << XmlNode.new('Ounces', "%0.1f" % [p.ounces,1].max)
|
318
|
+
package << XmlNode.new('Ounces', "%0.1f" % [p.ounces, 1].max)
|
278
319
|
package << XmlNode.new('Container', CONTAINERS[p.options[:container]])
|
279
320
|
package << XmlNode.new('Size', USPS.size_code_for(p))
|
280
321
|
package << XmlNode.new('Width', "%0.2f" % p.inches(:width))
|
@@ -302,14 +343,14 @@ module ActiveMerchant
|
|
302
343
|
#
|
303
344
|
# package.options[:mail_type] -- one of [:package, :postcard, :matter_for_the_blind, :envelope].
|
304
345
|
# Defaults to :package.
|
305
|
-
def build_world_rate_request(packages, destination)
|
346
|
+
def build_world_rate_request(packages, destination, options)
|
306
347
|
country = COUNTRY_NAME_CONVERSIONS[destination.country.code(:alpha2).value] || destination.country.name
|
307
348
|
request = XmlNode.new('IntlRateV2Request', :USERID => @options[:login]) do |rate_request|
|
308
349
|
packages.each_index do |id|
|
309
350
|
p = packages[id]
|
310
351
|
rate_request << XmlNode.new('Package', :ID => id.to_s) do |package|
|
311
352
|
package << XmlNode.new('Pounds', 0)
|
312
|
-
package << XmlNode.new('Ounces', [p.ounces,1].max.ceil) #takes an integer for some reason, must be rounded UP
|
353
|
+
package << XmlNode.new('Ounces', [p.ounces, 1].max.ceil) # takes an integer for some reason, must be rounded UP
|
313
354
|
package << XmlNode.new('MailType', MAIL_TYPES[p.options[:mail_type]] || 'Package')
|
314
355
|
package << XmlNode.new('GXG') do |gxg|
|
315
356
|
gxg << XmlNode.new('POBoxFlag', destination.po_box? ? 'Y' : 'N')
|
@@ -330,14 +371,16 @@ module ActiveMerchant
|
|
330
371
|
package << XmlNode.new('Length', "%0.2f" % [p.inches(:length), 0.01].max)
|
331
372
|
package << XmlNode.new('Height', "%0.2f" % [p.inches(:height), 0.01].max)
|
332
373
|
package << XmlNode.new('Girth', "%0.2f" % [p.inches(:girth), 0.01].max)
|
333
|
-
|
374
|
+
if commercial_type = commercial_type(options)
|
375
|
+
package << XmlNode.new(COMMERCIAL_FLAG_NAME.fetch(commercial_type), 'Y')
|
376
|
+
end
|
334
377
|
end
|
335
378
|
end
|
336
379
|
end
|
337
380
|
URI.encode(save_request(request.to_s))
|
338
381
|
end
|
339
382
|
|
340
|
-
def parse_rate_response(origin, destination, packages, response, options={})
|
383
|
+
def parse_rate_response(origin, destination, packages, response, options = {})
|
341
384
|
success = true
|
342
385
|
message = ''
|
343
386
|
rate_hash = {}
|
@@ -357,7 +400,7 @@ module ActiveMerchant
|
|
357
400
|
end
|
358
401
|
|
359
402
|
if success
|
360
|
-
rate_hash = rates_from_response_node(xml, packages)
|
403
|
+
rate_hash = rates_from_response_node(xml, packages, options)
|
361
404
|
unless rate_hash
|
362
405
|
success = false
|
363
406
|
message = "Unknown root node in XML response: '#{xml.root.name}'"
|
@@ -368,31 +411,28 @@ module ActiveMerchant
|
|
368
411
|
|
369
412
|
if success
|
370
413
|
rate_estimates = rate_hash.keys.map do |service_name|
|
371
|
-
RateEstimate.new(origin,destination
|
372
|
-
|
373
|
-
|
374
|
-
|
414
|
+
RateEstimate.new(origin, destination, @@name, "USPS #{service_name}",
|
415
|
+
:package_rates => rate_hash[service_name][:package_rates],
|
416
|
+
:service_code => rate_hash[service_name][:service_code],
|
417
|
+
:currency => 'USD')
|
375
418
|
end
|
376
|
-
rate_estimates.reject! {|e| e.package_count != packages.length}
|
419
|
+
rate_estimates.reject! { |e| e.package_count != packages.length }
|
377
420
|
rate_estimates = rate_estimates.sort_by(&:total_price)
|
378
421
|
end
|
379
422
|
|
380
423
|
RateResponse.new(success, message, Hash.from_xml(response), :rates => rate_estimates, :xml => response, :request => last_request)
|
381
424
|
end
|
382
425
|
|
383
|
-
def rates_from_response_node(response_node, packages)
|
426
|
+
def rates_from_response_node(response_node, packages, options = {})
|
384
427
|
rate_hash = {}
|
385
428
|
return false unless (root_node = response_node.elements['/IntlRateV2Response | /RateV4Response'])
|
386
|
-
domestic = (root_node.name == 'RateV4Response')
|
387
429
|
|
388
|
-
|
389
|
-
|
390
|
-
|
430
|
+
commercial_type = commercial_type(options)
|
431
|
+
service_node, service_code_node, service_name_node, rate_node = if root_node.name == 'RateV4Response'
|
432
|
+
%w(Postage CLASSID MailService) << DOMESTIC_RATE_FIELD[commercial_type]
|
391
433
|
else
|
392
|
-
|
393
|
-
international_elements = ['Service', 'ID', 'SvcDescription', 'Postage']
|
434
|
+
%w(Service ID SvcDescription) << INTERNATIONAL_RATE_FIELD[commercial_type]
|
394
435
|
end
|
395
|
-
service_node, service_code_node, service_name_node, rate_node = domestic ? domestic_elements : international_elements
|
396
436
|
|
397
437
|
root_node.each_element('Package') do |package_node|
|
398
438
|
this_package = packages[package_node.attributes['ID'].to_i]
|
@@ -400,13 +440,7 @@ module ActiveMerchant
|
|
400
440
|
package_node.each_element(service_node) do |service_response_node|
|
401
441
|
service_name = service_response_node.get_text(service_name_node).to_s
|
402
442
|
|
403
|
-
|
404
|
-
service_name.gsub!(/&lt;\S*&gt;/,'')
|
405
|
-
# ...leading "USPS"
|
406
|
-
service_name.gsub!(/^USPS/,'')
|
407
|
-
# ...trailing asterisks
|
408
|
-
service_name.gsub!(/\*+$/,'')
|
409
|
-
# ...surrounding spaces
|
443
|
+
service_name.gsub!(SERVICE_NAME_SUBSTITUTIONS, '')
|
410
444
|
service_name.strip!
|
411
445
|
|
412
446
|
# aggregate specific package rates into a service-centric RateEstimate
|
@@ -416,9 +450,9 @@ module ActiveMerchant
|
|
416
450
|
this_service[:service_code] ||= service_response_node.attributes[service_code_node]
|
417
451
|
package_rates = this_service[:package_rates] ||= []
|
418
452
|
this_package_rate = {:package => this_package,
|
419
|
-
:rate => Package.cents_from(
|
453
|
+
:rate => Package.cents_from(rate_value(rate_node, service_response_node, commercial_type))}
|
420
454
|
|
421
|
-
package_rates << this_package_rate if package_valid_for_service(this_package,service_response_node)
|
455
|
+
package_rates << this_package_rate if package_valid_for_service(this_package, service_response_node)
|
422
456
|
end
|
423
457
|
end
|
424
458
|
rate_hash
|
@@ -429,38 +463,38 @@ module ActiveMerchant
|
|
429
463
|
max_weight = service_node.get_text('MaxWeight').to_s.to_f
|
430
464
|
name = service_node.get_text('SvcDescription | MailService').to_s.downcase
|
431
465
|
|
432
|
-
if name =~ /flat.rate.box/ #domestic or international flat rate box
|
466
|
+
if name =~ /flat.rate.box/ # domestic or international flat rate box
|
433
467
|
# flat rate dimensions from http://www.usps.com/shipping/flatrate.htm
|
434
468
|
return (package_valid_for_max_dimensions(package,
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
469
|
+
:weight => max_weight, # domestic apparently has no weight restriction
|
470
|
+
:length => 11.0,
|
471
|
+
:width => 8.5,
|
472
|
+
:height => 5.5) or
|
439
473
|
package_valid_for_max_dimensions(package,
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
474
|
+
:weight => max_weight,
|
475
|
+
:length => 13.625,
|
476
|
+
:width => 11.875,
|
477
|
+
:height => 3.375))
|
444
478
|
elsif name =~ /flat.rate.envelope/
|
445
479
|
return package_valid_for_max_dimensions(package,
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
480
|
+
:weight => max_weight,
|
481
|
+
:length => 12.5,
|
482
|
+
:width => 9.5,
|
483
|
+
:height => 0.75)
|
450
484
|
elsif service_node.elements['MailService'] # domestic non-flat rates
|
451
485
|
return true
|
452
|
-
else #international non-flat rates
|
486
|
+
else # international non-flat rates
|
453
487
|
# Some sample english that this is required to parse:
|
454
488
|
#
|
455
489
|
# 'Max. length 46", width 35", height 46" and max. length plus girth 108"'
|
456
490
|
# 'Max. length 24", Max. length, height, depth combined 36"'
|
457
491
|
#
|
458
492
|
sentence = CGI.unescapeHTML(service_node.get_text('MaxDimensions').to_s)
|
459
|
-
tokens = sentence.downcase.split(/[^\d]*"/).reject
|
493
|
+
tokens = sentence.downcase.split(/[^\d]*"/).reject(&:empty?)
|
460
494
|
max_dimensions = {:weight => max_weight}
|
461
495
|
single_axis_values = []
|
462
496
|
tokens.each do |token|
|
463
|
-
axis_sum = [/length
|
497
|
+
axis_sum = [/length/, /width/, /height/, /depth/].sum { |regex| (token =~ regex) ? 1 : 0 }
|
464
498
|
unless axis_sum == 0
|
465
499
|
value = token[/\d+$/].to_f
|
466
500
|
if axis_sum == 3
|
@@ -473,15 +507,15 @@ module ActiveMerchant
|
|
473
507
|
end
|
474
508
|
end
|
475
509
|
single_axis_values.sort!.reverse!
|
476
|
-
[:length, :width, :height].each_with_index do |axis,i|
|
510
|
+
[:length, :width, :height].each_with_index do |axis, i|
|
477
511
|
max_dimensions[axis] = single_axis_values[i] if single_axis_values[i]
|
478
512
|
end
|
479
|
-
|
513
|
+
package_valid_for_max_dimensions(package, max_dimensions)
|
480
514
|
end
|
481
515
|
end
|
482
516
|
|
483
|
-
def package_valid_for_max_dimensions(package,dimensions)
|
484
|
-
|
517
|
+
def package_valid_for_max_dimensions(package, dimensions)
|
518
|
+
((not ([:length, :width, :height].map { |dim| dimensions[dim].nil? || dimensions[dim].to_f >= package.inches(dim).to_f }.include?(false))) and
|
485
519
|
(dimensions[:weight].nil? || dimensions[:weight] >= package.pounds) and
|
486
520
|
(dimensions[:length_plus_girth].nil? or
|
487
521
|
dimensions[:length_plus_girth].to_f >=
|
@@ -489,8 +523,6 @@ module ActiveMerchant
|
|
489
523
|
(dimensions[:length_plus_width_plus_height].nil? or
|
490
524
|
dimensions[:length_plus_width_plus_height].to_f >=
|
491
525
|
package.inches(:length) + package.inches(:width) + package.inches(:height)))
|
492
|
-
|
493
|
-
return valid
|
494
526
|
end
|
495
527
|
|
496
528
|
def parse_tracking_response(response, options)
|
@@ -502,11 +534,11 @@ module ActiveMerchant
|
|
502
534
|
message = response_message(xml)
|
503
535
|
|
504
536
|
if success
|
505
|
-
|
537
|
+
destination = nil
|
506
538
|
shipment_events = []
|
507
|
-
tracking_details = xml.elements.collect('*/*/TrackDetail'){ |e| e }
|
539
|
+
tracking_details = xml.elements.collect('*/*/TrackDetail') { |e| e }
|
508
540
|
|
509
|
-
tracking_summary = xml.elements.collect('*/*/TrackSummary'){ |e| e }.first
|
541
|
+
tracking_summary = xml.elements.collect('*/*/TrackSummary') { |e| e }.first
|
510
542
|
tracking_details << tracking_summary
|
511
543
|
|
512
544
|
tracking_number = root_node.elements['TrackInfo'].attributes['ID'].to_s
|
@@ -525,14 +557,14 @@ module ActiveMerchant
|
|
525
557
|
end
|
526
558
|
|
527
559
|
TrackingResponse.new(success, message, Hash.from_xml(response),
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
560
|
+
:carrier => @@name,
|
561
|
+
:xml => response,
|
562
|
+
:request => last_request,
|
563
|
+
:shipment_events => shipment_events,
|
564
|
+
:destination => destination,
|
565
|
+
:tracking_number => tracking_number,
|
566
|
+
:status => status,
|
567
|
+
:actual_delivery_date => actual_delivery_date
|
536
568
|
)
|
537
569
|
end
|
538
570
|
|
@@ -595,6 +627,19 @@ module ActiveMerchant
|
|
595
627
|
zip.to_s.scan(/\d{5}/).first || zip
|
596
628
|
end
|
597
629
|
|
630
|
+
private
|
631
|
+
|
632
|
+
def rate_value(rate_node, service_response_node, commercial_type)
|
633
|
+
service_response_node.get_text(rate_node).to_s.to_f
|
634
|
+
end
|
635
|
+
|
636
|
+
def commercial_type(options)
|
637
|
+
if options[:commercial_plus] == true
|
638
|
+
:plus
|
639
|
+
elsif options[:commercial_base] == true
|
640
|
+
:base
|
641
|
+
end
|
642
|
+
end
|
598
643
|
end
|
599
644
|
end
|
600
645
|
end
|