mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Merge branch 'development-before-sso' of https://gitlab.com/mbugroup/lti-api into dev/teguh
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
||||
ALTER TABLE kandangs
|
||||
DROP CONSTRAINT IF EXISTS kandangs_project_flock_id_fkey;
|
||||
|
||||
ALTER TABLE kandangs DROP COLUMN IF EXISTS project_flock_id;
|
||||
|
||||
-- Only alter if tables exist
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'project_chickins') THEN
|
||||
ALTER TABLE project_chickins
|
||||
DROP CONSTRAINT IF EXISTS fk_project_flock_kandang_id;
|
||||
ALTER TABLE project_chickins
|
||||
ADD CONSTRAINT fk_project_flock_kandang_id
|
||||
FOREIGN KEY (project_flock_kandang_id)
|
||||
REFERENCES project_flock_kandangs(id)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE;
|
||||
END IF;
|
||||
|
||||
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'project_flock_populations') THEN
|
||||
ALTER TABLE project_flock_populations
|
||||
DROP CONSTRAINT IF EXISTS fk_project_flock_kandang_id;
|
||||
ALTER TABLE project_flock_populations
|
||||
ADD CONSTRAINT fk_project_flock_kandang_id
|
||||
FOREIGN KEY (project_flock_kandang_id)
|
||||
REFERENCES project_flock_kandangs(id)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
@@ -0,0 +1,98 @@
|
||||
BEGIN;
|
||||
|
||||
DROP INDEX IF EXISTS project_flocks_base_period_unique;
|
||||
|
||||
ALTER TABLE project_flocks
|
||||
ADD COLUMN IF NOT EXISTS flock_id BIGINT;
|
||||
|
||||
WITH normalized AS (
|
||||
SELECT
|
||||
pf.id,
|
||||
COALESCE(
|
||||
NULLIF(TRIM(regexp_replace(pf.flock_name, '\\s+\\d+(\\s+\\d+)*$', '', 'g')), ''),
|
||||
CONCAT('Project Flock ', pf.id)
|
||||
) AS normalized_name,
|
||||
COALESCE(NULLIF(pf.created_by, 0), 1) AS created_by
|
||||
FROM project_flocks pf
|
||||
),
|
||||
seed_flocks AS (
|
||||
SELECT DISTINCT
|
||||
n.normalized_name,
|
||||
MIN(n.created_by) AS created_by
|
||||
FROM normalized n
|
||||
GROUP BY n.normalized_name
|
||||
)
|
||||
INSERT INTO flocks (name, created_by, created_at, updated_at)
|
||||
SELECT sf.normalized_name, sf.created_by, NOW(), NOW()
|
||||
FROM seed_flocks sf
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
WITH normalized AS (
|
||||
SELECT
|
||||
pf.id,
|
||||
COALESCE(
|
||||
NULLIF(TRIM(regexp_replace(pf.flock_name, '\\s+\\d+(\\s+\\d+)*$', '', 'g')), ''),
|
||||
CONCAT('Project Flock ', pf.id)
|
||||
) AS normalized_name
|
||||
FROM project_flocks pf
|
||||
),
|
||||
resolved AS (
|
||||
SELECT
|
||||
n.id,
|
||||
f.id AS flock_id
|
||||
FROM normalized n
|
||||
JOIN flocks f ON LOWER(f.name) = LOWER(n.normalized_name)
|
||||
)
|
||||
UPDATE project_flocks pf
|
||||
SET flock_id = resolved.flock_id
|
||||
FROM resolved
|
||||
WHERE pf.id = resolved.id;
|
||||
|
||||
WITH missing AS (
|
||||
SELECT
|
||||
pf.id,
|
||||
COALESCE(
|
||||
NULLIF(TRIM(regexp_replace(pf.flock_name, '\\s+\\d+(\\s+\\d+)*$', '', 'g')), ''),
|
||||
CONCAT('Project Flock ', pf.id)
|
||||
) AS normalized_name,
|
||||
COALESCE(NULLIF(pf.created_by, 0), 1) AS created_by
|
||||
FROM project_flocks pf
|
||||
WHERE pf.flock_id IS NULL
|
||||
),
|
||||
seed_missing AS (
|
||||
SELECT DISTINCT normalized_name, created_by FROM missing
|
||||
)
|
||||
INSERT INTO flocks (name, created_by, created_at, updated_at)
|
||||
SELECT sm.normalized_name, sm.created_by, NOW(), NOW()
|
||||
FROM seed_missing sm
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
WITH missing AS (
|
||||
SELECT
|
||||
pf.id,
|
||||
COALESCE(
|
||||
NULLIF(TRIM(regexp_replace(pf.flock_name, '\\s+\\d+(\\s+\\d+)*$', '', 'g')), ''),
|
||||
CONCAT('Project Flock ', pf.id)
|
||||
) AS normalized_name
|
||||
FROM project_flocks pf
|
||||
WHERE pf.flock_id IS NULL
|
||||
)
|
||||
UPDATE project_flocks pf
|
||||
SET flock_id = f.id
|
||||
FROM missing m
|
||||
JOIN flocks f ON LOWER(f.name) = LOWER(m.normalized_name)
|
||||
WHERE pf.id = m.id;
|
||||
|
||||
ALTER TABLE project_flocks
|
||||
ALTER COLUMN flock_id SET NOT NULL;
|
||||
|
||||
DROP INDEX IF EXISTS project_flocks_flock_name_unique;
|
||||
|
||||
ALTER TABLE project_flocks
|
||||
DROP COLUMN IF EXISTS flock_name;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS project_flocks_flock_period_unique
|
||||
ON project_flocks (flock_id, period)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,55 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE project_flocks
|
||||
ADD COLUMN IF NOT EXISTS flock_name VARCHAR(255);
|
||||
|
||||
WITH generated_names AS (
|
||||
SELECT
|
||||
pf.id,
|
||||
COALESCE(f.name, CONCAT('Project Flock ', pf.id)) AS base_name,
|
||||
pf.period,
|
||||
ROW_NUMBER() OVER (PARTITION BY COALESCE(f.name, CONCAT('Project Flock ', pf.id)) ORDER BY pf.id) AS rn
|
||||
FROM project_flocks pf
|
||||
LEFT JOIN flocks f ON f.id = pf.flock_id
|
||||
)
|
||||
UPDATE project_flocks pf
|
||||
SET flock_name = CASE
|
||||
WHEN gn.period IS NOT NULL THEN
|
||||
CASE
|
||||
WHEN gn.rn = 1 THEN CONCAT(gn.base_name, ' ', gn.period)
|
||||
ELSE CONCAT(gn.base_name, ' ', gn.period, ' ', gn.rn)
|
||||
END
|
||||
ELSE
|
||||
CASE
|
||||
WHEN gn.rn = 1 THEN gn.base_name
|
||||
ELSE CONCAT(gn.base_name, ' ', gn.rn)
|
||||
END
|
||||
END
|
||||
FROM generated_names gn
|
||||
WHERE pf.id = gn.id
|
||||
AND (pf.flock_name IS NULL OR pf.flock_name = '');
|
||||
|
||||
UPDATE project_flocks
|
||||
SET flock_name = CONCAT('Project Flock ', id)
|
||||
WHERE flock_name IS NULL OR flock_name = '';
|
||||
|
||||
ALTER TABLE project_flocks
|
||||
ALTER COLUMN flock_name SET NOT NULL;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS project_flocks_flock_name_unique
|
||||
ON project_flocks (flock_name)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
DROP INDEX IF EXISTS project_flocks_flock_period_unique;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS project_flocks_base_period_unique
|
||||
ON project_flocks (
|
||||
LOWER(TRIM(regexp_replace(flock_name, '\\s+\\d+(\\s+\\d+)*$', '', 'g'))),
|
||||
period
|
||||
)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
ALTER TABLE project_flocks
|
||||
DROP COLUMN IF EXISTS flock_id;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,143 @@
|
||||
BEGIN;
|
||||
|
||||
-- Drop newly introduced egg tables
|
||||
DROP TABLE IF EXISTS grading_eggs;
|
||||
DROP TABLE IF EXISTS recording_eggs;
|
||||
|
||||
-- Revert recording_stocks structure
|
||||
ALTER TABLE recording_stocks
|
||||
DROP CONSTRAINT IF EXISTS chk_recording_stocks_nonneg;
|
||||
|
||||
ALTER TABLE recording_stocks
|
||||
DROP COLUMN IF EXISTS usage_qty,
|
||||
DROP COLUMN IF EXISTS pending_qty;
|
||||
|
||||
ALTER TABLE recording_stocks
|
||||
ADD COLUMN increase NUMERIC(10,3),
|
||||
ADD COLUMN decrease NUMERIC(10,3),
|
||||
ADD COLUMN usage_amount BIGINT,
|
||||
ADD COLUMN notes VARCHAR;
|
||||
|
||||
ALTER TABLE recording_stocks
|
||||
ADD CONSTRAINT chk_recording_stocks_nonneg CHECK (
|
||||
(increase IS NULL OR increase >= 0) AND
|
||||
(decrease IS NULL OR decrease >= 0) AND
|
||||
(usage_amount IS NULL OR usage_amount >= 0)
|
||||
);
|
||||
|
||||
-- Revert recording_depletions structure
|
||||
ALTER TABLE recording_depletions
|
||||
DROP CONSTRAINT IF EXISTS chk_recording_depl_qty;
|
||||
|
||||
ALTER TABLE recording_depletions
|
||||
ALTER COLUMN qty TYPE BIGINT USING COALESCE(qty, 0)::BIGINT;
|
||||
|
||||
ALTER TABLE recording_depletions
|
||||
RENAME COLUMN qty TO total;
|
||||
|
||||
ALTER TABLE recording_depletions
|
||||
ADD COLUMN notes VARCHAR;
|
||||
|
||||
ALTER TABLE recording_depletions
|
||||
ADD CONSTRAINT chk_recording_depl_total CHECK (total >= 0);
|
||||
|
||||
-- Revert recording_bws structure
|
||||
ALTER TABLE recording_bws
|
||||
DROP CONSTRAINT IF EXISTS chk_recording_bws_nonneg;
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
ALTER COLUMN qty TYPE INT USING COALESCE(qty, 0)::INT;
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
DROP COLUMN IF EXISTS total_weight;
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
ALTER COLUMN avg_weight TYPE NUMERIC(8,2) USING COALESCE(avg_weight, 0)::NUMERIC(8,2);
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
RENAME COLUMN avg_weight TO weight;
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
ADD COLUMN notes VARCHAR;
|
||||
|
||||
UPDATE recording_bws
|
||||
SET qty = GREATEST(qty, 1);
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
ADD CONSTRAINT chk_recording_bws_nonneg CHECK (weight >= 0 AND qty >= 1);
|
||||
|
||||
-- Revert recordings header
|
||||
DROP INDEX IF EXISTS idx_recordings_flock_datetime;
|
||||
|
||||
ALTER TABLE recordings
|
||||
DROP CONSTRAINT IF EXISTS fk_recordings_project_flock_kandang,
|
||||
DROP CONSTRAINT IF EXISTS chk_recordings_nonnegatives_v2;
|
||||
|
||||
ALTER TABLE recordings
|
||||
ALTER COLUMN total_depletion_qty TYPE INT USING COALESCE(total_depletion_qty, 0)::INT,
|
||||
ALTER COLUMN total_chick_qty TYPE BIGINT USING COALESCE(total_chick_qty, 0)::BIGINT;
|
||||
|
||||
ALTER TABLE recordings
|
||||
RENAME COLUMN total_depletion_qty TO total_depletion;
|
||||
|
||||
ALTER TABLE recordings
|
||||
RENAME COLUMN total_chick_qty TO total_chick;
|
||||
|
||||
ALTER TABLE recordings
|
||||
ADD COLUMN record_date DATE,
|
||||
ADD COLUMN status INT NOT NULL DEFAULT 0,
|
||||
ADD COLUMN ontime INT NOT NULL DEFAULT 0,
|
||||
ADD COLUMN daily_depletion_rate NUMERIC(7,3),
|
||||
ADD COLUMN cum_depletion INT;
|
||||
|
||||
ALTER TABLE recordings
|
||||
RENAME COLUMN project_flock_kandangs_id TO project_flock_id;
|
||||
|
||||
ALTER TABLE recordings
|
||||
ADD CONSTRAINT fk_recordings_project_flock
|
||||
FOREIGN KEY (project_flock_id) REFERENCES project_flock_kandangs(id);
|
||||
|
||||
ALTER TABLE recordings
|
||||
ADD CONSTRAINT chk_recordings_status CHECK (status IN (0,1,2,3));
|
||||
|
||||
ALTER TABLE recordings
|
||||
ADD CONSTRAINT chk_recordings_ontime CHECK (ontime IN (0,1));
|
||||
|
||||
ALTER TABLE recordings
|
||||
ADD CONSTRAINT chk_recordings_nonnegatives CHECK (
|
||||
(total_depletion IS NULL OR total_depletion >= 0) AND
|
||||
(cum_depletion IS NULL OR cum_depletion >= 0) AND
|
||||
(total_chick IS NULL OR total_chick >= 0) AND
|
||||
(cum_intake IS NULL OR cum_intake >= 0) AND
|
||||
(daily_gain IS NULL OR daily_gain >= 0) AND
|
||||
(avg_daily_gain IS NULL OR avg_daily_gain >= 0) AND
|
||||
(fcr_value IS NULL OR fcr_value > 0) AND
|
||||
(daily_depletion_rate IS NULL OR daily_depletion_rate >= 0) AND
|
||||
(cum_depletion_rate IS NULL OR cum_depletion_rate >= 0)
|
||||
);
|
||||
|
||||
-- Ensure new columns carry derived data
|
||||
UPDATE recordings
|
||||
SET record_date = (record_datetime AT TIME ZONE 'Asia/Jakarta')::date
|
||||
WHERE record_date IS NULL;
|
||||
|
||||
-- Restore helper trigger/function and indexes
|
||||
CREATE OR REPLACE FUNCTION trg_set_record_date() RETURNS trigger AS $$
|
||||
BEGIN
|
||||
NEW.record_date := (NEW.record_datetime AT TIME ZONE 'Asia/Jakarta')::date;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER recordings_set_record_date_trg
|
||||
BEFORE INSERT OR UPDATE OF record_datetime ON recordings
|
||||
FOR EACH ROW EXECUTE FUNCTION trg_set_record_date();
|
||||
|
||||
CREATE INDEX idx_recordings_flock_datetime
|
||||
ON recordings (project_flock_id, record_datetime);
|
||||
|
||||
CREATE UNIQUE INDEX uq_recordings_flock_record_date
|
||||
ON recordings (project_flock_id, record_date)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,168 @@
|
||||
BEGIN;
|
||||
|
||||
-- Drop trigger & helper function tied to record_date before removing the column
|
||||
DROP TRIGGER IF EXISTS recordings_set_record_date_trg ON recordings;
|
||||
DROP FUNCTION IF EXISTS trg_set_record_date();
|
||||
|
||||
-- Drop indexes and constraints that reference legacy columns
|
||||
DROP INDEX IF EXISTS uq_recordings_flock_record_date;
|
||||
DROP INDEX IF EXISTS idx_recordings_flock_datetime;
|
||||
|
||||
ALTER TABLE recordings
|
||||
DROP CONSTRAINT IF EXISTS fk_recordings_project_flock,
|
||||
DROP CONSTRAINT IF EXISTS chk_recordings_status,
|
||||
DROP CONSTRAINT IF EXISTS chk_recordings_ontime,
|
||||
DROP CONSTRAINT IF EXISTS chk_recordings_nonnegatives;
|
||||
|
||||
-- Align recordings header with the new schema
|
||||
ALTER TABLE recordings
|
||||
RENAME COLUMN project_flock_id TO project_flock_kandangs_id;
|
||||
|
||||
ALTER TABLE recordings
|
||||
DROP COLUMN IF EXISTS record_date,
|
||||
DROP COLUMN IF EXISTS status,
|
||||
DROP COLUMN IF EXISTS ontime,
|
||||
DROP COLUMN IF EXISTS daily_depletion_rate,
|
||||
DROP COLUMN IF EXISTS cum_depletion;
|
||||
|
||||
ALTER TABLE recordings
|
||||
RENAME COLUMN total_depletion TO total_depletion_qty;
|
||||
|
||||
ALTER TABLE recordings
|
||||
RENAME COLUMN total_chick TO total_chick_qty;
|
||||
|
||||
ALTER TABLE recordings
|
||||
ALTER COLUMN total_depletion_qty TYPE NUMERIC(15,3) USING COALESCE(total_depletion_qty, 0)::NUMERIC(15,3),
|
||||
ALTER COLUMN total_chick_qty TYPE NUMERIC(15,3) USING COALESCE(total_chick_qty, 0)::NUMERIC(15,3),
|
||||
ALTER COLUMN cum_intake TYPE INT USING COALESCE(cum_intake, 0)::INT;
|
||||
|
||||
ALTER TABLE recordings
|
||||
ADD CONSTRAINT fk_recordings_project_flock_kandang
|
||||
FOREIGN KEY (project_flock_kandangs_id) REFERENCES project_flock_kandangs(id);
|
||||
|
||||
ALTER TABLE recordings
|
||||
ADD CONSTRAINT chk_recordings_nonnegatives_v2 CHECK (
|
||||
(total_depletion_qty IS NULL OR total_depletion_qty >= 0) AND
|
||||
(cum_depletion_rate IS NULL OR cum_depletion_rate >= 0) AND
|
||||
(daily_gain IS NULL OR daily_gain >= 0) AND
|
||||
(avg_daily_gain IS NULL OR avg_daily_gain >= 0) AND
|
||||
(cum_intake IS NULL OR cum_intake >= 0) AND
|
||||
(fcr_value IS NULL OR fcr_value >= 0) AND
|
||||
(total_chick_qty IS NULL OR total_chick_qty >= 0)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_recordings_flock_datetime
|
||||
ON recordings (project_flock_kandangs_id, record_datetime);
|
||||
|
||||
-- recording_bws reshape
|
||||
ALTER TABLE recording_bws
|
||||
RENAME COLUMN weight TO avg_weight;
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
ALTER COLUMN avg_weight TYPE NUMERIC(8,2) USING COALESCE(avg_weight, 0)::NUMERIC(8,2);
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
ADD COLUMN total_weight NUMERIC(10,3);
|
||||
|
||||
UPDATE recording_bws
|
||||
SET total_weight = COALESCE(avg_weight, 0) * COALESCE(qty, 0);
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
ALTER COLUMN total_weight SET NOT NULL;
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
ALTER COLUMN qty TYPE NUMERIC(15,3) USING COALESCE(qty, 0)::NUMERIC(15,3);
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
DROP COLUMN IF EXISTS notes;
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
DROP CONSTRAINT IF EXISTS chk_recording_bws_nonneg;
|
||||
|
||||
ALTER TABLE recording_bws
|
||||
ADD CONSTRAINT chk_recording_bws_nonneg CHECK (
|
||||
avg_weight >= 0 AND qty >= 0 AND total_weight >= 0
|
||||
);
|
||||
|
||||
-- recording_depletions reshape
|
||||
ALTER TABLE recording_depletions
|
||||
RENAME COLUMN total TO qty;
|
||||
|
||||
ALTER TABLE recording_depletions
|
||||
ALTER COLUMN qty TYPE NUMERIC(15,3) USING COALESCE(qty, 0)::NUMERIC(15,3);
|
||||
|
||||
ALTER TABLE recording_depletions
|
||||
DROP COLUMN IF EXISTS notes;
|
||||
|
||||
ALTER TABLE recording_depletions
|
||||
DROP CONSTRAINT IF EXISTS chk_recording_depl_total;
|
||||
|
||||
ALTER TABLE recording_depletions
|
||||
ADD CONSTRAINT chk_recording_depl_qty CHECK (qty >= 0);
|
||||
|
||||
-- recording_stocks reshape
|
||||
ALTER TABLE recording_stocks
|
||||
DROP CONSTRAINT IF EXISTS chk_recording_stocks_nonneg;
|
||||
|
||||
ALTER TABLE recording_stocks
|
||||
DROP COLUMN IF EXISTS increase,
|
||||
DROP COLUMN IF EXISTS decrease,
|
||||
DROP COLUMN IF EXISTS usage_amount,
|
||||
DROP COLUMN IF EXISTS notes;
|
||||
|
||||
ALTER TABLE recording_stocks
|
||||
ADD COLUMN usage_qty NUMERIC(15,3),
|
||||
ADD COLUMN pending_qty NUMERIC(15,3);
|
||||
|
||||
ALTER TABLE recording_stocks
|
||||
ADD CONSTRAINT chk_recording_stocks_nonneg CHECK (
|
||||
(usage_qty IS NULL OR usage_qty >= 0) AND
|
||||
(pending_qty IS NULL OR pending_qty >= 0)
|
||||
);
|
||||
|
||||
-- recording_eggs table
|
||||
CREATE TABLE recording_eggs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
recording_id BIGINT NOT NULL,
|
||||
product_warehouse_id BIGINT NOT NULL,
|
||||
qty INT NOT NULL,
|
||||
created_by BIGINT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT fk_recording_eggs_recording
|
||||
FOREIGN KEY (recording_id) REFERENCES recordings(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_recording_eggs_product_warehouse
|
||||
FOREIGN KEY (product_warehouse_id) REFERENCES product_warehouses(id),
|
||||
CONSTRAINT fk_recording_eggs_created_by
|
||||
FOREIGN KEY (created_by) REFERENCES users(id),
|
||||
CONSTRAINT chk_recording_eggs_qty CHECK (qty >= 0)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_recording_eggs_recording
|
||||
ON recording_eggs (recording_id);
|
||||
|
||||
CREATE INDEX idx_recording_eggs_product
|
||||
ON recording_eggs (product_warehouse_id);
|
||||
|
||||
-- grading_eggs table
|
||||
CREATE TABLE grading_eggs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
recording_egg_id BIGINT NOT NULL,
|
||||
qty NUMERIC(15,3) NOT NULL,
|
||||
grade VARCHAR,
|
||||
created_by BIGINT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT fk_grading_eggs_recording_egg
|
||||
FOREIGN KEY (recording_egg_id) REFERENCES recording_eggs(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_grading_eggs_created_by
|
||||
FOREIGN KEY (created_by) REFERENCES users(id),
|
||||
CONSTRAINT chk_grading_eggs_qty CHECK (qty >= 0)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_grading_eggs_recording_egg
|
||||
ON grading_eggs (recording_egg_id);
|
||||
|
||||
COMMIT;
|
||||
@@ -1,5 +0,0 @@
|
||||
DROP TABLE IF EXISTS project_chickin_details;
|
||||
|
||||
DROP TABLE IF EXISTS project_chickins;
|
||||
|
||||
DROP TABLE IF EXISTS project_flock_populations;
|
||||
+105
-415
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -41,22 +40,15 @@ func Run(db *gorm.DB) error {
|
||||
return err
|
||||
}
|
||||
|
||||
flocks, err := seedFlocks(tx, adminID)
|
||||
if err != nil {
|
||||
if _, err := seedFlocks(tx, adminID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fcrs, err := seedFcr(tx, adminID)
|
||||
if err != nil {
|
||||
if _, err := seedFcr(tx, adminID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projectFlocks, err := seedProjectFlocks(tx, adminID, flocks, areas, fcrs, locations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kandangs, err := seedKandangs(tx, adminID, locations, users, projectFlocks)
|
||||
kandangs, err := seedKandangs(tx, adminID, locations, users)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -93,10 +85,6 @@ func Run(db *gorm.DB) error {
|
||||
if err := seedTransferStock(tx, adminID); err != nil {
|
||||
return err
|
||||
}
|
||||
// if err := seedChickin(tx, adminID); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
fmt.Println("✅ Master data seeding completed")
|
||||
return nil
|
||||
})
|
||||
@@ -243,159 +231,16 @@ func seedFlocks(tx *gorm.DB, createdBy uint) (map[string]uint, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func seedProjectFlocks(tx *gorm.DB, createdBy uint, flocks, areas, fcrs, locations map[string]uint) (map[string]uint, error) {
|
||||
func seedKandangs(tx *gorm.DB, createdBy uint, locations map[string]uint, users map[string]uint) (map[string]uint, error) {
|
||||
seeds := []struct {
|
||||
Key string
|
||||
Flock string
|
||||
Area string
|
||||
Category utils.ProjectFlockCategory
|
||||
Fcr string
|
||||
Name string
|
||||
Status utils.KandangStatus
|
||||
Location string
|
||||
Period int
|
||||
PicKey string
|
||||
}{
|
||||
{
|
||||
Key: "Singaparna Period 1",
|
||||
Flock: "Flock Priangan",
|
||||
Area: "Priangan",
|
||||
Category: utils.ProjectFlockCategoryGrowing,
|
||||
Fcr: "FCR DOC",
|
||||
Location: "Singaparna",
|
||||
Period: 1,
|
||||
},
|
||||
{
|
||||
Key: "Cikaum Period 1",
|
||||
Flock: "Flock Banten",
|
||||
Area: "Banten",
|
||||
Category: utils.ProjectFlockCategoryGrowing,
|
||||
Fcr: "FCR DOC",
|
||||
Location: "Cikaum",
|
||||
Period: 1,
|
||||
},
|
||||
}
|
||||
|
||||
result := make(map[string]uint, len(seeds))
|
||||
|
||||
for _, seed := range seeds {
|
||||
flockID, ok := flocks[seed.Flock]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("floc %s not seeded", seed.Flock)
|
||||
}
|
||||
areaID, ok := areas[seed.Area]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("area %s not seeded", seed.Area)
|
||||
}
|
||||
fcrID, ok := fcrs[seed.Fcr]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("fcr %s not seeded", seed.Fcr)
|
||||
}
|
||||
locationID, ok := locations[seed.Location]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("location %s not seeded", seed.Location)
|
||||
}
|
||||
|
||||
var projectFlock entity.ProjectFlock
|
||||
err := tx.Where("flock_id = ? AND area_id = ? AND category = ? AND fcr_id = ? AND location_id = ? AND period = ?",
|
||||
flockID, areaID, seed.Category, fcrID, locationID, seed.Period).First(&projectFlock).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
projectFlock = entity.ProjectFlock{
|
||||
FlockId: flockID,
|
||||
AreaId: areaID,
|
||||
Category: string(seed.Category),
|
||||
FcrId: fcrID,
|
||||
LocationId: locationID,
|
||||
Period: seed.Period,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
if err := tx.Create(&projectFlock).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if err := tx.Model(&entity.ProjectFlock{}).Where("id = ?", projectFlock.Id).Updates(map[string]any{
|
||||
"flock_id": flockID,
|
||||
"area_id": areaID,
|
||||
"category": string(seed.Category),
|
||||
"fcr_id": fcrID,
|
||||
"location_id": locationID,
|
||||
"period": seed.Period,
|
||||
}).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := ensureProjectFlockApprovals(tx, projectFlock.Id, createdBy); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[seed.Key] = projectFlock.Id
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func ensureProjectFlockApprovals(tx *gorm.DB, projectFlockID uint, actorID uint) error {
|
||||
if projectFlockID == 0 || actorID == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
workflow := utils.ApprovalWorkflowProjectFlock.String()
|
||||
|
||||
steps := []struct {
|
||||
step approvalutils.ApprovalStep
|
||||
action entity.ApprovalAction
|
||||
}{
|
||||
{step: utils.ProjectFlockStepPengajuan, action: entity.ApprovalActionCreated},
|
||||
{step: utils.ProjectFlockStepAktif, action: entity.ApprovalActionApproved},
|
||||
}
|
||||
|
||||
for _, cfg := range steps {
|
||||
var count int64
|
||||
if err := tx.Model(&entity.Approval{}).
|
||||
Where("approvable_type = ? AND approvable_id = ? AND step_number = ?", workflow, projectFlockID, uint16(cfg.step)).
|
||||
Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
stepName, ok := utils.ProjectFlockApprovalSteps[cfg.step]
|
||||
if !ok || strings.TrimSpace(stepName) == "" {
|
||||
stepName = fmt.Sprintf("Step %d", cfg.step)
|
||||
}
|
||||
|
||||
var actionPtr *entity.ApprovalAction
|
||||
action := cfg.action
|
||||
actionPtr = &action
|
||||
|
||||
record := entity.Approval{
|
||||
ApprovableType: workflow,
|
||||
ApprovableId: projectFlockID,
|
||||
StepNumber: uint16(cfg.step),
|
||||
StepName: stepName,
|
||||
Action: actionPtr,
|
||||
ActionBy: uintPtr(actorID),
|
||||
}
|
||||
|
||||
if err := tx.Create(&record).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func seedKandangs(tx *gorm.DB, createdBy uint, locations map[string]uint, users map[string]uint, projectFlocks map[string]uint) (map[string]uint, error) {
|
||||
seeds := []struct {
|
||||
Name string
|
||||
Status utils.KandangStatus
|
||||
Location string
|
||||
PicKey string
|
||||
ProjectFlockKey *string
|
||||
}{
|
||||
{Name: "Singaparna 1", Status: utils.KandangStatusActive, Location: "Singaparna", PicKey: "admin", ProjectFlockKey: strPtr("Singaparna Period 1")},
|
||||
{Name: "Singaparna 1", Status: utils.KandangStatusNonActive, Location: "Singaparna", PicKey: "admin"},
|
||||
{Name: "Singaparna 2", Status: utils.KandangStatusNonActive, Location: "Singaparna", PicKey: "admin"},
|
||||
{Name: "Cikaum 1", Status: utils.KandangStatusActive, Location: "Cikaum", PicKey: "admin", ProjectFlockKey: strPtr("Cikaum Period 1")},
|
||||
{Name: "Cikaum 1", Status: utils.KandangStatusNonActive, Location: "Cikaum", PicKey: "admin"},
|
||||
{Name: "Cikaum 2", Status: utils.KandangStatusNonActive, Location: "Cikaum", PicKey: "admin"},
|
||||
}
|
||||
|
||||
@@ -411,32 +256,19 @@ func seedKandangs(tx *gorm.DB, createdBy uint, locations map[string]uint, users
|
||||
return nil, fmt.Errorf("user %s not seeded", seed.PicKey)
|
||||
}
|
||||
|
||||
var projectFlockID *uint
|
||||
if seed.ProjectFlockKey != nil {
|
||||
pfID, ok := projectFlocks[*seed.ProjectFlockKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("project flock %s not seeded", *seed.ProjectFlockKey)
|
||||
}
|
||||
projectFlockID = uintPtr(pfID)
|
||||
}
|
||||
|
||||
var kandang entity.Kandang
|
||||
err := tx.Where("name = ?", seed.Name).First(&kandang).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
kandang = entity.Kandang{
|
||||
Name: seed.Name,
|
||||
Status: string(seed.Status),
|
||||
LocationId: locID,
|
||||
PicId: picID,
|
||||
ProjectFlockId: projectFlockID,
|
||||
CreatedBy: createdBy,
|
||||
Name: seed.Name,
|
||||
Status: string(seed.Status),
|
||||
LocationId: locID,
|
||||
PicId: picID,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
if err := tx.Create(&kandang).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := syncPivotRelation(tx, projectFlockID, kandang.Id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
@@ -445,17 +277,9 @@ func seedKandangs(tx *gorm.DB, createdBy uint, locations map[string]uint, users
|
||||
"pic_id": picID,
|
||||
"status": string(seed.Status),
|
||||
}
|
||||
if projectFlockID != nil {
|
||||
updates["project_flock_id"] = *projectFlockID
|
||||
} else {
|
||||
updates["project_flock_id"] = nil
|
||||
}
|
||||
if err := tx.Model(&entity.Kandang{}).Where("id = ?", kandang.Id).Updates(updates).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := syncPivotRelation(tx, projectFlockID, kandang.Id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
result[seed.Name] = kandang.Id
|
||||
}
|
||||
@@ -463,38 +287,6 @@ func seedKandangs(tx *gorm.DB, createdBy uint, locations map[string]uint, users
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func syncPivotRelation(tx *gorm.DB, projectFlockID *uint, kandangID uint) error {
|
||||
if err := detachActivePivot(tx, kandangID); err != nil {
|
||||
return err
|
||||
}
|
||||
if projectFlockID == nil {
|
||||
return nil
|
||||
}
|
||||
return ensureActivePivot(tx, *projectFlockID, kandangID)
|
||||
}
|
||||
|
||||
func detachActivePivot(tx *gorm.DB, kandangID uint) error {
|
||||
return tx.Where("kandang_id = ?", kandangID).
|
||||
Delete(&entity.ProjectFlockKandang{}).Error
|
||||
}
|
||||
|
||||
func ensureActivePivot(tx *gorm.DB, projectFlockID, kandangID uint) error {
|
||||
var pivot entity.ProjectFlockKandang
|
||||
err := tx.Where("project_flock_id = ? AND kandang_id = ?", projectFlockID, kandangID).
|
||||
First(&pivot).Error
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
newRecord := entity.ProjectFlockKandang{
|
||||
ProjectFlockId: projectFlockID,
|
||||
KandangId: kandangID,
|
||||
}
|
||||
return tx.Create(&newRecord).Error
|
||||
}
|
||||
|
||||
func seedWarehouses(tx *gorm.DB, createdBy uint, areas map[string]uint, locations map[string]uint, kandangs map[string]uint) error {
|
||||
seeds := []struct {
|
||||
Name string
|
||||
@@ -571,9 +363,10 @@ func seedProductCategories(tx *gorm.DB, createdBy uint) (map[string]uint, error)
|
||||
Name string
|
||||
Code string
|
||||
}{
|
||||
{"Pullet", "PLT"},
|
||||
{"Bahan Baku", "RAW"},
|
||||
{"Day Old Chick", "DOC"},
|
||||
{"Pullet", "PULLET"},
|
||||
{"Telur", "EGG"},
|
||||
}
|
||||
|
||||
result := make(map[string]uint, len(seeds))
|
||||
@@ -697,25 +490,14 @@ func seedFcr(tx *gorm.DB, createdBy uint) (map[string]uint, error) {
|
||||
}
|
||||
}{
|
||||
{
|
||||
Name: "FCR DOC",
|
||||
Name: "FCR Layer",
|
||||
Standards: []struct {
|
||||
Weight float64
|
||||
FcrNumber float64
|
||||
Mortality float64
|
||||
}{
|
||||
{Weight: 0.1, FcrNumber: 1.20, Mortality: 1.0},
|
||||
{Weight: 0.3, FcrNumber: 1.35, Mortality: 1.5},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "FCR Pullet",
|
||||
Standards: []struct {
|
||||
Weight float64
|
||||
FcrNumber float64
|
||||
Mortality float64
|
||||
}{
|
||||
{Weight: 0.5, FcrNumber: 1.45, Mortality: 2.0},
|
||||
{Weight: 0.8, FcrNumber: 1.50, Mortality: 2.5},
|
||||
{Weight: 0.8, FcrNumber: 1.60, Mortality: 2.0},
|
||||
{Weight: 1.5, FcrNumber: 1.75, Mortality: 3.5},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -788,6 +570,56 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
|
||||
Suppliers: []string{"PT CHAROEN POKPHAND INDONESIA Tbk"},
|
||||
Flags: []utils.FlagType{utils.FlagDOC},
|
||||
},
|
||||
{
|
||||
Name: "Ayam Pullet",
|
||||
Brand: "MBU Pullet",
|
||||
Sku: "PLT0001",
|
||||
Uom: "Ekor",
|
||||
Category: "Pullet",
|
||||
Price: 15000,
|
||||
Suppliers: []string{"PT CHAROEN POKPHAND INDONESIA Tbk"},
|
||||
Flags: []utils.FlagType{utils.FlagPullet},
|
||||
},
|
||||
{
|
||||
Name: "Ayam Afkir",
|
||||
Brand: "-",
|
||||
Sku: "1",
|
||||
Uom: "Ekor",
|
||||
Category: "Day Old Chick",
|
||||
Price: 1,
|
||||
},
|
||||
{
|
||||
Name: "Ayam Mati",
|
||||
Brand: "-",
|
||||
Sku: "2",
|
||||
Uom: "Ekor",
|
||||
Category: "Day Old Chick",
|
||||
Price: 1,
|
||||
},
|
||||
{
|
||||
Name: "Ayam Culling",
|
||||
Brand: "-",
|
||||
Sku: "3",
|
||||
Uom: "Ekor",
|
||||
Category: "Day Old Chick",
|
||||
Price: 1,
|
||||
},
|
||||
{
|
||||
Name: "Telur Konsumsi Baik",
|
||||
Brand: "-",
|
||||
Sku: "4",
|
||||
Uom: "Unit",
|
||||
Category: "Telur",
|
||||
Price: 1,
|
||||
},
|
||||
{
|
||||
Name: "Telur Pecah",
|
||||
Brand: "-",
|
||||
Sku: "5",
|
||||
Uom: "Unit",
|
||||
Category: "Telur",
|
||||
Price: 1,
|
||||
},
|
||||
{
|
||||
Name: "281 SPECIAL STARTER",
|
||||
Brand: "281 STARTER",
|
||||
@@ -799,26 +631,6 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
|
||||
Suppliers: []string{"PT CHAROEN POKPHAND INDONESIA Tbk"},
|
||||
Flags: []utils.FlagType{utils.FlagPakan, utils.FlagStarter},
|
||||
},
|
||||
{
|
||||
Name: "DOC MAlindo",
|
||||
Brand: "MAlindo",
|
||||
Sku: "MAL0001",
|
||||
Uom: "Ekor",
|
||||
Category: "Day Old Chick",
|
||||
Price: 8000,
|
||||
Suppliers: []string{"PT CHAROEN POKPHAND INDONESIA Tbk"},
|
||||
Flags: []utils.FlagType{utils.FlagDOC},
|
||||
},
|
||||
{
|
||||
Name: "Ayam Pullet",
|
||||
Brand: "MBU Pullet",
|
||||
Sku: "PUL0001",
|
||||
Uom: "Ekor",
|
||||
Category: "Pullet",
|
||||
Price: 15000,
|
||||
Suppliers: []string{"PT CHAROEN POKPHAND INDONESIA Tbk"},
|
||||
Flags: []utils.FlagType{utils.FlagPullet},
|
||||
},
|
||||
}
|
||||
|
||||
for _, seed := range seeds {
|
||||
@@ -1058,25 +870,44 @@ func seedBanks(tx *gorm.DB, createdBy uint) error {
|
||||
}
|
||||
|
||||
func seedProductWarehouse(tx *gorm.DB, createdBy uint) error {
|
||||
|
||||
seeds := []struct {
|
||||
ProductID uint
|
||||
WarehouseID uint
|
||||
Quantity float64
|
||||
ProductName string
|
||||
WarehouseName string
|
||||
Quantity float64
|
||||
}{
|
||||
{ProductID: 1, WarehouseID: 1, Quantity: 100},
|
||||
{ProductID: 2, WarehouseID: 2, Quantity: 200},
|
||||
{ProductID: 2, WarehouseID: 1, Quantity: 300},
|
||||
{ProductID: 1, WarehouseID: 3, Quantity: 5000},
|
||||
{ProductName: "DOC Broiler", WarehouseName: "Gudang Priangan", Quantity: 100},
|
||||
{ProductName: "281 SPECIAL STARTER", WarehouseName: "Gudang Singaparna", Quantity: 200},
|
||||
{ProductName: "281 SPECIAL STARTER", WarehouseName: "Gudang Banten", Quantity: 300},
|
||||
{ProductName: "DOC Broiler", WarehouseName: "Gudang Singaparna 1", Quantity: 5000},
|
||||
{ProductName: "Telur Konsumsi Baik", WarehouseName: "Gudang Singaparna 1", Quantity: 600},
|
||||
{ProductName: "Telur Pecah", WarehouseName: "Gudang Singaparna 1", Quantity: 80},
|
||||
{ProductName: "Telur Konsumsi Baik", WarehouseName: "Gudang Cikaum 1", Quantity: 450},
|
||||
{ProductName: "Telur Pecah", WarehouseName: "Gudang Cikaum 1", Quantity: 60},
|
||||
}
|
||||
|
||||
for _, seed := range seeds {
|
||||
var product entity.Product
|
||||
if err := tx.Where("name = ?", seed.ProductName).First(&product).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("product %q not found for product warehouse seeding", seed.ProductName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var warehouse entity.Warehouse
|
||||
if err := tx.Where("name = ?", seed.WarehouseName).First(&warehouse).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("warehouse %q not found for product warehouse seeding", seed.WarehouseName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var productWarehouse entity.ProductWarehouse
|
||||
err := tx.Where("product_id = ? AND warehouse_id = ?", seed.ProductID, seed.WarehouseID).First(&productWarehouse).Error
|
||||
err := tx.Where("product_id = ? AND warehouse_id = ?", product.Id, warehouse.Id).First(&productWarehouse).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
productWarehouse = entity.ProductWarehouse{
|
||||
ProductId: seed.ProductID,
|
||||
WarehouseId: seed.WarehouseID,
|
||||
ProductId: product.Id,
|
||||
WarehouseId: warehouse.Id,
|
||||
Quantity: seed.Quantity,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
@@ -1085,6 +916,12 @@ func seedProductWarehouse(tx *gorm.DB, createdBy uint) error {
|
||||
}
|
||||
} else if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := tx.Model(&productWarehouse).Updates(map[string]any{
|
||||
"quantity": seed.Quantity,
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,153 +1002,6 @@ func seedTransferStock(tx *gorm.DB, createdBy uint) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// func seedChickin(tx *gorm.DB, createdBy uint) error {
|
||||
// seeds := []struct {
|
||||
// ProjectFlockKandangId uint
|
||||
// ChickInDate string
|
||||
// Quantity float64
|
||||
// Note string
|
||||
// }{
|
||||
// {ProjectFlockKandangId: 1, ChickInDate: "2025-10-20", Quantity: 100, Note: "Seeder chickin 1"},
|
||||
// {ProjectFlockKandangId: 2, ChickInDate: "2025-10-21", Quantity: 200, Note: "Seeder chickin 2"},
|
||||
// }
|
||||
|
||||
// for _, seed := range seeds {
|
||||
// chickinDate, err := time.Parse("2006-01-02", seed.ChickInDate)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// // Insert ProjectChickin jika belum ada
|
||||
// var chickin entity.ProjectChickin
|
||||
// err = tx.Where("project_flock_kandang_id = ? AND chick_in_date = ?", seed.ProjectFlockKandangId, chickinDate).
|
||||
// First(&chickin).Error
|
||||
// if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// chickin = entity.ProjectChickin{
|
||||
// ProjectFlockKandangId: seed.ProjectFlockKandangId,
|
||||
// ChickInDate: chickinDate,
|
||||
// Quantity: seed.Quantity,
|
||||
// Note: seed.Note,
|
||||
// CreatedBy: createdBy,
|
||||
// }
|
||||
// if err := tx.Create(&chickin).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// } else if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// var population entity.ProjectFlockPopulation
|
||||
// err = tx.Where("project_flock_kandang_id = ?", seed.ProjectFlockKandangId).First(&population).Error
|
||||
// if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// population = entity.ProjectFlockPopulation{
|
||||
// ProjectFlockKandangId: seed.ProjectFlockKandangId,
|
||||
// InitialQuantity: seed.Quantity,
|
||||
// CurrentQuantity: seed.Quantity,
|
||||
// ReservedQuantity: 0,
|
||||
// CreatedBy: createdBy,
|
||||
// }
|
||||
// if err := tx.Create(&population).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// } else if err != nil {
|
||||
// return err
|
||||
// } else {
|
||||
// // Update population quantities
|
||||
// if err := tx.Model(&entity.ProjectFlockPopulation{}).
|
||||
// Where("id = ?", population.Id).
|
||||
// Updates(map[string]any{
|
||||
// "initial_quantity": population.InitialQuantity + seed.Quantity,
|
||||
// "current_quantity": population.CurrentQuantity + seed.Quantity,
|
||||
// "reserved_quantity": 0,
|
||||
// }).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
|
||||
// var pfk entity.ProjectFlockKandang
|
||||
// if err := tx.Where("id = ?", seed.ProjectFlockKandangId).First(&pfk).Error; err != nil {
|
||||
// if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// // no pivot found; skip creating details
|
||||
// continue
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
|
||||
// var warehouse entity.Warehouse
|
||||
// if err := tx.Where("kandang_id = ?", pfk.KandangId).First(&warehouse).Error; err != nil {
|
||||
// // if warehouse not found, cannot create details
|
||||
// if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// continue
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
|
||||
// var productWarehouses []entity.ProductWarehouse
|
||||
// err = tx.Table("product_warehouses").
|
||||
// Select("product_warehouses.*").
|
||||
// Joins("JOIN products ON products.id = product_warehouses.product_id").
|
||||
// Joins("JOIN product_categories ON product_categories.id = products.product_category_id").
|
||||
// Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", "DOC", warehouse.Id).
|
||||
// Order("product_warehouses.created_at DESC").
|
||||
// Find(&productWarehouses).Error
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// // If no product warehouses found, keep existing chickin.Quantity and skip details
|
||||
// if len(productWarehouses) == 0 {
|
||||
// continue
|
||||
// }
|
||||
|
||||
// // sum all pw quantities and set chickin.Quantity to that total (mimic CreateOne)
|
||||
// totalQty := 0.0
|
||||
// for _, pw := range productWarehouses {
|
||||
// totalQty += pw.Quantity
|
||||
// }
|
||||
|
||||
// if chickin.Quantity != totalQty {
|
||||
// if err := tx.Model(&entity.ProjectChickin{}).Where("id = ?", chickin.Id).Update("quantity", totalQty).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// chickin.Quantity = totalQty
|
||||
// }
|
||||
|
||||
// for _, pw := range productWarehouses {
|
||||
// // ensure detail exists or create it with full pw.Quantity
|
||||
// var detail entity.ProjectChickinDetail
|
||||
// err = tx.Where("project_chickin_id = ? AND product_warehouse_id = ?", chickin.Id, pw.Id).First(&detail).Error
|
||||
// if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// detail = entity.ProjectChickinDetail{
|
||||
// ProjectChickinId: chickin.Id,
|
||||
// ProductWarehouseId: pw.Id,
|
||||
// Quantity: pw.Quantity,
|
||||
// CreatedBy: createdBy,
|
||||
// }
|
||||
// if err := tx.Create(&detail).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// } else if err != nil {
|
||||
// return err
|
||||
// } else {
|
||||
// if detail.Quantity != pw.Quantity {
|
||||
// if err := tx.Model(&entity.ProjectChickinDetail{}).Where("id = ?", detail.Id).Update("quantity", pw.Quantity).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // zero out pw quantity
|
||||
// if err := tx.Model(&entity.ProductWarehouse{}).Where("id = ?", pw.Id).Update("quantity", 0).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func ptr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user