| | 1 | = Резервирање термин |
| | 2 | |
| | 3 | == Актери |
| | 4 | * Најавен корисник (клиент) |
| | 5 | |
| | 6 | == Чекор 1 |
| | 7 | Најавениот корисник кликнува на копчето „Book Now“ од главната навигација. |
| | 8 | |
| | 9 | == Чекор 2 |
| | 10 | Системот ја прикажува страницата за резервирање термин со: |
| | 11 | * листа на услуги по категории (име, цена, времетраење), |
| | 12 | * листа на пакети (име, максимален број користења, вкупна цена и услуги во пакетот), |
| | 13 | * формa за избор на датум, термин и начин на плаќање. |
| | 14 | |
| | 15 | Податоците за категориите и услугите се вчитани преку SQL погледот `v_services_grouped_by_category`: |
| | 16 | |
| | 17 | {{{ |
| | 18 | SELECT category_id, category_name, services |
| | 19 | FROM v_services_grouped_by_category |
| | 20 | ORDER BY category_id; |
| | 21 | }}} |
| | 22 | |
| | 23 | Пакетите се вчитуваат со: |
| | 24 | |
| | 25 | {{{ |
| | 26 | SELECT |
| | 27 | p.package_id, |
| | 28 | p.name AS package_name, |
| | 29 | p.max_usage, |
| | 30 | CASE |
| | 31 | WHEN EXISTS ( |
| | 32 | SELECT 1 |
| | 33 | FROM information_schema.columns |
| | 34 | WHERE table_name = 'package' |
| | 35 | AND column_name = 'total_price' |
| | 36 | ) THEN p.total_price |
| | 37 | ELSE package_price.calc_total_price |
| | 38 | END::numeric AS total_price, |
| | 39 | s.service_id, |
| | 40 | s.name AS service_name, |
| | 41 | ps.discounted_price |
| | 42 | FROM Package p |
| | 43 | LEFT JOIN LATERAL ( |
| | 44 | SELECT COALESCE(SUM(ps2.discounted_price), 0)::numeric AS calc_total_price |
| | 45 | FROM PackageService ps2 |
| | 46 | WHERE ps2.package_id = p.package_id |
| | 47 | ) package_price ON true |
| | 48 | LEFT JOIN PackageService ps |
| | 49 | ON ps.package_id = p.package_id |
| | 50 | LEFT JOIN Service s |
| | 51 | ON s.service_id = ps.service_id |
| | 52 | ORDER BY p.package_id, s.name; |
| | 53 | }}} |
| | 54 | |
| | 55 | == Чекор 3 |
| | 56 | Корисникот избира една или повеќе услуги (пр. Anti-cellulite, Back Massage…). |
| | 57 | |
| | 58 | Системот ја пресметува вкупната цена и вкупното времетраење на терминот врз основа на избраните услуги. |
| | 59 | Овие податоци подоцна ќе се користат при креирањето на терминот во базата (преку функциите `fn_service_total_minutes` и `fn_service_total_price` кои ги користи `sp_create_appointment`). |
| | 60 | |
| | 61 | == Чекор 4 |
| | 62 | Корисникот избира датум за резервација во делот „Choose Date & Time“. |
| | 63 | |
| | 64 | Системот, врз основа на избраниот датум и избраните услуги, ги вчитува сите слободни термински слотови за тој ден, користејќи ја функцијата `fn_available_slots`: |
| | 65 | |
| | 66 | {{{ |
| | 67 | SELECT |
| | 68 | to_char(start_time, 'YYYY-MM-DD"T"HH24:MI:SS') AS start_time, |
| | 69 | to_char(end_time, 'YYYY-MM-DD"T"HH24:MI:SS') AS end_time |
| | 70 | FROM fn_available_slots($1::date, $2::int[]); |
| | 71 | }}} |
| | 72 | |
| | 73 | Параметри: |
| | 74 | * `$1` – избраниот датум, |
| | 75 | * `$2` – низа од `service_id` на избраните услуги. |
| | 76 | |
| | 77 | Функцијата `fn_available_slots` ги користи записите од табелата `availability` (само оние со `is_closed = false`) и ги исклучува сите слотови кои се преклопуваат со постоечки закажани термини (`SCHEDULED` appointments). |
| | 78 | |
| | 79 | == Чекор 5 |
| | 80 | Системот му прикажува на корисникот листа од достапни термини (почетно време и траење) за избраниот датум. |
| | 81 | |
| | 82 | Корисникот избира еден термин од листата (пример 2025-05-10 14:00–15:00). |
| | 83 | |
| | 84 | == Чекор 6 |
| | 85 | Корисникот во делот „Payment Option“ ја избира опцијата **„Pay now (online card payment)“** и по желба внесува број на лојалти поени што сака да ги искористи. |
| | 86 | |
| | 87 | Системот ја прикажува проценетата вредност: |
| | 88 | * вкупна сума, |
| | 89 | * можен попуст преку поени, |
| | 90 | * финална сума за плаќање. |
| | 91 | |
| | 92 | (Пресметката на овој чекор е на апликативно ниво, но истиот број поени и сума ќе се користат во SQL функцијата за креирање плаќање.) |
| | 93 | |
| | 94 | == Чекор 7 |
| | 95 | Корисникот го потврдува закажувањето со клик на „Confirm booking“. |
| | 96 | |
| | 97 | Системот креира нов appointment во базата со повик на функцијата `sp_create_appointment`: |
| | 98 | |
| | 99 | {{{ |
| | 100 | SELECT sp_create_appointment($1, $2::timestamp, $3::int[], $4) AS appointment_id; |
| | 101 | }}} |
| | 102 | |
| | 103 | Параметри: |
| | 104 | * `$1` – `user_id` на најавениот корисник, |
| | 105 | * `$2` – избраниот `appointment_time` (почетно време на терминот), |
| | 106 | * `$3` – низа од избрани `service_id`, |
| | 107 | * `$4` – текстуална забелешка (`notes`), може да биде и `NULL`. |
| | 108 | |
| | 109 | Функцијата `sp_create_appointment`: |
| | 110 | * проверува дека сите услуги постојат во табелата `service`, |
| | 111 | * ја пресметува вкупната должина и крајното време на терминот, |
| | 112 | * го наоѓа статусот `SCHEDULED` во табелата `status`, |
| | 113 | * внесува запис во табелата `appointment`, |
| | 114 | * внесува записи во табелата `appointmentservice` за сите услуги, |
| | 115 | * ја повикува функцијата `fn_validate_appointment`, која проверува: |
| | 116 | * дека терминот е во иднина, |
| | 117 | * дека терминот е внатре во некој прозорец од табелата `availability`, |
| | 118 | * дека нема преклопување со друг `SCHEDULED` термин. |
| | 119 | |
| | 120 | == Чекор 8 |
| | 121 | По успешно креирање на appointment-от, системот креира плаќање за истиот термин користејќи ја функцијата `sp_create_payment`: |
| | 122 | |
| | 123 | {{{ |
| | 124 | SELECT * |
| | 125 | FROM sp_create_payment($1, $2::int, $3::text, $4::int); |
| | 126 | }}} |
| | 127 | |
| | 128 | Параметри: |
| | 129 | * `$1` – `user_id` на корисникот, |
| | 130 | * `$2` – `appointment_id` од претходниот чекор, |
| | 131 | * `$3` – метод на плаќање, на пример `'CARD'`, |
| | 132 | * `$4` – број на лојалти поени што корисникот сака да ги искористи. |
| | 133 | |
| | 134 | Функцијата: |
| | 135 | * го зема `total_price` од табелата `appointment`, |
| | 136 | * ја проверува лојалти картичката (`loyaltycard`) преку `sp_ensure_loyalty_card`, |
| | 137 | * пресметува колку поени може да се искористат (ограничено на процент од сумата), |
| | 138 | * внесува запис во табелата `payment` со статус `PENDING` и поле `points_used`. |
| | 139 | |
| | 140 | == Чекор 9 |
| | 141 | Кога плаќањето е успешно потврдено, системот го означува плаќањето како платено и ги ажурира лојалти поените со повик на функцијата `sp_mark_payment_paid`: |
| | 142 | |
| | 143 | {{{ |
| | 144 | SELECT sp_mark_payment_paid($1::int) AS points_used; |
| | 145 | }}} |
| | 146 | |
| | 147 | Параметар: |
| | 148 | * `$1` – `payment_id` на креираното плаќање. |
| | 149 | |
| | 150 | Функцијата: |
| | 151 | * го ажурира статусот на записот во `payment` на `PAID`, |
| | 152 | * ги намалува поените на корисникот (доколку користел поени) и ја поставува финалната сума, |
| | 153 | * осигурува дека нема друго `PAID` плаќање за истиот appointment. |
| | 154 | |
| | 155 | == Резултат |
| | 156 | * Во табелата `appointment` и `appointmentservice` се запишува успешно креиран термин со избраните услуги и временски опсег. |
| | 157 | * Во табелата `payment` постои запис за плаќањето со статус `PAID` и коректно ажурирани `points_used` и износ. |
| | 158 | * Корисникот на екранот добива потврда за успешно резервиран термин и подоцна може да го прегледа во „My Appointments“, како и да остави рецензија по извршување на услугата. |