major-domo-v2/models/team.py
Cal Corum c01f88e7e3 CLAUDE: Comprehensive bot improvements and test infrastructure
This commit includes various enhancements across the bot architecture:

**New Infrastructure:**
- Added tests/factories.py - Factory classes for creating test data objects
- Added PRE_LAUNCH_ROADMAP.md - Project planning and roadmap documentation

**Model Enhancements:**
- Updated models/roster.py - Enhanced roster data structures
- Updated models/team.py - Improved team model definitions

**Service Layer Improvements:**
- Enhanced services/player_service.py - Better player data handling
- Updated services/roster_service.py - Roster management improvements
- Enhanced services/team_service.py - Team data service refinements
- Updated services/transaction_service.py - Transaction processing enhancements

**Command Updates:**
- Updated commands/teams/info.py - Team information command improvements
- Enhanced commands/voice/tracker.py - Voice channel tracking refinements

**Background Tasks:**
- Updated tasks/custom_command_cleanup.py - Automated cleanup improvements

**View Components:**
- Enhanced views/transaction_embed.py - Transaction embed UI improvements

**Test Coverage Enhancements:**
- Updated tests/test_commands_voice.py - Voice command test improvements
- Enhanced tests/test_dropadd_integration.py - Integration test coverage
- Updated tests/test_services_player_service.py - Player service test coverage
- Enhanced tests/test_services_transaction_builder.py - Transaction builder tests
- Updated tests/test_transactions_integration.py - Transaction integration tests
- Enhanced tests/test_views_transaction_embed.py - UI component test coverage

These changes collectively improve the bot's reliability, maintainability, and test coverage while adding essential infrastructure for continued development.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-02 11:35:26 -05:00

97 lines
4.0 KiB
Python

"""
Team model for SBA teams
Represents a team in the league with all associated metadata.
"""
from typing import Optional
from enum import Enum
from pydantic import Field
from models.base import SBABaseModel
from models.division import Division
class RosterType(Enum):
"""Roster designation types."""
MAJOR_LEAGUE = "ml"
MINOR_LEAGUE = "mil"
INJURED_LIST = "il"
FREE_AGENCY = "fa"
class Team(SBABaseModel):
"""Team model representing an SBA team."""
# Override base model to make id required for database entities
id: int = Field(..., description="Team ID from database")
abbrev: str = Field(..., description="Team abbreviation (e.g., 'NYY')")
sname: str = Field(..., description="Short team name")
lname: str = Field(..., description="Long team name")
season: int = Field(..., description="Season number")
# Manager information
gmid: Optional[int] = Field(None, description="Primary general manager ID")
gmid2: Optional[int] = Field(None, description="Secondary general manager ID")
manager1_id: Optional[int] = Field(None, description="Primary manager ID")
manager2_id: Optional[int] = Field(None, description="Secondary manager ID")
# Team metadata
division_id: Optional[int] = Field(None, description="Division ID")
division: Optional[Division] = Field(None, description="Division object (populated from API)")
stadium: Optional[str] = Field(None, description="Home stadium name")
thumbnail: Optional[str] = Field(None, description="Team thumbnail URL")
color: Optional[str] = Field(None, description="Primary team color")
dice_color: Optional[str] = Field(None, description="Dice rolling color")
@classmethod
def from_api_data(cls, data: dict) -> 'Team':
"""
Create Team instance from API data, handling nested division structure.
The API returns division data as a nested object, but our model expects
both division_id (int) and division (optional Division object).
"""
# Make a copy to avoid modifying original data
team_data = data.copy()
# Handle nested division structure
if 'division' in team_data and isinstance(team_data['division'], dict):
division_data = team_data['division']
# Extract division_id from nested division object
team_data['division_id'] = division_data.get('id')
# Keep division object for optional population
if division_data.get('id'):
team_data['division'] = Division.from_api_data(division_data)
return super().from_api_data(team_data)
def roster_type(self) -> RosterType:
"""Determine the roster type based on team abbreviation."""
if len(self.abbrev) <= 3:
return RosterType.MAJOR_LEAGUE
# For teams with extended abbreviations, check suffix patterns
abbrev_lower = self.abbrev.lower()
# Pattern analysis:
# - Minor League: ends with 'mil' (e.g., NYYMIL, BHMMIL)
# - Injured List: ends with 'il' but not 'mil' (e.g., NYYIL, BOSIL)
# - Edge case: teams whose base abbrev ends in 'M' + 'IL' = 'MIL'
# Only applies if removing 'IL' gives us exactly a 3-char base team
if abbrev_lower.endswith('mil'):
# Check if this is actually [BaseTeam]IL where BaseTeam ends in 'M'
# E.g., BHMIL = BHM + IL (injured list), not minor league
if len(self.abbrev) == 5: # Exactly 5 chars: 3-char base + IL
potential_base = self.abbrev[:-2] # Remove 'IL'
if len(potential_base) == 3 and potential_base.upper().endswith('M'):
return RosterType.INJURED_LIST
return RosterType.MINOR_LEAGUE
elif abbrev_lower.endswith('il'):
return RosterType.INJURED_LIST
else:
return RosterType.MAJOR_LEAGUE
def __str__(self):
return f"{self.abbrev} - {self.lname}"