#!/usr/bin/env python # -*- 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, Department, 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 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 = _(u"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=_(u"Creation date"), initial=get_now, widget=DatePicker) reception_date = forms.DateField( label=_(u"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 = u"Saisine" form_admin_name = _(u"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=_(u"Permit type"), required=False, choices=[]) saisine_type = forms.ChoiceField(label=_(u"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 = _(u"Planning") form_admin_name = _(u"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=_(u"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=_(u"Locality"), max_length=100, required=False) address = forms.CharField( label=_(u"Address (number/street)"), widget=forms.Textarea(attrs={"placeholder": _(u"Number/street")}), required=False) postal_code = forms.CharField(label=_(u"Postal code"), max_length=10, required=False) HEADERS['total_surface'] = FormHeader(_("Surfaces")) total_surface = forms.FloatField( required=False, widget=widgets.AreaWidget, label=_(u"Total surface (m2)"), validators=[validators.MinValueValidator(0), validators.MaxValueValidator(999999999)]) total_developed_surface = forms.FloatField( widget=widgets.AreaWidget, label=_(u"Total developed surface (m2)"), required=False, validators=[validators.MinValueValidator(0), validators.MaxValueValidator(999999999)]) class FileFormResearchAddress(CustomForm, forms.Form): form_label = _(u"Address") form_admin_name = _(u"Archaeological file - 015 - Research - Address") form_slug = "file-015-researchplanning" base_models = ['town', 'department'] associated_models = {'town': Town, 'department': Department} name = forms.CharField(label=_(u"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=_(u"Locality"), max_length=100, required=False) address = forms.CharField( label=_(u"Address (number/street)"), widget=forms.Textarea(attrs={"placeholder": _(u"Number/street")}), required=False) postal_code = forms.CharField(label=_(u"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 = _(u"General contractor") form_admin_name = _("Archaeological file - 030 - General contractor") form_slug = "file-030-generalcontractor" extra_form_modals = ["person", "organization"] 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" extra_form_modals = ["person", "organization"] 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=_(u"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=_(u"File reference"), required=False, max_length=200) 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" extra_form_modals = ["person", "organization"] 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=_(u"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