Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Activités des structures): Ajout du choix du périmètre d'intervention aux niveaux des activités #1457

Merged
merged 6 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lemarche/siaes/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ class SiaeActivityAdmin(admin.ModelAdmin):
search_fields = ["id", "siae__id", "siae__name"]
search_help_text = "Cherche sur les champs : ID, Structure (ID, Nom)"

autocomplete_fields = ["siae", "sectors", "location"]
autocomplete_fields = ["siae", "sectors", "locations"]
readonly_fields = ["created_at", "updated_at"]

fieldsets = (
Expand All @@ -759,7 +759,7 @@ class SiaeActivityAdmin(admin.ModelAdmin):
(
"Localisation et périmètre d'intervention",
{
"fields": ("location", "geo_range", "geo_range_custom_distance"),
"fields": ("locations", "geo_range", "geo_range_custom_distance"),
},
),
("Dates", {"fields": ("created_at", "updated_at")}),
Expand Down
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
18 changes: 17 additions & 1 deletion lemarche/siaes/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import factory.fuzzy
from factory.django import DjangoModelFactory

from lemarche.sectors.factories import SectorGroupFactory
from lemarche.siaes import constants as siae_constants
from lemarche.siaes.models import (
Siae,
Expand Down Expand Up @@ -69,13 +70,28 @@ class SiaeActivityFactory(DjangoModelFactory):
class Meta:
model = SiaeActivity

presta_type = factory.List([factory.fuzzy.FuzzyChoice([key for (key, value) in siae_constants.PRESTA_CHOICES])])
class Params:
with_country_perimeter = factory.Trait(geo_range=siae_constants.GEO_RANGE_COUNTRY)
with_custom_distance_perimeter = factory.Trait(
geo_range=siae_constants.GEO_RANGE_CUSTOM,
geo_range_custom_distance=factory.fuzzy.FuzzyInteger(1, 100),
)
with_zones_perimeter = factory.Trait(geo_range=siae_constants.GEO_RANGE_ZONES)

sector_group = factory.SubFactory(SectorGroupFactory)

presta_type = factory.List([factory.fuzzy.FuzzyChoice([key for (key, _) in siae_constants.PRESTA_CHOICES])])

@factory.post_generation
def sectors(self, create, extracted, **kwargs):
if extracted:
self.sectors.add(*extracted)

@factory.post_generation
def locations(self, create, extracted, **kwargs):
if extracted:
self.locations.add(*extracted)


class SiaeOfferFactory(DjangoModelFactory):
class Meta:
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
13 changes: 3 additions & 10 deletions lemarche/static/js/siae_activity_delete.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
document.addEventListener('alpine:init', function () {
Alpine.data('activityItem', () => ({
siaeSlug: null,
siaeActivityId: null,
siaeActivityNameDisplay: null,

initOptions(siaeSlug, siaeActivityId, siaeActivityNameDisplay) {
this.siaeSlug = siaeSlug;
initOptions(siaeActivityId, siaeActivityNameDisplay) {
this.siaeActivityId = siaeActivityId;
this.siaeActivityNameDisplay = siaeActivityNameDisplay;
},
Expand All @@ -20,13 +18,8 @@ document.addEventListener('alpine:init', function () {
if (modal.querySelector('#siae-activity-name-display')) {
modal.querySelector('#siae-activity-name-display').textContent = this.siaeActivityNameDisplay;
}

let formActionUrl = new URL(modalForm.getAttribute('data-action'));
formActionUrl.pathname = formActionUrl.pathname
.replace('siae-slug-to-replace', encodeURIComponent(this.siaeSlug))
.replace('siae-activity-id-to-replace', encodeURIComponent(this.siaeActivityId));

modalForm.setAttribute('action', formActionUrl.toString());
let formActionUrl = escapeHtml(modalForm.getAttribute('data-action'));
modalForm.setAttribute('action', formActionUrl.replace('siae-activity-id-to-replace', this.siaeActivityId.replace(/\D/g, '')));

const modalDialog = document.getElementById(modalID);
dsfr(modalDialog).modal.disclose();
Expand Down
22 changes: 9 additions & 13 deletions lemarche/static/js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ window.addEventListener('DOMContentLoaded', function () {
initSuperBadges();

// some elements have their url in data-url attribute
$(document).on("click", ".with-data-url", function(e) {
$(document).on("click", ".with-data-url", function (e) {
window.location.href = $(this).data("url");
});
});
Expand Down Expand Up @@ -57,13 +57,6 @@ let toggleInputElement = (toggle, element, required = undefined) => {
}
}

const initModalMessages = () => {
var elements = document.getElementsByClassName('modal-message-alert');
for (var i = 0; i < elements.length; i++) {
OpenBootstrapModal(elements[i]);
}
}

const initSuperBadges = () => {
$('.super-badge-badge').each(function (element) {
$(this).tooltip(
Expand Down Expand Up @@ -103,8 +96,11 @@ const initSuperBadges = () => {
})
}

function OpenBootstrapModal(elmt) {
setTimeout(function () {
$(elmt).modal('show');
}, 1000);
}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ <h3 id="siae_activity_delete_modal_title" class="fr-modal__title">Supprimer</h3>
<div class="fr-modal__footer">
<div class="fr-btns-group fr-btns-group--right fr-btns-group--inline-reverse fr-btns-group--inline-lg">
<form method="post"
data-action="{% url 'dashboard_siaes:siae_edit_activities_delete' siae.slug|default:'siae-slug-to-replace' activity.id|default:'siae-activity-id-to-replace' %}">
data-action="{% url 'dashboard_siaes:siae_edit_activities_delete' siae.slug 'siae-activity-id-to-replace' %}">
{% csrf_token %}
<button class="fr-btn fr-btn--icon-left" type="submit">Confirmer</button>
</form>
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 %}
4 changes: 1 addition & 3 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 All @@ -32,7 +30,7 @@ <h4>{{ activity.sector_group }}</h4>
<button id="siae-activity-delete-modal-btn"
class="fr-btn fr-btn--sm fr-btn--tertiary-no-outline fr-icon-delete-line"
x-data="activityItem"
x-init="initOptions('{{ activity.siae.slug }}','{{ activity.id }}','{{ activity.sector_group|escapejs }}')"
x-init="initOptions('{{ activity.id }}','{{ activity.sector_group|escapejs }}')"
@click="remove"
title="Supprimer l'activité">
<i class="ri-delete-bin-line ri-xl"></i>
Expand Down
Loading
Loading