Procedures
create_parking_reservation
CREATE OR REPLACE PROCEDURE public.create_parking_reservation(
IN p_user_id integer,
IN p_vehicle_id integer,
IN p_parking_id integer,
IN p_reservation_status_id integer,
IN p_start_time timestamp without time zone,
IN p_end_time timestamp without time zone
)
LANGUAGE plpgsql
AS $procedure$
BEGIN
IF NOT EXISTS (SELECT 1 FROM app_user WHERE user_id = p_user_id) THEN
RAISE EXCEPTION 'User does not exist.';
END IF;
IF NOT EXISTS (
SELECT 1 FROM vehicle
WHERE vehicle_id = p_vehicle_id AND user_id = p_user_id
) THEN
RAISE EXCEPTION 'Vehicle does not exist or does not belong to this user.';
END IF;
IF NOT EXISTS (SELECT 1 FROM parking WHERE parking_id = p_parking_id) THEN
RAISE EXCEPTION 'Parking does not exist.';
END IF;
IF NOT EXISTS (
SELECT 1 FROM parking
WHERE parking_id = p_parking_id AND supports_reservation = true
) THEN
RAISE EXCEPTION 'Parking does not support reservations.';
END IF;
IF p_start_time >= p_end_time THEN
RAISE EXCEPTION 'Start time must be before end time.';
END IF;
IF NOT EXISTS (
SELECT 1 FROM parking_spot
WHERE parking_id = p_parking_id AND status = 'free'
) THEN
RAISE EXCEPTION 'No free parking spots available.';
END IF;
INSERT INTO reservation (
user_id,
vehicle_id,
parking_id,
reservation_status_id,
start_time,
end_time,
reservation_code
)
VALUES (
p_user_id,
p_vehicle_id,
p_parking_id,
p_reservation_status_id,
p_start_time,
p_end_time,
'RES-' || p_user_id || '-' || EXTRACT(EPOCH FROM NOW())::INT
);
UPDATE parking_spot
SET status = 'reserved'
WHERE parking_spot_id = (
SELECT parking_spot_id
FROM parking_spot
WHERE parking_id = p_parking_id AND status = 'free'
LIMIT 1
);
END;
$procedure$;
Оваа процедура креира нова паркинг резервација само доколку се исполнети сите потребни услови, како постоење на корисник, возило, паркинг и слободно место. Ја имплементира бизнис логиката за управување со резервации и автоматски резервира слободно паркинг место.
cancel_reservation
CREATE OR REPLACE PROCEDURE public.cancel_reservation(
IN p_reservation_id integer
)
LANGUAGE plpgsql
AS $procedure$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM reservation
WHERE reservation_id = p_reservation_id
) THEN
RAISE EXCEPTION 'Reservation does not exist.';
END IF;
IF EXISTS (
SELECT 1 FROM reservation
WHERE reservation_id = p_reservation_id
AND reservation_status = 'cancelled'
) THEN
RAISE EXCEPTION 'Reservation is already cancelled.';
END IF;
IF EXISTS (
SELECT 1 FROM reservation
WHERE reservation_id = p_reservation_id
AND reservation_status = 'completed'
) THEN
RAISE EXCEPTION 'Completed reservation cannot be cancelled.';
END IF;
UPDATE reservation
SET reservation_status = 'cancelled'
WHERE reservation_id = p_reservation_id;
END;
$procedure$;
Оваа процедура овозможува откажување на постоечка резервација, при што спречува откажување на веќе завршени или претходно откажани резервации. Ја имплементира бизнис логиката за контрола и правилно управување со статусите на резервациите.
complete_reservation
CREATE OR REPLACE PROCEDURE public.complete_reservation(
IN p_reservation_id integer
)
LANGUAGE plpgsql
AS $procedure$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM reservation
WHERE reservation_id = p_reservation_id
) THEN
RAISE EXCEPTION 'Reservation does not exist.';
END IF;
IF EXISTS (
SELECT 1 FROM reservation
WHERE reservation_id = p_reservation_id
AND reservation_status = 'completed'
) THEN
RAISE EXCEPTION 'Reservation is already completed.';
END IF;
IF EXISTS (
SELECT 1 FROM reservation
WHERE reservation_id = p_reservation_id
AND reservation_status = 'cancelled'
) THEN
RAISE EXCEPTION 'Cancelled reservation cannot be completed.';
END IF;
UPDATE reservation
SET reservation_status = 'completed'
WHERE reservation_id = p_reservation_id;
END;
$procedure$;
Оваа процедура ја означува резервацијата како завршена, при што врши проверки за валидност на тековниот статус. Ја имплементира бизнис логиката за правилно завршување на процесот на резервација и спречување нелогични промени.
end_parking_session
CREATE OR REPLACE PROCEDURE public.end_parking_session(
IN p_session_id integer,
IN p_session_status_id integer
)
LANGUAGE plpgsql
AS $procedure$
BEGIN
IF NOT EXISTS (SELECT 1 FROM parking_session WHERE session_id = p_session_id) THEN
RAISE EXCEPTION 'Parking session does not exist.';
END IF;
IF EXISTS (
SELECT 1 FROM parking_session
WHERE session_id = p_session_id AND end_time IS NOT NULL
) THEN
RAISE EXCEPTION 'Parking session is already finished.';
END IF;
IF NOT EXISTS (
SELECT 1 FROM session_status
WHERE session_status_id = p_session_status_id
) THEN
RAISE EXCEPTION 'Session status does not exist.';
END IF;
UPDATE parking_session
SET end_time = NOW(),
session_status_id = p_session_status_id
WHERE session_id = p_session_id;
END;
$procedure$;
Оваа процедура ја завршува активната паркинг сесија со поставување на крајно време и ажурирање на нејзиниот статус. Ја имплементира бизнис логиката за правилно затворање на паркинг сесиите и спречување повторно завршување на веќе затворени сесии.
fill_total_amount
CREATE OR REPLACE PROCEDURE public.fill_total_amount(
IN p_session_id integer
)
LANGUAGE plpgsql
AS $procedure$
BEGIN
IF NOT EXISTS (SELECT 1 FROM parking_session WHERE session_id = p_session_id) THEN
RAISE EXCEPTION 'Parking session does not exist.';
END IF;
IF EXISTS (
SELECT 1 FROM parking_session
WHERE session_id = p_session_id AND end_time IS NULL
) THEN
RAISE EXCEPTION 'Parking session is still active.';
END IF;
UPDATE parking_session
SET total_amount = calculate_session_amount(p_session_id)
WHERE session_id = p_session_id;
END;
$procedure$;
Оваа процедура го пресметува и ажурира вкупниот износ за завршена паркинг сесија користејќи функција за пресметка на цена. Ја имплементира бизнис логиката за автоматска наплата според времетраењето и тарифата на паркирањето.
start_parking_session
CREATE OR REPLACE PROCEDURE public.start_parking_session(
IN p_user_id integer,
IN p_vehicle_id integer,
IN p_parking_id integer,
IN p_tariff_id integer,
IN p_session_status_id integer
)
LANGUAGE plpgsql
AS $procedure$
BEGIN
IF NOT EXISTS (SELECT 1 FROM app_user WHERE user_id = p_user_id) THEN
RAISE EXCEPTION 'User does not exist.';
END IF;
IF NOT EXISTS (
SELECT 1 FROM vehicle
WHERE vehicle_id = p_vehicle_id AND user_id = p_user_id
) THEN
RAISE EXCEPTION 'Vehicle does not exist or does not belong to this user.';
END IF;
IF NOT EXISTS (SELECT 1 FROM parking WHERE parking_id = p_parking_id) THEN
RAISE EXCEPTION 'Parking does not exist.';
END IF;
IF NOT EXISTS (SELECT 1 FROM tariff WHERE tariff_id = p_tariff_id) THEN
RAISE EXCEPTION 'Tariff does not exist.';
END IF;
IF NOT EXISTS (
SELECT 1 FROM session_status WHERE session_status_id = p_session_status_id
) THEN
RAISE EXCEPTION 'Session status does not exist.';
END IF;
IF has_active_session(p_user_id) THEN
RAISE EXCEPTION 'User already has an active parking session.';
END IF;
IF NOT EXISTS (
SELECT 1 FROM parking_spot
WHERE parking_id = p_parking_id AND status = 'free'
) THEN
RAISE EXCEPTION 'No free parking spots available.';
END IF;
INSERT INTO parking_session (
user_id,
vehicle_id,
parking_id,
tariff_id,
session_status_id,
start_time,
end_time,
total_amount
)
VALUES (
p_user_id,
p_vehicle_id,
p_parking_id,
p_tariff_id,
p_session_status_id,
NOW(),
NULL,
0.00
);
UPDATE parking_spot
SET status = 'occupied'
WHERE parking_spot_id = (
SELECT parking_spot_id
FROM parking_spot
WHERE parking_id = p_parking_id AND status = 'free'
LIMIT 1
);
END;
$procedure$;
Оваа процедура започнува нова паркинг сесија доколку корисникот ги исполнува сите услови и има достапно слободно место. Ја имплементира бизнис логиката за иницирање на паркирање, контрола на активни сесии и автоматско зафаќање на паркинг место.
Functions
calculate_session_amount
CREATE OR REPLACE FUNCTION public.calculate_session_amount(p_session_id integer)
RETURNS numeric
LANGUAGE plpgsql
AS $function$
DECLARE
v_start TIMESTAMP;
v_end TIMESTAMP;
v_tariff_id INT;
v_price NUMERIC;
v_hours NUMERIC;
BEGIN
SELECT start_time, end_time, tariff_id
INTO v_start, v_end, v_tariff_id
FROM parking_session
WHERE session_id = p_session_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'Parking session does not exist.';
END IF;
IF v_end IS NULL THEN
RETURN 0.00;
END IF;
v_hours := CEIL(EXTRACT(EPOCH FROM (v_end - v_start)) / 3600.0);
SELECT price
INTO v_price
FROM price_list
WHERE tariff_id = v_tariff_id
AND CURRENT_DATE BETWEEN valid_from AND valid_to
ORDER BY valid_from DESC
LIMIT 1;
IF NOT FOUND THEN
RAISE EXCEPTION 'Valid price for tariff does not exist.';
END IF;
RETURN ROUND(v_hours * v_price, 2);
END;
$function$;
Оваа функција ја пресметува вкупната цена за дадена паркинг сесија според времетраењето и важечката тарифа. Ја имплементира бизнис логиката за автоматска пресметка на наплата и се користи при ажурирање на вкупниот износ за завршена сесија.
has_active_session
CREATE OR REPLACE FUNCTION public.has_active_session(p_user_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $function$
DECLARE
v_exists BOOLEAN;
BEGIN
IF NOT EXISTS (
SELECT 1
FROM app_user
WHERE user_id = p_user_id
) THEN
RAISE EXCEPTION 'User does not exist.';
END IF;
SELECT EXISTS (
SELECT 1
FROM parking_session
WHERE user_id = p_user_id
AND end_time IS NULL
)
INTO v_exists;
RETURN v_exists;
END;
$function$;
Оваа функција проверува дали даден корисник има активна паркинг сесија, односно сесија која сè уште нема крајно време. Ја имплементира бизнис логиката за спречување на повеќе активни сесии кај ист корисник и се користи при започнување нова паркинг сесија.
trg_set_total_amount
CREATE OR REPLACE FUNCTION public.trg_set_total_amount()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
v_price NUMERIC;
v_hours NUMERIC;
BEGIN
IF NEW.end_time IS NULL THEN
NEW.total_amount := 0.00;
ELSE
IF NEW.start_time IS NULL THEN
RAISE EXCEPTION 'Start time cannot be null.';
END IF;
IF NEW.end_time <= NEW.start_time THEN
RAISE EXCEPTION 'End time must be after start time.';
END IF;
SELECT price
INTO v_price
FROM price_list
WHERE tariff_id = NEW.tariff_id
AND CURRENT_DATE BETWEEN valid_from AND valid_to
ORDER BY valid_from DESC
LIMIT 1;
IF NOT FOUND THEN
RAISE EXCEPTION 'Valid price for tariff does not exist.';
END IF;
v_hours := CEIL(EXTRACT(EPOCH FROM (NEW.end_time - NEW.start_time)) / 3600.0);
NEW.total_amount := ROUND(v_hours * v_price, 2);
END IF;
RETURN NEW;
END;
$function$;
Оваа trigger функција автоматски го поставува или пресметува вкупниот износ на паркинг сесијата при внесување или ажурирање на податоци. Ја имплементира бизнис логиката за автоматска наплата според времетраењето на сесијата и важечката тарифа.
Triggers
trg_update_total_amount
CREATE TRIGGER trg_update_total_amount BEFORE INSERT OR UPDATE OF end_time ON public.parking_session FOR EACH ROW EXECUTE FUNCTION trg_set_total_amount();
Овој trigger автоматски се активира при креирање нова паркинг сесија или при промена на крајното време на постоечка сесија. Ја имплементира бизнис логиката за автоматска пресметка на вкупниот износ за паркирање без потреба од рачна интервенција, преку повикување на trigger функцијата trg_set_total_amount().
