Spaces:
Sleeping
Sleeping
fix:notification data modified
Browse files- src/profile/notify.py +3 -3
- src/profile/router.py +39 -15
- src/profile/schemas.py +1 -0
- src/profile/utils.py +9 -1
src/profile/notify.py
CHANGED
|
@@ -42,7 +42,7 @@ async def send_leave_request_notification(session, user, leave, mentor_ids, lead
|
|
| 42 |
f"{user.user_name} requested leave",
|
| 43 |
{
|
| 44 |
"type": "leave_request",
|
| 45 |
-
"screen": "MentorApproval",
|
| 46 |
"leave_id": str(leave.id),
|
| 47 |
},
|
| 48 |
priority="high",
|
|
@@ -64,7 +64,7 @@ async def send_leave_request_notification(session, user, leave, mentor_ids, lead
|
|
| 64 |
f"{user.user_name} requested leave",
|
| 65 |
{
|
| 66 |
"type": "leave_request",
|
| 67 |
-
"screen": "LeaveDetails",
|
| 68 |
"leave_id": str(leave.id),
|
| 69 |
},
|
| 70 |
priority="high",
|
|
@@ -75,7 +75,7 @@ async def send_leave_request_notification(session, user, leave, mentor_ids, lead
|
|
| 75 |
# SEND TO USER + TEAM LEAD
|
| 76 |
# -------------------------------
|
| 77 |
async def send_leave_status_notification(session, leave, mentor_name, lead_ids):
|
| 78 |
-
title =
|
| 79 |
body = f"Your leave was {leave.status.lower()} by {mentor_name}"
|
| 80 |
|
| 81 |
# Send to USER
|
|
|
|
| 42 |
f"{user.user_name} requested leave",
|
| 43 |
{
|
| 44 |
"type": "leave_request",
|
| 45 |
+
"screen": "MentorApproval",
|
| 46 |
"leave_id": str(leave.id),
|
| 47 |
},
|
| 48 |
priority="high",
|
|
|
|
| 64 |
f"{user.user_name} requested leave",
|
| 65 |
{
|
| 66 |
"type": "leave_request",
|
| 67 |
+
"screen": "LeaveDetails",
|
| 68 |
"leave_id": str(leave.id),
|
| 69 |
},
|
| 70 |
priority="high",
|
|
|
|
| 75 |
# SEND TO USER + TEAM LEAD
|
| 76 |
# -------------------------------
|
| 77 |
async def send_leave_status_notification(session, leave, mentor_name, lead_ids):
|
| 78 |
+
title = "Leave status"
|
| 79 |
body = f"Your leave was {leave.status.lower()} by {mentor_name}"
|
| 80 |
|
| 81 |
# Send to USER
|
src/profile/router.py
CHANGED
|
@@ -29,7 +29,7 @@ from src.profile.schemas import (
|
|
| 29 |
ApproveRejectRequest,
|
| 30 |
)
|
| 31 |
from sqlalchemy import desc
|
| 32 |
-
|
| 33 |
from datetime import datetime
|
| 34 |
from src.profile.service import create_leave, mentor_decide_leave
|
| 35 |
|
|
@@ -188,24 +188,44 @@ async def list_notifications(
|
|
| 188 |
leave_lead = str(leave.lead_id)
|
| 189 |
current = str(user_id)
|
| 190 |
|
|
|
|
|
|
|
|
|
|
| 191 |
employee = await session.get(Users, uuid.UUID(leave_user))
|
| 192 |
employee_name = employee.user_name if employee else "Unknown User"
|
| 193 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
# ---------- USER ----------
|
| 195 |
if leave_user == current:
|
| 196 |
# User should NOT see pending
|
| 197 |
if leave.status == LeaveStatus.PENDING:
|
| 198 |
continue
|
| 199 |
|
| 200 |
-
|
| 201 |
-
|
|
|
|
|
|
|
|
|
|
| 202 |
|
| 203 |
# ---------- MENTOR ----------
|
| 204 |
elif leave_mentor == current:
|
| 205 |
# Mentor should ONLY see pending
|
| 206 |
if leave.status == LeaveStatus.PENDING:
|
| 207 |
-
title = "
|
| 208 |
-
body = f"{leave.
|
| 209 |
else:
|
| 210 |
continue # Mentor should not see approved/rejected
|
| 211 |
|
|
@@ -214,10 +234,10 @@ async def list_notifications(
|
|
| 214 |
# Lead sees ALL statuses
|
| 215 |
if leave.status == LeaveStatus.PENDING:
|
| 216 |
title = "Pending Leave Request"
|
| 217 |
-
body = f"{
|
| 218 |
else:
|
| 219 |
-
title = f"Leave {
|
| 220 |
-
body = f"{
|
| 221 |
|
| 222 |
else:
|
| 223 |
continue # no match → skip
|
|
@@ -291,7 +311,7 @@ async def mentor_pending_leaves(
|
|
| 291 |
):
|
| 292 |
mentor_uuid = uuid.UUID(mentor_id)
|
| 293 |
|
| 294 |
-
|
| 295 |
|
| 296 |
mentor_team = (
|
| 297 |
await session.exec(
|
|
@@ -344,6 +364,7 @@ async def mentor_pending_leaves(
|
|
| 344 |
lead_id=str(leave.lead_id),
|
| 345 |
user_name=user_name,
|
| 346 |
updated_at=(leave.updated_at.isoformat() if leave.updated_at else None),
|
|
|
|
| 347 |
)
|
| 348 |
)
|
| 349 |
|
|
@@ -537,9 +558,12 @@ async def get_profile_details(
|
|
| 537 |
sub_mentor_names = [u.user_name for u in sub_mentor_users]
|
| 538 |
sub_mentor_emails = [u.email_id for u in sub_mentor_users]
|
| 539 |
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
|
|
|
|
|
|
|
|
|
| 543 |
|
| 544 |
lead_label = "Mentor" if mentor_names else "Team Lead"
|
| 545 |
|
|
@@ -550,9 +574,9 @@ async def get_profile_details(
|
|
| 550 |
"name": user.user_name,
|
| 551 |
"email": user.email_id,
|
| 552 |
"team_name": team.name,
|
| 553 |
-
"lead_label": lead_label,
|
| 554 |
-
"lead_name": final_lead_name,
|
| 555 |
-
"lead_email": final_lead_email,
|
| 556 |
"join_date": user.join_date,
|
| 557 |
},
|
| 558 |
)
|
|
|
|
| 29 |
ApproveRejectRequest,
|
| 30 |
)
|
| 31 |
from sqlalchemy import desc
|
| 32 |
+
from src.profile.utils import safe_uuid
|
| 33 |
from datetime import datetime
|
| 34 |
from src.profile.service import create_leave, mentor_decide_leave
|
| 35 |
|
|
|
|
| 188 |
leave_lead = str(leave.lead_id)
|
| 189 |
current = str(user_id)
|
| 190 |
|
| 191 |
+
leave_type_text = leave.leave_type.name.lower() # "sick", "casual"
|
| 192 |
+
status_text = leave.status.lower()
|
| 193 |
+
|
| 194 |
employee = await session.get(Users, uuid.UUID(leave_user))
|
| 195 |
employee_name = employee.user_name if employee else "Unknown User"
|
| 196 |
|
| 197 |
+
# Fetch mentor name safely
|
| 198 |
+
mentor_id_safe = safe_uuid(leave_mentor)
|
| 199 |
+
mentor_user = (
|
| 200 |
+
await session.get(Users, mentor_id_safe) if mentor_id_safe else None
|
| 201 |
+
)
|
| 202 |
+
mentor_name = mentor_user.user_name if mentor_user else None
|
| 203 |
+
|
| 204 |
+
# Fetch lead name safely
|
| 205 |
+
lead_id_safe = safe_uuid(leave_lead)
|
| 206 |
+
lead_user = await session.get(Users, lead_id_safe) if lead_id_safe else None
|
| 207 |
+
lead_name = lead_user.user_name if lead_user else None
|
| 208 |
+
|
| 209 |
+
approver_name = mentor_name or lead_name or "Your manager"
|
| 210 |
+
|
| 211 |
# ---------- USER ----------
|
| 212 |
if leave_user == current:
|
| 213 |
# User should NOT see pending
|
| 214 |
if leave.status == LeaveStatus.PENDING:
|
| 215 |
continue
|
| 216 |
|
| 217 |
+
status_word = leave.status.lower()
|
| 218 |
+
title = (
|
| 219 |
+
f"{approver_name} {status_word} your {leave.leave_type.lower()} leave"
|
| 220 |
+
)
|
| 221 |
+
body = f"{leave.reject_reason or ''}"
|
| 222 |
|
| 223 |
# ---------- MENTOR ----------
|
| 224 |
elif leave_mentor == current:
|
| 225 |
# Mentor should ONLY see pending
|
| 226 |
if leave.status == LeaveStatus.PENDING:
|
| 227 |
+
title = f"{employee_name} requested {leave_type_text} leave"
|
| 228 |
+
body = f"{leave.reason} Days: {leave.days} "
|
| 229 |
else:
|
| 230 |
continue # Mentor should not see approved/rejected
|
| 231 |
|
|
|
|
| 234 |
# Lead sees ALL statuses
|
| 235 |
if leave.status == LeaveStatus.PENDING:
|
| 236 |
title = "Pending Leave Request"
|
| 237 |
+
body = f"{employee_name} requested {leave_type_text} leave"
|
| 238 |
else:
|
| 239 |
+
title = f"Leave {status_text}"
|
| 240 |
+
body = f"{leave_type_text} updated"
|
| 241 |
|
| 242 |
else:
|
| 243 |
continue # no match → skip
|
|
|
|
| 311 |
):
|
| 312 |
mentor_uuid = uuid.UUID(mentor_id)
|
| 313 |
|
| 314 |
+
|
| 315 |
|
| 316 |
mentor_team = (
|
| 317 |
await session.exec(
|
|
|
|
| 364 |
lead_id=str(leave.lead_id),
|
| 365 |
user_name=user_name,
|
| 366 |
updated_at=(leave.updated_at.isoformat() if leave.updated_at else None),
|
| 367 |
+
requested_at=leave.requested_at.isoformat() if leave.requested_at else None,
|
| 368 |
)
|
| 369 |
)
|
| 370 |
|
|
|
|
| 558 |
sub_mentor_names = [u.user_name for u in sub_mentor_users]
|
| 559 |
sub_mentor_emails = [u.email_id for u in sub_mentor_users]
|
| 560 |
|
| 561 |
+
final_lead_name = (
|
| 562 |
+
", ".join(mentor_names) if mentor_names else ", ".join(sub_mentor_names)
|
| 563 |
+
)
|
| 564 |
+
final_lead_email = (
|
| 565 |
+
", ".join(mentor_emails) if mentor_emails else ", ".join(sub_mentor_emails)
|
| 566 |
+
)
|
| 567 |
|
| 568 |
lead_label = "Mentor" if mentor_names else "Team Lead"
|
| 569 |
|
|
|
|
| 574 |
"name": user.user_name,
|
| 575 |
"email": user.email_id,
|
| 576 |
"team_name": team.name,
|
| 577 |
+
"lead_label": lead_label, # 🔥 Frontend uses this
|
| 578 |
+
"lead_name": final_lead_name, # 🔥 Frontend uses this
|
| 579 |
+
"lead_email": final_lead_email, # optional
|
| 580 |
"join_date": user.join_date,
|
| 581 |
},
|
| 582 |
)
|
src/profile/schemas.py
CHANGED
|
@@ -66,6 +66,7 @@ class LeaveResponse(BaseModel):
|
|
| 66 |
lead_id: str
|
| 67 |
user_name: Optional[str] = None
|
| 68 |
updated_at: Optional[str] = None
|
|
|
|
| 69 |
|
| 70 |
|
| 71 |
class DeviceTokenIn(BaseModel):
|
|
|
|
| 66 |
lead_id: str
|
| 67 |
user_name: Optional[str] = None
|
| 68 |
updated_at: Optional[str] = None
|
| 69 |
+
requested_at: Optional[str] = None
|
| 70 |
|
| 71 |
|
| 72 |
class DeviceTokenIn(BaseModel):
|
src/profile/utils.py
CHANGED
|
@@ -20,7 +20,8 @@ from src.core.models import (
|
|
| 20 |
) # adjust import path if differs
|
| 21 |
from src.core.config import settings # for FCM key if needed
|
| 22 |
import httpx
|
| 23 |
-
|
|
|
|
| 24 |
|
| 25 |
def calculate_days(
|
| 26 |
from_date: date, to_date: date, include_weekends: bool = True
|
|
@@ -29,6 +30,13 @@ def calculate_days(
|
|
| 29 |
delta = (to_date - from_date).days + 1
|
| 30 |
return max(0, delta)
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
async def find_mentor_and_lead(
|
| 34 |
session: AsyncSession, user_id
|
|
|
|
| 20 |
) # adjust import path if differs
|
| 21 |
from src.core.config import settings # for FCM key if needed
|
| 22 |
import httpx
|
| 23 |
+
from uuid import UUID
|
| 24 |
+
import uuid
|
| 25 |
|
| 26 |
def calculate_days(
|
| 27 |
from_date: date, to_date: date, include_weekends: bool = True
|
|
|
|
| 30 |
delta = (to_date - from_date).days + 1
|
| 31 |
return max(0, delta)
|
| 32 |
|
| 33 |
+
def safe_uuid(value):
|
| 34 |
+
try:
|
| 35 |
+
return uuid.UUID(str(value))
|
| 36 |
+
except:
|
| 37 |
+
return None
|
| 38 |
+
|
| 39 |
+
|
| 40 |
|
| 41 |
async def find_mentor_and_lead(
|
| 42 |
session: AsyncSession, user_id
|