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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/active_shipping.rb +2 -1
  3. data/lib/active_shipping/shipping/base.rb +2 -2
  4. data/lib/active_shipping/shipping/carrier.rb +16 -13
  5. data/lib/active_shipping/shipping/carriers/benchmark_carrier.rb +3 -4
  6. data/lib/active_shipping/shipping/carriers/bogus_carrier.rb +1 -3
  7. data/lib/active_shipping/shipping/carriers/canada_post.rb +33 -44
  8. data/lib/active_shipping/shipping/carriers/canada_post_pws.rb +72 -81
  9. data/lib/active_shipping/shipping/carriers/fedex.rb +118 -109
  10. data/lib/active_shipping/shipping/carriers/kunaki.rb +33 -32
  11. data/lib/active_shipping/shipping/carriers/new_zealand_post.rb +9 -16
  12. data/lib/active_shipping/shipping/carriers/shipwire.rb +36 -35
  13. data/lib/active_shipping/shipping/carriers/stamps.rb +39 -51
  14. data/lib/active_shipping/shipping/carriers/ups.rb +280 -116
  15. data/lib/active_shipping/shipping/carriers/ups.rb.orig +456 -0
  16. data/lib/active_shipping/shipping/carriers/usps.rb +145 -100
  17. data/lib/active_shipping/shipping/carriers/usps.rb.orig +616 -0
  18. data/lib/active_shipping/shipping/errors.rb +1 -1
  19. data/lib/active_shipping/shipping/label_response.rb +25 -0
  20. data/lib/active_shipping/shipping/location.rb +18 -16
  21. data/lib/active_shipping/shipping/package.rb +51 -54
  22. data/lib/active_shipping/shipping/rate_estimate.rb +10 -12
  23. data/lib/active_shipping/shipping/rate_response.rb +3 -7
  24. data/lib/active_shipping/shipping/response.rb +6 -9
  25. data/lib/active_shipping/shipping/shipment_event.rb +2 -4
  26. data/lib/active_shipping/shipping/shipment_packer.rb +32 -17
  27. data/lib/active_shipping/shipping/shipping_response.rb +2 -4
  28. data/lib/active_shipping/shipping/tracking_response.rb +3 -5
  29. data/lib/active_shipping/version.rb +1 -1
  30. data/lib/vendor/quantified/lib/quantified/attribute.rb +79 -80
  31. data/lib/vendor/quantified/lib/quantified/length.rb +5 -5
  32. data/lib/vendor/quantified/lib/quantified/mass.rb +4 -4
  33. data/lib/vendor/quantified/test/length_test.rb +19 -15
  34. data/lib/vendor/quantified/test/mass_test.rb +14 -14
  35. data/lib/vendor/quantified/test/test_helper.rb +1 -2
  36. data/lib/vendor/test_helper.rb +0 -1
  37. data/lib/vendor/xml_node/benchmark/bench_generation.rb +2 -4
  38. data/lib/vendor/xml_node/lib/xml_node.rb +54 -55
  39. data/lib/vendor/xml_node/test/test_generating.rb +23 -28
  40. data/lib/vendor/xml_node/test/test_parsing.rb +5 -8
  41. metadata +6 -25
  42. checksums.yaml.gz.sig +0 -1
  43. data.tar.gz.sig +0 -0
  44. 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
- :envelope => 'Flat Rate Envelope',
50
- :box => 'Flat Rate Box'
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 = ["AS", "FM", "GU", "MH", "MP", "PW", "PR", "VI"]
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
- def find_tracking_info(tracking_number, options={})
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
- response = if domestic_codes.include?(destination.country_code(:alpha2))
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($1.upcase, time, zoneless_time, location)
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
- # never use test mode; rate requests just won't work on test servers
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
- # never use test mode; rate requests just won't work on test servers
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 = "%3CCarrierPickupAvailabilityRequest%20USERID=%22#{URI.encode(@options[:login])}%22%3E%20%0A%3CFirmName%3EABC%20Corp.%3C/FirmName%3E%20%0A%3CSuiteOrApt%3ESuite%20777%3C/SuiteOrApt%3E%20%0A%3CAddress2%3E1390%20Market%20Street%3C/Address2%3E%20%0A%3CUrbanization%3E%3C/Urbanization%3E%20%0A%3CCity%3EHouston%3C/City%3E%20%0A%3CState%3ETX%3C/State%3E%20%0A%3CZIP5%3E77058%3C/ZIP5%3E%20%0A%3CZIP4%3E1234%3C/ZIP4%3E%20%0A%3C/CarrierPickupAvailabilityRequest%3E%0A"
246
- # expected_hash = {"CarrierPickupAvailabilityResponse"=>{"City"=>"HOUSTON", "Address2"=>"1390 Market Street", "FirmName"=>"ABC Corp.", "State"=>"TX", "Date"=>"3/1/2004", "DayOfWeek"=>"Monday", "Urbanization"=>nil, "ZIP4"=>"1234", "ZIP5"=>"77058", "CarrierRoute"=>"C", "SuiteOrApt"=>"Suite 777"}}
247
- xml = REXML::Document.new(commit(:test, request, true))
248
- xml.get_text('/CarrierPickupAvailabilityResponse/City').to_s == 'HOUSTON' &&
249
- xml.get_text('/CarrierPickupAvailabilityResponse/Address2').to_s == '1390 Market Street'
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
- if @options[:commercial_base] == true
266
- raise ArgumentError.new("Commercial Base rates are only provided with the :online method.") if !options[:service].blank? && options[:service] != :online
267
- default_service = :online
268
- else
269
- default_service = :all
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[options[:service] || default_service])
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
- package << XmlNode.new('CommercialFlag', 'Y') if @options[:commercial_base]
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,@@name,"USPS #{service_name}",
372
- :package_rates => rate_hash[service_name][:package_rates],
373
- :service_code => rate_hash[service_name][:service_code],
374
- :currency => 'USD')
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
- if @options[:commercial_base]
389
- domestic_elements = ['Postage', 'CLASSID', 'MailService', 'CommercialRate']
390
- international_elements = ['Service', 'ID', 'SvcDescription', 'CommercialPostage']
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
- domestic_elements = ['Postage', 'CLASSID', 'MailService', 'Rate']
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
- # strips the double-escaped HTML for trademark symbols from service names
404
- service_name.gsub!(/&amp;lt;\S*&amp;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(service_response_node.get_text(rate_node).to_s.to_f)}
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
- :weight => max_weight, #domestic apparently has no weight restriction
436
- :length => 11.0,
437
- :width => 8.5,
438
- :height => 5.5) or
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
- :weight => max_weight,
441
- :length => 13.625,
442
- :width => 11.875,
443
- :height => 3.375))
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
- :weight => max_weight,
447
- :length => 12.5,
448
- :width => 9.5,
449
- :height => 0.75)
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 {|t| t.empty?}
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/,/width/,/height/,/depth/].sum {|regex| (token =~ regex) ? 1 : 0}
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
- return package_valid_for_max_dimensions(package, max_dimensions)
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
- valid = ((not ([:length,:width,:height].map {|dim| dimensions[dim].nil? || dimensions[dim].to_f >= package.inches(dim).to_f}.include?(false))) and
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
- tracking_number, origin, destination = nil
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
- :carrier => @@name,
529
- :xml => response,
530
- :request => last_request,
531
- :shipment_events => shipment_events,
532
- :destination => destination,
533
- :tracking_number => tracking_number,
534
- :status => status,
535
- :actual_delivery_date => actual_delivery_date
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