| 1 | ----------------------------------------------------------------------------------------funkcii--------------------------------------------------------------------
|
|---|
| 2 |
|
|---|
| 3 | -- 1. funkcija za vkupna cena za rezervacija, i plus i so equipment ako rentat, ako sakat da koristit dopolnitelen service, plus i za activities ako ima rezervacija
|
|---|
| 4 | CREATE OR REPLACE FUNCTION calculate_full_reservation_price(
|
|---|
| 5 | p_reservation_id INT
|
|---|
| 6 | )
|
|---|
| 7 | RETURNS TABLE (
|
|---|
| 8 | base_price NUMERIC,
|
|---|
| 9 | activity_price NUMERIC,
|
|---|
| 10 | equipment_price NUMERIC,
|
|---|
| 11 | service_price NUMERIC,
|
|---|
| 12 | discount_amount NUMERIC,
|
|---|
| 13 | discount_percent INT,
|
|---|
| 14 | final_price NUMERIC
|
|---|
| 15 | ) AS $$
|
|---|
| 16 | DECLARE
|
|---|
| 17 | v_base_price NUMERIC := 0;
|
|---|
| 18 | v_activity_price NUMERIC := 0;
|
|---|
| 19 | v_equipment_price NUMERIC := 0;
|
|---|
| 20 | v_service_price NUMERIC := 0;
|
|---|
| 21 | v_discount_percent INT := 0;
|
|---|
| 22 | v_discount_amount NUMERIC := 0;
|
|---|
| 23 | v_final_price NUMERIC := 0;
|
|---|
| 24 | v_campLocationId INTEGER;
|
|---|
| 25 | BEGIN
|
|---|
| 26 |
|
|---|
| 27 | SELECT total_price, CampLocationcamplocationId
|
|---|
| 28 | INTO v_base_price, v_campLocationId
|
|---|
| 29 | FROM Reservation
|
|---|
| 30 | WHERE reservationId = p_reservation_id;
|
|---|
| 31 |
|
|---|
| 32 | IF NOT FOUND THEN
|
|---|
| 33 | RAISE EXCEPTION 'Reservation with ID % does not exist!', p_reservation_id;
|
|---|
| 34 | END IF;
|
|---|
| 35 |
|
|---|
| 36 | SELECT COALESCE(SUM(total_price_for_activity), 0)
|
|---|
| 37 | INTO v_activity_price
|
|---|
| 38 | FROM ReservationActivity
|
|---|
| 39 | WHERE ReservationreservationId = p_reservation_id
|
|---|
| 40 | AND status <> 'cancelled';
|
|---|
| 41 |
|
|---|
| 42 | SELECT COALESCE(SUM(total_price), 0)
|
|---|
| 43 | INTO v_equipment_price
|
|---|
| 44 | FROM EquipmentRental
|
|---|
| 45 | WHERE ReservationreservationId = p_reservation_id
|
|---|
| 46 | AND status <> 'cancelled';
|
|---|
| 47 |
|
|---|
| 48 | SELECT COALESCE(SUM(s.additional_fee), 0)
|
|---|
| 49 | INTO v_service_price
|
|---|
| 50 | FROM camp_location_service cls
|
|---|
| 51 | JOIN Service s ON cls.ServiceserviceId = s.serviceId
|
|---|
| 52 | WHERE cls.CampLocationcampLocationId = v_campLocationId;
|
|---|
| 53 |
|
|---|
| 54 | SELECT
|
|---|
| 55 | COALESCE(p.discount_percent, 0),
|
|---|
| 56 | COALESCE(p.discount_amount, 0)
|
|---|
| 57 | INTO
|
|---|
| 58 | v_discount_percent,
|
|---|
| 59 | v_discount_amount
|
|---|
| 60 | FROM Reservation r
|
|---|
| 61 | LEFT JOIN Promotion p ON r.PromotionpromotionId = p.promotionId
|
|---|
| 62 | WHERE r.reservationId = p_reservation_id;
|
|---|
| 63 |
|
|---|
| 64 | v_final_price :=
|
|---|
| 65 | v_base_price +
|
|---|
| 66 | v_activity_price +
|
|---|
| 67 | v_equipment_price +
|
|---|
| 68 | v_service_price;
|
|---|
| 69 |
|
|---|
| 70 | IF v_discount_percent > 0 THEN
|
|---|
| 71 | v_final_price := v_final_price - (v_final_price * v_discount_percent / 100.0);
|
|---|
| 72 | END IF;
|
|---|
| 73 |
|
|---|
| 74 | IF v_discount_amount > 0 THEN
|
|---|
| 75 | v_final_price := v_final_price - v_discount_amount;
|
|---|
| 76 | END IF;
|
|---|
| 77 |
|
|---|
| 78 | IF v_final_price < 0 THEN
|
|---|
| 79 | v_final_price := 0;
|
|---|
| 80 | END IF;
|
|---|
| 81 |
|
|---|
| 82 | base_price := ROUND(v_base_price, 2);
|
|---|
| 83 | activity_price := ROUND(v_activity_price, 2);
|
|---|
| 84 | equipment_price := ROUND(v_equipment_price, 2);
|
|---|
| 85 | service_price := ROUND(v_service_price, 2);
|
|---|
| 86 | discount_amount := ROUND(v_discount_amount, 2);
|
|---|
| 87 | discount_percent := v_discount_percent;
|
|---|
| 88 | final_price := ROUND(v_final_price, 2);
|
|---|
| 89 |
|
|---|
| 90 | RETURN NEXT;
|
|---|
| 91 |
|
|---|
| 92 | END;
|
|---|
| 93 | $$ LANGUAGE plpgsql;
|
|---|
| 94 |
|
|---|
| 95 | --test
|
|---|
| 96 | SELECT * FROM calculate_full_reservation_price(2);
|
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 | -- 2. funkcija za dostapnost na camplocation za odreden period
|
|---|
| 100 | CREATE OR REPLACE FUNCTION is_camp_available(
|
|---|
| 101 | p_campLocationId INTEGER,
|
|---|
| 102 | p_check_in DATE,
|
|---|
| 103 | p_check_out DATE
|
|---|
| 104 | )
|
|---|
| 105 | RETURNS BOOLEAN AS $$
|
|---|
| 106 | DECLARE
|
|---|
| 107 | v_conflict INTEGER;
|
|---|
| 108 | v_status VARCHAR(20);
|
|---|
| 109 | BEGIN
|
|---|
| 110 |
|
|---|
| 111 | IF p_check_out <= p_check_in THEN
|
|---|
| 112 | RAISE EXCEPTION
|
|---|
| 113 | 'Check-out date must be after check-in date!';
|
|---|
| 114 | END IF;
|
|---|
| 115 |
|
|---|
| 116 | SELECT status
|
|---|
| 117 | INTO v_status
|
|---|
| 118 | FROM CampLocation
|
|---|
| 119 | WHERE campLocationId = p_campLocationId;
|
|---|
| 120 |
|
|---|
| 121 | IF NOT FOUND THEN
|
|---|
| 122 | RAISE EXCEPTION
|
|---|
| 123 | 'Camp location with ID % does not exist!',
|
|---|
| 124 | p_campLocationId;
|
|---|
| 125 | END IF;
|
|---|
| 126 |
|
|---|
| 127 | IF v_status <> 'active' THEN
|
|---|
| 128 | RETURN FALSE;
|
|---|
| 129 | END IF;
|
|---|
| 130 |
|
|---|
| 131 | SELECT COUNT(*)
|
|---|
| 132 | INTO v_conflict
|
|---|
| 133 | FROM Reservation
|
|---|
| 134 | WHERE CampLocationcamplocationId = p_campLocationId
|
|---|
| 135 | AND reservation_status IN ('pending', 'confirmed')
|
|---|
| 136 | AND check_in_date < p_check_out
|
|---|
| 137 | AND check_out_date > p_check_in;
|
|---|
| 138 |
|
|---|
| 139 | IF v_conflict > 0 THEN
|
|---|
| 140 | RETURN FALSE;
|
|---|
| 141 | END IF;
|
|---|
| 142 |
|
|---|
| 143 | RETURN TRUE;
|
|---|
| 144 |
|
|---|
| 145 | END;
|
|---|
| 146 | $$ LANGUAGE plpgsql;
|
|---|
| 147 |
|
|---|
| 148 | --test
|
|---|
| 149 | SELECT is_camp_available(11, '2026-08-18', '2026-08-21');
|
|---|
| 150 | SELECT camplocationcamplocationid, check_in_date, check_out_date, reservation_status
|
|---|
| 151 | FROM Reservation
|
|---|
| 152 | WHERE reservation_status IN ('pending', 'confirmed')
|
|---|
| 153 | LIMIT 10;
|
|---|
| 154 |
|
|---|
| 155 |
|
|---|
| 156 |
|
|---|
| 157 |
|
|---|
| 158 | ------------------------------------------------------------------------------------proceduri----------------------------------------------------------------------------------------------------------
|
|---|
| 159 |
|
|---|
| 160 | -- 1. procedura za kreiranje rezervacija
|
|---|
| 161 | CREATE OR REPLACE PROCEDURE make_reservation(
|
|---|
| 162 | p_guestUserId INTEGER,
|
|---|
| 163 | p_campLocationId INTEGER,
|
|---|
| 164 | p_check_in DATE,
|
|---|
| 165 | p_check_out DATE,
|
|---|
| 166 | p_num_guests INTEGER,
|
|---|
| 167 | p_promo_code VARCHAR(50) DEFAULT NULL
|
|---|
| 168 | )
|
|---|
| 169 | LANGUAGE plpgsql AS $$
|
|---|
| 170 | DECLARE
|
|---|
| 171 | v_min_nights INTEGER;
|
|---|
| 172 | v_max_guests INTEGER;
|
|---|
| 173 | v_nights INTEGER;
|
|---|
| 174 | v_price_per_night NUMERIC(12, 2);
|
|---|
| 175 | v_total_price NUMERIC(12, 2);
|
|---|
| 176 | v_promotionId INTEGER := NULL;
|
|---|
| 177 | v_discount NUMERIC(10, 2) := 0;
|
|---|
| 178 | v_new_res_id INTEGER;
|
|---|
| 179 | BEGIN
|
|---|
| 180 |
|
|---|
| 181 | IF NOT is_camp_available(p_campLocationId, p_check_in, p_check_out) THEN
|
|---|
| 182 | RAISE EXCEPTION 'Camp location not available for the chosen period!';
|
|---|
| 183 | END IF;
|
|---|
| 184 |
|
|---|
| 185 | SELECT min_nights_stay, max_guests
|
|---|
| 186 | INTO v_min_nights, v_max_guests
|
|---|
| 187 | FROM CampLocation
|
|---|
| 188 | WHERE campLocationId = p_campLocationId;
|
|---|
| 189 |
|
|---|
| 190 | IF p_num_guests > v_max_guests THEN
|
|---|
| 191 | RAISE EXCEPTION 'Maximum number of guests is %!', v_max_guests;
|
|---|
| 192 | END IF;
|
|---|
| 193 |
|
|---|
| 194 | SELECT ph.price_per_night
|
|---|
| 195 | INTO v_price_per_night
|
|---|
| 196 | FROM PriceHistory ph
|
|---|
| 197 | WHERE ph.CampLocationcampLocationId = p_campLocationId
|
|---|
| 198 | AND p_check_in BETWEEN ph.date_from AND ph.date_to
|
|---|
| 199 | LIMIT 1;
|
|---|
| 200 |
|
|---|
| 201 | IF v_price_per_night IS NULL THEN
|
|---|
| 202 | RAISE EXCEPTION 'There is no active price for the chosen camp location!';
|
|---|
| 203 | END IF;
|
|---|
| 204 |
|
|---|
| 205 | v_nights := p_check_out - p_check_in;
|
|---|
| 206 | v_total_price := v_nights * v_price_per_night;
|
|---|
| 207 |
|
|---|
| 208 | IF p_promo_code IS NOT NULL THEN
|
|---|
| 209 | SELECT p.promotionId,
|
|---|
| 210 | COALESCE(p.discount_amount, 0) +
|
|---|
| 211 | COALESCE(v_total_price * p.discount_percent / 100.0, 0)
|
|---|
| 212 | INTO v_promotionId, v_discount
|
|---|
| 213 | FROM Promotion p
|
|---|
| 214 | WHERE p.promo_code = p_promo_code
|
|---|
| 215 | AND p.valid_from <= CURRENT_DATE
|
|---|
| 216 | AND p.valid_to >= CURRENT_DATE
|
|---|
| 217 | LIMIT 1;
|
|---|
| 218 |
|
|---|
| 219 | IF NOT FOUND THEN
|
|---|
| 220 | RAISE EXCEPTION 'The promo code "%" is not valid or is expired!', p_promo_code;
|
|---|
| 221 | END IF;
|
|---|
| 222 | END IF;
|
|---|
| 223 |
|
|---|
| 224 | v_total_price := GREATEST(v_total_price - v_discount, 0);
|
|---|
| 225 |
|
|---|
| 226 | INSERT INTO Reservation (
|
|---|
| 227 | GuestUseruserId,
|
|---|
| 228 | CampLocationcamplocationId,
|
|---|
| 229 | PromotionpromotionId,
|
|---|
| 230 | number_of_guests,
|
|---|
| 231 | reservation_status,
|
|---|
| 232 | check_in_date,
|
|---|
| 233 | check_out_date,
|
|---|
| 234 | created_at,
|
|---|
| 235 | total_price
|
|---|
| 236 | )
|
|---|
| 237 | VALUES (
|
|---|
| 238 | p_guestUserId,
|
|---|
| 239 | p_campLocationId,
|
|---|
| 240 | v_promotionId,
|
|---|
| 241 | p_num_guests,
|
|---|
| 242 | 'pending',
|
|---|
| 243 | p_check_in,
|
|---|
| 244 | p_check_out,
|
|---|
| 245 | LEAST(CURRENT_DATE, p_check_in - 1),
|
|---|
| 246 | v_total_price
|
|---|
| 247 | )
|
|---|
| 248 | RETURNING reservationId INTO v_new_res_id;
|
|---|
| 249 |
|
|---|
| 250 | RAISE NOTICE 'Reservation is successfully created! ID: %, Total price: % EUR',
|
|---|
| 251 | v_new_res_id, v_total_price;
|
|---|
| 252 |
|
|---|
| 253 | COMMIT;
|
|---|
| 254 | END;
|
|---|
| 255 | $$;
|
|---|
| 256 |
|
|---|
| 257 | --test
|
|---|
| 258 | --guest
|
|---|
| 259 | SELECT user_id FROM "User" WHERE type = 'guest' LIMIT 5;
|
|---|
| 260 | --camplocation
|
|---|
| 261 | SELECT campLocationId, min_nights_stay, max_guests FROM CampLocation LIMIT 5;
|
|---|
| 262 | --za price vo toj period
|
|---|
| 263 | SELECT * FROM PriceHistory WHERE CampLocationcampLocationId = 1 LIMIT 5;
|
|---|
| 264 |
|
|---|
| 265 | CALL make_reservation(
|
|---|
| 266 | 423,
|
|---|
| 267 | 1,
|
|---|
| 268 | '2023-04-11',
|
|---|
| 269 | '2023-05-01',
|
|---|
| 270 | 2,
|
|---|
| 271 | NULL
|
|---|
| 272 | );
|
|---|
| 273 |
|
|---|
| 274 |
|
|---|
| 275 | -- 2. procedura za dodavanje promotion_code
|
|---|
| 276 | CREATE OR REPLACE PROCEDURE add_promotion(
|
|---|
| 277 | p_hostUserId INTEGER,
|
|---|
| 278 | p_promo_code VARCHAR(50),
|
|---|
| 279 | p_valid_from DATE,
|
|---|
| 280 | p_valid_to DATE,
|
|---|
| 281 | p_discount_amount NUMERIC(10,2) DEFAULT 0,
|
|---|
| 282 | p_discount_percent NUMERIC(5,2) DEFAULT 0
|
|---|
| 283 | )
|
|---|
| 284 | LANGUAGE plpgsql AS $$
|
|---|
| 285 | BEGIN
|
|---|
| 286 |
|
|---|
| 287 | IF NOT EXISTS (SELECT 1 FROM Host WHERE UseruserId = p_hostUserId) THEN
|
|---|
| 288 | RAISE EXCEPTION 'Host with ID % does not exist!', p_hostUserId;
|
|---|
| 289 | END IF;
|
|---|
| 290 |
|
|---|
| 291 | IF EXISTS (SELECT 1 FROM Promotion WHERE promo_code = p_promo_code) THEN
|
|---|
| 292 | RAISE EXCEPTION 'Promo code "%" already exists!', p_promo_code;
|
|---|
| 293 | END IF;
|
|---|
| 294 |
|
|---|
| 295 | IF p_valid_from > p_valid_to THEN
|
|---|
| 296 | RAISE EXCEPTION 'Invalid date range: valid_from > valid_to!';
|
|---|
| 297 | END IF;
|
|---|
| 298 |
|
|---|
| 299 | IF p_discount_percent = 0 AND p_discount_amount = 0 THEN
|
|---|
| 300 | RAISE EXCEPTION 'At least one discount must be provided!';
|
|---|
| 301 | END IF;
|
|---|
| 302 |
|
|---|
| 303 | IF p_discount_percent < 0 OR p_discount_percent > 100 THEN
|
|---|
| 304 | RAISE EXCEPTION 'Discount percent must be between 0 and 100!';
|
|---|
| 305 | END IF;
|
|---|
| 306 |
|
|---|
| 307 | IF p_discount_amount < 0 THEN
|
|---|
| 308 | RAISE EXCEPTION 'Discount amount cannot be negative!';
|
|---|
| 309 | END IF;
|
|---|
| 310 |
|
|---|
| 311 | INSERT INTO Promotion (
|
|---|
| 312 | HostUserUserId,
|
|---|
| 313 | promo_code,
|
|---|
| 314 | discount_amount,
|
|---|
| 315 | discount_percent,
|
|---|
| 316 | valid_from,
|
|---|
| 317 | valid_to
|
|---|
| 318 | )
|
|---|
| 319 | VALUES (
|
|---|
| 320 | p_hostUserId,
|
|---|
| 321 | p_promo_code,
|
|---|
| 322 | p_discount_amount,
|
|---|
| 323 | p_discount_percent,
|
|---|
| 324 | p_valid_from,
|
|---|
| 325 | p_valid_to
|
|---|
| 326 | );
|
|---|
| 327 |
|
|---|
| 328 | RAISE NOTICE 'Promotion "%" successfully created!', p_promo_code;
|
|---|
| 329 |
|
|---|
| 330 | COMMIT;
|
|---|
| 331 | END;
|
|---|
| 332 | $$;
|
|---|
| 333 |
|
|---|
| 334 | --test
|
|---|
| 335 | SELECT UseruserId FROM Host LIMIT 5;
|
|---|
| 336 | CALL add_promotion(
|
|---|
| 337 | 634,
|
|---|
| 338 | 'SUMMER2026',
|
|---|
| 339 | '2026-01-01',
|
|---|
| 340 | '2026-12-31',
|
|---|
| 341 | 0,
|
|---|
| 342 | 10
|
|---|
| 343 | );
|
|---|
| 344 | CALL add_promotion(
|
|---|
| 345 | 634,
|
|---|
| 346 | 'SUMMER2026v2',
|
|---|
| 347 | '2026-01-01',
|
|---|
| 348 | '2026-12-31',
|
|---|
| 349 | 30,
|
|---|
| 350 | 0
|
|---|
| 351 | );
|
|---|
| 352 | --ist promo code
|
|---|
| 353 | CALL add_promotion(
|
|---|
| 354 | 634,
|
|---|
| 355 | 'SUMMER2026',
|
|---|
| 356 | '2026-01-01',
|
|---|
| 357 | '2026-12-31',
|
|---|
| 358 | 0,
|
|---|
| 359 | 100
|
|---|
| 360 | );
|
|---|
| 361 | --bez discount_amount i discount_percent
|
|---|
| 362 | CALL add_promotion(
|
|---|
| 363 | 634,
|
|---|
| 364 | 'SUMMER2026_promotion',
|
|---|
| 365 | '2026-01-01',
|
|---|
| 366 | '2026-12-31',
|
|---|
| 367 | 0,
|
|---|
| 368 | 0
|
|---|
| 369 | );
|
|---|
| 370 |
|
|---|
| 371 |
|
|---|
| 372 | -- 3. procedura za iznajmuvanje equipment za postoecka rezervacija
|
|---|
| 373 | CREATE OR REPLACE PROCEDURE rent_equipment(
|
|---|
| 374 | p_reservationId INTEGER,
|
|---|
| 375 | p_equipmentId INTEGER,
|
|---|
| 376 | p_start_date DATE,
|
|---|
| 377 | p_end_date DATE,
|
|---|
| 378 | p_quantity INTEGER
|
|---|
| 379 | )
|
|---|
| 380 | LANGUAGE plpgsql AS $$
|
|---|
| 381 | DECLARE
|
|---|
| 382 | v_price_per_day NUMERIC(10,2);
|
|---|
| 383 | v_deposit NUMERIC(10,2);
|
|---|
| 384 | v_available_qty INTEGER;
|
|---|
| 385 | v_days INTEGER;
|
|---|
| 386 | v_total_price NUMERIC(10,2);
|
|---|
| 387 | v_res_status VARCHAR(20);
|
|---|
| 388 | BEGIN
|
|---|
| 389 |
|
|---|
| 390 | SELECT reservation_status
|
|---|
| 391 | INTO v_res_status
|
|---|
| 392 | FROM Reservation
|
|---|
| 393 | WHERE reservationId = p_reservationId;
|
|---|
| 394 |
|
|---|
| 395 | IF NOT FOUND THEN
|
|---|
| 396 | RAISE EXCEPTION 'Reservation with ID % does not exist!', p_reservationId;
|
|---|
| 397 | END IF;
|
|---|
| 398 |
|
|---|
| 399 | IF v_res_status NOT IN ('pending', 'confirmed') THEN
|
|---|
| 400 | RAISE EXCEPTION 'Cannot rent equipment for reservation with status: %', v_res_status;
|
|---|
| 401 | END IF;
|
|---|
| 402 |
|
|---|
| 403 | SELECT rental_price_per_day, deposit_amount, available_quantity
|
|---|
| 404 | INTO v_price_per_day, v_deposit, v_available_qty
|
|---|
| 405 | FROM Equipment
|
|---|
| 406 | WHERE equipmentId = p_equipmentId;
|
|---|
| 407 |
|
|---|
| 408 | IF NOT FOUND THEN
|
|---|
| 409 | RAISE EXCEPTION 'Equipment with ID % does not exist!', p_equipmentId;
|
|---|
| 410 | END IF;
|
|---|
| 411 |
|
|---|
| 412 | IF p_quantity > v_available_qty THEN
|
|---|
| 413 | RAISE EXCEPTION 'Not enough equipment available! Requested: %, Available: %',
|
|---|
| 414 | p_quantity, v_available_qty;
|
|---|
| 415 | END IF;
|
|---|
| 416 |
|
|---|
| 417 | IF p_start_date >= p_end_date THEN
|
|---|
| 418 | RAISE EXCEPTION 'Invalid rental period: end date must be after start date!';
|
|---|
| 419 | END IF;
|
|---|
| 420 |
|
|---|
| 421 | v_days := p_end_date - p_start_date;
|
|---|
| 422 | v_total_price := v_days * v_price_per_day * p_quantity;
|
|---|
| 423 |
|
|---|
| 424 | INSERT INTO EquipmentRental (
|
|---|
| 425 | EquipmentequipmentId,
|
|---|
| 426 | ReservationreservationId,
|
|---|
| 427 | quantity,
|
|---|
| 428 | start_date,
|
|---|
| 429 | end_date,
|
|---|
| 430 | total_price,
|
|---|
| 431 | deposit_paid,
|
|---|
| 432 | status
|
|---|
| 433 | )
|
|---|
| 434 | VALUES (
|
|---|
| 435 | p_equipmentId,
|
|---|
| 436 | p_reservationId,
|
|---|
| 437 | p_quantity,
|
|---|
| 438 | p_start_date,
|
|---|
| 439 | p_end_date,
|
|---|
| 440 | v_total_price,
|
|---|
| 441 | v_deposit * p_quantity,
|
|---|
| 442 | 'active'
|
|---|
| 443 | );
|
|---|
| 444 |
|
|---|
| 445 | UPDATE Equipment
|
|---|
| 446 | SET available_quantity = available_quantity - p_quantity
|
|---|
| 447 | WHERE equipmentId = p_equipmentId;
|
|---|
| 448 |
|
|---|
| 449 | RAISE NOTICE 'Equipment rented successfully. Total: % EUR', v_total_price;
|
|---|
| 450 |
|
|---|
| 451 | COMMIT;
|
|---|
| 452 | END;
|
|---|
| 453 | $$;
|
|---|
| 454 |
|
|---|
| 455 | --test
|
|---|
| 456 | SELECT equipmentId, available_quantity, rental_price_per_day FROM Equipment
|
|---|
| 457 | WHERE available_quantity > 0 LIMIT 5;
|
|---|
| 458 |
|
|---|
| 459 | SELECT reservationId FROM Reservation
|
|---|
| 460 | WHERE reservation_status IN ('pending', 'confirmed')
|
|---|
| 461 | LIMIT 5;
|
|---|
| 462 |
|
|---|
| 463 | CALL rent_equipment(
|
|---|
| 464 | 2,
|
|---|
| 465 | 2,
|
|---|
| 466 | '2026-06-01',
|
|---|
| 467 | '2026-06-05',
|
|---|
| 468 | 2
|
|---|
| 469 | );
|
|---|
| 470 |
|
|---|
| 471 | SELECT equipmentId, available_quantity
|
|---|
| 472 | FROM Equipment
|
|---|
| 473 | WHERE equipmentId = 2;
|
|---|
| 474 |
|
|---|
| 475 | --4. procedura za koga kje se vrati equipmentrental, da se promeni statusot 'rented' -> 'returned' i da se zgolemi available_quantity na equipment
|
|---|
| 476 | CREATE OR REPLACE PROCEDURE return_equipment(
|
|---|
| 477 | p_equipmentRentalId INTEGER
|
|---|
| 478 | )
|
|---|
| 479 | LANGUAGE plpgsql AS $$
|
|---|
| 480 | DECLARE
|
|---|
| 481 | v_equipmentId INTEGER;
|
|---|
| 482 | v_quantity INTEGER;
|
|---|
| 483 | v_status VARCHAR(20);
|
|---|
| 484 | BEGIN
|
|---|
| 485 | SELECT EquipmentequipmentId, quantity, status
|
|---|
| 486 | INTO v_equipmentId, v_quantity, v_status
|
|---|
| 487 | FROM EquipmentRental
|
|---|
| 488 | WHERE equipmentrentalid = p_equipmentRentalId;
|
|---|
| 489 |
|
|---|
| 490 | IF NOT FOUND THEN
|
|---|
| 491 | RAISE EXCEPTION 'Equipment rental with ID % does not exist!', p_equipmentRentalId;
|
|---|
| 492 | END IF;
|
|---|
| 493 |
|
|---|
| 494 | IF v_status = 'returned' THEN
|
|---|
| 495 | RAISE EXCEPTION 'Equipment is already returned!';
|
|---|
| 496 | END IF;
|
|---|
| 497 |
|
|---|
| 498 | UPDATE EquipmentRental
|
|---|
| 499 | SET status = 'returned'
|
|---|
| 500 | WHERE equipmentrentalid = p_equipmentRentalId;
|
|---|
| 501 |
|
|---|
| 502 | UPDATE Equipment
|
|---|
| 503 | SET available_quantity = LEAST(available_quantity + v_quantity, total_quantity)
|
|---|
| 504 | WHERE equipmentId = v_equipmentId;
|
|---|
| 505 |
|
|---|
| 506 | RAISE NOTICE 'Equipment ID % returned successfully. Quantity restored: %.',
|
|---|
| 507 | v_equipmentId, v_quantity;
|
|---|
| 508 |
|
|---|
| 509 | COMMIT;
|
|---|
| 510 | END;
|
|---|
| 511 | $$;
|
|---|
| 512 |
|
|---|
| 513 | --test
|
|---|
| 514 | SELECT er.equipmentrentalid, er.EquipmentequipmentId, er.quantity, e.available_quantity, e.total_quantity
|
|---|
| 515 | FROM EquipmentRental er
|
|---|
| 516 | JOIN Equipment e ON e.equipmentId = er.EquipmentequipmentId
|
|---|
| 517 | WHERE er.status = 'active'
|
|---|
| 518 | AND e.available_quantity < e.total_quantity
|
|---|
| 519 | LIMIT 5;
|
|---|
| 520 | --equipmentrentalId=35,equipmentId=36, quantity=2
|
|---|
| 521 | --quantity pred e 0
|
|---|
| 522 | SELECT equipmentId, available_quantity
|
|---|
| 523 | FROM Equipment
|
|---|
| 524 | WHERE equipmentId = 36;
|
|---|
| 525 | ---
|
|---|
| 526 | CALL return_equipment(35);
|
|---|
| 527 | --proverk posle, quantity se zgolemi za 2
|
|---|
| 528 | SELECT equipmentId, available_quantity, total_quantity
|
|---|
| 529 | FROM Equipment
|
|---|
| 530 | WHERE equipmentId = 36;
|
|---|
| 531 | --proverka na status
|
|---|
| 532 | SELECT equipmentrentalid, status
|
|---|
| 533 | FROM EquipmentRental
|
|---|
| 534 | WHERE equipmentrentalid = 35;
|
|---|
| 535 |
|
|---|
| 536 |
|
|---|
| 537 | --5. procedura za da se zgolemi num_reservations koga kje se kreira nova rezervacija kaj Guest
|
|---|
| 538 | CREATE OR REPLACE PROCEDURE add_reservation_count(
|
|---|
| 539 | p_guestUserId INTEGER
|
|---|
| 540 | )
|
|---|
| 541 | LANGUAGE plpgsql AS $$
|
|---|
| 542 | DECLARE
|
|---|
| 543 | v_current_count INTEGER;
|
|---|
| 544 | BEGIN
|
|---|
| 545 | IF NOT EXISTS (SELECT 1 FROM Guest WHERE UseruserId = p_guestUserId) THEN
|
|---|
| 546 | RAISE EXCEPTION 'Guest with ID % does not exist!', p_guestUserId;
|
|---|
| 547 | END IF;
|
|---|
| 548 |
|
|---|
| 549 | SELECT num_reservations
|
|---|
| 550 | INTO v_current_count
|
|---|
| 551 | FROM Guest
|
|---|
| 552 | WHERE UseruserId = p_guestUserId;
|
|---|
| 553 |
|
|---|
| 554 | UPDATE Guest
|
|---|
| 555 | SET num_reservations = num_reservations + 1
|
|---|
| 556 | WHERE UseruserId = p_guestUserId;
|
|---|
| 557 |
|
|---|
| 558 | RAISE NOTICE 'Guest % reservation count updated from % to %.',
|
|---|
| 559 | p_guestUserId, v_current_count, v_current_count + 1;
|
|---|
| 560 |
|
|---|
| 561 | COMMIT;
|
|---|
| 562 | END;
|
|---|
| 563 | $$;
|
|---|
| 564 |
|
|---|
| 565 | --test
|
|---|
| 566 | SELECT UseruserId, num_reservations
|
|---|
| 567 | FROM Guest
|
|---|
| 568 | WHERE UseruserId = 1663;
|
|---|
| 569 | --num_reservations=22
|
|---|
| 570 |
|
|---|
| 571 | CALL add_reservation_count(1663);
|
|---|
| 572 |
|
|---|
| 573 | SELECT UseruserId, num_reservations
|
|---|
| 574 | FROM Guest
|
|---|
| 575 | WHERE UseruserId = 1663;
|
|---|
| 576 | --num_reservations=23
|
|---|
| 577 |
|
|---|
| 578 |
|
|---|
| 579 |
|
|---|
| 580 | --6.
|
|---|
| 581 | CREATE OR REPLACE PROCEDURE refund_payment(
|
|---|
| 582 | p_paymentId INTEGER,
|
|---|
| 583 | p_refund_amount NUMERIC(12,2) DEFAULT NULL
|
|---|
| 584 | )
|
|---|
| 585 | LANGUAGE plpgsql AS $$
|
|---|
| 586 | DECLARE
|
|---|
| 587 | v_payment_status VARCHAR(30);
|
|---|
| 588 | v_amount NUMERIC(12,2);
|
|---|
| 589 | v_reservationId INTEGER;
|
|---|
| 590 | v_reservation_status VARCHAR(20);
|
|---|
| 591 | v_refund_amount NUMERIC(12,2);
|
|---|
| 592 | BEGIN
|
|---|
| 593 | SELECT payment_status, amount, ReservationreservationId
|
|---|
| 594 | INTO v_payment_status, v_amount, v_reservationId
|
|---|
| 595 | FROM Payment
|
|---|
| 596 | WHERE paymentId = p_paymentId;
|
|---|
| 597 |
|
|---|
| 598 | IF NOT FOUND THEN
|
|---|
| 599 | RAISE EXCEPTION 'Payment with ID % does not exist!', p_paymentId;
|
|---|
| 600 | END IF;
|
|---|
| 601 |
|
|---|
| 602 | IF v_payment_status NOT IN ('completed', 'partially_refunded') THEN
|
|---|
| 603 | RAISE EXCEPTION 'Payment with status "%" cannot be refunded!', v_payment_status;
|
|---|
| 604 | END IF;
|
|---|
| 605 |
|
|---|
| 606 | SELECT reservation_status
|
|---|
| 607 | INTO v_reservation_status
|
|---|
| 608 | FROM Reservation
|
|---|
| 609 | WHERE reservationId = v_reservationId;
|
|---|
| 610 |
|
|---|
| 611 | IF v_reservation_status != 'cancelled' THEN
|
|---|
| 612 | RAISE EXCEPTION 'Refund is only allowed for cancelled reservations!';
|
|---|
| 613 | END IF;
|
|---|
| 614 |
|
|---|
| 615 | IF p_refund_amount IS NULL THEN
|
|---|
| 616 | v_refund_amount := v_amount;
|
|---|
| 617 | ELSE
|
|---|
| 618 | v_refund_amount := p_refund_amount;
|
|---|
| 619 | END IF;
|
|---|
| 620 |
|
|---|
| 621 | IF v_refund_amount > v_amount THEN
|
|---|
| 622 | RAISE EXCEPTION 'Refund amount (%) cannot exceed payment amount (%)!',
|
|---|
| 623 | v_refund_amount, v_amount;
|
|---|
| 624 | END IF;
|
|---|
| 625 |
|
|---|
| 626 | IF v_refund_amount <= 0 THEN
|
|---|
| 627 | RAISE EXCEPTION 'Refund amount must be greater than 0!';
|
|---|
| 628 | END IF;
|
|---|
| 629 |
|
|---|
| 630 | UPDATE Payment
|
|---|
| 631 | SET payment_status = CASE
|
|---|
| 632 | WHEN v_refund_amount = v_amount THEN 'refunded'
|
|---|
| 633 | ELSE 'partially_refunded'
|
|---|
| 634 | END
|
|---|
| 635 | WHERE paymentId = p_paymentId;
|
|---|
| 636 |
|
|---|
| 637 | UPDATE ReservationStatus
|
|---|
| 638 | SET refund_amount = v_refund_amount,
|
|---|
| 639 | cancellation_date = CURRENT_DATE
|
|---|
| 640 | WHERE ReservationreservationId = v_reservationId;
|
|---|
| 641 |
|
|---|
| 642 | RAISE NOTICE 'Payment % refunded successfully. Refund amount: % EUR.',
|
|---|
| 643 | p_paymentId, v_refund_amount;
|
|---|
| 644 |
|
|---|
| 645 | COMMIT;
|
|---|
| 646 | END;
|
|---|
| 647 | $$;
|
|---|
| 648 |
|
|---|
| 649 | --test
|
|---|
| 650 | SELECT p.paymentId, p.amount, p.payment_status, r.reservation_status
|
|---|
| 651 | FROM Payment p
|
|---|
| 652 | JOIN Reservation r ON r.reservationId = p.ReservationreservationId
|
|---|
| 653 | WHERE r.reservation_status = 'cancelled'
|
|---|
| 654 | AND p.payment_status = 'completed'
|
|---|
| 655 | LIMIT 5;
|
|---|
| 656 | --paymentId=156, amount 317
|
|---|
| 657 | CALL refund_payment(156);
|
|---|
| 658 | --proverka na status
|
|---|
| 659 | SELECT paymentId, amount, payment_status
|
|---|
| 660 | FROM Payment
|
|---|
| 661 | WHERE paymentId = 156;
|
|---|
| 662 | -- proveri refund_amount vo ReservationStatus
|
|---|
| 663 | SELECT rs.ReservationreservationId, rs.refund_amount, rs.cancellation_date
|
|---|
| 664 | FROM ReservationStatus rs
|
|---|
| 665 | JOIN Payment p ON p.ReservationreservationId = rs.ReservationreservationId
|
|---|
| 666 | WHERE p.paymentId = 156;
|
|---|
| 667 |
|
|---|
| 668 | -------------------------------------------------------------------------------------trigeri-----------------------------------------------------------------------------------------------------------
|
|---|
| 669 | -- 1. triger za avtomatsko azuriranje na average rating na Host, koga kje se vnese review se presmetuva nov average rating za Host
|
|---|
| 670 |
|
|---|
| 671 | CREATE OR REPLACE FUNCTION update_host_rating()
|
|---|
| 672 | RETURNS TRIGGER AS $$
|
|---|
| 673 | DECLARE
|
|---|
| 674 | v_host_id INTEGER;
|
|---|
| 675 | v_avg NUMERIC(3,2);
|
|---|
| 676 | BEGIN
|
|---|
| 677 | SELECT h.HostUseruserid
|
|---|
| 678 | INTO v_host_id
|
|---|
| 679 | FROM Host_Host h
|
|---|
| 680 | WHERE h.CampLocationcampLocationId = NEW.CampLocationcampLocationId
|
|---|
| 681 | LIMIT 1;
|
|---|
| 682 |
|
|---|
| 683 | SELECT ROUND(AVG(r.rating), 2)
|
|---|
| 684 | INTO v_avg
|
|---|
| 685 | FROM Review r
|
|---|
| 686 | WHERE r.CampLocationcampLocationId = NEW.CampLocationcampLocationId;
|
|---|
| 687 |
|
|---|
| 688 | UPDATE Host
|
|---|
| 689 | SET average_score = v_avg
|
|---|
| 690 | WHERE UseruserId = v_host_id;
|
|---|
| 691 |
|
|---|
| 692 | REFRESH MATERIALIZED VIEW view_camp_avg_rating;
|
|---|
| 693 |
|
|---|
| 694 | RAISE NOTICE 'Host % average score updated to %. Materialized view refreshed.',
|
|---|
| 695 | v_host_id, v_avg;
|
|---|
| 696 |
|
|---|
| 697 | RETURN NEW;
|
|---|
| 698 | END;
|
|---|
| 699 | $$ LANGUAGE plpgsql;
|
|---|
| 700 |
|
|---|
| 701 |
|
|---|
| 702 | CREATE TRIGGER trg_update_host_rating
|
|---|
| 703 | AFTER INSERT ON Review
|
|---|
| 704 | FOR EACH ROW
|
|---|
| 705 | EXECUTE FUNCTION update_host_rating();
|
|---|
| 706 |
|
|---|
| 707 | --test
|
|---|
| 708 | --barame camp sho imat reviews
|
|---|
| 709 | SELECT CampLocationcampLocationId, COUNT(*), AVG(rating)
|
|---|
| 710 | FROM Review
|
|---|
| 711 | GROUP BY CampLocationcampLocationId
|
|---|
| 712 | LIMIT 5;
|
|---|
| 713 | --barame current host rating
|
|---|
| 714 | SELECT UseruserId, average_score
|
|---|
| 715 | FROM Host
|
|---|
| 716 | WHERE UseruserId = (
|
|---|
| 717 | SELECT HostUseruserid
|
|---|
| 718 | FROM Host_Host
|
|---|
| 719 | WHERE CampLocationcampLocationId = 39224
|
|---|
| 720 | limit 1
|
|---|
| 721 | );
|
|---|
| 722 | --avg_score e 4
|
|---|
| 723 | INSERT INTO Review (
|
|---|
| 724 | guestuseruserid,
|
|---|
| 725 | CampLocationcampLocationId,
|
|---|
| 726 | review_date,
|
|---|
| 727 | comment,
|
|---|
| 728 | rating
|
|---|
| 729 | )
|
|---|
| 730 | VALUES (
|
|---|
| 731 | 1663,
|
|---|
| 732 | 39224,
|
|---|
| 733 | CURRENT_DATE,
|
|---|
| 734 | 'Great experience!',
|
|---|
| 735 | 5
|
|---|
| 736 | );
|
|---|
| 737 | --sega avg_score e 3
|
|---|
| 738 | SELECT UseruserId, average_score
|
|---|
| 739 | FROM Host
|
|---|
| 740 | WHERE UseruserId = (
|
|---|
| 741 | SELECT HostUseruserid
|
|---|
| 742 | FROM Host_Host
|
|---|
| 743 | WHERE CampLocationcampLocationId = 39224
|
|---|
| 744 | limit 1
|
|---|
| 745 | ); |
|---|