mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-25 20:46:48 +00:00
- cop class: RuboCop::Cop::Rails::NegateInclude - replaced !array.include?(2) by array.exclude?(2)
88 lines
3.2 KiB
Ruby
88 lines
3.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Spree
|
|
module LocalizedNumber
|
|
# This method overwrites the attribute setters of a model
|
|
# to make them use the LocalizedNumber parsing method.
|
|
# It works with ActiveRecord "normal" attributes
|
|
# and Preference attributes.
|
|
# It also adds a validation on the input format.
|
|
# It accepts as arguments a variable number of attribute as symbols
|
|
def localize_number(*attributes)
|
|
validate :validate_localizable_number
|
|
|
|
attributes.each do |attribute|
|
|
setter = "#{attribute}="
|
|
old_setter = instance_method(setter) if non_activerecord_attribute?(attribute)
|
|
|
|
define_method(setter) do |number|
|
|
if Spree::Config.enable_localized_number? &&
|
|
Spree::LocalizedNumber.valid_localizable_number?(number)
|
|
number = Spree::LocalizedNumber.parse(number)
|
|
elsif Spree::Config.enable_localized_number?
|
|
@invalid_localized_number ||= []
|
|
@invalid_localized_number << attribute
|
|
number = nil unless is_a?(Spree::Calculator)
|
|
end
|
|
if has_attribute?(attribute)
|
|
# In this case it's a regular AR attribute with standard setters
|
|
self[attribute] = number
|
|
else
|
|
# In this case it's a Spree preference, and the interface is very different
|
|
old_setter.bind(self).call(number)
|
|
end
|
|
end
|
|
end
|
|
|
|
define_method(:validate_localizable_number) do
|
|
return unless Spree::Config.enable_localized_number?
|
|
|
|
@invalid_localized_number&.each do |error_attribute|
|
|
errors.add(error_attribute, I18n.t('spree.localized_number.invalid_format'))
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.valid_localizable_number?(number)
|
|
return true unless number.is_a?(String) || number.respond_to?(:to_d)
|
|
# Invalid if only two digits between dividers, or if any non-number characters
|
|
return false if number.to_s =~ /[.,]\d{2}[.,]/ || number.to_s =~ /[^-0-9,.]+/
|
|
|
|
true
|
|
end
|
|
|
|
def self.parse(number)
|
|
return nil if number.blank?
|
|
return number.to_d unless number.is_a?(String)
|
|
|
|
# Replace all Currency Symbols, Letters and -- from the string
|
|
number = number.gsub(/[^\d.,-]/, '')
|
|
|
|
add_trailing_zeros(number)
|
|
|
|
# Replace all (.) and (,) so the string result becomes in "cents"
|
|
number = number.gsub(/[.,]/, '')
|
|
number.to_d / 100 # Let to_decimal do the rest
|
|
end
|
|
|
|
def self.add_trailing_zeros(number)
|
|
# If string ends in a single digit (e.g. ,2), make it
|
|
# ,20 in order for the result to be in "cents"
|
|
number << "0" if number =~ /^.*[.,]\d{1}$/
|
|
|
|
# If does not end in ,00 / .00 then add trailing 00 to turn it into cents
|
|
number << "00" unless number =~ /^.*[.,]\d{2}$/
|
|
end
|
|
|
|
private
|
|
|
|
def non_activerecord_attribute?(attribute)
|
|
table_exists? && column_names.exclude?(attribute.to_s)
|
|
rescue ::ActiveRecord::NoDatabaseError
|
|
# This class is now loaded during `rake db:create` (since Rails 5.2), and not only does the
|
|
# table not exist, but the database does not even exist yet, and throws a fatal error.
|
|
# We can rescue and safely ignore it in that case.
|
|
end
|
|
end
|
|
end
|