class ActiveModel::Validations::TrackingNumberValidator

Constants

MOD10_WEIGHTS
MOD11_WEIGHTS
UPS_REGEXES

UPS: ups tracking codes are validated solely on their format see www.ups.com/content/us/en/tracking/help/tracking/tnh.html

USS128_REGEX
USS39_REGEX

Public Instance Methods

usps_mod10(chars) click to toggle source
# File lib/active_validators/active_model/validations/tracking_number_validator.rb, line 46
def usps_mod10(chars)
  (10 - weighted_sum(chars.reverse, MOD10_WEIGHTS) % 10) % 10
end
usps_mod11(chars) click to toggle source
# File lib/active_validators/active_model/validations/tracking_number_validator.rb, line 51
def usps_mod11(chars)
  mod = weighted_sum(chars, MOD11_WEIGHTS) % 11
  case mod
  when 0 then 5
  when 1 then 0
  else 11 - mod
  end
end
uss228?(value) click to toggle source
# File lib/active_validators/active_model/validations/tracking_number_validator.rb, line 32
def uss228?(value)
  m = value.match(USS128_REGEX)
  m.present? && (m[2].to_i == usps_mod10(m[1]))
end
uss39?(value) click to toggle source
# File lib/active_validators/active_model/validations/tracking_number_validator.rb, line 38
def uss39?(value)
  m = value.match(USS39_REGEX)
  # it appears to be valid for a USS39 barcode's checkdigit to be calculated with either the usps mod 10
  # algorithm or the usps mod 11.
  m.present? && (m[2].to_i == usps_mod10(m[1]) || m[2].to_i == usps_mod11(m[1]))
end
valid_ups?(value) click to toggle source
# File lib/active_validators/active_model/validations/tracking_number_validator.rb, line 16
def valid_ups?(value)
  !!UPS_REGEXES.detect { |fmt| value.match(fmt) }
end
valid_usps?(value) click to toggle source

USPS: usps tracking codes are validated based on format (one of USS228 or USS39) and a check digit (using either of the USPS's MOD10 or MOD11 algorithms) see USPS Publications:

-  #91 (05/2008) pp. 38
-  #97 (05/2002) pp. 62-63
- #109 (09/2007) pp. 19-21
# File lib/active_validators/active_model/validations/tracking_number_validator.rb, line 27
def valid_usps?(value)
  uss228?(value) || uss39?(value)
end
validate_each(record, attribute, value) click to toggle source
# File lib/active_validators/active_model/validations/tracking_number_validator.rb, line 4
def validate_each(record, attribute, value)
  carrier = options[:carrier] || (options[:carrier_field] && record.send(options[:carrier_field]))
  raise "Carrier option required" unless carrier
  method = "valid_#{carrier.to_s}?"
  raise "Tracking number validation not supported for carrier #{carrier}" unless self.respond_to?(method)
  record.errors.add(attribute) if value.blank? || !self.send(method, value)
end
weighted_sum(value, weights) click to toggle source

takes a string containing digits and calculates a checksum using the provided weight array cycles the weight array if it's not long enough

# File lib/active_validators/active_model/validations/tracking_number_validator.rb, line 62
def weighted_sum(value, weights)
  digits = value.split('').map { |d| d.to_i }
  weights = weights.cycle.take(digits.count) if weights.count < digits.count
  digits.zip(weights).inject(0) { |s,p| s + p[0] * p[1] }
end