We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Bug : Export des interventions filtrées dans la table n'est pas filtré dans le csv exporté
**Contexte :** 

Bug dans le module intervention

**Résultat attendu :** 

Lorsque je filtre la table qui liste les objets dans le module et que j'exporte le résultat au format CSV, le CSV ne doit contenir que les résultats filtrés

**Résultat observé (bug) :** 

La table CSV obtenue contient l'ensemble des interventions non filtrées, sans tenir compte des éventuels filtres choisis par l'utilisateur dans l'interface. 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `geotrek/maintenance/views.py`
Content:
```
1 import logging
2 import re
3 
4 from django.conf import settings
5 from django.db.models import Subquery, OuterRef, Sum
6 from django.db.models.expressions import Value
7 from django.utils.translation import gettext_lazy as _
8 from mapentity.views import (MapEntityList, MapEntityFormat, MapEntityDetail, MapEntityDocument,
9                              MapEntityCreate, MapEntityUpdate, MapEntityDelete)
10 
11 from geotrek.altimetry.models import AltimetryMixin
12 from geotrek.authent.decorators import same_structure_required
13 from geotrek.common.mixins.forms import FormsetMixin
14 from geotrek.common.mixins.views import CustomColumnsMixin
15 from geotrek.common.viewsets import GeotrekMapentityViewSet
16 from .filters import InterventionFilterSet, ProjectFilterSet
17 from .forms import (InterventionForm, ProjectForm,
18                     FundingFormSet, ManDayFormSet)
19 from .models import Intervention, Project, ManDay
20 from .serializers import (InterventionSerializer, ProjectSerializer,
21                           InterventionGeojsonSerializer, ProjectGeojsonSerializer)
22 
23 logger = logging.getLogger(__name__)
24 
25 
26 ANNOTATION_FORBIDDEN_CHARS = re.compile(r"['`\"\]\[;\s]|--|/\*|\*/")
27 REPLACEMENT_CHAR = "_"
28 
29 
30 def _normalize_annotation_column_name(col_name):
31     return ANNOTATION_FORBIDDEN_CHARS.sub(repl=REPLACEMENT_CHAR, string=col_name)
32 
33 
34 class InterventionList(CustomColumnsMixin, MapEntityList):
35     queryset = Intervention.objects.existing()
36     filterform = InterventionFilterSet
37     mandatory_columns = ['id', 'name']
38     default_extra_columns = ['date', 'type', 'target', 'status', 'stake']
39     searchable_columns = ['id', 'name']
40     unorderable_columns = ['target']
41 
42 
43 class InterventionFormatList(MapEntityFormat, InterventionList):
44 
45     @classmethod
46     def build_cost_column_name(cls, job_name):
47         return _normalize_annotation_column_name(f"{_('Cost')} {job_name}")
48 
49     def get_queryset(self):
50         """Returns all interventions joined with a new column for each job, to record the total cost of each job in each intervention"""
51 
52         queryset = Intervention.objects.existing()
53 
54         if settings.ENABLE_JOBS_COSTS_DETAILED_EXPORT:
55 
56             # Get all jobs that are used in interventions, as unique names, ids and costs
57             all_mandays = ManDay.objects.all()
58             jobs_used_in_interventions = list(
59                 set(all_mandays.values_list("job__job", "job_id", "job__cost"))
60             )
61 
62             # Iter over unique jobs
63             for job_name, job_id, job_cost in jobs_used_in_interventions:
64 
65                 # Create column name for current job cost
66                 column_name = self.build_cost_column_name(job_name)
67 
68                 # Create subquery to retrieve total cost of mandays for a given intervention and a given job
69                 mandays_query = (
70                     ManDay.objects.filter(intervention=OuterRef("pk"), job_id=job_id)  # Extract all mandays for a given intervention and a given job
71                     .values("job_id")  # Group by job
72                     .annotate(total_days=Sum("nb_days"))  # Select number of days worked
73                     .values("total_days")  # Rename result as total_days
74                 )
75 
76                 # Use total_days and job cost to calculate total cost for a given intervention and a given job
77                 job_cost_query = Subquery(mandays_query) * Value(job_cost)
78 
79                 # Annotate queryset with this cost query
80                 params = {column_name: job_cost_query}
81                 queryset = queryset.annotate(**params)
82         return queryset
83 
84     @classmethod
85     def get_mandatory_columns(cls):
86         mandatory_columns = ['id']
87         if settings.ENABLE_JOBS_COSTS_DETAILED_EXPORT:
88             all_mandays = ManDay.objects.all()  # Used to find all jobs that ARE USED in interventions
89             # Get all jobs that are used in interventions, as unique names
90             jobs_as_names = list(
91                 set(all_mandays.values_list("job__job", flat=True))
92             )
93             # Create column names for each unique job cost
94             cost_column_names = list(map(cls.build_cost_column_name, jobs_as_names))
95             # Add these column names to export
96             mandatory_columns = mandatory_columns + cost_column_names
97         return mandatory_columns
98 
99     default_extra_columns = [
100         'name', 'date', 'type', 'target', 'status', 'stake',
101         'disorders', 'total_manday', 'project', 'subcontracting',
102         'width', 'height', 'area', 'structure',
103         'description', 'date_insert', 'date_update',
104         'material_cost', 'heliport_cost', 'subcontract_cost',
105         'total_cost_mandays', 'total_cost',
106         'cities', 'districts', 'areas',
107     ] + AltimetryMixin.COLUMNS
108 
109 
110 class InterventionDetail(MapEntityDetail):
111     queryset = Intervention.objects.existing()
112 
113     def get_context_data(self, *args, **kwargs):
114         context = super().get_context_data(*args, **kwargs)
115         context['can_edit'] = self.get_object().same_structure(self.request.user)
116         return context
117 
118 
119 class InterventionDocument(MapEntityDocument):
120     model = Intervention
121 
122 
123 class ManDayFormsetMixin(FormsetMixin):
124     context_name = 'manday_formset'
125     formset_class = ManDayFormSet
126 
127 
128 class InterventionCreate(ManDayFormsetMixin, MapEntityCreate):
129     model = Intervention
130     form_class = InterventionForm
131 
132     def get_form_kwargs(self):
133         kwargs = super().get_form_kwargs()
134         if 'target_id' in self.request.GET and 'target_type' in self.request.GET:
135             # Create intervention on an existing infrastructure
136             kwargs['target_id'] = self.request.GET['target_id']
137             kwargs['target_type'] = self.request.GET['target_type']
138         return kwargs
139 
140 
141 class InterventionUpdate(ManDayFormsetMixin, MapEntityUpdate):
142     queryset = Intervention.objects.existing()
143     form_class = InterventionForm
144 
145     @same_structure_required('maintenance:intervention_detail')
146     def dispatch(self, *args, **kwargs):
147         return super().dispatch(*args, **kwargs)
148 
149     def get_form_kwargs(self):
150         kwargs = super().get_form_kwargs()
151         # If deletion is allowed
152         if kwargs['can_delete']:
153             intervention = self.get_object()
154             # Disallow deletion if this intervention is part of Suricate Workflow at the moment
155             not_workflow = not settings.SURICATE_WORKFLOW_ENABLED
156             is_report = intervention.target and intervention.target.__class__.__name__ == "Report"
157             report_is_closed = False
158             if is_report:
159                 report_is_closed = (intervention.target.status.identifier == 'solved')
160             kwargs["can_delete"] = not_workflow or (not is_report) or report_is_closed
161         return kwargs
162 
163 
164 class InterventionDelete(MapEntityDelete):
165     model = Intervention
166 
167     @same_structure_required('maintenance:intervention_detail')
168     def dispatch(self, *args, **kwargs):
169         return super().dispatch(*args, **kwargs)
170 
171 
172 class InterventionViewSet(GeotrekMapentityViewSet):
173     model = Intervention
174     serializer_class = InterventionSerializer
175     geojson_serializer_class = InterventionGeojsonSerializer
176     filterset_class = InterventionFilterSet
177     mapentity_list_class = InterventionList
178 
179     def get_queryset(self):
180         qs = self.model.objects.existing()
181         if self.format_kwarg == 'geojson':
182             qs = qs.only('id', 'name')
183         else:
184             qs = qs.select_related("stake", "status", "type", "target_type").prefetch_related('target')
185         return qs
186 
187 
188 class ProjectList(CustomColumnsMixin, MapEntityList):
189     queryset = Project.objects.existing()
190     filterform = ProjectFilterSet
191     mandatory_columns = ['id', 'name']
192     default_extra_columns = ['period', 'type', 'domain']
193     searchable_columns = ['id', 'name']
194     unorderable_columns = ['period', ]
195 
196 
197 class ProjectFormatList(MapEntityFormat, ProjectList):
198     mandatory_columns = ['id']
199     default_extra_columns = [
200         'structure', 'name', 'period', 'type', 'domain', 'constraint', 'global_cost',
201         'interventions', 'interventions_total_cost', 'comments', 'contractors',
202         'project_owner', 'project_manager', 'founders',
203         'date_insert', 'date_update',
204         'cities', 'districts', 'areas',
205     ]
206 
207 
208 class ProjectDetail(MapEntityDetail):
209     queryset = Project.objects.existing()
210 
211     def get_context_data(self, *args, **kwargs):
212         context = super().get_context_data(*args, **kwargs)
213         context['can_edit'] = self.get_object().same_structure(self.request.user)
214         context['empty_map_message'] = _("No intervention related.")
215         return context
216 
217 
218 class ProjectDocument(MapEntityDocument):
219     model = Project
220 
221 
222 class FundingFormsetMixin(FormsetMixin):
223     context_name = 'funding_formset'
224     formset_class = FundingFormSet
225 
226 
227 class ProjectCreate(FundingFormsetMixin, MapEntityCreate):
228     model = Project
229     form_class = ProjectForm
230 
231 
232 class ProjectUpdate(FundingFormsetMixin, MapEntityUpdate):
233     queryset = Project.objects.existing()
234     form_class = ProjectForm
235 
236     @same_structure_required('maintenance:project_detail')
237     def dispatch(self, *args, **kwargs):
238         return super().dispatch(*args, **kwargs)
239 
240 
241 class ProjectDelete(MapEntityDelete):
242     model = Project
243 
244     @same_structure_required('maintenance:project_detail')
245     def dispatch(self, *args, **kwargs):
246         return super().dispatch(*args, **kwargs)
247 
248 
249 class ProjectViewSet(GeotrekMapentityViewSet):
250     model = Project
251     serializer_class = ProjectSerializer
252     geojson_serializer_class = ProjectGeojsonSerializer
253     filterset_class = ProjectFilterSet
254     mapentity_list_class = ProjectList
255 
256     def get_queryset(self):
257         qs = self.model.objects.existing()
258         if self.format_kwarg == 'geojson':
259             non_empty_qs = Intervention.objects.existing().filter(project__isnull=False).values('project')
260             qs = qs.filter(pk__in=non_empty_qs)
261             qs = qs.only('id', 'name')
262         return qs
263
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/geotrek/maintenance/views.py b/geotrek/maintenance/views.py
--- a/geotrek/maintenance/views.py
+++ b/geotrek/maintenance/views.py
@@ -49,7 +49,7 @@
     def get_queryset(self):
         """Returns all interventions joined with a new column for each job, to record the total cost of each job in each intervention"""
 
-        queryset = Intervention.objects.existing()
+        queryset = super().get_queryset()
 
         if settings.ENABLE_JOBS_COSTS_DETAILED_EXPORT:

{"golden_diff": "diff --git a/geotrek/maintenance/views.py b/geotrek/maintenance/views.py\n--- a/geotrek/maintenance/views.py\n+++ b/geotrek/maintenance/views.py\n@@ -49,7 +49,7 @@\n     def get_queryset(self):\n         \"\"\"Returns all interventions joined with a new column for each job, to record the total cost of each job in each intervention\"\"\"\n \n-        queryset = Intervention.objects.existing()\n+        queryset = super().get_queryset()\n \n         if settings.ENABLE_JOBS_COSTS_DETAILED_EXPORT:\n", "issue": "Bug : Export des interventions filtr\u00e9es dans la table n'est pas filtr\u00e9 dans le csv export\u00e9\n**Contexte :** \r\n\r\nBug dans le module intervention\r\n\r\n**R\u00e9sultat attendu :** \r\n\r\nLorsque je filtre la table qui liste les objets dans le module et que j'exporte le r\u00e9sultat au format CSV, le CSV ne doit contenir que les r\u00e9sultats filtr\u00e9s\r\n\r\n**R\u00e9sultat observ\u00e9 (bug) :** \r\n\r\nLa table CSV obtenue contient l'ensemble des interventions non filtr\u00e9es, sans tenir compte des \u00e9ventuels filtres choisis par l'utilisateur dans l'interface. \n", "before_files": [{"content": "import logging\nimport re\n\nfrom django.conf import settings\nfrom django.db.models import Subquery, OuterRef, Sum\nfrom django.db.models.expressions import Value\nfrom django.utils.translation import gettext_lazy as _\nfrom mapentity.views import (MapEntityList, MapEntityFormat, MapEntityDetail, MapEntityDocument,\n                             MapEntityCreate, MapEntityUpdate, MapEntityDelete)\n\nfrom geotrek.altimetry.models import AltimetryMixin\nfrom geotrek.authent.decorators import same_structure_required\nfrom geotrek.common.mixins.forms import FormsetMixin\nfrom geotrek.common.mixins.views import CustomColumnsMixin\nfrom geotrek.common.viewsets import GeotrekMapentityViewSet\nfrom .filters import InterventionFilterSet, ProjectFilterSet\nfrom .forms import (InterventionForm, ProjectForm,\n                    FundingFormSet, ManDayFormSet)\nfrom .models import Intervention, Project, ManDay\nfrom .serializers import (InterventionSerializer, ProjectSerializer,\n                          InterventionGeojsonSerializer, ProjectGeojsonSerializer)\n\nlogger = logging.getLogger(__name__)\n\n\nANNOTATION_FORBIDDEN_CHARS = re.compile(r\"['`\\\"\\]\\[;\\s]|--|/\\*|\\*/\")\nREPLACEMENT_CHAR = \"_\"\n\n\ndef _normalize_annotation_column_name(col_name):\n    return ANNOTATION_FORBIDDEN_CHARS.sub(repl=REPLACEMENT_CHAR, string=col_name)\n\n\nclass InterventionList(CustomColumnsMixin, MapEntityList):\n    queryset = Intervention.objects.existing()\n    filterform = InterventionFilterSet\n    mandatory_columns = ['id', 'name']\n    default_extra_columns = ['date', 'type', 'target', 'status', 'stake']\n    searchable_columns = ['id', 'name']\n    unorderable_columns = ['target']\n\n\nclass InterventionFormatList(MapEntityFormat, InterventionList):\n\n    @classmethod\n    def build_cost_column_name(cls, job_name):\n        return _normalize_annotation_column_name(f\"{_('Cost')} {job_name}\")\n\n    def get_queryset(self):\n        \"\"\"Returns all interventions joined with a new column for each job, to record the total cost of each job in each intervention\"\"\"\n\n        queryset = Intervention.objects.existing()\n\n        if settings.ENABLE_JOBS_COSTS_DETAILED_EXPORT:\n\n            # Get all jobs that are used in interventions, as unique names, ids and costs\n            all_mandays = ManDay.objects.all()\n            jobs_used_in_interventions = list(\n                set(all_mandays.values_list(\"job__job\", \"job_id\", \"job__cost\"))\n            )\n\n            # Iter over unique jobs\n            for job_name, job_id, job_cost in jobs_used_in_interventions:\n\n                # Create column name for current job cost\n                column_name = self.build_cost_column_name(job_name)\n\n                # Create subquery to retrieve total cost of mandays for a given intervention and a given job\n                mandays_query = (\n                    ManDay.objects.filter(intervention=OuterRef(\"pk\"), job_id=job_id)  # Extract all mandays for a given intervention and a given job\n                    .values(\"job_id\")  # Group by job\n                    .annotate(total_days=Sum(\"nb_days\"))  # Select number of days worked\n                    .values(\"total_days\")  # Rename result as total_days\n                )\n\n                # Use total_days and job cost to calculate total cost for a given intervention and a given job\n                job_cost_query = Subquery(mandays_query) * Value(job_cost)\n\n                # Annotate queryset with this cost query\n                params = {column_name: job_cost_query}\n                queryset = queryset.annotate(**params)\n        return queryset\n\n    @classmethod\n    def get_mandatory_columns(cls):\n        mandatory_columns = ['id']\n        if settings.ENABLE_JOBS_COSTS_DETAILED_EXPORT:\n            all_mandays = ManDay.objects.all()  # Used to find all jobs that ARE USED in interventions\n            # Get all jobs that are used in interventions, as unique names\n            jobs_as_names = list(\n                set(all_mandays.values_list(\"job__job\", flat=True))\n            )\n            # Create column names for each unique job cost\n            cost_column_names = list(map(cls.build_cost_column_name, jobs_as_names))\n            # Add these column names to export\n            mandatory_columns = mandatory_columns + cost_column_names\n        return mandatory_columns\n\n    default_extra_columns = [\n        'name', 'date', 'type', 'target', 'status', 'stake',\n        'disorders', 'total_manday', 'project', 'subcontracting',\n        'width', 'height', 'area', 'structure',\n        'description', 'date_insert', 'date_update',\n        'material_cost', 'heliport_cost', 'subcontract_cost',\n        'total_cost_mandays', 'total_cost',\n        'cities', 'districts', 'areas',\n    ] + AltimetryMixin.COLUMNS\n\n\nclass InterventionDetail(MapEntityDetail):\n    queryset = Intervention.objects.existing()\n\n    def get_context_data(self, *args, **kwargs):\n        context = super().get_context_data(*args, **kwargs)\n        context['can_edit'] = self.get_object().same_structure(self.request.user)\n        return context\n\n\nclass InterventionDocument(MapEntityDocument):\n    model = Intervention\n\n\nclass ManDayFormsetMixin(FormsetMixin):\n    context_name = 'manday_formset'\n    formset_class = ManDayFormSet\n\n\nclass InterventionCreate(ManDayFormsetMixin, MapEntityCreate):\n    model = Intervention\n    form_class = InterventionForm\n\n    def get_form_kwargs(self):\n        kwargs = super().get_form_kwargs()\n        if 'target_id' in self.request.GET and 'target_type' in self.request.GET:\n            # Create intervention on an existing infrastructure\n            kwargs['target_id'] = self.request.GET['target_id']\n            kwargs['target_type'] = self.request.GET['target_type']\n        return kwargs\n\n\nclass InterventionUpdate(ManDayFormsetMixin, MapEntityUpdate):\n    queryset = Intervention.objects.existing()\n    form_class = InterventionForm\n\n    @same_structure_required('maintenance:intervention_detail')\n    def dispatch(self, *args, **kwargs):\n        return super().dispatch(*args, **kwargs)\n\n    def get_form_kwargs(self):\n        kwargs = super().get_form_kwargs()\n        # If deletion is allowed\n        if kwargs['can_delete']:\n            intervention = self.get_object()\n            # Disallow deletion if this intervention is part of Suricate Workflow at the moment\n            not_workflow = not settings.SURICATE_WORKFLOW_ENABLED\n            is_report = intervention.target and intervention.target.__class__.__name__ == \"Report\"\n            report_is_closed = False\n            if is_report:\n                report_is_closed = (intervention.target.status.identifier == 'solved')\n            kwargs[\"can_delete\"] = not_workflow or (not is_report) or report_is_closed\n        return kwargs\n\n\nclass InterventionDelete(MapEntityDelete):\n    model = Intervention\n\n    @same_structure_required('maintenance:intervention_detail')\n    def dispatch(self, *args, **kwargs):\n        return super().dispatch(*args, **kwargs)\n\n\nclass InterventionViewSet(GeotrekMapentityViewSet):\n    model = Intervention\n    serializer_class = InterventionSerializer\n    geojson_serializer_class = InterventionGeojsonSerializer\n    filterset_class = InterventionFilterSet\n    mapentity_list_class = InterventionList\n\n    def get_queryset(self):\n        qs = self.model.objects.existing()\n        if self.format_kwarg == 'geojson':\n            qs = qs.only('id', 'name')\n        else:\n            qs = qs.select_related(\"stake\", \"status\", \"type\", \"target_type\").prefetch_related('target')\n        return qs\n\n\nclass ProjectList(CustomColumnsMixin, MapEntityList):\n    queryset = Project.objects.existing()\n    filterform = ProjectFilterSet\n    mandatory_columns = ['id', 'name']\n    default_extra_columns = ['period', 'type', 'domain']\n    searchable_columns = ['id', 'name']\n    unorderable_columns = ['period', ]\n\n\nclass ProjectFormatList(MapEntityFormat, ProjectList):\n    mandatory_columns = ['id']\n    default_extra_columns = [\n        'structure', 'name', 'period', 'type', 'domain', 'constraint', 'global_cost',\n        'interventions', 'interventions_total_cost', 'comments', 'contractors',\n        'project_owner', 'project_manager', 'founders',\n        'date_insert', 'date_update',\n        'cities', 'districts', 'areas',\n    ]\n\n\nclass ProjectDetail(MapEntityDetail):\n    queryset = Project.objects.existing()\n\n    def get_context_data(self, *args, **kwargs):\n        context = super().get_context_data(*args, **kwargs)\n        context['can_edit'] = self.get_object().same_structure(self.request.user)\n        context['empty_map_message'] = _(\"No intervention related.\")\n        return context\n\n\nclass ProjectDocument(MapEntityDocument):\n    model = Project\n\n\nclass FundingFormsetMixin(FormsetMixin):\n    context_name = 'funding_formset'\n    formset_class = FundingFormSet\n\n\nclass ProjectCreate(FundingFormsetMixin, MapEntityCreate):\n    model = Project\n    form_class = ProjectForm\n\n\nclass ProjectUpdate(FundingFormsetMixin, MapEntityUpdate):\n    queryset = Project.objects.existing()\n    form_class = ProjectForm\n\n    @same_structure_required('maintenance:project_detail')\n    def dispatch(self, *args, **kwargs):\n        return super().dispatch(*args, **kwargs)\n\n\nclass ProjectDelete(MapEntityDelete):\n    model = Project\n\n    @same_structure_required('maintenance:project_detail')\n    def dispatch(self, *args, **kwargs):\n        return super().dispatch(*args, **kwargs)\n\n\nclass ProjectViewSet(GeotrekMapentityViewSet):\n    model = Project\n    serializer_class = ProjectSerializer\n    geojson_serializer_class = ProjectGeojsonSerializer\n    filterset_class = ProjectFilterSet\n    mapentity_list_class = ProjectList\n\n    def get_queryset(self):\n        qs = self.model.objects.existing()\n        if self.format_kwarg == 'geojson':\n            non_empty_qs = Intervention.objects.existing().filter(project__isnull=False).values('project')\n            qs = qs.filter(pk__in=non_empty_qs)\n            qs = qs.only('id', 'name')\n        return qs\n", "path": "geotrek/maintenance/views.py"}], "after_files": [{"content": "import logging\nimport re\n\nfrom django.conf import settings\nfrom django.db.models import Subquery, OuterRef, Sum\nfrom django.db.models.expressions import Value\nfrom django.utils.translation import gettext_lazy as _\nfrom mapentity.views import (MapEntityList, MapEntityFormat, MapEntityDetail, MapEntityDocument,\n                             MapEntityCreate, MapEntityUpdate, MapEntityDelete)\n\nfrom geotrek.altimetry.models import AltimetryMixin\nfrom geotrek.authent.decorators import same_structure_required\nfrom geotrek.common.mixins.forms import FormsetMixin\nfrom geotrek.common.mixins.views import CustomColumnsMixin\nfrom geotrek.common.viewsets import GeotrekMapentityViewSet\nfrom .filters import InterventionFilterSet, ProjectFilterSet\nfrom .forms import (InterventionForm, ProjectForm,\n                    FundingFormSet, ManDayFormSet)\nfrom .models import Intervention, Project, ManDay\nfrom .serializers import (InterventionSerializer, ProjectSerializer,\n                          InterventionGeojsonSerializer, ProjectGeojsonSerializer)\n\nlogger = logging.getLogger(__name__)\n\n\nANNOTATION_FORBIDDEN_CHARS = re.compile(r\"['`\\\"\\]\\[;\\s]|--|/\\*|\\*/\")\nREPLACEMENT_CHAR = \"_\"\n\n\ndef _normalize_annotation_column_name(col_name):\n    return ANNOTATION_FORBIDDEN_CHARS.sub(repl=REPLACEMENT_CHAR, string=col_name)\n\n\nclass InterventionList(CustomColumnsMixin, MapEntityList):\n    queryset = Intervention.objects.existing()\n    filterform = InterventionFilterSet\n    mandatory_columns = ['id', 'name']\n    default_extra_columns = ['date', 'type', 'target', 'status', 'stake']\n    searchable_columns = ['id', 'name']\n    unorderable_columns = ['target']\n\n\nclass InterventionFormatList(MapEntityFormat, InterventionList):\n\n    @classmethod\n    def build_cost_column_name(cls, job_name):\n        return _normalize_annotation_column_name(f\"{_('Cost')} {job_name}\")\n\n    def get_queryset(self):\n        \"\"\"Returns all interventions joined with a new column for each job, to record the total cost of each job in each intervention\"\"\"\n\n        queryset = super().get_queryset()\n\n        if settings.ENABLE_JOBS_COSTS_DETAILED_EXPORT:\n\n            # Get all jobs that are used in interventions, as unique names, ids and costs\n            all_mandays = ManDay.objects.all()\n            jobs_used_in_interventions = list(\n                set(all_mandays.values_list(\"job__job\", \"job_id\", \"job__cost\"))\n            )\n\n            # Iter over unique jobs\n            for job_name, job_id, job_cost in jobs_used_in_interventions:\n\n                # Create column name for current job cost\n                column_name = self.build_cost_column_name(job_name)\n\n                # Create subquery to retrieve total cost of mandays for a given intervention and a given job\n                mandays_query = (\n                    ManDay.objects.filter(intervention=OuterRef(\"pk\"), job_id=job_id)  # Extract all mandays for a given intervention and a given job\n                    .values(\"job_id\")  # Group by job\n                    .annotate(total_days=Sum(\"nb_days\"))  # Select number of days worked\n                    .values(\"total_days\")  # Rename result as total_days\n                )\n\n                # Use total_days and job cost to calculate total cost for a given intervention and a given job\n                job_cost_query = Subquery(mandays_query) * Value(job_cost)\n\n                # Annotate queryset with this cost query\n                params = {column_name: job_cost_query}\n                queryset = queryset.annotate(**params)\n        return queryset\n\n    @classmethod\n    def get_mandatory_columns(cls):\n        mandatory_columns = ['id']\n        if settings.ENABLE_JOBS_COSTS_DETAILED_EXPORT:\n            all_mandays = ManDay.objects.all()  # Used to find all jobs that ARE USED in interventions\n            # Get all jobs that are used in interventions, as unique names\n            jobs_as_names = list(\n                set(all_mandays.values_list(\"job__job\", flat=True))\n            )\n            # Create column names for each unique job cost\n            cost_column_names = list(map(cls.build_cost_column_name, jobs_as_names))\n            # Add these column names to export\n            mandatory_columns = mandatory_columns + cost_column_names\n        return mandatory_columns\n\n    default_extra_columns = [\n        'name', 'date', 'type', 'target', 'status', 'stake',\n        'disorders', 'total_manday', 'project', 'subcontracting',\n        'width', 'height', 'area', 'structure',\n        'description', 'date_insert', 'date_update',\n        'material_cost', 'heliport_cost', 'subcontract_cost',\n        'total_cost_mandays', 'total_cost',\n        'cities', 'districts', 'areas',\n    ] + AltimetryMixin.COLUMNS\n\n\nclass InterventionDetail(MapEntityDetail):\n    queryset = Intervention.objects.existing()\n\n    def get_context_data(self, *args, **kwargs):\n        context = super().get_context_data(*args, **kwargs)\n        context['can_edit'] = self.get_object().same_structure(self.request.user)\n        return context\n\n\nclass InterventionDocument(MapEntityDocument):\n    model = Intervention\n\n\nclass ManDayFormsetMixin(FormsetMixin):\n    context_name = 'manday_formset'\n    formset_class = ManDayFormSet\n\n\nclass InterventionCreate(ManDayFormsetMixin, MapEntityCreate):\n    model = Intervention\n    form_class = InterventionForm\n\n    def get_form_kwargs(self):\n        kwargs = super().get_form_kwargs()\n        if 'target_id' in self.request.GET and 'target_type' in self.request.GET:\n            # Create intervention on an existing infrastructure\n            kwargs['target_id'] = self.request.GET['target_id']\n            kwargs['target_type'] = self.request.GET['target_type']\n        return kwargs\n\n\nclass InterventionUpdate(ManDayFormsetMixin, MapEntityUpdate):\n    queryset = Intervention.objects.existing()\n    form_class = InterventionForm\n\n    @same_structure_required('maintenance:intervention_detail')\n    def dispatch(self, *args, **kwargs):\n        return super().dispatch(*args, **kwargs)\n\n    def get_form_kwargs(self):\n        kwargs = super().get_form_kwargs()\n        # If deletion is allowed\n        if kwargs['can_delete']:\n            intervention = self.get_object()\n            # Disallow deletion if this intervention is part of Suricate Workflow at the moment\n            not_workflow = not settings.SURICATE_WORKFLOW_ENABLED\n            is_report = intervention.target and intervention.target.__class__.__name__ == \"Report\"\n            report_is_closed = False\n            if is_report:\n                report_is_closed = (intervention.target.status.identifier == 'solved')\n            kwargs[\"can_delete\"] = not_workflow or (not is_report) or report_is_closed\n        return kwargs\n\n\nclass InterventionDelete(MapEntityDelete):\n    model = Intervention\n\n    @same_structure_required('maintenance:intervention_detail')\n    def dispatch(self, *args, **kwargs):\n        return super().dispatch(*args, **kwargs)\n\n\nclass InterventionViewSet(GeotrekMapentityViewSet):\n    model = Intervention\n    serializer_class = InterventionSerializer\n    geojson_serializer_class = InterventionGeojsonSerializer\n    filterset_class = InterventionFilterSet\n    mapentity_list_class = InterventionList\n\n    def get_queryset(self):\n        qs = self.model.objects.existing()\n        if self.format_kwarg == 'geojson':\n            qs = qs.only('id', 'name')\n        else:\n            qs = qs.select_related(\"stake\", \"status\", \"type\", \"target_type\").prefetch_related('target')\n        return qs\n\n\nclass ProjectList(CustomColumnsMixin, MapEntityList):\n    queryset = Project.objects.existing()\n    filterform = ProjectFilterSet\n    mandatory_columns = ['id', 'name']\n    default_extra_columns = ['period', 'type', 'domain']\n    searchable_columns = ['id', 'name']\n    unorderable_columns = ['period', ]\n\n\nclass ProjectFormatList(MapEntityFormat, ProjectList):\n    mandatory_columns = ['id']\n    default_extra_columns = [\n        'structure', 'name', 'period', 'type', 'domain', 'constraint', 'global_cost',\n        'interventions', 'interventions_total_cost', 'comments', 'contractors',\n        'project_owner', 'project_manager', 'founders',\n        'date_insert', 'date_update',\n        'cities', 'districts', 'areas',\n    ]\n\n\nclass ProjectDetail(MapEntityDetail):\n    queryset = Project.objects.existing()\n\n    def get_context_data(self, *args, **kwargs):\n        context = super().get_context_data(*args, **kwargs)\n        context['can_edit'] = self.get_object().same_structure(self.request.user)\n        context['empty_map_message'] = _(\"No intervention related.\")\n        return context\n\n\nclass ProjectDocument(MapEntityDocument):\n    model = Project\n\n\nclass FundingFormsetMixin(FormsetMixin):\n    context_name = 'funding_formset'\n    formset_class = FundingFormSet\n\n\nclass ProjectCreate(FundingFormsetMixin, MapEntityCreate):\n    model = Project\n    form_class = ProjectForm\n\n\nclass ProjectUpdate(FundingFormsetMixin, MapEntityUpdate):\n    queryset = Project.objects.existing()\n    form_class = ProjectForm\n\n    @same_structure_required('maintenance:project_detail')\n    def dispatch(self, *args, **kwargs):\n        return super().dispatch(*args, **kwargs)\n\n\nclass ProjectDelete(MapEntityDelete):\n    model = Project\n\n    @same_structure_required('maintenance:project_detail')\n    def dispatch(self, *args, **kwargs):\n        return super().dispatch(*args, **kwargs)\n\n\nclass ProjectViewSet(GeotrekMapentityViewSet):\n    model = Project\n    serializer_class = ProjectSerializer\n    geojson_serializer_class = ProjectGeojsonSerializer\n    filterset_class = ProjectFilterSet\n    mapentity_list_class = ProjectList\n\n    def get_queryset(self):\n        qs = self.model.objects.existing()\n        if self.format_kwarg == 'geojson':\n            non_empty_qs = Intervention.objects.existing().filter(project__isnull=False).values('project')\n            qs = qs.filter(pk__in=non_empty_qs)\n            qs = qs.only('id', 'name')\n        return qs\n", "path": "geotrek/maintenance/views.py"}]}