In some countries, postal codes are defined with a dash in the middle, so we're using a colon to define ranges instead. We could also use two dots, like in Ruby ranges, but IMHO this would cause typos since people would enter codes separated with three dots or just one dot.
116 lines
3.1 KiB
Ruby
116 lines
3.1 KiB
Ruby
class Verification::Residence
|
|
include ActiveModel::Model
|
|
include ActiveModel::Dates
|
|
include ActiveModel::Validations::Callbacks
|
|
|
|
attr_accessor :user, :document_number, :document_type, :date_of_birth, :postal_code, :terms_of_service
|
|
|
|
validates :document_number, presence: true
|
|
validates :document_type, presence: true
|
|
validates :date_of_birth, presence: true
|
|
validates :postal_code, presence: true
|
|
validates :terms_of_service, acceptance: { allow_nil: false }
|
|
|
|
validate :allowed_age
|
|
validate :document_number_uniqueness
|
|
|
|
validate :local_postal_code
|
|
validate :local_residence
|
|
|
|
def initialize(attrs = {})
|
|
self.date_of_birth = parse_date("date_of_birth", attrs)
|
|
attrs = remove_date("date_of_birth", attrs)
|
|
super
|
|
clean_document_number
|
|
end
|
|
|
|
def save
|
|
return false unless valid?
|
|
|
|
user.take_votes_if_erased_document(document_number, document_type)
|
|
|
|
user.update(document_number: document_number,
|
|
document_type: document_type,
|
|
geozone: geozone,
|
|
date_of_birth: date_of_birth.in_time_zone.to_datetime,
|
|
gender: gender,
|
|
residence_verified_at: Time.current)
|
|
end
|
|
|
|
def save!
|
|
validate! && save
|
|
end
|
|
|
|
def allowed_age
|
|
return if errors[:date_of_birth].any? || Age.in_years(date_of_birth) >= User.minimum_required_age
|
|
|
|
errors.add(:date_of_birth, I18n.t("verification.residence.new.error_not_allowed_age"))
|
|
end
|
|
|
|
def document_number_uniqueness
|
|
errors.add(:document_number, I18n.t("errors.messages.taken")) if User.active.where(document_number: document_number).any?
|
|
end
|
|
|
|
def store_failed_attempt
|
|
FailedCensusCall.create(
|
|
user: user,
|
|
document_number: document_number,
|
|
document_type: document_type,
|
|
date_of_birth: date_of_birth,
|
|
postal_code: postal_code
|
|
)
|
|
end
|
|
|
|
def geozone
|
|
Geozone.find_by(census_code: district_code)
|
|
end
|
|
|
|
def district_code
|
|
census_data.district_code
|
|
end
|
|
|
|
def gender
|
|
census_data.gender
|
|
end
|
|
|
|
def local_postal_code
|
|
errors.add(:postal_code, I18n.t("verification.residence.new.error_not_allowed_postal_code")) unless valid_postal_code?
|
|
end
|
|
|
|
def local_residence
|
|
return if errors.any?
|
|
|
|
unless residency_valid?
|
|
errors.add(:local_residence, false)
|
|
store_failed_attempt
|
|
Lock.increase_tries(user)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def census_data
|
|
@census_data ||= CensusCaller.new.call(document_type, document_number, date_of_birth, postal_code)
|
|
end
|
|
|
|
def residency_valid?
|
|
census_data.valid? &&
|
|
census_data.postal_code == postal_code &&
|
|
census_data.date_of_birth == date_of_birth
|
|
end
|
|
|
|
def clean_document_number
|
|
self.document_number = document_number.gsub(/[^a-z0-9]+/i, "").upcase if document_number.present?
|
|
end
|
|
|
|
def valid_postal_code?
|
|
Setting["postal_codes"].split(",").any? do |code_or_range|
|
|
if code_or_range.include?(":")
|
|
Range.new(*code_or_range.split(":")).include?(postal_code)
|
|
else
|
|
postal_code == code_or_range
|
|
end
|
|
end
|
|
end
|
|
end
|