- Services now use db.flush() instead of db.commit() for database operations - API endpoints handle transaction commit after service calls - Remove db.rollback() from services (let exception handlers manage this) - Ensures consistent transaction boundaries at API layer This pattern gives API endpoints full control over when to commit, allowing for better error handling and potential multi-operation transactions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
218 lines
6.1 KiB
Python
218 lines
6.1 KiB
Python
# app/services/team_service.py
|
|
"""
|
|
Team service for vendor team management.
|
|
|
|
This module provides:
|
|
- Team member invitation
|
|
- Role management
|
|
- Team member CRUD operations
|
|
"""
|
|
|
|
import logging
|
|
from datetime import UTC, datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.exceptions import ValidationException
|
|
from models.database.user import User
|
|
from models.database.vendor import Role, VendorUser
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class TeamService:
|
|
"""Service for team management operations."""
|
|
|
|
def get_team_members(
|
|
self, db: Session, vendor_id: int, current_user: User
|
|
) -> list[dict[str, Any]]:
|
|
"""
|
|
Get all team members for vendor.
|
|
|
|
Args:
|
|
db: Database session
|
|
vendor_id: Vendor ID
|
|
current_user: Current user
|
|
|
|
Returns:
|
|
List of team members
|
|
"""
|
|
try:
|
|
vendor_users = (
|
|
db.query(VendorUser)
|
|
.filter(VendorUser.vendor_id == vendor_id, VendorUser.is_active == True)
|
|
.all()
|
|
)
|
|
|
|
members = []
|
|
for vu in vendor_users:
|
|
members.append(
|
|
{
|
|
"id": vu.user_id,
|
|
"email": vu.user.email,
|
|
"first_name": vu.user.first_name,
|
|
"last_name": vu.user.last_name,
|
|
"role": vu.role.name,
|
|
"role_id": vu.role_id,
|
|
"is_active": vu.is_active,
|
|
"joined_at": vu.created_at,
|
|
}
|
|
)
|
|
|
|
return members
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting team members: {str(e)}")
|
|
raise ValidationException("Failed to retrieve team members")
|
|
|
|
def invite_team_member(
|
|
self, db: Session, vendor_id: int, invitation_data: dict, current_user: User
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Invite a new team member.
|
|
|
|
Args:
|
|
db: Database session
|
|
vendor_id: Vendor ID
|
|
invitation_data: Invitation details
|
|
current_user: Current user
|
|
|
|
Returns:
|
|
Invitation result
|
|
"""
|
|
try:
|
|
# TODO: Implement full invitation flow with email
|
|
# For now, return placeholder
|
|
return {
|
|
"message": "Team invitation feature coming soon",
|
|
"email": invitation_data.get("email"),
|
|
"role": invitation_data.get("role"),
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error inviting team member: {str(e)}")
|
|
raise ValidationException("Failed to invite team member")
|
|
|
|
def update_team_member(
|
|
self,
|
|
db: Session,
|
|
vendor_id: int,
|
|
user_id: int,
|
|
update_data: dict,
|
|
current_user: User,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Update team member role or status.
|
|
|
|
Args:
|
|
db: Database session
|
|
vendor_id: Vendor ID
|
|
user_id: User ID to update
|
|
update_data: Update data
|
|
current_user: Current user
|
|
|
|
Returns:
|
|
Updated member info
|
|
"""
|
|
try:
|
|
vendor_user = (
|
|
db.query(VendorUser)
|
|
.filter(
|
|
VendorUser.vendor_id == vendor_id, VendorUser.user_id == user_id
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if not vendor_user:
|
|
raise ValidationException("Team member not found")
|
|
|
|
# Update fields
|
|
if "role_id" in update_data:
|
|
vendor_user.role_id = update_data["role_id"]
|
|
|
|
if "is_active" in update_data:
|
|
vendor_user.is_active = update_data["is_active"]
|
|
|
|
vendor_user.updated_at = datetime.now(UTC)
|
|
db.flush()
|
|
db.refresh(vendor_user)
|
|
|
|
return {
|
|
"message": "Team member updated successfully",
|
|
"user_id": user_id,
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error updating team member: {str(e)}")
|
|
raise ValidationException("Failed to update team member")
|
|
|
|
def remove_team_member(
|
|
self, db: Session, vendor_id: int, user_id: int, current_user: User
|
|
) -> bool:
|
|
"""
|
|
Remove team member from vendor.
|
|
|
|
Args:
|
|
db: Database session
|
|
vendor_id: Vendor ID
|
|
user_id: User ID to remove
|
|
current_user: Current user
|
|
|
|
Returns:
|
|
True if removed
|
|
"""
|
|
try:
|
|
vendor_user = (
|
|
db.query(VendorUser)
|
|
.filter(
|
|
VendorUser.vendor_id == vendor_id, VendorUser.user_id == user_id
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if not vendor_user:
|
|
raise ValidationException("Team member not found")
|
|
|
|
# Soft delete
|
|
vendor_user.is_active = False
|
|
vendor_user.updated_at = datetime.now(UTC)
|
|
|
|
logger.info(f"Removed user {user_id} from vendor {vendor_id}")
|
|
return True
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error removing team member: {str(e)}")
|
|
raise ValidationException("Failed to remove team member")
|
|
|
|
def get_vendor_roles(self, db: Session, vendor_id: int) -> list[dict[str, Any]]:
|
|
"""
|
|
Get available roles for vendor.
|
|
|
|
Args:
|
|
db: Database session
|
|
vendor_id: Vendor ID
|
|
|
|
Returns:
|
|
List of roles
|
|
"""
|
|
try:
|
|
roles = db.query(Role).filter(Role.vendor_id == vendor_id).all()
|
|
|
|
return [
|
|
{
|
|
"id": role.id,
|
|
"name": role.name,
|
|
"permissions": role.permissions,
|
|
}
|
|
for role in roles
|
|
]
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting vendor roles: {str(e)}")
|
|
raise ValidationException("Failed to retrieve roles")
|
|
|
|
|
|
# Create service instance
|
|
team_service = TeamService()
|