From 7116826b854188604e21e2a613ac6672b6fd81f3 Mon Sep 17 00:00:00 2001 From: Marius Peter Date: Mon, 8 Sep 2025 21:21:56 +0200 Subject: Create Target and nutrient target table on dashboard. --- app/models/nutrient_measurement.rb | 14 +++++++++++++ app/models/nutrient_profile.rb | 11 ++++++++++ app/models/target.rb | 42 ++++++++++++++++++++++++++++++++++++++ app/models/target_allocation.rb | 7 +++++++ 4 files changed, 74 insertions(+) create mode 100644 app/models/target.rb create mode 100644 app/models/target_allocation.rb (limited to 'app/models') diff --git a/app/models/nutrient_measurement.rb b/app/models/nutrient_measurement.rb index f1d6d5b..1139af7 100644 --- a/app/models/nutrient_measurement.rb +++ b/app/models/nutrient_measurement.rb @@ -1,4 +1,18 @@ class NutrientMeasurement < ApplicationRecord + NUTRIENT_FIELDS = %i[ + nno3 p k ca mg s na cl si fe zn b mn cu mo nnh4 + ].freeze + validates :measured_on, presence: true validates :measured_on, uniqueness: true + + def self.data_series_for(*nutrients) + nutrients.map do |formula| + { name: formula, data: self.order(:measured_on).pluck(:measured_on, formula) } + end + end + + def self.nutrient_fields + NUTRIENT_FIELDS + end end diff --git a/app/models/nutrient_profile.rb b/app/models/nutrient_profile.rb index 22f2704..0610855 100644 --- a/app/models/nutrient_profile.rb +++ b/app/models/nutrient_profile.rb @@ -1,2 +1,13 @@ class NutrientProfile < ApplicationRecord + # Align these keys with your schema columns (per your schema.txt) + NUTRIENT_KEYS = %i[ + nno3 p k ca mg s na cl si fe zn b mn cu mo nnh4 + ].freeze + + # Returns a Hash of nutrient => numeric requirement (nil kept; caller can skip nils) + def requirements_hash + attributes + .slice(*NUTRIENT_KEYS.map(&:to_s)) # only nutrient columns + .transform_keys(&:to_s) + end end diff --git a/app/models/target.rb b/app/models/target.rb new file mode 100644 index 0000000..3063b42 --- /dev/null +++ b/app/models/target.rb @@ -0,0 +1,42 @@ +# app/models/target.rb +class Target < ApplicationRecord + has_many :target_allocations, dependent: :destroy + has_many :nutrient_profiles, through: :target_allocations + + accepts_nested_attributes_for :target_allocations, allow_destroy: true + validate :percentages_sum_to_100 + + def weighted_requirements + totals = Hash.new(0.0) + denom = 100.0 + + target_allocations.includes(:nutrient_profile).each do |alloc| + profile = alloc.nutrient_profile + next unless profile + + weight = (alloc.percentage || 0).to_f / denom + next if weight <= 0 + + # Prefer the helper, but gracefully fall back to slicing attributes. + reqs = if profile.respond_to?(:requirements_hash) + profile.requirements_hash + else + profile.attributes.slice(*NutrientProfile::NUTRIENT_KEYS.map(&:to_s)) + end + + reqs.each do |nutrient_key, value| + next if value.nil? + totals[nutrient_key.to_s] += value.to_f * weight + end + end + + totals + end + + private + + def percentages_sum_to_100 + sum = target_allocations.reject(&:marked_for_destruction?).sum { |a| a.percentage.to_f } + errors.add(:base, "La somme des pourcentages doit être égale à 100%") unless (sum - 100.0).abs <= 0.01 + end +end diff --git a/app/models/target_allocation.rb b/app/models/target_allocation.rb new file mode 100644 index 0000000..6aa1dcb --- /dev/null +++ b/app/models/target_allocation.rb @@ -0,0 +1,7 @@ +class TargetAllocation < ApplicationRecord + belongs_to :target + belongs_to :nutrient_profile + + validates :percentage, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 } + validates :nutrient_profile_id, uniqueness: { scope: :target_id } +end -- cgit v1.2.3