""" Celery tasks for billing operations """ import logging from celery import shared_task from django.utils import timezone from django.db import transaction from igny8_core.auth.models import Account from .services import CreditService logger = logging.getLogger(__name__) @shared_task(name='igny8_core.modules.billing.tasks.replenish_monthly_credits') def replenish_monthly_credits(): """ Replenish monthly credits for all active accounts. Runs on the first day of each month at midnight. For each active account with a plan: - Resets credits to plan.included_credits - Creates a CreditTransaction record - Logs the replenishment """ logger.info("=" * 80) logger.info("MONTHLY CREDIT REPLENISHMENT TASK STARTED") logger.info(f"Timestamp: {timezone.now()}") logger.info("=" * 80) # Get all active accounts with plans accounts = Account.objects.filter( status='active', plan__isnull=False ).select_related('plan') total_accounts = accounts.count() logger.info(f"Found {total_accounts} active accounts with plans") replenished = 0 skipped = 0 errors = 0 for account in accounts: try: plan = account.plan # Get monthly credits from plan monthly_credits = plan.included_credits or plan.credits_per_month or 0 if monthly_credits <= 0: logger.info(f"Account {account.id} ({account.name}): Plan has no included credits, skipping") skipped += 1 continue # Reset credits using CreditService with transaction.atomic(): new_balance = CreditService.reset_credits_for_renewal( account=account, new_amount=monthly_credits, description=f"Monthly credit replenishment - {plan.name} plan", metadata={ 'plan_id': plan.id, 'plan_name': plan.name, 'monthly_credits': monthly_credits, 'replenishment_date': timezone.now().isoformat() } ) logger.info( f"Account {account.id} ({account.name}): " f"Reset credits to {monthly_credits} (balance: {new_balance})" ) replenished += 1 except Exception as e: logger.error( f"Account {account.id} ({account.name}): " f"Failed to replenish credits: {str(e)}", exc_info=True ) errors += 1 logger.info("=" * 80) logger.info("MONTHLY CREDIT REPLENISHMENT TASK COMPLETED") logger.info(f"Total accounts: {total_accounts}") logger.info(f"Replenished: {replenished}") logger.info(f"Skipped: {skipped}") logger.info(f"Errors: {errors}") logger.info("=" * 80) return { 'success': True, 'total_accounts': total_accounts, 'replenished': replenished, 'skipped': skipped, 'errors': errors }