1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
# 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'..'N', 'P', *'R'..'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] || 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
|