Add source_site_id to ActiveSite model and implement unique constraint. Update serializers and views for site registration and claiming. Enhance tests for site registration and claiming functionality.
This commit is contained in:
1 parent
521f36d22d
commit
61f954a3bd
12 files changed
+684
-172
No files matched your search
+189
-120
@@ -1,15 +1,20 @@
|
||||
-- =============================================================================
|
||||
-- PostgreSQL Schema — CPSP Dashboard ERD
|
||||
-- Source: ERD_dashboard.png (updated 2026-08-20)
|
||||
-- PostgreSQL Schema — CPSP Executive Dashboard ERD
|
||||
-- Source: live DB (dashboard-cpsp-executive) + Django models (updated 2026-09-14)
|
||||
--
|
||||
-- user_access.status:
|
||||
-- inactive | gm | gm_admin | buh | bu_admin | director | director_admin |
|
||||
-- account_admin | superuser
|
||||
-- (Django syncs is_active/is_superuser from status on save:
|
||||
-- inactive => both false; superuser => both true; other executive roles =>
|
||||
-- is_active true, is_superuser false. Product roles never use is_staff.)
|
||||
--
|
||||
-- user_access.status: active | inactive | superadmin
|
||||
-- (Django syncs is_active/is_staff/is_superuser from status on save:
|
||||
-- inactive => all false; superadmin => is_active/is_superuser true,
|
||||
-- is_staff false; active => is_active true, is_superuser false, is_staff
|
||||
-- left untouched so operators can be marked staff)
|
||||
-- user_access → sites → kandang → cycles
|
||||
-- cycles → flock (flock.cycle_id, required; cycles has no flock_id)
|
||||
-- flock → iot_panel
|
||||
-- kandang → flock → iot_panel
|
||||
-- user_access → api_keys
|
||||
-- user_access → active_sites (managed_by)
|
||||
-- sites ↔ active_sites (optional 1:1)
|
||||
-- cycles → active_sites (mirror source) + close-approval user FKs
|
||||
-- cycles → ai_insight, feed_sacks, chicken_counting, chicken_weight,
|
||||
-- manual_input, kpi
|
||||
-- kpi → chicken_counting, chicken_weight, feed_sacks, manual_input
|
||||
@@ -17,120 +22,184 @@
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 1. User Access
|
||||
-- Django AbstractBaseUser + PermissionsMixin. `status` is the app's role
|
||||
-- (active | inactive | superadmin); Django auth flags are synced from it on
|
||||
-- save (is_staff stays untouched for active users, superadmin => is_staff
|
||||
-- false, is_superuser true).
|
||||
-- Django AbstractBaseUser + PermissionsMixin. `status` is the executive
|
||||
-- role; is_active/is_superuser are derived from it on save.
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS user_access (
|
||||
user_id SERIAL PRIMARY KEY,
|
||||
user_name VARCHAR(30) NOT NULL UNIQUE,
|
||||
display_name VARCHAR(30) NOT NULL UNIQUE,
|
||||
password VARCHAR(128) NOT NULL,
|
||||
last_login TIMESTAMP WITH TIME ZONE,
|
||||
is_superuser BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
status VARCHAR(30) NOT NULL
|
||||
user_id BIGSERIAL PRIMARY KEY,
|
||||
user_name VARCHAR(30) NOT NULL UNIQUE,
|
||||
display_name VARCHAR(30) NOT NULL UNIQUE,
|
||||
password VARCHAR(128) NOT NULL,
|
||||
last_login TIMESTAMP WITH TIME ZONE,
|
||||
is_superuser BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
status VARCHAR(30) NOT NULL DEFAULT 'gm',
|
||||
managed_by_id BIGINT REFERENCES user_access (user_id) ON DELETE SET NULL,
|
||||
managed_by_pending_id BIGINT REFERENCES user_access (user_id) ON DELETE SET NULL,
|
||||
managed_by_requested_at TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_access_status ON user_access (status);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_access_managed_by_id ON user_access (managed_by_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_access_managed_by_pending_id ON user_access (managed_by_pending_id);
|
||||
|
||||
-- Django PermissionsMixin many-to-many tables.
|
||||
CREATE TABLE IF NOT EXISTS user_access_groups (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES user_access (user_id) ON DELETE CASCADE,
|
||||
group_id INTEGER NOT NULL REFERENCES auth_group (id) ON DELETE CASCADE
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL REFERENCES user_access (user_id) ON DELETE CASCADE,
|
||||
group_id INTEGER NOT NULL REFERENCES auth_group (id) ON DELETE CASCADE,
|
||||
UNIQUE (user_id, group_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_access_user_permissions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES user_access (user_id) ON DELETE CASCADE,
|
||||
permission_id INTEGER NOT NULL REFERENCES auth_permission (id) ON DELETE CASCADE
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL REFERENCES user_access (user_id) ON DELETE CASCADE,
|
||||
permission_id INTEGER NOT NULL REFERENCES auth_permission (id) ON DELETE CASCADE,
|
||||
UNIQUE (user_id, permission_id)
|
||||
);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 2. Sites
|
||||
-- 2. API Keys (inbound X-API-Key auth to HQ)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS api_keys (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL REFERENCES user_access (user_id) ON DELETE CASCADE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
prefix VARCHAR(12) NOT NULL,
|
||||
key_hash VARCHAR(64) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
last_used_at TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_user_id ON api_keys (user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_prefix ON api_keys (prefix);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 3. Active Sites (farm-location dashboard-cpsp registry)
|
||||
-- source_site_id = farm-location sites.site_id slug (e.g. sukawarna-4821),
|
||||
-- sent by site dashboard on register-from-site (API field name: site_id).
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS active_sites (
|
||||
active_site_id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(64) NOT NULL UNIQUE,
|
||||
name VARCHAR(120) NOT NULL,
|
||||
source_site_id VARCHAR(64) NOT NULL DEFAULT '',
|
||||
api_base_url VARCHAR(255) NOT NULL DEFAULT '',
|
||||
api_key VARCHAR(255) NOT NULL DEFAULT '',
|
||||
managed_by_id BIGINT REFERENCES user_access (user_id) ON DELETE SET NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
last_synced_at TIMESTAMP WITH TIME ZONE,
|
||||
last_sync_status VARCHAR(32) NOT NULL DEFAULT '',
|
||||
last_sync_message TEXT NOT NULL DEFAULT '',
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_active_sites_managed_by_id ON active_sites (managed_by_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_active_sites_source_site_id ON active_sites (source_site_id);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 4. Sites
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS sites (
|
||||
site_id SERIAL PRIMARY KEY,
|
||||
site_name VARCHAR(30) NOT NULL,
|
||||
user_id INTEGER NOT NULL REFERENCES user_access (user_id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
site_id BIGSERIAL PRIMARY KEY,
|
||||
site_name VARCHAR(30) NOT NULL,
|
||||
user_id BIGINT NOT NULL REFERENCES user_access (user_id) ON DELETE CASCADE,
|
||||
active_site_id BIGINT UNIQUE REFERENCES active_sites (active_site_id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sites_user_id ON sites (user_id);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 3. Kandang (Coop / Pen)
|
||||
-- 5. Kandang (Coop / Pen)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS kandang (
|
||||
kandang_id SERIAL PRIMARY KEY,
|
||||
kandang_name VARCHAR(30) NOT NULL,
|
||||
site_id INTEGER NOT NULL REFERENCES sites (site_id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
kandang_id BIGSERIAL PRIMARY KEY,
|
||||
kandang_name VARCHAR(30) NOT NULL,
|
||||
feed_in_button_urls JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
site_id BIGINT NOT NULL REFERENCES sites (site_id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_kandang_site_id ON kandang (site_id);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 4. Cycles
|
||||
-- No flock_id — flock belongs to cycle via flock.cycle_id.
|
||||
-- 6. Flock
|
||||
-- Belongs to kandang (not cycle). IoT readings attach here.
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS flock (
|
||||
flock_id BIGSERIAL PRIMARY KEY,
|
||||
flock_name VARCHAR(30) NOT NULL,
|
||||
kandang_id BIGINT NOT NULL REFERENCES kandang (kandang_id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_flock_kandang_id ON flock (kandang_id);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 7. Cycles
|
||||
-- end_date NULL while open; status active | pending_close | closed.
|
||||
-- Optional active_site + source_cycle_id identify the mirrored farm cycle.
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS cycles (
|
||||
cycle_id SERIAL PRIMARY KEY,
|
||||
total_days INTEGER NOT NULL,
|
||||
start_date DATE NOT NULL,
|
||||
end_date DATE NOT NULL,
|
||||
doc_in_weight INTEGER NOT NULL,
|
||||
doc_in_count INTEGER NOT NULL,
|
||||
feed_initial_balance INTEGER NOT NULL DEFAULT 0,
|
||||
feed_initial_balance_date DATE,
|
||||
status VARCHAR(30) NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
kandang_id INTEGER NOT NULL REFERENCES kandang (kandang_id) ON DELETE CASCADE,
|
||||
CONSTRAINT chk_cycles_date_range CHECK (end_date >= start_date)
|
||||
cycle_id BIGSERIAL PRIMARY KEY,
|
||||
total_days INTEGER NOT NULL DEFAULT 1,
|
||||
start_date DATE NOT NULL,
|
||||
end_date DATE,
|
||||
doc_in_weight INTEGER NOT NULL,
|
||||
doc_in_count INTEGER NOT NULL,
|
||||
feed_initial_balance INTEGER NOT NULL DEFAULT 0,
|
||||
feed_initial_balance_date DATE,
|
||||
status VARCHAR(30) NOT NULL DEFAULT 'active',
|
||||
kandang_id BIGINT NOT NULL REFERENCES kandang (kandang_id) ON DELETE CASCADE,
|
||||
active_site_id BIGINT REFERENCES active_sites (active_site_id) ON DELETE SET NULL,
|
||||
source_cycle_id BIGINT,
|
||||
proposed_end_date DATE,
|
||||
close_requested_at TIMESTAMP WITH TIME ZONE,
|
||||
close_requested_by_id BIGINT REFERENCES user_access (user_id) ON DELETE SET NULL,
|
||||
close_approved_by_id BIGINT REFERENCES user_access (user_id) ON DELETE SET NULL,
|
||||
close_approved_at TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_cycles_date_range CHECK (end_date IS NULL OR end_date >= start_date)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_cycles_kandang_id ON cycles (kandang_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cycles_status ON cycles (status);
|
||||
CREATE INDEX IF NOT EXISTS idx_cycles_start_date ON cycles (start_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_cycles_active_site_id ON cycles (active_site_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cycles_close_requested_by_id ON cycles (close_requested_by_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cycles_close_approved_by_id ON cycles (close_approved_by_id);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_cycle_active_source
|
||||
ON cycles (active_site_id, source_cycle_id)
|
||||
WHERE active_site_id IS NOT NULL AND source_cycle_id IS NOT NULL;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 5. Flock
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS flock (
|
||||
flock_id SERIAL PRIMARY KEY,
|
||||
flock_name VARCHAR(30) NOT NULL,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_flock_cycle_id ON flock (cycle_id);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 6. IoT Panel
|
||||
-- 8. IoT Panel
|
||||
-- One row per sensor reading; the panel polls every 10 minutes, so a cycle
|
||||
-- day holds up to 144 rows. `timestamp` carries the reading time; `date` is
|
||||
-- kept denormalized for fast daily grouping.
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS iot_panel (
|
||||
panel_id SERIAL PRIMARY KEY,
|
||||
panel_id BIGSERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
timestamp TIMESTAMP WITH TIME ZONE,
|
||||
wind_speed FLOAT NOT NULL,
|
||||
humidity FLOAT NOT NULL,
|
||||
water_total FLOAT NOT NULL,
|
||||
average_temperature FLOAT NOT NULL,
|
||||
experience_temperature FLOAT NOT NULL,
|
||||
wind_speed DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
humidity DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
water_total DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
average_temperature DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
experience_temperature DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
flock_id INTEGER NOT NULL REFERENCES flock (flock_id) ON DELETE CASCADE
|
||||
flock_id BIGINT NOT NULL REFERENCES flock (flock_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_iot_panel_flock_id ON iot_panel (flock_id);
|
||||
@@ -139,10 +208,10 @@ CREATE INDEX IF NOT EXISTS idx_iot_panel_timestamp ON iot_panel (timestamp);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_iot_panel_flock_timestamp ON iot_panel (flock_id, timestamp);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 7. AI Insight
|
||||
-- 9. AI Insight
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS ai_insight (
|
||||
id SERIAL PRIMARY KEY,
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
insight_text TEXT NOT NULL,
|
||||
alert VARCHAR(100) NOT NULL,
|
||||
@@ -150,17 +219,17 @@ CREATE TABLE IF NOT EXISTS ai_insight (
|
||||
session VARCHAR(100) NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
cycle_id BIGINT NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_insight_cycle_id ON ai_insight (cycle_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_insight_date ON ai_insight (date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 8. Feed Sacks
|
||||
-- 10. Feed Sacks
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS feed_sacks (
|
||||
fs_id SERIAL PRIMARY KEY,
|
||||
fs_id BIGSERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
in_today INTEGER NOT NULL DEFAULT 0,
|
||||
out_today INTEGER NOT NULL DEFAULT 0,
|
||||
@@ -170,7 +239,7 @@ CREATE TABLE IF NOT EXISTS feed_sacks (
|
||||
feed_use_total INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
cycle_id BIGINT NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_feed_sacks_cycle_id ON feed_sacks (cycle_id);
|
||||
@@ -178,16 +247,16 @@ CREATE INDEX IF NOT EXISTS idx_feed_sacks_date ON feed_sacks (date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_feed_sacks_cycle_date ON feed_sacks (cycle_id, date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 9. Chicken Counting
|
||||
-- 11. Chicken Counting
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS chicken_counting (
|
||||
cc_id SERIAL PRIMARY KEY,
|
||||
cc_id BIGSERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
total_count INTEGER NOT NULL DEFAULT 0,
|
||||
mortality_count INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
cycle_id BIGINT NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_chicken_counting_cycle_id ON chicken_counting (cycle_id);
|
||||
@@ -195,31 +264,31 @@ CREATE INDEX IF NOT EXISTS idx_chicken_counting_date ON chicken_counting (date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_chicken_counting_cycle_date ON chicken_counting (cycle_id, date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 10. Chicken Weight
|
||||
-- 12. Chicken Weight
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS chicken_weight (
|
||||
cw_id SERIAL PRIMARY KEY,
|
||||
cw_id BIGSERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
age INTEGER NOT NULL,
|
||||
doc_weight INTEGER NOT NULL,
|
||||
average_weight FLOAT NOT NULL,
|
||||
average_weight DOUBLE PRECISION NOT NULL,
|
||||
chicken_count INTEGER NOT NULL,
|
||||
uniformity FLOAT NOT NULL,
|
||||
average_daily_gain FLOAT NOT NULL,
|
||||
uniformity DOUBLE PRECISION NOT NULL,
|
||||
average_daily_gain DOUBLE PRECISION NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
cycle_id BIGINT NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_chicken_weight_cycle_id ON chicken_weight (cycle_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chicken_weight_date ON chicken_weight (date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_chicken_weight_cycle_date ON chicken_weight (cycle_id, date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_cw_cycle_date ON chicken_weight (cycle_id, date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 11. Manual Input
|
||||
-- 13. Manual Input
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS manual_input (
|
||||
manual_id SERIAL PRIMARY KEY,
|
||||
manual_id BIGSERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
age_manual INTEGER NOT NULL DEFAULT 0,
|
||||
mortality_manual INTEGER NOT NULL DEFAULT 0,
|
||||
@@ -232,16 +301,16 @@ CREATE TABLE IF NOT EXISTS manual_input (
|
||||
feed_out_manual_total INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_manual INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_manual_total INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_weight_manual FLOAT NOT NULL DEFAULT 0,
|
||||
harvest_weight_manual_total FLOAT NOT NULL DEFAULT 0,
|
||||
manual_weight FLOAT NOT NULL DEFAULT 0,
|
||||
average_harvest_day_manual FLOAT NOT NULL DEFAULT 0,
|
||||
average_harvest_weight_manual FLOAT NOT NULL DEFAULT 0,
|
||||
fcr_manual FLOAT NOT NULL DEFAULT 0,
|
||||
eef_manual FLOAT NOT NULL DEFAULT 0,
|
||||
harvest_weight_manual DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
harvest_weight_manual_total DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
manual_weight DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
average_harvest_day_manual DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
average_harvest_weight_manual DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
fcr_manual DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
eef_manual DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
cycle_id BIGINT NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_manual_input_cycle_id ON manual_input (cycle_id);
|
||||
@@ -249,10 +318,10 @@ CREATE INDEX IF NOT EXISTS idx_manual_input_date ON manual_input (date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_manual_input_cycle_date ON manual_input (cycle_id, date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 12. KPI (aggregates data from cycle + source records)
|
||||
-- 14. KPI (aggregates data from cycle + source records)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS kpi (
|
||||
kpi_id SERIAL PRIMARY KEY,
|
||||
kpi_id BIGSERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
age INTEGER NOT NULL DEFAULT 0,
|
||||
mortality INTEGER NOT NULL DEFAULT 0,
|
||||
@@ -261,22 +330,22 @@ CREATE TABLE IF NOT EXISTS kpi (
|
||||
feed_total INTEGER NOT NULL DEFAULT 0,
|
||||
harvest INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_total INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_weight FLOAT NOT NULL DEFAULT 0,
|
||||
harvest_weight_total FLOAT NOT NULL DEFAULT 0,
|
||||
harvest_weight DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
harvest_weight_total DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
chicken_life INTEGER NOT NULL DEFAULT 0,
|
||||
chicken_life_percentage FLOAT NOT NULL DEFAULT 0,
|
||||
iot_weight FLOAT NOT NULL DEFAULT 0,
|
||||
average_harvest_day FLOAT NOT NULL DEFAULT 0,
|
||||
average_harvest_weight FLOAT NOT NULL DEFAULT 0,
|
||||
fcr FLOAT NOT NULL DEFAULT 0,
|
||||
eef FLOAT NOT NULL DEFAULT 0,
|
||||
chicken_life_percentage DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
iot_weight DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
average_harvest_day DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
average_harvest_weight DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
fcr DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
eef DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE,
|
||||
cc_id INTEGER NOT NULL REFERENCES chicken_counting (cc_id) ON DELETE RESTRICT,
|
||||
cw_id INTEGER NOT NULL REFERENCES chicken_weight (cw_id) ON DELETE RESTRICT,
|
||||
fs_id INTEGER NOT NULL REFERENCES feed_sacks (fs_id) ON DELETE RESTRICT,
|
||||
manual_id INTEGER NOT NULL REFERENCES manual_input (manual_id) ON DELETE RESTRICT
|
||||
cycle_id BIGINT NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE,
|
||||
cc_id BIGINT NOT NULL REFERENCES chicken_counting (cc_id) ON DELETE RESTRICT,
|
||||
cw_id BIGINT NOT NULL REFERENCES chicken_weight (cw_id) ON DELETE RESTRICT,
|
||||
fs_id BIGINT NOT NULL REFERENCES feed_sacks (fs_id) ON DELETE RESTRICT,
|
||||
manual_id BIGINT NOT NULL REFERENCES manual_input (manual_id) ON DELETE RESTRICT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_kpi_cycle_id ON kpi (cycle_id);
|
||||
@@ -299,8 +368,8 @@ DECLARE
|
||||
tbl TEXT;
|
||||
BEGIN
|
||||
FOREACH tbl IN ARRAY ARRAY[
|
||||
'user_access', 'sites', 'kandang', 'cycles', 'flock',
|
||||
'iot_panel', 'ai_insight', 'feed_sacks', 'chicken_counting',
|
||||
'user_access', 'api_keys', 'active_sites', 'sites', 'kandang', 'flock',
|
||||
'cycles', 'iot_panel', 'ai_insight', 'feed_sacks', 'chicken_counting',
|
||||
'chicken_weight', 'manual_input', 'kpi'
|
||||
]
|
||||
LOOP
|
||||
|
||||
Reference in new issue
Block a user