# frozen_string_literals: true module Jobshop class Inspection::DeviationCriterion < ApplicationRecord self.primary_keys = %i[ organization_id report_id criterion_id criterion_type ] after_initialize { self.criterion_id ||= SecureRandom.uuid if new_record? } before_save(on: :create) { criterion.save unless criterion.persisted? } belongs_to :organization belongs_to :report, class_name: "Jobshop::Inspection::Report", foreign_key: %i[ organization_id report_id ] has_one :criterion, as: :criterion, autosave: true, dependent: :destroy, foreign_key: %i[ organization_id report_id criterion_id criterion_type ], inverse_of: :criterion def criterion super || build_criterion end delegate :name, :name=, :position, :position=, to: :criterion validates :nominal, presence: true validates :lower, presence: true validates :upper, presence: true validate :lower_less_than_upper def mean ((nominal + lower) + (nominal + upper)) / 2 end def nominal self[:nominal] && Unitwise(self[:nominal].truncate(4), self[:unit]) end def lower self[:lower] && Unitwise(self[:lower].truncate(4), self[:unit]) end def lower=(value) self[:lower] = if value.respond_to?(:unit) value.convert_to(self[:unit]).value else value end end def upper self[:upper] && Unitwise(self[:upper].truncate(4), self[:unit]) end def upper=(value) self[:upper] = if value.respond_to?(:unit) value.convert_to(self[:unit]).value else value end end def lower_less_than_upper return unless lower && upper if lower > upper errors[:base] << "minimum must be less than maximum" end end =begin def specification @specfication ||= if symmetric? "#{nominal}±#{abs(upper)}" else "#{nominal}\n#{lower}/#{upper}" end end =end def symmetric? @symmetrical ||= lower == upper * -1 end def pass?(value) !undersize?(value) && !oversize?(value) end # Generate a random value that has a 90% chance of being in spec. # TODO: This needs to go in the tests somewhere, not really in the model. def random rand_lower = nominal.to_f + lower.to_f * 1.1 rand_upper = nominal.to_f + upper.to_f * 1.1 value = rand(rand_lower..rand_upper) Unitwise(value.truncate(4), self[:unit]) end def oversize?(value) value = if value.respond_to?(:unit) value.convert_to(self[:unit]) else Unitwise(value, self[:unit]) end value > upper || false end def undersize?(value) value = if value.respond_to?(:unit) value.convert_to(self[:unit]) else Unitwise(value, self[:unit]) end value < nominal - lower || false end end end