Repository: akvo/akvo-rsr

Issue:
Bug: Deleting a period in a program doesn't delete the period in contributing projects
### What were you doing?

Trying to delete a period on a program. It successfully deletes the reporting period, but the contributing projects still have the period available.

### What should've happened?

The period in the contributing projects should've been deleted.

### My environment

_No response_

### Additional context

This bug was reported, but I'm unclear on the steps to reproduce it at the moment.

A preliminary investigation was done by @zuhdil  and the source seems to be https://github.com/akvo/akvo-rsr/blame/master/akvo/rsr/models/result/indicator_period.py#L24 . The [commit](https://github.com/akvo/akvo-rsr/commit/6fde048e5a8521ee435fdf911698484d6c222b8c#diff-e1dfb15ce5a9d17b782854e07cb2cec99ad744d638a5821ce0e01b94061fff39) erroneously just sets the parent period to null instead of deleting the child period.
Bug: Deleting a period in a program doesn't delete the period in contributing projects
### What were you doing?

Trying to delete a period on a program. It successfully deletes the reporting period, but the contributing projects still have the period available.

### What should've happened?

The period in the contributing projects should've been deleted.

### My environment

_No response_

### Additional context

This bug was reported, but I'm unclear on the steps to reproduce it at the moment.

A preliminary investigation was done by @zuhdil  and the source seems to be https://github.com/akvo/akvo-rsr/blame/master/akvo/rsr/models/result/indicator_period.py#L24 . The [commit](https://github.com/akvo/akvo-rsr/commit/6fde048e5a8521ee435fdf911698484d6c222b8c#diff-e1dfb15ce5a9d17b782854e07cb2cec99ad744d638a5821ce0e01b94061fff39) erroneously just sets the parent period to null instead of deleting the child period.


Discussion:

Resolving patch:
diff --git a/akvo/rsr/migrations/0217_cascade_indicator_period_deletes.py b/akvo/rsr/migrations/0217_cascade_indicator_period_deletes.py
new file mode 100644
--- /dev/null
+++ b/akvo/rsr/migrations/0217_cascade_indicator_period_deletes.py
@@ -0,0 +1,19 @@
+# Generated by Django 3.2.10 on 2022-02-03 12:05
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('rsr', '0216_django_3_2_upgrade'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='indicatorperiod',
+            name='parent_period',
+            field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child_periods', to='rsr.indicatorperiod', verbose_name='parent indicator period'),
+        ),
+    ]
diff --git a/akvo/rsr/models/result/indicator_period.py b/akvo/rsr/models/result/indicator_period.py
--- a/akvo/rsr/models/result/indicator_period.py
+++ b/akvo/rsr/models/result/indicator_period.py
@@ -21,7 +21,7 @@ class IndicatorPeriod(models.Model):
     project_relation = 'results__indicators__periods__in'
 
     indicator = models.ForeignKey('Indicator', on_delete=models.CASCADE, verbose_name=_('indicator'), related_name='periods')
-    parent_period = models.ForeignKey('self', on_delete=models.SET_NULL, blank=True, null=True, default=None,
+    parent_period = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, default=None,
                                       verbose_name=_('parent indicator period'),
                                       related_name='child_periods')
     locked = models.BooleanField(_('locked'), default=True, db_index=True)


Test patch:
diff --git a/akvo/rsr/tests/models/test_indicator_period.py b/akvo/rsr/tests/models/test_indicator_period.py
--- a/akvo/rsr/tests/models/test_indicator_period.py
+++ b/akvo/rsr/tests/models/test_indicator_period.py
@@ -196,3 +196,20 @@ def test_update_score(self):
         update.save(update_fields=['status'])
         period.refresh_from_db()
         self.assertIsNone(period.score_index)
+
+    def test_deleting_parent_period(self):
+        """Child periods should be deleted when a parent is deleted"""
+        child_project = Project.objects.create(title="Child Test project 1")
+        child_project.set_parent(self.project.id)
+        child_result = Result.objects.create(project=child_project, title='Child Test Result')
+        child_indicator = Indicator.objects.create(result=child_result, title='Child Test Indicator')
+        child_period = IndicatorPeriod.objects.create(
+            indicator=child_indicator,
+            actual_comment='child initial actual comment',
+            parent_period=self.period
+        )
+
+        self.period.delete()
+
+        self.assertIsNone(IndicatorPeriod.objects.filter(id=child_period.id).first())
+        self.assertEqual(child_indicator.periods.count(), 0)