2015-12-03 15:02:22 +01:00
|
|
|
class SiretFormatValidator < ActiveModel::EachValidator
|
2018-09-18 22:14:07 +02:00
|
|
|
def validate_each(record, attribute, value)
|
2018-09-19 10:28:07 +02:00
|
|
|
if !format_is_valid(value)
|
2021-11-25 08:49:42 +01:00
|
|
|
record.errors.add(attribute, :length)
|
2022-07-19 13:04:59 +02:00
|
|
|
elsif !luhn_passed(value)
|
2015-12-03 15:02:22 +01:00
|
|
|
record.errors.add(attribute, :checksum)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2017-06-12 15:35:21 +02:00
|
|
|
|
2018-09-19 10:29:43 +02:00
|
|
|
LA_POSTE_SIREN = '356000000'
|
|
|
|
|
2018-09-19 10:28:07 +02:00
|
|
|
def format_is_valid(value)
|
2022-07-25 18:17:30 +02:00
|
|
|
value&.match?(/^\d{14}$/)
|
2018-09-19 10:28:07 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def luhn_passed(value)
|
2018-09-19 10:29:43 +02:00
|
|
|
# Do not enforce Luhn for La Poste SIRET numbers, the only exception to this rule
|
2018-09-18 22:27:38 +02:00
|
|
|
siret_is_attached_to_la_poste(value) || (luhn_checksum(value) % 10 == 0)
|
2018-09-19 10:29:43 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def siret_is_attached_to_la_poste(value)
|
|
|
|
value[0..8] == LA_POSTE_SIREN
|
2018-09-19 10:28:07 +02:00
|
|
|
end
|
|
|
|
|
2015-12-03 15:02:22 +01:00
|
|
|
def luhn_checksum(value)
|
2018-09-19 10:28:55 +02:00
|
|
|
value.reverse.each_char.map(&:to_i).map.with_index do |digit, index|
|
2015-12-03 15:02:22 +01:00
|
|
|
t = index.even? ? digit : digit * 2
|
2018-09-19 10:28:55 +02:00
|
|
|
t < 10 ? t : t - 9
|
|
|
|
end.sum
|
2015-12-03 15:02:22 +01:00
|
|
|
end
|
|
|
|
end
|