summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
authorMarius Peter <dev@marius-peter.com>2025-09-08 21:21:56 +0200
committerMarius Peter <dev@marius-peter.com>2025-09-08 21:21:56 +0200
commit7116826b854188604e21e2a613ac6672b6fd81f3 (patch)
tree33150bf2e04e69b8e1fa7d37901d2643b1955534 /app/models
parent8ba568ae0ebe715b5da453681eb141886f1977a8 (diff)
Create Target and nutrient target table on dashboard.
Diffstat (limited to 'app/models')
-rw-r--r--app/models/nutrient_measurement.rb14
-rw-r--r--app/models/nutrient_profile.rb11
-rw-r--r--app/models/target.rb42
-rw-r--r--app/models/target_allocation.rb7
4 files changed, 74 insertions, 0 deletions
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
Copyright 2019--2025 Marius PETER