#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014-2016 Étienne Loks # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # See the file COPYING for details. import datetime from django import forms from django.core import validators from django.utils.functional import lazy from django.utils.safestring import mark_safe from ishtar_common.utils import ugettext_lazy as _ from ishtar_common.models import ( Person, Town, valid_id, person_type_pk_lazy, person_type_pks_lazy, organization_type_pks_lazy, organization_type_pk_lazy, get_sra_agent_label, get_orga_general_contractor_label, get_general_contractor_label, get_orga_planning_service_label, get_responsible_planning_service_label, ) from ishtar_common.models_common import Department from archaeological_files import models from ishtar_common.forms import ( get_now, reverse_lazy, ManageOldType, CustomForm, FieldType, IshtarForm, FormHeader, ) from ishtar_common import widgets from bootstrap_datepicker.widgets import DatePicker class FileFormGeneral(CustomForm, ManageOldType): form_label = _("General") form_admin_name = _("Archaeological file - 010 - General") form_slug = "file-010-general" associated_models = {"file_type": models.FileType} file_type = forms.ChoiceField(label=_("File type"), choices=[]) year = forms.IntegerField( label=_("Year"), initial=lambda: datetime.datetime.now().year, validators=[ validators.MinValueValidator(1000), validators.MaxValueValidator(2100), ], ) creation_date = forms.DateField( label=_("Creation date"), initial=get_now, widget=DatePicker ) reception_date = forms.DateField( label=_("Reception date"), initial=get_now, widget=DatePicker ) TYPES = [ FieldType("file_type", models.FileType), ] def clean_reception_date(self): value = self.cleaned_data.get("reception_date", None) if value and value > datetime.date.today(): raise forms.ValidationError(_("Reception date cannot be after today.")) return value class FileFormPreventiveType(CustomForm, ManageOldType, forms.Form): form_label = "Saisine" form_admin_name = _("Archaeological file - 013 - Preventive - Saisine") form_slug = "file-013-preventivesaisine" associated_models = { "saisine_type": models.SaisineType, "permit_type": models.PermitType, } permit_type = forms.ChoiceField(label=_("Permit type"), required=False, choices=[]) saisine_type = forms.ChoiceField(label=_("Saisine type"), choices=[]) TYPES = [ FieldType("saisine_type", models.SaisineType), ] def __init__(self, *args, **kwargs): super(FileFormPreventiveType, self).__init__(*args, **kwargs) self.fields["permit_type"].choices = models.PermitType.get_types( default="NP", initial=self.init_data.get("permit_type") ) self.fields["permit_type"].help_text = models.PermitType.get_help() class FileFormPlanning(CustomForm, ManageOldType): form_label = _("Planning") form_admin_name = _("Archaeological file - 017 - Preventive - Planning") form_slug = "file-017-preventiveplanning" base_models = ["town", "department"] associated_models = {"town": Town, "department": Department} HEADERS = {} HEADERS["town"] = FormHeader(_("Localisation")) name = forms.CharField(label=_("Planning name"), required=False, max_length=100) town = widgets.Select2MultipleField( model=Town, label=_("Towns"), required=False, remote=True ) department = widgets.Select2MultipleField( model=Department, label=_("Departments"), required=False, help_text=_("Only relevant when no town is provided."), ) locality = forms.CharField(label=_("Locality"), max_length=100, required=False) address = forms.CharField( label=_("Address (number/street)"), widget=forms.Textarea(attrs={"placeholder": _("Number/street")}), required=False, ) postal_code = forms.CharField(label=_("Postal code"), max_length=10, required=False) HEADERS["total_surface"] = FormHeader(_("Surfaces")) total_surface = forms.FloatField( required=False, widget=widgets.AreaWidget, label=_("Total surface (m2)"), validators=[ validators.MinValueValidator(0), validators.MaxValueValidator(999999999), ], ) total_developed_surface = forms.FloatField( widget=widgets.AreaWidget, label=_("Total developed surface (m2)"), required=False, validators=[ validators.MinValueValidator(0), validators.MaxValueValidator(999999999), ], ) class FileFormResearchAddress(CustomForm, forms.Form): form_label = _("Address") form_admin_name = _("Archaeological file - 015 - Research - Address") form_slug = "file-015-researchplanning" base_models = ["town", "department"] associated_models = {"town": Town, "department": Department} name = forms.CharField(label=_("Project name"), required=False, max_length=100) town = widgets.Select2MultipleField( model=Town, label=_("Towns"), required=False, remote=True ) department = widgets.Select2MultipleField( model=Department, label=_("Departments"), required=False ) locality = forms.CharField(label=_("Locality"), max_length=100, required=False) address = forms.CharField( label=_("Address (number/street)"), widget=forms.Textarea(attrs={"placeholder": _("Number/street")}), required=False, ) postal_code = forms.CharField(label=_("Postal code"), max_length=10, required=False) class PersonOrgaForm(forms.Form): PERSON_FIELD = "TO BE DEFINED" PERSON_TYPE_PK = person_type_pk_lazy("general_contractor") PERSON_LABEL = "" ORGA_FIELD = "TO BE DEFINED" ORGA_TYPE_PK = organization_type_pk_lazy("general_contractor") ORGA_LABEL = "" def _media(self): if self.status == "corporation": return forms.Media(js=("js/JQueryCorporation.js",)) media = property(_media) def __init__(self, *args, **kwargs): # get the status: natural person or corporation DEFAULT_STATUS = "natural" current_status = "" if "data" in kwargs: # the order is important: PERSON can have an ORGA for field in [self.ORGA_FIELD, self.PERSON_FIELD]: current_item_key = ( (kwargs["prefix"] + "-") if kwargs.get("prefix") else "" ) + field if kwargs["data"] and kwargs["data"].get(current_item_key): model = self.associated_models[field] try: model.objects.get(pk=kwargs["data"][current_item_key]) current_status = ( "natural" if field == self.PERSON_FIELD else "corporation" ) except (model.DoesNotExist, ValueError): pass initial = kwargs.get("initial", {}) if not current_status: # the order is important: PERSON can have an ORGA for field in [self.ORGA_FIELD, self.PERSON_FIELD]: value = initial.get(field) model = self.associated_models[field] try: model.objects.get(pk=value) current_status = ( "natural" if field == self.PERSON_FIELD else "corporation" ) except (model.DoesNotExist, ValueError): pass status = "" if "status" in kwargs: status = kwargs.pop("status") if current_status != status: if kwargs.get("data"): # status is different from the existing - clear fields kwargs.pop("data") elif current_status: status = current_status else: status = DEFAULT_STATUS self.status = status if status not in ("natural", "corporation"): status = DEFAULT_STATUS super(PersonOrgaForm, self).__init__(*args, **kwargs) # distinct widget for natural and corporation if status == "natural": self.fields[self.PERSON_FIELD] = forms.IntegerField( label=self.PERSON_LABEL, required=False, initial=initial.get(self.PERSON_FIELD, None), widget=widgets.JQueryPersonOrganization( reverse_lazy("autocomplete-person", args=[self.PERSON_TYPE_PK]), reverse_lazy("person_create"), model=Person, limit={ "person_types": [self.PERSON_TYPE_PK], "attached_to__isnull": True, }, js_template="ishtar/blocks/JQueryNaturalPerson.js", new=True, ), validators=[valid_id(Person)], ) else: self.fields[self.ORGA_FIELD] = forms.IntegerField( label=self.ORGA_LABEL, required=False, initial=initial.get(self.ORGA_FIELD, None), widget=widgets.JQueryPersonOrganization( reverse_lazy("autocomplete-organization", args=[self.ORGA_TYPE_PK]), reverse_lazy("organization_create"), model=models.Organization, limit={"organization_type": [self.ORGA_TYPE_PK]}, js_template="ishtar/blocks/JQueryCorporationPerson.js", new=True, ), validators=[valid_id(models.Organization)], ) class FileFormGeneralContractor(CustomForm, ManageOldType): form_label = _("General contractor") form_admin_name = _("Archaeological file - 030 - General contractor") form_slug = "file-030-generalcontractor" associated_models = { "general_contractor": models.Person, "corporation_general_contractor": models.Organization, } corporation_general_contractor = forms.IntegerField( label=_("General contractor"), widget=widgets.JQueryAutoComplete( reverse_lazy( "autocomplete-organization", args=[ organization_type_pks_lazy(["general_contractor"]), ], ), limit={ "organization_type": [organization_type_pk_lazy("general_contractor")] }, tips=lazy(get_orga_general_contractor_label), associated_model=models.Organization, new=True, detail=True, modify=True, ), validators=[valid_id(models.Organization)], ) general_contractor = forms.IntegerField( label=_("In charge"), required=False, widget=widgets.JQueryAutoComplete( reverse_lazy( "autocomplete-person", args=[person_type_pks_lazy(["general_contractor"])], ), associated_model=Person, limit={"person_types": [person_type_pk_lazy("general_contractor")]}, tips=lazy(get_general_contractor_label), detail=True, modify=True, new=True, ), validators=[valid_id(Person)], ) def clean(self): general_contractor = self.cleaned_data["general_contractor"] corporation_general_contractor = self.cleaned_data[ "corporation_general_contractor" ] if general_contractor: try: person = models.Person.objects.get(pk=general_contractor) except models.Person.DoesNotExist: raise forms.ValidationError(_("Non existing person.")) if ( not person.attached_to or person.attached_to.pk != corporation_general_contractor ): raise forms.ValidationError( _( "The organization of the person in charge differs from the " "general contractor." ) ) return self.cleaned_data class FileFormPlanningService(CustomForm, IshtarForm): form_label = _("Planning service") form_admin_name = _("Archaeological file - 040 - Planning service") form_slug = "file-040-planningservice" associated_models = { "responsible_town_planning_service": models.Person, "planning_service": models.Organization, } planning_service = forms.IntegerField( label=_("Planning service"), required=False, widget=widgets.JQueryAutoComplete( reverse_lazy( "autocomplete-organization", args=[organization_type_pks_lazy(["planning_service"])], ), associated_model=models.Organization, limit={ "organization_type": [organization_type_pk_lazy(["planning_service"])], }, tips=lazy(get_orga_planning_service_label), new=True, detail=True, modify=True, ), validators=[valid_id(models.Organization)], ) responsible_town_planning_service = forms.IntegerField( label=_("In charge"), required=False, widget=widgets.JQueryAutoComplete( reverse_lazy( "autocomplete-person", args=[person_type_pks_lazy(["responsible_planning_service"])], ), associated_model=Person, limit={ "person_types": [person_type_pk_lazy("responsible_planning_service")] }, dynamic_limit=["planning_service"], tips=lazy(get_responsible_planning_service_label), detail=True, modify=True, new=True, ), validators=[valid_id(Person)], ) permit_reference = forms.CharField( label=_("File reference"), required=False, max_length=200 ) planning_service_date = forms.DateField( label=_("Date of planning service file"), widget=DatePicker, required=False ) def clean(self): responsible = self.cleaned_data["responsible_town_planning_service"] orga = self.cleaned_data["planning_service"] if responsible: try: person = models.Person.objects.get(pk=responsible) except models.Person.DoesNotExist: raise forms.ValidationError(_("Non existing person.")) if not person.attached_to or person.attached_to.pk != orga: raise forms.ValidationError( _( "The organization of the person in charge differs from the " "planning service." ) ) return self.cleaned_data class FileFormInstruction(CustomForm, IshtarForm): form_label = _("Instruction") form_admin_name = _("Archaeological file - 050 - Instruction") form_slug = "file-050-instruction" associated_models = {"in_charge": models.Person, "related_file": models.File} in_charge = forms.IntegerField( label=_("File managed by"), widget=widgets.JQueryAutoComplete( reverse_lazy( "autocomplete-person", args=[person_type_pks_lazy(["sra_agent"])] ), limit={"person_types": [person_type_pk_lazy("sra_agent")]}, tips=lazy(get_sra_agent_label), associated_model=Person, new=True, ), validators=[valid_id(Person)], ) related_file = forms.IntegerField( label=_("Related file"), required=False, widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-file"), associated_model=models.File ), validators=[valid_id(models.File)], ) comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False) instruction_deadline = forms.DateField(widget=DatePicker, required=False) year = forms.IntegerField( label=_("Year"), validators=[ validators.MinValueValidator(1000), validators.MaxValueValidator(2100), ], ) numeric_reference = forms.IntegerField(label=_("Numeric reference"), required=False) numeric_reference_is_readonly = True end_date = forms.DateField(widget=DatePicker, required=False) def __init__(self, *args, **kwargs): c_year = datetime.date.today().year if "year" in kwargs: c_year = kwargs.pop("year") saisine_type = None if "saisine_type" in kwargs: saisine_type = kwargs.pop("saisine_type") reception_date = None if "reception_date" in kwargs: reception_date = kwargs.pop("reception_date") if "data" in kwargs and kwargs["data"]: kwargs["data"][kwargs.get("prefix", "") + "-year"] = c_year super(FileFormInstruction, self).__init__(*args, **kwargs) self.fields["year"].initial = c_year self.fields["year"].widget.attrs.update({"readonly": "readonly"}) c_num = 0 q = models.File.objects.filter( numeric_reference__isnull=False, year=c_year ).order_by("-numeric_reference") if q.count(): c_num = q.all()[0].numeric_reference lbl = self.fields["numeric_reference"].label self.fields["numeric_reference"].label = mark_safe(lbl) self.fields["numeric_reference"].initial = c_num + 1 if self.numeric_reference_is_readonly: self.fields["numeric_reference"].widget.attrs["readonly"] = True if reception_date and saisine_type: if type(reception_date) == str: try: reception_date = datetime.datetime.strptime( reception_date, "%d/%m/%Y" ) self.fields["instruction_deadline"].initial = ( reception_date + datetime.timedelta(days=saisine_type.delay or 0) ).strftime("%Y-%m-%d") except ValueError: pass def clean_numeric_reference(self): if self.numeric_reference_is_readonly: return self.fields["numeric_reference"].initial return self.cleaned_data["numeric_reference"] class FileFormInstructionEdit(FileFormInstruction): numeric_reference_is_readonly = False