# frozen_string_literal: true
module FFaker
module Vehicle
module VIN
extend ModuleUtils
extend self
# https://en.wikibooks.org/wiki/Vehicle_Identification_Numbers_(VIN_codes)/World_Manufacturer_Identifier_(WMI)
VALID_WMI_REGIONS = [*'A'..'C', *'J'..'Z', *'1'..'9'].freeze
VALID_YEAR_CHARS = %w[
5 6 7 8 9 A B C D E F G H J K L M N P R S T V W X Y 1 2 3 4 5 6 7 8 9
].freeze # 2005-2039
# https://en.wikibooks.org/wiki/Vehicle_Identification_Numbers_(VIN_codes)/Check_digit
TRANSLITERATION_VALUES = {
'A' => 1, 'B' => 2, 'C' => 3, 'D' => 4, 'E' => 5, 'F' => 6, 'G' => 7, 'H' => 8,
'J' => 1, 'K' => 2, 'L' => 3, 'M' => 4, 'N' => 5, 'P' => 7, 'R' => 9,
'S' => 2, 'T' => 3, 'U' => 4, 'V' => 5, 'W' => 6, 'X' => 7, 'Y' => 8, 'Z' => 9
}.freeze
POSITION_WEIGHTS = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2].freeze
VALID_ALPHA = TRANSLITERATION_VALUES.keys
VALID_ALPHANUMERIC = [*VALID_ALPHA, *'1'..'9'].freeze
# Generate a VIN that is compliant with specifications of US Title 49 Section 565.15
# https://www.govinfo.gov/content/pkg/CFR-2019-title49-vol6/xml/CFR-2019-title49-vol6-part565.xml#seqnum565.15
#
# Position Meaning
# 1-3 Manufacturer ID aka WMI (alpha and digits)
# 4-8 Vehicle Description ("For passenger cars ..[position 7].. shall be alphabetic")
# 9 Check Digit (0-9 or "X")
# 10 Year (see VIN_VALID_YEARS)
# 11 Plant of manufacture (alpha and digits)
# 12-17 Serial number (digits only)
#
# I, O and Q are NOT allowed. VIN_VALID_ALPHA has valid alpha characters.
def vin
generated_vin = [
# Manufacturer ID / WMI
fetch_sample(VALID_WMI_REGIONS),
fetch_sample(VALID_ALPHANUMERIC, count: 2),
# Vehicle Description
fetch_sample(VALID_ALPHANUMERIC, count: 3),
fetch_sample(VALID_ALPHA),
fetch_sample(VALID_ALPHANUMERIC),
'0', # check digit placeholder
fetch_sample(VALID_YEAR_CHARS), # Year of Manufacture
fetch_sample(VALID_ALPHANUMERIC), # Plant ID
FFaker.numerify('######') # Serial Number
].join
# Calculate the Check Digit
weighted_sum = generated_vin.chars.each_with_index.sum do |char, idx|
(TRANSLITERATION_VALUES[char.to_sym] || char).to_i * POSITION_WEIGHTS[idx]
end
check_digit = weighted_sum % 11
check_digit = 'X' if check_digit == 10
generated_vin[8] = check_digit.to_s
generated_vin
end
end
extend ModuleUtils
extend self
DRIVETRAINS = %w[4WD 4X4 AWD FWD RWD].freeze
YEARS = Array('1900'..(::Time.now.year + 1).to_s).freeze
TRANSMISSIONS_ABBR = %w[AT MT AM CVT].freeze
CYLINDERS = %w[2 5 6 8].freeze
def base_color
FFaker::Color.name
end
def drivetrain
fetch_sample(DRIVETRAINS)
end
def make
fetch_sample(MAKES_LIST)
end
def manufacturer_color(count = 2)
# Take two prefixes because it's more fun than one
(fetch_sample(COLOR_PREFIXES, count: count) + [base_color]).join(' ')
end
alias mfg_color manufacturer_color
def model
fetch_sample(MODELS_LIST)
end
def trim
fetch_sample(TRIMS_LIST)
end
def vin
VIN.vin
end
def year
fetch_sample(YEARS)
end
def transmission
fetch_sample(TRANSMISSIONS_LIST)
end
def transmission_abbr
fetch_sample(TRANSMISSIONS_ABBR)
end
def engine_cylinders
fetch_sample(CYLINDERS)
end
def engine_displacement
fetch_sample(DISPLACEMENTS_LIST)
end
def fuel_type
fetch_sample(FUEL_TYPES_LIST)
end
def interior_upholstery
fetch_sample(UPHOLSTERY_LIST)
end
end
end