CLAUDE: Add automatic transaction logging to #transaction-log channel

Implemented automatic posting of transaction notifications to #transaction-log
channel when transactions are submitted via /dropadd or /ilmove commands.

**New Utility:**
- `utils/transaction_logging.py` - Centralized transaction logging function
  - `post_transaction_to_log()` - Posts transaction embed to #transaction-log
  - Uses team's ML affiliate for consistent branding
  - Displays team thumbnail, colors, and player moves
  - Shows season from transaction data (not hardcoded)
  - Format matches legacy transaction log embeds

**Integration Points:**
- `/dropadd` (scheduled transactions) - Posts when submitted
- `/ilmove` (immediate transactions) - Posts when executed
- Both use shared `post_transaction_to_log()` function

**Embed Format:**
```
Week 18 Transaction
[Team Name]
Player Moves:
- **PlayerName** (sWAR) from OLDTEAM to NEWTEAM
- **PlayerName** (sWAR) from OLDTEAM to NEWTEAM
[Team Thumbnail]
Footer: "SBa Season 12" with SBA logo
```

**Features:**
- Automatic ML affiliate lookup for consistent team display
- Team colors and thumbnails in embeds
- Season number from transaction data
- Graceful error handling (logs warnings, doesn't block submission)
- Matches legacy embed format exactly

**Files Changed:**
- NEW: `utils/transaction_logging.py` - Transaction logging utility
- MODIFIED: `views/transaction_embed.py` - Added logging calls on submission

**Testing:**
- Transaction builder tests pass (31/31)
- No new test failures introduced
- Logging is non-blocking (submission succeeds even if logging fails)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2025-10-23 12:24:37 -05:00
parent 74c5059aba
commit 8ebbc26a0d
2 changed files with 153 additions and 0 deletions

View File

@ -0,0 +1,144 @@
"""
Transaction Logging Utility
Provides centralized function for posting transaction notifications
to the #transaction-log channel.
"""
from typing import List, Optional
import discord
from config import get_config
from models.transaction import Transaction
from models.team import Team
from views.embeds import EmbedTemplate, EmbedColors
from utils.logging import get_contextual_logger
logger = get_contextual_logger(f'{__name__}')
async def post_transaction_to_log(
bot: discord.Client,
transactions: List[Transaction],
team: Optional[Team] = None
) -> bool:
"""
Post a transaction to the #transaction-log channel.
Args:
bot: Discord bot instance
transactions: List of Transaction objects to post
team: Optional team override (if None, determined from transactions)
Returns:
True if posted successfully, False otherwise
"""
try:
if not transactions:
logger.warning("No transactions provided to post_transaction_to_log")
return False
# Get guild and channel
config = get_config()
guild = bot.get_guild(config.guild_id)
if not guild:
logger.warning(f"Could not find guild {config.guild_id}")
return False
channel = discord.utils.get(guild.text_channels, name='transaction-log')
if not channel:
logger.warning("Could not find #transaction-log channel")
return False
# Determine the team for the embed (team making the moves)
if team is None:
team = await _determine_team_from_transactions(transactions)
# Build move string
move_string = ""
week_num = transactions[0].week
season = transactions[0].season
for txn in transactions:
# Format: PlayerName (sWAR) from OLDTEAM to NEWTEAM
move_string += (
f'**{txn.player.name}** ({txn.player.wara:.2f}) '
f'from {txn.oldteam.abbrev} to {txn.newteam.abbrev}\n'
)
# Create embed matching legacy format
embed = EmbedTemplate.create_base_embed(
title=f'Week {week_num} Transaction',
description=team.sname if hasattr(team, 'sname') else team.lname,
color=EmbedColors.INFO
)
# Set team color if available
if hasattr(team, 'color') and team.color:
try:
# Remove # if present and convert to int
color_hex = team.color.replace('#', '')
embed.color = discord.Color(int(color_hex, 16))
except (ValueError, AttributeError):
pass # Use default color on error
# Set team thumbnail if available
if hasattr(team, 'thumbnail') and team.thumbnail:
embed.set_thumbnail(url=team.thumbnail)
# Add player moves field
embed.add_field(name='Player Moves', value=move_string, inline=False)
# Add footer with SBA branding using current season from transaction
embed.set_footer(
text=f"SBa Season {season}",
icon_url="https://sombaseball.ddns.net/static/images/sba-logo.png"
)
# Post to channel
await channel.send(embed=embed)
logger.info(f"Transaction posted to log: {transactions[0].moveid}, {len(transactions)} moves")
return True
except Exception as e:
logger.error(f"Error posting transaction to log: {e}")
return False
async def _determine_team_from_transactions(transactions: List[Transaction]) -> Team:
"""
Determine which team to display for the transaction embed.
Uses the major league affiliate of the team involved in the transaction
to ensure consistent branding (no MiL or IL team logos).
Logic:
- Use newteam's ML affiliate if it's not FA
- Otherwise use oldteam's ML affiliate if it's not FA
- Otherwise default to newteam
Args:
transactions: List of transactions
Returns:
Team to display in the embed (always Major League team)
"""
first_move = transactions[0]
# Check newteam first
if first_move.newteam.abbrev.upper() != 'FA':
try:
return await first_move.newteam.major_league_affiliate()
except Exception as e:
logger.warning(f"Could not get ML affiliate for {first_move.newteam.abbrev}: {e}")
return first_move.newteam
# Check oldteam
if first_move.oldteam.abbrev.upper() != 'FA':
try:
return await first_move.oldteam.major_league_affiliate()
except Exception as e:
logger.warning(f"Could not get ML affiliate for {first_move.oldteam.abbrev}: {e}")
return first_move.oldteam
# Default to newteam (both are FA)
return first_move.newteam

View File

@ -9,6 +9,7 @@ from datetime import datetime
from services.transaction_builder import TransactionBuilder, RosterValidationResult from services.transaction_builder import TransactionBuilder, RosterValidationResult
from views.embeds import EmbedColors, EmbedTemplate from views.embeds import EmbedColors, EmbedTemplate
from utils.transaction_logging import post_transaction_to_log
class TransactionEmbedView(discord.ui.View): class TransactionEmbedView(discord.ui.View):
@ -239,6 +240,10 @@ class SubmitConfirmationModal(discord.ui.Modal):
# Submit the transaction for NEXT week # Submit the transaction for NEXT week
transactions = await self.builder.submit_transaction(week=current_state.week + 1) transactions = await self.builder.submit_transaction(week=current_state.week + 1)
# Post to #transaction-log channel
bot = interaction.client
await post_transaction_to_log(bot, transactions, team=self.builder.team)
# Create success message # Create success message
success_msg = f"✅ **Transaction Submitted Successfully!**\n\n" success_msg = f"✅ **Transaction Submitted Successfully!**\n\n"
success_msg += f"**Move ID:** `{transactions[0].moveid}`\n" success_msg += f"**Move ID:** `{transactions[0].moveid}`\n"
@ -270,6 +275,10 @@ class SubmitConfirmationModal(discord.ui.Modal):
) )
player_updates.append(updated_player) player_updates.append(updated_player)
# Post to #transaction-log channel
bot = interaction.client
await post_transaction_to_log(bot, created_transactions, team=self.builder.team)
# Create success message # Create success message
success_msg = f"✅ **IL Move Executed Successfully!**\n\n" success_msg = f"✅ **IL Move Executed Successfully!**\n\n"
success_msg += f"**Move ID:** `{created_transactions[0].moveid}`\n" success_msg += f"**Move ID:** `{created_transactions[0].moveid}`\n"