-
-
C'est votre structure et vous souhaitez modifier ses informations ?
-
-
+
- {{ siae.get_kind_display }}
-
-
-
- {{ siae.presta_type_display }}
-
-
-
-
{% siae_sectors_display siae display_max=3 current_search_query=current_search_query %}
+ {% siae_sector_groups_display siae display_max=3 current_sector_groups=current_sector_groups %}
+ {% if user.is_authenticated and user.is_admin and not siae.user_count %}
+
pas encore inscrite
+ {% endif %}
-
-
+
+
{{ siae.city }}
-
- {{ siae.geo_range_pretty_display }}
- {% if user.is_authenticated and user.is_admin and not siae.user_count %}
-
pas encore inscrite
- {% endif %}
diff --git a/lemarche/templates/siaes/_siae_activity_card.html b/lemarche/templates/siaes/_siae_activity_card.html
index 5788c5305..abf9f9cca 100644
--- a/lemarche/templates/siaes/_siae_activity_card.html
+++ b/lemarche/templates/siaes/_siae_activity_card.html
@@ -10,7 +10,7 @@
{{ activity.sector_group }}
- Type(s) de prestation :
+ Type(s) de prestation :
{{ activity.presta_type_display }}
diff --git a/lemarche/templates/siaes/_siae_activity_content.html b/lemarche/templates/siaes/_siae_activity_content.html
index 9581f8daf..a25a9f6ce 100644
--- a/lemarche/templates/siaes/_siae_activity_content.html
+++ b/lemarche/templates/siaes/_siae_activity_content.html
@@ -1,28 +1,23 @@
{% load siae_sectors_display %}
-
-
- {% if with_collapse %}
-
- {{ activity.sector_group }}
-
- {% else %}
- {{ activity.sector_group }}
- {% endif %}
-
-
-
-
- {% siae_sectors_display activity display_max=6 output_format='li' %}
-
-
-
-
- Type(s) de prestation :
- {{ activity.presta_type_display }}
-
-
-
- Intervient sur : {{ siae.geo_range_pretty_title }}
- {{ siae.geo_range_pretty_display }}
-
-
+
+
+ {{ activity.sector_group }}
+
+
+
+ {% siae_sectors_display activity display_max=6 output_format='li' %}
+
+
+
+ Type(s) de prestation :
+ {{ activity.presta_type_display }}
+
+
+
+ Intervient sur :
+ {{ activity.geo_range_pretty_display }}
+
+
+
diff --git a/lemarche/templates/utils/templatetags/siae_sectors_display.html b/lemarche/templates/utils/templatetags/siae_sectors_display.html
new file mode 100644
index 000000000..840fba514
--- /dev/null
+++ b/lemarche/templates/utils/templatetags/siae_sectors_display.html
@@ -0,0 +1,12 @@
+
diff --git a/lemarche/utils/templatetags/siae_sectors_display.py b/lemarche/utils/templatetags/siae_sectors_display.py
index 00a087af7..6e2da3024 100644
--- a/lemarche/utils/templatetags/siae_sectors_display.py
+++ b/lemarche/utils/templatetags/siae_sectors_display.py
@@ -39,3 +39,44 @@ def siae_sectors_display(object, display_max=5, current_search_query="", output_
return mark_safe("".join([f"
{elem_name} " for elem_name in values]))
else: # "string"
return ", ".join(values)
+
+
+@register.inclusion_tag("utils/templatetags/siae_sectors_display.html")
+def siae_sector_groups_display(object, display_max=5, current_sector_groups=[]):
+ """
+ Pretty rendering of M2M field SectorGroup for Siae.
+ """
+
+ # to avoid duplicates and display current search values first
+ seen_slugs = set()
+
+ current_values = []
+ # Add sector groups from current_sector_groups if they are in object's activities
+ for sector_group in current_sector_groups:
+ if any(activity.sector_group.slug == sector_group.slug for activity in object.activities.all()):
+ if sector_group.slug not in seen_slugs:
+ current_values.append(sector_group.name)
+ seen_slugs.add(sector_group.slug)
+
+ values = []
+
+ # Add remaining sector groups from object's activities
+ for activity in object.activities.all():
+ if activity.sector_group.slug not in seen_slugs:
+ values.append(activity.sector_group.name)
+ seen_slugs.add(activity.sector_group.slug)
+
+ # alphabetical order here to avoid N+1 queries
+ values = sorted(values)
+
+ # filter number of displayed values
+ groups_count = len(seen_slugs)
+ if groups_count > display_max:
+ display_max_values = display_max - len(current_values)
+ if display_max_values > 0:
+ values = values[:display_max_values]
+ else:
+ values = []
+ values.append(f"+{groups_count-display_max}")
+
+ return {"current_search_sector_groups": sorted(current_values), "sector_groups": values}
diff --git a/lemarche/utils/tests_templatetags.py b/lemarche/utils/tests_templatetags.py
index 0c750aa9e..67bae1991 100644
--- a/lemarche/utils/tests_templatetags.py
+++ b/lemarche/utils/tests_templatetags.py
@@ -1,55 +1,72 @@
+from django.template import Context, Template
from django.test import TestCase
-from lemarche.sectors.factories import SectorFactory
-from lemarche.siaes.factories import SiaeFactory
+from lemarche.sectors.factories import SectorFactory, SectorGroupFactory
+from lemarche.siaes.factories import SiaeActivityFactory, SiaeFactory
from lemarche.utils.templatetags.siae_sectors_display import siae_sectors_display
class SiaeSectorDisplayTest(TestCase):
@classmethod
def setUpTestData(cls):
- cls.siae_with_one_sector = SiaeFactory()
- cls.siae_with_two_sectors = SiaeFactory()
- cls.siae_with_many_sectors = SiaeFactory()
+ siae_with_one_sector = SiaeFactory()
+ siae_with_two_sectors = SiaeFactory()
+ siae_with_many_sectors = SiaeFactory()
cls.siae_etti = SiaeFactory(kind="ETTI")
sector_1 = SectorFactory(name="Entretien")
sector_2 = SectorFactory(name="Agro")
sector_3 = SectorFactory(name="Hygiène")
sector_4 = SectorFactory(name="Bâtiment")
sector_5 = SectorFactory(name="Informatique")
- cls.siae_with_one_sector.sectors.add(sector_1)
- cls.siae_with_two_sectors.sectors.add(sector_1, sector_2)
- cls.siae_with_many_sectors.sectors.add(sector_1, sector_2, sector_3, sector_4, sector_5)
+
+ cls.siae_activity_with_one_sector = SiaeActivityFactory(siae=siae_with_one_sector)
+ cls.siae_activity_with_one_sector.sectors.add(sector_1)
+ cls.siae_activity_with_two_sectors = SiaeActivityFactory(siae=siae_with_two_sectors)
+ cls.siae_activity_with_two_sectors.sectors.add(sector_1, sector_2)
+ cls.siae_activity_with_many_sectors = SiaeActivityFactory(siae=siae_with_many_sectors)
+ cls.siae_activity_with_many_sectors.sectors.add(sector_1, sector_2, sector_3, sector_4, sector_5)
+
cls.siae_etti.sectors.add(sector_1, sector_2, sector_3, sector_4, sector_5)
def test_should_return_list_of_siae_sector_strings(self):
- self.assertEqual(siae_sectors_display(self.siae_with_one_sector), "Entretien")
- self.assertEqual(siae_sectors_display(self.siae_with_two_sectors), "Agro, Entretien") # default ordering: name
+ self.assertEqual(siae_sectors_display(self.siae_activity_with_one_sector), "Entretien")
+ self.assertEqual(
+ siae_sectors_display(self.siae_activity_with_two_sectors), "Agro, Entretien"
+ ) # default ordering: name
self.assertEqual(
- siae_sectors_display(self.siae_with_many_sectors), "Agro, Bâtiment, Entretien, Hygiène, Informatique"
+ siae_sectors_display(self.siae_activity_with_many_sectors),
+ "Agro, Bâtiment, Entretien, Hygiène, Informatique",
)
def test_should_filter_list_of_siae_sectors(self):
self.assertEqual(
- siae_sectors_display(self.siae_with_many_sectors, display_max=3), "Agro, Bâtiment, Entretien, …"
+ siae_sectors_display(self.siae_activity_with_many_sectors, display_max=3), "Agro, Bâtiment, Entretien, …"
)
def test_should_return_list_in_the_specified_format(self):
- self.assertEqual(siae_sectors_display(self.siae_with_two_sectors, output_format="list"), ["Agro", "Entretien"])
self.assertEqual(
- siae_sectors_display(self.siae_with_two_sectors, output_format="li"), "
Agro Entretien "
+ siae_sectors_display(self.siae_activity_with_two_sectors, output_format="list"), ["Agro", "Entretien"]
+ )
+ self.assertEqual(
+ siae_sectors_display(self.siae_activity_with_two_sectors, output_format="li"),
+ "
Agro Entretien ",
)
def test_should_have_different_behavior_for_etti(self):
self.assertEqual(siae_sectors_display(self.siae_etti), "Multisectoriel")
def test_should_filter_list_on_current_search_query(self):
- self.assertEqual(siae_sectors_display(self.siae_with_one_sector, current_search_query="sectors=agro"), "")
self.assertEqual(
- siae_sectors_display(self.siae_with_two_sectors, current_search_query="sectors=entretien"), "Entretien"
+ siae_sectors_display(self.siae_activity_with_one_sector, current_search_query="sectors=agro"), ""
)
self.assertEqual(
- siae_sectors_display(self.siae_with_many_sectors, current_search_query="sectors=entretien§ors=agro"),
+ siae_sectors_display(self.siae_activity_with_two_sectors, current_search_query="sectors=entretien"),
+ "Entretien",
+ )
+ self.assertEqual(
+ siae_sectors_display(
+ self.siae_activity_with_many_sectors, current_search_query="sectors=entretien§ors=agro"
+ ),
"Agro, Entretien",
)
# priority is on current_search (over ETTI)
@@ -57,3 +74,103 @@ def test_should_filter_list_on_current_search_query(self):
siae_sectors_display(self.siae_etti, current_search_query="sectors=entretien§ors=agro"),
"Agro, Entretien",
)
+
+
+class SiaeSectorGroupsDisplayTest(TestCase):
+ @classmethod
+ def setUpTestData(cls):
+ cls.siae_with_one_sector = SiaeFactory()
+ cls.siae_with_three_sectors = SiaeFactory()
+ cls.siae_with_many_sectors = SiaeFactory()
+
+ cls.sector_group_1 = SectorGroupFactory(name="Entretien du linge")
+ cls.sector_group_2 = SectorGroupFactory(name="Espaces verts")
+ cls.sector_group_3 = SectorGroupFactory(name="Bâtiment")
+ cls.sector_group_4 = SectorGroupFactory(name="Agro-Alimentaire")
+
+ sector_1 = SectorFactory(name="Blanchisserie", group=cls.sector_group_1)
+ sector_2 = SectorFactory(name="Génie écologique", group=cls.sector_group_2)
+ sector_3 = SectorFactory(name="Menuiserie", group=cls.sector_group_3)
+ sector_4 = SectorFactory(name="Agriculture", group=cls.sector_group_4)
+ sector_5 = SectorFactory(name="Plomberie", group=cls.sector_group_3)
+
+ siae_with_one_sector_activity = SiaeActivityFactory(
+ siae=cls.siae_with_one_sector, sector_group=cls.sector_group_1
+ )
+ siae_with_one_sector_activity.sectors.add(sector_1)
+
+ siae_with_three_sectors_activity_1 = SiaeActivityFactory(
+ siae=cls.siae_with_three_sectors, sector_group=cls.sector_group_1
+ )
+ siae_with_three_sectors_activity_1.sectors.add(sector_1)
+ siae_with_three_sectors_activity_2 = SiaeActivityFactory(
+ siae=cls.siae_with_three_sectors, sector_group=cls.sector_group_2
+ )
+ siae_with_three_sectors_activity_2.sectors.add(sector_2)
+ siae_with_three_sectors_activity_3 = SiaeActivityFactory(
+ siae=cls.siae_with_three_sectors, sector_group=cls.sector_group_3
+ )
+ siae_with_three_sectors_activity_3.sectors.add(sector_3, sector_5)
+
+ siae_with_many_sectors_activity_1 = SiaeActivityFactory(
+ siae=cls.siae_with_many_sectors, sector_group=cls.sector_group_1
+ )
+ siae_with_many_sectors_activity_1.sectors.add(sector_1)
+ siae_with_many_sectors_activity_2 = SiaeActivityFactory(
+ siae=cls.siae_with_many_sectors, sector_group=cls.sector_group_2
+ )
+ siae_with_many_sectors_activity_2.sectors.add(sector_2)
+ siae_with_many_sectors_activity_3 = SiaeActivityFactory(
+ siae=cls.siae_with_many_sectors, sector_group=cls.sector_group_3
+ )
+ siae_with_many_sectors_activity_3.sectors.add(sector_3)
+ siae_with_many_sectors_activity_4 = SiaeActivityFactory(
+ siae=cls.siae_with_many_sectors, sector_group=cls.sector_group_4
+ )
+ siae_with_many_sectors_activity_4.sectors.add(sector_4)
+ siae_with_many_sectors_activity_5 = SiaeActivityFactory(
+ siae=cls.siae_with_many_sectors, sector_group=cls.sector_group_3
+ )
+ siae_with_many_sectors_activity_5.sectors.add(sector_5)
+
+ # Test siae_sector_groups_display if return only one sector group
+ def test_should_return_html_with_siae_sector_groups(self):
+ template = Template(
+ "{% load siae_sectors_display %}"
+ "{% siae_sector_groups_display siae display_max=3 current_sector_groups=current_sector_groups %}"
+ )
+
+ # Render the template with a context (if needed)
+ rendered = template.render(Context({"siae": self.siae_with_one_sector, "current_sector_groups": []}))
+
+ self.assertInHTML("Entretien du linge", rendered)
+ self.assertNotIn("+", rendered)
+
+ rendered = template.render(Context({"siae": self.siae_with_three_sectors, "current_sector_groups": []}))
+ self.assertInHTML("Bâtiment", rendered)
+ self.assertInHTML("Entretien du linge", rendered)
+ self.assertInHTML("Espaces verts", rendered)
+ self.assertNotIn("+", rendered)
+
+ rendered = template.render(Context({"siae": self.siae_with_many_sectors, "current_sector_groups": []}))
+
+ self.assertInHTML("Agro-Alimentaire", rendered)
+ self.assertInHTML("Bâtiment", rendered)
+ self.assertInHTML("Entretien du linge", rendered)
+ self.assertInHTML("+1", rendered)
+
+ self.assertNotIn("Espaces verts", rendered)
+
+ rendered = template.render(
+ Context(
+ {
+ "siae": self.siae_with_many_sectors,
+ "current_sector_groups": [self.sector_group_3],
+ }
+ )
+ )
+ self.assertInHTML('
Bâtiment ', rendered)
+ self.assertInHTML("Agro-Alimentaire", rendered)
+ self.assertInHTML("Entretien du linge", rendered)
+ self.assertInHTML("+1", rendered)
+ self.assertNotIn("Espaces verts", rendered)
diff --git a/lemarche/www/dashboard_favorites/tests.py b/lemarche/www/dashboard_favorites/tests.py
index 286a3ae48..9e39909ea 100644
--- a/lemarche/www/dashboard_favorites/tests.py
+++ b/lemarche/www/dashboard_favorites/tests.py
@@ -34,5 +34,8 @@ def test_only_favorite_list_user_can_view_favorite_list_detail(self):
# favorite list user
self.client.force_login(self.user_favorite_list)
url = reverse("dashboard_favorites:list_detail", args=[self.favorite_list_1.slug])
- response = self.client.get(url)
- self.assertEqual(response.status_code, 200)
+
+ # check number of queries
+ with self.assertNumQueries(6):
+ response = self.client.get(url)
+ self.assertEqual(response.status_code, 200)
diff --git a/lemarche/www/dashboard_favorites/views.py b/lemarche/www/dashboard_favorites/views.py
index d2c843ba0..294571be8 100644
--- a/lemarche/www/dashboard_favorites/views.py
+++ b/lemarche/www/dashboard_favorites/views.py
@@ -64,7 +64,7 @@ def get_success_message(self, cleaned_data):
class DashboardFavoriteListDetailView(FavoriteListOwnerRequiredMixin, DetailView):
template_name = "favorites/dashboard_favorite_list_detail.html"
- queryset = FavoriteList.objects.prefetch_related("siaes").all()
+ queryset = FavoriteList.objects.prefetch_related("siaes", "siaes__activities__sector_group").all()
context_object_name = "favorite_list"
def get_context_data(self, **kwargs):
diff --git a/lemarche/www/siaes/forms.py b/lemarche/www/siaes/forms.py
index ff12e31dc..a22f3161b 100644
--- a/lemarche/www/siaes/forms.py
+++ b/lemarche/www/siaes/forms.py
@@ -230,6 +230,8 @@ def filter_queryset(self, qs=None): # noqa C901
if not hasattr(self, "cleaned_data"):
self.full_clean()
+ qs = qs.prefetch_related("activities__sector_group")
+
kinds = self.cleaned_data.get("kind", None)
if kinds:
qs = qs.filter(kind__in=kinds)
diff --git a/lemarche/www/siaes/tests.py b/lemarche/www/siaes/tests.py
index d279162c5..b3f57680a 100644
--- a/lemarche/www/siaes/tests.py
+++ b/lemarche/www/siaes/tests.py
@@ -64,7 +64,7 @@ def test_search_num_queries(self):
# See https://docs.djangoproject.com/en/5.1/ref/contrib/sites/#caching-the-current-site-object
Site.objects.get_current()
- with self.assertNumQueries(12):
+ with self.assertNumQueries(13):
response = self.client.get(url)
siaes = list(response.context["siaes"])
self.assertEqual(len(siaes), 20)
diff --git a/lemarche/www/siaes/views.py b/lemarche/www/siaes/views.py
index 369623f77..9eeffd301 100644
--- a/lemarche/www/siaes/views.py
+++ b/lemarche/www/siaes/views.py
@@ -120,6 +120,7 @@ def get_context_data(self, **kwargs):
current_sectors = siae_search_form.cleaned_data.get("sectors")
if current_sectors:
context["current_sectors"] = list(current_sectors.values("id", "slug", "name"))
+ context["current_sector_groups"] = list(set(sector.group for sector in current_sectors))
# store the current search query in the session
current_search_query = self.request.GET.urlencode()