diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2022-11-15 16:29:30 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2022-12-12 12:23:19 +0100 |
commit | cda77c979e232386ef24ea7a04600f16f3c32c98 (patch) | |
tree | 7d53e762723338913594ccdb42c6fa08c4bfb5ef /archaeological_files | |
parent | 4746cd2938df3cf87ae338d22eb4f67f35bac960 (diff) | |
download | Ishtar-cda77c979e232386ef24ea7a04600f16f3c32c98.tar.bz2 Ishtar-cda77c979e232386ef24ea7a04600f16f3c32c98.zip |
File module refactoring - more tests for files
Diffstat (limited to 'archaeological_files')
-rw-r--r-- | archaeological_files/forms.py | 415 | ||||
-rw-r--r-- | archaeological_files/ishtar_menu.py | 8 | ||||
-rw-r--r-- | archaeological_files/models.py | 31 | ||||
-rw-r--r-- | archaeological_files/templates/ishtar/blocks/JQueryCorporationPerson.js | 2 | ||||
-rw-r--r-- | archaeological_files/templates/ishtar/blocks/JQueryNaturalPerson.js | 2 | ||||
-rw-r--r-- | archaeological_files/templates/ishtar/blocks/JQueryPersonOrga.js | 66 | ||||
-rw-r--r-- | archaeological_files/templates/ishtar/wizard/file_confirm_wizard.html | 27 | ||||
-rw-r--r-- | archaeological_files/templates/ishtar/wizard/wizard_instruction.html | 83 | ||||
-rw-r--r-- | archaeological_files/templates/ishtar/wizard/wizard_person_orga.html | 76 | ||||
-rw-r--r-- | archaeological_files/tests.py | 386 | ||||
-rw-r--r-- | archaeological_files/urls.py | 18 | ||||
-rw-r--r-- | archaeological_files/views.py | 137 | ||||
-rw-r--r-- | archaeological_files/wizards.py | 122 |
13 files changed, 1201 insertions, 172 deletions
diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index a75e5bf34..9466d7d52 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -34,12 +34,19 @@ from ishtar_common.utils import ugettext_lazy as _ from ishtar_common.models import ( Person, Organization, + Town, valid_id, valid_ids, person_type_pks_lazy, person_type_pk_lazy, organization_type_pks_lazy, + organization_type_pk_lazy, + get_sra_agent_label, get_sra_agent_head_scientist_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_operations.models import ActType, AdministrativeAct, OperationType @@ -65,8 +72,6 @@ from archaeological_operations.forms import ( AdministrativeActForm, AdministrativeActOpeFormSelection, AdministrativeActModifForm, - ParcelForm, - ParcelFormSet, ) from ishtar_common import widgets from bootstrap_datepicker.widgets import DatePicker @@ -194,25 +199,12 @@ class FileFormMultiSelection(LockForm, MultiSearchForm): ) -class FileFormGeneral(ManageOldType): +class FileFormGeneral(CustomForm, ManageOldType): form_label = _("General") - associated_models = { - "in_charge": Person, - "related_file": models.File, - "file_type": models.FileType, - } - in_charge = forms.IntegerField( - label=_("Person in charge"), - widget=widgets.JQueryAutoComplete( - reverse_lazy( - "autocomplete-person", args=[person_type_pks_lazy(["sra_agent"])] - ), - limit={"person_types": [person_type_pk_lazy("sra_agent")]}, - associated_model=Person, - new=True, - ), - validators=[valid_id(Person)], - ) + 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, @@ -221,56 +213,22 @@ class FileFormGeneral(ManageOldType): validators.MaxValueValidator(2100), ], ) - numeric_reference = forms.IntegerField( - label=_("Numeric reference"), widget=forms.HiddenInput, required=False - ) - internal_reference = forms.CharField( - label=_("Other reference"), max_length=60, required=False - ) - name = forms.CharField(label=_("Name"), required=False, max_length=100) creation_date = forms.DateField( label=_("Creation date"), initial=get_now, widget=DatePicker ) - file_type = forms.ChoiceField(label=_("File type"), choices=[]) - 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) - total_surface = forms.FloatField( - required=False, - widget=widgets.AreaWidget, - label=_("Total surface (m2)"), - validators=[ - validators.MinValueValidator(0), - validators.MaxValueValidator(999999999), - ], - ) - address = forms.CharField(label=_("Main address"), widget=forms.Textarea) - address_complement = forms.CharField( - label=_("Main address - complement"), required=False + reception_date = forms.DateField( + label=_("Reception date"), initial=get_now, widget=DatePicker ) - def __init__(self, *args, **kwargs): - super(FileFormGeneral, self).__init__(*args, **kwargs) - if "file_type" in self.fields: - self.fields["file_type"].choices = models.FileType.get_types( - initial=self.init_data.get("file_type") - ) - self.fields["file_type"].help_text = models.FileType.get_help() - q = ( - models.File.objects.filter(internal_reference__isnull=False) - .exclude(internal_reference="") - .order_by("-pk") - ) - if q.count() and "internal_reference" in self.fields: - lbl = self.fields["internal_reference"].label - lbl += _("<br/>(last recorded: %s)") % (q.all()[0].internal_reference) - self.fields["internal_reference"].label = mark_safe(lbl) + 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 FileFormGeneralRO(FileFormGeneral): @@ -295,10 +253,239 @@ class FileFormGeneralRO(FileFormGeneral): return cleaned_data -ParcelFormset = formset_factory(ParcelForm, can_delete=True, formset=ParcelFormSet) -ParcelFormset.form_label = _("Parcels") -ParcelFormset.form_admin_name = _("Archaeological file - 020 - Parcel") -ParcelFormset.form_slug = "file-020-parcels" +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 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.get("general_contractor", None) + corporation_general_contractor = self.cleaned_data.get( + "corporation_general_contractor", None + ) + if general_contractor and corporation_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 FileFormPreventive(ManageOldType, forms.Form): @@ -447,6 +634,96 @@ class FileFormResearch(CustomForm, ManageOldType, forms.Form): self.fields["requested_operation_type"].help_text = OperationType.get_help() +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 + + class FinalFileClosingForm(FinalForm): confirm_msg = " " confirm_end_msg = _("Would you like to close this archaeological file?") diff --git a/archaeological_files/ishtar_menu.py b/archaeological_files/ishtar_menu.py index 517b0276d..bfdd72148 100644 --- a/archaeological_files/ishtar_menu.py +++ b/archaeological_files/ishtar_menu.py @@ -71,25 +71,25 @@ MENU_SECTIONS = [ _("Administrative act"), childs=[ MenuItem( - "file_administrativeactfil_search", + "file_administrativeactfile_search", _("Search"), model=AdministrativeAct, access_controls=["change_administrativeact"], ), MenuItem( - "file_administrativeactfil", + "file_administrativeactfile", _("Creation"), model=AdministrativeAct, access_controls=["change_administrativeact"], ), MenuItem( - "file_administrativeactfil_modification", + "file_administrativeactfile_modification", _("Modification"), model=AdministrativeAct, access_controls=["change_administrativeact"], ), MenuItem( - "file_administrativeactfil_deletion", + "file_administrativeactfile_deletion", _("Deletion"), model=AdministrativeAct, access_controls=["change_administrativeact"], diff --git a/archaeological_files/models.py b/archaeological_files/models.py index bcc90ab4f..9b878ab35 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -282,10 +282,10 @@ class FileType(GeneralType): ordering = ("label",) @classmethod - def is_preventive(cls, file_type_id, key=""): + def is_preventive(cls, file_type_id, key="", force=False): key = key or "preventive" try: - preventive = FileType.get_cache(key).pk + preventive = FileType.get_cache(key, force=force).pk return file_type_id == preventive except (FileType.DoesNotExist, AttributeError): return False @@ -793,6 +793,11 @@ class File( if not date: date = datetime.date(2500, 1, 1) elif settings.COUNTRY == "fr" and self.saisine_type and self.saisine_type.delay: + if isinstance(date, str): + try: + date = datetime.datetime.strptime(date, "%Y-%m-%d").date() + except ValueError: + date = datetime.date(2500, 1, 1) date += datetime.timedelta(days=self.saisine_type.delay) cache.set(cache_key, date, settings.CACHE_TIMEOUT) return date @@ -917,13 +922,21 @@ class File( if not self.file_type.txt_idx == "preventive": cls = "blue" elif not self.has_adminact and self.reception_date: - delta = datetime.date.today() - self.reception_date - cls = "red" - if self.saisine_type and self.saisine_type.delay: - if delta.days <= (self.saisine_type.delay * 2 / 3): - cls = "green" - elif delta.days <= self.saisine_type.delay: - cls = "orange" + reception_date = self.reception_date + if isinstance(self.reception_date, str): + try: + reception_date = datetime.datetime.strptime(self.reception_date, + "%Y-%m-%d").date() + except ValueError: + reception_date = None + if reception_date: + delta = datetime.date.today() - reception_date + cls = "red" + if self.saisine_type and self.saisine_type.delay: + if delta.days <= (self.saisine_type.delay * 2 / 3): + cls = "green" + elif delta.days <= self.saisine_type.delay: + cls = "orange" cache.set(cache_key, cls, settings.CACHE_TIMEOUT) return cls diff --git a/archaeological_files/templates/ishtar/blocks/JQueryCorporationPerson.js b/archaeological_files/templates/ishtar/blocks/JQueryCorporationPerson.js new file mode 100644 index 000000000..3eb375167 --- /dev/null +++ b/archaeological_files/templates/ishtar/blocks/JQueryCorporationPerson.js @@ -0,0 +1,2 @@ +var current_status = 'corporation'; +{% include "ishtar/blocks/JQueryPersonOrga.js" %} diff --git a/archaeological_files/templates/ishtar/blocks/JQueryNaturalPerson.js b/archaeological_files/templates/ishtar/blocks/JQueryNaturalPerson.js new file mode 100644 index 000000000..fc4b9a90c --- /dev/null +++ b/archaeological_files/templates/ishtar/blocks/JQueryNaturalPerson.js @@ -0,0 +1,2 @@ +var current_status = 'natural'; +{% include "ishtar/blocks/JQueryPersonOrga.js" %} diff --git a/archaeological_files/templates/ishtar/blocks/JQueryPersonOrga.js b/archaeological_files/templates/ishtar/blocks/JQueryPersonOrga.js new file mode 100644 index 000000000..1877e4579 --- /dev/null +++ b/archaeological_files/templates/ishtar/blocks/JQueryPersonOrga.js @@ -0,0 +1,66 @@ +person_save_callback = function(item_id, lbl){ + var url = {{edit_source}}; + $('#id_{{field_id}}').val(null); + $('#id_select_{{field_id}}').val(lbl); + if (item_id){ + url = {{edit_source}}+item_id; + $('#id_{{field_id}}').val(item_id); + } + $("#id_select_{{field_id}}").trigger('autocompletechange'); + $.get(url , function( data ) { + $( "#div-{{field_id}}" ).html( data ); + }); +}; + +edit_url = {{edit_source}}; +parent_id = "{{field_id}}"; + +person_new_callback = function(){ + var url = {{edit_source}}; + $('#id_{{field_id}}').val(null); + $('#id_select_{{field_id}}').val(null); +} + +$(function() { + var $radios = $('input:radio[name=person_type]'); + if($radios.is(':checked') === false) { + $radios.filter('[value='+ current_status +']').prop('checked', true); + } + + $radios.change(function(){ + var loc = window.location; + window.location = loc.protocol + '//' + loc.host + loc.pathname + "?status=" + $('input:radio[name=person_type]:checked').val(); + }); + + $("#id_select_{{field_id}}").autocomplete({ + source: {{source}}, + select: function( event, ui ) { + var url = {{edit_source}}; + if(ui.item){ + url = {{edit_source}}+ui.item.id; + $('#id_{{field_id}}').val(ui.item.id); + $('#id_{{field_id}}').change(); + } else { + $('#id_{{field_id}}').val(null); + } + $.get(url, function( data ) { + $( "#div-{{field_id}}" ).html( data ); + }); + }, + minLength: 2{% if options %}, + {{options}} + {% endif %} + }); + + $.get( {{edit_source}}{% if selected %}+'{{selected}}'{% endif %}, function( data ) { + $( "#div-{{field_id}}" ).html( data ); + }); + + $(document).on("click", '#id_select_{{field_id}}', function(){ + $('#id_{{field_id}}').val(null); + $('#id_select_{{field_id}}').val(null); + $.get( {{edit_source}}, function( data ) { + $( "#div-{{field_id}}" ).html( data ); + }); + }); +}); diff --git a/archaeological_files/templates/ishtar/wizard/file_confirm_wizard.html b/archaeological_files/templates/ishtar/wizard/file_confirm_wizard.html new file mode 100644 index 000000000..914a5198b --- /dev/null +++ b/archaeological_files/templates/ishtar/wizard/file_confirm_wizard.html @@ -0,0 +1,27 @@ +{% extends "ishtar/wizard/confirm_wizard.html" %} +{% load i18n %} + +{% block "warning_informations" %} +{% for file in numeric_reference_files %} +{% if forloop.first %} +<p class='alert'><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> <label>{% trans "The following files have the same numeric index as this file:" %}</label></p> +<ul> +{% endif%} + <li>{{file}} <a href='#' onclick='load_window("{% url 'show-file' file.pk '' %}", "{{model_name}}");' class='display_details'><i class="fa fa-info-circle" aria-hidden="true"></i></a></li> +{% if forloop.last %} +</ul> +<hr/> +{% endif %} +{% endfor %} +{% for file in similar_files %} +{% if forloop.first %} +<p class='alert'><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> <label>{% trans "The following files are in the same town and have parcels in common with this file:" %}</label></p> +<ul> +{% endif%} + <li>{{file}} <a href='#' onclick='load_window("{% url 'show-file' file.pk '' %}", "{{model_name}}");' class='display_details'><i class="fa fa-info-circle" aria-hidden="true"></i></a></li> +{% if forloop.last %} +</ul> +<hr/> +{% endif %} +{% endfor %} +{% endblock %} diff --git a/archaeological_files/templates/ishtar/wizard/wizard_instruction.html b/archaeological_files/templates/ishtar/wizard/wizard_instruction.html new file mode 100644 index 000000000..34db944aa --- /dev/null +++ b/archaeological_files/templates/ishtar/wizard/wizard_instruction.html @@ -0,0 +1,83 @@ +{% extends "ishtar/wizard/default_wizard.html" %} +{% load i18n range table_form %} +{% block form_detail %} + <div class="form-row"> + {% with wizard.form.in_charge as field %} + {% include "blocks/bs_field_snippet.html" %} + {% endwith %} + {% with wizard.form.related_file as field %} + {% include "blocks/bs_field_snippet.html" %} + {% endwith %} + {% with wizard.form.comment as field %} + {% include "blocks/bs_field_snippet.html" %} + {% endwith %} + + <div class="form-group col-lg-6"> + <span class="required"> + <label class="required">{% trans "State of the file:" %}</label> + </span> + <div class="form-group col-lg-12 mb-0"> + <span><input type='radio' name='state' value='open' id='state-open'/> + <label for='state-open'>Dossier actif</label></span> + </div> + <div class="form-group col-lg-12"> + <span>{{wizard.form.end_date.errors}}<input type='radio' name='state' value='closed' id='state-closed'/> + <label for='state-closed'>Dossier clos / date de clôture</label> : {{wizard.form.end_date|safe}}</span> + </div> + </div> + {% with wizard.form.instruction_deadline as field %}{% with saisine_type_message as extra_field_label %} + {% include "blocks/bs_field_snippet.html" %} + {% endwith %}{% endwith %} + <div class="form-group col-lg-6"> + <span class="required"> + <label>{{wizard.form.numeric_reference.label}}{% trans ":" %}</label> + </span> + <div class="form-inline"> + {{wizard.form.numeric_reference.errors}} + {% if FILE_PREFIX %}<span class="pr-2">{{FILE_PREFIX}}</span>{% endif %} + <span class="pr-2">{{wizard.form.year|safe}}</span> - + <span class="pl-2">{{wizard.form.numeric_reference|safe}}</span> + </div> + </div> + </div> +{% endblock %} + +{% block "js_extra_ready" %} + if ($('#id_instruction-{{CURRENT_ACTION}}-end_date').val()){ + $("#state-closed").prop('checked', true); + } else { + $("#state-open").prop('checked', true); + } + + check_state = function(){ + var state = $("input[name=state]:checked").val(); + if (state == 'closed'){ + $('#id_instruction-{{CURRENT_ACTION}}-end_date').focus(); + $('#id_instruction-{{CURRENT_ACTION}}-end_date').prop('disabled', false); + } else if (state == 'open'){ + $('#id_instruction-{{CURRENT_ACTION}}-end_date').val(''); + $('#id_instruction-{{CURRENT_ACTION}}-end_date').prop('disabled', true); + } + }; + + $('input[name=state]').click(check_state); + + check_state(); + + $('#submit_form').click(function(){ + var state = $("input[name=state]:checked").val(); + if (state == 'closed'){ + if (!$('#id_instruction-{{CURRENT_ACTION}}-end_date').val()){ + alert("{% trans 'You must select a closing date.' %}") + return false; + } + return true; + } else if (state == 'open'){ + return true; + } else { + alert("{% trans 'You must select a state for this file.' %}") + return false; + } + return true; + }); + {% endblock %} diff --git a/archaeological_files/templates/ishtar/wizard/wizard_person_orga.html b/archaeological_files/templates/ishtar/wizard/wizard_person_orga.html new file mode 100644 index 000000000..36f1aa4f8 --- /dev/null +++ b/archaeological_files/templates/ishtar/wizard/wizard_person_orga.html @@ -0,0 +1,76 @@ +{% extends "ishtar/wizard/default_wizard.html" %} +{% load i18n range table_form %} +{% block wizard_form %} +<script type='text/javascript'> +function update_form(){ + if ($('input[name="person_type"]:radio:checked').val() == 'corporation'){ + $('#natural_div').hide(); + $('#corporation_div').show(); + $('#orga-form').show(); + } else { + $('#natural_div').show(); + $('#corporation_div').hide(); + $('#orga-form').hide(); + } +} +$(function() { + update_form(); +}); +</script> +<form action="." method="post" name='wizard'{% if wizard.form.file_upload %} enctype="multipart/form-data"{% endif %}>{% csrf_token %} +<div class='form'> +{% if wizard.form.media %}{{ wizard.form.media }}{% endif %} +{{ wizard.management_form }} + +<table class='formset'> + <caption>Statut</caption> + <tr> + <th><label>{% trans "Corporation" %}</label></th> + <td><input type='radio' name='person_type' value='corporation'/></td> + </tr> + <tr> + <th><label>{% trans "Natural person" %}</label></th> + <td><input type='radio' name='person_type' value='natural'/></td> + </tr> +</table> + +<table id='corporation_div'> + {% if wizard.form.non_field_errors %}<tr class='errors'> + <td colspan='3'>{{wizard.form.non_field_errors}}</td> + </tr>{%endif%} + +{% block corporation %} +{% endblock %} +</table> +<div id='natural_div'> +<table> + {% if wizard.form.non_field_errors %}<tr class='errors'> + <td colspan='3'>{{wizard.form.non_field_errors}}</td> + </tr>{%endif%} + +{% block natural %} +{% endblock %} +</table> +</div> + +<div> +{% block otherfields %} +{% endblock %} +</div> +{% block extra_head_po %} +{% endblock %} + +<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> +{{ previous_fields|safe }} + {% block "footer" %} + <div id="footer"> + {% block "validation_bar" %} + {% include 'ishtar/wizard/validation_bar.html' %} + {% endblock %} + {% include 'ishtar/blocks/footer.html' %} + </div> + {% endblock %} +</div> +</form> +{% endblock %} + diff --git a/archaeological_files/tests.py b/archaeological_files/tests.py index 7145cb836..f0684c756 100644 --- a/archaeological_files/tests.py +++ b/archaeological_files/tests.py @@ -30,10 +30,13 @@ from ishtar_common.tests import ( create_superuser, AutocompleteTestBase, AcItem, + WizardTest, + WizardTestFormData as FormData, FILE_TOWNS_FIXTURES, ) -from ishtar_common.models import Town, IshtarSiteProfile +from ishtar_common.models import Town, IshtarSiteProfile, Person, PersonType, \ + Organization, OrganizationType from ishtar_common.utils import ugettext_lazy as _ from archaeological_files import models, views @@ -45,7 +48,7 @@ from archaeological_operations.models import ( ) from archaeological_operations.tests import OperationInitTest, FileInit - +""" def create_administrativact(user, fle): act_type, created = ActType.objects.get_or_create( txt_idx="act_type_F", intented_to="F" @@ -59,6 +62,7 @@ def create_administrativact(user, fle): } adminact, created = AdministrativeAct.objects.get_or_create(**dct) return [act_type], [adminact] +""" class FileTest(TestCase, FileInit): @@ -754,3 +758,381 @@ class AutocompleteTest(AutocompleteTestBase, TestCase): name=base_name, file_type=models.FileType.objects.all()[0] ) return item, None + + +class FileWizardCreationTest(WizardTest, OperationInitTest, TestCase): + fixtures = FILE_TOWNS_FIXTURES + url_name = "file_creation" + wizard_name = "file_wizard" + steps = views.file_creation_steps + redirect_url = ( + "/file_modification/selec-file_modification?open_item={last_id}" + ) + model = models.File + + form_datas = [ + FormData( + "Create a research file", + form_datas={ + "general": { + "file_type": None, + "year": None, + "creation_date": None, + "reception_date": None + }, + "researchaddress": {}, + "research": { + "requested_operation_type": None, + "scientist": None, + }, + "instruction": { + "in_charge": None + } + }, + ignored=( + "preventivetype-file_creation", + "preventiveplanning-file_creation", + "generalcontractor-file_creation", + "planningservice-file_creation", + ), + ), + FormData( + "Create a preventive file", + form_datas={ + "general": { + "file_type": None, + "year": None, + "creation_date": None, + "reception_date": None + }, + "preventivetype-file_creation": { + "saisine_type": None, + }, + "preventiveplanning-file_creation": {}, + "generalcontractor-file_creation": { + "corporation_general_contractor": None + }, + "instruction": { + "in_charge": None + } + }, + ignored=( + "planningservice-file_creation", + "researchaddress-file_creation", + "research-file_creation", + ), + ), + ] + + def pre_wizard(self): + profile, created = IshtarSiteProfile.objects.get_or_create( + slug="default", active=True + ) + profile.files = True + profile.save() + + if "general" not in self.form_datas[0].form_datas: + super().pre_wizard() + return + + file_type_pk = models.FileType.objects.get(txt_idx="prog").pk + # force cache reinit because previous mess up that - do not know why + models.FileType.is_preventive(file_type_pk, force=True) + self.form_datas[0].set( + "general", + "file_type", + file_type_pk + ) + file_type_pk = models.FileType.objects.get(txt_idx="preventive").pk + models.FileType.is_preventive(file_type_pk, force=True) + self.form_datas[1].set( + "general", + "file_type", + file_type_pk + ) + + responsability = Person.objects.create(name="OK", surname="SuperComputer") + responsability.person_types.add(PersonType.objects.get(txt_idx="sra_agent")) + for idx in range(2): + self.form_datas[idx].set("general", "year", 2022) + self.form_datas[idx].set("general", "creation_date", "2022-10-01") + self.form_datas[idx].set("general", "reception_date", "2022-10-03") + self.form_datas[idx].set("instruction", "in_charge", responsability.pk) + + ope_type = models.OperationType.objects.get(txt_idx="documents_study_research") + self.form_datas[0].set("research", "requested_operation_type", ope_type.pk) + person = Person.objects.create(name="OK", surname="Computer") + person.person_types.add(PersonType.objects.get(txt_idx="head_scientist")) + self.form_datas[0].set("research", "scientist", person.pk) + + self.form_datas[1].set( + "preventivetype", "saisine_type", + models.SaisineType.objects.filter(delay__gt=0).all()[0].pk + ) + self.form_datas[1].set( + "preventivetype", "permit_type", + models.PermitType.objects.all()[0].pk + ) + orga = Organization.objects.create( + name="Big corpo", + organization_type=OrganizationType.objects.get(txt_idx="general_contractor") + ) + self.form_datas[1].set( + "generalcontractor", "corporation_general_contractor", orga.pk + ) + + self.file_number = models.File.objects.count() + super().pre_wizard() + + def post_wizard(self): + self.assertEqual(models.File.objects.count(), self.file_number + 2) + + +class FileWizardModifTest(WizardTest, OperationInitTest, TestCase): + fixtures = FILE_TOWNS_FIXTURES + url_name = "file_modification" + wizard_name = url_name + "_wizard" + steps = views.file_modification_steps + redirect_url = ( + "/file_modification/selec-file_modification?open_item={current_id}" + ) + model = models.File + + form_datas = [ + FormData( + "Modify a research file", + form_datas={ + "selec": {}, + "general": { + "year": 2019, + }, + "generalcontractor": { + "corporation_general_contractor": None + }, + "instruction": { + "in_charge": None + } + }, + ignored=( + "preventivetype-file_modification", + "preventiveplanning-file_modification", + "researchaddress-file_modification", + "planningservice-file_modification", + "research-file_modification", + ), + ), + FormData( + "Modify a preventive file", + form_datas={ + "selec": {}, + "general": { + "file_type": None, + "year": 2012, + "creation_date": None, + "reception_date": None + }, + "preventivetype": { + "saisine_type": None, + }, + "preventiveplanning": {}, + "planningservice":{ + "permit_reference": "XKCD" + }, + "generalcontractor": { + "corporation_general_contractor": None + }, + "instruction": { + "in_charge": None + } + }, + ignored=( + "researchaddress-file_modification", + "research-file_modification", + ), + ), + ] + + def pre_wizard(self): + profile, created = IshtarSiteProfile.objects.get_or_create( + slug="default", active=True + ) + profile.files = True + profile.save() + + if "general" not in self.form_datas[0].form_datas: + super().pre_wizard() + return + + responsability = Person.objects.create(name="OK", surname="SuperComputer") + responsability.person_types.add(PersonType.objects.get(txt_idx="sra_agent")) + ope_type = models.OperationType.objects.get(txt_idx="documents_study_research") + person = Person.objects.create(name="OK", surname="Computer") + person.person_types.add(PersonType.objects.get(txt_idx="head_scientist")) + orga = Organization.objects.create( + name="Big corpo", + organization_type=OrganizationType.objects.get(txt_idx="general_contractor") + ) + + file_type_pk = models.FileType.objects.get(txt_idx="prog").pk + # force cache reinit because previous mess up that - do not know why + models.FileType.is_preventive(file_type_pk, force=True) + fle = models.File.objects.create( + file_type_id=file_type_pk, + year=2022, + creation_date="2022-10-01", + reception_date="2022-10-03", + in_charge=responsability, + requested_operation_type=ope_type, + scientist=person, + corporation_general_contractor=orga, + ) + file_type_pk = models.FileType.objects.get(txt_idx="preventive").pk + # force cache reinit because previous mess up that - do not know why + models.FileType.is_preventive(file_type_pk, force=True) + fle2 = models.File.objects.create( + file_type_id=file_type_pk, + year=2021, + creation_date="2022-09-01", + reception_date="2022-10-03", + in_charge=responsability, + corporation_general_contractor=orga, + saisine_type=models.SaisineType.objects.filter(delay__gt=0).all()[0] + ) + self.files = [fle, fle2] + + data = self.form_datas[0].form_datas + data["selec"]["pk"] = str(fle.pk) + data["general"]["file_type"] = fle.file_type.pk + data["general"]["creation_date"] = fle.creation_date + data["general"]["reception_date"] = fle.reception_date + data["generalcontractor"]["corporation_general_contractor"] = \ + fle.corporation_general_contractor.pk + data["instruction"]["in_charge"] = fle.in_charge.pk + data["instruction"]["numeric_reference"] = fle.numeric_reference + + data2 = self.form_datas[1].form_datas + data2["selec"]["pk"] = str(fle2.pk) + data2["general"]["file_type"] = fle2.file_type.pk + data2["general"]["creation_date"] = fle2.creation_date + data2["general"]["reception_date"] = fle2.reception_date + data2["preventivetype"]["saisine_type"] = fle2.saisine_type.pk + data2["generalcontractor"]["corporation_general_contractor"] = \ + fle2.corporation_general_contractor.pk + data2["instruction"]["in_charge"] = fle2.in_charge.pk + data2["instruction"]["numeric_reference"] = fle2.numeric_reference + self.file_number = models.File.objects.count() + + def post_first_wizard(test_object, final_step_response): + fle = models.File.objects.get(pk=test_object.files[0].pk) + test_object.assertEqual(fle.year, 2019) + + def post_second_wizard(test_object, final_step_response): + fle = models.File.objects.get(pk=test_object.files[1].pk) + test_object.assertEqual(fle.year, 2012) + + self.form_datas[0].extra_tests = [post_first_wizard] + self.form_datas[1].extra_tests = [post_second_wizard] + super().pre_wizard() + + def post_wizard(self): + self.assertEqual(models.File.objects.count(), self.file_number) + + +class FileWizardDeleteTest(FileWizardCreationTest): + fixtures = FILE_TOWNS_FIXTURES + url_name = "file_deletion" + wizard_name = url_name + "_wizard" + steps = views.file_deletion_steps + redirect_url = "/{}/selec-{}".format(url_name, url_name) + form_datas = [ + FormData( + "Wizard deletion test", + form_datas={ + "selec": {"pks": None}, + }, + ) + ] + + def pass_test(self): + if not settings.TEST_VIEWS: + # with no migration the views are not created + return True + + def pre_wizard(self): + self.file = models.File.objects.create( + file_type=models.FileType.objects.get(txt_idx="prog"), + year=2022, + ) + self.form_datas[0].form_datas["selec"]["pks"] = self.file.pk + self.file_number = models.File.objects.count() + super().pre_wizard() + + def post_wizard(self): + self.assertEqual(self.file_number - 1, models.File.objects.count()) + + +class FileWizardClosingTest(FileWizardCreationTest): + fixtures = FILE_TOWNS_FIXTURES + url_name = "file_closing" + wizard_name = url_name + "_wizard" + steps = views.file_closing_steps + redirect_url = "/file_closing/done" + form_datas = [ + FormData( + "Wizard closing test", + form_datas={ + "selec": {"pk": None}, + "date": {"end_date": "2016-01-01"}, + }, + ) + ] + + def pre_wizard(self): + self.file = models.File.objects.create( + file_type=models.FileType.objects.get(txt_idx="prog"), + year=2022, + ) + self.form_datas[0].form_datas["selec"]["pk"] = self.file.pk + self.assertTrue(self.file.is_active()) + super().pre_wizard() + + def post_wizard(self): + fle = models.File.objects.get(pk=self.file.pk) + self.assertFalse(fle.is_active()) + self.assertEqual( + fle.closing()["date"].strftime("%Y-%d-%m"), + self.form_datas[0].form_datas["date-" + self.url_name]["end_date"] + ) + + +class FileAdminActWizardCreationTest(WizardTest, OperationInitTest, TestCase): + fixtures = FILE_TOWNS_FIXTURES + url_name = "file_administrativeactfile" + wizard_name = "file_administrative_act_wizard" + steps = views.administrativeact_steps + form_datas = [ + FormData( + "Admin act creation", + form_datas={ + "selec": {}, + "administrativeact": { + "signature_date": str(datetime.date.today()) + }, + }, + ) + ] + + def pre_wizard(self): + self.file = models.File.objects.create( + file_type=models.FileType.objects.get(txt_idx="prog"), + year=2022, + ) + data = self.form_datas[0].form_datas + data["selec"]["pk"] = self.file.pk + act = ActType.objects.filter(intented_to="F").all()[0].pk + data["administrativeact"]["act_type"] = act + self.number = AdministrativeAct.objects.count() + super().pre_wizard() + + def post_wizard(self): + self.assertEqual(AdministrativeAct.objects.count(), self.number + 1) diff --git a/archaeological_files/urls.py b/archaeological_files/urls.py index 084f2155f..fd2059bbe 100644 --- a/archaeological_files/urls.py +++ b/archaeological_files/urls.py @@ -29,14 +29,14 @@ from archaeological_operations.views import administrativeactfile_document # forms: urlpatterns = [ url( - r"file_administrativeactfil_search/(?P<step>.+)?$", + r"file_administrativeactfile_search/(?P<step>.+)?$", check_rights(["change_administrativeact"])( views.file_administrativeactfile_search_wizard ), name="file_administrativeactfile_search", ), url( - r"file_administrativeactfil/(?P<step>.+)?$", + r"^file_administrativeactfile/(?P<step>.+)?$", check_rights(["change_administrativeact"])( views.file_administrativeactfile_wizard ), @@ -48,14 +48,14 @@ urlpatterns = [ name="file_administrativeactfile_modify", ), url( - r"file_administrativeactfil_deletion/(?P<step>.+)?$", + r"file_administrativeactfile_deletion/(?P<step>.+)?$", check_rights(["change_administrativeact"])( views.file_administrativeactfile_deletion_wizard ), name="file_administrativeactfile_deletion", ), url( - r"file_administrativeactfil_modification/(?P<step>.+)?$", + r"file_administrativeactfile_modification/(?P<step>.+)?$", check_rights(["change_administrativeact"])( views.file_administrativeactfile_modification_wizard ), @@ -172,6 +172,16 @@ urlpatterns = [ name="file-edit-preventive-copy-planned", ), url( + r"townplanning-edit/$", + views.TownPlanningCreate.as_view(), + name="townplanning_create", + ), + url( + r"townplanning-edit/(?P<pk>\d+)$", + views.TownPlanningEdit.as_view(), + name="townplanning_edit", + ), + url( r"api/facets/file/$", views_api.FacetFileAPIView.as_view(), name="api-facets-file" ), diff --git a/archaeological_files/views.py b/archaeological_files/views.py index cbe1a9f96..5988ba1c0 100644 --- a/archaeological_files/views.py +++ b/archaeological_files/views.py @@ -29,7 +29,8 @@ from django.urls import reverse from ishtar_common.utils import ugettext_lazy as _ from archaeological_operations.utils import parse_parcels -from ishtar_common.views import wizard_is_available +from ishtar_common.views import wizard_is_available, OrganizationPersonCreate, \ + OrganizationPersonEdit from ishtar_common.views_item import get_item, show_item, revert_item, check_permission from archaeological_operations.wizards import ( @@ -52,7 +53,6 @@ from ishtar_common.views import IshtarMixin, LoginRequiredMixin from archaeological_operations.wizards import OperationWizard from archaeological_operations.views import operation_creation_wizard -from ishtar_common.forms_common import TownFormset from archaeological_operations.forms import FinalAdministrativeActDeleteForm, \ SelectedParcelGeneralFormSet from ishtar_common.forms import ClosingDateFormSelection @@ -137,43 +137,69 @@ file_search_wizard = wizards.FileSearch.as_view( url_name="file_search", ) -file_creation_wizard = wizards.FileWizard.as_view( - [ - ("general-file_creation", forms.FileFormGeneral), - ("towns-file_creation", TownFormset), - ("preventive-file_creation", forms.FileFormPreventive), - ("research-file_creation", forms.FileFormResearch), - ("final-file_creation", forms.FinalForm), - ], +file_creation_wizard_is_preventive = is_preventive( + "general-file_creation", models.FileType, type_key="file_type" +) +file_creation_wizard_is_not_preventive = is_not_preventive( + "general-file_creation", models.FileType, type_key="file_type" +) + +file_creation_steps = [ + ("general-file_creation", forms.FileFormGeneral), + ("preventivetype-file_creation", forms.FileFormPreventiveType), + ("preventiveplanning-file_creation", forms.FileFormPlanning), + ("researchaddress-file_creation", forms.FileFormResearchAddress), + ("generalcontractor-file_creation", forms.FileFormGeneralContractor), + ("planningservice-file_creation", forms.FileFormPlanningService), + ("research-file_creation", forms.FileFormResearch), + ("instruction-file_creation", forms.FileFormInstruction), + ("final-file_creation", forms.FinalForm), +] + +file_creation_wizard = FileWizard.as_view( + file_creation_steps, label=_("New file"), condition_dict={ - "preventive-file_creation": is_preventive( - "general-file_creation", models.FileType, type_key="file_type" - ), - "research-file_creation": is_not_preventive( - "general-file_creation", models.FileType, type_key="file_type" - ), + "preventivetype-file_creation": file_creation_wizard_is_preventive, + "preventiveplanning-file_creation": file_creation_wizard_is_preventive, + "generalcontractor-file_creation": file_creation_wizard_is_preventive, + "planningservice-file_creation": file_creation_wizard_is_preventive, + "researchaddress-file_creation": file_creation_wizard_is_not_preventive, + "research-file_creation": file_creation_wizard_is_not_preventive, }, url_name="file_creation", ) -file_modification_wizard = wizards.FileModificationWizard.as_view( - [ - ("selec-file_modification", forms.FileFormSelection), - ("general-file_modification", forms.FileFormGeneralRO), - ("towns-file_modification", TownFormset), - ("preventive-file_modification", forms.FileFormPreventive), - ("research-file_modification", forms.FileFormResearch), - ("final-file_modification", forms.FinalForm), - ], +file_modification_wizard_is_preventive = is_preventive( + "general-file_modification", models.FileType, type_key="file_type" +) +file_modification_wizard_is_not_preventive = is_not_preventive( + "general-file_modification", models.FileType, type_key="file_type" +) + +file_modification_steps = [ + ("selec-file_modification", forms.FileFormSelection), + ("general-file_modification", forms.FileFormGeneral), + ("preventivetype-file_modification", forms.FileFormPreventiveType), + ("preventiveplanning-file_modification", forms.FileFormPlanning), + ("researchaddress-file_modification", forms.FileFormResearchAddress), + ("generalcontractor-file_modification", forms.FileFormGeneralContractor), + ("planningservice-file_modification", forms.FileFormPlanningService), + ("research-file_modification", forms.FileFormResearch), + ("instruction-file_modification", forms.FileFormInstructionEdit), + ("final-file_modification", forms.FinalForm), +] + +file_modification_wizard = FileModificationWizard.as_view( + file_modification_steps, label=_("File modification"), condition_dict={ - "preventive-file_modification": is_preventive( - "general-file_modification", models.FileType, type_key="file_type" - ), - "research-file_modification": is_not_preventive( - "general-file_modification", models.FileType, type_key="file_type" - ), + "preventivetype-file_modification": file_modification_wizard_is_preventive, + "preventiveplanning-file_modification": file_modification_wizard_is_preventive, + "generalcontractor-file_modification": file_modification_wizard_is_preventive, + "planningservice-file_modification": file_modification_wizard_is_preventive, + "researchaddress-file_modification": file_modification_wizard_is_not_preventive, + "research-file_modification": file_modification_wizard_is_not_preventive, }, url_name="file_modification", ) @@ -191,21 +217,25 @@ def file_modify(request, pk): ) +file_closing_steps = [ + ("selec-file_closing", forms.FileFormSelection), + ("date-file_closing", ClosingDateFormSelection), + ("final-file_closing", forms.FinalFileClosingForm), +] + file_closing_wizard = wizards.FileClosingWizard.as_view( - [ - ("selec-file_closing", forms.FileFormSelection), - ("date-file_closing", ClosingDateFormSelection), - ("final-file_closing", forms.FinalFileClosingForm), - ], + file_closing_steps, label=_("File closing"), url_name="file_closing", ) +file_deletion_steps = [ + ("selec-file_deletion", forms.FileFormMultiSelection), + ("final-file_deletion", forms.FinalFileDeleteForm), +] + file_deletion_wizard = wizards.FileDeletionWizard.as_view( - [ - ("selec-file_deletion", forms.FileFormMultiSelection), - ("final-file_deletion", forms.FinalFileDeleteForm), - ], + file_deletion_steps, label=_("File deletion"), url_name="file_deletion", ) @@ -221,6 +251,14 @@ def file_delete(request, pk): return redirect(reverse("file_deletion", kwargs={"step": "final-file_deletion"})) +class TownPlanningEdit(OrganizationPersonEdit): + relative_label = _("File followed by") + + +class TownPlanningCreate(OrganizationPersonCreate): + relative_label = _("File followed by") + + file_administrativeactfile_search_wizard = SearchWizard.as_view( [ ( @@ -232,15 +270,18 @@ file_administrativeactfile_search_wizard = SearchWizard.as_view( url_name="file_administrativeactfile_search", ) + +administrativeact_steps = [ + ("selec-file_administrativeactfile", forms.FileFormSelection), + ( + "administrativeact-file_administrativeactfile", + forms.AdministrativeActFileForm, + ), + ("final-file_administrativeactfile", forms.FinalForm), +] + file_administrativeactfile_wizard = wizards.FileAdministrativeActWizard.as_view( - [ - ("selec-file_administrativeactfile", forms.FileFormSelection), - ( - "administrativeact-file_administrativeactfile", - forms.AdministrativeActFileForm, - ), - ("final-file_administrativeactfile", forms.FinalForm), - ], + administrativeact_steps, label=_("File: new administrative act"), url_name="file_administrativeactfile", ) diff --git a/archaeological_files/wizards.py b/archaeological_files/wizards.py index 1538a984a..569b01a56 100644 --- a/archaeological_files/wizards.py +++ b/archaeological_files/wizards.py @@ -39,10 +39,23 @@ class FileSearch(SearchWizard): class FileWizard(OperationWizard): model = models.File object_parcel_type = "associated_file" - parcel_step_key = "parcels-" - town_step_keys = ["towns-"] + parcel_step_key = "parcelspdl-" + town_step_keys = ["preventiveplanning-", "researchaddress-"] wizard_done_window = reverse_lazy("show-file") redirect_url = "file_modification" + town_input_id = "town" + towns_formset = False + multi_towns = True + wizard_templates = { + "planningservice-%(url_name)s": "ishtar/wizard/wizard_planningservice.html", + "instruction-%(url_name)s": "ishtar/wizard/wizard_instruction.html", + "preventiveplanning-%(url_name)s": "ishtar/wizard/wizard_preventiveplanning.html", + } + wizard_confirm = "ishtar/wizard/file_confirm_wizard.html" + + def get_current_year(self): + general_form_key = "general-" + self.url_name + return self.session_get_value(general_form_key, "year") def get_extra_model(self, dct, m2m, form_list): dct = super(FileWizard, self).get_extra_model(dct, m2m, form_list) @@ -53,9 +66,79 @@ class FileWizard(OperationWizard): dct["numeric_reference"] = current_ref and current_ref + 1 or 1 return dct + def get_form_kwargs(self, *args, **kwargs): + returned = super(FileWizard, self).get_form_kwargs(*args, **kwargs) + if args and args[0].startswith("generalcontractor-"): + if "status" in self.request.GET: + returned["status"] = self.request.GET["status"] + if args and args[0].startswith("instruction-"): + returned["year"] = self.get_current_year() + returned["saisine_type"] = self.get_saisine_type() + returned["reception_date"] = self.session_get_value( + "general-" + self.url_name, "reception_date" + ) + return returned + + def get_saisine_type(self): + try: + idx = int( + self.session_get_value( + "preventivetype-" + self.url_name, "saisine_type" + ) + ) + return models.SaisineType.objects.get(pk=idx) + except (TypeError, ValueError, models.PermitType.DoesNotExist): + pass + + def get_context_data(self, form, **kwargs): + context = super(FileWizard, self).get_context_data(form) + formplanning = "planningservice-" + self.url_name + forminstruction = "instruction-" + self.url_name + formfinal = "final-" + self.url_name + if self.steps.current == formplanning: + try: + idx = int( + self.session_get_value( + "preventivetype-" + self.url_name, "permit_type" + ) + ) + permit_type = models.PermitType.objects.get(pk=idx) + context["permit_type"] = str(permit_type) + context["permit_type_code"] = str(permit_type.txt_idx) + except (TypeError, ValueError, models.PermitType.DoesNotExist): + pass + elif self.steps.current == forminstruction: + saisine_type = self.get_saisine_type() + context["FILE_PREFIX"] = settings.ISHTAR_FILE_PREFIX + if saisine_type: + context["saisine_type"] = str(saisine_type) + context["saisine_type_message"] = str(saisine_type) + if saisine_type.delay: + context["saisine_type_message"] += str( + _(": delay of {} days") + ).format(saisine_type.delay) + elif self.steps.current == formfinal: + if not self.steps.current.endswith("creation"): # modification only + try: + numeric_reference = int( + self.session_get_value( + "instruction-" + self.url_name, "numeric_reference" + ) + ) + + q = models.File.objects.filter( + numeric_reference=numeric_reference, + year=self.get_current_year(), + ).exclude(pk=self.get_current_object().pk) + context["numeric_reference_files"] = q.all() + except (ValueError, TypeError): + pass + + return context + def done(self, form_list, **kwargs): """ - Save parcels and make numeric_reference unique + Make numeric_reference unique """ r = super(FileWizard, self).done(form_list, return_object=True, **kwargs) if type(r) not in (list, tuple) or len(r) != 2: @@ -77,39 +160,6 @@ class FileWizard(OperationWizard): if changed: obj.numeric_reference = numeric_reference obj.save() - obj.parcels.clear() - for form in form_list: - if ( - not hasattr(form, "prefix") - or not form.prefix.startswith(self.parcel_step_key) - or not hasattr(form, "forms") - ): - continue - for frm in form.forms: - if not frm.is_valid(): - continue - dct = frm.cleaned_data.copy() - if "parcel" in dct: - try: - parcel = Parcel.objects.get(pk=dct["parcel"]) - setattr(parcel, self.object_parcel_type, obj) - parcel.save() - except (ValueError, ObjectDoesNotExist): - continue - continue - try: - dct["town"] = models.Town.objects.get(pk=int(dct["town"])) - except (ValueError, ObjectDoesNotExist, KeyError): - continue - dct["associated_file"], dct["operation"] = None, None - dct[self.object_parcel_type] = obj - if "DELETE" in dct: - dct.pop("DELETE") - parcel = Parcel.objects.filter(**dct).count() - if not parcel: - dct["history_modifier"] = self.request.user - parcel = Parcel(**dct) - parcel.save() return res |