lib/valvat/checksum/gb.rb
# frozen_string_literal: true
class Valvat
module Checksum
class GB < Base
OLD_FORMAT_FORBIDDEN_RANGES = [(100_000..999_999), (9_490_001..9_700_000), (9_990_001..9_999_999)].freeze
NEW_FORMAT_FORBIDDEN_RANGES = [(1..100_000), (100_001..1_000_000)].freeze
GOV_NUMBER = /\A(GD[0-4]{1}\d{2})\Z/.freeze
HEALTH_NUMBER = /\A(HA[5-9]{1}\d{2})\Z/.freeze
def validate # rubocop:disable Metrics/CyclomaticComplexity
# government departments and health authorities, so no checksum
return true if gov_or_health?
return false if all_zero?
return false if old_format_remainder.zero? && fobidden_in_old_format?
return false if new_format_remainder.zero? && fobidden_in_new_format?
old_format_remainder.zero? || new_format_remainder.zero?
end
private
def checksum
@checksum ||= str_wo_country[7..8].to_i
end
def vat_base
@vat_base ||= str_wo_country[0..6]
end
def gov_or_health?
str_wo_country =~ GOV_NUMBER || str_wo_country =~ HEALTH_NUMBER
end
def all_zero?
str_wo_country =~ /\A0{9}\Z/ || str_wo_country =~ /\A0{12}\Z/
end
def vat_base_sum
@vat_base_sum ||= vat_base.split('')
.map(&:to_i)
.zip([8, 7, 6, 5, 4, 3, 2])
.map { |vat_number_digit, multiplier| vat_number_digit * multiplier }
.inject(:+)
end
def old_format_remainder
@old_format_remainder ||= (vat_base_sum + checksum).modulo(97)
end
def new_format_remainder
@new_format_remainder ||= (vat_base_sum + 55 + checksum).modulo(97)
end
def fobidden_in_new_format?
vat_base_int = vat_base.to_i
NEW_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include?(vat_base_int) }
end
def fobidden_in_old_format?
vat_base_int = vat_base.to_i
OLD_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include?(vat_base_int) }
end
end
end
end