From 1c6d62d435e9da2fcf1e654e46c0c0c355b7943d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vergez?= Date: Fri, 10 Jan 2025 16:13:23 +0100 Subject: [PATCH 1/5] fix: gestion d'erreur minimaliste pour les fragments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le contenu est toujours retourné en cas d'erreur pour ne pas perturber l'affichage, mais avec un code d'erreur en cas de problème (400). --- impact/reglementations/views/fragments/rapport.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/impact/reglementations/views/fragments/rapport.py b/impact/reglementations/views/fragments/rapport.py index 973cf4c6..809f126f 100644 --- a/impact/reglementations/views/fragments/rapport.py +++ b/impact/reglementations/views/fragments/rapport.py @@ -27,13 +27,17 @@ def selection_rapport(request, csrd_id): def soumettre_lien_rapport(request, csrd_id): csrd = get_object_or_404(RapportCSRD, pk=csrd_id) form = LienRapportCSRDForm(instance=csrd, data=request.POST) + # les erreurs de format sont captées sur l'input du formulaire coté frontend + status = 400 if form.is_valid(): form.save() + status = 200 return render( request, template_name="fragments/lien_rapport.html", + status=status, context={ "csrd": csrd, "form": form, From c60caabfa12b16dc13b77df943c0699238eac6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vergez?= Date: Fri, 10 Jan 2025 16:11:26 +0100 Subject: [PATCH 2/5] =?UTF-8?q?fix:=20identification=20de=20certains=20?= =?UTF-8?q?=C3=A9l=C3=A9ments=20UI=20pour=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- impact/reglementations/templates/snippets/csrd_header.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impact/reglementations/templates/snippets/csrd_header.html b/impact/reglementations/templates/snippets/csrd_header.html index 5c8654b6..301c9a7d 100644 --- a/impact/reglementations/templates/snippets/csrd_header.html +++ b/impact/reglementations/templates/snippets/csrd_header.html @@ -8,7 +8,7 @@

Rapport de durabilité {{ csrd.annee }}

Rapports CSRD disponibles :  {% for rapport in rapports_csrd %} - + {% if rapport.pk == csrd.pk %} {{ rapport.annee }} {% else %} From 813553b0645b7217384d263d4fcd17dab9b1d80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vergez?= Date: Fri, 10 Jan 2025 16:48:32 +0100 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20ajout=20de=20tests=20sur=20la=20dern?= =?UTF-8?q?i=C3=A8re=20=C3=A9tape=20de=20l'espace=20CSRD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Essentiellement pour valider le fonctionnement des fragments HTMX --- .../tests/test_csrd_fragments.py | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 impact/reglementations/tests/test_csrd_fragments.py diff --git a/impact/reglementations/tests/test_csrd_fragments.py b/impact/reglementations/tests/test_csrd_fragments.py new file mode 100644 index 00000000..4f0c9e0a --- /dev/null +++ b/impact/reglementations/tests/test_csrd_fragments.py @@ -0,0 +1,112 @@ +import pytest +from django.shortcuts import reverse +from django.utils.timezone import now + +from reglementations.models import RapportCSRD + +""" +Fragments HTMX pour la gestion de l'espace CSRD +""" + + +def _rapport_csrd_personnel(entreprise_non_qualifiee, alice, annee=now().year): + entreprise_non_qualifiee.users.add(alice) + rapport = RapportCSRD( + entreprise=entreprise_non_qualifiee, proprietaire=alice, annee=annee + ) + rapport.save() + return rapport + + +@pytest.fixture +def rapport_csrd_courant(entreprise_non_qualifiee, alice): + return _rapport_csrd_personnel(entreprise_non_qualifiee, alice) + + +@pytest.fixture +def rapport_csrd_precedent(entreprise_non_qualifiee, alice): + return _rapport_csrd_personnel( + entreprise_non_qualifiee, alice, annee=now().year - 1 + ) + + +def test_soumission_lien_rapport(client, rapport_csrd_courant): + # vérifie que la saisie du lien est bien effectuée + url = reverse( + "reglementations:soumettre_lien_rapport", + kwargs={"csrd_id": rapport_csrd_courant.pk}, + ) + lien = "https://exemple.com/rapport_csrd" + + # avec un lien de rapport incorrect + data = {"lien_rapport": "foo"} + + client.force_login(user=rapport_csrd_courant.proprietaire) + response = client.post(url, data=data, follow=True) + + assert ( + 400 == response.status_code + ), "Cet URL n'est pas un lien de rapport CSRD valide" + + # avec un lien correct + data |= {"lien_rapport": lien} + response = client.post(url, data=data, follow=True) + body = response.content.decode("utf-8") + rapport_csrd_courant.refresh_from_db() + + assert response.status_code == 200 + assert ( + rapport_csrd_courant.lien_rapport == lien + ), "Le lien du rapport n'est pas correctement enregistré" + assert lien in body, "La réponse ne contient pas le lien du rapport" + assert "Enregistré" in body, "Le lien n'est pas mentionné comme 'enregistré'" + + +def test_presence_annee_precedente( + client, rapport_csrd_courant, rapport_csrd_precedent +): + # vérifie si l'affichage du sélecteur contient bien les deux années (courant et précédente) + url = reverse( + "reglementations:gestion_csrd", + kwargs={ + "siren": rapport_csrd_courant.entreprise.siren, + "id_etape": "redaction-rapport-durabilite", + }, + ) + client.force_login(user=rapport_csrd_courant.proprietaire) + response = client.get(url) + body = response.content.decode("utf-8") + + assert response.status_code == 200 + assert f"_selection_{now().year}" in body + assert f"_selection_{now().year-1}" in body + + +def test_selection_annee_rapport(client, rapport_csrd_courant, rapport_csrd_precedent): + # verifie que la selection de l'annee est bien effectuée (session) + url = reverse( + "reglementations:gestion_csrd", + kwargs={ + "siren": rapport_csrd_courant.entreprise.siren, + "id_etape": "redaction-rapport-durabilite", + }, + ) + client.force_login(user=rapport_csrd_courant.proprietaire) + client.get(url) + + # aucun element de session enregistre pour le rapport CSRD : on utilise le rapport courant + assert not client.session.get( + "rapport_csrd_courant" + ), "Aucune sélection de rapport CSRD (encore)" + + # sélection du rapport de l'année précédente (activation du fragment) : + client.post( + reverse( + "reglementations:selection_rapport", + kwargs={"csrd_id": rapport_csrd_precedent.pk}, + ) + ) + + assert rapport_csrd_precedent.pk == client.session.get( + "rapport_csrd_courant" + ), "Le rapport CSRD actuel est différent du rapport sélectionné" From a6e346461e852cb4451cd5a33d836b9b2fac1787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vergez?= Date: Tue, 28 Jan 2025 09:33:46 +0100 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20blocage=20des=20modifications=20sur?= =?UTF-8?q?=20un=20rapport=20CSRD=20publi=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0028_rapportcsrd_bloque.py | 20 +++++++++++++++++++ impact/reglementations/models/csrd.py | 11 ++++++++++ 2 files changed, 31 insertions(+) create mode 100644 impact/reglementations/migrations/0028_rapportcsrd_bloque.py diff --git a/impact/reglementations/migrations/0028_rapportcsrd_bloque.py b/impact/reglementations/migrations/0028_rapportcsrd_bloque.py new file mode 100644 index 00000000..04d7dddd --- /dev/null +++ b/impact/reglementations/migrations/0028_rapportcsrd_bloque.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.5 on 2025-01-17 14:15 +from django.db import migrations +from django.db import models + + +class Migration(migrations.Migration): + + dependencies = [ + ("reglementations", "0027_rapportcsrd_lien_rapport"), + ] + + operations = [ + migrations.AddField( + model_name="rapportcsrd", + name="bloque", + field=models.BooleanField( + default=False, verbose_name="rapport bloqué après publication" + ), + ), + ] diff --git a/impact/reglementations/models/csrd.py b/impact/reglementations/models/csrd.py index de99c211..72ba6400 100644 --- a/impact/reglementations/models/csrd.py +++ b/impact/reglementations/models/csrd.py @@ -50,6 +50,9 @@ class RapportCSRD(TimestampedModel): lien_rapport = models.URLField( verbose_name="lien du rapport CSRD publié", blank=True ) + bloque = models.BooleanField( + verbose_name="rapport bloqué après publication", default=False + ) objects = RapportCSRDQuerySet.as_manager() @@ -119,6 +122,13 @@ def save(self, *args, **kwargs): # on vérifie systématiquement les contraintes métiers avant la sauvegarde self.clean() + + # on vérifie si le rapport est actuellement bloqué, auquel cas seuls l'URL de publication + # et la date de modification sont mis à jour + kwargs |= ( + {"update_fields": ["lien_rapport", "updated_at"]} if self.bloque else {} + ) + super().save(*args, **kwargs) if enjeux: @@ -187,6 +197,7 @@ def enjeux_par_esrs(self, esrs): return qs def est_publie(self): + # utilisé pour déterminer si le rapport est modifiable ou pas return bool(self.lien_rapport) From c7fcb081c5f78158965e225cde635d89e5485e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vergez?= Date: Wed, 29 Jan 2025 16:57:44 +0100 Subject: [PATCH 5/5] chore(deps): maj/sync Pipfile.lock --- Pipfile.lock | 114 +++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index fdd8ea5b..44c68136 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -416,59 +416,59 @@ "woff" ], "hashes": [ - "sha256:07f8288aacf0a38d174445fc78377a97fb0b83cfe352a90c9d9c1400571963c7", - "sha256:11e5de1ee0d95af4ae23c1a138b184b7f06e0b6abacabf1d0db41c90b03d834b", - "sha256:1bc7ad24ff98846282eef1cbeac05d013c2154f977a79886bb943015d2b1b261", - "sha256:1dcc07934a2165ccdc3a5a608db56fb3c24b609658a5b340aee4ecf3ba679dc0", - "sha256:22f38464daa6cdb7b6aebd14ab06609328fe1e9705bb0fcc7d1e69de7109ee02", - "sha256:27e4ae3592e62eba83cd2c4ccd9462dcfa603ff78e09110680a5444c6925d841", - "sha256:3983313c2a04d6cc1fe9251f8fc647754cf49a61dac6cb1e7249ae67afaafc45", - "sha256:529cef2ce91dc44f8e407cc567fae6e49a1786f2fefefa73a294704c415322a4", - "sha256:5323a22eabddf4b24f66d26894f1229261021dacd9d29e89f7872dd8c63f0b8b", - "sha256:54153c49913f45065c8d9e6d0c101396725c5621c8aee744719300f79771d75a", - "sha256:546565028e244a701f73df6d8dd6be489d01617863ec0c6a42fa25bf45d43048", - "sha256:5480673f599ad410695ca2ddef2dfefe9df779a9a5cda89503881e503c9c7d90", - "sha256:5e8d657cd7326eeaba27de2740e847c6b39dde2f8d7cd7cc56f6aad404ddf0bd", - "sha256:62d65a3022c35e404d19ca14f291c89cc5890032ff04f6c17af0bd1927299674", - "sha256:6314bf82c54c53c71805318fcf6786d986461622dd926d92a465199ff54b1b72", - "sha256:7a8aa2c5e5b8b3bcb2e4538d929f6589a5c6bdb84fd16e2ed92649fb5454f11c", - "sha256:827e95fdbbd3e51f8b459af5ea10ecb4e30af50221ca103bea68218e9615de07", - "sha256:859c358ebf41db18fb72342d3080bce67c02b39e86b9fbcf1610cca14984841b", - "sha256:86721fbc389ef5cc1e2f477019e5069e8e4421e8d9576e9c26f840dbb04678de", - "sha256:89bdc5d88bdeec1b15af790810e267e8332d92561dce4f0748c2b95c9bdf3926", - "sha256:8c4491699bad88efe95772543cd49870cf756b019ad56294f6498982408ab03e", - "sha256:8c5ec45428edaa7022f1c949a632a6f298edc7b481312fc7dc258921e9399628", - "sha256:8e75f12c82127486fac2d8bfbf5bf058202f54bf4f158d367e41647b972342ca", - "sha256:a430178ad3e650e695167cb53242dae3477b35c95bef6525b074d87493c4bf29", - "sha256:a8c2794ded89399cc2169c4d0bf7941247b8d5932b2659e09834adfbb01589aa", - "sha256:aca318b77f23523309eec4475d1fbbb00a6b133eb766a8bdc401faba91261abe", - "sha256:ae3b6600565b2d80b7c05acb8e24d2b26ac407b27a3f2e078229721ba5698427", - "sha256:aedbeb1db64496d098e6be92b2e63b5fac4e53b1b92032dfc6988e1ea9134a4d", - "sha256:aee3b57643827e237ff6ec6d28d9ff9766bd8b21e08cd13bff479e13d4b14765", - "sha256:b54baf65c52952db65df39fcd4820668d0ef4766c0ccdf32879b77f7c804d5c5", - "sha256:b586ab5b15b6097f2fb71cafa3c98edfd0dba1ad8027229e7b1e204a58b0e09d", - "sha256:b8d5e8916c0970fbc0f6f1bece0063363bb5857a7f170121a4493e31c3db3314", - "sha256:bc5dbb4685e51235ef487e4bd501ddfc49be5aede5e40f4cefcccabc6e60fb4b", - "sha256:bdcc9f04b36c6c20978d3f060e5323a43f6222accc4e7fcbef3f428e216d96af", - "sha256:c3ca99e0d460eff46e033cd3992a969658c3169ffcd533e0a39c63a38beb6831", - "sha256:caf8230f3e10f8f5d7593eb6d252a37caf58c480b19a17e250a63dad63834cf3", - "sha256:cd70de1a52a8ee2d1877b6293af8a2484ac82514f10b1c67c1c5762d38073e56", - "sha256:cf4fe7c124aa3f4e4c1940880156e13f2f4d98170d35c749e6b4f119a872551e", - "sha256:d342e88764fb201286d185093781bf6628bbe380a913c24adf772d901baa8276", - "sha256:da9da6d65cd7aa6b0f806556f4985bcbf603bf0c5c590e61b43aa3e5a0f822d0", - "sha256:dc5294a3d5c84226e3dbba1b6f61d7ad813a8c0238fceea4e09aa04848c3d851", - "sha256:dd68c87a2bfe37c5b33bcda0fba39b65a353876d3b9006fde3adae31f97b3ef5", - "sha256:e6e8766eeeb2de759e862004aa11a9ea3d6f6d5ec710551a88b476192b64fd54", - "sha256:e894b5bd60d9f473bed7a8f506515549cc194de08064d829464088d23097331b", - "sha256:eb6ca911c4c17eb51853143624d8dc87cdcdf12a711fc38bf5bd21521e79715f", - "sha256:ed63959d00b61959b035c7d47f9313c2c1ece090ff63afea702fe86de00dbed4", - "sha256:f412604ccbeee81b091b420272841e5ec5ef68967a9790e80bffd0e30b8e2977", - "sha256:f7d66c15ba875432a2d2fb419523f5d3d347f91f48f57b8b08a2dfc3c39b8a3f", - "sha256:f9e736f60f4911061235603a6119e72053073a12c6d7904011df2d8fad2c0e35", - "sha256:fb594b5a99943042c702c550d5494bdd7577f6ef19b0bc73877c948a63184a32" + "sha256:05568a66b090ed9d79aefdce2ceb180bb64fc856961deaedc29f5ad51355ce2c", + "sha256:087ace2d06894ccdb03e6975d05da6bb9cec0c689b2a9983c059880e33a1464a", + "sha256:09740feed51f9ed816aebf5d82071b7fecf693ac3a7e0fc8ea433f5dc3bd92f5", + "sha256:0ed25d7b5fa4ae6a805c2a9cc0e5307d45cbb3b8e155584fe932d0f3b6a997bf", + "sha256:1101976c703ff4008a928fc3fef42caf06d035bfc4614230d7e797cbe356feb0", + "sha256:12e81d44f762156d28b5c93a6b65d98ed73678be45b22546de8ed29736c3cb96", + "sha256:1d4be8354c245c00aecfc90f5d3da8606226f0ac22e1cb0837b39139e4c2df85", + "sha256:23df0f1003abaf8a435543f59583fc247e7ae1b047ee2263510e0654a5f207e0", + "sha256:2dbc08e227fbeb716776905a7bd3c4fc62c8e37c8ef7d481acd10cb5fde12222", + "sha256:2e6dffe9cbcd163ef617fab1f81682e4d1629b7a5b9c5e598274dc2d03e88bcd", + "sha256:3098355e7a7b5ac48d5dc29684a65271187b865b85675033958b57c40364ee34", + "sha256:30c3501328363b73a90acc8a722dd199c993f2c4369ea16886128d94e91897ec", + "sha256:3304dfcf9ca204dd0ef691a287bd851ddd8e8250108658c0677c3fdfec853a20", + "sha256:371197de1283cc99f5f10eb91496520eb0e2d079312d014fd6cef9e802174c6a", + "sha256:3976db357484bf4cb533dfd0d1a444b38ad06062458715ebf21e38c71aff325d", + "sha256:418ece624fbc04e199f58398ffef3eaad645baba65434871b09eb7350a3a346b", + "sha256:5ff0daf8b2e0612e5761fed2e4a2f54eff9d9ec0aeb4091c9f3666f9a118325e", + "sha256:6899e3d97225a8218f525e9754da0376e1c62953a0d57a76c5abaada51e0d140", + "sha256:69ed0660750993150f7c4d966c0c1ffaa0385f23ccef85c2ff108062d80dd7ea", + "sha256:6eb93cbba484a463b5ee83f7dd3211905f27a3871d20d90fb72de84c6c5056e3", + "sha256:775ed0700ee6f781436641f18a0c61b1846a8c1aecae6da6b395c4417e2cb567", + "sha256:77e5115a425d53be6e31cd0fe9210f62a488bccf81eb113ab5dd7f4fa88e4d81", + "sha256:7858dc6823296a053d85b831fa8428781c6c6f06fca44582bf7b6b2ff32a9089", + "sha256:7ff8e606f905048dc91a55a06d994b68065bf35752ae199df54a9bf30013dcaa", + "sha256:82163d58b43eff6e2025a25c32905fdb9042a163cc1ff82dab393e7ffc77a7d5", + "sha256:833927d089e6585019f2c85e3f8f7d87733e3fe81cd704ebaca7afa27e2e7113", + "sha256:8ef5ee98fc320c158e4e459a5ee40d1ac3728d4ce11c3c8dfd854aa0aa5c042f", + "sha256:9074a2848ea5b607377e16998dfcf90cf5eb614d0c388541b9782d5cc038e149", + "sha256:916e1d926823b4b3b3815c59fc79f4ed670696fdd5fd9a5e690a0503eef38f79", + "sha256:9ec71d0cc0242899f87e4c230ed0b22c7b8681f288fb80e3d81c2c54c5bd2c79", + "sha256:a3d19ea483b3cd8833e9e2ee8115f3d2044d55d3743d84f9c23b48b52d7516d8", + "sha256:a7831d16c95b60866772a15fdcc03772625c4bb6d858e0ad8ef3d6e48709b2ef", + "sha256:b89da448e0073408d7b2c44935f9fdae4fdc93644899f99f6102ef883ecf083c", + "sha256:bee4920ebeb540849bc3555d871e2a8487e39ce8263c281f74d5b6d44d2bf1df", + "sha256:c135c91d47351b84893fb6fcbb8f178eba14f7cb195850264c0675c85e4238b6", + "sha256:c26445a7be689f8b70df7d5d2e2c85ec4407bdb769902a23dd45ac44f767575d", + "sha256:c2680a3e6e2e2d104a7ea81fb89323e1a9122c23b03d6569d0768887d0d76e69", + "sha256:c665df9c9d99937a5bf807bace1c0c95bd13f55de8c82aaf9856b868dcbfe5d9", + "sha256:d4b1c5939c0521525f45522823508e6fad21175bca978583688ea3b3736e6625", + "sha256:d4bd27f0fa5120aaa39f76de5768959bc97300e0f59a3160d466b51436a38aea", + "sha256:e10c7fb80cdfdc32244514cbea0906e9f53e3cc80d64d3389da09502fd999b55", + "sha256:e2cbafedb9462be7cf68c66b6ca1d8309842fe36b729f1b1969595f5d660e5c2", + "sha256:e4bde87985012adbd7559bc363d802fb335e92a07ff86a76cf02bebb0b8566d1", + "sha256:e696d6e2baf4cc57ded34bb87e5d3a9e4da9732f3d9e8e2c6db0746e57a6dc0b", + "sha256:ee7aa8bb716318e3d835ef473978e22b7a39c0f1b3b08cc0b0ee1bba6f73bc1e", + "sha256:f0899cd23967950e7b902ea75af06cfe5f59ac71eb38e98a774c9e596790e6aa", + "sha256:f0c45eae32d090763820756b18322a70571dada3f1cbe003debc37a9c35bc260", + "sha256:f3b63648600dd0081bdd6856a86d014a7f1d2d11c3c974542f866478d832e103", + "sha256:f669910b64d27750398f6c56c651367d4954b05c86ff067af1c9949e109cf1e2", + "sha256:fd4ebc475d43f3de2b26e0cf551eff92c24e22d1aee03dc1b33adb52fc2e6cb2" ], "markers": "python_version >= '3.8'", - "version": "==4.55.3" + "version": "==4.55.7" }, "gunicorn": { "hashes": [ @@ -583,12 +583,12 @@ }, "psycopg": { "hashes": [ - "sha256:644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907", - "sha256:a5764f67c27bec8bfac85764d23c534af2c27b893550377e37ce59c12aac47a2" + "sha256:43665368ccd48180744cab26b74332f46b63b7e06e8ce0775547a3533883d381", + "sha256:f26f1346d6bf1ef5f5ef1714dd405c67fb365cfd1c6cea07de1792747b167b92" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==3.2.3" + "version": "==3.2.4" }, "pycparser": { "hashes": [ @@ -608,11 +608,11 @@ }, "pyphen": { "hashes": [ - "sha256:1d13acd1ce37a384d7612954ae6c7801bb4c5316da0e2b937b2127ba702a3da4", - "sha256:dad0b2e4aa80f6d70bf06711b2da36c47a756b933c1d0c4cbbab40f643a5958c" + "sha256:3a07fb017cb2341e1d9ff31b8634efb1ae4dc4b130468c7c39dd3d32e7c3affd", + "sha256:f60647a9c9b30ec6c59910097af82bc5dd2d36576b918e44148d8b07ef3b4aa3" ], "markers": "python_version >= '3.9'", - "version": "==0.17.0" + "version": "==0.17.2" }, "python-dateutil": { "hashes": [