from datetime import datetime from dateutil.relativedelta import relativedelta from django import forms from django.utils.translation import gettext_lazy as _ from .models import RoadAuthorization, RoadAuthorizationDocument, RoadAuthorizationDate # Default initial datetime for occupation dates: next month _DEFAULT_DATE = lambda: (datetime.today() + relativedelta(months=1)).strftime('%Y-%m-%d') class AuthorizationForm(forms.ModelForm): """Main authorization request form – no crispy forms dependency.""" class Meta: model = RoadAuthorization fields = ( 'language', 'type', 'description', 'location', 'applicant_name', 'applicant_email', 'applicant_address', 'applicant_enterprise', ) widgets = { 'type': forms.RadioSelect(attrs={'class': 'btn-check', 'autocomplete': 'off'}), 'language': forms.RadioSelect(attrs={'class': 'btn-check', 'autocomplete': 'off'}), } # Hidden field that receives the GeoJSON polygon drawn on the MapLibre map. # The view converts it to a MultiPolygonField before saving. geom_geojson = forms.CharField( widget=forms.HiddenInput(), required=True, label='', ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Remove the blank "-------" choice Django injects when there is no default value self.fields['type'].choices = [ (k, v) for k, v in self.fields['type'].choices if k != '' ] self.fields['language'].choices = [ (k, v) for k, v in self.fields['language'].choices if k != '' ] self.fields['description'].widget.attrs.update({'class': 'form-control', 'rows': 5}) self.fields['location'].widget.attrs.update({'class': 'form-control'}) self.fields['applicant_name'].widget.attrs.update({'class': 'form-control'}) self.fields['applicant_email'].widget.attrs.update({'class': 'form-control'}) self.fields['applicant_address'].widget.attrs.update({'class': 'form-control'}) self.fields['applicant_enterprise'].widget.attrs.update({'class': 'form-control'}) def clean_geom_geojson(self): """Validate that the submitted GeoJSON is a valid polygon.""" import json value = self.cleaned_data.get('geom_geojson', '').strip() if not value: raise forms.ValidationError(_("Veuillez dessiner la zone concernée sur la carte.")) try: geom = json.loads(value) except (ValueError, TypeError): raise forms.ValidationError(_("Géométrie invalide.")) if geom.get('type') not in ('Polygon', 'MultiPolygon'): raise forms.ValidationError(_("Veuillez dessiner un polygone.")) return value class AuthorizationDocumentForm(forms.ModelForm): class Meta: model = RoadAuthorizationDocument fields = ('description', 'file') widgets = { 'description': forms.TextInput(attrs={'class': 'form-control', 'placeholder': _('Description du document')}), 'file': forms.ClearableFileInput(attrs={'class': 'form-control'}), } AuthorizationDocumentFormSet = forms.inlineformset_factory( RoadAuthorization, RoadAuthorizationDocument, form=AuthorizationDocumentForm, extra=1, can_delete=False, ) class AuthorizationDateForm(forms.ModelForm): class Meta: model = RoadAuthorizationDate fields = ('begin_date', 'end_date') widgets = { 'begin_date': forms.DateTimeInput( attrs={ 'type': 'datetime-local', 'class': 'form-control', } ), 'end_date': forms.DateTimeInput( attrs={ 'type': 'datetime-local', 'class': 'form-control', } ), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['end_date'].required = False AuthorizationDateFormSet = forms.inlineformset_factory( RoadAuthorization, RoadAuthorizationDate, form=AuthorizationDateForm, extra=1, can_delete=False, ) class AuthorizationFilterForm(forms.Form): """Filter form used on the staff list view.""" include_archives = forms.BooleanField( label=_("Inclure les archives (> 2 ans)"), required=False, widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}), ) authorization_type = forms.MultipleChoiceField( label=_("Type d'autorisation"), choices=RoadAuthorization.AUTH_TYPE, widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-check-input'}), required=False, ) search_text = forms.CharField( max_length=250, required=False, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': _('Recherche…')}), )