import logging from sqlalchemy.orm import Session from app import crud, schemas from app.models.transaction import TransactionType from app.models.wallet import WalletType from app.core.email import send_bot_completion_notification logger = logging.getLogger(__name__) def process_completed_bot_purchases(db: Session) -> int: """ Process bot purchases that have reached their end time. Returns the number of bot purchases processed. """ # Get bot purchases that are running but have passed their end time completed_due = crud.bot_purchase.get_completed_due(db) if not completed_due: return 0 count = 0 for purchase in completed_due: try: # Get user and bot information user = crud.user.get(db, id=purchase.user_id) bot = crud.bot.get(db, id=purchase.bot_id) if not user or not bot: logger.error( f"User or bot not found for bot purchase {purchase.id}. " f"User ID: {purchase.user_id}, Bot ID: {purchase.bot_id}" ) continue # Get user's trading wallet trading_wallet = crud.wallet.get_by_user_and_type( db, user_id=user.id, wallet_type=WalletType.TRADING ) if not trading_wallet: logger.error( f"Trading wallet not found for user {user.id} " f"when processing bot purchase {purchase.id}" ) continue # Calculate the total amount to be credited (principal + ROI) principal = purchase.amount roi = purchase.expected_roi_amount total = principal + roi # Update trading wallet balance crud.wallet.update_balance(db, wallet_id=trading_wallet.id, amount=total, add=True) # Create transaction records # 1. Return of principal principal_transaction = crud.transaction.create( db, obj_in=schemas.TransactionCreate( user_id=user.id, wallet_id=trading_wallet.id, amount=principal, transaction_type=TransactionType.BOT_EARNING, description=f"Bot {bot.name} - Return of principal", bot_purchase_id=purchase.id, ), ) # 2. ROI roi_transaction = crud.transaction.create( db, obj_in=schemas.TransactionCreate( user_id=user.id, wallet_id=trading_wallet.id, amount=roi, transaction_type=TransactionType.BOT_EARNING, description=f"Bot {bot.name} - ROI", bot_purchase_id=purchase.id, related_transaction_id=principal_transaction.id, ), ) # Update the first transaction to reference the second crud.transaction.update( db, db_obj=principal_transaction, obj_in={"related_transaction_id": roi_transaction.id}, ) # Mark the bot purchase as completed crud.bot_purchase.complete(db, db_obj=purchase) # Send email notification send_bot_completion_notification( email_to=user.email, bot_name=bot.name, amount=principal, roi=roi, ) count += 1 except Exception as e: logger.error( f"Error processing bot purchase {purchase.id}: {str(e)}" ) return count def get_bot_simulation_stats(db: Session) -> dict: """ Get statistics about bot simulations. """ # Get counts by status running_count = len(crud.bot_purchase.get_by_status( db, status=schemas.BotPurchaseStatus.RUNNING )) completed_count = len(crud.bot_purchase.get_by_status( db, status=schemas.BotPurchaseStatus.COMPLETED )) cancelled_count = len(crud.bot_purchase.get_by_status( db, status=schemas.BotPurchaseStatus.CANCELLED )) # Calculate total invested amount (running bots) running_purchases = crud.bot_purchase.get_by_status( db, status=schemas.BotPurchaseStatus.RUNNING ) total_invested = sum(p.amount for p in running_purchases) # Calculate total ROI generated (completed bots) completed_purchases = crud.bot_purchase.get_by_status( db, status=schemas.BotPurchaseStatus.COMPLETED ) total_roi_generated = sum(p.expected_roi_amount for p in completed_purchases) return { "running_count": running_count, "completed_count": completed_count, "cancelled_count": cancelled_count, "total_invested": total_invested, "total_roi_generated": total_roi_generated, }