Coverage for models/matches.py: 91.23%

55 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2026-04-15 17:36 +0000

1""" 

2Match-related Pydantic models. 

3""" 

4 

5from datetime import datetime 

6 

7from pydantic import BaseModel 

8 

9 

10class EnhancedMatch(BaseModel): 

11 """Model for creating or updating a match with full context.""" 

12 

13 match_date: str 

14 home_team_id: int 

15 away_team_id: int 

16 home_score: int 

17 away_score: int 

18 season_id: int 

19 age_group_id: int 

20 match_type_id: int 

21 division_id: int | None = None 

22 status: str | None = "scheduled" # scheduled, played, postponed, cancelled (maps to match_status in DB) 

23 created_by: str | None = None # User ID who created the match (for audit trail) 

24 updated_by: str | None = None # User ID who last updated the match 

25 source: str = "manual" # Source: manual, match-scraper, import 

26 external_match_id: str | None = None # External match identifier (e.g., from match-scraper) 

27 scheduled_kickoff: datetime | None = None # Scheduled kickoff datetime in UTC 

28 home_penalty_score: int | None = None # Penalty shootout score (only when regulation ends in draw) 

29 away_penalty_score: int | None = None 

30 

31 

32class MatchPatch(BaseModel): 

33 """Model for partial match updates.""" 

34 

35 home_score: int | None = None 

36 away_score: int | None = None 

37 match_status: str | None = None 

38 match_date: str | None = None 

39 home_team_id: int | None = None 

40 away_team_id: int | None = None 

41 season_id: int | None = None 

42 age_group_id: int | None = None 

43 match_type_id: int | None = None 

44 division_id: int | None = None 

45 status: str | None = None 

46 external_match_id: str | None = None # External match identifier 

47 scheduled_kickoff: datetime | None = None # Scheduled kickoff datetime in UTC 

48 home_penalty_score: int | None = None # Penalty shootout score (only when regulation ends in draw) 

49 away_penalty_score: int | None = None 

50 

51 class Config: 

52 # Validation for scores 

53 @staticmethod 

54 def validate_score(v): 

55 if v is not None and v < 0: 

56 raise ValueError("Score must be non-negative") 

57 return v 

58 

59 

60class MatchSubmissionData(BaseModel): 

61 """ 

62 Match data for async submission to Celery queue. 

63 This model accepts flexible data from match-scraper. 

64 """ 

65 

66 home_team: str # Team name (will be looked up) 

67 away_team: str # Team name (will be looked up) 

68 match_date: str # ISO format date 

69 season: str # Season name (e.g., "2024-25") 

70 age_group: str | None = None 

71 division: str | None = None 

72 home_score: int | None = None 

73 away_score: int | None = None 

74 match_status: str = "scheduled" # scheduled, live, played, postponed, cancelled 

75 match_type: str | None = None 

76 location: str | None = None 

77 external_match_id: str | None = None # External identifier for deduplication