| | 1 | = Програмирање на базата на податоци |
| | 2 | |
| | 3 | == Функции |
| | 4 | |
| | 5 | === `get_customer_ticket_summary` |
| | 6 | |
| | 7 | Оваа функција враќа детален преглед за билетите на одреден корисник, прикажувајќи колку вкупно билети има купено, колку од нив се single или pass билети, како и вкупната сума што ја има потрошено преку успешно реализирани плаќања. |
| | 8 | |
| | 9 | {{{ |
| | 10 | |
| | 11 | CREATE OR REPLACE FUNCTION get_customer_ticket_summary(p_customer_id BIGINT) |
| | 12 | RETURNS TABLE ( |
| | 13 | customer_id BIGINT, |
| | 14 | total_tickets BIGINT, |
| | 15 | single_tickets BIGINT, |
| | 16 | pass_tickets BIGINT, |
| | 17 | total_spent NUMERIC |
| | 18 | ) |
| | 19 | LANGUAGE plpgsql |
| | 20 | AS $$ |
| | 21 | BEGIN |
| | 22 | IF NOT EXISTS ( |
| | 23 | SELECT 1 |
| | 24 | FROM Customer c |
| | 25 | WHERE c.user_id = p_customer_id |
| | 26 | ) THEN |
| | 27 | RAISE EXCEPTION 'Customer with id % does not exist.', p_customer_id; |
| | 28 | END IF; |
| | 29 | |
| | 30 | RETURN QUERY |
| | 31 | SELECT |
| | 32 | c.user_id AS customer_id, |
| | 33 | COUNT(DISTINCT t.ticket_id) AS total_tickets, |
| | 34 | COUNT(DISTINCT st.ticket_id) AS single_tickets, |
| | 35 | COUNT(DISTINCT pt.ticket_id) AS pass_tickets, |
| | 36 | COALESCE( |
| | 37 | SUM( |
| | 38 | CASE |
| | 39 | WHEN p.status = 'Completed'::payment_status |
| | 40 | THEN COALESCE(st.amount, pass.amount, 0) |
| | 41 | ELSE 0 |
| | 42 | END |
| | 43 | ), |
| | 44 | 0 |
| | 45 | )::NUMERIC AS total_spent |
| | 46 | FROM Customer c |
| | 47 | LEFT JOIN Ticket t |
| | 48 | ON c.user_id = t.user_id |
| | 49 | LEFT JOIN Single_ticket st |
| | 50 | ON t.ticket_id = st.ticket_id |
| | 51 | LEFT JOIN Pass_ticket pt |
| | 52 | ON t.ticket_id = pt.ticket_id |
| | 53 | LEFT JOIN Pass_type pass |
| | 54 | ON pt.type_id = pass.id |
| | 55 | LEFT JOIN Customer_Payment_Ticket cpt |
| | 56 | ON t.ticket_id = cpt.ticket_id |
| | 57 | AND c.user_id = cpt.user_id |
| | 58 | LEFT JOIN Payment p |
| | 59 | ON cpt.payment_id = p.payment_id |
| | 60 | WHERE c.user_id = p_customer_id |
| | 61 | GROUP BY c.user_id; |
| | 62 | END; |
| | 63 | $$; |
| | 64 | |
| | 65 | }}} |
| | 66 | |
| | 67 | === `is_ticket_valid` |
| | 68 | |
| | 69 | Оваа функција служи за проверка дали даден билет е валиден за користење односно дали е платен и активен според неговиот тип (single или pass) и условите за важност. |
| | 70 | |
| | 71 | {{{ |
| | 72 | |
| | 73 | CREATE OR REPLACE FUNCTION is_ticket_valid( |
| | 74 | p_ticket_id BIGINT, |
| | 75 | p_assignment_id BIGINT |
| | 76 | ) |
| | 77 | RETURNS BOOLEAN |
| | 78 | LANGUAGE plpgsql |
| | 79 | AS $$ |
| | 80 | DECLARE |
| | 81 | v_is_valid BOOLEAN; |
| | 82 | BEGIN |
| | 83 | IF NOT EXISTS ( |
| | 84 | SELECT 1 |
| | 85 | FROM Ticket t |
| | 86 | WHERE t.ticket_id = p_ticket_id |
| | 87 | ) THEN |
| | 88 | RAISE EXCEPTION 'Ticket with id % does not exist.', p_ticket_id; |
| | 89 | END IF; |
| | 90 | |
| | 91 | SELECT |
| | 92 | EXISTS ( |
| | 93 | SELECT 1 |
| | 94 | FROM Single_ticket st |
| | 95 | JOIN Customer_Payment_Ticket cpt |
| | 96 | ON st.ticket_id = cpt.ticket_id |
| | 97 | JOIN Payment p |
| | 98 | ON cpt.payment_id = p.payment_id |
| | 99 | WHERE st.ticket_id = p_ticket_id |
| | 100 | AND st.assignment_id = p_assignment_id |
| | 101 | AND p.status = 'Completed'::payment_status |
| | 102 | ) |
| | 103 | OR |
| | 104 | EXISTS ( |
| | 105 | SELECT 1 |
| | 106 | FROM Pass_ticket pt |
| | 107 | JOIN Pass_type pass |
| | 108 | ON pt.type_id = pass.id |
| | 109 | JOIN Customer_Payment_Ticket cpt |
| | 110 | ON pt.ticket_id = cpt.ticket_id |
| | 111 | JOIN Payment p |
| | 112 | ON cpt.payment_id = p.payment_id |
| | 113 | WHERE pt.ticket_id = p_ticket_id |
| | 114 | AND p.status = 'Completed'::payment_status |
| | 115 | AND CURRENT_DATE BETWEEN pass.valid_from AND pass.valid_until |
| | 116 | ) |
| | 117 | INTO v_is_valid; |
| | 118 | |
| | 119 | RETURN v_is_valid; |
| | 120 | END; |
| | 121 | $$; |
| | 122 | |
| | 123 | }}} |
| | 124 | |
| | 125 | === `get_customer_monthly_spending` |
| | 126 | |
| | 127 | Оваа функција служи за пресметување на вкупната сума што одреден клиент ја има потрошено во даден месец за сите успешно завршени плаќања за билети (single или pass). |
| | 128 | |
| | 129 | {{{ |
| | 130 | |
| | 131 | CREATE OR REPLACE FUNCTION get_customer_monthly_spending( |
| | 132 | p_customer_id BIGINT, |
| | 133 | p_month DATE |
| | 134 | ) |
| | 135 | RETURNS NUMERIC |
| | 136 | LANGUAGE plpgsql |
| | 137 | AS $$ |
| | 138 | DECLARE |
| | 139 | v_month_start DATE; |
| | 140 | v_month_end DATE; |
| | 141 | v_total NUMERIC; |
| | 142 | BEGIN |
| | 143 | IF NOT EXISTS ( |
| | 144 | SELECT 1 |
| | 145 | FROM Customer c |
| | 146 | WHERE c.user_id = p_customer_id |
| | 147 | ) THEN |
| | 148 | RAISE EXCEPTION 'Customer with id % does not exist.', p_customer_id; |
| | 149 | END IF; |
| | 150 | |
| | 151 | v_month_start := date_trunc('month', p_month)::date; |
| | 152 | v_month_end := (v_month_start + INTERVAL '1 month')::date; |
| | 153 | |
| | 154 | SELECT |
| | 155 | COALESCE(SUM(COALESCE(st.amount, pass.amount, 0)), 0) |
| | 156 | INTO v_total |
| | 157 | FROM Customer_Payment_Ticket cpt |
| | 158 | JOIN Payment p |
| | 159 | ON cpt.payment_id = p.payment_id |
| | 160 | JOIN Ticket t |
| | 161 | ON cpt.ticket_id = t.ticket_id |
| | 162 | LEFT JOIN Single_ticket st |
| | 163 | ON t.ticket_id = st.ticket_id |
| | 164 | LEFT JOIN Pass_ticket pt |
| | 165 | ON t.ticket_id = pt.ticket_id |
| | 166 | LEFT JOIN Pass_type pass |
| | 167 | ON pt.type_id = pass.id |
| | 168 | WHERE cpt.user_id = p_customer_id |
| | 169 | AND p.status = 'Completed'::payment_status |
| | 170 | AND p.payment_date >= v_month_start |
| | 171 | AND p.payment_date < v_month_end; |
| | 172 | |
| | 173 | RETURN v_total; |
| | 174 | END; |
| | 175 | $$; |
| | 176 | |
| | 177 | }}} |
| | 178 | |
| | 179 | === `get_driver_shift_count` |
| | 180 | |
| | 181 | Оваа функција служи за да го пресмета бројот на смени (line assignments) што одреден возач ги има извршено во даден временски интервал. |
| | 182 | |
| | 183 | {{{ |
| | 184 | |
| | 185 | CREATE OR REPLACE FUNCTION get_driver_shift_count( |
| | 186 | p_driver_id BIGINT, |
| | 187 | p_date_from TIMESTAMP, |
| | 188 | p_date_to TIMESTAMP |
| | 189 | ) |
| | 190 | RETURNS INTEGER |
| | 191 | LANGUAGE plpgsql |
| | 192 | AS $$ |
| | 193 | DECLARE |
| | 194 | v_count INTEGER; |
| | 195 | BEGIN |
| | 196 | IF p_date_from >= p_date_to THEN |
| | 197 | RAISE EXCEPTION 'Start date must be before end date.'; |
| | 198 | END IF; |
| | 199 | |
| | 200 | IF NOT EXISTS ( |
| | 201 | SELECT 1 |
| | 202 | FROM Driver d |
| | 203 | WHERE d.user_id = p_driver_id |
| | 204 | ) THEN |
| | 205 | RAISE EXCEPTION 'Driver with id % does not exist.', p_driver_id; |
| | 206 | END IF; |
| | 207 | |
| | 208 | SELECT COUNT(*) |
| | 209 | INTO v_count |
| | 210 | FROM Line_assignment la |
| | 211 | WHERE la.driver_id = p_driver_id |
| | 212 | AND la.start_time >= p_date_from |
| | 213 | AND la.start_time < p_date_to; |
| | 214 | |
| | 215 | RETURN v_count; |
| | 216 | END; |
| | 217 | $$; |
| | 218 | |
| | 219 | }}} |
| | 220 | |
| | 221 | == Процедури |
| | 222 | |
| | 223 | === `buy_single_ticket` |
| | 224 | |
| | 225 | Оваа процедура служи за креирање и купување на single билет за одреден клиент, при што автоматски се регистрира плаќање, се генерира билет поврзан со одредена линија и се поврзуваат сите потребни записи во системот за евиденција. |
| | 226 | |
| | 227 | {{{ |
| | 228 | |
| | 229 | CREATE OR REPLACE PROCEDURE buy_single_ticket( |
| | 230 | p_customer_id BIGINT, |
| | 231 | p_assignment_id BIGINT, |
| | 232 | p_payment_type_id BIGINT |
| | 233 | ) |
| | 234 | LANGUAGE plpgsql |
| | 235 | AS $$ |
| | 236 | DECLARE |
| | 237 | v_payment_id BIGINT; |
| | 238 | v_ticket_id BIGINT; |
| | 239 | BEGIN |
| | 240 | IF NOT EXISTS ( |
| | 241 | SELECT 1 |
| | 242 | FROM Customer c |
| | 243 | WHERE c.user_id = p_customer_id |
| | 244 | ) THEN |
| | 245 | RAISE EXCEPTION 'Customer with id % does not exist.', p_customer_id; |
| | 246 | END IF; |
| | 247 | |
| | 248 | IF NOT EXISTS ( |
| | 249 | SELECT 1 |
| | 250 | FROM Line_assignment la |
| | 251 | WHERE la.assignment_id = p_assignment_id |
| | 252 | ) THEN |
| | 253 | RAISE EXCEPTION 'Line assignment with id % does not exist.', p_assignment_id; |
| | 254 | END IF; |
| | 255 | |
| | 256 | IF NOT EXISTS ( |
| | 257 | SELECT 1 |
| | 258 | FROM Payment_type pt |
| | 259 | WHERE pt.type_id = p_payment_type_id |
| | 260 | ) THEN |
| | 261 | RAISE EXCEPTION 'Payment type with id % does not exist.', p_payment_type_id; |
| | 262 | END IF; |
| | 263 | |
| | 264 | INSERT INTO Payment (type_id, status, payment_date, transaction_number) |
| | 265 | VALUES ( |
| | 266 | p_payment_type_id, |
| | 267 | 'Completed'::payment_status, |
| | 268 | CURRENT_DATE, |
| | 269 | 'TRX-SINGLE-' || extract(epoch from clock_timestamp())::BIGINT || '-' || p_customer_id |
| | 270 | ) |
| | 271 | RETURNING payment_id INTO v_payment_id; |
| | 272 | |
| | 273 | INSERT INTO Ticket (user_id) |
| | 274 | VALUES (p_customer_id) |
| | 275 | RETURNING ticket_id INTO v_ticket_id; |
| | 276 | |
| | 277 | INSERT INTO Single_ticket (ticket_id, amount, assignment_id) |
| | 278 | VALUES (v_ticket_id, 50, p_assignment_id); |
| | 279 | |
| | 280 | INSERT INTO Customer_Payment_Ticket (payment_id, ticket_id, user_id) |
| | 281 | VALUES (v_payment_id, v_ticket_id, p_customer_id); |
| | 282 | |
| | 283 | RAISE NOTICE 'Single ticket created. ticket_id=%, payment_id=%', v_ticket_id, v_payment_id; |
| | 284 | END; |
| | 285 | $$; |
| | 286 | |
| | 287 | }}} |
| | 288 | |
| | 289 | === `buy_pass_ticket` |
| | 290 | |
| | 291 | Оваа процедура служи за купување и креирање на pass билет за клиент, при што се регистрира плаќање, се создава билет од избран тип на pass и се поврзуваат сите релевантни записи во системот за евиденција. |
| | 292 | |
| | 293 | {{{ |
| | 294 | |
| | 295 | CREATE OR REPLACE PROCEDURE buy_pass_ticket( |
| | 296 | p_customer_id BIGINT, |
| | 297 | p_pass_type_id INTEGER, |
| | 298 | p_payment_type_id BIGINT |
| | 299 | ) |
| | 300 | LANGUAGE plpgsql |
| | 301 | AS $$ |
| | 302 | DECLARE |
| | 303 | v_payment_id BIGINT; |
| | 304 | v_ticket_id BIGINT; |
| | 305 | BEGIN |
| | 306 | IF NOT EXISTS ( |
| | 307 | SELECT 1 |
| | 308 | FROM Customer c |
| | 309 | WHERE c.user_id = p_customer_id |
| | 310 | ) THEN |
| | 311 | RAISE EXCEPTION 'Customer with id % does not exist.', p_customer_id; |
| | 312 | END IF; |
| | 313 | |
| | 314 | IF NOT EXISTS ( |
| | 315 | SELECT 1 |
| | 316 | FROM Pass_type pt |
| | 317 | WHERE pt.id = p_pass_type_id |
| | 318 | ) THEN |
| | 319 | RAISE EXCEPTION 'Pass type with id % does not exist.', p_pass_type_id; |
| | 320 | END IF; |
| | 321 | |
| | 322 | IF NOT EXISTS ( |
| | 323 | SELECT 1 |
| | 324 | FROM Payment_type pt |
| | 325 | WHERE pt.type_id = p_payment_type_id |
| | 326 | ) THEN |
| | 327 | RAISE EXCEPTION 'Payment type with id % does not exist.', p_payment_type_id; |
| | 328 | END IF; |
| | 329 | |
| | 330 | INSERT INTO Payment (type_id, status, payment_date, transaction_number) |
| | 331 | VALUES ( |
| | 332 | p_payment_type_id, |
| | 333 | 'Completed'::payment_status, |
| | 334 | CURRENT_DATE, |
| | 335 | 'TRX-PASS-' || extract(epoch from clock_timestamp())::BIGINT || '-' || p_customer_id |
| | 336 | ) |
| | 337 | RETURNING payment_id INTO v_payment_id; |
| | 338 | |
| | 339 | INSERT INTO Ticket (user_id) |
| | 340 | VALUES (p_customer_id) |
| | 341 | RETURNING ticket_id INTO v_ticket_id; |
| | 342 | |
| | 343 | INSERT INTO Pass_ticket (ticket_id, type_id) |
| | 344 | VALUES (v_ticket_id, p_pass_type_id); |
| | 345 | |
| | 346 | INSERT INTO Customer_Payment_Ticket (payment_id, ticket_id, user_id) |
| | 347 | VALUES (v_payment_id, v_ticket_id, p_customer_id); |
| | 348 | |
| | 349 | RAISE NOTICE 'Pass ticket created. ticket_id=%, payment_id=%', v_ticket_id, v_payment_id; |
| | 350 | END; |
| | 351 | $$; |
| | 352 | |
| | 353 | }}} |
| | 354 | |
| | 355 | === `assign_driver_to_line` |
| | 356 | |
| | 357 | Оваа процедура служи за доделување на возач на конкретна линија и автобус во одреден временски период, при што прво проверува дали сите учесници и ресурси се активни и достапни и дали нема преклопување со други смени. |
| | 358 | |
| | 359 | {{{ |
| | 360 | |
| | 361 | CREATE OR REPLACE PROCEDURE assign_driver_to_line( |
| | 362 | p_driver_id BIGINT, |
| | 363 | p_admin_id BIGINT, |
| | 364 | p_chassis_number VARCHAR, |
| | 365 | p_schedule_id INTEGER, |
| | 366 | p_start_time TIMESTAMP, |
| | 367 | p_end_time TIMESTAMP |
| | 368 | ) |
| | 369 | LANGUAGE plpgsql |
| | 370 | AS $$ |
| | 371 | DECLARE |
| | 372 | v_assignment_id BIGINT; |
| | 373 | BEGIN |
| | 374 | IF p_start_time >= p_end_time THEN |
| | 375 | RAISE EXCEPTION 'Start time must be before end time.'; |
| | 376 | END IF; |
| | 377 | |
| | 378 | IF NOT EXISTS ( |
| | 379 | SELECT 1 |
| | 380 | FROM Driver d |
| | 381 | WHERE d.user_id = p_driver_id |
| | 382 | AND d.status = 'Active'::employee_status |
| | 383 | ) THEN |
| | 384 | RAISE EXCEPTION 'Driver % does not exist or is not active.', p_driver_id; |
| | 385 | END IF; |
| | 386 | |
| | 387 | IF NOT EXISTS ( |
| | 388 | SELECT 1 |
| | 389 | FROM Admin a |
| | 390 | WHERE a.user_id = p_admin_id |
| | 391 | AND a.status = 'Active'::employee_status |
| | 392 | ) THEN |
| | 393 | RAISE EXCEPTION 'Admin % does not exist or is not active.', p_admin_id; |
| | 394 | END IF; |
| | 395 | |
| | 396 | IF NOT EXISTS ( |
| | 397 | SELECT 1 |
| | 398 | FROM Bus_instance bi |
| | 399 | WHERE bi.chassis_number = p_chassis_number |
| | 400 | AND bi.status = 'Active'::bus_status |
| | 401 | ) THEN |
| | 402 | RAISE EXCEPTION 'Bus % does not exist or is not active.', p_chassis_number; |
| | 403 | END IF; |
| | 404 | |
| | 405 | IF NOT EXISTS ( |
| | 406 | SELECT 1 |
| | 407 | FROM Schedule s |
| | 408 | WHERE s.schedule_id = p_schedule_id |
| | 409 | ) THEN |
| | 410 | RAISE EXCEPTION 'Schedule % does not exist.', p_schedule_id; |
| | 411 | END IF; |
| | 412 | |
| | 413 | IF EXISTS ( |
| | 414 | SELECT 1 |
| | 415 | FROM Line_assignment la |
| | 416 | WHERE la.driver_id = p_driver_id |
| | 417 | AND p_start_time < la.end_time |
| | 418 | AND p_end_time > la.start_time |
| | 419 | ) THEN |
| | 420 | RAISE EXCEPTION 'Driver % already has an overlapping shift.', p_driver_id; |
| | 421 | END IF; |
| | 422 | |
| | 423 | IF EXISTS ( |
| | 424 | SELECT 1 |
| | 425 | FROM Line_assignment la |
| | 426 | WHERE la.chassis_number = p_chassis_number |
| | 427 | AND p_start_time < la.end_time |
| | 428 | AND p_end_time > la.start_time |
| | 429 | ) THEN |
| | 430 | RAISE EXCEPTION 'Bus % is already assigned in this time interval.', p_chassis_number; |
| | 431 | END IF; |
| | 432 | |
| | 433 | INSERT INTO Line_assignment |
| | 434 | (driver_id, admin_id, chassis_number, schedule_id, start_time, end_time) |
| | 435 | VALUES |
| | 436 | (p_driver_id, p_admin_id, p_chassis_number, p_schedule_id, p_start_time, p_end_time) |
| | 437 | RETURNING assignment_id INTO v_assignment_id; |
| | 438 | |
| | 439 | RAISE NOTICE 'Line assignment created. assignment_id=%', v_assignment_id; |
| | 440 | END; |
| | 441 | $$; |
| | 442 | |
| | 443 | }}} |
| | 444 | |
| | 445 | == Тригери |
| | 446 | |
| | 447 | === `prevent_driver_shift_overlap` |
| | 448 | |
| | 449 | Оваа функција со trigger служи за автоматска проверка и спречување на преклопување на работни смени за возач, односно не дозволува внес или измена на assignment ако временски се поклопува со друга веќе постоечка смена за истиот возач. |
| | 450 | |
| | 451 | {{{ |
| | 452 | |
| | 453 | CREATE OR REPLACE FUNCTION prevent_driver_shift_overlap_fn() |
| | 454 | RETURNS TRIGGER |
| | 455 | LANGUAGE plpgsql |
| | 456 | AS $$ |
| | 457 | BEGIN |
| | 458 | IF NEW.start_time >= NEW.end_time THEN |
| | 459 | RAISE EXCEPTION 'Start time must be before end time.'; |
| | 460 | END IF; |
| | 461 | |
| | 462 | IF EXISTS ( |
| | 463 | SELECT 1 |
| | 464 | FROM Line_assignment la |
| | 465 | WHERE la.driver_id = NEW.driver_id |
| | 466 | AND la.assignment_id <> COALESCE(NEW.assignment_id, -1) |
| | 467 | AND NEW.start_time < la.end_time |
| | 468 | AND NEW.end_time > la.start_time |
| | 469 | ) THEN |
| | 470 | RAISE EXCEPTION 'Driver % already has an overlapping shift.', NEW.driver_id; |
| | 471 | END IF; |
| | 472 | |
| | 473 | RETURN NEW; |
| | 474 | END; |
| | 475 | $$; |
| | 476 | |
| | 477 | DROP TRIGGER IF EXISTS trg_prevent_driver_shift_overlap ON Line_assignment; |
| | 478 | |
| | 479 | CREATE TRIGGER trg_prevent_driver_shift_overlap |
| | 480 | BEFORE INSERT OR UPDATE ON Line_assignment |
| | 481 | FOR EACH ROW |
| | 482 | EXECUTE FUNCTION prevent_driver_shift_overlap_fn(); |
| | 483 | |
| | 484 | }}} |
| | 485 | |
| | 486 | === `log_payment_status_change` |
| | 487 | |
| | 488 | Оваа функција со trigger служи за автоматско логирање на секоја промена на статусот на плаќање, така што секогаш кога ќе се смени статусот во табелата Payment, се зачувува запис со стар и нов статус во посебна лог табела. |
| | 489 | |
| | 490 | {{{ |
| | 491 | |
| | 492 | CREATE TABLE IF NOT EXISTS Payment_status_log |
| | 493 | ( |
| | 494 | log_id BIGSERIAL PRIMARY KEY, |
| | 495 | payment_id BIGINT NOT NULL, |
| | 496 | old_status payment_status, |
| | 497 | new_status payment_status, |
| | 498 | changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
| | 499 | description TEXT, |
| | 500 | CONSTRAINT payment_status_log_payment_fk |
| | 501 | FOREIGN KEY (payment_id) REFERENCES Payment(payment_id) |
| | 502 | ON DELETE CASCADE |
| | 503 | ON UPDATE CASCADE |
| | 504 | ); |
| | 505 | |
| | 506 | CREATE OR REPLACE FUNCTION log_payment_status_change_fn() |
| | 507 | RETURNS TRIGGER |
| | 508 | LANGUAGE plpgsql |
| | 509 | AS $$ |
| | 510 | BEGIN |
| | 511 | IF OLD.status IS DISTINCT FROM NEW.status THEN |
| | 512 | INSERT INTO Payment_status_log |
| | 513 | (payment_id, old_status, new_status, description) |
| | 514 | VALUES |
| | 515 | ( |
| | 516 | NEW.payment_id, |
| | 517 | OLD.status, |
| | 518 | NEW.status, |
| | 519 | 'Payment status changed from ' || OLD.status || ' to ' || NEW.status |
| | 520 | ); |
| | 521 | END IF; |
| | 522 | |
| | 523 | RETURN NEW; |
| | 524 | END; |
| | 525 | $$; |
| | 526 | |
| | 527 | DROP TRIGGER IF EXISTS trg_log_payment_status_change ON Payment; |
| | 528 | |
| | 529 | CREATE TRIGGER trg_log_payment_status_change |
| | 530 | AFTER UPDATE OF status ON Payment |
| | 531 | FOR EACH ROW |
| | 532 | EXECUTE FUNCTION log_payment_status_change_fn(); |
| | 533 | |
| | 534 | }}} |