class TrackingNumberValidator

Public Instance Methods

validate_each(record, attribute, value) click to toggle source
# File lib/active_validation/validators/tracking_number_validator.rb, line 26
def validate_each(record, attribute, value)
  return if valid?(value.to_s, options)

  record.errors[attribute] <<
    (options[:message] || I18n.t('active_validation.errors.messages.tracking_number'))
end

Private Instance Methods

valid?(value, options) click to toggle source
# File lib/active_validation/validators/tracking_number_validator.rb, line 242
def valid?(value, options)
  valid_length?(value) &&
    valid_checksum?(value, options)
end
valid_checksum?(value, options) click to toggle source

Base rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

# File lib/active_validation/validators/tracking_number_validator.rb, line 212
def valid_checksum?(value, options)
  carrier = options[:carrier]
  service = options[:service]
  result = false

  if carrier.nil? && service.nil?
    CARRIERS_AND_SERVICES.each do |car, ser|
      ser.each_key do |car_ser|
        result = send("valid_#{car}_#{car_ser}_checksum?", value)
        break if result
      end
      break if result
    end
  elsif service.nil?
    CARRIERS_AND_SERVICES[carrier].each_key do |car_ser|
      result = send("valid_#{carrier}_#{car_ser}_checksum?", value)
      break if result
    end
  else
    result = send("valid_#{carrier}_#{service}_checksum?", value)
  end

  result
end
valid_fedex_express_checksum?(value) click to toggle source

FedEx

# File lib/active_validation/validators/tracking_number_validator.rb, line 48
def valid_fedex_express_checksum?(value)
  return(false) unless value.size == 12

  pattern = CARRIERS_AND_SERVICES[:fedex][:express]
  formula = value.scan(pattern).flatten.compact
  return(false) if formula.empty?

  sequence, check_digit = formula

  total = 0
  sequence.chars.zip([3, 1, 7, 3, 1, 7, 3, 1, 7, 3, 1]).each do |chr, chrx|
    total += (chr.to_i * chrx)
  end

  (total % 11 % 10) == check_digit.to_i
end
valid_fedex_smart_post_checksum?(value) click to toggle source
# File lib/active_validation/validators/tracking_number_validator.rb, line 89
def valid_fedex_smart_post_checksum?(value)
  value = "92#{value}" unless /^92/.match?(value)
  return(false) unless value.size == 22

  pattern = CARRIERS_AND_SERVICES[:fedex][:smart_post]
  formula = value.scan(pattern).flatten.compact
  return(false) if formula.empty?

  sequence, check_digit = formula

  total = 0
  sequence.chars.reverse.each_with_index do |chr, idx|
    result = chr.to_i
    result *= 3 if idx.even?
    total += result
  end

  check = total % 10
  check = (10 - check) unless check.zero?
  check == check_digit.to_i
end
valid_length?(value) click to toggle source

rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

# File lib/active_validation/validators/tracking_number_validator.rb, line 238
def valid_length?(value)
  value.present?
end
valid_usps_usps13_checksum?(value) click to toggle source

USPS

# File lib/active_validation/validators/tracking_number_validator.rb, line 139
def valid_usps_usps13_checksum?(value)
  return(false) unless value.size == 13

  pattern = CARRIERS_AND_SERVICES[:usps][:usps13]
  sequence = value.scan(pattern).flatten.compact
  return(false) if sequence.empty?

  characters = sequence[1].chars
  check_digit = characters.pop.to_i

  total = 0
  characters.zip([8, 6, 4, 2, 3, 5, 9, 7]).each do |par|
    total += (par[0].to_i * par[1].to_i)
  end

  remainder = total % 11
  check = case remainder
          when 1 then 0
          when 0 then 5
          else
            11 - remainder
          end

  check == check_digit
end
valid_usps_usps20_checksum?(value) click to toggle source
# File lib/active_validation/validators/tracking_number_validator.rb, line 165
def valid_usps_usps20_checksum?(value)
  return(false) unless value.size == 20

  pattern = CARRIERS_AND_SERVICES[:usps][:usps20]
  sequence = value.scan(pattern).flatten.compact
  return(false) if sequence.empty?

  characters = sequence.first(3).join.chars
  check_digit = sequence.last.to_i

  total = 0
  characters.reverse.each_with_index do |chr, idx|
    result = chr.to_i
    result *= 3 if idx.even?
    total += result
  end

  check = total % 10
  check = (10 - check) unless check.zero?
  check == check_digit
end
valid_usps_usps91_checksum?(value) click to toggle source
# File lib/active_validation/validators/tracking_number_validator.rb, line 187
def valid_usps_usps91_checksum?(value)
  value = "91#{value}" unless /^(420\d{5})?9[1-5]/.match?(value)
  return(false) unless value.size == 22

  pattern = CARRIERS_AND_SERVICES[:usps][:usps91]
  sequence = value.scan(pattern).flatten.compact
  return(false) if sequence.empty?

  characters = sequence.first.chars
  check_digit = sequence.last.to_i

  total = 0
  characters.reverse.each_with_index do |chr, idx|
    result = chr.to_i
    result *= 3 if idx.even?
    total += result
  end

  check = total % 10
  check = (10 - check) unless check.zero?
  check == check_digit
end