# Generated by Django 5.0.10 on 2025-12-27 20:24 import django.db.models.deletion from decimal import Decimal from django.conf import settings from django.db import migrations, models def populate_signed_amount(apps, schema_editor): """ Заполняем signed_amount на основе старого amount и типа транзакции. spend -> отрицательная сумма deposit/adjustment -> положительная сумма """ WalletTransaction = apps.get_model('customers', 'WalletTransaction') for txn in WalletTransaction.objects.all(): if txn.transaction_type == 'spend': txn.signed_amount = -abs(txn.amount) else: # deposit, adjustment - положительные txn.signed_amount = abs(txn.amount) txn.save(update_fields=['signed_amount']) def calculate_balance_after(apps, schema_editor): """ Вычисляем balance_after для всех существующих транзакций. """ Customer = apps.get_model('customers', 'Customer') WalletTransaction = apps.get_model('customers', 'WalletTransaction') for customer in Customer.objects.all(): running_balance = Decimal('0') # Обрабатываем транзакции в хронологическом порядке for txn in WalletTransaction.objects.filter(customer=customer).order_by('created_at'): running_balance += txn.signed_amount or Decimal('0') txn.balance_after = running_balance txn.save(update_fields=['balance_after']) def reverse_populate(apps, schema_editor): """Обратная операция - ничего не делаем.""" pass class Migration(migrations.Migration): dependencies = [ ('customers', '0003_alter_customer_email_alter_customer_phone_and_more'), ('orders', '0008_historicalorder_needs_delivery_photo_and_more'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ # 1. Добавляем новые поля (signed_amount временно nullable) migrations.AddField( model_name='wallettransaction', name='signed_amount', field=models.DecimalField( decimal_places=2, max_digits=10, null=True, # Временно nullable для миграции данных help_text='Положительная для пополнений, отрицательная для списаний', verbose_name='Сумма' ), ), migrations.AddField( model_name='wallettransaction', name='balance_after', field=models.DecimalField( blank=True, decimal_places=2, help_text='Баланс кошелька после применения этой транзакции', max_digits=10, null=True, verbose_name='Баланс после' ), ), migrations.AddField( model_name='wallettransaction', name='balance_category', field=models.CharField( choices=[('money', 'Реальные деньги')], default='money', max_length=20, verbose_name='Категория' ), ), # 2. Копируем данные из amount в signed_amount migrations.RunPython(populate_signed_amount, reverse_populate), # 3. Вычисляем balance_after migrations.RunPython(calculate_balance_after, reverse_populate), # 4. Делаем signed_amount NOT NULL migrations.AlterField( model_name='wallettransaction', name='signed_amount', field=models.DecimalField( decimal_places=2, max_digits=10, help_text='Положительная для пополнений, отрицательная для списаний', verbose_name='Сумма' ), ), # 5. Удаляем старое поле amount migrations.RemoveField( model_name='wallettransaction', name='amount', ), # 6. Удаляем wallet_balance из Customer migrations.RemoveField( model_name='customer', name='wallet_balance', ), # 7. Обновляем связь с Order (добавляем related_name) migrations.AlterField( model_name='wallettransaction', name='order', field=models.ForeignKey( blank=True, help_text='Заказ, к которому относится транзакция (если применимо)', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='wallet_transactions', to='orders.order', verbose_name='Заказ' ), ), # 8. Добавляем индексы migrations.AddIndex( model_name='wallettransaction', index=models.Index(fields=['balance_category'], name='customers_w_balance_81f0a9_idx'), ), migrations.AddIndex( model_name='wallettransaction', index=models.Index(fields=['customer', 'balance_category'], name='customers_w_custome_060570_idx'), ), ]