# app/exceptions/team.py """ Team management specific exceptions. """ from typing import Any from .base import ( AuthorizationException, BusinessLogicException, ConflictException, ResourceNotFoundException, ValidationException, ) class TeamMemberNotFoundException(ResourceNotFoundException): """Raised when a team member is not found.""" def __init__(self, user_id: int, vendor_id: int | None = None): details = {"user_id": user_id} if vendor_id: details["vendor_id"] = vendor_id message = ( f"Team member with user ID '{user_id}' not found in vendor {vendor_id}" ) else: message = f"Team member with user ID '{user_id}' not found" super().__init__( resource_type="TeamMember", identifier=str(user_id), message=message, error_code="TEAM_MEMBER_NOT_FOUND", details=details, ) class TeamMemberAlreadyExistsException(ConflictException): """Raised when trying to add a user who is already a team member.""" def __init__(self, user_id: int, vendor_id: int): super().__init__( message=f"User {user_id} is already a team member of vendor {vendor_id}", error_code="TEAM_MEMBER_ALREADY_EXISTS", details={ "user_id": user_id, "vendor_id": vendor_id, }, ) class TeamInvitationNotFoundException(ResourceNotFoundException): """Raised when a team invitation is not found.""" def __init__(self, invitation_token: str): super().__init__( resource_type="TeamInvitation", identifier=invitation_token, message=f"Team invitation with token '{invitation_token}' not found or expired", error_code="TEAM_INVITATION_NOT_FOUND", ) class TeamInvitationExpiredException(BusinessLogicException): """Raised when trying to accept an expired invitation.""" def __init__(self, invitation_token: str): super().__init__( message="Team invitation has expired", error_code="TEAM_INVITATION_EXPIRED", details={"invitation_token": invitation_token}, ) class TeamInvitationAlreadyAcceptedException(ConflictException): """Raised when trying to accept an already accepted invitation.""" def __init__(self, invitation_token: str): super().__init__( message="Team invitation has already been accepted", error_code="TEAM_INVITATION_ALREADY_ACCEPTED", details={"invitation_token": invitation_token}, ) class UnauthorizedTeamActionException(AuthorizationException): """Raised when user tries to perform team action without permission.""" def __init__( self, action: str, user_id: int | None = None, required_permission: str | None = None, ): details = {"action": action} if user_id: details["user_id"] = user_id if required_permission: details["required_permission"] = required_permission super().__init__( message=f"Unauthorized to perform action: {action}", error_code="UNAUTHORIZED_TEAM_ACTION", details=details, ) class CannotRemoveOwnerException(BusinessLogicException): """Raised when trying to remove the vendor owner from team.""" def __init__(self, user_id: int, vendor_id: int): super().__init__( message="Cannot remove vendor owner from team", error_code="CANNOT_REMOVE_OWNER", details={ "user_id": user_id, "vendor_id": vendor_id, }, ) class CannotModifyOwnRoleException(BusinessLogicException): """Raised when user tries to modify their own role.""" def __init__(self, user_id: int): super().__init__( message="Cannot modify your own role", error_code="CANNOT_MODIFY_OWN_ROLE", details={"user_id": user_id}, ) class RoleNotFoundException(ResourceNotFoundException): """Raised when a role is not found.""" def __init__(self, role_id: int, vendor_id: int | None = None): details = {"role_id": role_id} if vendor_id: details["vendor_id"] = vendor_id message = f"Role with ID '{role_id}' not found in vendor {vendor_id}" else: message = f"Role with ID '{role_id}' not found" super().__init__( resource_type="Role", identifier=str(role_id), message=message, error_code="ROLE_NOT_FOUND", details=details, ) class InvalidRoleException(ValidationException): """Raised when role data is invalid.""" def __init__( self, message: str = "Invalid role data", field: str | None = None, details: dict[str, Any] | None = None, ): super().__init__( message=message, field=field, details=details, ) self.error_code = "INVALID_ROLE_DATA" class InsufficientTeamPermissionsException(AuthorizationException): """Raised when user lacks required team permissions for an action.""" def __init__( self, required_permission: str, user_id: int | None = None, action: str | None = None, ): details = {"required_permission": required_permission} if user_id: details["user_id"] = user_id if action: details["action"] = action message = f"Insufficient team permissions. Required: {required_permission}" super().__init__( message=message, error_code="INSUFFICIENT_TEAM_PERMISSIONS", details=details, ) class MaxTeamMembersReachedException(BusinessLogicException): """Raised when vendor has reached maximum team members limit.""" def __init__(self, max_members: int, vendor_id: int): super().__init__( message=f"Maximum number of team members reached ({max_members})", error_code="MAX_TEAM_MEMBERS_REACHED", details={ "max_members": max_members, "vendor_id": vendor_id, }, ) class TeamValidationException(ValidationException): """Raised when team operation validation fails.""" def __init__( self, message: str = "Team operation validation failed", field: str | None = None, validation_errors: dict[str, str] | None = None, ): details = {} if validation_errors: details["validation_errors"] = validation_errors super().__init__( message=message, field=field, details=details, ) self.error_code = "TEAM_VALIDATION_FAILED" class InvalidInvitationDataException(ValidationException): """Raised when team invitation data is invalid.""" def __init__( self, message: str = "Invalid invitation data", field: str | None = None, details: dict[str, Any] | None = None, ): super().__init__( message=message, field=field, details=details, ) self.error_code = "INVALID_INVITATION_DATA" # ============================================================================ # NEW: Add InvalidInvitationTokenException # ============================================================================ class InvalidInvitationTokenException(ValidationException): """Raised when invitation token is invalid, expired, or already used. This is a general exception for any invitation token validation failure. Use this when checking invitation tokens during the acceptance flow. """ def __init__( self, message: str = "Invalid or expired invitation token", invitation_token: str | None = None, ): details = {} if invitation_token: details["invitation_token"] = invitation_token super().__init__( message=message, field="invitation_token", details=details, ) self.error_code = "INVALID_INVITATION_TOKEN"