| Version 32 (modified by , 4 days ago) ( diff ) |
|---|
Програмирање на базата на податоци
Функции
get_current_price
Функцијата овозможува динамично одредување на цената на билетот во реално време. Таа го мапира билетот кон неговиот настан, ја проверува валидноста на тековниот датум во рамките на дефинираните временски периоди (Event_Period) и применува соодветен попуст. Со користење на COALESCE, функцијата гарантира враќање на основната цена доколку не е дефиниран активен период на попуст.
CREATE OR REPLACE FUNCTION get_current_price(p_ticket_id BIGINT)
RETURNS DECIMAL(10,2)
LANGUAGE plpgsql
AS $$
DECLARE
v_base_price DECIMAL(10,2);
v_happening_id BIGINT;
v_discount_percent INT;
v_final_price DECIMAL(10,2);
BEGIN
SELECT base_price, event_happening_id
INTO v_base_price, v_happening_id
FROM "Ticket"
WHERE ticket_id = p_ticket_id;
SELECT price_discount_percent
INTO v_discount_percent
FROM "Event_Period"
WHERE event_happening_id = v_happening_id
AND CURRENT_DATE BETWEEN start_date AND end_date
LIMIT 1;
v_final_price := COALESCE(v_base_price * (1 - (v_discount_percent / 100.0)), v_base_price);
RETURN v_final_price;
END;
$$;
calculate_refund_amount
Функцијата ја автоматизира пресметката на износот за рефундација. Со примена на фиксна административна такса од 15% (враќање на 85% од износот), се спроведува бизнис политиката за заштита на оперативните трошоци на компанијата. Функцијата вклучува и проверка за постоење на ставката преку RAISE EXCEPTION за заштита од невалидни прашалници.
CREATE OR REPLACE FUNCTION calculate_refund_amount(p_order_item_id BIGINT)
RETURNS DECIMAL(10,2)
LANGUAGE plpgsql
AS $$
DECLARE
v_original_price DECIMAL(10,2);
BEGIN
SELECT item_price
INTO v_original_price
FROM "Ticket_Order_Item"
WHERE order_item_id = p_order_item_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'Order item record not found.';
END IF;
RETURN v_original_price * 0.85;
END;
$$;
Процедури
buy_ticket
Процедурата го координира комплетниот трансакциски циклус на купување: валидација на статус на корисник, пресметка на моментална цена (преку get_current_price), генерирање на уникатен QR-код и ажурирање на статусот на билетот во инвентарот. Со ова се осигурува „Atomic“ природа на операцијата - билетот се резервира инстантно за да се спречи конфликт при истовремена продажба.
CREATE OR REPLACE PROCEDURE buy_ticket(p_user_id BIGINT, p_ticket_id BIGINT)
LANGUAGE plpgsql
AS $$
DECLARE
v_price DECIMAL(10,2);
v_qr_code TEXT;
v_order_id BIGINT;
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_Order" (user_id, order_amount)
VALUES (p_user_id, v_price)
RETURNING order_id INTO v_order_id;
INSERT INTO "Ticket_Order_Item" (order_id, ticket_id, qr_code, item_price)
VALUES (v_order_id, p_ticket_id, v_qr_code, v_price);
UPDATE "Ticket" SET is_available = FALSE WHERE ticket_id = p_ticket_id;
END;
$$;
cancel_ticket
Оваа процедура менаџира процес на враќање на средства. Покрај пресметката на рефундацијата и евидентирањето во табелите Ticket_Refund и Ticket_Refund_Item, процедурата го ослободува билетот (is_available = TRUE), овозможувајќи негова повторна продажба. Оваа грануларност дозволува прецизно сметководствено следење на секоја поединечна ставка од нарачката.
CREATE OR REPLACE PROCEDURE cancel_ticket(p_order_item_id BIGINT, p_reason TEXT)
LANGUAGE plpgsql
AS $$
DECLARE
v_refund_amount DECIMAL(10,2);
v_ticket_id BIGINT;
v_order_id BIGINT;
v_refund_id BIGINT;
BEGIN
v_refund_amount := calculate_refund_amount(p_order_item_id);
SELECT order_id, ticket_id
INTO v_order_id, v_ticket_id
FROM "Ticket_Order_Item"
WHERE order_item_id = p_order_item_id;
INSERT INTO "Ticket_Refund" (order_id, refund_amount, reasons)
VALUES (v_order_id, v_refund_amount, p_reason)
RETURNING refund_id INTO v_refund_id;
INSERT INTO "Ticket_Refund_Item" (refund_id, order_item_id, item_price)
VALUES (v_refund_id, p_order_item_id, v_refund_amount);
UPDATE "Ticket" SET is_available = TRUE WHERE ticket_id = v_ticket_id;
END;
$$;
schedule_new_happening
Процедура наменета за администратори, која овозможува брзо „пуштање во продажба“ на нов настан. Таа автоматски го инстанцира терминот и, што е најважно, врши масовно внесување на записи во Ticket табелата за сите седишта во одбраната сала. Со ова се елиминира потребата од рачно креирање на билети, со што се зголемува ефикасноста при планирањето.
CREATE OR REPLACE PROCEDURE schedule_new_happening(
p_admin_id BIGINT,
p_event_id BIGINT,
p_venue_id BIGINT,
p_time TIMESTAMP,
p_duration_minutes INT,
p_base_price DECIMAL(10,2)
)
LANGUAGE plpgsql
AS $$
DECLARE
v_happening_id BIGINT;
BEGIN
INSERT INTO "Event_Happening" (event_id, event_time, venue_id, duration_minutes, organizers)
VALUES (p_event_id, p_time, p_venue_id, p_duration_minutes, 'System Generated')
RETURNING event_happening_id INTO v_happening_id;
INSERT INTO "Ticket" (base_price, is_available, event_happening_id, seat_id)
SELECT p_base_price, TRUE, v_happening_id, s.seat_id
FROM "Seat" s
JOIN "Section" sec ON s.section_id = sec.section_id
WHERE sec.venue_id = p_venue_id;
END;
$$;
create_rating
Оваа процедура ја заштитува веродостојноста на системот за рецензии. Преку сложен SELECT прашалник, таа верификува дали корисникот бил вистински сопственик на билет кој не е рефундиран. Со ова се спречува „лажирање“ на оценки и се обезбедува квалитетен социјален доказ за квалитетот на настаните.
CREATE OR REPLACE PROCEDURE create_rating(p_user_id BIGINT, p_event_happening_id BIGINT, p_rating INT, p_comment TEXT)
LANGUAGE plpgsql
AS $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM "Ticket_Order" o
JOIN "Ticket_Order_Item" toi ON o.order_id = toi.order_id
JOIN "Ticket" t ON toi.ticket_id = t.ticket_id
LEFT JOIN "Ticket_Refund_Item" tri ON toi.order_item_id = tri.order_item_id
WHERE o.user_id = p_user_id
AND t.event_happening_id = p_event_happening_id
AND tri.refund_item_id IS NULL
) THEN
RAISE EXCEPTION 'Access Denied: Cannot rate.';
END IF;
INSERT INTO "Event_Happening_Rating" (rating, comment, event_happening_id, user_id, timestamp)
VALUES (p_rating, p_comment, p_event_happening_id, p_user_id, CURRENT_TIMESTAMP);
END;
$$;
Тригери
trg_check_user_age
Овој тригер служи како „чувар“ на законската регулатива. Пред вметнување на било која ставка во нарачка, системот ја пресметува возраста на купувачот врз основа на датумот на раѓање и ја споредува со min_age атрибутот на настанот. Доколку корисникот не ја исполнува старосната граница, операцијата се прекинува пред да дојде до финализирање на нарачката.
CREATE OR REPLACE FUNCTION trg_check_user_age()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
DECLARE
v_user_age INT;
v_min_age INT;
v_user_id BIGINT;
BEGIN
SELECT user_id INTO v_user_id FROM "Ticket_Order" WHERE order_id = NEW.order_id;
SELECT DATE_PART('year', AGE(date_of_birth))
INTO v_user_age
FROM "Regular_User"
WHERE user_id = v_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 'Age restriction.';
END IF;
RETURN NEW;
END;
$$;
CREATE TRIGGER check_age_before_item_insert
BEFORE INSERT ON "Ticket_Order_Item"
FOR EACH ROW EXECUTE FUNCTION trg_check_user_age();
trg_limit_tickets_per_happening
Овој тригер обезбедува фер дистрибуција на билети преку ограничување на бројот на карти кои еден корисник може да ги купи за истиот настан. Со лимитирање на купувањето на максимум 4 билети по корисник, се спречува појавата на препродажба („scalping“) и се овозможува поголем број на уникатни посетители да дојдат до влезници.
CREATE OR REPLACE FUNCTION trg_limit_tickets_per_happening()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
DECLARE
v_happening_id BIGINT;
v_count INT;
BEGIN
SELECT event_happening_id INTO v_happening_id FROM "Ticket" WHERE ticket_id = NEW.ticket_id;
SELECT COUNT(*) INTO v_count
FROM "Ticket_Order_Item" toi
JOIN "Ticket_Order" o ON toi.order_id = o.order_id
JOIN "Ticket" t ON toi.ticket_id = t.ticket_id
WHERE o.user_id = (SELECT user_id FROM "Ticket_Order" WHERE order_id = NEW.order_id)
AND t.event_happening_id = v_happening_id;
IF v_count >= 4 THEN
RAISE EXCEPTION 'Purchase limit reached: You cannot own more than 4 tickets for this event.';
END IF;
RETURN NEW;
END;
$$;
CREATE TRIGGER trg_limit_user_happening_tickets
BEFORE INSERT ON "Ticket_Order_Item"
FOR EACH ROW EXECUTE FUNCTION trg_limit_tickets_per_happening();
trg_prevent_double_booking
Овој тригер е критичен за операционата стабилност. Тој спречува преклопување на термини во иста сала, земајќи ги предвид времетраењето на настанот и задолжителното „бафер“ време од 3 часа за техничка подготовка. При секој обид за вметнување или ажурирање, се врши проверка преку OVERLAPS операторот, со што се гарантира дека распоредот на салата е секогаш логички исправен.
CREATE OR REPLACE FUNCTION trg_prevent_double_booking()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
IF EXISTS (
SELECT 1 FROM "Event_Happening"
WHERE venue_id = NEW.venue_id
AND event_happening_id <> NEW.event_happening_id
AND (NEW.event_time, NEW.event_time + (NEW.duration_minutes || ' minutes')::INTERVAL + INTERVAL '3 hours')
OVERLAPS (event_time, event_time + (duration_minutes || ' minutes')::INTERVAL + INTERVAL '3 hours')
) THEN
RAISE EXCEPTION 'Venue occupied.';
END IF;
RETURN NEW;
END;
$$;
CREATE TRIGGER check_venue_integrity
BEFORE INSERT OR UPDATE ON "Event_Happening"
FOR EACH ROW EXECUTE FUNCTION trg_prevent_double_booking();
