Skip to content

Commit

Permalink
an activity can have several perimeters
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastienReuiller committed Oct 15, 2024
1 parent ca689af commit ed2fe1b
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 37 deletions.
7 changes: 7 additions & 0 deletions lemarche/siaes/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
GEO_RANGE_REGION = "REGION"
GEO_RANGE_CUSTOM = "CUSTOM"
GEO_RANGE_COUNTRY = "COUNTRY"
GEO_RANGE_ZONES = "ZONES"

GEO_RANGE_CHOICES = (
(GEO_RANGE_COUNTRY, "France entière"),
Expand All @@ -88,6 +89,12 @@
(GEO_RANGE_CUSTOM, "Distance en kilomètres"),
)

ACTIVITIES_GEO_RANGE_CHOICES = (
(GEO_RANGE_COUNTRY, "France entière"),
(GEO_RANGE_CUSTOM, "Distance en kilomètres"),
(GEO_RANGE_ZONES, "Zone(s) d'intervention personnalisée(s)"),
)

SOURCE_ASP = "ASP"
SOURCE_GEIQ = "GEIQ"
SOURCE_EA_EATT = "EA_EATT"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Django 4.2.15 on 2024-10-07 14:03

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("perimeters", "0005_alter_perimeter_post_codes"),
("siaes", "0076_siaeactivity"),
]

operations = [
migrations.RemoveField(
model_name="siaeactivity",
name="location",
),
migrations.AddField(
model_name="siaeactivity",
name="locations",
field=models.ManyToManyField(
blank=True, related_name="siae_activities", to="perimeters.perimeter", verbose_name="Localisations"
),
),
migrations.AlterField(
model_name="siaeactivity",
name="geo_range",
field=models.CharField(
blank=True,
choices=[
("COUNTRY", "France entière"),
("CUSTOM", "Distance en kilomètres"),
("ZONES", "Zone(s) d'intervention personnalisée(s)"),
],
db_index=True,
max_length=20,
verbose_name="Périmètre d'intervention",
),
),
]
33 changes: 6 additions & 27 deletions lemarche/siaes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1428,25 +1428,19 @@ class SiaeActivity(models.Model):
null=True,
db_index=True,
)
location: Perimeter = models.ForeignKey(
to="perimeters.Perimeter",
verbose_name="Localisation",
related_name="siae_activities",
on_delete=models.DO_NOTHING,
blank=True,
null=True,
locations = models.ManyToManyField(
"perimeters.Perimeter", verbose_name="Localisations", related_name="siae_activities", blank=True
)
geo_range = models.CharField(
verbose_name="Périmètre d'intervention",
max_length=20,
choices=siae_constants.GEO_RANGE_CHOICES,
choices=siae_constants.ACTIVITIES_GEO_RANGE_CHOICES,
blank=True,
db_index=True,
)
geo_range_custom_distance = models.IntegerField(
verbose_name="Distance en kilomètres (périmètre d'intervention)", blank=True, null=True
)

created_at = models.DateTimeField(verbose_name="Date de création", default=timezone.now)
updated_at = models.DateTimeField(verbose_name="Date de modification", auto_now=True)

Expand All @@ -1463,28 +1457,13 @@ def presta_type_display(self) -> str:
def geo_range_pretty_display(self):
if self.geo_range == siae_constants.GEO_RANGE_COUNTRY:
return self.get_geo_range_display()
elif self.geo_range == siae_constants.GEO_RANGE_REGION:
return f"{self.get_geo_range_display().lower()} ({self.siae.region})"
elif self.geo_range == siae_constants.GEO_RANGE_DEPARTMENT:
return f"{self.get_geo_range_display().lower()} ({self.siae.department})"
elif self.geo_range == siae_constants.GEO_RANGE_ZONES:
return f"{self.get_geo_range_display()} : {', '.join(self.locations.values_list('name', flat=True))}"
elif self.geo_range == siae_constants.GEO_RANGE_CUSTOM:
if self.geo_range_custom_distance:
return f"{self.geo_range_custom_distance} km"
return f"{self.geo_range_custom_distance} km de {self.siae.city}"
return "non disponible"

@property
def geo_range_pretty_title(self):
if self.geo_range == siae_constants.GEO_RANGE_COUNTRY:
return self.geo_range_pretty_display
elif self.geo_range == siae_constants.GEO_RANGE_REGION:
return self.siae.region
elif self.geo_range == siae_constants.GEO_RANGE_DEPARTMENT:
return self.siae.get_department_display()
elif self.geo_range == siae_constants.GEO_RANGE_CUSTOM:
if self.geo_range_custom_distance:
return f"{self.geo_range_pretty_display} de {self.siae.city}"
return self.geo_range_pretty_display


class SiaeOffer(models.Model):
name = models.CharField(verbose_name="Nom", max_length=255)
Expand Down
63 changes: 58 additions & 5 deletions lemarche/templates/dashboard/siae_edit_activities_create.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<div class="fr-container">
<div class="fr-grid-row">
<div class="fr-col-12">
<form method="POST" action="">
<form method="post" action="">
{% csrf_token %}
{% if form.non_field_errors %}
<section class="fr-my-4v fr-input-group fr-input-group--error">
Expand Down Expand Up @@ -54,7 +54,11 @@ <h3 class="fr-callout__title fr-text--sm">
<div class="fr-grid-row fr-grid-row--gutters">
<div class="fr-col-12 fr-col-lg-8">
{% dsfr_form_field form.geo_range %}
{% dsfr_form_field form.geo_range_custom_distance %}
<div id="geo_range_custom_distance_wrapper">{% dsfr_form_field form.geo_range_custom_distance %}</div>
<div id="geo_range_locations_wrapper" class="fr-input-group">
{{ form.locations }}
{{ current_locations|json_script:"current-locations" }}
</div>
</div>
<div class="fr-col-12 fr-col-lg-4">
<div class="fr-callout fr-p-4v">
Expand All @@ -67,7 +71,7 @@ <h3 class="fr-callout__title fr-text--sm">
</div>
</div>
</div>
<div class="fr-grid-row fr-grid-row--gutters fr-mt-3v fr-mt-lg-5v">
<div class="fr-grid-row fr-grid-row--gutters fr-my-3v fr-my-lg-5v">
<div class="fr-col-12 fr-col-lg-8">
<ul class="fr-mt-2v fr-btns-group fr-btns-group--right fr-btns-group--inline-reverse fr-btns-group--inline-sm fr-btns-group--icon-left">
<li>
Expand All @@ -89,10 +93,11 @@ <h3 class="fr-callout__title fr-text--sm">
{% endblock content %}
{% block extra_js %}
<script type="text/javascript"
src="{% static 'js/siae_geo_range_field.js' %}"></script>
src="{% static 'js/perimeter_autocomplete_field.js' %}"></script>
<script type="text/javascript">
// dynamic sector display based on sector group selection
document.addEventListener('DOMContentLoaded', function() {
// -------------------------------------------------------------------
// dynamic sector display based on sector group selection
let sectorGroupSelect = document.getElementById('id_sector_group');
let sectorGroupSelectOptions = sectorGroupSelect.children;
let sectorRadios = document.querySelectorAll('#checkboxes-id_sectors input[type="checkbox"][name="sectors"]');
Expand Down Expand Up @@ -135,6 +140,54 @@ <h3 class="fr-callout__title fr-text--sm">
showSectorsOfSelectedSectorGroup(event.target.value);
}
})
// -------------------------------------------------------------------


// -------------------------------------------------------------------
// init locations autocomplete form fields
const LOCATION_AUTOCOMPLETE_ID = 'id_locations';
const LOCATION_AUTOCOMPLETE_CONTAINER_SELECTOR = '#dir_form_locations';
const LOCATION_SELECTED_CONTAINER_SELECTOR = '#locations-selected';
const LOCATION_HIDDEN_INPUT_SELECTOR_PREFIX = 'hiddenLocation';
const LOCATION_CURRENT_ID = 'current-locations';
const locationsAutoComplete = new PerimetersMultiAutocomplete(LOCATION_AUTOCOMPLETE_ID, LOCATION_AUTOCOMPLETE_CONTAINER_SELECTOR, LOCATION_SELECTED_CONTAINER_SELECTOR, LOCATION_HIDDEN_INPUT_SELECTOR_PREFIX, LOCATION_CURRENT_ID);
locationsAutoComplete.init();
// -------------------------------------------------------------------


// -------------------------------------------------------------------
// geo range custom distance input
let geoRangeCustomDistanceInput = document.getElementById('id_geo_range_custom_distance');
let geoRangeCustomDistanceInputGroup = document.getElementById('geo_range_custom_distance_wrapper');
let geoRangeLocationsInputGroup = document.getElementById('geo_range_locations_wrapper');

function toggleGeoRangeFieldsAccordingToRadio(value) {
geoRangeLocationsInputGroup.style.display = 'none';
geoRangeCustomDistanceInputGroup.style.display = 'none';
geoRangeCustomDistanceInput.disabled = true;

if (value === 'CUSTOM') {
geoRangeCustomDistanceInput.disabled = false;
geoRangeCustomDistanceInputGroup.style.display = 'block';
} else if (value === 'ZONES') {
geoRangeLocationsInputGroup.style.display = 'block';
}
}

let geoRangeRadios = document.querySelectorAll('input[type=radio][name="geo_range"]');
// init
geoRangeLocationsInputGroup.style.display = 'none';
geoRangeCustomDistanceInputGroup.style.display = 'none';
geoRangeRadios.forEach(radio => {
if (radio.checked) {
toggleGeoRangeFieldsAccordingToRadio(radio.value);
}
});
// on change
geoRangeRadios.forEach(radio => radio.addEventListener('change', () => {
toggleGeoRangeFieldsAccordingToRadio(radio.value);
}));
// -------------------------------------------------------------------
});
</script>
{% endblock extra_js %}
2 changes: 0 additions & 2 deletions lemarche/templates/siaes/_siae_activity_card.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ <h4>{{ activity.sector_group }}</h4>
</p>
<p>
<span class="fr-icon-map-pin-2-line" aria-hidden="true"></span>
<span class="fr-sr-only">Intervient sur :</span>{{ activity.geo_range_pretty_title }}
<span class="fr-icon-road-map-line fr-ml-2w" aria-hidden="true"></span>
<span>{{ activity.geo_range_pretty_display }}</span>
</p>
</div>
Expand Down
42 changes: 39 additions & 3 deletions lemarche/www/dashboard_siaes/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dsfr.forms import DsfrBaseForm

from lemarche.networks.models import Network
from lemarche.perimeters.models import Perimeter
from lemarche.sectors.models import Sector
from lemarche.siaes import constants as siae_constants
from lemarche.siaes.models import (
Expand All @@ -18,6 +19,7 @@
SiaeUserRequest,
)
from lemarche.utils.fields import GroupedModelMultipleChoiceField
from lemarche.www.siaes.widgets import CustomLocationWidget


class SiaeSearchBySiretForm(forms.Form):
Expand Down Expand Up @@ -266,15 +268,36 @@ class SiaeActivitiesCreateForm(forms.ModelForm):
widget=forms.CheckboxSelectMultiple,
)
geo_range = forms.ChoiceField(
label=Siae._meta.get_field("geo_range").verbose_name,
choices=siae_constants.GEO_RANGE_CHOICES,
label=SiaeActivity._meta.get_field("geo_range").verbose_name,
choices=siae_constants.ACTIVITIES_GEO_RANGE_CHOICES,
initial=siae_constants.GEO_RANGE_COUNTRY,
required=True,
widget=forms.RadioSelect,
)
geo_range_custom_distance = forms.IntegerField(
label="",
required=False,
help_text="Distance mesurée depuis le point central de la ville où se situe votre structure.",
)
locations = forms.ModelMultipleChoiceField(
label="Localisation",
queryset=Perimeter.objects.all(),
to_field_name="slug",
required=False,
widget=CustomLocationWidget( # displayed with a JS autocomplete library (see `perimeter_autocomplete_field.js`) # noqa
attrs={
"placeholder": "Région, département, ville",
}
),
help_text="Vous pouvez ajouter autant de régions, de départements ou de villes que vous le souhaitez.",
# FIXME: help_text not displayed
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# these fields are autocompletes
self.fields["locations"].choices = []

def clean(self):
cleaned_data = super().clean()
Expand All @@ -284,8 +307,21 @@ def clean(self):
if geo_range == siae_constants.GEO_RANGE_CUSTOM and not geo_range_custom_distance:
self.add_error("geo_range_custom_distance", "Une distance en kilomètres est requise pour cette option.")

# TODO: check if locations are set if geo_range is set to ZONES
return cleaned_data

def save(self, *args, **kwargs):
if self.instance.pk and self.cleaned_data.get("geo_range") is not siae_constants.GEO_RANGE_ZONES:
self.instance.locations.clear()
return super().save(*args, **kwargs)

class Meta:
model = SiaeActivity
fields = ["sector_group", "sectors", "presta_type", "geo_range", "geo_range_custom_distance"] # location
fields = [
"sector_group",
"sectors",
"presta_type",
"geo_range",
"geo_range_custom_distance",
"locations",
]
1 change: 1 addition & 0 deletions lemarche/www/dashboard_siaes/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def get_context_data(self, **kwargs):
context["page_title"] = "Modifier une activité"
context["siae"] = self.siae
context["activity"] = self.object
context["current_locations"] = list(self.object.locations.values("id", "slug", "name"))
context["breadcrumb_data"] = {
"root_dir": settings_context_processors.expose_settings(self.request)["HOME_PAGE_PATH"],
"links": [
Expand Down

0 comments on commit ed2fe1b

Please sign in to comment.