| Version 28 (modified by , 6 days ago) ( diff ) |
|---|
Програмирање на базата на податоци
Функции
get_current_price
Оваа функција ја пресметува моменталната цена на билетот со примена на активниот процент на попуст дефиниран за тековниот временски период. Таа проверува дали денешниот датум се наоѓа во некој од опсезите на Event_Period и линеарно ја намалува основната цена на билетот.
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;
IF FOUND THEN
v_final_price := v_base_price * (1 - (v_discount_percent / 100.0));
ELSE
v_final_price := v_base_price;
END IF;
RETURN v_final_price;
END;
$$;
calculate_refund_amount
Оваа функција ја калкулира сумата за поврат на средства при откажување на конкретна ставка од нарачката со задржување на 15% административна такса. Таа го идентификува билетот преку неговиот уникатен ID во трансакцискиот дел и враќа чисто 85% од оригинално платената цена.
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);
v_refund_amount 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;
v_refund_amount := v_original_price * 0.85;
RETURN v_refund_amount;
END;
$$;
Процедури
buy_ticket
Оваа процедура го автоматизира процесот на купување билет преку симултано генерирање на главна нарачка и поединечна ставка со уникатен QR-код. По успешното запишување на трансакцијата, процедурата инстантни го менува статусот на билетот во недостапен за да спречи паралелна продажба на истото седиште.
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;
COMMIT;
END;
$$;
cancel_ticket
Оваа процедура менаџира делумно или целосно откажување на купени ставки преку евидентирање на рефундацијата и поврат на средствата со пресметани пенали. По завршување на финансискиот запис во релационите табели, таа автоматски го враќа билетот во статус на достапен за повторна продажба на пазарот.
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;
RAISE NOTICE 'Ticket item cancelled successfully. Refund amount: %', v_refund_amount;
END;
$$;
schedule_new_happening
Оваа процедура овозможува авторизиран администратор да закаже нов термин за настан и автоматски да го генерира почетниот инвентар на билети. Системот динамички ги презема сите достапни седишта од дефинираната сала и ги мапира како слободни влезници со почетна базна цена.
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
IF NOT EXISTS (
SELECT 1 FROM "Admin" WHERE user_id = p_admin_id
) THEN
RAISE EXCEPTION 'Access Denied: Only administrators can schedule a new event happening.';
END IF;
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 Organizer')
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;
RAISE NOTICE 'Event happening successfully scheduled by admin % and tickets generated.', p_admin_id;
END;
$$;
create_rating
Оваа процедура ја гарантира веродостојноста на рецензиите преку строга проверка на историјата на нарачки на корисникот. Спуштањето на оцена и коментар е дозволено исклучиво доколку корисникот реално поседува валиден, купен и воедно нерефундиран билет за конкретниот термин на настанот.
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: You can only rate events you attended and did not refund.';
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);
RAISE NOTICE 'Rating successfully submitted.';
END;
$$;
Тригери
trg_check_user_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 'Access Denied: User does not meet the minimum age restriction for this event.';
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_sync_order_amount
Овој тригер одржува конзистентност на податоците преку автоматска синхронизација на финансиската сума во главната нарачка при секоја измена на нејзините ставки. Тој динамички го прекалкулира вкупниот износ земајќи ги предвид само активните и нерефундираните билети по секој INSERT, UPDATE или DELETE.
CREATE OR REPLACE FUNCTION trg_sync_order_amount()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
DECLARE
v_target_order_id BIGINT;
v_new_total DECIMAL(10,2);
BEGIN
IF TG_OP = 'DELETE' THEN
v_target_order_id := OLD.order_id;
ELSE
v_target_order_id := NEW.order_id;
END IF;
SELECT COALESCE(SUM(toi.item_price), 0.00) INTO v_new_total
FROM "Ticket_Order_Item" toi
LEFT JOIN "Ticket_Refund_Item" tri ON toi.order_item_id = tri.order_item_id
WHERE toi.order_id = v_target_order_id AND tri.refund_item_id IS NULL;
UPDATE "Ticket_Order"
SET order_amount = v_new_total
WHERE order_id = v_target_order_id;
RETURN NEW;
END;
$$;
CREATE TRIGGER sync_order_total_on_change
AFTER INSERT OR UPDATE OR DELETE ON "Ticket_Order_Item"
FOR EACH ROW EXECUTE FUNCTION trg_sync_order_amount();
trg_prevent_double_booking
Овој тригер го штити интегритетот на распоредот на локациите преку спречување на временско преклопување на настани во иста сала. Тој применува напредна OVERLAPS логика која вклучува времетраење на перформансот и задолжителен технички бафер од 3 часа за подготовка на сцената пред почеток на следниот настан.
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 'Access Denied: Venue is already occupied or currently in technical preparation (3-hour buffer required).';
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();
