""" Management command to fix account balances for existing paid payments. This command will: 1. Find all payments marked as 'ausgezahlt' (paid) 2. Check if corresponding bank transactions exist 3. Create missing bank transactions 4. Update account balances to reflect all paid payments Usage: python manage.py fix_account_balances """ from django.core.management.base import BaseCommand from django.utils import timezone from decimal import Decimal from stiftung.models import DestinataerUnterstuetzung, BankTransaction, StiftungsKonto class Command(BaseCommand): help = 'Fix account balances for existing paid payments' def add_arguments(self, parser): parser.add_argument( '--dry-run', action='store_true', help='Show what would be done without making changes', ) parser.add_argument( '--account', type=str, help='Only process payments for specific account (by kontoname)', ) def handle(self, *args, **options): dry_run = options['dry_run'] account_filter = options.get('account') self.stdout.write( self.style.SUCCESS('šŸ” Analyzing paid payments and account balances...') ) if dry_run: self.stdout.write( self.style.WARNING('DRY RUN MODE - No changes will be made') ) # Get all paid payments paid_payments_query = DestinataerUnterstuetzung.objects.filter( status='ausgezahlt' ).select_related('konto', 'destinataer') if account_filter: paid_payments_query = paid_payments_query.filter( konto__kontoname__icontains=account_filter ) paid_payments = paid_payments_query.all() self.stdout.write(f"Found {paid_payments.count()} paid payments") # Group payments by account accounts_data = {} missing_transactions = [] for payment in paid_payments: konto_id = payment.konto.id if konto_id not in accounts_data: accounts_data[konto_id] = { 'konto': payment.konto, 'payments': [], 'total_paid': Decimal('0.00'), 'missing_transactions': [] } accounts_data[konto_id]['payments'].append(payment) accounts_data[konto_id]['total_paid'] += payment.betrag # Check if bank transaction exists for this payment existing_transaction = BankTransaction.objects.filter( konto=payment.konto, betrag=-payment.betrag, # Negative for outgoing payment kommentare__contains=f'Unterstützung {payment.id}' ).first() if not existing_transaction: accounts_data[konto_id]['missing_transactions'].append(payment) missing_transactions.append(payment) # Report findings self.stdout.write("\nšŸ“Š ANALYSIS RESULTS:") self.stdout.write("=" * 50) for account_data in accounts_data.values(): konto = account_data['konto'] payments_count = len(account_data['payments']) total_paid = account_data['total_paid'] missing_count = len(account_data['missing_transactions']) self.stdout.write(f"\nšŸ¦ {konto.bank_name} - {konto.kontoname}") self.stdout.write(f" Current Balance: €{konto.saldo}") self.stdout.write(f" Paid Payments: {payments_count} (Total: €{total_paid})") self.stdout.write(f" Missing Transactions: {missing_count}") if missing_count > 0: expected_balance = konto.saldo - sum(p.betrag for p in account_data['missing_transactions']) self.stdout.write( self.style.WARNING(f" Expected Balance after fix: €{expected_balance}") ) if not missing_transactions: self.stdout.write( self.style.SUCCESS("\nāœ… All paid payments have corresponding transactions!") ) return self.stdout.write(f"\nāš ļø Found {len(missing_transactions)} payments without transactions") if not dry_run: self.stdout.write("\nšŸ”§ CREATING MISSING TRANSACTIONS...") created_count = 0 for payment in missing_transactions: # Create bank transaction transaction = BankTransaction.objects.create( konto=payment.konto, datum=payment.ausgezahlt_am or payment.faellig_am, valuta=payment.ausgezahlt_am or payment.faellig_am, betrag=-payment.betrag, # Negative for outgoing payment waehrung='EUR', verwendungszweck=f"Unterstützungszahlung: {payment.beschreibung or payment.destinataer.get_full_name()}", empfaenger_zahlungspflichtiger=payment.empfaenger_name or payment.destinataer.get_full_name(), iban_gegenpartei=payment.empfaenger_iban or '', transaction_type='ueberweisung', status='verified', kommentare=f'NachtrƤglich erstellt für Unterstützung {payment.id} - Zahlung vom {payment.ausgezahlt_am or payment.faellig_am}', ) # Update account balance payment.konto.saldo -= payment.betrag payment.konto.saldo_datum = payment.ausgezahlt_am or payment.faellig_am payment.konto.save() created_count += 1 self.stdout.write( f" āœ… Created transaction for {payment.destinataer.get_full_name()}: €{payment.betrag}" ) self.stdout.write( self.style.SUCCESS(f"\nšŸŽ‰ Successfully created {created_count} transactions and updated account balances!") ) # Show final balances self.stdout.write("\nšŸ“ˆ UPDATED ACCOUNT BALANCES:") for account_data in accounts_data.values(): if account_data['missing_transactions']: konto = account_data['konto'] konto.refresh_from_db() # Get updated balance self.stdout.write(f" {konto.bank_name} - {konto.kontoname}: €{konto.saldo}") else: self.stdout.write("\nšŸ“ DRY RUN - Would create the following transactions:") for payment in missing_transactions: self.stdout.write( f" - {payment.destinataer.get_full_name()}: €{payment.betrag} " f"on {payment.ausgezahlt_am or payment.faellig_am} " f"from {payment.konto.kontoname}" )