| Version 21 (modified by , 2 weeks ago) ( diff ) |
|---|
Програмирање на базата на податоци
Функции
get_current_price
Оваа функција ја пресметува моменталната цена на билетот земајќи ги предвид активните промотивни периоди или поскапувања во реално време. Таа проверува дали за денешниот датум постои дефиниран период за промена на цената и соодветно ја зголемува или намалува основната цена.
CREATE OR REPLACE FUNCTION get_current_price(p_ticket_id BIGINT)
RETURNS FLOAT4 AS $$
DECLARE
v_base_price FLOAT4;
v_happening_id BIGINT;
v_percent INT;
v_increase BOOLEAN;
v_final_price FLOAT4;
BEGIN
SELECT base_price, event_happening_id INTO v_base_price, v_happening_id
FROM "Ticket" WHERE ticket_id = p_ticket_id;
SELECT price_change_percent, increase_decrease INTO v_percent, v_increase
FROM "Event_Period"
WHERE event_happening_id = v_happening_id
AND CURRENT_DATE BETWEEN start_date AND end_date
LIMIT 1;
IF FOUND THEN
IF v_increase THEN
v_final_price := v_base_price * (1 + (v_percent / 100.0));
ELSE
v_final_price := v_base_price * (1 - (v_percent / 100.0));
END IF;
ELSE
v_final_price := v_base_price;
END IF;
RETURN v_final_price;
END;
$$ LANGUAGE plpgsql;
calculate_refund_amount
Оваа функција ја пресметува сумата за рефундација со примена на 15% задршка од оригиналната уплата. Таа го идентификува плаќањето преку неговиот уникатен ID и враќа 85% од износот како финален износ за поврат на средства.
CREATE OR REPLACE FUNCTION calculate_refund_amount(p_purchase_id BIGINT)
RETURNS FLOAT4 AS $$
DECLARE
v_original_price FLOAT4;
v_refund_amount FLOAT4;
BEGIN
-- Преземање на износот кој корисникот навистина го платил
SELECT purchase_amount INTO v_original_price
FROM "Ticket_Purchase"
WHERE purchase_id = p_purchase_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'Purchase record not found.';
END IF;
-- Примена на 15% пенали (се враќаат 85% од цената)
v_refund_amount := v_original_price * 0.85;
RETURN v_refund_amount;
END;
$$ LANGUAGE plpgsql;
Процедури
buy_ticket
Оваа процедура го извршува целиот процес на купување билет, вклучувајќи пресметка на цена, генерирање на уникатен QR код и креирање на запис за трансакцијата. По успешното купување, процедурата автоматски го менува статусот на билетот во недостапен за да се спречи двојна продажба.
CREATE OR REPLACE PROCEDURE buy_ticket(
p_user_id BIGINT,
p_ticket_id BIGINT
)
AS $$
DECLARE
v_price FLOAT4;
v_qr_code TEXT;
BEGIN
v_price := get_current_price(p_ticket_id);
v_qr_code := 'QR-' || p_ticket_id || '-' || p_user_id || '-' || EXTRACT(EPOCH FROM NOW());
INSERT INTO "Ticket_Purchase" (ticket_id, user_id, qr_code, purchase_amount)
VALUES (p_ticket_id, p_user_id, v_qr_code, v_price);
UPDATE "Ticket" SET is_available = FALSE WHERE ticket_id = p_ticket_id;
COMMIT;
END;
$$ LANGUAGE plpgsql;
schedule_new_happening
Оваа процедура се користи за автоматизирано закажување на нов настан и генерирање на инвентар од билети за сите достапни седишта во објектот. Со еден повик, таа го креира настанот и веднаш ги пополнува соодветните табели со достапни билети за секоја секција во салата.
CREATE OR REPLACE PROCEDURE schedule_new_happening(
p_event_id BIGINT,
p_venue_id BIGINT,
p_time TIMESTAMP,
p_duration INT,
p_base_price FLOAT4
)
AS $$
DECLARE
v_happening_id BIGINT;
v_seat_record RECORD;
BEGIN
INSERT INTO "Event_Happening" (event_id, event_time, venue_id, duration)
VALUES (p_event_id, p_time, p_venue_id, p_duration)
RETURNING event_happening_id INTO v_happening_id;
FOR v_seat_record IN
SELECT seat_id FROM "Seat" s
JOIN "Section" sec ON s.section_id = sec.section_id
WHERE sec.venue_id = p_venue_id
LOOP
INSERT INTO "Ticket" (ticket_type, base_price, is_available, event_happening_id, seat_id)
VALUES ('Standard', p_base_price, TRUE, v_happening_id, v_seat_record.seat_id);
END LOOP;
RAISE NOTICE 'Event scheduled and tickets generated.';
END;
$$ LANGUAGE plpgsql;
Тригери
trg_check_ticket_availability
Овој тригер служи како безбедносен механизам кој пред секое купување проверува дали билетот е навистина слободен. Доколку билетот е веќе продаден, тригерот ја блокира трансакцијата и фрла грешка, со што се спречува конфликт на податоци.
CREATE OR REPLACE FUNCTION trg_check_ticket_availability()
RETURNS TRIGGER AS $$
BEGIN
IF (SELECT is_available FROM "Ticket" WHERE ticket_id = NEW.ticket_id) = FALSE THEN
RAISE EXCEPTION 'Ticket is already sold or unavailable.';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER check_ticket_availability_before_buy
BEFORE INSERT ON "Ticket_Purchase"
FOR EACH ROW EXECUTE FUNCTION trg_check_ticket_availability();
trg_check_user_age
Овој тригер врши автоматска проверка на старосната граница на корисникот пред да му дозволи да купи билет за одреден настан. Доколку настанот има ограничување (на пр. 18+), тригерот ја пресметува возраста на корисникот и го блокира внесувањето во табелата за нарачки ако условот не е исполнет.
CREATE OR REPLACE FUNCTION trg_check_user_age()
RETURNS TRIGGER AS $$
DECLARE
v_user_age INT;
v_min_age INT;
BEGIN
SELECT DATE_PART('year', AGE(date_of_birth)) INTO v_user_age
FROM "User" WHERE user_id = NEW.user_id;
SELECT e.min_age INTO v_min_age
FROM "Ticket" t
JOIN "Event_Happening" eh ON t.event_happening_id = eh.event_happening_id
JOIN "Event" e ON eh.event_id = e.event_id
WHERE t.ticket_id = NEW.ticket_id;
IF v_user_age < v_min_age THEN
RAISE EXCEPTION 'Access Denied: User is too young.';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER check_age_before_purchase
BEFORE INSERT ON "Ticket_Purchase"
FOR EACH ROW EXECUTE FUNCTION trg_check_user_age();
trg_check_venue_schedule
Овој тригер спречува преклопување на два настани во ист објект и во исто време. Пред секој внес или измена во распоредот, базата проверува дали терминот е веќе резервиран за таа локација.
CREATE OR REPLACE FUNCTION trg_check_venue_schedule()
RETURNS TRIGGER AS $$
BEGIN
IF EXISTS (
SELECT 1 FROM "Event_Happening"
WHERE venue_id = NEW.venue_id
AND event_time = NEW.event_time
AND event_happening_id <> NEW.event_happening_id
) THEN
RAISE EXCEPTION 'Venue is already occupied at this time.';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER check_venue_before_insert_update
BEFORE INSERT OR UPDATE ON "Event_Happening"
FOR EACH ROW EXECUTE FUNCTION trg_check_venue_schedule();
trg_check_performer_availability
Овој тригер гарантира дека еден изведувач не може да биде на две места истовремено. Со поврзување на табелите за изведувачи и настани, системот автоматски го блокира секој обид за дуплирање на ангажманот во ист термин.
CREATE OR REPLACE FUNCTION trg_check_performer_availability()
RETURNS TRIGGER AS $$
DECLARE
v_new_event_time TIMESTAMP;
BEGIN
SELECT event_time INTO v_new_event_time
FROM "Event_Happening"
WHERE event_happening_id = NEW.event_happening_id;
IF EXISTS (
SELECT 1
FROM "Event_Happening_Performer" ehp
JOIN "Event_Happening" eh ON ehp.event_happening_id = eh.event_happening_id
WHERE ehp.performer_id = NEW.performer_id
AND eh.event_time = v_new_event_time
AND ehp.event_happening_id <> NEW.event_happening_id
) THEN
RAISE EXCEPTION 'Performer is already booked for another event at this time.';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER check_performer_before_assign
BEFORE INSERT OR UPDATE ON "Event_Happening_Performer"
FOR EACH ROW EXECUTE FUNCTION trg_check_performer_availability();
trg_validate_event_rating
Овој тригер овозможува оставање на рејтинг само за корисници кои поседуваат валиден билет за конкретниот настан. Системот проверува дали постои купопродажен запис кој не е поврзан со рефундација, со што се спречува лажно оценување од корисници кои не присуствувале на настанот.
CREATE OR REPLACE FUNCTION trg_validate_event_rating()
RETURNS TRIGGER AS $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM "Ticket_Purchase" tp
JOIN "Ticket" t ON tp.ticket_id = t.ticket_id
LEFT JOIN "Ticket_Refund" tr ON tp.purchase_id = tr.purchase_id
WHERE tp.user_id = NEW.user_id
AND t.event_happening_id = NEW.event_happening_id
AND tr.refund_id IS NULL
) THEN
RAISE EXCEPTION 'Access Denied: You can only rate events you attended and did not refund.';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER check_rating_eligibility_before_insert
BEFORE INSERT ON "Event_Happening_Rating"
FOR EACH ROW EXECUTE FUNCTION trg_validate_event_rating();
