from django.core.management.base import BaseCommand from django.contrib.auth import get_user_model from finance.models import Account, Budget, FinancialYear, YearlyIncome, YearlyBudgetItem User = get_user_model() TARGET_YEAR = 2026 class Command(BaseCommand): help = 'Migrate existing revenue accounts and budgets into FinancialYear 2026. Idempotent — safe to run multiple times.' def add_arguments(self, parser): parser.add_argument( '--dry-run', action='store_true', help='Preview what would be created without writing to the database.', ) def handle(self, *args, **options): dry_run = options['dry_run'] if dry_run: self.stdout.write(self.style.WARNING('DRY RUN — no changes will be saved.\n')) total_incomes = 0 total_budgets = 0 for user in User.objects.all(): revenue_accounts = Account.objects.filter(user=user, account_type='revenue', active=True) budgets = Budget.objects.filter(account__user=user, active=True) if not revenue_accounts.exists() and not budgets.exists(): continue self.stdout.write(f'\nUser: {user.email}') if dry_run: fy = FinancialYear.objects.filter(user=user, year=TARGET_YEAR).first() if fy: self.stdout.write(f' FinancialYear {TARGET_YEAR} already exists (id={fy.pk})') else: self.stdout.write(f' Would create FinancialYear {TARGET_YEAR}') else: fy, fy_created = FinancialYear.objects.get_or_create(user=user, year=TARGET_YEAR) if fy_created: self.stdout.write(f' Created FinancialYear {TARGET_YEAR} (id={fy.pk})') else: self.stdout.write(f' FinancialYear {TARGET_YEAR} exists (id={fy.pk})') for account in revenue_accounts: label = f'YearlyIncome "{account.name}" CHF {account.balance}' if dry_run: exists = fy and YearlyIncome.objects.filter(financial_year=fy, name=account.name).exists() self.stdout.write(f' {"SKIP (exists)" if exists else "Would create"}: {label}') else: _, created = YearlyIncome.objects.get_or_create( financial_year=fy, name=account.name, defaults={'amount': account.balance, 'member': user, 'active': True}, ) self.stdout.write(f' {"Created" if created else "Skipped (exists)"}: {label}') if created: total_incomes += 1 for budget in budgets: label = f'YearlyBudgetItem "{budget.name}" CHF {budget.amount}' if dry_run: exists = fy and YearlyBudgetItem.objects.filter(financial_year=fy, name=budget.name).exists() self.stdout.write(f' {"SKIP (exists)" if exists else "Would create"}: {label}') else: _, created = YearlyBudgetItem.objects.get_or_create( financial_year=fy, name=budget.name, defaults={'amount': budget.amount, 'active': budget.active}, ) self.stdout.write(f' {"Created" if created else "Skipped (exists)"}: {label}') if created: total_budgets += 1 if not dry_run: self.stdout.write(self.style.SUCCESS( f'\nDone. Created {total_incomes} income(s) and {total_budgets} budget item(s).' )) else: self.stdout.write(self.style.WARNING('\nDry run complete. Re-run without --dry-run to apply.'))