major-domo-v2/models/draft_pick.py
Cal Corum 483f1f492f Fix draft pick API parsing and enhance admin command feedback
Root Cause Fixes:
- Add _extract_items_and_count_from_response() override to DraftPickService
  to handle API returning 'picks' key instead of 'draftpicks'
- Add custom from_api_data() to DraftPick model to handle API field mapping
  (origowner/owner/player -> origowner_id/owner_id/player_id)

Enhancements:
- Add timer status to /draft-admin set-pick success message
  - Shows relative deadline timestamp when timer active
  - Shows "Timer Inactive" when timer not running

Also includes related draft module improvements from prior work.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 15:33:52 -06:00

111 lines
4.4 KiB
Python

"""
Draft pick model
Represents individual draft picks with team and player relationships.
API FIELD MAPPING:
The API returns fields without _id suffix (origowner, owner, player).
When the API short_output=false, these fields contain full Team/Player objects.
When short_output=true (or default), they contain integer IDs.
We use Pydantic aliases to handle both cases.
"""
from typing import Optional, Any, Dict, Union
from pydantic import Field, field_validator, model_validator
from models.base import SBABaseModel
from models.team import Team
from models.player import Player
class DraftPick(SBABaseModel):
"""Draft pick model representing a single draft selection."""
season: int = Field(..., description="Draft season")
overall: int = Field(..., description="Overall pick number")
round: int = Field(..., description="Draft round")
# Team relationships - IDs extracted from API response
# API returns "origowner" which can be int or Team object
origowner_id: int = Field(..., description="Original owning team ID")
origowner: Optional[Team] = Field(None, description="Original owning team (populated when needed)")
# API returns "owner" which can be int or Team object
owner_id: Optional[int] = Field(None, description="Current owning team ID")
owner: Optional[Team] = Field(None, description="Current owning team (populated when needed)")
# Player selection - API returns "player" which can be int or Player object
player_id: Optional[int] = Field(None, description="Selected player ID")
player: Optional[Player] = Field(None, description="Selected player (populated when needed)")
@classmethod
def from_api_data(cls, data: Dict[str, Any]) -> 'DraftPick':
"""
Create DraftPick from API response data.
Handles API field mapping:
- API returns 'origowner', 'owner', 'player' (without _id suffix)
- These can be integer IDs or full objects depending on short_output setting
"""
if not data:
raise ValueError("Cannot create DraftPick from empty data")
# Make a copy to avoid modifying the original
parsed = dict(data)
# Handle origowner: can be int ID or Team object
if 'origowner' in parsed:
origowner = parsed.pop('origowner')
if isinstance(origowner, dict):
# Full Team object from API
parsed['origowner'] = Team.from_api_data(origowner)
parsed['origowner_id'] = origowner.get('id', origowner)
elif isinstance(origowner, int):
# Just the ID
parsed['origowner_id'] = origowner
elif origowner is not None:
parsed['origowner_id'] = int(origowner)
# Handle owner: can be int ID or Team object
if 'owner' in parsed:
owner = parsed.pop('owner')
if isinstance(owner, dict):
# Full Team object from API
parsed['owner'] = Team.from_api_data(owner)
parsed['owner_id'] = owner.get('id', owner)
elif isinstance(owner, int):
# Just the ID
parsed['owner_id'] = owner
elif owner is not None:
parsed['owner_id'] = int(owner)
# Handle player: can be int ID or Player object (or None)
if 'player' in parsed:
player = parsed.pop('player')
if isinstance(player, dict):
# Full Player object from API
parsed['player'] = Player.from_api_data(player)
parsed['player_id'] = player.get('id', player)
elif isinstance(player, int):
# Just the ID
parsed['player_id'] = player
elif player is not None:
parsed['player_id'] = int(player)
return cls(**parsed)
@property
def is_traded(self) -> bool:
"""Check if this pick has been traded."""
return self.origowner_id != self.owner_id
@property
def is_selected(self) -> bool:
"""Check if a player has been selected with this pick."""
return self.player_id is not None
def __str__(self):
team_str = f"({self.owner.abbrev})" if self.owner else f"(Team {self.owner_id})"
if self.is_selected and self.player:
return f"Pick {self.overall}: {self.player.name} {team_str}"
else:
return f"Pick {self.overall}: Available {team_str}"