Read all spreadsheet data (plays, box score, pitching decisions) before any
database writes so formula errors like #N/A don't leave the DB in a partial
state. Also preserve SheetsException detail through the error chain and show
users the specific cell/error instead of a generic failure message.
Closes#78
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codebase audit identified ~50 lazy imports. Moved 42 unnecessary ones to
top-level imports — only keeping those justified by circular imports,
init-order dependencies, or optional dependency guards. Updated test mock
patch targets where needed. See #57 for remaining DI candidates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- #37: Fix stale comment in transaction_freeze.py referencing wrong moveid format
- #27: Change config.testing default from True to False (was masking prod behavior)
- #25: Replace deprecated asyncio.get_event_loop() with get_running_loop()
- #38: Replace naive datetime.now() with timezone-aware datetime.now(UTC) across
7 source files and 4 test files to prevent subtle timezone bugs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
**Problem:**
The _is_spreadsheet_error() check was logging a warning and silently skipping
rows with formula errors (#REF!, #N/A, etc.). This could lead to incomplete
game data being submitted without the user knowing.
**Solution:**
Raise SheetsException immediately when spreadsheet errors are detected,
providing:
- Exact row number and field name
- Actual error value found in the cell
- Common error type explanations
- Clear action required to fix
**Impact:**
- Users get immediate feedback about spreadsheet errors
- No partial/incomplete data submitted to API
- Clear instructions on what needs to be fixed
- Better data integrity
**Example Error Message:**
```
❌ Spreadsheet Error Detected
**Location:** Row 7, Column 'pitcher_id'
**Value Found:** `#REF!`
This cell contains a formula error that must be fixed before submission.
**Action Required:** Fix cell pitcher_id in row 7 and resubmit.
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added robust validation to handle spreadsheet errors and invalid data
when reading pitching decisions from scorecards.
Problem:
- POST /api/v3/decisions was failing with 422 errors
- Google Sheets cells containing "#N/A" were passed directly to API
- API correctly rejected invalid team_id values like "#N/A" string
- No validation of integer fields or required fields
Root Cause:
- sheets_service.py:read_pitching_decisions() read values without
validation or type checking
- Spreadsheet formula errors (#N/A, #REF!, etc.) passed through
- Invalid data types not caught until API validation failed
Solution:
1. Added _is_spreadsheet_error() to detect formula errors
2. Added _sanitize_int_field() to validate and convert integers
3. Enhanced read_pitching_decisions() to:
- Detect and skip rows with spreadsheet errors
- Validate integer fields (pitcher_id, team_id, etc.)
- Ensure required fields (pitcher_id, team_id) are present
- Log warnings for invalid data with row numbers
- Only return valid, sanitized decision data
Impact:
- Prevents 422 errors from bad spreadsheet data
- Provides clear warnings in logs when data is invalid
- Gracefully skips invalid rows instead of crashing
- Helps identify scorecard data entry errors
Testing:
- Handles #N/A, #REF!, #VALUE!, #DIV/0! and other errors
- Converts "123.0" strings to integers correctly
- Validates required fields before sending to API
- Logs row numbers for debugging bad data
Production logs showed:
"Input should be a valid integer, unable to parse string as
an integer", input: "#N/A" for team_id field
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements full Google Sheets scorecard submission with:
- Complete game data extraction (68 play fields, pitching decisions, box score)
- Transaction rollback support at 3 states (plays/game/complete)
- Duplicate game detection with confirmation dialog
- Permission-based submission (GMs only)
- Automated results posting to news channel
- Automatic standings recalculation
- Key plays display with WPA sorting
New Components:
- Play, Decision, Game models with full validation
- SheetsService for Google Sheets integration
- GameService, PlayService, DecisionService for data management
- ConfirmationView for user confirmations
- Discord helper utilities for channel operations
Services Enhanced:
- StandingsService: Added recalculate_standings() method
- CustomCommandsService: Fixed creator endpoint path
- Team/Player models: Added helper methods for display
Configuration:
- Added SHEETS_CREDENTIALS_PATH environment variable
- Added SBA_NETWORK_NEWS_CHANNEL and role constants
- Enabled pygsheets dependency
Documentation:
- Comprehensive README updates across all modules
- Added command, service, model, and view documentation
- Detailed workflow and error handling documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>