| 5 | | |
| | 5 | === get_current_price |
| | 6 | |
| | 7 | Оваа функција ја пресметува моменталната цена на билетот земајќи ги предвид активните промотивни периоди или поскапувања во реално време. Таа проверува дали за денешниот датум постои дефиниран период за промена на цената и соодветно ја зголемува или намалува основната цена. |
| | 8 | |
| | 9 | {{{ |
| | 10 | |
| | 11 | CREATE OR REPLACE FUNCTION get_current_price(p_ticket_id BIGINT) |
| | 12 | RETURNS FLOAT4 AS $$ |
| | 13 | DECLARE |
| | 14 | v_base_price FLOAT4; |
| | 15 | v_happening_id BIGINT; |
| | 16 | v_percent INT; |
| | 17 | v_increase BOOLEAN; |
| | 18 | v_final_price FLOAT4; |
| | 19 | BEGIN |
| | 20 | SELECT base_price, event_happening_id INTO v_base_price, v_happening_id |
| | 21 | FROM "Ticket" WHERE ticket_id = p_ticket_id; |
| | 22 | |
| | 23 | SELECT price_change_percent, increase_decrease INTO v_percent, v_increase |
| | 24 | FROM "Event_Period" |
| | 25 | WHERE event_happening_id = v_happening_id |
| | 26 | AND CURRENT_DATE BETWEEN start_date AND end_date |
| | 27 | LIMIT 1; |
| | 28 | |
| | 29 | IF FOUND THEN |
| | 30 | IF v_increase THEN |
| | 31 | v_final_price := v_base_price * (1 + (v_percent / 100.0)); |
| | 32 | ELSE |
| | 33 | v_final_price := v_base_price * (1 - (v_percent / 100.0)); |
| | 34 | END IF; |
| | 35 | ELSE |
| | 36 | v_final_price := v_base_price; |
| | 37 | END IF; |
| | 38 | |
| | 39 | RETURN v_final_price; |
| | 40 | END; |
| | 41 | $$ LANGUAGE plpgsql; |
| | 42 | |
| | 43 | }}} |
| | 44 | |
| | 45 | === calculate_refund_amount |
| | 46 | |
| | 47 | Оваа функција ја пресметува сумата за рефундација со примена на 15% задршка од оригиналната уплата. Таа го идентификува плаќањето преку неговиот уникатен ID и враќа 85% од износот како финален износ за поврат на средства. |
| | 48 | |
| | 49 | {{{ |
| | 50 | |
| | 51 | CREATE OR REPLACE FUNCTION calculate_refund_amount(p_purchase_id BIGINT) |
| | 52 | RETURNS FLOAT4 AS $$ |
| | 53 | DECLARE |
| | 54 | v_original_price FLOAT4; |
| | 55 | v_refund_amount FLOAT4; |
| | 56 | BEGIN |
| | 57 | -- Преземање на износот кој корисникот навистина го платил |
| | 58 | SELECT purchase_amount INTO v_original_price |
| | 59 | FROM "Ticket_Purchase" |
| | 60 | WHERE purchase_id = p_purchase_id; |
| | 61 | |
| | 62 | IF NOT FOUND THEN |
| | 63 | RAISE EXCEPTION 'Purchase record not found.'; |
| | 64 | END IF; |
| | 65 | |
| | 66 | -- Примена на 15% пенали (се враќаат 85% од цената) |
| | 67 | v_refund_amount := v_original_price * 0.85; |
| | 68 | |
| | 69 | RETURN v_refund_amount; |
| | 70 | END; |
| | 71 | $$ LANGUAGE plpgsql; |
| | 72 | |
| | 73 | }}} |
| 9 | | |
| | 77 | === buy_ticket |
| | 78 | |
| | 79 | Оваа процедура го извршува целиот процес на купување билет, вклучувајќи пресметка на цена, генерирање на уникатен QR код и креирање на запис за трансакцијата. По успешното купување, процедурата автоматски го менува статусот на билетот во недостапен за да се спречи двојна продажба. |
| | 80 | |
| | 81 | {{{ |
| | 82 | |
| | 83 | CREATE OR REPLACE PROCEDURE buy_ticket( |
| | 84 | p_user_id BIGINT, |
| | 85 | p_ticket_id BIGINT |
| | 86 | ) |
| | 87 | AS $$ |
| | 88 | DECLARE |
| | 89 | v_price FLOAT4; |
| | 90 | v_qr_code TEXT; |
| | 91 | BEGIN |
| | 92 | v_price := get_current_price(p_ticket_id); |
| | 93 | v_qr_code := 'QR-' || p_ticket_id || '-' || p_user_id || '-' || EXTRACT(EPOCH FROM NOW()); |
| | 94 | |
| | 95 | INSERT INTO "Ticket_Purchase" (ticket_id, user_id, qr_code, purchase_amount) |
| | 96 | VALUES (p_ticket_id, p_user_id, v_qr_code, v_price); |
| | 97 | |
| | 98 | UPDATE "Ticket" SET is_available = FALSE WHERE ticket_id = p_ticket_id; |
| | 99 | |
| | 100 | COMMIT; |
| | 101 | END; |
| | 102 | $$ LANGUAGE plpgsql; |
| | 103 | |
| | 104 | }}} |
| | 105 | |
| | 106 | === schedule_new_happening |
| | 107 | |
| | 108 | Оваа процедура се користи за автоматизирано закажување на нов настан и генерирање на инвентар од билети за сите достапни седишта во објектот. Со еден повик, таа го креира настанот и веднаш ги пополнува соодветните табели со достапни билети за секоја секција во салата. |
| | 109 | |
| | 110 | {{{ |
| | 111 | |
| | 112 | CREATE OR REPLACE PROCEDURE schedule_new_happening( |
| | 113 | p_event_id BIGINT, |
| | 114 | p_venue_id BIGINT, |
| | 115 | p_time TIMESTAMP, |
| | 116 | p_duration INT, |
| | 117 | p_base_price FLOAT4 |
| | 118 | ) |
| | 119 | AS $$ |
| | 120 | DECLARE |
| | 121 | v_happening_id BIGINT; |
| | 122 | v_seat_record RECORD; |
| | 123 | BEGIN |
| | 124 | INSERT INTO "Event_Happening" (event_id, event_time, venue_id, duration) |
| | 125 | VALUES (p_event_id, p_time, p_venue_id, p_duration) |
| | 126 | RETURNING event_happening_id INTO v_happening_id; |
| | 127 | |
| | 128 | FOR v_seat_record IN |
| | 129 | SELECT seat_id FROM "Seat" s |
| | 130 | JOIN "Section" sec ON s.section_id = sec.section_id |
| | 131 | WHERE sec.venue_id = p_venue_id |
| | 132 | LOOP |
| | 133 | INSERT INTO "Ticket" (ticket_type, base_price, is_available, event_happening_id, seat_id) |
| | 134 | VALUES ('Standard', p_base_price, TRUE, v_happening_id, v_seat_record.seat_id); |
| | 135 | END LOOP; |
| | 136 | |
| | 137 | RAISE NOTICE 'Event scheduled and tickets generated.'; |
| | 138 | END; |
| | 139 | $$ LANGUAGE plpgsql; |
| | 140 | |
| | 141 | }}} |
| | 145 | === trg_check_ticket_availability |
| | 146 | |
| | 147 | Овој тригер служи како безбедносен механизам кој пред секое купување проверува дали билетот е навистина слободен. Доколку билетот е веќе продаден, тригерот ја блокира трансакцијата и фрла грешка, со што се спречува конфликт на податоци. |
| | 148 | |
| | 149 | {{{ |
| | 150 | |
| | 151 | CREATE OR REPLACE FUNCTION trg_check_ticket_availability() |
| | 152 | RETURNS TRIGGER AS $$ |
| | 153 | BEGIN |
| | 154 | IF (SELECT is_available FROM "Ticket" WHERE ticket_id = NEW.ticket_id) = FALSE THEN |
| | 155 | RAISE EXCEPTION 'Ticket is already sold or unavailable.'; |
| | 156 | END IF; |
| | 157 | RETURN NEW; |
| | 158 | END; |
| | 159 | $$ LANGUAGE plpgsql; |
| | 160 | |
| | 161 | CREATE TRIGGER check_ticket_availability_before_buy |
| | 162 | BEFORE INSERT ON "Ticket_Purchase" |
| | 163 | FOR EACH ROW EXECUTE FUNCTION trg_check_ticket_availability(); |
| | 164 | |
| | 165 | }}} |
| | 166 | |
| | 167 | === trg_check_user_age |
| | 168 | |
| | 169 | Овој тригер врши автоматска проверка на старосната граница на корисникот пред да му дозволи да купи билет за одреден настан. Доколку настанот има ограничување (на пр. 18+), тригерот ја пресметува возраста на корисникот и го блокира внесувањето во табелата за нарачки ако условот не е исполнет. |
| | 170 | |
| | 171 | {{{ |
| | 172 | |
| | 173 | CREATE OR REPLACE FUNCTION trg_check_user_age() |
| | 174 | RETURNS TRIGGER AS $$ |
| | 175 | DECLARE |
| | 176 | v_user_age INT; |
| | 177 | v_min_age INT; |
| | 178 | BEGIN |
| | 179 | SELECT DATE_PART('year', AGE(date_of_birth)) INTO v_user_age |
| | 180 | FROM "User" WHERE user_id = NEW.user_id; |
| | 181 | |
| | 182 | SELECT e.min_age INTO v_min_age |
| | 183 | FROM "Ticket" t |
| | 184 | JOIN "Event_Happening" eh ON t.event_happening_id = eh.event_happening_id |
| | 185 | JOIN "Event" e ON eh.event_id = e.event_id |
| | 186 | WHERE t.ticket_id = NEW.ticket_id; |
| | 187 | |
| | 188 | IF v_user_age < v_min_age THEN |
| | 189 | RAISE EXCEPTION 'Access Denied: User is too young.'; |
| | 190 | END IF; |
| | 191 | |
| | 192 | RETURN NEW; |
| | 193 | END; |
| | 194 | $$ LANGUAGE plpgsql; |
| | 195 | |
| | 196 | CREATE TRIGGER check_age_before_purchase |
| | 197 | BEFORE INSERT ON "Ticket_Purchase" |
| | 198 | FOR EACH ROW EXECUTE FUNCTION trg_check_user_age(); |
| | 199 | |
| | 200 | }}} |