# Business Logic Service for Lead Management from typing import List, Dict, Any, Optional from uuid import UUID from datetime import datetime from .repositories import LeadRepository class LeadService: def __init__(self, repository: LeadRepository): self.repo = repository # Institution Services def list_institutions(self) -> List[Dict[str, Any]]: """Get all institutions with contact counts""" return self.repo.get_institutions_with_counts() def create_institution(self, name: str, user: str) -> Dict[str, Any]: """Create a new institution""" # Validation if not name or len(name.strip()) == 0: raise ValueError("Institution name cannot be empty") # Create institution institution = self.repo.create_institution(name.strip(), user) # Note: Audit logging removed as it requires different implementation # Can be added later with proper audit system integration return institution def update_institution(self, institution_id: UUID, name: str, user: str) -> Dict[str, Any]: """Update institution name""" # Validation if not name or len(name.strip()) == 0: raise ValueError("Institution name cannot be empty") # Get current institution current = self.repo.get_institution_by_id(institution_id) if not current: raise ValueError("Institution not found") # Update institution = self.repo.update_institution(institution_id, name.strip()) return institution # Contact Services def list_contacts_by_institution(self, institution_id: UUID) -> List[Dict[str, Any]]: """Get all contacts for an institution""" return self.repo.get_contacts_by_institution(institution_id) def create_contact(self, data: Dict[str, Any], user: str) -> Dict[str, Any]: """Create a new contact""" # Validation if not data.get('first_name') or not data.get('last_name'): raise ValueError("First and last name are required") if not data.get('institution_id'): raise ValueError("Institution ID is required") # Create contact contact = self.repo.create_contact(data) return contact def get_contact_details(self, contact_id: UUID) -> Dict[str, Any]: """Get full contact information including details and notes""" contact = self.repo.get_contact_with_details(contact_id) if not contact: raise ValueError("Contact not found") # Group details by type contact['phones'] = [d for d in contact.get('details', []) if d['detail_type'] == 'phone'] contact['emails'] = [d for d in contact.get('details', []) if d['detail_type'] == 'email'] return contact def update_contact(self, contact_id: UUID, data: Dict[str, Any], user: str) -> Dict[str, Any]: """Update contact information""" # Validation if not data.get('first_name') or not data.get('last_name'): raise ValueError("First and last name are required") # Update contact contact = self.repo.update_contact(contact_id, data) return contact # Contact Details Services def add_phone(self, contact_id: UUID, phone_number: str, phone_type: str = None, user: str = None) -> Dict[str, Any]: """Add phone number to contact""" if not phone_number: raise ValueError("Phone number is required") detail = self.repo.add_contact_detail( contact_id, 'phone', phone_number, phone_type ) return detail def add_email(self, contact_id: UUID, email: str, email_type: str = None, user: str = None) -> Dict[str, Any]: """Add email to contact""" if not email: raise ValueError("Email is required") # Basic email validation if '@' not in email: raise ValueError("Invalid email format") detail = self.repo.add_contact_detail( contact_id, 'email', email, email_type ) return detail def update_contact_detail(self, detail_id: UUID, detail_value: str, detail_label: str = None, user: str = None) -> Dict[str, Any]: """Update a contact detail (phone/email)""" if not detail_value or len(detail_value.strip()) == 0: raise ValueError("Detail value cannot be empty") # Get current detail to check type current_detail = self.repo.get_contact_detail_by_id(detail_id) if not current_detail: raise ValueError("Contact detail not found") # Validation based on type if current_detail['detail_type'] == 'email' and '@' not in detail_value: raise ValueError("Invalid email format") detail = self.repo.update_contact_detail( detail_id, detail_value.strip(), detail_label ) return detail def delete_contact_detail(self, detail_id: UUID, user: str) -> bool: """Delete a contact detail (phone/email)""" success = self.repo.delete_contact_detail(detail_id) return success # Note Services def add_note(self, contact_id: UUID, note_text: str, user: str) -> Dict[str, Any]: """Add a note to contact""" if not note_text or len(note_text.strip()) == 0: raise ValueError("Note text cannot be empty") note = self.repo.create_note(contact_id, note_text.strip(), user) return note def update_note(self, note_id: UUID, note_text: str, user: str) -> Dict[str, Any]: """Update a note (creates new version)""" if not note_text or len(note_text.strip()) == 0: raise ValueError("Note text cannot be empty") note = self.repo.update_note(note_id, note_text.strip(), user) return note def delete_note(self, note_id: UUID, user: str) -> bool: """Delete a note (soft delete)""" success = self.repo.delete_note(note_id) return success def list_all_contacts(self) -> List[Dict[str, Any]]: """Get all contacts across all institutions with summary info""" return self.repo.get_all_contacts_with_institutions()