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.
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