summaryrefslogtreecommitdiff
path: root/db
diff options
context:
space:
mode:
Diffstat (limited to 'db')
-rw-r--r--db/data/dolibarr_measurements.csv44
-rw-r--r--db/data/nutrient_requirements.csv9
-rw-r--r--db/migrate/20250820175727_create_nutrients.rb10
-rw-r--r--db/migrate/20250820175742_create_nutrient_measurements.rb27
-rw-r--r--db/migrate/20250823140019_create_crops.rb26
-rw-r--r--db/migrate/20250823142743_create_beds.rb11
-rw-r--r--db/migrate/20250823142858_create_rafts.rb13
-rw-r--r--db/migrate/20250824121914_create_fertilizer_components.rb26
-rw-r--r--db/migrate/20250824163242_create_fertilizer_products.rb11
-rw-r--r--db/migrate/20250824163257_create_fertilizer_compositions.rb11
-rw-r--r--db/schema.rb130
-rw-r--r--db/seeds.rb13
-rw-r--r--db/seeds/1_nutrients.rb24
-rw-r--r--db/seeds/2_nutrient_measurements.rb27
-rw-r--r--db/seeds/3_crops.rb125
-rw-r--r--db/seeds/4_beds_and_rafts.rb24
-rw-r--r--db/seeds/5_fertilizer_components.rb.bkp38
-rw-r--r--db/seeds/6_fertilizer_products.rb143
18 files changed, 712 insertions, 0 deletions
diff --git a/db/data/dolibarr_measurements.csv b/db/data/dolibarr_measurements.csv
new file mode 100644
index 0000000..38be569
--- /dev/null
+++ b/db/data/dolibarr_measurements.csv
@@ -0,0 +1,44 @@
+date,nno3,p,k,ca,mg,s,na,cl,si,fe,zn,b,mn,cu,mo,nnh4
+08/05/2021,1.87,0.0031936,0.91,100.79,8.37,1.08666558,6.73,12.28,5.42,0.01,0.01,0.01,0.01,0.01,0.01,0.02
+02/07/2021,66.3,0.0095808,110.91,93.09,17.95,32.84663382,10.27,18.53,5.02,4.37,0.03,0.18,0.15,0,0,0.63
+12/07/2021,61.66,2.011968,122.53,73.5,17.44,47.64328569,0.45,0.82,0.36,1.76,0.05,0.13,0.32,0,0,0
+12/08/2021,67.27,0.351296,94.45,89.48,16.25,9.11665755,10.76,16.51,4.95,3.2,0.03,0.14,0.07,0,0,0.06
+06/09/2021,77.8,7.1153408,96.29,86.31,14.21,23.90664276,9.32,14.92,4.61,2.45,0.08,0.12,0.05,0.03,0,0.02
+21/09/2021,87.88,11.33728,117.24,90.64,17.25,29.90663676,9.92,15.96,4.68,2.4,0.08,0.27,0.12,0.04,0.01,0.02
+19/10/2021,77.84,13.4195072,121.91,94.71,18.3,33.19663347,12.36,15.28,4.47,2.72,0.11,0.74,0.04,0.04,0.02,0.03
+01/12/2021,57.09,6.6842048,81.46,61.45,10.52,17.72331561,17.36,23.05,2.11,1.27,0.17,0.32,0.01,0.03,0.02,0.07
+04/02/2022,43.56,6.5979776,63.1,63.72,9.92,17.3999826,17.08,21.15,1.44,1.6,0.22,0.34,0.01,0.04,0.01,0.03
+12/04/2022,38.36,6.5021696,83.48,49.75,6.42,14.14331919,29.8,38.85,0.23,0.3,0.2,0,0.02,0.01,0.4,0.07
+16/05/2022,24.63,0.542912,30.22,39.79,6.75,0.0666666,25.98,25.89,0.14,1.13,0.3,0.23,0.01,0.02,0.005,0.12
+15/06/2022,2.45,0.0606784,0.69,24.58,4.14,1.24999875,19.59,11.33,0.32,0.79,0.25,0.13,0.01,0.02,0.01,0.1
+04/07/2022,24.3,3.081824,42.34,39.79,8.09,0.41333292,19.79,11.32,1.24,0.7,0.18,0.07,0.02,0.01,0.005,0.68
+01/08/2022,4.88,0.2299392,27.77,22.48,6.71,18.68331465,23,5,0.64,0.97,0.17,0.04,0.005,0.005,0.005,0.07
+07/09/2022,29.28,2.07584,79.65,36.05,13.82,31.17663549,33.41,12.32,0.83,0.84,0.13,0.07,0.01,0.005,0.005,0.8
+24/10/2022,41.61,1.2646656,68.38,47.44,11.54,21.55664511,28.22,18.73,0.81,0.41,0.1,0.05,0.005,0.005,0.005,0.09
+21/11/2022,40.34,3.1105664,53.6,51.09,9.69,17.97331536,25.5,18.85,0.97,0.58,0.11,0.07,0.005,0.005,0.005,0.04
+09/01/2023,48.71,6.6171392,63.08,71.45,11.58,6.55666011,23.81,21.32,1.46,1.04,0.13,0.13,0.01,0.01,0.01,0.03
+21/02/2023,56.03,7.5273152,53.3,81.75,12.11,19.31998068,23.16,27.27,1.86,0.95,0.18,0.19,0.01,0.005,0.02,0.13
+20/04/2023,50.67,7.0546624,76.45,76.63,10.57,15.54331779,22.25,26.97,0.95,0.96,0.19,0.12,0.005,0.005,0.005,0.21
+07/06/2023,48.82,7.3005696,90.04,64.58,9.96,16.92664974,22.39,25.93,0.78,0.42,0.2,0.11,0.005,0.005,0.005,0.16
+13/07/2023,21.79,1.5712512,77.61,40.41,9.74,20.82331251,26.23,22.49,0.6,1.16,0.22,0.31,0,0,0.02,0.14
+17/07/2023,21.79,4.9213376,77.61,40.41,9.74,20.82331251,26.23,22.49,0.6,1.16,0.22,0.31,0.01,0.01,0.02,0.14
+23/08/2023,23.88,2.778432,97.75,49.74,26.25,31.24996875,31.11,16.43,1.33,0.8,0.18,0.14,0,0,0.01,1.01
+02/09/2023,23.88,2.778432,97.75,49.74,16.15,31.24996875,31.11,16.43,1.33,0.8,0.18,0.14,0,0,0.01,1.01
+13/10/2023,71.9,5.0905984,106.35,91.03,18.11,34.90663176,32.36,14.59,1.43,0.97,0.17,0.05,0,0,0,0.24
+28/12/2023,70.58,9.1368896,141.05,68.18,11.96,24.18664248,27.95,21.57,1.31,0.88,0.16,0.15,0,0,0.02,0.06
+16/01/2024,77.26,11.433088,149.17,68.71,12.14,23.24331009,29.88,27.04,1.15,1.14,0.26,0.14,0,0,0,0.09
+04/03/2024,84.65,13.4418624,185.21,66.05,15.61,30.69330264,40.12,36.82,0.66,0.93,0.39,0.35,0,0,0.03,0.16
+23/04/2024,69.17,11.2350848,116.41,52.96,14.07,28.95330438,80.73,37.54,0.57,0.79,0.42,0.38,0.01,0,0.03,0.16
+30/05/2024,46.74,7.520928,81.84,38.61,10.48,26.52997347,79.96,40.47,0.34,0.87,0.45,0.37,0,0.03,0.03,0.12
+05/07/2024,27.51,3.960064,75.58,27.78,8.29,25.99330734,92.2,44.74,0.32,0.59,0.45,0.37,0,0.03,0.03,0.15
+23/07/2024,16.55,2.4143616,83.62,16.52,4.9,20.45997954,79.04,40.51,0.32,0.77,0.43,0.26,0,0.03,0.02,0.43
+06/08/2024,0,0.3001984,74.41,6.82,2.56,17.28664938,78.79,35.04,0.42,0.9,0.37,0.29,0,0.03,0.02,0.13
+09/09/2024,18.3,2.87424,85.3,8.7,1.7,10.5666561,53.7,22.7,2.5,0.7,0.2,0.1,0,0,0,0
+01/10/2024,22.94,4.1740352,112.46,9.44,2,13.51998648,58.57,28.76,0.27,0.6,0.26,0.17,0,0.02,0,0.2
+22/11/2024,66,2.87424,127,33,9,7.333326,63,40,2.8,0.73,0.37,0.16,0.01,0.01,0.01,0
+20/01/2025,94.26,15.664608,146.27,76.06,14.24,32.05663461,64.29,46.99,0.45,0.37,0.48,0.16,0.08,0.03,0.01,0.11
+06/03/2025,95.82,20.007904,171.83,92.24,15.75,35.2332981,82.27,54.5,0.45,0.17,0.49,0.16,0.03,0.02,0,0.06
+04/04/2025,85.49,17.2646016,109.91,88.54,13.47,31.08663558,65.02,53.96,0.28,0.65,0.51,0.13,0.01,0.01,0,0
+22/05/2025,49.8,9.9927744,92.41,61.42,8.47,22.42331091,52.95,38.25,0.32,0.86,0.48,0.23,0.03,0,0.02,0.13
+11/06/2025,30.28,5.700576,50.2,48.96,5.73,22.10664456,51.34,33.41,0,0.96,0.51,0.26,0,0,0,0
+01/08/2025,1.34,0.4854272,77.64,16.45,5.52,22.93997706,58.45,25.83,0.5,0.48,0.44,0.17,0,0,0,0
diff --git a/db/data/nutrient_requirements.csv b/db/data/nutrient_requirements.csv
new file mode 100644
index 0000000..61406b8
--- /dev/null
+++ b/db/data/nutrient_requirements.csv
@@ -0,0 +1,9 @@
+Nom,NNO3,P,K,Ca,Mg,S,Na,Cl,Si,Fe,Zn,B,Mn,Cu,Mo,NNH4
+Générique croissance,160,30,230,100,30,60,0,0,0,5,"0,15","0,3","0,5","0,15","0,05",0
+Générique floraison,130,60,300,100,30,60,0,0,0,2,"0,1","0,5","0,5","0,05","0,05",0
+Laitue,190,50,210,200,50,66,0,0,0,5,"0,15","0,3","0,5","0,15","0,05",0
+Tomate (cycle entier),140,50,352,180,50,168,0,0,0,5,"0,1","0,3","0,8","0,07","0,03",0
+Tomate 10-14 jours,100,40,200,100,20,53,0,0,0,3,"0,1","0,3","0,8","0,07","0,03",0
+Tomate 1ere grappe,130,55,300,150,33,109,0,0,0,3,"0,1","0,3","0,8","0,07","0,03",0
+Tomate à maturité,180,65,400,400,45,144,0,0,0,3,"0,1","0,3","0,8","0,07","0,03",0
+Framboise - tous stades,70,12,88,90,24,48,0,0,50,0.56,"0,325",11,"0,11","0,032","0,01",0
diff --git a/db/migrate/20250820175727_create_nutrients.rb b/db/migrate/20250820175727_create_nutrients.rb
new file mode 100644
index 0000000..d054375
--- /dev/null
+++ b/db/migrate/20250820175727_create_nutrients.rb
@@ -0,0 +1,10 @@
+class CreateNutrients < ActiveRecord::Migration[8.0]
+ def change
+ create_table :nutrients do |t|
+ t.string :formula
+ t.string :name
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20250820175742_create_nutrient_measurements.rb b/db/migrate/20250820175742_create_nutrient_measurements.rb
new file mode 100644
index 0000000..b4bae51
--- /dev/null
+++ b/db/migrate/20250820175742_create_nutrient_measurements.rb
@@ -0,0 +1,27 @@
+class CreateNutrientMeasurements < ActiveRecord::Migration[8.0]
+ def change
+ create_table :nutrient_measurements do |t|
+ t.date :measured_on
+ t.float :nno3
+ t.float :p
+ t.float :k
+ t.float :ca
+ t.float :mg
+ t.float :s
+ t.float :na
+ t.float :cl
+ t.float :si
+ t.float :fe
+ t.float :zn
+ t.float :b
+ t.float :mn
+ t.float :cu
+ t.float :mo
+ t.float :nnh4
+
+ t.timestamps
+ end
+
+ add_index :nutrient_measurements, :measured_on, unique: true
+ end
+end
diff --git a/db/migrate/20250823140019_create_crops.rb b/db/migrate/20250823140019_create_crops.rb
new file mode 100644
index 0000000..e88abd3
--- /dev/null
+++ b/db/migrate/20250823140019_create_crops.rb
@@ -0,0 +1,26 @@
+class CreateCrops < ActiveRecord::Migration[8.0]
+ def change
+ create_table :crops do |t|
+ t.string :name
+ t.integer :crop_type, null: false, default: 1
+ t.float :nno3
+ t.float :p
+ t.float :k
+ t.float :ca
+ t.float :mg
+ t.float :s
+ t.float :na
+ t.float :cl
+ t.float :si
+ t.float :fe
+ t.float :zn
+ t.float :b
+ t.float :mn
+ t.float :cu
+ t.float :mo
+ t.float :nnh4
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20250823142743_create_beds.rb b/db/migrate/20250823142743_create_beds.rb
new file mode 100644
index 0000000..3c23ad7
--- /dev/null
+++ b/db/migrate/20250823142743_create_beds.rb
@@ -0,0 +1,11 @@
+class CreateBeds < ActiveRecord::Migration[8.0]
+ def change
+ create_table :beds do |t|
+ t.integer :location, null: false
+
+ t.timestamps
+ end
+
+ add_index :beds, :location, unique: true
+ end
+end
diff --git a/db/migrate/20250823142858_create_rafts.rb b/db/migrate/20250823142858_create_rafts.rb
new file mode 100644
index 0000000..6b7f006
--- /dev/null
+++ b/db/migrate/20250823142858_create_rafts.rb
@@ -0,0 +1,13 @@
+class CreateRafts < ActiveRecord::Migration[8.0]
+ def change
+ create_table :rafts do |t|
+ t.references :bed, null: false, foreign_key: true
+ t.integer :location, null: false
+ t.references :crop, null: true, foreign_key: true
+
+ t.timestamps
+ end
+
+ add_index :rafts, [ :bed_id, :location ], unique: true
+ end
+end
diff --git a/db/migrate/20250824121914_create_fertilizer_components.rb b/db/migrate/20250824121914_create_fertilizer_components.rb
new file mode 100644
index 0000000..2e08fff
--- /dev/null
+++ b/db/migrate/20250824121914_create_fertilizer_components.rb
@@ -0,0 +1,26 @@
+class CreateFertilizerComponents < ActiveRecord::Migration[8.0]
+ def change
+ create_table :fertilizer_components do |t|
+ t.string :name
+ t.string :formula
+ t.float :nno3
+ t.float :nnh4
+ t.float :p
+ t.float :k
+ t.float :ca
+ t.float :mg
+ t.float :s
+ t.float :na
+ t.float :cl
+ t.float :si
+ t.float :fe
+ t.float :zn
+ t.float :b
+ t.float :mn
+ t.float :cu
+ t.float :mo
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20250824163242_create_fertilizer_products.rb b/db/migrate/20250824163242_create_fertilizer_products.rb
new file mode 100644
index 0000000..024f82c
--- /dev/null
+++ b/db/migrate/20250824163242_create_fertilizer_products.rb
@@ -0,0 +1,11 @@
+class CreateFertilizerProducts < ActiveRecord::Migration[8.0]
+ def change
+ create_table :fertilizer_products do |t|
+ t.string :name, null: false
+ t.decimal :purity, precision: 5, scale: 2, null: false, default: 100.00
+
+ t.timestamps
+ end
+ add_index :fertilizer_products, :name, unique: true
+ end
+end
diff --git a/db/migrate/20250824163257_create_fertilizer_compositions.rb b/db/migrate/20250824163257_create_fertilizer_compositions.rb
new file mode 100644
index 0000000..b48954a
--- /dev/null
+++ b/db/migrate/20250824163257_create_fertilizer_compositions.rb
@@ -0,0 +1,11 @@
+class CreateFertilizerCompositions < ActiveRecord::Migration[8.0]
+ def change
+ create_table :fertilizer_compositions do |t|
+ t.references :fertilizer_product, null: false, foreign_key: true
+ t.references :fertilizer_component, null: false, foreign_key: true
+ t.decimal :percent_w, precision: 6, scale: 3, null: false # e.g. 13.500 (% w/w)
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
new file mode 100644
index 0000000..b5f2e03
--- /dev/null
+++ b/db/schema.rb
@@ -0,0 +1,130 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# This file is the source Rails uses to define your schema when running `bin/rails
+# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
+# be faster and is potentially less error prone than running all of your
+# migrations from scratch. Old migrations may fail to apply correctly if those
+# migrations use external dependencies or application code.
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema[8.0].define(version: 2025_08_24_163257) do
+ create_table "beds", force: :cascade do |t|
+ t.integer "location", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["location"], name: "index_beds_on_location", unique: true
+ end
+
+ create_table "crops", force: :cascade do |t|
+ t.string "name"
+ t.integer "crop_type", default: 1, null: false
+ t.float "nno3"
+ t.float "p"
+ t.float "k"
+ t.float "ca"
+ t.float "mg"
+ t.float "s"
+ t.float "na"
+ t.float "cl"
+ t.float "si"
+ t.float "fe"
+ t.float "zn"
+ t.float "b"
+ t.float "mn"
+ t.float "cu"
+ t.float "mo"
+ t.float "nnh4"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ create_table "fertilizer_components", force: :cascade do |t|
+ t.string "name"
+ t.string "formula"
+ t.float "nno3"
+ t.float "nnh4"
+ t.float "p"
+ t.float "k"
+ t.float "ca"
+ t.float "mg"
+ t.float "s"
+ t.float "na"
+ t.float "cl"
+ t.float "si"
+ t.float "fe"
+ t.float "zn"
+ t.float "b"
+ t.float "mn"
+ t.float "cu"
+ t.float "mo"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ create_table "fertilizer_compositions", force: :cascade do |t|
+ t.integer "fertilizer_product_id", null: false
+ t.integer "fertilizer_component_id", null: false
+ t.decimal "percent_w", precision: 6, scale: 3, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["fertilizer_component_id"], name: "index_fertilizer_compositions_on_fertilizer_component_id"
+ t.index ["fertilizer_product_id"], name: "index_fertilizer_compositions_on_fertilizer_product_id"
+ end
+
+ create_table "fertilizer_products", force: :cascade do |t|
+ t.string "name", null: false
+ t.decimal "purity", precision: 5, scale: 2, default: "100.0", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["name"], name: "index_fertilizer_products_on_name", unique: true
+ end
+
+ create_table "nutrient_measurements", force: :cascade do |t|
+ t.date "measured_on"
+ t.float "nno3"
+ t.float "p"
+ t.float "k"
+ t.float "ca"
+ t.float "mg"
+ t.float "s"
+ t.float "na"
+ t.float "cl"
+ t.float "si"
+ t.float "fe"
+ t.float "zn"
+ t.float "b"
+ t.float "mn"
+ t.float "cu"
+ t.float "mo"
+ t.float "nnh4"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["measured_on"], name: "index_nutrient_measurements_on_measured_on", unique: true
+ end
+
+ create_table "nutrients", force: :cascade do |t|
+ t.string "formula"
+ t.string "name"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ create_table "rafts", force: :cascade do |t|
+ t.integer "bed_id", null: false
+ t.integer "location", null: false
+ t.integer "crop_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["bed_id", "location"], name: "index_rafts_on_bed_id_and_location", unique: true
+ t.index ["bed_id"], name: "index_rafts_on_bed_id"
+ t.index ["crop_id"], name: "index_rafts_on_crop_id"
+ end
+
+ add_foreign_key "fertilizer_compositions", "fertilizer_components"
+ add_foreign_key "fertilizer_compositions", "fertilizer_products"
+ add_foreign_key "rafts", "beds"
+ add_foreign_key "rafts", "crops"
+end
diff --git a/db/seeds.rb b/db/seeds.rb
new file mode 100644
index 0000000..848db0d
--- /dev/null
+++ b/db/seeds.rb
@@ -0,0 +1,13 @@
+# This file should ensure the existence of records required to run the application in every environment (production,
+# development, test). The code here should be idempotent so that it can be executed at any point in every environment.
+# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup).
+#
+# Example:
+#
+# ["Action", "Comedy", "Drama", "Horror"].each do |genre_name|
+# MovieGenre.find_or_create_by!(name: genre_name)
+# end
+
+Dir[Rails.root.join("db/seeds/*.rb")].sort.each do |seed|
+ load seed
+end
diff --git a/db/seeds/1_nutrients.rb b/db/seeds/1_nutrients.rb
new file mode 100644
index 0000000..dab2249
--- /dev/null
+++ b/db/seeds/1_nutrients.rb
@@ -0,0 +1,24 @@
+NUTRIENTS = [
+ [ "nno3", "nitrate" ],
+ [ "p", "phosphore" ],
+ [ "k", "potassium" ],
+ [ "ca", "calcium" ],
+ [ "mg", "magnésium" ],
+ [ "s", "soufre" ],
+ [ "na", "sodium" ],
+ [ "cl", "chlore" ],
+ [ "si", "silice" ],
+ [ "fe", "fer" ],
+ [ "zn", "zinc" ],
+ [ "b", "bore" ],
+ [ "mn", "manganèse" ],
+ [ "cu", "cuivre" ],
+ [ "mo", "molybdène" ],
+ [ "nnh4", "ammonium" ]
+]
+
+NUTRIENTS.each do |formula, name|
+ Nutrient.find_or_create_by!(formula:) { |n| n.name = name }
+end
+
+puts "Nutrients: #{Nutrient.count}"
diff --git a/db/seeds/2_nutrient_measurements.rb b/db/seeds/2_nutrient_measurements.rb
new file mode 100644
index 0000000..0ca14f1
--- /dev/null
+++ b/db/seeds/2_nutrient_measurements.rb
@@ -0,0 +1,27 @@
+require "csv"
+
+csv_path = Rails.root.join("db", "data", "dolibarr_measurements.csv")
+abort "CSV not found: #{csv_path}" unless File.exist?(csv_path)
+
+CSV.foreach(csv_path, headers: true) do |row|
+ NutrientMeasurement.find_or_create_by!(measured_on: Date.parse(row["date"])) do |m|
+ m.nno3 = row["nno3"]
+ m.p = row["p"]
+ m.k = row["k"]
+ m.ca = row["ca"]
+ m.mg = row["mg"]
+ m.s = row["s"]
+ m.na = row["na"]
+ m.cl = row["cl"]
+ m.si = row["si"]
+ m.fe = row["fe"]
+ m.zn = row["zn"]
+ m.b = row["b"]
+ m.mn = row["mn"]
+ m.cu = row["cu"]
+ m.mo = row["mo"]
+ m.nnh4 = row["nnh4"]
+ end
+end
+
+puts "NutrientMeasurements: #{NutrientMeasurement.count}"
diff --git a/db/seeds/3_crops.rb b/db/seeds/3_crops.rb
new file mode 100644
index 0000000..2957188
--- /dev/null
+++ b/db/seeds/3_crops.rb
@@ -0,0 +1,125 @@
+# crop_type: 0=leafy greens, 1=fruits, 2=herbs
+
+LEAFY = {
+ nno3: 150,
+ p: 31,
+ k: 210,
+ ca: 90,
+ mg: 24,
+ s: 32,
+ fe: 1.0,
+ mn: 0.25,
+ zn: 0.13,
+ b: 0.16,
+ cu: 0.023,
+ mo: 0.024,
+ nnh4: 5,
+ # keep low for leafy
+ na: 10,
+ cl: 5,
+ si: 20
+}
+
+HERB = LEAFY # Herbs run well on the Cornell leafy recipe
+
+TOMATO = {
+ # CEAC Stage 3 "multi-crop" / mature tomato
+ nno3: 190,
+ p: 47,
+ k: 350,
+ ca: 200,
+ mg: 65,
+ s: 102,
+ fe: 2.0,
+ mn: 0.55,
+ zn: 0.33,
+ b: 0.28,
+ cu: 0.05,
+ mo: 0.05,
+ nnh4: 0,
+ # CEAC recipes are NO3-N; keep NH4 minimal
+ na: 20,
+ cl: 25,
+ si: 20
+}
+
+HOT_PEPPER = {
+ # Mature greenhouse pepper (HortAmericas summary of UA recipes)
+ nno3: 180,
+ p: 50,
+ k: 280,
+ ca: 200,
+ mg: 45,
+ s: 20,
+ fe: 1.0,
+ mn: 0.55,
+ zn: 0.33,
+ b: 0.30,
+ cu: 0.05,
+ mo: 0.05,
+ nnh4: 15,
+ na: 20,
+ cl: 10,
+ si: 20
+}
+
+STRAWBERRY = {
+ # UA strawberry (Yamazaki) emphasizes lower EC; use conservative macros
+ nno3: 120,
+ p: 30,
+ k: 200,
+ ca: 120,
+ mg: 35,
+ s: 50,
+ fe: 1.5,
+ mn: 0.50,
+ zn: 0.20,
+ b: 0.30,
+ cu: 0.05,
+ mo: 0.05,
+ nnh4: 5,
+ na: 10,
+ cl: 5,
+ si: 20
+}
+
+RASPBERRY = {
+ # Sparse data; align with strawberry but a touch higher vigor
+ nno3: 140,
+ p: 35,
+ k: 230,
+ ca: 150,
+ mg: 40,
+ s: 50,
+ fe: 1.5,
+ mn: 0.50,
+ zn: 0.20,
+ b: 0.30,
+ cu: 0.05,
+ mo: 0.05,
+ nnh4: 5,
+ na: 15,
+ cl: 5,
+ si: 20
+}
+
+[
+ [ "lettuce", 0, LEAFY ],
+ [ "kale", 0, LEAFY ],
+ [ "chinese cabbage", 0, LEAFY ],
+ [ "tomatoes", 1, TOMATO ],
+ [ "raspberries", 1, RASPBERRY ],
+ [ "strawberries", 1, STRAWBERRY ],
+ [ "hot peppers", 1, HOT_PEPPER ],
+ [ "parsley", 2, HERB ],
+ [ "chives", 2, HERB ],
+ [ "italian basil", 2, HERB ],
+ [ "dill", 2, HERB ]
+].each do |name, type, nutrient_requirements|
+ Crop.find_or_create_by!(name: name) do |c|
+ c.crop_type = type
+ c.attributes = nutrient_requirements
+ end
+end
+
+puts "Crops: #{Crop.count}"
diff --git a/db/seeds/4_beds_and_rafts.rb b/db/seeds/4_beds_and_rafts.rb
new file mode 100644
index 0000000..0105260
--- /dev/null
+++ b/db/seeds/4_beds_and_rafts.rb
@@ -0,0 +1,24 @@
+BEDS = 14
+RAFTS = 10
+
+1.upto(BEDS) do |b|
+ bed = Bed.find_or_create_by!(location: b)
+
+ crop_name = case b
+ when 1..2 then "tomatoes"
+ when 3 then "hot peppers"
+ when 4 then "chives"
+ when 5 then "italian basil"
+ when 6..7 then "chinese cabbage"
+ else "lettuce"
+ end
+
+ 1.upto(RAFTS) do |r|
+ raft = bed.rafts.find_or_create_by!(location: r) do |raft|
+ raft.crop = Crop.find_by!(name: crop_name)
+ end
+ end
+end
+
+puts "Beds: #{Bed.count}"
+puts "Rafts: #{Raft.count}"
diff --git a/db/seeds/5_fertilizer_components.rb.bkp b/db/seeds/5_fertilizer_components.rb.bkp
new file mode 100644
index 0000000..8a1fc54
--- /dev/null
+++ b/db/seeds/5_fertilizer_components.rb.bkp
@@ -0,0 +1,38 @@
+FERTILIZER_COMPONENTS = [
+ # Macros / bases
+ { name: "Potassium Nitrate", formula: "KNO3", nno3: 13.50, k: 38.60 },
+ { name: "Calcium Nitrate", formula: "Ca(NO3)2·xH2O", nno3: 15.50, ca: 18.94 },
+ { name: "Ammonium Nitrate", formula: "NH4NO3", nno3: 13.50, nnh4: 13.50 }, # total N ≈ 27
+ { name: "Diammonium Phosphate", formula: "(NH4)2HPO4", p: 21.00 }, # NH4 can be added later if desired
+
+ # Acids / buffers
+ { name: "Nitric Acid 53%", formula: "HNO3", nno3: 11.70 },
+ { name: "Potassium Bicarbonate", formula: "KHCO3", k: 39.05 },
+ { name: "Calcium Carbonate", formula: "CaCO3", ca: 38.00 },
+
+ # K–Mg–S complex (Patentkali-type blend)
+ { name: "Potassium Sulfate blend (K–Mg–S + NaCl)", formula: "K2SO4+MgSO4+NaCl",
+ p: 0.44, k: 22.66, mg: 6.16, s: 17.77, na: 2.16, cl: 3.34 },
+
+ # Sulfates (micros / secondary)
+ { name: "Magnesium Sulfate", formula: "MgSO4·7H2O", mg: 9.648, s: 13.016 },
+ { name: "Manganese Sulfate", formula: "MnSO4", s: 7.17, mn: 12.00 },
+ { name: "Zinc Sulfate (Fiza Zinc)", formula: "ZnSO4", zn: 12.00 },
+
+ # Chelates / traces
+ { name: "Iron DTPA 11.8%", formula: "Fe-DTPA", fe: 11.80 },
+ { name: "HelioCopper (Cu chelate)", formula: "Cu-chelate", cu: 40.00 },
+
+ # Boron & Mo sources
+ { name: "Boron–Molybdenum (Boronia LS)", formula: "B+Mo", b: 13.50, mo: 0.028 },
+ { name: "Boronia MO12 (10L)", formula: "B+Mn+Cu", b: 8.90, mn: 0.089, cu: 0.89 },
+ { name: "Sodium Molybdate", formula: "Na2MoO4", mo: 39.50 }
+]
+
+FERTILIZER_COMPONENTS.each do |attrs|
+ FertilizerComponent.find_or_create_by!(name: attrs[:name]) do |c|
+ c.attributes = attrs
+ end
+end
+
+puts "Fertilizer components: #{FertilizerComponent.count}"
diff --git a/db/seeds/6_fertilizer_products.rb b/db/seeds/6_fertilizer_products.rb
new file mode 100644
index 0000000..6769bde
--- /dev/null
+++ b/db/seeds/6_fertilizer_products.rb
@@ -0,0 +1,143 @@
+FERTILIZER_RECIPES = [
+ {
+ name: "Multi K Reci",
+ purity: 99.0,
+ composition: [
+ { component: {
+ name: "Potassium nitrate",
+ formula: "KNO3",
+ nno3: 13.0,
+ k: 46.0 },
+ percent_w: 100.0 }
+ ]
+ },
+ {
+ name: "Fixa Mn",
+ purity: 98.0,
+ composition: [
+ { component: {
+ name: "Manganese sulfate",
+ formula: "MnSO4·H2O",
+ mn: 32.0,
+ s: 18.0 },
+ percent_w: 100.0 }
+ ]
+ },
+ {
+ name: "Multi-Cal Haïfa",
+ purity: 99.0,
+ composition: [
+ { component: {
+ name: "Calcium nitrate",
+ formula: "Ca(NO3)2·4H2O",
+ nno3: 15.5,
+ ca: 19.0 },
+ percent_w: 100.0 }
+ ]
+ },
+ {
+ name: "DAP 18/46/00",
+ purity: 100.0,
+ composition: [
+ { component: {
+ name: "Diammonium phosphate",
+ formula: "(NH4)2HPO4",
+ nnh4: 18.0,
+ p: 20.0 },
+ percent_w: 100.0 }
+ ]
+ },
+ {
+ name: "Patenkali",
+ purity: 100.0,
+ composition: [
+ { component: {
+ name: "Potassium sulfate",
+ formula: "K2SO4",
+ k: 50.0,
+ s: 18.0
+ }, percent_w: 100.0 }
+ ]
+ },
+ {
+ name: "Eso Top",
+ purity: 100.0,
+ composition: [
+ { component: {
+ name: "Magnesium sulfate",
+ formula: "MgSO4·7H2O",
+ mg: 9.8,
+ s: 13.0 },
+ percent_w: 100.0 }
+ ]
+ },
+ {
+ name: "Ammonitrate 27",
+ purity: 100.0,
+ composition: [
+ { component: {
+ name: "Ammonium nitrate",
+ formula: "NH4NO3",
+ nno3: 13.5,
+ nnh4: 13.5 },
+ percent_w: 100.0 }
+ ]
+ },
+ {
+ name: "Fer chélaté",
+ purity: 100.0,
+ composition: [
+ { component: {
+ name: "Iron chelate (EDDHA)",
+ formula: "Fe-EDDHA",
+ fe: 6.0 },
+ percent_w: 100.0 }
+ ]
+ },
+ {
+ name: "Carbonate de calcium",
+ purity: 100.0,
+ composition: [
+ { component: {
+ name: "Calcium carbonate",
+ formula: "CaCO3",
+ ca: 40.0 },
+ percent_w: 100.0 }
+ ]
+ },
+ {
+ name: "Héliocuivre",
+ purity: 100.0,
+ composition: [
+ { component: {
+ name: "Copper chelate (EDTA)",
+ formula: "Cu-EDTA",
+ cu: 14.0 },
+ percent_w: 100.0 }
+ ]
+ }
+]
+
+FERTILIZER_RECIPES.each do |recipe|
+ product = FertilizerProduct.find_or_create_by!(name: recipe[:name]) do |fp|
+ fp.purity = recipe[:purity]
+ end
+
+ recipe[:composition].each do |c|
+ comp_attrs = c[:component]
+ component = FertilizerComponent.find_or_create_by!(name: comp_attrs[:name]) do |fc|
+ fc.formula = comp_attrs[:formula]
+ end
+ # update nutrient fields if missing
+ component.update!(comp_attrs.except(:name, :formula))
+
+ FertilizerComposition.find_or_create_by!(
+ fertilizer_product: product,
+ fertilizer_component: component
+ ) do |fc|
+ fc.percent_w = c[:percent_w]
+ end
+ end
+end
+
+puts "FertilizerProducts: #{FertilizerProduct.count}"
Copyright 2019--2025 Marius PETER