Repository: svthalia/concrexit

Issue:
0008_migrate_processing_date cannot be run when existing Payables have payments
### Describe the bug

Inside the `0008_migrate_processing_date` migration we delete payments. However, the payables they belong to protect them so the migration fails.


### How to reproduce
Steps to reproduce the behaviour:
1. Have an existing pizza order or membership renewal with a non-processed payment
2. Execute migration

### Expected behaviour
Successful migration.

### Additional context
```
web_1       | Running migrations:
web_1       | Traceback (most recent call last):
web_1       |   File "./manage.py", line 19, in <module>
web_1       |     execute_from_command_line(sys.argv)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
web_1       |     utility.execute()
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
web_1       |     self.fetch_command(subcommand).run_from_argv(self.argv)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 330, in run_from_argv
web_1       |     self.execute(*args, **cmd_options)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 371, in execute
web_1       |     output = self.handle(*args, **options)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 85, in wrapped
web_1       |     res = handle_func(*args, **kwargs)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/commands/migrate.py", line 243, in handle
web_1       |     post_migrate_state = executor.migrate(
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/executor.py", line 117, in migrate
web_1       |     state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
web_1       |     state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/executor.py", line 227, in apply_migration
web_1       |     state = migration.apply(state, schema_editor)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/migration.py", line 124, in apply
web_1       |     operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/operations/special.py", line 190, in database_forwards
web_1       |     self.code(from_state.apps, schema_editor)
web_1       |   File "/usr/src/app/website/payments/migrations/0008_migrate_processing_date.py", line 11, in set_created_at
web_1       |     payment.delete()
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 946, in delete
web_1       |     collector.collect([self], keep_parents=keep_parents)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/models/deletion.py", line 302, in collect
web_1       |     raise ProtectedError(
web_1       | django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'Payment' because they are referenced through protected foreign keys: 'Entry.payment'.", <itertools.chain object at 0x7f087b01aa00>)
```

```
web_1       | Running migrations:
web_1       | Traceback (most recent call last):
web_1       |   File "./manage.py", line 19, in <module>
web_1       |     execute_from_command_line(sys.argv)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
web_1       |     utility.execute()
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
web_1       |     self.fetch_command(subcommand).run_from_argv(self.argv)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 330, in run_from_argv
web_1       |     self.execute(*args, **cmd_options)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 371, in execute
web_1       |     output = self.handle(*args, **options)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 85, in wrapped
web_1       |     res = handle_func(*args, **kwargs)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/core/management/commands/migrate.py", line 243, in handle
web_1       |     post_migrate_state = executor.migrate(
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/executor.py", line 117, in migrate
web_1       |     state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
web_1       |     state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/executor.py", line 227, in apply_migration
web_1       |     state = migration.apply(state, schema_editor)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/migration.py", line 124, in apply
web_1       |     operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/migrations/operations/special.py", line 190, in database_forwards
web_1       |     self.code(from_state.apps, schema_editor)
web_1       |   File "/usr/src/app/website/payments/migrations/0008_migrate_processing_date.py", line 11, in set_created_at
web_1       |     payment.delete()
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 946, in delete
web_1       |     collector.collect([self], keep_parents=keep_parents)
web_1       |   File "/usr/local/lib/python3.8/site-packages/django/db/models/deletion.py", line 302, in collect
web_1       |     raise ProtectedError(
web_1       | django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'Payment' because they are referenced through protected foreign keys: 'Order.payment'.", <itertools.chain object at 0x7f5e652bcaf0>)
```


Discussion:

Resolving patch:
diff --git a/website/payments/migrations/0008_migrate_processing_date.py b/website/payments/migrations/0008_migrate_processing_date.py
--- a/website/payments/migrations/0008_migrate_processing_date.py
+++ b/website/payments/migrations/0008_migrate_processing_date.py
@@ -8,9 +8,26 @@ def set_created_at(apps, schema_editor):
         if payment.processing_date:
             payment.created_at = payment.processing_date
         else:
+            if hasattr(payment, 'pizzas_order'):
+                order = payment.pizzas_order
+                order.payment = None
+                order.save()
+
+            if hasattr(payment, 'registrations_entry'):
+                entry = payment.registrations_entry
+                entry.payment = None
+                entry.save()
+
             payment.delete()
 
 
+def set_processed_date(apps, schema_editor):
+    """Revert sets the processing date to the created_at value."""
+    Payment = apps.get_model('payments', 'Payment')
+    for payment in Payment.objects.all():
+        payment.processing_date = payment.created_at
+
+
 class Migration(migrations.Migration):
 
     dependencies = [
@@ -18,5 +35,5 @@ class Migration(migrations.Migration):
     ]
 
     operations = [
-        migrations.RunPython(set_created_at)
+        migrations.RunPython(set_created_at, set_processed_date)
     ]


Test patch: