Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions app/models/scenario_updater/services/validate_input_values.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,46 @@ def validate_numeric_input(key, input, input_data, value, errors)
# and will be validated after balancing
return if input.share_group.present?

# Validate step alignment first - skip min/max check if step invalid
step_valid = validate_step(key, value, input_data[:min], input_data[:step], errors)
return unless step_valid

validate_min_max(key, value, input_data[:min], input_data[:max], errors)
end

def validate_step(key, value, min, step, errors)
return true unless step.present? && step.positive?
return true if value_on_valid_step?(value, min, step)

nearest_lower = calculate_nearest_step(value, min, step)
nearest_higher = nearest_lower + step
precision = decimal_places(step)

errors << "Input #{key} value #{value} must align with step size #{step}. " \
"Nearest valid values: #{nearest_lower.round(precision)} or #{nearest_higher.round(precision)}"

false
end

def value_on_valid_step?(value, min, step)
remainder = ((value - min) % step).abs
remainder < 0.0001 || (step - remainder).abs < 0.0001
end

def calculate_nearest_step(value, min, step)
steps_from_min = ((value - min) / step).round
min + (steps_from_min * step)
end

def decimal_places(num)
return 0 if num.to_i == num

num_str = num.to_s
return 0 unless num_str.include?('.')

num_str.split('.')[1].gsub(/0+$/, '').length
end

def validate_min_max(key, value, min, max, errors)
if value < min
errors << "Input #{key} cannot be less than #{min}"
Expand Down