| | 171 | Функцијата `fn_eligibility_matrix` е дизајнирана да ја пресмета матрицата на компатибилност помеѓу одреден студент и ментор, враќајќи ги резултатите во структуриран JSONB формат. По почетната проверка за постоење на корисниците во системот, таа го анализира бројот на заеднички предмети кои ги слушаат или предаваат, како и бројот на заеднички интереси кои ги делат, преку кои се одредува компатибилност. Исто така, функцијата утврдува дали двајцата корисници припаѓаат на ист факултет. Финалната одлука за подобност се носи врз основа на тоа дали корисниците имаат барем еден заеднички предмет или најмалку два заеднички интереси. Сите овие пресметани метрики се подредени во прегледен објект за понатамошна обработка во апликацискиот слој. |
| | 172 | |
| | 173 | {{{ |
| | 174 | CREATE OR REPLACE FUNCTION fn_eligibility_matrix(p_student_id BIGINT, p_mentor_id BIGINT) |
| | 175 | RETURNS JSONB |
| | 176 | LANGUAGE plpgsql |
| | 177 | AS $$ |
| | 178 | DECLARE |
| | 179 | v_shared_subjects INT; |
| | 180 | v_shared_interests INT; |
| | 181 | v_same_faculty BOOLEAN; |
| | 182 | v_student_fac BIGINT; |
| | 183 | v_mentor_fac BIGINT; |
| | 184 | v_is_eligible BOOLEAN; |
| | 185 | BEGIN |
| | 186 | -- Проверки дали постојат |
| | 187 | IF NOT EXISTS (SELECT 1 FROM "User" WHERE ID = p_student_id) OR NOT EXISTS (SELECT 1 FROM "User" WHERE ID = p_mentor_id) THEN |
| | 188 | RETURN jsonb_build_object('error', 'Корисниците не постојат'); |
| | 189 | END IF; |
| | 190 | |
| | 191 | -- Заеднички предмети |
| | 192 | SELECT COUNT(*) INTO v_shared_subjects FROM User_Subject us1 |
| | 193 | JOIN User_Subject us2 ON us1.SubjectID = us2.SubjectID |
| | 194 | WHERE us1.UserID = p_student_id AND us2.UserID = p_mentor_id; |
| | 195 | |
| | 196 | -- Заеднички интереси |
| | 197 | SELECT COUNT(*) INTO v_shared_interests FROM User_Interest ui1 |
| | 198 | JOIN User_Interest ui2 ON ui1.InterestID = ui2.InterestID |
| | 199 | WHERE ui1.UserID = p_student_id AND ui2.UserID = p_mentor_id; |
| | 200 | |
| | 201 | -- Факултет |
| | 202 | SELECT FacultyID INTO v_student_fac FROM "User" WHERE ID = p_student_id; |
| | 203 | SELECT FacultyID INTO v_mentor_fac FROM "User" WHERE ID = p_mentor_id; |
| | 204 | v_same_faculty := (v_student_fac = v_mentor_fac); |
| | 205 | |
| | 206 | -- Логика за подобност |
| | 207 | v_is_eligible := (v_shared_subjects > 0 OR v_shared_interests >= 2); |
| | 208 | |
| | 209 | RETURN jsonb_build_object( |
| | 210 | 'student_id', p_student_id, |
| | 211 | 'mentor_id', p_mentor_id, |
| | 212 | 'is_eligible', v_is_eligible, |
| | 213 | 'metrics', jsonb_build_object( |
| | 214 | 'shared_subjects', v_shared_subjects, |
| | 215 | 'shared_interests', v_shared_interests, |
| | 216 | 'same_faculty', v_same_faculty |
| | 217 | ) |
| | 218 | ); |
| | 219 | END; |
| | 220 | $$; |
| | 221 | |
| | 222 | SELECT fn_eligibility_matrix(1, 2); |
| | 223 | }}} |
| | 224 | |
| | 225 | ---- |
| | 226 | |
| | 227 | Функцијата `fn_mentor_bottleneck_score` служи за пресметување на нумерички индекс кој го рефлектира просечното доцнење на одреден ментор при реализација на задачите со неговите студенти. Таа ги анализира сите активни задачи за кои е задолжен менторот, а чиј краен рок е веќе поминат, па го собира вкупниот број на денови на доцнење во однос на тековниот датум. Доколку менторот нема активни задачи кои доцнат, функцијата веднаш враќа вредност нула. Во спротивно, таа го пресметува просечниот број на денови на доцнење по задача и го заокружува овој резултат на две децимали, овозможувајќи лесна детекција на ментори кои претставуваат тесно грло во процесот. |
| | 228 | |
| | 229 | {{{ |
| | 230 | CREATE OR REPLACE FUNCTION fn_mentor_bottleneck_score(p_mentor_id BIGINT) |
| | 231 | RETURNS NUMERIC |
| | 232 | LANGUAGE plpgsql |
| | 233 | AS $$ |
| | 234 | DECLARE |
| | 235 | v_total_overdue_days NUMERIC; |
| | 236 | v_active_tasks INT; |
| | 237 | BEGIN |
| | 238 | SELECT |
| | 239 | COALESCE(SUM(EXTRACT(DAY FROM (CURRENT_DATE - t.EndDate))), 0), |
| | 240 | COUNT(t.ID) |
| | 241 | INTO v_total_overdue_days, v_active_tasks |
| | 242 | FROM Task t |
| | 243 | JOIN Mentorship m ON t.MentorshipID = m.ID |
| | 244 | WHERE m.MentorID = p_mentor_id AND t.Status = 0 AND t.EndDate < CURRENT_DATE; |
| | 245 | |
| | 246 | IF v_active_tasks = 0 THEN |
| | 247 | RETURN 0.00; |
| | 248 | END IF; |
| | 249 | |
| | 250 | -- Формула: Просечно доцнење во денови по задача |
| | 251 | RETURN ROUND(v_total_overdue_days / v_active_tasks, 2); |
| | 252 | END; |
| | 253 | $$; |
| | 254 | |
| | 255 | SELECT fn_mentor_bottleneck_score(2); |
| | 256 | }}} |
| | 257 | |
| | 258 | ---- |
| | 259 | |
| | 260 | Функцијата `fn_predict_completion_date` користи едноставен алгоритам за предвидување на точниот датум и време кога би завршило одредено менторство врз основа на досегашната динамика на работа. Таа го извлекува бројот на завршени и преостанати задачи за менторството, како и датумот кога е започната првата задача. Доколку нема доволно историски податоци, односно ако нема ниту една завршена или преостаната задача, функцијата враќа празна (NULL) вредност. Ако податоците се достапни, таа го пресметува просечното време потребно за извршување на една задача и го множи со бројот на преостанати задачи, додавајќи го овој временски интервал на тековното време за да пресмета крајна временска прогноза. |
| | 261 | |
| | 262 | {{{ |
| | 263 | CREATE OR REPLACE FUNCTION fn_predict_completion_date(p_mentorship_id BIGINT) |
| | 264 | RETURNS TIMESTAMP |
| | 265 | LANGUAGE plpgsql |
| | 266 | AS $$ |
| | 267 | DECLARE |
| | 268 | v_completed INT; |
| | 269 | v_pending INT; |
| | 270 | v_avg_days_per_task NUMERIC; |
| | 271 | v_start_date TIMESTAMP; |
| | 272 | BEGIN |
| | 273 | SELECT COUNT(*) FILTER (WHERE Status = 1), COUNT(*) FILTER (WHERE Status = 0), MIN(StartDate) |
| | 274 | INTO v_completed, v_pending, v_start_date |
| | 275 | FROM Task WHERE MentorshipID = p_mentorship_id; |
| | 276 | |
| | 277 | -- Нема доволно податоци |
| | 278 | IF v_completed = 0 OR v_pending = 0 THEN |
| | 279 | RETURN NULL; |
| | 280 | END IF; |
| | 281 | |
| | 282 | -- Колку денови му требале во просек за една задача |
| | 283 | v_avg_days_per_task := EXTRACT(DAY FROM (CURRENT_TIMESTAMP - v_start_date)) / v_completed; |
| | 284 | |
| | 285 | -- Прогноза: Денес + (Просек * Останати Задачи) |
| | 286 | RETURN CURRENT_TIMESTAMP + (v_avg_days_per_task * v_pending || ' days')::INTERVAL; |
| | 287 | END; |
| | 288 | $$; |
| | 289 | |
| | 290 | SELECT fn_predict_completion_date(9887604); |
| | 291 | }}} |
| | 292 | |