-- erp_full_20260505.sql — FULL ERP (SAP-Lite) za PGŽ Sport
-- Author: Damir Radulić (dradulic@outlook.com / damir@rinet.one)
-- Date:   2026-05-05
-- Description: 9 tablica + 5 viewova + seed HR-RRIF kontnog plana

SET search_path TO pgz_sport, public;

-- ======================================================================
-- 1) KONTNI PLAN (HR-RRIF)
-- ======================================================================
CREATE TABLE IF NOT EXISTS pgz_sport.kontni_plan (
    id          SERIAL PRIMARY KEY,
    sifra       TEXT UNIQUE NOT NULL,
    naziv       TEXT NOT NULL,
    klasa       SMALLINT NOT NULL CHECK (klasa BETWEEN 0 AND 9),
    vrsta       TEXT NOT NULL CHECK (vrsta IN ('aktiva','pasiva','prihod','rashod','izvanbilanca','kapital')),
    parent_id   INTEGER REFERENCES pgz_sport.kontni_plan(id),
    aktivan     BOOLEAN DEFAULT true,
    napomena    TEXT,
    created_at  TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_kontni_plan_klasa ON pgz_sport.kontni_plan(klasa);

-- ======================================================================
-- 2) PARTNERI (kupci/dobavljači)
-- ======================================================================
CREATE TABLE IF NOT EXISTS pgz_sport.partneri (
    id          SERIAL PRIMARY KEY,
    oib         CHAR(11) UNIQUE,
    naziv       TEXT NOT NULL,
    vrsta       TEXT NOT NULL CHECK (vrsta IN ('kupac','dobavljac','oba')),
    iban        TEXT,
    adresa      TEXT,
    grad        TEXT,
    drzava      TEXT DEFAULT 'HR',
    email       TEXT,
    telefon     TEXT,
    aktivan     BOOLEAN DEFAULT true,
    napomena    TEXT,
    created_at  TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_partneri_naziv ON pgz_sport.partneri(naziv);

-- ======================================================================
-- 3) DNEVNIK + KNJIŽENJA (double-entry)
-- ======================================================================
CREATE TABLE IF NOT EXISTS pgz_sport.dnevnik_zapisa (
    id           SERIAL PRIMARY KEY,
    datum        DATE NOT NULL,
    opis         TEXT,
    dokument_tip TEXT,           -- 'racun_u'|'racun_i'|'placa'|'rucno'|'storno'
    dokument_id  INTEGER,
    redni_broj   INTEGER,        -- u godini
    godina       INTEGER GENERATED ALWAYS AS (EXTRACT(YEAR FROM datum)::int) STORED,
    storno_od_id INTEGER REFERENCES pgz_sport.dnevnik_zapisa(id),
    created_by   INTEGER,
    created_at   TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_dnev_datum ON pgz_sport.dnevnik_zapisa(datum);
CREATE INDEX IF NOT EXISTS ix_dnev_dokument ON pgz_sport.dnevnik_zapisa(dokument_tip, dokument_id);

CREATE TABLE IF NOT EXISTS pgz_sport.knjizenja (
    id           SERIAL PRIMARY KEY,
    dnevnik_id   INTEGER NOT NULL REFERENCES pgz_sport.dnevnik_zapisa(id) ON DELETE CASCADE,
    konto_id     INTEGER NOT NULL REFERENCES pgz_sport.kontni_plan(id),
    partner_id   INTEGER REFERENCES pgz_sport.partneri(id),
    duguje       NUMERIC(14,2) DEFAULT 0 CHECK (duguje >= 0),
    potrazuje    NUMERIC(14,2) DEFAULT 0 CHECK (potrazuje >= 0),
    opis         TEXT,
    CHECK (duguje = 0 OR potrazuje = 0),
    CHECK (duguje > 0 OR potrazuje > 0)
);
CREATE INDEX IF NOT EXISTS ix_knj_dnevnik ON pgz_sport.knjizenja(dnevnik_id);
CREATE INDEX IF NOT EXISTS ix_knj_konto ON pgz_sport.knjizenja(konto_id);
CREATE INDEX IF NOT EXISTS ix_knj_partner ON pgz_sport.knjizenja(partner_id);

-- ======================================================================
-- 4) RAČUNI (ulazni/izlazni) + STAVKE
-- ======================================================================
CREATE TABLE IF NOT EXISTS pgz_sport.racuni_ulazni (
    id              SERIAL PRIMARY KEY,
    broj            TEXT,
    partner_id      INTEGER REFERENCES pgz_sport.partneri(id),
    klub_id         INTEGER REFERENCES pgz_sport.klubovi(id),
    datum_izdavanja DATE NOT NULL,
    datum_dospjeca  DATE,
    datum_primitka  DATE DEFAULT CURRENT_DATE,
    valuta          TEXT DEFAULT 'EUR',
    iznos_neto      NUMERIC(14,2) DEFAULT 0,
    iznos_pdv       NUMERIC(14,2) DEFAULT 0,
    iznos_brutto    NUMERIC(14,2) DEFAULT 0,
    status          TEXT DEFAULT 'nacrt' CHECK (status IN ('nacrt','knjizen','placen','otkazan')),
    napomena        TEXT,
    eracun_xml      TEXT,
    dnevnik_id      INTEGER REFERENCES pgz_sport.dnevnik_zapisa(id),
    created_at      TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_racu_status ON pgz_sport.racuni_ulazni(status);
CREATE INDEX IF NOT EXISTS ix_racu_partner ON pgz_sport.racuni_ulazni(partner_id);
CREATE INDEX IF NOT EXISTS ix_racu_datum ON pgz_sport.racuni_ulazni(datum_izdavanja);

CREATE TABLE IF NOT EXISTS pgz_sport.racuni_izlazni (
    id              SERIAL PRIMARY KEY,
    broj            TEXT,
    partner_id      INTEGER REFERENCES pgz_sport.partneri(id),
    klub_id         INTEGER REFERENCES pgz_sport.klubovi(id),
    datum_izdavanja DATE NOT NULL,
    datum_dospjeca  DATE,
    valuta          TEXT DEFAULT 'EUR',
    iznos_neto      NUMERIC(14,2) DEFAULT 0,
    iznos_pdv       NUMERIC(14,2) DEFAULT 0,
    iznos_brutto    NUMERIC(14,2) DEFAULT 0,
    status          TEXT DEFAULT 'nacrt' CHECK (status IN ('nacrt','knjizen','placen','otkazan')),
    napomena        TEXT,
    dnevnik_id      INTEGER REFERENCES pgz_sport.dnevnik_zapisa(id),
    created_at      TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_raci_status ON pgz_sport.racuni_izlazni(status);
CREATE INDEX IF NOT EXISTS ix_raci_partner ON pgz_sport.racuni_izlazni(partner_id);
CREATE INDEX IF NOT EXISTS ix_raci_datum ON pgz_sport.racuni_izlazni(datum_izdavanja);

CREATE TABLE IF NOT EXISTS pgz_sport.racun_stavke (
    id           SERIAL PRIMARY KEY,
    racun_tip    TEXT NOT NULL CHECK (racun_tip IN ('ulazni','izlazni')),
    racun_id     INTEGER NOT NULL,
    naziv        TEXT NOT NULL,
    kolicina     NUMERIC(12,3) DEFAULT 1,
    jed_mjera    TEXT DEFAULT 'kom',
    cijena_jed   NUMERIC(14,4) DEFAULT 0,
    popust_pct   NUMERIC(5,2) DEFAULT 0,
    pdv_pct      NUMERIC(5,2) DEFAULT 25,
    iznos_neto   NUMERIC(14,2) DEFAULT 0,
    iznos_pdv    NUMERIC(14,2) DEFAULT 0,
    iznos_brutto NUMERIC(14,2) DEFAULT 0
);
CREATE INDEX IF NOT EXISTS ix_stavke_racun ON pgz_sport.racun_stavke(racun_tip, racun_id);

-- ======================================================================
-- 5) ZAPOSLENICI + PLAĆE
-- ======================================================================
CREATE TABLE IF NOT EXISTS pgz_sport.zaposlenici (
    id            SERIAL PRIMARY KEY,
    oib           CHAR(11) UNIQUE,
    ime           TEXT NOT NULL,
    prezime       TEXT NOT NULL,
    klub_id       INTEGER REFERENCES pgz_sport.klubovi(id),
    radno_mjesto  TEXT,
    plata_bruto   NUMERIC(12,2) DEFAULT 0,
    iban          TEXT,
    datum_pocetka DATE,
    datum_kraja   DATE,
    aktivan       BOOLEAN DEFAULT true,
    created_at    TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE IF NOT EXISTS pgz_sport.place_obracun (
    id                  SERIAL PRIMARY KEY,
    zaposlenik_id       INTEGER NOT NULL REFERENCES pgz_sport.zaposlenici(id),
    godina              INTEGER NOT NULL,
    mjesec              SMALLINT NOT NULL CHECK (mjesec BETWEEN 1 AND 12),
    bruto               NUMERIC(12,2) NOT NULL,
    osobni_odbitak      NUMERIC(12,2) DEFAULT 600,
    doprinosi_iz_plate  NUMERIC(12,2) DEFAULT 0,   -- 20% MIO
    porezna_osnovica    NUMERIC(12,2) DEFAULT 0,
    dohodnina           NUMERIC(12,2) DEFAULT 0,
    prirez              NUMERIC(12,2) DEFAULT 0,
    neto                NUMERIC(12,2) DEFAULT 0,
    doprinosi_na_plate  NUMERIC(12,2) DEFAULT 0,   -- 16.5% zdravstveno
    ukupni_trosak       NUMERIC(12,2) DEFAULT 0,
    datum_isplate       DATE,
    dnevnik_id          INTEGER REFERENCES pgz_sport.dnevnik_zapisa(id),
    created_at          TIMESTAMPTZ DEFAULT now(),
    UNIQUE(zaposlenik_id, godina, mjesec)
);

-- ======================================================================
-- 6) VIEWS
-- ======================================================================
CREATE OR REPLACE VIEW pgz_sport.v_glavna_knjiga AS
SELECT k.konto_id, kp.sifra, kp.naziv, kp.klasa, kp.vrsta,
       SUM(k.duguje)    AS sum_duguje,
       SUM(k.potrazuje) AS sum_potrazuje,
       SUM(k.duguje) - SUM(k.potrazuje) AS saldo,
       COUNT(*)         AS broj_stavki
FROM pgz_sport.knjizenja k
JOIN pgz_sport.kontni_plan kp ON kp.id = k.konto_id
GROUP BY k.konto_id, kp.sifra, kp.naziv, kp.klasa, kp.vrsta
ORDER BY kp.sifra;

CREATE OR REPLACE VIEW pgz_sport.v_partner_saldo AS
SELECT p.id AS partner_id, p.naziv, p.oib, p.vrsta,
       COALESCE(SUM(k.duguje),0)    AS uk_duguje,
       COALESCE(SUM(k.potrazuje),0) AS uk_potrazuje,
       COALESCE(SUM(k.duguje),0) - COALESCE(SUM(k.potrazuje),0) AS saldo
FROM pgz_sport.partneri p
LEFT JOIN pgz_sport.knjizenja k ON k.partner_id = p.id
GROUP BY p.id, p.naziv, p.oib, p.vrsta;

CREATE OR REPLACE VIEW pgz_sport.v_pdv_ulazni AS
SELECT r.id, r.broj, r.datum_izdavanja, r.datum_primitka,
       p.naziv AS partner_naziv, p.oib AS partner_oib,
       r.iznos_neto, r.iznos_pdv, r.iznos_brutto, r.status
FROM pgz_sport.racuni_ulazni r
LEFT JOIN pgz_sport.partneri p ON p.id = r.partner_id
WHERE r.status IN ('knjizen','placen');

CREATE OR REPLACE VIEW pgz_sport.v_pdv_izlazni AS
SELECT r.id, r.broj, r.datum_izdavanja,
       p.naziv AS partner_naziv, p.oib AS partner_oib,
       r.iznos_neto, r.iznos_pdv, r.iznos_brutto, r.status
FROM pgz_sport.racuni_izlazni r
LEFT JOIN pgz_sport.partneri p ON p.id = r.partner_id
WHERE r.status IN ('knjizen','placen');

CREATE OR REPLACE VIEW pgz_sport.v_bilanca AS
SELECT kp.klasa, kp.vrsta, kp.sifra, kp.naziv,
       COALESCE(SUM(k.duguje),0)    AS duguje,
       COALESCE(SUM(k.potrazuje),0) AS potrazuje,
       COALESCE(SUM(k.duguje),0) - COALESCE(SUM(k.potrazuje),0) AS saldo
FROM pgz_sport.kontni_plan kp
LEFT JOIN pgz_sport.knjizenja k ON k.konto_id = kp.id
WHERE kp.vrsta IN ('aktiva','pasiva','kapital')
GROUP BY kp.klasa, kp.vrsta, kp.sifra, kp.naziv
ORDER BY kp.sifra;

CREATE OR REPLACE VIEW pgz_sport.v_pnl AS
SELECT kp.klasa, kp.vrsta, kp.sifra, kp.naziv,
       COALESCE(SUM(k.duguje),0)    AS duguje,
       COALESCE(SUM(k.potrazuje),0) AS potrazuje,
       CASE WHEN kp.vrsta='prihod'
            THEN COALESCE(SUM(k.potrazuje),0) - COALESCE(SUM(k.duguje),0)
            ELSE COALESCE(SUM(k.duguje),0) - COALESCE(SUM(k.potrazuje),0)
       END AS iznos
FROM pgz_sport.kontni_plan kp
LEFT JOIN pgz_sport.knjizenja k ON k.konto_id = kp.id
WHERE kp.vrsta IN ('prihod','rashod')
GROUP BY kp.klasa, kp.vrsta, kp.sifra, kp.naziv
ORDER BY kp.sifra;

-- ======================================================================
-- 7) SEED HR-RRIF kontni plan (skraćeni okvirni, ~80 konta)
-- ======================================================================
INSERT INTO pgz_sport.kontni_plan (sifra, naziv, klasa, vrsta) VALUES
-- KLASA 0 — Dugotrajna imovina
('00','DUGOTRAJNA NEMATERIJALNA IMOVINA',0,'aktiva'),
('001','Izdaci za razvoj',0,'aktiva'),
('002','Koncesije, patenti, licencije',0,'aktiva'),
('003','Software',0,'aktiva'),
('01','DUGOTRAJNA MATERIJALNA IMOVINA',0,'aktiva'),
('010','Zemljišta',0,'aktiva'),
('011','Građevinski objekti',0,'aktiva'),
('012','Postrojenja i oprema',0,'aktiva'),
('013','Alati, pogonski inventar',0,'aktiva'),
('014','Transportna sredstva',0,'aktiva'),
('029','Ispravak vrijednosti DI',0,'aktiva'),
-- KLASA 1 — Novac, potraživanja, financijska imovina
('10','NOVAC U BANCI I BLAGAJNI',1,'aktiva'),
('100','Blagajna - kuna/euro',1,'aktiva'),
('1000','Glavna blagajna',1,'aktiva'),
('101','Žiro-račun',1,'aktiva'),
('1010','Žiro-račun HRK/EUR',1,'aktiva'),
('102','Devizni račun',1,'aktiva'),
('12','POTRAŽIVANJA OD KUPACA',1,'aktiva'),
('120','Potraživanja od kupaca u zemlji',1,'aktiva'),
('1200','Kupci u zemlji - domaće osobe',1,'aktiva'),
('121','Potraživanja od kupaca u inozemstvu',1,'aktiva'),
('13','POTRAŽIVANJA OD ZAPOSLENIH',1,'aktiva'),
('130','Predujmovi za putne troškove',1,'aktiva'),
('14','POTRAŽIVANJA ZA PDV',1,'aktiva'),
('1400','Pretporez',1,'aktiva'),
('15','POTRAŽIVANJA ZA SUFINANCIRANJE',1,'aktiva'),
('1500','Potraživanja od PGŽ',1,'aktiva'),
('1501','Potraživanja od HOO/Ministarstva',1,'aktiva'),
-- KLASA 2 — Obveze
('22','OBVEZE PREMA DOBAVLJAČIMA',2,'pasiva'),
('220','Dobavljači u zemlji',2,'pasiva'),
('2200','Dobavljači - domaće osobe',2,'pasiva'),
('221','Dobavljači u inozemstvu',2,'pasiva'),
('23','KRATKOROČNE OBVEZE PO KREDITIMA',2,'pasiva'),
('24','OBVEZE PREMA ZAPOSLENIMA',2,'pasiva'),
('240','Obveze za neto plaće',2,'pasiva'),
('241','Obveze za doprinose iz plaća',2,'pasiva'),
('242','Obveze za dohodninu',2,'pasiva'),
('243','Obveze za prirez',2,'pasiva'),
('244','Obveze za doprinose na plaće',2,'pasiva'),
('25','OBVEZE ZA PDV',2,'pasiva'),
('2500','Porez na dodanu vrijednost',2,'pasiva'),
-- KLASA 3 — Zalihe
('30','ZALIHE SIROVINA I MATERIJALA',3,'aktiva'),
('31','ZALIHE TRGOVAČKE ROBE',3,'aktiva'),
-- KLASA 4 — Rashodi
('40','MATERIJALNI TROŠKOVI',4,'rashod'),
('400','Utrošeni materijal',4,'rashod'),
('401','Energija',4,'rashod'),
('402','Sitan inventar',4,'rashod'),
('41','TROŠKOVI USLUGA',4,'rashod'),
('410','Usluge prijevoza',4,'rashod'),
('411','Usluge održavanja',4,'rashod'),
('412','Najamnine',4,'rashod'),
('413','Komunalne usluge',4,'rashod'),
('414','Telekomunikacije',4,'rashod'),
('415','Sudske takse, javnobilježničke usluge',4,'rashod'),
('42','PLAĆE I NAKNADE',4,'rashod'),
('420','Bruto plaće',4,'rashod'),
('421','Doprinosi na plaće',4,'rashod'),
('422','Naknade volonterima',4,'rashod'),
('423','Putni troškovi - dnevnice',4,'rashod'),
('424','Putni troškovi - prijevoz',4,'rashod'),
('43','AMORTIZACIJA',4,'rashod'),
('430','Amortizacija DMI',4,'rashod'),
('44','OSTALI TROŠKOVI POSLOVANJA',4,'rashod'),
('440','Reprezentacija',4,'rashod'),
('441','Reklama i promidžba',4,'rashod'),
('442','Članarine savezima',4,'rashod'),
('443','Kotizacije i natjecanja',4,'rashod'),
('444','Sportska oprema',4,'rashod'),
('445','Liječnički pregledi',4,'rashod'),
('446','Suđenja, suci',4,'rashod'),
-- KLASA 7 — Prihodi (preskačemo 5,6 — manje korišteni za neprofit)
('70','PRIHODI OD ČLANARINA',7,'prihod'),
('700','Članarine članova',7,'prihod'),
('71','PRIHODI OD SUFINANCIRANJA',7,'prihod'),
('710','Sufinanciranje PGŽ',7,'prihod'),
('711','Sufinanciranje Ministarstva',7,'prihod'),
('712','Sufinanciranje HOO/HOK',7,'prihod'),
('713','Sufinanciranje grad/općina',7,'prihod'),
('72','PRIHODI OD DONACIJA',7,'prihod'),
('720','Donacije od pravnih osoba',7,'prihod'),
('721','Donacije od fizičkih osoba',7,'prihod'),
('73','PRIHODI OD KOTIZACIJA',7,'prihod'),
('730','Kotizacije za natjecanja',7,'prihod'),
('74','OSTALI POSLOVNI PRIHODI',7,'prihod'),
('740','Sponzorstva',7,'prihod'),
('741','Naplata reklamnog prostora',7,'prihod'),
-- KLASA 9 — Kapital
('90','VLASTITI IZVORI',9,'kapital'),
('900','Temeljni kapital',9,'kapital'),
('91','REZERVE',9,'kapital'),
('92','REZULTAT POSLOVANJA',9,'kapital'),
('920','Višak prihoda nad rashodima',9,'kapital'),
('921','Manjak prihoda nad rashodima',9,'kapital')
ON CONFLICT (sifra) DO NOTHING;
