| 1 | -- ==============================================================================
|
|---|
| 2 | -- 13. ФУНКЦИИ / ПРОЦЕДУРИ / ТРИГЕРИ (3 + 3 + 3)
|
|---|
| 3 | -- ==============================================================================
|
|---|
| 4 |
|
|---|
| 5 | -- ============================== ФУНКЦИИ =======================================
|
|---|
| 6 |
|
|---|
| 7 | -- F1: Кредитно-пондериран просек на студент (опционално по систем на оценување).
|
|---|
| 8 | CREATE
|
|---|
| 9 | OR REPLACE FUNCTION fn_prosek_student(p_student_id integer,
|
|---|
| 10 | p_sistem_ocenuvanje_id integer DEFAULT NULL)
|
|---|
| 11 | RETURNS numeric
|
|---|
| 12 | LANGUAGE sql
|
|---|
| 13 | STABLE
|
|---|
| 14 | AS
|
|---|
| 15 | $$
|
|---|
| 16 | SELECT ROUND(SUM(sov.ocena_vrednost::numeric * ak.krediti)
|
|---|
| 17 | / NULLIF(SUM(ak.krediti), 0), 2)
|
|---|
| 18 | FROM sm_student_ocena_zapis soz
|
|---|
| 19 | JOIN sm_student_upisan_kurs suk ON soz.student_upisan_kurs_id = suk.id
|
|---|
| 20 | JOIN sm_student_semestar_upis ssu ON suk.student_semestar_upis_id = ssu.id
|
|---|
| 21 | JOIN sm_studenti_smerovi ss ON ssu.studenti_smerovi_id = ss.id
|
|---|
| 22 | JOIN sm_kurs_realizacija kr ON suk.kurs_realizacija_id = kr.id
|
|---|
| 23 | JOIN sm_akreditacija ak ON kr.akreditacija_id = ak.id
|
|---|
| 24 | JOIN sm_sistem_ocenuvanje_vrednost sov ON soz.sistem_ocenuvanje_vrednost_id = sov.id
|
|---|
| 25 | WHERE ss.student_id = p_student_id
|
|---|
| 26 | AND sov.polozitelna
|
|---|
| 27 | AND (p_sistem_ocenuvanje_id IS NULL OR sov.sistem_ocenuvanje_id = p_sistem_ocenuvanje_id)
|
|---|
| 28 | $$;
|
|---|
| 29 |
|
|---|
| 30 | -- F2: Вкупен отворен долг на корисник во дадена валута.
|
|---|
| 31 | CREATE
|
|---|
| 32 | OR REPLACE FUNCTION fn_otvoren_dolg(p_user_id integer, p_vid_valuta_id integer)
|
|---|
| 33 | RETURNS numeric
|
|---|
| 34 | LANGUAGE sql
|
|---|
| 35 | STABLE
|
|---|
| 36 | AS
|
|---|
| 37 | $$
|
|---|
| 38 | SELECT COALESCE(SUM(fo.otvorena_suma), 0)
|
|---|
| 39 | FROM fin_finansiska_obvrska fo
|
|---|
| 40 | WHERE fo.user_id = p_user_id
|
|---|
| 41 | AND fo.vid_valuta_id = p_vid_valuta_id
|
|---|
| 42 | AND fo.otvorena_suma > 0
|
|---|
| 43 | AND fo.status_finansiska_obvrska_id IN
|
|---|
| 44 | (SELECT id FROM fin_status_finansiska_obvrska WHERE ime IN ('Izdadena', 'Delumno platena'))
|
|---|
| 45 | $$;
|
|---|
| 46 |
|
|---|
| 47 | -- F3: Слободни места на реализација на курс (NULL капацитет = неограничено).
|
|---|
| 48 | CREATE
|
|---|
| 49 | OR REPLACE FUNCTION fn_slobodni_mesta(p_kurs_realizacija_id integer)
|
|---|
| 50 | RETURNS integer
|
|---|
| 51 | LANGUAGE sql
|
|---|
| 52 | STABLE
|
|---|
| 53 | AS
|
|---|
| 54 | $$
|
|---|
| 55 | SELECT kr.kapacitet_studenti
|
|---|
| 56 | - (SELECT COUNT(*) ::int
|
|---|
| 57 | FROM sm_student_upisan_kurs suk
|
|---|
| 58 | WHERE suk.kurs_realizacija_id = kr.id
|
|---|
| 59 | AND suk.status_slushanje = 'UPISAN')
|
|---|
| 60 | FROM sm_kurs_realizacija kr
|
|---|
| 61 | WHERE kr.id = p_kurs_realizacija_id
|
|---|
| 62 | $$;
|
|---|
| 63 |
|
|---|
| 64 | -- ============================== ПРОЦЕДУРИ =====================================
|
|---|
| 65 |
|
|---|
| 66 | -- P1: Регистрирање наплата + автоматска алокација кон отворени обврски
|
|---|
| 67 | -- (најстаро доспевање прво). Ажурирањето на otvorena_suma го врши тригерот T2.
|
|---|
| 68 | CREATE
|
|---|
| 69 | OR REPLACE PROCEDURE pr_registriraj_naplata(p_user_id integer,
|
|---|
| 70 | p_suma numeric,
|
|---|
| 71 | p_vid_valuta_id integer,
|
|---|
| 72 | p_organizaciona_edinica_id integer,
|
|---|
| 73 | p_referenca varchar DEFAULT NULL,
|
|---|
| 74 | p_korisnik_naplata_id integer DEFAULT NULL)
|
|---|
| 75 | LANGUAGE plpgsql
|
|---|
| 76 | AS
|
|---|
| 77 | $$
|
|---|
| 78 | DECLARE
|
|---|
| 79 | v_naplata_id integer;
|
|---|
| 80 | v_smetka_id
|
|---|
| 81 | integer;
|
|---|
| 82 | v_ostatok
|
|---|
| 83 | numeric := p_suma;
|
|---|
| 84 | v_obvrska
|
|---|
| 85 | record;
|
|---|
| 86 | v_alocirano
|
|---|
| 87 | numeric;
|
|---|
| 88 | BEGIN
|
|---|
| 89 | IF
|
|---|
| 90 | p_suma <= 0 THEN
|
|---|
| 91 | RAISE EXCEPTION 'Сумата мора да биде позитивна (добиено: %)', p_suma;
|
|---|
| 92 | END IF;
|
|---|
| 93 |
|
|---|
| 94 | -- активна трансакциска сметка на организационата единица (приоритет: иста валута)
|
|---|
| 95 | SELECT oes.transakciska_smetka_id
|
|---|
| 96 | INTO v_smetka_id
|
|---|
| 97 | FROM or_organizaciona_edinica_smetki oes
|
|---|
| 98 | JOIN fin_transakciski_smetki ts ON oes.transakciska_smetka_id = ts.id
|
|---|
| 99 | WHERE oes.organizaciona_edinica_id = p_organizaciona_edinica_id
|
|---|
| 100 | AND oes.aktivna
|
|---|
| 101 | AND ts.aktivna
|
|---|
| 102 | ORDER BY (ts.vid_valuta_id = p_vid_valuta_id) DESC, ts.id LIMIT 1;
|
|---|
| 103 | IF
|
|---|
| 104 | v_smetka_id IS NULL THEN
|
|---|
| 105 | RAISE EXCEPTION 'Организационата единица % нема активна трансакциска сметка',
|
|---|
| 106 | p_organizaciona_edinica_id;
|
|---|
| 107 | END IF;
|
|---|
| 108 |
|
|---|
| 109 | INSERT INTO fin_naplati (user_id, korisnik_naplata_id, transakciska_smetka_id,
|
|---|
| 110 | organizaciona_edinica_id, naplatena_suma, vid_valuta_id,
|
|---|
| 111 | status_transakcija_id, nadvoresna_referenca,
|
|---|
| 112 | requested_at, confirmed_at, data)
|
|---|
| 113 | VALUES (p_user_id, COALESCE(p_korisnik_naplata_id, p_user_id), v_smetka_id,
|
|---|
| 114 | p_organizaciona_edinica_id, p_suma, p_vid_valuta_id,
|
|---|
| 115 | (SELECT id FROM fin_status_transakcija WHERE ime_status = 'ACCEPTED'),
|
|---|
| 116 | p_referenca, now(), now(), now()) RETURNING id
|
|---|
| 117 | INTO v_naplata_id;
|
|---|
| 118 |
|
|---|
| 119 | FOR v_obvrska IN
|
|---|
| 120 | SELECT fo.id, fo.otvorena_suma
|
|---|
| 121 | FROM fin_finansiska_obvrska fo
|
|---|
| 122 | WHERE fo.user_id = p_user_id
|
|---|
| 123 | AND fo.vid_valuta_id = p_vid_valuta_id
|
|---|
| 124 | AND fo.otvorena_suma > 0
|
|---|
| 125 | ORDER BY fo.datum_dospevanje NULLS LAST, fo.id
|
|---|
| 126 | FOR UPDATE LOOP
|
|---|
| 127 | EXIT WHEN v_ostatok <= 0;
|
|---|
| 128 | v_alocirano
|
|---|
| 129 | := LEAST(v_ostatok, v_obvrska.otvorena_suma);
|
|---|
| 130 | INSERT INTO fin_naplata_alokacija (naplata_id, finansiska_obvrska_id,
|
|---|
| 131 | alocirana_suma, created_at)
|
|---|
| 132 | VALUES (v_naplata_id, v_obvrska.id, v_alocirano, now());
|
|---|
| 133 | v_ostatok
|
|---|
| 134 | := v_ostatok - v_alocirano;
|
|---|
| 135 | END LOOP;
|
|---|
| 136 |
|
|---|
| 137 | IF
|
|---|
| 138 | v_ostatok > 0 THEN
|
|---|
| 139 | RAISE NOTICE 'Наплата %: % останува неалоцирано (преплата).', v_naplata_id, v_ostatok;
|
|---|
| 140 | END IF;
|
|---|
| 141 | END;
|
|---|
| 142 | $$;
|
|---|
| 143 |
|
|---|
| 144 | -- P2: Запишување студент на курс — проверува долг и слободни места,
|
|---|
| 145 | -- па внесува во sm_student_upisan_kurs (тригерот T3 е последна одбрана).
|
|---|
| 146 | CREATE
|
|---|
| 147 | OR REPLACE PROCEDURE pr_zapisi_student_na_kurs(p_student_id integer,
|
|---|
| 148 | p_kurs_realizacija_id integer)
|
|---|
| 149 | LANGUAGE plpgsql
|
|---|
| 150 | AS
|
|---|
| 151 | $$
|
|---|
| 152 | DECLARE
|
|---|
| 153 | v_ssu_id integer;
|
|---|
| 154 | v_user_id
|
|---|
| 155 | integer;
|
|---|
| 156 | v_dolg
|
|---|
| 157 | numeric;
|
|---|
| 158 | v_valuta
|
|---|
| 159 | integer;
|
|---|
| 160 | v_slobodni
|
|---|
| 161 | integer;
|
|---|
| 162 | BEGIN
|
|---|
| 163 | SELECT ssu.id
|
|---|
| 164 | INTO v_ssu_id
|
|---|
| 165 | FROM sm_student_semestar_upis ssu
|
|---|
| 166 | JOIN sm_studenti_smerovi ss ON ssu.studenti_smerovi_id = ss.id
|
|---|
| 167 | JOIN sm_kurs_realizacija kr ON kr.id = p_kurs_realizacija_id
|
|---|
| 168 | WHERE ss.student_id = p_student_id
|
|---|
| 169 | AND ssu.akademski_semestar_id = kr.akademski_semestar_id
|
|---|
| 170 | ORDER BY ssu.datum_upis DESC LIMIT 1;
|
|---|
| 171 | IF
|
|---|
| 172 | v_ssu_id IS NULL THEN
|
|---|
| 173 | RAISE EXCEPTION 'Студентот % нема упис во семестарот на курсот %',
|
|---|
| 174 | p_student_id, p_kurs_realizacija_id;
|
|---|
| 175 | END IF;
|
|---|
| 176 |
|
|---|
| 177 | IF
|
|---|
| 178 | EXISTS (SELECT 1
|
|---|
| 179 | FROM sm_student_upisan_kurs
|
|---|
| 180 | WHERE student_semestar_upis_id = v_ssu_id
|
|---|
| 181 | AND kurs_realizacija_id = p_kurs_realizacija_id) THEN
|
|---|
| 182 | RAISE EXCEPTION 'Студентот % е веќе запишан на курсот %',
|
|---|
| 183 | p_student_id, p_kurs_realizacija_id;
|
|---|
| 184 | END IF;
|
|---|
| 185 |
|
|---|
| 186 | SELECT s.user_id
|
|---|
| 187 | INTO v_user_id
|
|---|
| 188 | FROM sm_studenti s
|
|---|
| 189 | WHERE s.id = p_student_id;
|
|---|
| 190 | FOR v_valuta IN
|
|---|
| 191 | SELECT DISTINCT vid_valuta_id
|
|---|
| 192 | FROM fin_finansiska_obvrska
|
|---|
| 193 | WHERE user_id = v_user_id
|
|---|
| 194 | AND otvorena_suma > 0 LOOP
|
|---|
| 195 | v_dolg := fn_otvoren_dolg(v_user_id, v_valuta);
|
|---|
| 196 | IF
|
|---|
| 197 | v_dolg > 0 THEN
|
|---|
| 198 | RAISE EXCEPTION 'Студентот % има отворен долг % (валута %) — уписот е блокиран',
|
|---|
| 199 | p_student_id, v_dolg, v_valuta;
|
|---|
| 200 | END IF;
|
|---|
| 201 | END LOOP;
|
|---|
| 202 |
|
|---|
| 203 | v_slobodni
|
|---|
| 204 | := fn_slobodni_mesta(p_kurs_realizacija_id);
|
|---|
| 205 | IF
|
|---|
| 206 | v_slobodni IS NOT NULL AND v_slobodni <= 0 THEN
|
|---|
| 207 | RAISE EXCEPTION 'Нема слободни места на курсот %', p_kurs_realizacija_id;
|
|---|
| 208 | END IF;
|
|---|
| 209 |
|
|---|
| 210 | INSERT INTO sm_student_upisan_kurs (student_semestar_upis_id, kurs_realizacija_id, status_slushanje)
|
|---|
| 211 | VALUES (v_ssu_id, p_kurs_realizacija_id, 'UPISAN');
|
|---|
| 212 | END;
|
|---|
| 213 | $$;
|
|---|
| 214 |
|
|---|
| 215 | -- P3: Сериско генерирање обврски за школарина за сите студенти запишани
|
|---|
| 216 | -- во даден академски семестар, според активниот ценовник. COMMIT на
|
|---|
| 217 | -- секои 1000 студенти — можно само во процедура.
|
|---|
| 218 | CREATE
|
|---|
| 219 | OR REPLACE PROCEDURE pr_generiraj_obvrski_za_semestar(p_akademski_semestar_id integer)
|
|---|
| 220 | LANGUAGE plpgsql
|
|---|
| 221 | AS
|
|---|
| 222 | $$
|
|---|
| 223 | DECLARE
|
|---|
| 224 | v_cenovnik record;
|
|---|
| 225 | v_oe
|
|---|
| 226 | integer;
|
|---|
| 227 | v_opis
|
|---|
| 228 | varchar;
|
|---|
| 229 | v_student
|
|---|
| 230 | record;
|
|---|
| 231 | v_brojac
|
|---|
| 232 | integer := 0;
|
|---|
| 233 | BEGIN
|
|---|
| 234 | SELECT asem.organizaciona_edinica_id,
|
|---|
| 235 | c.id AS cenovnik_id,
|
|---|
| 236 | c.iznos,
|
|---|
| 237 | c.vid_valuta_id,
|
|---|
| 238 | asem.tip_naplata_organizaciona_edinica_id
|
|---|
| 239 | INTO v_cenovnik
|
|---|
| 240 | FROM sm_akademski_semestar asem
|
|---|
| 241 | JOIN fin_tip_naplati_cenovnik c
|
|---|
| 242 | ON c.tip_naplata_organizaciona_edinica_id = asem.tip_naplata_organizaciona_edinica_id
|
|---|
| 243 | AND c.aktivna
|
|---|
| 244 | WHERE asem.id = p_akademski_semestar_id
|
|---|
| 245 | ORDER BY c.prioritet LIMIT 1;
|
|---|
| 246 | IF
|
|---|
| 247 | v_cenovnik IS NULL THEN
|
|---|
| 248 | RAISE EXCEPTION 'Нема активен ценовник за семестар %', p_akademski_semestar_id;
|
|---|
| 249 | END IF;
|
|---|
| 250 |
|
|---|
| 251 | v_oe
|
|---|
| 252 | := v_cenovnik.organizaciona_edinica_id;
|
|---|
| 253 | v_opis
|
|---|
| 254 | := 'Школарина семестар ' || p_akademski_semestar_id;
|
|---|
| 255 |
|
|---|
| 256 | FOR v_student IN
|
|---|
| 257 | SELECT DISTINCT s.user_id
|
|---|
| 258 | FROM sm_student_semestar_upis ssu
|
|---|
| 259 | JOIN sm_studenti_smerovi ss ON ssu.studenti_smerovi_id = ss.id
|
|---|
| 260 | JOIN sm_studenti s ON ss.student_id = s.id
|
|---|
| 261 | WHERE ssu.akademski_semestar_id = p_akademski_semestar_id
|
|---|
| 262 | AND NOT EXISTS (SELECT 1
|
|---|
| 263 | FROM fin_finansiska_obvrska fo
|
|---|
| 264 | WHERE fo.user_id = s.user_id
|
|---|
| 265 | AND fo.opis = 'Школарина семестар ' || p_akademski_semestar_id)
|
|---|
| 266 | LOOP
|
|---|
| 267 | INSERT
|
|---|
| 268 | INTO fin_finansiska_obvrska (user_id, organizaciona_edinica_id,
|
|---|
| 269 | tip_naplata_organizaciona_edinica_id,
|
|---|
| 270 | tip_naplati_cenovnik_id,
|
|---|
| 271 | status_finansiska_obvrska_id,
|
|---|
| 272 | datum_kreiranje, datum_dospevanje,
|
|---|
| 273 | originalna_suma, otvorena_suma,
|
|---|
| 274 | vid_valuta_id, opis)
|
|---|
| 275 | VALUES (v_student.user_id, v_oe, v_cenovnik.tip_naplata_organizaciona_edinica_id, v_cenovnik.cenovnik_id, (SELECT id FROM fin_status_finansiska_obvrska WHERE ime = 'Izdadena'), now(), CURRENT_DATE + 30, v_cenovnik.iznos, v_cenovnik.iznos, v_cenovnik.vid_valuta_id, v_opis);
|
|---|
| 276 | v_brojac
|
|---|
| 277 | := v_brojac + 1;
|
|---|
| 278 | IF
|
|---|
| 279 | v_brojac % 1000 = 0 THEN
|
|---|
| 280 | COMMIT; -- дозволено само во процедура
|
|---|
| 281 | END IF;
|
|---|
| 282 | END LOOP;
|
|---|
| 283 |
|
|---|
| 284 | RAISE
|
|---|
| 285 | NOTICE 'Генерирани % обврски за семестар %', v_brojac, p_akademski_semestar_id;
|
|---|
| 286 | END;
|
|---|
| 287 | $$;
|
|---|
| 288 |
|
|---|
| 289 | -- ============================== ТРИГЕРИ =======================================
|
|---|
| 290 |
|
|---|
| 291 | -- T1: Валидација при внес на оценка — уписот мора да е активен (UPISAN),
|
|---|
| 292 | -- поените во опсег 0–100, датумот не во иднина.
|
|---|
| 293 | CREATE
|
|---|
| 294 | OR REPLACE FUNCTION trgf_validna_ocena()
|
|---|
| 295 | RETURNS trigger
|
|---|
| 296 | LANGUAGE plpgsql
|
|---|
| 297 | AS
|
|---|
| 298 | $$
|
|---|
| 299 | DECLARE
|
|---|
| 300 | v_status varchar;
|
|---|
| 301 | BEGIN
|
|---|
| 302 | SELECT status_slushanje
|
|---|
| 303 | INTO v_status
|
|---|
| 304 | FROM sm_student_upisan_kurs
|
|---|
| 305 | WHERE id = NEW.student_upisan_kurs_id;
|
|---|
| 306 | IF
|
|---|
| 307 | v_status IS DISTINCT FROM 'UPISAN' THEN
|
|---|
| 308 | RAISE EXCEPTION 'Оценка може да се внесе само за активен упис (статус: %)', v_status;
|
|---|
| 309 | END IF;
|
|---|
| 310 | IF
|
|---|
| 311 | NEW.osvoeni_poeni IS NOT NULL AND (NEW.osvoeni_poeni < 0 OR NEW.osvoeni_poeni > 100) THEN
|
|---|
| 312 | RAISE EXCEPTION 'Освоени поени мора да бидат 0–100 (добиено: %)', NEW.osvoeni_poeni;
|
|---|
| 313 | END IF;
|
|---|
| 314 | IF
|
|---|
| 315 | NEW.datum_zapis > now() THEN
|
|---|
| 316 | RAISE EXCEPTION 'Датумот на запис не смее да биде во иднина';
|
|---|
| 317 | END IF;
|
|---|
| 318 | RETURN NEW;
|
|---|
| 319 | END;
|
|---|
| 320 | $$;
|
|---|
| 321 |
|
|---|
| 322 | DROP TRIGGER IF EXISTS trg_validna_ocena ON sm_student_ocena_zapis;
|
|---|
| 323 | CREATE TRIGGER trg_validna_ocena
|
|---|
| 324 | BEFORE INSERT
|
|---|
| 325 | ON sm_student_ocena_zapis
|
|---|
| 326 | FOR EACH ROW
|
|---|
| 327 | EXECUTE FUNCTION trgf_validna_ocena();
|
|---|
| 328 |
|
|---|
| 329 | -- T2: По алокација на наплата — намали otvorena_suma и постави статус
|
|---|
| 330 | -- (Delumno platena / Platena). Изведената вредност ја одржува тригерот,
|
|---|
| 331 | -- без разлика кој ја внел алокацијата.
|
|---|
| 332 | CREATE
|
|---|
| 333 | OR REPLACE FUNCTION trgf_azuriraj_otvorena_suma()
|
|---|
| 334 | RETURNS trigger
|
|---|
| 335 | LANGUAGE plpgsql
|
|---|
| 336 | AS
|
|---|
| 337 | $$
|
|---|
| 338 | DECLARE
|
|---|
| 339 | v_nova numeric;
|
|---|
| 340 | BEGIN
|
|---|
| 341 | SELECT otvorena_suma - NEW.alocirana_suma
|
|---|
| 342 | INTO v_nova
|
|---|
| 343 | FROM fin_finansiska_obvrska
|
|---|
| 344 | WHERE id = NEW.finansiska_obvrska_id
|
|---|
| 345 | FOR UPDATE;
|
|---|
| 346 |
|
|---|
| 347 | IF
|
|---|
| 348 | v_nova < 0 THEN
|
|---|
| 349 | RAISE EXCEPTION 'Алокацијата (%) ја надминува отворената сума на обврската %',
|
|---|
| 350 | NEW.alocirana_suma, NEW.finansiska_obvrska_id;
|
|---|
| 351 | END IF;
|
|---|
| 352 |
|
|---|
| 353 | UPDATE fin_finansiska_obvrska
|
|---|
| 354 | SET otvorena_suma = v_nova,
|
|---|
| 355 | status_finansiska_obvrska_id = CASE
|
|---|
| 356 | WHEN v_nova = 0 THEN
|
|---|
| 357 | (SELECT id FROM fin_status_finansiska_obvrska WHERE ime = 'Platena')
|
|---|
| 358 | ELSE
|
|---|
| 359 | (SELECT id
|
|---|
| 360 | FROM fin_status_finansiska_obvrska
|
|---|
| 361 | WHERE ime = 'Delumno platena')
|
|---|
| 362 | END
|
|---|
| 363 | WHERE id = NEW.finansiska_obvrska_id;
|
|---|
| 364 |
|
|---|
| 365 | RETURN NEW;
|
|---|
| 366 | END;
|
|---|
| 367 | $$;
|
|---|
| 368 |
|
|---|
| 369 | DROP TRIGGER IF EXISTS trg_azuriraj_otvorena_suma ON fin_naplata_alokacija;
|
|---|
| 370 | CREATE TRIGGER trg_azuriraj_otvorena_suma
|
|---|
| 371 | AFTER INSERT
|
|---|
| 372 | ON fin_naplata_alokacija
|
|---|
| 373 | FOR EACH ROW
|
|---|
| 374 | EXECUTE FUNCTION trgf_azuriraj_otvorena_suma();
|
|---|
| 375 |
|
|---|
| 376 | -- T3: Капацитет на курс — одбиј упис над kapacitet_studenti, и при
|
|---|
| 377 | -- конкурентни инсерти (FOR UPDATE врз реализацијата).
|
|---|
| 378 | CREATE
|
|---|
| 379 | OR REPLACE FUNCTION trgf_kapacitet_kurs()
|
|---|
| 380 | RETURNS trigger
|
|---|
| 381 | LANGUAGE plpgsql
|
|---|
| 382 | AS
|
|---|
| 383 | $$
|
|---|
| 384 | DECLARE
|
|---|
| 385 | v_kapacitet integer;
|
|---|
| 386 | v_upisani
|
|---|
| 387 | integer;
|
|---|
| 388 | BEGIN
|
|---|
| 389 | IF
|
|---|
| 390 | NEW.status_slushanje <> 'UPISAN' THEN
|
|---|
| 391 | RETURN NEW;
|
|---|
| 392 | END IF;
|
|---|
| 393 |
|
|---|
| 394 | SELECT kapacitet_studenti
|
|---|
| 395 | INTO v_kapacitet
|
|---|
| 396 | FROM sm_kurs_realizacija
|
|---|
| 397 | WHERE id = NEW.kurs_realizacija_id
|
|---|
| 398 | FOR UPDATE; -- сериализира конкурентни уписи на иста реализација
|
|---|
| 399 |
|
|---|
| 400 | IF
|
|---|
| 401 | v_kapacitet IS NULL THEN
|
|---|
| 402 | RETURN NEW; -- неограничен капацитет
|
|---|
| 403 | END IF;
|
|---|
| 404 |
|
|---|
| 405 | SELECT COUNT(*)
|
|---|
| 406 | INTO v_upisani
|
|---|
| 407 | FROM sm_student_upisan_kurs
|
|---|
| 408 | WHERE kurs_realizacija_id = NEW.kurs_realizacija_id
|
|---|
| 409 | AND status_slushanje = 'UPISAN';
|
|---|
| 410 |
|
|---|
| 411 | IF
|
|---|
| 412 | v_upisani >= v_kapacitet THEN
|
|---|
| 413 | RAISE EXCEPTION 'Курсот % е полн (капацитет %)', NEW.kurs_realizacija_id, v_kapacitet;
|
|---|
| 414 | END IF;
|
|---|
| 415 |
|
|---|
| 416 | RETURN NEW;
|
|---|
| 417 | END;
|
|---|
| 418 | $$;
|
|---|
| 419 |
|
|---|
| 420 | DROP TRIGGER IF EXISTS trg_kapacitet_kurs ON sm_student_upisan_kurs;
|
|---|
| 421 | CREATE TRIGGER trg_kapacitet_kurs
|
|---|
| 422 | BEFORE INSERT
|
|---|
| 423 | ON sm_student_upisan_kurs
|
|---|
| 424 | FOR EACH ROW
|
|---|
| 425 | EXECUTE FUNCTION trgf_kapacitet_kurs();
|
|---|