From d15ee37fdbeb21551f95d87862b2749a1eb11eee Mon Sep 17 00:00:00 2001 From: Helen Root Date: Fri, 24 Jan 2025 18:11:03 +0100 Subject: [PATCH] Rename field, edit migration to handle generated field change --- api/tests/test_declaration.py | 8 ++-- api/views/declaration/declaration.py | 2 +- config/tests/test_automatic_approval.py | 32 +++++++------- data/admin/declaration.py | 2 +- ...declaration_overridden_article_and_more.py | 43 +++++++++++++++++++ data/models/declaration.py | 6 +-- data/tests/test_declaration.py | 26 +++++------ 7 files changed, 81 insertions(+), 38 deletions(-) create mode 100644 data/migrations/0118_rename_overriden_article_declaration_overridden_article_and_more.py diff --git a/api/tests/test_declaration.py b/api/tests/test_declaration.py index 2c8b008d7..330939a50 100644 --- a/api/tests/test_declaration.py +++ b/api/tests/test_declaration.py @@ -1335,9 +1335,9 @@ def test_filter_by_article(self): Les déclarations peuvent être filtrées par article """ InstructionRoleFactory(user=authenticate.user) - art_15 = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) - AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_16) - AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ANSES_REFERAL) + art_15 = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) + AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_16) + AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ANSES_REFERAL) # Filtrage pour obtenir les déclarations en article 15 url = f"{reverse('api:list_all_declarations')}?article=ART_15" @@ -1579,7 +1579,7 @@ def test_update_article(self): art_15.refresh_from_db() self.assertEqual(art_15.article, Declaration.Article.ARTICLE_16) self.assertEqual(art_15.calculated_article, Declaration.Article.ARTICLE_15) - self.assertEqual(art_15.overriden_article, Declaration.Article.ARTICLE_16) + self.assertEqual(art_15.overridden_article, Declaration.Article.ARTICLE_16) @authenticate def test_update_article_unauthorized(self): diff --git a/api/views/declaration/declaration.py b/api/views/declaration/declaration.py index c6630f5d1..3a13fe764 100644 --- a/api/views/declaration/declaration.py +++ b/api/views/declaration/declaration.py @@ -406,7 +406,7 @@ def post(self, request, pk): if new_article not in Declaration.Article: raise ProjectAPIException(global_error="Merci de spécifier un article valide") - declaration.overriden_article = Declaration.Article(new_article) + declaration.overridden_article = Declaration.Article(new_article) declaration.save() declaration.refresh_from_db() serializer = self.get_serializer(declaration) diff --git a/config/tests/test_automatic_approval.py b/config/tests/test_automatic_approval.py index 347e6c6e4..94535982e 100644 --- a/config/tests/test_automatic_approval.py +++ b/config/tests/test_automatic_approval.py @@ -49,11 +49,11 @@ def test_awaiting_declaration_approved_art_15(self, _): * aucune action d'instruction n'a été effectuée dessus * son snapshot de soumission date de plus de trente jours. """ - declaration_15 = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) + declaration_15 = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) TestAutomaticApproval._create_submission_snapshot(declaration_15) declaration_high_risk_population = AwaitingInstructionDeclarationFactory( - overriden_article=Declaration.Article.ARTICLE_15_HIGH_RISK_POPULATION + overridden_article=Declaration.Article.ARTICLE_15_HIGH_RISK_POPULATION ) TestAutomaticApproval._create_submission_snapshot(declaration_high_risk_population) @@ -76,7 +76,7 @@ def test_double_submission_declaration_approved_art_15(self, _): deux snapshots type SUBMIT sont créés. Le bot doit quand même approuver ces déclarations. Plus d'infos : https://github.com/betagouv/complements-alimentaires/issues/1395 """ - declaration_15 = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) + declaration_15 = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) # Double soumission TestAutomaticApproval._create_submission_snapshot(declaration_15) @@ -94,7 +94,7 @@ def test_non_submission_snapshots_not_approved_art_15(self, _): Si au moins un snapshot est présent avec un type différent de "SUBMIT" la déclaration ne devra pas être autorisée """ - declaration_15 = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) + declaration_15 = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) # Double soumission TestAutomaticApproval._create_submission_snapshot(declaration_15) @@ -117,7 +117,7 @@ def test_email_sent_declaration_approved(self, mocked_brevo): """ L'email d'approbation doit être envoyé lors d'une approbation automatique """ - declaration = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) + declaration = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) TestAutomaticApproval._create_submission_snapshot(declaration) approve_declarations() @@ -137,7 +137,7 @@ def test_awaiting_declaration_not_approved_without_setting(self, mocked_brevo): Le bot ne doit pas approuver des déclarations si le setting ENABLE_AUTO_VALIDATION n'est pas True """ - declaration = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) + declaration = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) TestAutomaticApproval._create_submission_snapshot(declaration) approve_declarations() @@ -150,7 +150,7 @@ def test_awaiting_declaration_not_approved_art_15_vig(self, mocked_brevo): Une déclaration en attente d'instruction de doit pas se valider si elle a l'article 15 vigilance """ - declaration = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15_WARNING) + declaration = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15_WARNING) TestAutomaticApproval._create_submission_snapshot(declaration) approve_declarations() @@ -162,7 +162,7 @@ def test_awaiting_declaration_not_approved_art_16(self, mocked_brevo): """ Une déclaration en attente d'instruction de doit pas se valider si elle a l'article 16 """ - declaration = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_16) + declaration = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_16) TestAutomaticApproval._create_submission_snapshot(declaration) approve_declarations() @@ -174,7 +174,7 @@ def test_awaiting_declaration_not_approved_art_anses(self, mocked_brevo): """ Une déclaration en attente d'instruction de doit pas se valider si elle a l'article ANSES """ - declaration = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ANSES_REFERAL) + declaration = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ANSES_REFERAL) TestAutomaticApproval._create_submission_snapshot(declaration) approve_declarations() @@ -200,7 +200,7 @@ def test_awaiting_declaration_not_approved_instructed(self, mocked_brevo): actions d'instruction ont été effectuées dessus, par exemple des observations, objections, requêtes de visa, etc. """ - declaration = AwaitingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) + declaration = AwaitingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) TestAutomaticApproval._create_submission_snapshot(declaration) # On crée un autre snapshot indiquant que la déclaration a subi des actions autres @@ -224,7 +224,7 @@ def test_ongoing_declaration_not_approved(self, mocked_brevo): Une déclaration dont l'instruction est en cours ne doit pas se valider toute seule """ - declaration = OngoingInstructionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) + declaration = OngoingInstructionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) TestAutomaticApproval._create_submission_snapshot(declaration) approve_declarations() @@ -236,7 +236,7 @@ def test_observed_declaration_not_approved(self, mocked_brevo): """ Une déclaration en observation ne doit pas se valider toute seule """ - declaration = ObservationDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) + declaration = ObservationDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) TestAutomaticApproval._create_submission_snapshot(declaration) approve_declarations() @@ -248,7 +248,7 @@ def test_objected_declaration_not_approved(self, mocked_brevo): """ Une déclaration en objection ne doit pas se valider toute seule """ - declaration = ObjectionDeclarationFactory(overriden_article=Declaration.Article.ARTICLE_15) + declaration = ObjectionDeclarationFactory(overridden_article=Declaration.Article.ARTICLE_15) TestAutomaticApproval._create_submission_snapshot(declaration) approve_declarations() @@ -261,7 +261,7 @@ def test_abandoned_declaration_not_approved(self, mocked_brevo): Une déclaration en abandon ne doit pas se valider toute seule """ declaration = InstructionReadyDeclarationFactory( - status=Declaration.DeclarationStatus.ABANDONED, overriden_article=Declaration.Article.ARTICLE_15 + status=Declaration.DeclarationStatus.ABANDONED, overridden_article=Declaration.Article.ARTICLE_15 ) TestAutomaticApproval._create_submission_snapshot(declaration) @@ -275,7 +275,7 @@ def test_refused_declaration_not_approved(self, mocked_brevo): Une déclaration refusée ne doit pas se valider toute seule """ declaration = InstructionReadyDeclarationFactory( - status=Declaration.DeclarationStatus.REJECTED, overriden_article=Declaration.Article.ARTICLE_15 + status=Declaration.DeclarationStatus.REJECTED, overridden_article=Declaration.Article.ARTICLE_15 ) TestAutomaticApproval._create_submission_snapshot(declaration) @@ -289,7 +289,7 @@ def test_withdrawn_declaration_not_approved(self, mocked_brevo): Une déclaration retirée du marché ne doit pas se valider toute seule """ declaration = InstructionReadyDeclarationFactory( - status=Declaration.DeclarationStatus.WITHDRAWN, overriden_article=Declaration.Article.ARTICLE_15 + status=Declaration.DeclarationStatus.WITHDRAWN, overridden_article=Declaration.Article.ARTICLE_15 ) TestAutomaticApproval._create_submission_snapshot(declaration) diff --git a/data/admin/declaration.py b/data/admin/declaration.py index fe96a0091..3f87f037f 100644 --- a/data/admin/declaration.py +++ b/data/admin/declaration.py @@ -264,7 +264,7 @@ class DeclarationAdmin(SimpleHistoryAdmin): "gamme", "flavor", "calculated_article", - "overriden_article", + "overridden_article", ) }, ), diff --git a/data/migrations/0118_rename_overriden_article_declaration_overridden_article_and_more.py b/data/migrations/0118_rename_overriden_article_declaration_overridden_article_and_more.py new file mode 100644 index 000000000..6aa199e7b --- /dev/null +++ b/data/migrations/0118_rename_overriden_article_declaration_overridden_article_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 5.1.5 on 2025-01-24 16:59 + +import django.db.models.functions.comparison +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('data', '0117_remove_blogpost_body'), + ] + + operations = [ + migrations.RenameField( + model_name='declaration', + old_name='overriden_article', + new_name='overridden_article', + ), + migrations.RenameField( + model_name='historicaldeclaration', + old_name='overriden_article', + new_name='overridden_article', + ), + # ValueError: Modifying GeneratedFields is not supported - the field data.Declaration.article must be removed and re-added with the new definition. + migrations.RemoveField( + model_name="declaration", + name="article", + ), + migrations.RemoveField( + model_name="historicaldeclaration", + name="article", + ), + migrations.AddField( + model_name='declaration', + name='article', + field=models.GeneratedField(db_persist=True, expression=django.db.models.functions.comparison.Coalesce(models.Case(models.When(overridden_article='', then=models.Value(None)), default='overridden_article'), models.Case(models.When(calculated_article='', then=models.Value(None)), default='calculated_article'), models.Value(None)), output_field=models.TextField(null=True, verbose_name='article')), + ), + migrations.AddField( + model_name='historicaldeclaration', + name='article', + field=models.GeneratedField(db_persist=True, expression=django.db.models.functions.comparison.Coalesce(models.Case(models.When(overridden_article='', then=models.Value(None)), default='overridden_article'), models.Case(models.When(calculated_article='', then=models.Value(None)), default='calculated_article'), models.Value(None)), output_field=models.TextField(null=True, verbose_name='article')), + ), + ] diff --git a/data/models/declaration.py b/data/models/declaration.py index fae619db6..513227123 100644 --- a/data/models/declaration.py +++ b/data/models/declaration.py @@ -179,11 +179,11 @@ class Article(models.TextChoices): other_effects = models.TextField(blank=True, verbose_name="autres objectifs ou effets non listés") calculated_article = models.TextField("article calculé automatiquement", blank=True, choices=Article) - # TODO: les Article.choice pour overriden_article ne devraient pas inclure les choices calculés automatiquement - overriden_article = models.TextField("article manuellement spécifié", blank=True, choices=Article) + # TODO: les Article.choice pour overridden_article ne devraient pas inclure les choices calculés automatiquement + overridden_article = models.TextField("article manuellement spécifié", blank=True, choices=Article) article = models.GeneratedField( expression=Coalesce( - Case(When(overriden_article="", then=Value(None)), default="overriden_article"), + Case(When(overridden_article="", then=Value(None)), default="overridden_article"), Case(When(calculated_article="", then=Value(None)), default="calculated_article"), Value(None), ), diff --git a/data/tests/test_declaration.py b/data/tests/test_declaration.py index 5d87cc1d5..91e25be4e 100644 --- a/data/tests/test_declaration.py +++ b/data/tests/test_declaration.py @@ -135,7 +135,7 @@ def test_article_empty(self): self.assertIsNone(declaration.article) self.assertEqual(declaration.calculated_article, "") - self.assertEqual(declaration.overriden_article, "") + self.assertEqual(declaration.overridden_article, "") def test_article_15(self): declaration = InstructionReadyDeclarationFactory( @@ -152,7 +152,7 @@ def test_article_15(self): self.assertEqual(declaration.article, Declaration.Article.ARTICLE_15) self.assertEqual(declaration.calculated_article, Declaration.Article.ARTICLE_15) - self.assertEqual(declaration.overriden_article, "") + self.assertEqual(declaration.overridden_article, "") def test_article_15_warning(self): """ @@ -173,7 +173,7 @@ def test_article_15_warning(self): declaration_with_risky_substance.refresh_from_db() self.assertEqual(declaration_with_risky_substance.article, Declaration.Article.ARTICLE_15_WARNING) self.assertEqual(declaration_with_risky_substance.calculated_article, Declaration.Article.ARTICLE_15_WARNING) - self.assertEqual(declaration_with_risky_substance.overriden_article, "") + self.assertEqual(declaration_with_risky_substance.overridden_article, "") declaration_with_risky_prepared_plant = InstructionReadyDeclarationFactory( declared_plants=[], @@ -188,7 +188,7 @@ def test_article_15_warning(self): self.assertEqual( declaration_with_risky_prepared_plant.calculated_article, Declaration.Article.ARTICLE_15_WARNING ) - self.assertEqual(declaration_with_risky_prepared_plant.overriden_article, "") + self.assertEqual(declaration_with_risky_prepared_plant.overridden_article, "") risky_galenic_formulation = GalenicFormulationFactory(is_risky=True) declaration_with_risky_galenic_formulation = InstructionReadyDeclarationFactory( @@ -202,7 +202,7 @@ def test_article_15_warning(self): self.assertEqual( declaration_with_risky_galenic_formulation.calculated_article, Declaration.Article.ARTICLE_15_WARNING ) - self.assertEqual(declaration_with_risky_galenic_formulation.overriden_article, "") + self.assertEqual(declaration_with_risky_galenic_formulation.overridden_article, "") risky_target_population = PopulationFactory(is_defined_by_anses=True) declaration_with_risky_population = InstructionReadyDeclarationFactory( @@ -218,7 +218,7 @@ def test_article_15_warning(self): self.assertEqual( declaration_with_risky_population.calculated_article, Declaration.Article.ARTICLE_15_HIGH_RISK_POPULATION ) - self.assertEqual(declaration_with_risky_population.overriden_article, "") + self.assertEqual(declaration_with_risky_population.overridden_article, "") def test_article_15_override(self): declaration = InstructionReadyDeclarationFactory( @@ -230,14 +230,14 @@ def test_article_15_override(self): ) # La PlantFactory utilisée dans DeclaredPlantFactory a par défaut un status = AUTHORIZED DeclaredPlantFactory(new=False, declaration=declaration) - declaration.overriden_article = Declaration.Article.ARTICLE_16 + declaration.overridden_article = Declaration.Article.ARTICLE_16 declaration.assign_calculated_article() declaration.save() declaration.refresh_from_db() self.assertEqual(declaration.article, Declaration.Article.ARTICLE_16) self.assertEqual(declaration.calculated_article, Declaration.Article.ARTICLE_15) - self.assertEqual(declaration.overriden_article, Declaration.Article.ARTICLE_16) + self.assertEqual(declaration.overridden_article, Declaration.Article.ARTICLE_16) def test_article_16(self): """ @@ -259,7 +259,7 @@ def test_article_16(self): self.assertEqual(declaration_new.article, Declaration.Article.ARTICLE_16) self.assertEqual(declaration_new.calculated_article, Declaration.Article.ARTICLE_16) - self.assertEqual(declaration_new.overriden_article, "") + self.assertEqual(declaration_new.overridden_article, "") declaration_not_autorized = InstructionReadyDeclarationFactory( declared_plants=[], @@ -277,7 +277,7 @@ def test_article_16(self): self.assertEqual(declaration_not_autorized.article, Declaration.Article.ARTICLE_16) self.assertEqual(declaration_not_autorized.calculated_article, Declaration.Article.ARTICLE_16) - self.assertEqual(declaration_not_autorized.overriden_article, "") + self.assertEqual(declaration_not_autorized.overridden_article, "") def test_article_anses_referal(self): SUBSTANCE_MAX_QUANTITY = 1.0 @@ -298,7 +298,7 @@ def test_article_anses_referal(self): self.assertEqual( declaration_with_computed_substance_max_exceeded.calculated_article, Declaration.Article.ANSES_REFERAL ) - self.assertEqual(declaration_with_computed_substance_max_exceeded.overriden_article, "") + self.assertEqual(declaration_with_computed_substance_max_exceeded.overridden_article, "") # La déclaration ne doit pas passer en saisine ANSES si la dose est exactement égale à la dose maximale declaration_with_computed_substance_equals_max = InstructionReadyDeclarationFactory( @@ -317,7 +317,7 @@ def test_article_anses_referal(self): self.assertEqual( declaration_with_computed_substance_equals_max.calculated_article, Declaration.Article.ARTICLE_15 ) - self.assertEqual(declaration_with_computed_substance_equals_max.overriden_article, "") + self.assertEqual(declaration_with_computed_substance_equals_max.overridden_article, "") declaration_with_declared_substance_max_exceeded = InstructionReadyDeclarationFactory( computed_substances=[], @@ -335,7 +335,7 @@ def test_article_anses_referal(self): self.assertEqual( declaration_with_declared_substance_max_exceeded.calculated_article, Declaration.Article.ANSES_REFERAL ) - self.assertEqual(declaration_with_declared_substance_max_exceeded.overriden_article, "") + self.assertEqual(declaration_with_declared_substance_max_exceeded.overridden_article, "") def test_visa_refused(self): """