diff --git a/opentech/apply/funds/migrations/0029_applicationsubmission_next.py b/opentech/apply/funds/migrations/0029_applicationsubmission_next.py new file mode 100644 index 0000000000000000000000000000000000000000..0f3baa78691bf7c70d430d729d9d0b9895235413 --- /dev/null +++ b/opentech/apply/funds/migrations/0029_applicationsubmission_next.py @@ -0,0 +1,19 @@ +# Generated by Django 2.0.2 on 2018-03-14 11:15 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('funds', '0028_update_on_delete_django2'), + ] + + operations = [ + migrations.AddField( + model_name='applicationsubmission', + name='next', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='previous', to='funds.ApplicationSubmission'), + ), + ] diff --git a/opentech/apply/funds/models.py b/opentech/apply/funds/models.py index bb6ad0786ad40332c9c2ed006da66d935b471269..b40577b761f7f7c454b978eca889bf1f1eddb758 100644 --- a/opentech/apply/funds/models.py +++ b/opentech/apply/funds/models.py @@ -479,6 +479,7 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission): related_name='submission_lead', on_delete=models.PROTECT, ) + next = models.OneToOneField('self', on_delete=models.CASCADE, related_name='previous', null=True) user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True) search_data = models.TextField() @@ -536,7 +537,12 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission): def handle_file(self, file): # File is potentially optional if file: - filename = self.save_path(file.name) + try: + filename = self.save_path(file.name) + except AttributeError: + # file is not changed, it is still the dictionary + return file + saved_name = default_storage.save(filename, file) return { 'name': file.name, @@ -565,6 +571,7 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission): file = self.form_data[field.id] self.form_data[field.id] = self.handle_files(file) + progressing_stage = False if not self.id: # We are creating the object default to first stage try: @@ -579,11 +586,20 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission): except AttributeError: # Its a lab self.lead = self.page.specific.lead + else: + submission_in_db = ApplicationSubmission.objects.get(id=self.id) + if self.stage != submission_in_db.stage: + progressing_stage = True + self.id = None # add a denormed version of the answer for searching self.search_data = ' '.join(self.prepare_search_values()) - return super().save(*args, **kwargs) + super().save(*args, **kwargs) + + if progressing_stage: + submission_in_db.next = self + submission_in_db.save() def data_and_fields(self): for stream_value in self.form_fields: diff --git a/opentech/apply/funds/tests/test_models.py b/opentech/apply/funds/tests/test_models.py index caff470b997bf74ed0a59f7cb5fd11ff2ff3c51d..c18280c098e6c4f3a59e02db9f89f9b0ab499135 100644 --- a/opentech/apply/funds/tests/test_models.py +++ b/opentech/apply/funds/tests/test_models.py @@ -374,3 +374,20 @@ class TestApplicationSubmission(TestCase): submission = self.make_submission(form_data__image__filename=filename) save_path = os.path.join(settings.MEDIA_ROOT, submission.save_path(filename)) self.assertTrue(os.path.isfile(save_path)) + + +class TestApplicationProgression(TestCase): + def test_new_submission_created(self): + submission = ApplicationSubmissionFactory(round__workflow_name='double') + self.assertEqual(ApplicationSubmission.objects.count(), 1) + old_id = submission.id + + # Update the status to the first phase of the new stage + submission.status = str(submission.workflow.stages[1].first()) + submission.save() + + old_submission = ApplicationSubmission.objects.get(id=old_id) + + self.assertEqual(ApplicationSubmission.objects.count(), 2) + self.assertEqual(submission.previous, old_submission) + self.assertEqual(old_submission.next, submission) diff --git a/opentech/apply/funds/workflow.py b/opentech/apply/funds/workflow.py index 02fd0f82191ef82d0d71047b83e0633c53d2a057..592516cd66c02b6e927c23b2dc3a42cea469efb5 100644 --- a/opentech/apply/funds/workflow.py +++ b/opentech/apply/funds/workflow.py @@ -128,6 +128,12 @@ class Stage(Iterable): # Make the phases new instances to prevent errors with mutability self.phases = self.copy_phases(self.phases) + def __eq__(self, other): + if isinstance(other, Stage): + return self.name == other.name + + return super().__eq__(other) + def copy_phases(self, phases: List['Phase']) -> List['Phase']: new_phases = list() for step, phase in enumerate(self.phases):