active_shipping 0.12.4 → 0.12.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|