This shows you the differences between two versions of the page.
poo-ca-cd:teme:2025:b73f56dc-17a1-42ac-bd7e-d57f3caaf9fd:tema-2 [2025/10/02 09:19] valentin.carauleanu [Restricții] |
poo-ca-cd:teme:2025:b73f56dc-17a1-42ac-bd7e-d57f3caaf9fd:tema-2 [2025/10/02 12:07] (current) valentin.carauleanu [Customer Impact] |
||
---|---|---|---|
Line 103: | Line 103: | ||
<note tip> | <note tip> | ||
Câmpul **description** este opțional. </note> | Câmpul **description** este opțional. </note> | ||
+ | |||
+ | ==== Rezumat ==== | ||
+ | {{:poo-ca-cd:teme:2025:b73f56dc-17a1-42ac-bd7e-d57f3caaf9fd:types.png?800|}} | ||
+ | |||
+ | |||
==== 1. BUG ==== | ==== 1. BUG ==== | ||
Line 550: | Line 555: | ||
</code> | </code> | ||
</spoiler> | </spoiler> | ||
+ | \\ | ||
3. Un **Reporter** nu poate comenta dacă ticket-ul are status **CLOSED**. În cazul în care se încearcă comentarea unui ticket cu status **CLOSED**, comanda este respinsă: | 3. Un **Reporter** nu poate comenta dacă ticket-ul are status **CLOSED**. În cazul în care se încearcă comentarea unui ticket cu status **CLOSED**, comanda este respinsă: | ||
Line 563: | Line 569: | ||
</code> | </code> | ||
</spoiler> | </spoiler> | ||
+ | \\ | ||
4. Conținutul comentariului trebuie să aibă minim **10 caractere**. Dacă este mai mic, comanda este respinsă: | 4. Conținutul comentariului trebuie să aibă minim **10 caractere**. Dacă este mai mic, comanda este respinsă: | ||
Line 576: | Line 582: | ||
</code> | </code> | ||
</spoiler> | </spoiler> | ||
+ | \\ | ||
5. Un **Developer** poate comenta doar pe ticketele care îi sunt atribuite. Dacă un developer încearcă să comenteze un ticket care nu îi este atribuit, comanda este respinsă: | 5. Un **Developer** poate comenta doar pe ticketele care îi sunt atribuite. Dacă un developer încearcă să comenteze un ticket care nu îi este atribuit, comanda este respinsă: | ||
Line 589: | Line 595: | ||
</code> | </code> | ||
</spoiler> | </spoiler> | ||
+ | \\ | ||
6. Un **Reporter** poate comenta doar pe ticketele pe care le-a raportat. Dacă un reporter încearcă să comenteze un ticket pe care nu l-a raportat, comanda este respinsă: | 6. Un **Reporter** poate comenta doar pe ticketele pe care le-a raportat. Dacă un reporter încearcă să comenteze un ticket pe care nu l-a raportat, comanda este respinsă: | ||
+ | \\ | ||
<spoiler Output eroare> | <spoiler Output eroare> | ||
Line 750: | Line 757: | ||
+ | ===== assignTicket ===== | ||
+ | **Disponibilă pentru:** **Developer** | ||
+ | |||
+ | **Descriere:** | ||
+ | Un developer își poate atribui un ticket conform regulilor de expertiză, senioritate și milestone. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | |||
+ | 1. Un **Developer** își poate atribui tickete doar din aria lui de expertiză. În cazul în care un developer încearcă să își atribuie un ticket din altă arie de expertiză, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "assignTicket", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Developer <developer_name> cannot assign ticket <id> due to expertise area. Required: <required_area1>, <required_area2>; Current: <current_area>." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | 2. Un **Developer** își poate atribui singur doar tickete accesibile nivelului său de senioritate. În cazul în care un developer încearcă să își atribuie un ticket care nu îi este permis, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "assignTicket", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Developer <developer_name> cannot assign ticket <id> due to seniority level. Required: <required_level>, <required_level>; Current: <current_level>." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | 3. Un ticket poate fi atribuit doar dacă este în status **OPEN**. Dacă un developer încearcă să își atribuie un ticket cu alt status, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "assignTicket", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Only OPEN tickets can be assigned." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | 4. Dacă un developer încearcă să își atribuie un ticket dintr-un milestone la care nu este repartizat, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "assignTicket", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Developer <developer_name> is not assigned to milestone <milestone_name>." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | 5. Un developer nu își poate atribui tickete dintr-un milestone blocat (vezi detalii la secțiunea Milestone). Dacă încearcă să își atribuie un ticket dintr-un milestone blocat, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "assignTicket", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Cannot assign ticket <id> from blocked milestone <milestone_name>." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | <note tip> | ||
+ | * Odată atribuit, statusul unui ticket devine **IN_PROGRESS**. | ||
+ | * Se garantează că ID-ul ticket-ului există. | ||
+ | </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "assignTicket", | ||
+ | "username": "dev_one", | ||
+ | "ticketID": 0, | ||
+ | "timestamp": "2025-09-21" | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | **Nu există output.** | ||
+ | |||
+ | ===== undoAssignTicket ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Developer** | ||
+ | |||
+ | **Descriere:** | ||
+ | Developer-ul realizează că nu poate rezolva un ticket și decide să renunțe, pentru a fi reatribuit de altcineva. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | |||
+ | 1. Un ticket poate fi „de-asignat” doar dacă are statusul **IN_PROGRESS**. În cazul în care un developer încearcă să renunțe la un ticket cu alt status, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "undoAssign", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Only IN_PROGRESS tickets can be unassigned." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | <note tip> | ||
+ | * Se garantează că ID-ul ticket-ului pentru care se încearcă „de-asignarea” există. | ||
+ | * Se garantează că ticket-ul este atribuit developerului care inițiază comanda. | ||
+ | * În urma „de-asignării”, statusul ticket-ului revine la **OPEN**. | ||
+ | * Operația rămâne în istoric. Pentru detalii suplimentare, vezi sectiunea **viewTicketHistory**. | ||
+ | </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "undoAssign", | ||
+ | "username": "dev_one", | ||
+ | "ticketID": 0, | ||
+ | "timestamp": "2025-09-22" | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | **Nu există output.** | ||
+ | |||
+ | ===== changeStatus ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Developer** | ||
+ | |||
+ | **Descriere:** | ||
+ | Permite unui developer să modifice statusul unui ticket atribuit lui. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | |||
+ | 1. Ticketul trebuie să fie atribuit developerului care face schimbarea. În cazul în care un developer încearcă să schimbe statusul unui ticket care nu îi este atribuit, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "changeStatus", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Ticket <id> is not assigned to developer <developer_name>." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | <note tip> | ||
+ | * Sunt permise doar următoarele tranziții de status: **IN_PROGRESS → RESOLVED → CLOSED**. Nu vor exista excepții în teste. | ||
+ | </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "changeStatus", | ||
+ | "username": "dev_one", | ||
+ | "ticketID": 0, | ||
+ | "timestamp": "2025-09-23" | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | **Nu există output.** | ||
+ | |||
+ | ===== undoChangeStatus ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Developer** | ||
+ | |||
+ | **Descriere:** | ||
+ | Developer-ul realizează că a făcut o greșeală și decide să reîntoarcă un ticket la statusul anterior. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | |||
+ | 1. Ticketul trebuie să fie atribuit developerului care face schimbarea. În cazul în care un developer încearcă să reîntoarcă statusul unui ticket care nu îi este atribuit, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "undoChangeStatus", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Ticket <id> is not assigned to developer <developer_name>." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | <note tip> | ||
+ | |||
+ | * Sunt permise doar următoarele tranziții de status: **RESOLVED → IN_PROGRESS**, **CLOSED → RESOLVED**. Nu vor exista excepții în teste. | ||
+ | |||
+ | * Operația rămâne în istoric. | ||
+ | </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "undoChangeStatus", | ||
+ | "username": "dev_one", | ||
+ | "ticketID": 0, | ||
+ | "timestamp": "2025-09-24" | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | **Nu există output.** | ||
+ | |||
+ | ===== viewAssignedTickets ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Developer** | ||
+ | |||
+ | **Descriere:** Afișează toate ticketele atribuite developerului curent. | ||
+ | |||
+ | <note tip> | ||
+ | * Sortarea se face după **businessPriority** (CRITICAL > HIGH > MEDIUM > LOW), apoi după **createdAt** crescător, apoi după **id** crescător. | ||
+ | </note> | ||
+ | |||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "viewAssignedTickets", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-25" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "viewAssignedTickets", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-25", | ||
+ | "assignedTickets": [ | ||
+ | { | ||
+ | "id": 0, | ||
+ | "type": "BUG", | ||
+ | "title": "Crash on settings page", | ||
+ | "businessPriority": "HIGH", | ||
+ | "status": "IN_PROGRESS", | ||
+ | "createdAt": "2025-09-10", | ||
+ | "assignedAt": "", | ||
+ | "reportedBy": "cleopatra", | ||
+ | "comments": [ | ||
+ | { | ||
+ | "author": "dev_one", | ||
+ | "content": "I am looking into this issue.", | ||
+ | "createdAt": "2025-09-10" | ||
+ | }, | ||
+ | { | ||
+ | "author": "reporter_one", | ||
+ | "content": "Please prioritize this bug.", | ||
+ | "createdAt": "2025-09-11" | ||
+ | } | ||
+ | ] | ||
+ | }, | ||
+ | { | ||
+ | "id": 2, | ||
+ | "type": "FEATURE_REQUEST", | ||
+ | "title": "Add dark mode", | ||
+ | "businessPriority": "MEDIUM", | ||
+ | "status": "RESOLVED", | ||
+ | "createdAt": "2025-09-12", | ||
+ | "assignedAt": "", | ||
+ | "reportedBy": "user123", | ||
+ | "comments": [] | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | ===== viewTickets ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Developer**, **Manager**, **Reporter** | ||
+ | |||
+ | **Descriere:** | ||
+ | Afișează ticketele din sistem în funcție de rolul utilizatorului curent. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | 1. **Developer**: vede toate ticketele cu status **OPEN** din milestone-urile la care este repartizat (indiferent dacă și le poate atribui). | ||
+ | | ||
+ | 2. **Manager**: vede toate ticketele din sistem. | ||
+ | |||
+ | 3. **Reporter**: vede doar ticketele raportate de el (ticketele anonime sunt excluse). | ||
+ | |||
+ | <note tip> | ||
+ | |||
+ | * Rezultatele sunt sortate după **createdAt** (de la cele mai vechi la cele mai noi), iar în caz de egalitate după **id** crescător. | ||
+ | |||
+ | </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "viewTickets", | ||
+ | "username": "manager_one", | ||
+ | "timestamp": "2025-09-25" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "viewTickets", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-25", | ||
+ | "tickets": [ | ||
+ | { | ||
+ | "id": 0, | ||
+ | "type": "BUG", | ||
+ | "title": "Crash on settings page", | ||
+ | "businessPriority": "HIGH", | ||
+ | "status": "IN_PROGRESS", | ||
+ | "createdAt": "2025-09-10", | ||
+ | "solvedAt": "", | ||
+ | "assignedAt": "2025-09-21", | ||
+ | "assignedTo": "dev_one", | ||
+ | "reportedBy": "cleopatra", | ||
+ | "comments": [ | ||
+ | { | ||
+ | "author": "dev_one", | ||
+ | "content": "I am looking into this issue.", | ||
+ | "createdAt": "2025-09-10" | ||
+ | }, | ||
+ | { | ||
+ | "author": "manager_gabriel", | ||
+ | "content": "Please prioritize this bug.", | ||
+ | "createdAt": "2025-09-11" | ||
+ | } | ||
+ | ] | ||
+ | }, | ||
+ | { | ||
+ | "id": 3, | ||
+ | "type": "BUG", | ||
+ | "title": "UI glitch on dashboard", | ||
+ | "businessPriority": "LOW", | ||
+ | "status": "OPEN", | ||
+ | "createdAt": "2025-09-20", | ||
+ | "solvedAt": "", | ||
+ | "reportedBy": "", | ||
+ | "comments": [] | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | ===== viewMilestones ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Manager**, **Developer** | ||
+ | |||
+ | **Descriere:** Afișează milestone-urile din sistem în funcție de rolul utilizatorului curent. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | 1. **Manager**: vede toate milestone-urile create de el. | ||
+ | |||
+ | 2. **Developer**: vede toate milestone-urile la care este atribuit. | ||
+ | |||
+ | |||
+ | <note tip> | ||
+ | * Milestone-urile sunt afișate crescător după **dueDate**, iar în caz de egalitate lexicografic crescător după `name`. | ||
+ | </note> | ||
+ | | ||
+ | <note warning> | ||
+ | * Când un milestone devine inactiv (ultimul ticket devine CLOSED), **overdueBy** și **daysUntilDue** rămân blocate. | ||
+ | |||
+ | * Exemplu: un milestone are **dueDate** pe 20 oct. Pe 18 oct ultimul ticket este închis. Comanda **viewMilestones** de pe 21 octombrie va afișa **daysUntilDue = 3** și **overdueBy = 0**. | ||
+ | </note> | ||
+ | |||
+ | <spoiler **completionPercentage**> | ||
+ | \\ | ||
+ | Calculat ca raportul dintre numărul de tickete **CLOSED** și numărul total de tickete din milestone. | ||
+ | Valoare de tip **Double**, afișată cu **2 zecimale**. | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler **daysUntilDue**> | ||
+ | \\ | ||
+ | Numărul de zile rămase până la **dueDate**. | ||
+ | Dacă **dueDate** este în trecut, valoarea este **0**. | ||
+ | **Formulă:** **dueDate - currentDay + 1** | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler **overdueBy**> | ||
+ | \\ | ||
+ | Numărul de zile cu care **dueDate** a fost depășit. | ||
+ | Dacă **dueDate** este în viitor, valoarea este **0**. | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler **repartition**> | ||
+ | \\ | ||
+ | Listă de obiecte ce conțin: | ||
+ | * numele developerilor responsabili pentru milestone | ||
+ | * ID-urile ticketelor atribuite fiecăruia | ||
+ | |||
+ | Lista este: | ||
+ | * sortată **descrescător** după numărul de tickete atribuite | ||
+ | * în caz de egalitate, după **username** (ordine alfabetică). | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler **status**> | ||
+ | \\ | ||
+ | Poate avea două valori: | ||
+ | * **ACTIVE** – dacă există tickete nerezolvate în milestone | ||
+ | * **COMPLETED** – dacă **toate** ticketele sunt **CLOSED** | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "viewMilestones", | ||
+ | "username": "username", | ||
+ | "timestamp": "2025-09-25" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "viewMilestones", | ||
+ | "username": "pm_lead", | ||
+ | "timestamp": "2025-09-25", | ||
+ | "milestones": [ | ||
+ | { | ||
+ | "name": "v1.0", | ||
+ | "blockingFor": ["v2.0"], | ||
+ | "dueDate": "2025-10-01", | ||
+ | "createdAt": "2025-09-15", | ||
+ | "tickets": [0, 1, 2], | ||
+ | "assignedDevs": ["dev_one", "dev_two"], | ||
+ | "createdBy": "gabriel_manager", | ||
+ | "status": "ACTIVE", | ||
+ | "isBlocked": false, | ||
+ | "daysUntilDue": 6, | ||
+ | "overdueBy": 0, | ||
+ | "openTickets": [0, 1, 2], | ||
+ | "closedTickets": [], | ||
+ | "completionPercentage": 0.00, | ||
+ | "repartition": [ | ||
+ | { | ||
+ | "developer": "dev_one", | ||
+ | "assignedTickets": [1] | ||
+ | }, | ||
+ | { | ||
+ | "developer": "dev_two", | ||
+ | "assignedTickets": [2] | ||
+ | }, | ||
+ | { | ||
+ | "developer": "dev_three", | ||
+ | "assignedTickets": [] | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | ===== viewNotifications ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Developer**, **Reporter** | ||
+ | |||
+ | **Descriere:** | ||
+ | Afișează toate notificările primite de utilizator. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | |||
+ | <note tip> | ||
+ | * Notificările sunt afișate în ordinea primirii (**cele mai vechi primele**). În caz de egalitate, în ordine lexicografică după conținut. | ||
+ | |||
+ | * După vizualizare, notificările sunt șterse din sistem. | ||
+ | </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "viewNotifications", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "2025-09-25" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "viewNotifications", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "2025-09-25", | ||
+ | "notifications": [ | ||
+ | "<Notification 1>", | ||
+ | "<Notification 2>", | ||
+ | "<Notification 3>" | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ===== viewTicketHistory ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Developer**, **Manager** | ||
+ | |||
+ | **Descriere:** Un user vede istoricul ticketelor. | ||
+ | |||
+ | |||
+ | ==== Restricții ==== | ||
+ | 1. Un **Developer** poate vedea istoricul ticketelor pe care le-a avut atribuite (inclusiv cele rezolvate) și parcursul lor (**status changes**, **comments**). | ||
+ | |||
+ | 2. Un **Manager** poate vedea istoricul ticketelor care au fost în milestone-urile pe care le-a creat, pentru toți developerii implicați. | ||
+ | |||
+ | <note tip> | ||
+ | * Rezultatele sunt sortate după data **createdAt**, cele mai vechi fiind afișate primele, iar în caz de egalitate după **id**. | ||
+ | * | ||
+ | * Acțiunile apar în ordinea în care au fost efectuate. | ||
+ | </note> | ||
+ | |||
+ | === Acțiuni posibile === | ||
+ | |||
+ | * **ASSIGNED** – ticket-ul a fost atribuit unui developer. | ||
+ | |||
+ | <spoiler Exemplu JSON> | ||
+ | <code json> | ||
+ | { | ||
+ | "action": "ASSIGNED", | ||
+ | "by": "developer_name", | ||
+ | "timestamp": "YYYY-MM-DD" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | * **DE-ASSIGNED** – developer-ul a renunțat la ticket. | ||
+ | |||
+ | <spoiler Exemplu JSON> | ||
+ | <code json> | ||
+ | { | ||
+ | "action": "DE-ASSIGNED", | ||
+ | "by": "developer_name", | ||
+ | "timestamp": "YYYY-MM-DD" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | * **STATUS_CHANGED** – status-ul ticket-ului a fost schimbat. | ||
+ | |||
+ | <spoiler Exemplu JSON> | ||
+ | <code json> | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "OLD_STATUS", | ||
+ | "to": "NEW_STATUS", | ||
+ | "by": "developer_name", | ||
+ | "timestamp": "YYYY-MM-DD" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | * **ADDED_TO_MILESTONE** – ticket-ul a fost adăugat într-un milestone. | ||
+ | |||
+ | <spoiler Exemplu JSON> | ||
+ | <code json> | ||
+ | { | ||
+ | "action": "ADDED_TO_MILESTONE", | ||
+ | "milestone": "milestone_name", | ||
+ | "by": "manager_name", | ||
+ | "timestamp": "YYYY-MM-DD" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | ==== ==== | ||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "viewTicketHistory", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-25" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "viewTicketHistory", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-25", | ||
+ | "ticketHistory": [ | ||
+ | { | ||
+ | "id": 0, | ||
+ | "title": "Ticket 1", | ||
+ | "status": "CLOSED", | ||
+ | "actions": [ | ||
+ | { | ||
+ | "action": "ASSIGNED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-15" | ||
+ | }, | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "OPEN", | ||
+ | "to": "IN_PROGRESS", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-15" | ||
+ | }, | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "IN_PROGRESS", | ||
+ | "to": "RESOLVED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-18" | ||
+ | }, | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "RESOLVED", | ||
+ | "to": "CLOSED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-20" | ||
+ | } | ||
+ | ], | ||
+ | "comments": [ | ||
+ | { | ||
+ | "author": "dev_one", | ||
+ | "timestamp": "2025-09-20", | ||
+ | "message": "Fixed the issue." | ||
+ | } | ||
+ | ] | ||
+ | }, | ||
+ | { | ||
+ | "id": 1, | ||
+ | "title": "Ticket 2", | ||
+ | "status": "IN_PROGRESS", | ||
+ | "actions": [ | ||
+ | { | ||
+ | "action": "ASSIGNED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-22" | ||
+ | }, | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "OPEN", | ||
+ | "to": "IN_PROGRESS", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-22" | ||
+ | }, | ||
+ | { | ||
+ | "action": "DE-ASSIGNED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-23" | ||
+ | } | ||
+ | ], | ||
+ | "comments": [] | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | |||
+ | ===== search ===== | ||
+ | |||
+ | |||
+ | **Disponibilă pentru:** **Developer**, **Manager** | ||
+ | |||
+ | **Descriere:** | ||
+ | Permite căutarea avansată a ticketelor (sau developerilor, în cazul managerilor) pe baza unor criterii de filtrare. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | |||
+ | 1. Dacă un filtru este invalid pentru rolul utilizatorului, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Invalid filter <filter_name> for role <role>." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | ==== Reguli generale ==== | ||
+ | * Rezultatele sunt sortate după createdAt (cele mai vechi primele), apoi după id | ||
+ | * Dacă un filtru nu este specificat → nu se aplică filtrare pe acel câmp | ||
+ | * Dacă nu este specificat niciun filtru → comanda este echivalentă cu viewTickets | ||
+ | * Dacă nu există rezultate → se returnează o listă goală | ||
+ | |||
+ | <note warning> | ||
+ | **Atenție!** | ||
+ | Dacă sunt introduse mai multe filtre invalide, comanda va eșua la **primul filtru invalid**. | ||
+ | </note> | ||
+ | |||
+ | ==== Filtre Developer ==== | ||
+ | * Poate căuta: **doar tickete cu status OPEN** din milestone-urile la care este repartizat | ||
+ | * Filtre disponibile: | ||
+ | * businessPriority | ||
+ | * type | ||
+ | * createdAt | ||
+ | * createdBefore | ||
+ | * createdAfter | ||
+ | * availableForAssignment | ||
+ | |||
+ | ==== Filtre manager ==== | ||
+ | * Poate căuta: **toate ticketele din sistem** și **developerii din subordine** | ||
+ | * Filtre disponibile: | ||
+ | * toate filtrele Developer | ||
+ | * keywords | ||
+ | * expertiseArea | ||
+ | * seniority | ||
+ | * performanceScoreAbove | ||
+ | * performanceScoreBelow | ||
+ | |||
+ | <note warning> | ||
+ | **Atenție!** | ||
+ | * keywords este case-insensitive și caută potrivirea parțială sau completă în câmpurile text. | ||
+ | |||
+ | * Nu se aplică pentru câmpuri cu valori predefinite (enums). | ||
+ | | ||
+ | * În output, **matchingWords** arată cuvintele cheie găsite ca potrivire pentru keywords | ||
+ | |||
+ | </note> | ||
+ | |||
+ | |||
+ | <note warning> | ||
+ | **Atenție!** Dacă **availableForAssignment** = **true**, comanda returnează doar ticketele ce pot fi repartizate developerului curent (în funcție de senioritate, expertiză și milestone) | ||
+ | </note> | ||
+ | |||
+ | |||
+ | <note tip> | ||
+ | **Tip:** | ||
+ | Implementarea căutării trebuie să urmeze **Open-Closed Principle**, permițând adăugarea de noi strategii de filtrare fără modificarea codului existent. </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input – Developer:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "filters": { | ||
+ | "searchType": "TICKET", | ||
+ | "businessPriority": "HIGH", | ||
+ | "type": "BUG", | ||
+ | "createdAfter": "2025-09-01", | ||
+ | "availableForAssignment": true | ||
+ | } | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output – Developer:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "searchType": "TICKET", | ||
+ | "results": [ | ||
+ | { | ||
+ | "id": 0, | ||
+ | "type": "BUG", | ||
+ | "title": "Crash on settings page", | ||
+ | "businessPriority": "HIGH", | ||
+ | "status": "OPEN", | ||
+ | "createdAt": "2025-09-10", | ||
+ | "solvedAt": "", | ||
+ | "reportedBy": "cleopatra" | ||
+ | }, | ||
+ | { | ||
+ | "id": 3, | ||
+ | "type": "BUG", | ||
+ | "title": "Data sync failure", | ||
+ | "businessPriority": "HIGH", | ||
+ | "status": "OPEN", | ||
+ | "createdAt": "2025-09-15", | ||
+ | "solvedAt": "", | ||
+ | "reportedBy": "" | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input – Manager (tickets):** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "filters": { | ||
+ | "searchType": "TICKET", | ||
+ | "keywords": ["pay", "bug"], | ||
+ | "businessPriority": "HIGH", | ||
+ | "type": "BUG", | ||
+ | "createdAfter": "2025-09-01" | ||
+ | } | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output – Manager (tickets):** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "searchType": "TICKET", | ||
+ | "results": [ | ||
+ | { | ||
+ | "id": 5, | ||
+ | "type": "BUG", | ||
+ | "title": "Payment gateway error", | ||
+ | "businessPriority": "HIGH", | ||
+ | "status": "OPEN", | ||
+ | "createdAt": "2025-09-12", | ||
+ | "solvedAt": "", | ||
+ | "reportedBy": "user456", | ||
+ | "matchingWords": ["payment", "bug"] | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input – Manager (developers):** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "filters": { | ||
+ | "searchType": "DEVELOPER", | ||
+ | "expertiseArea": "BACKEND", | ||
+ | "seniority": "MID", | ||
+ | "performanceScoreAbove": number | ||
+ | } | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output – Manager (developers):** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "searchType": "DEVELOPER", | ||
+ | "results": [ | ||
+ | { | ||
+ | "username": "dev_two", | ||
+ | "expertiseArea": "BACKEND", | ||
+ | "seniority": "MID", | ||
+ | "performanceScore": number, | ||
+ | "hireDate": "2024-05-10" | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | ===== generatePerformanceReport ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Manager** | ||
+ | |||
+ | **Descriere:** Generează raportul lunar de performanță pentru toți developerii din subordinea managerului. În raport sunt incluse toate ticketele rezolvate (status **CLOSED**) în luna anterioară datei curente (preluată din **timestamp**). | ||
+ | |||
+ | ==== Calculare raport ==== | ||
+ | |||
+ | Scorul de performanță se calculează diferit pentru fiecare nivel de **seniority**. | ||
+ | |||
+ | <spoiler Bonusuri nivel de senioritate> | ||
+ | * **JUNIOR** → +5 | ||
+ | * **MID** → +15 | ||
+ | * **SENIOR** → +30 | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | === Junior Performance === | ||
+ | |||
+ | <spoiler Formula> | ||
+ | \\ | ||
+ | * juniorPerformance = max(0, 0.5 * closedTickets - ticketDiversityFactor) + seniorityBonus | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | Vom defini **ticketDiversityFactor** ca fiind coeficientul de variație dintre deviația standard și media aritmetică. | ||
+ | |||
+ | <spoiler Detalii calcul> | ||
+ | * **averageResolvedTicketType** | ||
+ | <code>(bugTickets + featureTickets + uiTickets) / 3</code> | ||
+ | * **standardDeviation** | ||
+ | <code>sqrt(((bugTickets - avg)^2 + (featureTickets - avg)^2 + (uiTickets - avg)^2) / 3)</code> | ||
+ | * **ticketDiversityFactor** | ||
+ | <code>standardDeviation / averageResolvedTicketType</code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | |||
+ | === Mid Performance === | ||
+ | |||
+ | <spoiler Formula> | ||
+ | \\ | ||
+ | * midPerformance = max(0, 0.5 * closedTickets + 0.7 * highPriorityTickets - 0.3 * averageResolutionTime) + seniorityBonus | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | <spoiler Detalii calcul Mid Performance> | ||
+ | \\ | ||
+ | * closedTickets = numărul total de tickete rezolvate | ||
+ | * highPriorityTickets = numărul de tickete rezolvate cu prioritate HIGH sau CRITICAL | ||
+ | * averageResolutionTime = media timpilor de rezolvare (zile) | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | === Senior Performance === | ||
+ | |||
+ | <spoiler Formula> | ||
+ | * seniorPerformance = max(0, 0.5 * closedTickets + 1.0 * highPriorityTickets - 0.5 * averageResolutionTime) + seniorityBonus | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | <spoiler Detalii calcul Senior Performance> | ||
+ | \\ | ||
+ | * closedTickets = numărul total de tickete rezolvate | ||
+ | * highPriorityTickets = numărul de tickete rezolvate cu prioritate HIGH sau CRITICAL | ||
+ | * averageResolutionTime = media timpilor de rezolvare (zile) | ||
+ | * Impactul ticketelor cu prioritate ridicată și timpul de rezolvare contează mai mult | ||
+ | * Formula penalizează timpi mari de rezolvare și răsplătește rezolvarea ticketelor importante | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | === Metode utile === | ||
+ | Puteti folosi următoarele metode în soluția temei: | ||
+ | |||
+ | <spoiler Java code> | ||
+ | <code java> | ||
+ | public static double averageResolvedTicketType(int bug, int feature, int ui) { | ||
+ | return (bug + feature + ui) / 3.0; | ||
+ | } | ||
+ | |||
+ | public static double standardDeviation(int bug, int feature, int ui) { | ||
+ | double mean = averageResolvedTicketType(bug, feature, ui); | ||
+ | double variance = (Math.pow(bug - mean, 2) + Math.pow(feature - mean, 2) + Math.pow(ui - mean, 2)) / 3.0; | ||
+ | return Math.sqrt(variance); | ||
+ | } | ||
+ | |||
+ | public static double ticketDiversityFactor(int bug, int feature, int ui) { | ||
+ | double mean = averageResolvedTicketType(bug, feature, ui); | ||
+ | |||
+ | // dacă nu există tickete, diversitatea este 0 | ||
+ | if (mean == 0.0) { | ||
+ | return 0.0; | ||
+ | } | ||
+ | |||
+ | double std = standardDeviation(bug, feature, ui); | ||
+ | return std / mean; | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** | ||
+ | <spoiler Exemplu input complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generatePerformanceReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-01" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** | ||
+ | <spoiler Exemplu output complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generatePerformanceReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-01", | ||
+ | "report": [ | ||
+ | { | ||
+ | "username": "dev_one", | ||
+ | "closedTickets": 5, | ||
+ | "averageResolutionTime": 4.2, | ||
+ | "ticketTypes": { | ||
+ | "BUG": 3, | ||
+ | "FEATURE_REQUEST": 1, | ||
+ | "UI_FEEDBACK": 1 | ||
+ | }, | ||
+ | "ticketPriorities": { | ||
+ | "LOW": 1, | ||
+ | "MEDIUM": 2, | ||
+ | "HIGH": 1, | ||
+ | "CRITICAL": 1 | ||
+ | }, | ||
+ | "performanceScore": 88.56, | ||
+ | "seniority": "SENIOR" | ||
+ | }, | ||
+ | { | ||
+ | "username": "dev_two", | ||
+ | "closedTickets": 3, | ||
+ | "averageResolutionTime": 5.0, | ||
+ | "ticketTypes": { | ||
+ | "BUG": 2, | ||
+ | "FEATURE_REQUEST": 1 | ||
+ | }, | ||
+ | "ticketPriorities": { | ||
+ | "LOW": 1, | ||
+ | "MEDIUM": 1, | ||
+ | "HIGH": 1 | ||
+ | }, | ||
+ | "performanceScore": 75.00, | ||
+ | "seniority": "MID" | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | |||
+ | ===== Ticket Risk ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Manager** | ||
+ | |||
+ | |||
+ | **Descriere:** Generează un raport pe baza metricii **ticket risk**. | ||
+ | |||
+ | **Comanda: generateTicketRiskReport** | ||
+ | |||
+ | <note tip> | ||
+ | Raportul este creat pe baza **tuturor** ticketelor **OPEN** si **IN_PROGRESS** din sistem, indiferent de managerul care a generat raportul. | ||
+ | </note> | ||
+ | |||
+ | **Calculare:** | ||
+ | \\ | ||
+ | <spoiler BUG> | ||
+ | **Formula:** | ||
+ | **frequency × severityFactor** | ||
+ | |||
+ | **Valoare maximă:** 12 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | frequency = ALWAYS (4) | ||
+ | severityFactor = SEVERE (3) | ||
+ | |||
+ | Risc brut = 4 × 3 = 12 | ||
+ | Risc final = (12 × 100) / 12 = 100.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler FEATURE_REQUEST> | ||
+ | **Formula:** | ||
+ | **businessValue + customerDemand** | ||
+ | |||
+ | **Valoare maximă:** 20 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | businessValue = XL (10) | ||
+ | customerDemand = HIGH (6) | ||
+ | |||
+ | Risc brut = 10 + 6 = 16 | ||
+ | Risc final = (16 × 100) / 20 = 80.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler UI_FEEDBACK> | ||
+ | **Formula:** | ||
+ | **(11 − usabilityScore) × businessValue** | ||
+ | |||
+ | **Valoare maximă:** 100 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | usabilityScore = 2 | ||
+ | businessValue = XL (10) | ||
+ | |||
+ | Risc brut = (11 − 2) × 10 = 90 | ||
+ | Risc final = (90 × 100) / 100 = 90.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | \\ | ||
+ | În urma raportului, fiecare categorie va avea un **calificativ**: | ||
+ | \\ | ||
+ | <spoiler Calificative risc> | ||
+ | \\ | ||
+ | ^ Interval Risc ^ Calificativ ^ | ||
+ | | 0 – 24 | **NEGLIJABIL** | | ||
+ | | 25 – 49 | **MEDIU** | | ||
+ | | 50 – 74 | **SEMNIFICATIV** | | ||
+ | | 75 – 100 | **MAJOR** | | ||
+ | </spoiler> | ||
+ | |||
+ | ===== ===== | ||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "generateTicketRiskReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "generateTicketRiskReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30", | ||
+ | "report": { | ||
+ | "totalTickets": 20, | ||
+ | "ticketsByType": { | ||
+ | "BUG": 10, | ||
+ | "FEATURE_REQUEST": 6, | ||
+ | "UI_FEEDBACK": 4 | ||
+ | }, | ||
+ | "ticketsByPriority": { | ||
+ | "LOW": 5, | ||
+ | "MEDIUM": 7, | ||
+ | "HIGH": 6, | ||
+ | "CRITICAL": 2 | ||
+ | }, | ||
+ | "riskByType": { | ||
+ | "BUG": "NEGLIJABIL", | ||
+ | "FEATURE_REQUEST": "MEDIU", | ||
+ | "UI_FEEDBACK": "SEMNIFICATIV" | ||
+ | } | ||
+ | } | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | ===== Resolution Efficiency ===== | ||
+ | |||
+ | **Disponibilă pentru: Manager** | ||
+ | |||
+ | **Descriere:** Evaluează cât de eficientă este echipa în a rezolva tickete. Se vor considera doar tickete în stările **RESOLVED** și **CLOSED**. | ||
+ | |||
+ | **Comanda:**: **generateResolutionEfficiencyReport** | ||
+ | |||
+ | <note tip> | ||
+ | Raportul este creat pe baza **tuturor ticketelor** **CLOSED** si **RESOLVED** din sistem, indiferent de managerul care a generat raportul. | ||
+ | </note> | ||
+ | |||
+ | <spoiler BUG> | ||
+ | **Formula:** | ||
+ | |||
+ | (bugFrequency + severityFactor) × 10 / daysToResolve | ||
+ | |||
+ | |||
+ | **Valoare maximă:** 70 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | frequency = FREQUENT (3) | ||
+ | severityFactor = MODERATE (2) | ||
+ | daysToResolve = 2 | ||
+ | |||
+ | Scor eficiență = (3 + 2) × 10 / 2 = 25 | ||
+ | Eficiență finală = (25 × 100) / 70 = 35.71 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler FEATURE_REQUEST> | ||
+ | **Formula:** | ||
+ | |||
+ | (businessValue + customerDemand) / daysToResolve | ||
+ | |||
+ | |||
+ | **Valoare maximă:** 20 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | businessValue = L (6) | ||
+ | customerDemand = HIGH (6) | ||
+ | daysToResolve = 2 | ||
+ | |||
+ | Scor eficiență = (6 + 6) / 2 = 6.00 | ||
+ | Eficiență finală = (6 × 100) / 20 = 30.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler UI_FEEDBACK> | ||
+ | **Formula:** | ||
+ | |||
+ | (usabilityScore + businessValue) / 2 | ||
+ | |||
+ | |||
+ | **Valoare maximă:** 20 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | usabilityScore = 9 | ||
+ | businessValue = XL (10) | ||
+ | |||
+ | Scor eficiență = (9 + 10) / 2 = 9.5 | ||
+ | Eficiență finală = (9.5 × 100) / 20 = 47.50 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | <note warning> | ||
+ | **Atenție!** | ||
+ | **daysToResolve** = numărul de zile dintre **assignedAt** și data la care ticket-ul a fost marcat ultima dată ca **RESOLVED** sau **CLOSED**. | ||
+ | </note> | ||
+ | |||
+ | ===== ===== | ||
+ | **Exemplu Input:** | ||
+ | <spoiler Exemplu input complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generateResolutionEfficiencyReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | **Exemplu Output:** | ||
+ | <spoiler Exemplu output complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generateResolutionEfficiencyReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30", | ||
+ | "report": { | ||
+ | "totalTickets": 20, | ||
+ | "ticketsByType": { | ||
+ | "BUG": 10, | ||
+ | "FEATURE_REQUEST": 6, | ||
+ | "UI_FEEDBACK": 4 | ||
+ | }, | ||
+ | "ticketsByPriority": { | ||
+ | "LOW": 5, | ||
+ | "MEDIUM": 7, | ||
+ | "HIGH": 6, | ||
+ | "CRITICAL": 2 | ||
+ | }, | ||
+ | "efficiencyByType": { | ||
+ | "BUG": 65.50, | ||
+ | "FEATURE_REQUEST": 55.30, | ||
+ | "UI_FEEDBACK": 40.25 | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | ===== Customer Impact ===== | ||
+ | |||
+ | **Disponibilă pentru: Manager** | ||
+ | |||
+ | **Descriere:** Estimează **impactul asupra clienților** al ticketelor. | ||
+ | |||
+ | **Comanda:** **generateCustomerImpactReport** | ||
+ | |||
+ | <note tip> | ||
+ | Raportul este creat pe baza **tuturor ticketelor** aflate în stările **OPEN** și **IN_PROGRESS**, indiferent de managerul care a generat raportul. | ||
+ | </note> | ||
+ | |||
+ | |||
+ | <spoiler BUG> | ||
+ | **Formula:** | ||
+ | |||
+ | frequency × businessPriority × severityFactor | ||
+ | |||
+ | **Valoare maximă:** 48 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | frequency = ALWAYS (4) | ||
+ | businessPriority = CRITICAL (4) | ||
+ | severityFactor = SEVERE (3) | ||
+ | |||
+ | Impact brut = 4 × 4 × 3 = 48 | ||
+ | Impact final = (48 × 100) / 48 = 100.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler FEATURE_REQUEST> | ||
+ | **Formula:** | ||
+ | |||
+ | businessValue × customerDemand | ||
+ | |||
+ | **Valoare maximă:** 100 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | businessValue = M (3) | ||
+ | customerDemand = HIGH (6) | ||
+ | |||
+ | Impact brut = 3 × 6 = 18 | ||
+ | Impact final = (18 × 100) / 100 = 18.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler UI_FEEDBACK> | ||
+ | **Formula:** | ||
+ | |||
+ | businessValue × usabilityScore | ||
+ | |||
+ | **Valoare maximă:** 100 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | businessValue = L (6) | ||
+ | usabilityScore = 9 | ||
+ | |||
+ | Impact brut = 6 × 9 = 54 | ||
+ | Impact final = (54 × 100) / 100 = 54.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | ===== ===== | ||
+ | **Exemplu Input:** | ||
+ | <spoiler Exemplu input complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generateCustomerImpactReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | **Exemplu Output:** | ||
+ | <spoiler Exemplu output complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generateCustomerImpactReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30", | ||
+ | "report": { | ||
+ | "totalTickets": 20, | ||
+ | "ticketsByType": { | ||
+ | "BUG": 10, | ||
+ | "FEATURE_REQUEST": 6, | ||
+ | "UI_FEEDBACK": 4 | ||
+ | }, | ||
+ | "ticketsByPriority": { | ||
+ | "LOW": 5, | ||
+ | "MEDIUM": 7, | ||
+ | "HIGH": 6, | ||
+ | "CRITICAL": 2 | ||
+ | }, | ||
+ | "customerImpactByType": { | ||
+ | "BUG": 75.55, | ||
+ | "FEATURE_REQUEST": 60.05, | ||
+ | "UI_FEEDBACK": 45.02 | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||