#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2010-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. """ Finds forms definitions """ import logging from django import forms from django.core import validators from django.core.exceptions import PermissionDenied from django.db.models import Q from django.forms.formsets import formset_factory from ishtar_common.utils import ugettext_lazy as _ from . import models from archaeological_operations.models import CulturalAttributionType from archaeological_context_records.models import ( DatingType, DatingQuality, ContextRecord, RelationType as CRRelationType, Dating, ) from archaeological_finds.forms_treatments import ( TreatmentSelect, TreatmentFormSelection, BaseTreatmentForm, TreatmentModifyForm, AdministrativeActTreatmentForm, TreatmentFormFileChoice, TreatmentDeletionForm, TreatmentFileSelect, TreatmentFileFormSelection, TreatmentFileForm, TreatmentFileModifyForm, TreatmentFileDeletionForm, TreatmentFileFormSelectionMultiple, AdministrativeActTreatmentFormSelection, AdministrativeActTreatmentModifForm, AdministrativeActTreatmentFileForm, AdministrativeActTreatmentFileFormSelection, AdministrativeActTreatmentFileModifForm, N1TreatmentForm, QAFindTreatmentForm, OneNTreatmentForm, ) from archaeological_operations.models import ( Period, ArchaeologicalSite, RelationType as OpeRelationType, ) from archaeological_operations.widgets import OAWidget from archaeological_warehouse.models import Warehouse, Container from bootstrap_datepicker.widgets import DatePicker from ishtar_common import widgets from ishtar_common.forms import ( CustomForm, CustomFormSearch, FormSet, FloatField, reverse_lazy, TableSelect, get_now, FinalForm, ManageOldType, FieldType, IshtarForm, FormHeader, QAForm, MultiSearchForm, LockForm, GeoItemSelect, ) from ishtar_common.forms_common import get_town_field from archaeological_context_records.forms import PeriodSelect from ishtar_common.models import ( valid_id, valid_ids, get_current_profile, SpatialReferenceSystem, Area, OperationType, IshtarUser, Person, person_type_pks_lazy, ) from ishtar_common.utils import convert_coordinates_to_point __all__ = [ "TreatmentSelect", "TreatmentFormSelection", "BaseTreatmentForm", "TreatmentModifyForm", "AdministrativeActTreatmentForm", "TreatmentFormFileChoice", "TreatmentDeletionForm", "AdministrativeActTreatmentModifForm", "TreatmentFileSelect", "TreatmentFileFormSelection", "TreatmentFileForm", "TreatmentFileModifyForm", "TreatmentFileDeletionForm", "AdministrativeActTreatmentFileForm", "AdministrativeActTreatmentFileFormSelection", "AdministrativeActTreatmentFormSelection", "AdministrativeActTreatmentFileModifForm", "RecordFormSelection", "FindForm", "SimpleFindForm", "DateForm", "DatingFormSet", "PreservationForm", "FindBasketFormSelection", "FindBasketForWriteFormSelection", "FindBasketForm", "FindSelect", "FindFormSelection", "FindFormSelectionWarehouseModule", "MultipleFindFormSelection", "MultipleFindFormSelectionWarehouseModule", "FindMultipleFormSelection", "check_form", "check_exist", "check_not_exist", "check_value", "check_type_field", "check_type_not_field", "check_treatment", "ResultFindForm", "ResultFindFormSet", "FindDeletionForm", "UpstreamFindFormSelection", "NewFindBasketForm", "SelectFindBasketForm", "SelectFindBasketWriteForm", "FindBasketAddItemForm", "QAFindFormSingle", "QAFindFormMulti", "QAFindBasketForm", "QAFindTreatmentForm", "QAFindbasketDuplicateForm", "N1TreatmentForm", "OneNTreatmentForm", "ResultingFindForm", "ResultingFindsForm", "SingleUpstreamFindFormSelection", ] logger = logging.getLogger(__name__) class RecordFormSelection(CustomForm, forms.Form): form_label = _("Context record") form_admin_name = _("Find - 010 - Context record choice") form_slug = "find-010-contextrecord" base_models = ["get_first_base_find"] associated_models = {"get_first_base_find__context_record": ContextRecord} get_first_base_find__context_record = forms.IntegerField( label=_("Context record"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-contextrecord"), associated_model=ContextRecord ), validators=[valid_id(ContextRecord)], ) def __init__(self, *args, **kwargs): super(RecordFormSelection, self).__init__(*args, **kwargs) # get the current operation and restrict search to it cr_pk = None if "data" in kwargs and kwargs["data"]: cr_pk = kwargs["data"].get("get_first_base_find__context_record") if not cr_pk and "initial" in kwargs and kwargs["initial"]: cr_pk = kwargs["initial"].get("get_first_base_find__context_record") if not cr_pk: return try: cr = ContextRecord.objects.get(pk=cr_pk) except ContextRecord.DoesNotExist: return widget = self.fields["get_first_base_find__context_record"].widget widget.source = str(widget.source) + "?operation__pk={}".format(cr.operation.pk) class BasicFindForm(CustomForm, ManageOldType): """ Basic find form with no field related to base_find """ file_upload = True form_label = _("Find") form_admin_name = _("Simple find - 020 - General") form_slug = "simplefind-020-general" base_models = [ "object_type", "material_type", "communicabilitie", "cultural_attribution", "functional_area", ] associated_models = { "material_type": models.MaterialType, "cultural_attribution": CulturalAttributionType, "object_type": models.ObjectType, "functional_area": models.FunctionalArea, "communicabilitie": models.CommunicabilityType, "material_type_quality": models.MaterialTypeQualityType, "object_type_quality": models.ObjectTypeQualityType, "checked_type": models.CheckedType, #'collection': Warehouse, } field_order = [ "label", "denomination", "previous_id", "museum_id", "laboratory_id", "seal_number", "mark", "description", "public_description", "is_complete", "material_type", "material_type_quality", "material_comment", "object_type", "object_type_quality", "functional_area", "find_number", "min_number_of_individuals", "decoration", "inscription", "manufacturing_place", "communicabilitie", "comment", "cultural_attribution", "dating_comment", "length", "width", "height", "thickness", "diameter", "circumference", "volume", "weight", "clutter_long_side", "clutter_short_side", "clutter_height", "dimensions_comment", "checked_type", "check_date", ] HEADERS = {} HEADERS["label"] = FormHeader(_("Identification")) label = forms.CharField( label=_("Free ID"), validators=[validators.MaxLengthValidator(60)] ) denomination = forms.CharField(label=_("Denomination"), required=False) previous_id = forms.CharField(label=_("Previous ID"), required=False) museum_id = forms.CharField(label=_("Museum ID"), required=False) laboratory_id = forms.CharField(label=_("Laboratory ID"), required=False) seal_number = forms.CharField(label=_("Seal number"), required=False) mark = forms.CharField(label=_("Mark"), required=False) # collection = forms.IntegerField( # label=_("Collection (warehouse)"), # widget=widgets.JQueryAutoComplete( # reverse_lazy('autocomplete-warehouse'), # associated_model=Warehouse, new=True), # validators=[valid_id(Warehouse)], required=False) HEADERS["description"] = FormHeader(_("Description")) description = forms.CharField( label=_("Description"), widget=forms.Textarea, required=False ) public_description = forms.CharField( label=_("Public description"), widget=forms.Textarea, required=False ) is_complete = forms.NullBooleanField(label=_("Is complete?"), required=False) material_type = widgets.Select2MultipleField( label=_("Material types"), required=False ) material_type_quality = forms.ChoiceField( label=_("Material type quality"), required=False, choices=[] ) material_comment = forms.CharField( label=_("Comment on the material"), required=False, widget=forms.Textarea ) object_type = widgets.Select2MultipleField( label=_("Object types"), required=False, ) object_type_quality = forms.ChoiceField( label=_("Object type quality"), required=False, choices=[] ) functional_area = widgets.Select2MultipleField( label=_("Functional areas"), required=False, ) find_number = forms.IntegerField(label=_("Find number"), required=False) min_number_of_individuals = forms.IntegerField( label=_("Minimum number of individuals (MNI)"), required=False ) decoration = forms.CharField( label=_("Decoration"), widget=forms.Textarea, required=False ) inscription = forms.CharField( label=_("Inscription"), widget=forms.Textarea, required=False ) manufacturing_place = forms.CharField( label=_("Manufacturing place"), required=False ) communicabilitie = widgets.Select2MultipleField( label=_("Communicability"), required=False ) comment = forms.CharField(label=_("Comment"), required=False, widget=forms.Textarea) cultural_attribution = widgets.Select2MultipleField( label=_("Cultural attribution"), required=False, ) dating_comment = forms.CharField( label=_("Comment on dating"), required=False, widget=forms.Textarea ) HEADERS["length"] = FormHeader(_("Dimensions")) length = FloatField( label=_("Length (cm)"), widget=widgets.CentimeterMeterWidget, required=False ) width = FloatField( label=_("Width (cm)"), required=False, widget=widgets.CentimeterMeterWidget ) height = FloatField( label=_("Height (cm)"), widget=widgets.CentimeterMeterWidget, required=False ) thickness = FloatField( label=_("Thickness (cm)"), widget=widgets.CentimeterMeterWidget, required=False ) diameter = FloatField( label=_("Diameter (cm)"), widget=widgets.CentimeterMeterWidget, required=False ) circumference = FloatField( label=_("Circumference (cm)"), widget=widgets.CentimeterMeterWidget, required=False, ) volume = FloatField(label=_("Volume (l)"), required=False) weight = FloatField( label=_("Weight (g)"), widget=widgets.GramKilogramWidget, required=False ) clutter_long_side = FloatField( label=_("Clutter long side (cm)"), widget=widgets.CentimeterMeterWidget, required=False, ) clutter_short_side = FloatField( label=_("Clutter short side (cm)"), widget=widgets.CentimeterMeterWidget, required=False, ) clutter_height = FloatField( label=_("Clutter height (cm)"), widget=widgets.CentimeterMeterWidget, required=False, ) dimensions_comment = forms.CharField( label=_("Dimensions comment"), required=False, widget=forms.Textarea ) HEADERS["checked_type"] = FormHeader(_("Sheet")) checked_type = forms.ChoiceField(label=_("Check"), required=False) check_date = forms.DateField( initial=get_now, label=_("Check date"), widget=DatePicker ) TYPES = [ FieldType( "material_type", models.MaterialType, is_multiple=True, extra_args={"full_hierarchy": True}, ), FieldType("cultural_attribution", CulturalAttributionType, is_multiple=True), FieldType("material_type_quality", models.MaterialTypeQualityType), FieldType( "object_type", models.ObjectType, is_multiple=True, extra_args={"full_hierarchy": True}, ), FieldType("object_type_quality", models.ObjectTypeQualityType), FieldType("functional_area", models.FunctionalArea, is_multiple=True), FieldType("communicabilitie", models.CommunicabilityType, is_multiple=True), FieldType("checked_type", models.CheckedType, is_multiple=True), ] def __init__(self, *args, **kwargs): context_record = kwargs.pop("context_record") super(BasicFindForm, self).__init__(*args, **kwargs) if not context_record or not context_record.operation.operation_type.judiciary: self.fields.pop("seal_number") def clean(self): clutter_long_side = self.cleaned_data.get("clutter_long_side", None) clutter_short_side = self.cleaned_data.get("clutter_short_side", None) if ( clutter_long_side and clutter_short_side and clutter_short_side > clutter_long_side ): raise forms.ValidationError( str(_("Clutter: short side cannot be bigger than the long side.")) ) return self.cleaned_data class FindForm(BasicFindForm): file_upload = True form_label = _("Find") form_admin_name = _("Find - 020 - General") form_slug = "find-020-general" base_models = ["get_first_base_find"] + BasicFindForm.base_models associated_models = BasicFindForm.associated_models.copy() associated_models.update( { "get_first_base_find__batch": models.BatchType, "get_first_base_find__spatial_reference_system": SpatialReferenceSystem, } ) field_order = [ "label", "denomination", "previous_id", "get_first_base_find__excavation_id", "museum_id", "laboratory_id", "seal_number", "mark", "description", "public_description", "get_first_base_find__discovery_date", "get_first_base_find__discovery_date_taq", "get_first_base_find__batch", "is_complete", "material_type", "material_type_quality", "material_comment", "object_type", "object_type_quality", "functional_area", "find_number", "min_number_of_individuals", "inscription", "decoration", "manufacturing_place", "communicabilitie", "comment", "cultural_attribution", "dating_comment", "length", "width", "height", "thickness", "diameter", "circumference", "volume", "weight", "clutter_long_side", "clutter_short_side", "clutter_height", "dimensions_comment", "get_first_base_find__x", "get_first_base_find__estimated_error_x", "get_first_base_find__y", "get_first_base_find__estimated_error_y", "get_first_base_find__z", "get_first_base_find__estimated_error_z", "get_first_base_find__spatial_reference_system", "get_first_base_find__topographic_localisation", "checked_type", "check_date", ] HEADERS = BasicFindForm.HEADERS.copy() get_first_base_find__excavation_id = forms.CharField( label=_("Excavation ID"), required=False ) get_first_base_find__discovery_date = forms.DateField( label=_("Discovery date (exact or TPQ)"), widget=DatePicker, required=False ) get_first_base_find__discovery_date_taq = forms.DateField( label=_("Discovery date (TAQ)"), widget=DatePicker, required=False ) get_first_base_find__batch = forms.ChoiceField( label=_("Batch/object"), choices=[], required=False ) HEADERS["get_first_base_find__topographic_localisation"] = FormHeader(_("Topography")) get_first_base_find__topographic_localisation = forms.CharField( label=_("Point of topographic reference"), required=False, max_length=120 ) TYPES = BasicFindForm.TYPES + [ FieldType("get_first_base_find__batch", models.BatchType), FieldType( "get_first_base_find__spatial_reference_system", SpatialReferenceSystem ), ] def clean(self): self.cleaned_data = super(FindForm, self).clean() taq = self.cleaned_data.get("get_first_base_find__discovery_date_taq", None) tpq = self.cleaned_data.get("get_first_base_find__discovery_date", None) if taq and not tpq: raise forms.ValidationError( str( _( "Discovery date: if a TAQ date is provided a TPQ date has " "to be informed. If you have a precise date fill only the " "TPQ - discovery date field." ) ) ) elif tpq and taq and taq < tpq: raise forms.ValidationError( str(_("Discovery date: TAQ date must be older than TPQ date.")) ) if not get_current_profile().mapping: return self.cleaned_data x = self.cleaned_data.get("get_first_base_find__x", None) y = self.cleaned_data.get("get_first_base_find__y", None) s = "get_first_base_find__spatial_reference_system" srs = self.cleaned_data.get(s, None) if srs: try: srs = SpatialReferenceSystem.objects.get(pk=srs) except SpatialReferenceSystem.DoesNotExist: srs = None if x and y and not srs: raise forms.ValidationError( _( "You should at least provide X, Y and the spatial " "reference system used." ) ) if x and y and srs: try: convert_coordinates_to_point( x, y, self.cleaned_data.get("get_first_base_find__z", None), srs.srid, ) except forms.ValidationError as e: raise forms.ValidationError( str( _( "Coordinates are not relevant for the spatial " "reference system used: {}." ) ).format(e) ) return self.cleaned_data class SimpleFindForm(BasicFindForm): def __init__(self, *args, **kwargs): self.base_finds = kwargs.pop("base_finds") super(SimpleFindForm, self).__init__(*args, **kwargs) class ResultingFindForm(CustomForm, ManageOldType): file_upload = True form_label = _("Resulting find") form_admin_name = _("Treatment n-1 - 030 - Resulting find") form_slug = "treatmentn1-030-resulting-find" associated_models = { "resulting_material_type": models.MaterialType, "resulting_object_type": models.ObjectType, "resulting_communicabilitie": models.CommunicabilityType, "resulting_material_type_quality": models.MaterialTypeQualityType, "resulting_object_type_quality": models.ObjectTypeQualityType, "resulting_checked_type": models.CheckedType, } HEADERS = {} HEADERS["resulting_label"] = FormHeader(_("Identification")) resulting_label = forms.CharField( label=_("Free ID"), validators=[validators.MaxLengthValidator(60)] ) resulting_denomination = forms.CharField(label=_("Denomination"), required=False) HEADERS["resulting_description"] = FormHeader(_("Description")) resulting_description = forms.CharField( label=_("Description"), widget=forms.Textarea, required=False ) resulting_is_complete = forms.NullBooleanField( label=_("Is complete?"), required=False ) resulting_material_type = widgets.Select2MultipleField( label=_("Material types"), required=False ) resulting_material_type_quality = forms.ChoiceField( label=_("Material type quality"), required=False, choices=[] ) resulting_object_type = widgets.Select2MultipleField( label=_("Object types"), required=False, ) resulting_object_type_quality = forms.ChoiceField( label=_("Object type quality"), required=False, choices=[] ) resulting_find_number = forms.IntegerField(label=_("Find number"), required=False) resulting_min_number_of_individuals = forms.IntegerField( label=_("Minimum number of individuals (MNI)"), required=False ) resulting_decoration = forms.CharField( label=_("Decoration"), widget=forms.Textarea, required=False ) resulting_inscription = forms.CharField( label=_("Inscription"), widget=forms.Textarea, required=False ) resulting_manufacturing_place = forms.CharField( label=_("Manufacturing place"), required=False ) resulting_communicabilitie = widgets.Select2MultipleField( label=_("Communicability"), required=False ) resulting_comment = forms.CharField( label=_("Comment"), required=False, widget=forms.Textarea ) resulting_dating_comment = forms.CharField( label=_("Comment on dating"), required=False, widget=forms.Textarea ) HEADERS["resulting_length"] = FormHeader(_("Dimensions")) resulting_length = FloatField(label=_("Length (cm)"), required=False) resulting_width = FloatField(label=_("Width (cm)"), required=False) resulting_height = FloatField(label=_("Height (cm)"), required=False) resulting_diameter = FloatField(label=_("Diameter (cm)"), required=False) resulting_circumference = FloatField(label=_("Circumference (cm)"), required=False) resulting_thickness = FloatField(label=_("Thickness (cm)"), required=False) resulting_volume = FloatField(label=_("Volume (l)"), required=False) resulting_weight = FloatField(label=_("Weight (g)"), required=False) resulting_clutter_long_side = FloatField( label=_("Clutter long side (cm)"), required=False ) resulting_clutter_short_side = FloatField( label=_("Clutter short side (cm)"), required=False ) resulting_clutter_height = FloatField( label=_("Clutter height (cm)"), required=False ) resulting_dimensions_comment = forms.CharField( label=_("Dimensions comment"), required=False, widget=forms.Textarea ) HEADERS["resulting_checked_type"] = FormHeader(_("Sheet")) resulting_checked_type = forms.ChoiceField(label=_("Check"), required=False) resulting_check_date = forms.DateField( initial=get_now, label=_("Check date"), widget=DatePicker ) TYPES = [ FieldType("resulting_material_type", models.MaterialType, is_multiple=True), FieldType("resulting_material_type_quality", models.MaterialTypeQualityType), FieldType("resulting_object_type", models.ObjectType, is_multiple=True), FieldType("resulting_object_type_quality", models.ObjectTypeQualityType), FieldType( "resulting_communicabilitie", models.CommunicabilityType, is_multiple=True ), FieldType("resulting_checked_type", models.CheckedType, is_multiple=True), ] class ResultingFindsForm(CustomForm, ManageOldType): form_label = _("Resulting finds") form_admin_name = _("Treatment 1-n - 030 - Resulting finds") form_slug = "treatment1n-030-resulting-finds" associated_models = {} resultings_number = forms.IntegerField( label=_("Number of resulting finds"), min_value=1 ) resultings_label = forms.CharField( label=_("Prefix label for resulting finds"), validators=[validators.MaxLengthValidator(200)], help_text=_( 'E.g.: with a prefix "item-", each resulting item will be named ' '"item-1", "item-2", "item-3"' ), ) resultings_start_number = forms.IntegerField( label=_("Numbering starting from"), initial=1, min_value=0 ) resultings_basket_name = forms.CharField( label=_("Name of the new basket containing the resulting items"), max_length=200 ) def __init__(self, *args, **kwargs): self.user = None if "user" in kwargs: self.user = kwargs.pop("user") if hasattr(self.user, "ishtaruser"): self.user = self.user.ishtaruser super(ResultingFindsForm, self).__init__(*args, **kwargs) if not self.user: return def clean(self): q = models.FindBasket.objects.filter( user=self.user, label=self.cleaned_data["resultings_basket_name"] ) if q.count(): raise forms.ValidationError( _("A basket with this label already " "exists.") ) return self.cleaned_data class QAFindFormMulti(QAForm): form_admin_name = _("Find - Quick action - Modify") form_slug = "find-quickaction-modify" base_models = [ "get_first_base_find", "qa_object_types", "qa_functional_areas", "qa_material_types", "qa_communicabilities", "qa_alterations", "qa_alteration_causes", ] associated_models = { "qa_material_types": models.MaterialType, "qa_object_types": models.ObjectType, "qa_functional_areas": models.FunctionalArea, "qa_communicabilities": models.CommunicabilityType, "qa_alterations": models.AlterationType, "qa_alteration_causes": models.AlterationCauseType, "qa_checked_type": models.CheckedType, "qa_period": Period, "qa_conservatory_state": models.ConservatoryState, "qa_treatment_emergency": models.TreatmentEmergencyType, } MULTI = True REPLACE_FIELDS = [ "qa_denomination", "qa_ue", "qa_manufacturing_place", "qa_checked_type", "qa_check_date", "qa_conservatory_state", "qa_treatment_emergency", "qa_appraisal_date", "qa_insurance_value", # 'qa_collection', ] HEADERS = { "qa_ue": FormHeader(_("Context record")), "qa_denomination": FormHeader(_("Identification")), "qa_description": FormHeader(_("Description")), "qa_checked_type": FormHeader(_("Sheet")), "qa_period": FormHeader(_("Datation")), "qa_conservatory_comment": FormHeader(_("Preservation")), } SINGLE_FIELDS = [ "qa_label", "qa_previous_id", "qa_get_first_base_find__excavation_id", "qa_museum_id", "qa_laboratory_id", "qa_seal_number", "qa_mark", ] qa_ue = forms.IntegerField( label=_("Context record"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-contextrecord"), associated_model=ContextRecord ), validators=[valid_id(ContextRecord)], required=False, ) qa_label = forms.CharField( label=_("Free ID"), validators=[validators.MaxLengthValidator(60)], required=False, ) qa_denomination = forms.CharField(label=_("Denomination"), required=False) qa_previous_id = forms.CharField(label=_("Previous ID"), required=False) qa_get_first_base_find__excavation_id = forms.CharField( label=_("Excavation ID"), required=False ) qa_museum_id = forms.CharField(label=_("Museum ID"), required=False) qa_laboratory_id = forms.CharField(label=_("Laboratory ID"), required=False) qa_seal_number = forms.CharField(label=_("Seal number"), required=False) qa_mark = forms.CharField(label=_("Mark"), required=False) # qa_collection = forms.IntegerField( # label=_("Collection"), # widget=widgets.JQueryAutoComplete( # reverse_lazy('autocomplete-warehouse'), # associated_model=Warehouse), # validators=[valid_id(Warehouse)], required=False) qa_description = forms.CharField( label=_("Description"), widget=forms.Textarea, required=False ) qa_material_types = widgets.Select2MultipleField( label=_("Material types"), required=False ) qa_object_types = widgets.Select2MultipleField( label=_("Object types"), required=False, ) qa_functional_areas = widgets.Select2MultipleField( label=_("Functional areas"), required=False, ) qa_manufacturing_place = forms.CharField( label=_("Manufacturing place"), required=False ) qa_communicabilities = widgets.Select2MultipleField( label=_("Communicability"), required=False ) qa_alterations = widgets.Select2MultipleField(label=_("Alteration"), required=False) qa_alteration_causes = widgets.Select2MultipleField( label=_("Alteration cause"), required=False ) qa_conservatory_state = forms.ChoiceField( label=_("Conservatory state"), required=False, choices=[] ) qa_treatment_emergency = forms.ChoiceField( label=_("Treatment emergency"), choices=[], required=False ) qa_remarkabilities = widgets.Select2MultipleField( label=_("Remarkability"), required=False ) qa_comment = forms.CharField( label=_("Comment"), required=False, widget=forms.Textarea ) qa_checked_type = forms.ChoiceField(label=_("Check"), required=False) qa_check_date = forms.DateField( label=_("Check date"), widget=DatePicker, required=False ) qa_appraisal_date = forms.DateField( label=_("Appraisal date"), widget=DatePicker, required=False ) qa_insurance_value = forms.FloatField(label=_("Insurance value"), required=False) qa_period = widgets.Select2MultipleField( label=_("Period"), choices=[], required=False ) qa_dating_comment = forms.CharField( label=_("Comment on dating"), required=False, widget=forms.Textarea ) qa_conservatory_comment = forms.CharField( label=_("Comment on conservatory"), required=False, widget=forms.Textarea ) TYPES = [ FieldType("qa_material_types", models.MaterialType, is_multiple=True), FieldType("qa_object_types", models.ObjectType, is_multiple=True), FieldType("qa_functional_areas", models.FunctionalArea, is_multiple=True), FieldType("qa_communicabilities", models.CommunicabilityType, is_multiple=True), FieldType("qa_alterations", models.AlterationType, is_multiple=True), FieldType("qa_alteration_causes", models.AlterationCauseType, is_multiple=True), FieldType("qa_remarkabilities", models.RemarkabilityType, is_multiple=True), FieldType("qa_checked_type", models.CheckedType), FieldType("qa_conservatory_state", models.ConservatoryState), FieldType("qa_treatment_emergency", models.TreatmentEmergencyType), FieldType("qa_period", Period, is_multiple=True), ] def __init__(self, *args, **kwargs): super(QAFindFormMulti, self).__init__(*args, **kwargs) if "qa_insurance_value" in self.fields: self.fields["qa_insurance_value"].label = "{} ({})".format( str(self.fields["qa_insurance_value"].label), get_current_profile().currency, ) def _get_qa_ue(self, value): try: value = ContextRecord.objects.get(pk=value).cached_label except ContextRecord.DoesNotExist: return "" return value # def _get_qa_collection(self, value): # try: # value = Warehouse.objects.get(pk=value).name # except Warehouse.DoesNotExist: # return "" # return value def _set_qa_ue(self, item, user): ue = self.cleaned_data["qa_ue"] if not ue: return cr = ContextRecord.objects.get(pk=ue) bf = item.get_first_base_find() bf.context_record = cr bf.history_modifier = user bf.save() def _set_qa_period(self, item, user): periods = self.cleaned_data["qa_period"] if not periods: return for period in periods: if Dating.objects.filter(find=item, period__pk=period).count(): continue d = Dating.objects.create(period_id=period) item.datings.add(d) class QAFindFormSingle(QAFindFormMulti): MULTI = False form_admin_name = _("Find - Quick action - Modify single") form_slug = "find-quickaction-modifysingle" def __init__(self, *args, **kwargs): super(QAFindFormSingle, self).__init__(*args, **kwargs) if ( not self.items or not self.items[0] .get_first_base_find() .context_record.operation.operation_type.judiciary ): self.fields.pop("qa_seal_number") class QAFindBasketForm(IshtarForm): qa_bf_create_or_update = forms.ChoiceField( choices=(("create", _("Create")), ("update", _("Update"))), initial="create" ) qa_bf_label = forms.CharField(label="", max_length=None, required=False) qa_bf_basket = forms.IntegerField( label=_("Basket"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-findbasket-write"), associated_model=models.FindBasket, ), validators=[valid_id(models.FindBasket)], required=False, ) def __init__(self, *args, **kwargs): self.user = None if "user" in kwargs: self.user = kwargs.pop("user") if hasattr(self.user, "ishtaruser"): self.user = self.user.ishtaruser self.items = kwargs.pop("items") super(QAFindBasketForm, self).__init__(*args, **kwargs) def clean(self): if self.cleaned_data["qa_bf_create_or_update"] == "update": if not self.cleaned_data["qa_bf_basket"]: raise forms.ValidationError( _("On update, you have to select a basket.") ) q = Q(user=self.user) | Q(shared_write_with__pk=self.user.pk) q = models.FindBasket.objects.filter(q).filter( pk=self.cleaned_data["qa_bf_basket"] ) if not q.count(): raise forms.ValidationError(_("You cannot update the selected basket.")) return self.cleaned_data label = self.cleaned_data["qa_bf_label"].strip() if not label: raise forms.ValidationError(_("A label is required.")) if models.FindBasket.objects.filter(user=self.user, label=label).count(): raise forms.ValidationError( _("A basket with this label already " "exists.") ) return self.cleaned_data def save(self, items): if self.cleaned_data["qa_bf_create_or_update"] == "update": q = Q(user=self.user) | Q(shared_write_with__pk=self.user.pk) basket = ( models.FindBasket.objects.filter(q) .distinct() .get(pk=self.cleaned_data["qa_bf_basket"]) ) else: label = self.cleaned_data["qa_bf_label"].strip() basket = models.FindBasket.objects.create(user=self.user, label=label) for item in items: basket.items.add(item) class QAFindDuplicateForm(IshtarForm): label = forms.CharField(label=_("Free ID"), max_length=None, required=True) denomination = forms.CharField( label=_("Denomination"), max_length=None, required=False ) # modify = forms.BooleanField(label=_("Edit the new find"), required=False) def __init__(self, *args, **kwargs): self.user = None if "user" in kwargs: self.user = kwargs.pop("user") if hasattr(self.user, "ishtaruser"): self.user = self.user.ishtaruser self.find = kwargs.pop("items")[0] super(QAFindDuplicateForm, self).__init__(*args, **kwargs) self.fields["label"].initial = self.find.label + str(_(" - duplicate")) self.fields["denomination"].initial = self.find.denomination or "" def save(self): return self.find.duplicate( self.user, duplicate_for_treatment=False, data={ "label": self.cleaned_data["label"], "denomination": self.cleaned_data["denomination"], }, ) class QAFindbasketDuplicateForm(IshtarForm): label = forms.CharField(label="", max_length=None, required=True) def __init__(self, *args, **kwargs): self.user = None if "user" in kwargs: self.user = kwargs.pop("user") if hasattr(self.user, "ishtaruser"): self.user = self.user.ishtaruser self.basket = kwargs.pop("items")[0] super(QAFindbasketDuplicateForm, self).__init__(*args, **kwargs) self.fields["label"].initial = self.basket.label + str(_(" - duplicate")) def clean(self): label = self.cleaned_data["label"].strip() if not label: raise forms.ValidationError(_("A label is required.")) if models.FindBasket.objects.filter(user=self.user, label=label).count(): raise forms.ValidationError( _("A basket with this label already " "exists.") ) return self.cleaned_data def save(self): self.basket.duplicate(label=self.cleaned_data["label"], ishtaruser=self.user) class QAFindBasketModify(QAForm): form_admin_name = _("Find - Quick action - Modify") form_slug = "findbasket-quickaction-modify" MULTI = True SINGLE_FIELDS = ["qa_slug"] qa_label = forms.CharField( label="Denomination", validators=[validators.MaxLengthValidator(1000)], required=False ) qa_slug = forms.SlugField(label=_("Slug"), required=False) qa_public = forms.BooleanField(label=_("Is public"), required=False) qa_comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False) qa_shared_with = widgets.Select2MultipleField( model=IshtarUser, remote=True, label=_("Shared (read) with"), required=False, long_widget=True, ) qa_shared_write_with = widgets.Select2MultipleField( model=IshtarUser, remote=True, label=_("Shared (read/edit) with"), required=False, long_widget=True, ) REPLACE_FIELDS = [ "qa_label", "qa_slug", "qa_public", ] def _get_ishtar_user_list(self, value): if not isinstance(value, list): value = [value] values = [] for v in value: try: values.append(str(IshtarUser.objects.get(pk=v))) except IshtarUser.DoesNotExist: pass return " ; ".join(values) def _get_qa_shared_with(self, value): return self._get_ishtar_user_list(value) def _get_qa_shared_write_with(self, value): return self._get_ishtar_user_list(value) class PreservationForm(CustomForm, ManageOldType): form_label = _("Preservation") form_admin_name = _("Find - 030 - Preservation") form_slug = "find-030-preservation" base_models = [ "alteration", "alteration_cause", "preservation_to_consider", "integritie", "remarkabilitie", ] associated_models = { "alteration": models.AlterationType, "alteration_cause": models.AlterationCauseType, "treatment_emergency": models.TreatmentEmergencyType, "conservatory_state": models.ConservatoryState, "preservation_to_consider": models.TreatmentType, "remarkabilitie": models.RemarkabilityType, "integritie": models.IntegrityType, } integritie = forms.MultipleChoiceField( label=_("Integrity / interest"), choices=[], widget=widgets.Select2Multiple, required=False, ) remarkabilitie = forms.MultipleChoiceField( label=_("Remarkability"), choices=[], widget=widgets.Select2Multiple, required=False, ) conservatory_state = forms.ChoiceField( label=_("Conservatory state"), choices=[], required=False ) alteration = forms.MultipleChoiceField( label=_("Alteration"), choices=[], widget=widgets.Select2Multiple, required=False, ) alteration_cause = forms.MultipleChoiceField( label=_("Alteration cause"), choices=[], widget=widgets.Select2Multiple, required=False, ) preservation_to_consider = forms.MultipleChoiceField( label=_("Recommended treatments"), choices=[], widget=widgets.Select2Multiple, required=False, ) treatment_emergency = forms.ChoiceField( label=_("Treatment emergency"), choices=[], required=False ) estimated_value = FloatField(label=_("Estimated value"), required=False) insurance_value = FloatField(label=_("Insurance value"), required=False) appraisal_date = forms.DateField( label=_("Appraisal date"), widget=DatePicker, required=False ) conservatory_comment = forms.CharField( label=_("Conservatory comment"), required=False, widget=forms.Textarea ) TYPES = [ FieldType("conservatory_state", models.ConservatoryState), FieldType("treatment_emergency", models.TreatmentEmergencyType), FieldType("preservation_to_consider", models.TreatmentType, True), FieldType("alteration", models.AlterationType, True), FieldType("alteration_cause", models.AlterationCauseType, True), FieldType("integritie", models.IntegrityType, is_multiple=True), FieldType("remarkabilitie", models.RemarkabilityType, is_multiple=True), ] def __init__(self, *args, **kwargs): super(PreservationForm, self).__init__(*args, **kwargs) if "insurance_value" in self.fields: self.fields["insurance_value"].label = "{} ({})".format( str(self.fields["insurance_value"].label), get_current_profile().currency, ) if "estimated_value" in self.fields: self.fields["estimated_value"].label = "{} ({})".format( str(self.fields["estimated_value"].label), get_current_profile().currency, ) class DateForm(ManageOldType, forms.Form): form_label = _("Dating") base_model = "dating" associated_models = { "dating_type": DatingType, "quality": DatingQuality, "period": Period, } period = forms.ChoiceField(label=_("Period"), choices=[]) dating_type = forms.ChoiceField(label=_("Dating type"), required=False, choices=[]) start_date = forms.IntegerField(label=_("Start date"), required=False) end_date = forms.IntegerField(label=_("End date"), required=False) quality = forms.ChoiceField(label=_("Quality"), required=False, choices=[]) precise_dating = forms.CharField(label=_("Precise dating"), required=False) TYPES = [ FieldType("dating_type", DatingType), FieldType("period", Period), FieldType("quality", DatingQuality), ] DatingFormSet = formset_factory(DateForm, can_delete=True, formset=FormSet) DatingFormSet.form_label = _("Dating") DatingFormSet.form_admin_name = _("Find - 040 - Dating") DatingFormSet.form_slug = "find-040-dating" class FindSelect(GeoItemSelect, PeriodSelect): _model = models.Find form_admin_name = _("Find - 001 - Search") form_slug = "find-001-search" FORM_FILTERS = [ ( _("Find origin"), [ "base_finds__cache_short_id", "base_finds__cache_complete_id", "base_finds__context_record__town", "base_finds__context_record__operation__year", "base_finds__context_record__operation__operation_code", "base_finds__context_record__operation__code_patriarche", "base_finds__context_record__operation__operation_type", "base_finds__context_record__operation__person_in_charge", "base_finds__context_record__operation__common_name" "base_finds__context_record__operation__operator", "base_finds__context_record__operation__address", "base_finds__context_record__town__areas", "archaeological_sites", "archaeological_sites_context_record", "base_finds__context_record", "ope_relation_types", "cr_relation_types", ], ), ( _("Discovery date"), [ "base_finds__discovery_date__before", "base_finds__discovery_date__after", "base_finds__discovery_date_tpq__before", "base_finds__discovery_date_tpq__after", "base_finds__discovery_date_taq__before", "base_finds__discovery_date_taq__after", ], ), ( _("Dimensions"), [ "length__higher", "width__higher", "height__higher", "thickness__higher", "diameter__higher", "circumference__higher", "volume__higher", "weight__higher", "clutter_long_side__higher", "clutter_short_side__higher", "clutter_height__higher", "length__lower", "width__lower", "height__lower", "thickness__lower", "diameter__lower", "circumference__lower", "volume__lower", "weight__lower", "clutter_long_side__lower", "clutter_short_side__lower", "clutter_height__lower", "dimensions_comment", ], ), ( _("Preservation"), ( "integrities", "remarkabilities", "conservatory_state", "conservatory_comment", "alterations", "alteration_causes", "preservation_to_considers", "treatment_emergency", ), ), ] search_vector = forms.CharField( label=_("Full text search"), widget=widgets.SearchWidget("archaeological-finds", "find"), ) label = forms.CharField(label=_("Free ID")) denomination = forms.CharField(label=_("Denomination")) previous_id = forms.CharField(label=_("Previous ID")) base_finds__excavation_id = forms.CharField(label=_("Excavation ID")) seal_number = forms.CharField(label=_("Seal number")) museum_id = forms.CharField(label=_("Museum ID")) laboratory_id = forms.CharField(label=_("Laboratory ID")) mark = forms.CharField(label=_("Mark")) base_finds__cache_short_id = forms.CharField(label=_("Base find - Short ID")) base_finds__cache_complete_id = forms.CharField(label=_("Base find - Complete ID")) base_finds__context_record__town = get_town_field() base_finds__context_record__operation__year = forms.IntegerField(label=_("Year")) base_finds__context_record__operation__operation_code = forms.IntegerField( label=_("Operation's number (index by year)") ) base_finds__context_record__operation__code_patriarche = forms.IntegerField( label=_("Code PATRIARCHE"), widget=OAWidget ) base_finds__context_record__operation__operation_type = forms.ChoiceField( label=_("Operation type"), choices=[] ) base_finds__context_record__operation__address = forms.CharField( label=_("Operation - Address / Locality") ) base_finds__context_record__operation__in_charge = forms.IntegerField( label=_("Operation - In charge"), widget=widgets.JQueryAutoComplete(reverse_lazy("autocomplete-person")), ) base_finds__context_record__operation__scientist = forms.IntegerField( widget=widgets.JQueryAutoComplete( reverse_lazy( "autocomplete-person-permissive", args=[person_type_pks_lazy(["sra_agent", "head_scientist"])], ), associated_model=Person, ), label=_("Operation - Scientist in charge"), ) base_finds__context_record__operation__operator = forms.IntegerField( label=_("Operation - Operator"), widget=widgets.JQueryAutoComplete(reverse_lazy("autocomplete-organization")), ) base_finds__context_record__operation__common_name = forms.CharField( label=_("Operation - Name"), ) base_finds__context_record__town__areas = forms.ChoiceField( label=_("Areas"), choices=[] ) archaeological_sites = forms.IntegerField( label=_("Archaeological site (attached to the operation)"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-archaeologicalsite"), associated_model=ArchaeologicalSite, ), validators=[valid_id(ArchaeologicalSite)], ) archaeological_sites_name = forms.CharField( label=_("Archaeological site name (attached to the operation)") ) archaeological_sites_context_record = forms.IntegerField( label=_("Archaeological site (attached to the context record)"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-archaeologicalsite"), associated_model=ArchaeologicalSite, ), validators=[valid_id(ArchaeologicalSite)], ) archaeological_sites_context_record_name = forms.CharField( label=_("Archaeological site name (attached to the context record)") ) base_finds__context_record = forms.IntegerField( label=_("Context record"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-contextrecord"), associated_model=ContextRecord ), validators=[valid_id(ContextRecord)], ) ope_relation_types = forms.ChoiceField( label=_("Search within related operations"), choices=[] ) cr_relation_types = forms.ChoiceField( label=_("Search within related context records"), choices=[] ) basket = forms.IntegerField( label=_("Basket"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-findbasket"), associated_model=models.FindBasket ), validators=[valid_id(models.FindBasket)], ) description = forms.CharField(label=_("Description")) base_finds__discovery_date__after = forms.DateField( label=_("Discovery date after"), widget=DatePicker ) base_finds__discovery_date__before = forms.DateField( label=_("Discovery date before"), widget=DatePicker ) base_finds__discovery_date_tpq__after = forms.DateField( label=_("Discovery date (exact or TPQ) after"), widget=DatePicker ) base_finds__discovery_date_tpq__before = forms.DateField( label=_("Discovery date (exact or TPQ) before"), widget=DatePicker ) base_finds__discovery_date_taq__after = forms.DateField( label=_("Discovery date (TAQ) after"), widget=DatePicker ) base_finds__discovery_date_taq__before = forms.DateField( label=_("Discovery date (TAQ) before"), widget=DatePicker ) base_finds__batch = forms.ChoiceField(label=_("Batch/object"), choices=[]) is_complete = forms.NullBooleanField(label=_("Is complete?")) material_types = forms.IntegerField( label=_("Material type"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-materialtype"), associated_model=models.MaterialType, ), ) material_type_quality = forms.ChoiceField( label=_("Material type quality"), choices=[] ) material_comment = forms.CharField(label=_("Comment on the material")) object_types = forms.IntegerField( label=_("Object type"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-objecttype"), associated_model=models.ObjectType ), ) object_type_quality = forms.ChoiceField(label=_("Object type quality"), choices=[]) functional_areas = forms.IntegerField( label=_("Functional areas"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-functionalarea"), associated_model=models.FunctionalArea, ), ) find_number = forms.IntegerField(label=_("Find number")) min_number_of_individuals = forms.IntegerField( label=_("Minimum number of individuals (MNI)") ) manufacturing_place = forms.CharField(label=_("Manufacturing place")) decoration = forms.CharField(label=_("Decoration")) inscription = forms.CharField(label=_("Inscription")) communicabilities = forms.ChoiceField(label=_("Communicability")) comment = forms.CharField(label=_("Comment")) cultural_attributions = forms.ChoiceField( label=_("Cultural attribution"), choices=[], required=False ) dating_comment = forms.CharField(label=_("Comment on dating")) length__higher = FloatField( label=_("Length - higher than (cm)"), widget=widgets.CentimeterMeterWidget ) length__lower = FloatField( label=_("Length - lower than (cm)"), widget=widgets.CentimeterMeterWidget ) width__lower = FloatField( label=_("Width - lower than (cm)"), widget=widgets.CentimeterMeterWidget ) width__higher = FloatField( label=_("Width - higher than (cm)"), widget=widgets.CentimeterMeterWidget ) height__lower = FloatField( label=_("Height - lower than (cm)"), widget=widgets.CentimeterMeterWidget ) height__higher = FloatField( label=_("Height - higher than (cm)"), widget=widgets.CentimeterMeterWidget ) thickness__lower = FloatField( label=_("Thickness - lower than (cm)"), widget=widgets.CentimeterMeterWidget ) thickness__higher = FloatField( label=_("Thickness - higher than (cm)"), widget=widgets.CentimeterMeterWidget ) diameter__lower = FloatField( label=_("Diameter - lower than (cm)"), widget=widgets.CentimeterMeterWidget ) diameter__higher = FloatField( label=_("Diameter - higher than (cm)"), widget=widgets.CentimeterMeterWidget ) circumference__lower = FloatField( label=_("Circumference - lower than (cm)"), widget=widgets.CentimeterMeterWidget ) circumference__higher = FloatField( label=_("Circumference - higher than (cm)"), widget=widgets.CentimeterMeterWidget, ) volume__lower = FloatField(label=_("Volume - lower than (l)")) volume__higher = FloatField(label=_("Volume - higher than (l)")) weight__lower = FloatField( label=_("Weight - lower than (g)"), widget=widgets.GramKilogramWidget ) weight__higher = FloatField( label=_("Weight - higher than (g)"), widget=widgets.GramKilogramWidget ) clutter_long_side__lower = FloatField( label=_("Clutter long side - lower than (cm)"), widget=widgets.CentimeterMeterWidget, ) clutter_long_side__higher = FloatField( label=_("Clutter long side - higher than (cm)"), widget=widgets.CentimeterMeterWidget, ) clutter_short_side__lower = FloatField( label=_("Clutter short side - lower than (cm)"), widget=widgets.CentimeterMeterWidget, ) clutter_short_side__higher = FloatField( label=_("Clutter short side - higher than (cm)"), widget=widgets.CentimeterMeterWidget, ) clutter_height__lower = FloatField( label=_("Clutter height - lower than (cm)"), widget=widgets.CentimeterMeterWidget, ) clutter_height__higher = FloatField( label=_("Clutter height - higher than (cm)"), widget=widgets.CentimeterMeterWidget, ) dimensions_comment = forms.CharField(label=_("Dimensions comment")) base_finds__topographic_localisation = forms.CharField( label=_("Point of topographic reference"), ) checked_type = forms.ChoiceField(label=_("Check")) check_date__after = forms.DateField(label=_("Check date after"), widget=DatePicker) check_date__before = forms.DateField( label=_("Check date before"), widget=DatePicker ) integrities = forms.ChoiceField(label=_("Integrity / interest"), choices=[]) remarkabilities = forms.ChoiceField(label=_("Remarkability"), choices=[]) conservatory_state = forms.ChoiceField(label=_("Conservatory state"), choices=[]) conservatory_comment = forms.CharField(label=_("Conservatory comment")) alterations = forms.ChoiceField(label=_("Alteration"), choices=[]) alteration_causes = forms.ChoiceField(label=_("Alteration cause"), choices=[]) preservation_to_considers = forms.ChoiceField( choices=[], label=_("Recommended treatments") ) treatment_emergency = forms.ChoiceField(choices=[], label=_("Treatment emergency")) estimated_value__higher = FloatField(label=_("Estimated value - higher than")) estimated_value__lower = FloatField(label=_("Estimated value - lower than")) insurance_value__higher = FloatField(label=_("Insurance value - higher than")) insurance_value__lower = FloatField(label=_("Insurance value - lower than")) appraisal_date__after = forms.DateField( label=_("Appraisal date after"), widget=DatePicker ) appraisal_date__before = forms.DateField( label=_("Appraisal date before"), widget=DatePicker ) loan = forms.NullBooleanField(label=_("Loan?")) treatments_file_end_date = forms.DateField( label=_("Treatment file end date before"), widget=DatePicker ) treatments_end_date = forms.DateField( label=_("Treatment end date before"), widget=DatePicker ) TYPES = PeriodSelect.TYPES + [ FieldType("conservatory_state", models.ConservatoryState), FieldType("base_finds__batch", models.BatchType), FieldType("preservation_to_considers", models.TreatmentType), FieldType("integrities", models.IntegrityType), FieldType("remarkabilities", models.RemarkabilityType), FieldType("base_finds__context_record__town__areas", Area), FieldType( "base_finds__context_record__operation__operation_type", OperationType ), FieldType("checked_type", models.CheckedType), FieldType("material_type_quality", models.MaterialTypeQualityType), FieldType("object_type_quality", models.ObjectTypeQualityType), FieldType("communicabilities", models.CommunicabilityType), FieldType("alterations", models.AlterationType), FieldType("alteration_causes", models.AlterationCauseType), FieldType("treatment_emergency", models.TreatmentEmergencyType), FieldType("cultural_attributions", CulturalAttributionType), ] + GeoItemSelect.TYPES SITE_KEYS = { "archaeological_sites": "attached-to-operation", "archaeological_sites_name": "name-attached-to-operation", "archaeological_sites_context_record": "attached-to-cr", "archaeological_sites_context_record_name": "name-attached-to-cr", } def __init__(self, *args, **kwargs): super(FindSelect, self).__init__(*args, **kwargs) if "ope_relation_types" in self.fields: self.fields["ope_relation_types"].choices = OpeRelationType.get_types() if "cr_relation_types" in self.fields: self.fields["cr_relation_types"].choices = CRRelationType.get_types() self._reorder_period_fields("cultural_attributions") def get_input_ids(self): ids = super(FindSelect, self).get_input_ids() if "ope_relation_types" in ids: ids.pop(ids.index("ope_relation_types")) for idx, c in enumerate(self.fields["ope_relation_types"].choices): ids.append("ope_relation_types_{}".format(idx)) if "cr_relation_types" in ids: ids.pop(ids.index("cr_relation_types")) for idx, c in enumerate(self.fields["cr_relation_types"].choices): ids.append("cr_relation_types_{}".format(idx)) return ids class FindSelectWarehouseModule(FindSelect): # collection = forms.IntegerField( # label=_("Collection (warehouse)"), # widget=widgets.JQueryAutoComplete( # reverse_lazy('autocomplete-warehouse'), # associated_model=Warehouse), # validators=[valid_id(Warehouse)]) container_ref = forms.IntegerField( label=_("Reference container"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-container"), associated_model=Container ), validators=[valid_id(Container)], ) container_ref__location = forms.IntegerField( label=_("Reference container - Warehouse (location)"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-warehouse"), associated_model=Warehouse ), validators=[valid_id(Warehouse)], ) """ container_ref__responsible = forms.IntegerField( label=_("Reference container - Warehouse (responsible)"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse), validators=[valid_id(Warehouse)]) container_ref__index = forms.IntegerField( label=_("Reference container ID")) container_ref__reference = forms.CharField( label=_("Reference container ref.")) """ container = forms.IntegerField( label=_("Current container"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-container"), associated_model=Container ), validators=[valid_id(Container)], ) container__location = forms.IntegerField( label=_("Current container - Warehouse (location)"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-warehouse"), associated_model=Warehouse ), validators=[valid_id(Warehouse)], ) """ container__responsible = forms.IntegerField( label=_("Current container - Warehouse (responsible)"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse), validators=[valid_id(Warehouse)]) container__index = forms.IntegerField(label=_("Current container ID")) container__reference = forms.CharField(label=_("Current container ref.")) """ class FindFormSelection(LockForm, CustomFormSearch): SEARCH_AND_SELECT = True form_label = _("Find search") associated_models = {"pk": models.Find} currents = {"pk": models.Find} pk_key = "pk" pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-find"), FindSelect, models.Find, gallery=True, map=True, source_full=reverse_lazy("get-find-full"), ), validators=[valid_id(models.Find)], ) class FindFormMultiSelection(LockForm, MultiSearchForm): form_label = _("Find search") associated_models = {"pks": models.Find} pk_key = "pks" pk = forms.CharField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-find"), FindSelect, models.Find, gallery=True, map=True, multiple_select=True, source_full=reverse_lazy("get-find-full"), ), validators=[valid_ids(models.Find)], ) class FindFormSelectionWarehouseModule(FindFormSelection): pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-find"), FindSelectWarehouseModule, models.Find, gallery=True, map=True, source_full=reverse_lazy("get-find-full"), ), validators=[valid_id(models.Find)], ) class FindFormMultiSelectionWarehouseModule(FindFormMultiSelection): pk = forms.CharField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-find"), FindSelectWarehouseModule, models.Find, gallery=True, map=True, multiple_select=True, source_full=reverse_lazy("get-find-full"), ), validators=[valid_ids(models.Find)], ) class MultipleFindFormSelection(forms.Form): # used for basket management # TODO: could probably use FindFormMultiSelection form_label = _("Find search") associated_models = {"pk": models.Find} currents = {"pk": models.Find} pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-find"), FindSelect, models.Find, gallery=True, map=True, multiple_select=True, source_full=reverse_lazy("get-find-full"), ), validators=[valid_id(models.Find)], ) class MultipleFindFormSelectionWarehouseModule(MultipleFindFormSelection): # used for basket management # TODO: could probably use FindFormMultiSelectionWarehouse pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-find"), FindSelectWarehouseModule, models.Find, gallery=True, map=True, multiple_select=True, source_full=reverse_lazy("get-find-full"), ), validators=[valid_id(models.Find)], ) class FindMultipleFormSelection(forms.Form): form_label = _("Upstream finds") associated_models = {"finds": models.Find} associated_labels = {"finds": _("Finds")} # using FindSelectWarehouseModule because this form is only used with # the warehouse module activated finds = forms.CharField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-find"), FindSelectWarehouseModule, models.Find, gallery=True, map=True, multiple=True, multiple_cols=[2, 3, 4], ), validators=[valid_ids(models.Find)], ) def clean(self): if "finds" not in self.cleaned_data or not self.cleaned_data["finds"]: raise forms.ValidationError( _("You should at least select one " "archaeological find.") ) return self.cleaned_data def check_form(wizard, form_name, key): request = wizard.request storage = wizard.storage if ( storage.prefix not in request.session or "step_data" not in request.session[storage.prefix] or form_name not in request.session[storage.prefix]["step_data"] or form_name + "-" + key not in request.session[storage.prefix]["step_data"][form_name] ): return False return True def check_exist(form_name, key): def func(self): request = self.request storage = self.storage if not check_form(self, form_name, key): return False try: val = request.session[storage.prefix]["step_data"][form_name][ form_name + "-" + key ] if val and len(val) > 0: val = val[0] return bool(val) except ValueError: return False return func def check_not_exist(form_name, key): def func(self): return not check_exist(form_name, key)(self) return func def check_value(form_name, key, value): def func(self): request = self.request storage = self.storage if not check_form(self, form_name, key): return False try: val = request.session[storage.prefix]["step_data"][form_name][ form_name + "-" + key ] if val and len(val) > 0: val = val[0] return str(val) == str(value) except ValueError: return False return func def check_type_field(form_name, key, model, field): def func(self): request = self.request storage = self.storage if not check_form(self, form_name, key): return False try: val = model.objects.get( pk=request.session[storage.prefix]["step_data"][form_name][ form_name + "-" + key ][0] ) return bool(getattr(val, field)) except (ValueError, model.DoesNotExist): return False return func def check_type_not_field(form_name, key, model, field): def func(self): return not check_type_field(form_name, key, model, field)(self) return func def check_treatment(form_name, type_key, type_list=[], not_type_list=[]): type_list = [models.TreatmentType.objects.get(txt_idx=tpe).pk for tpe in type_list] not_type_list = [ models.TreatmentType.objects.get(txt_idx=tpe).pk for tpe in not_type_list ] def func(self): request = self.request storage = self.storage if not check_form(self, form_name, type_key): return False try: tpe = request.session[storage.prefix]["step_data"][form_name][ form_name + "-" + type_key ] if not tpe: return False type = int(tpe[0]) return (not type_list or type in type_list) and type not in not_type_list except ValueError: return False return func class ResultFindForm(ManageOldType, forms.Form): form_label = _("Resulting find") associated_models = {"material_type": models.MaterialType} label = forms.CharField( label=_("Free ID"), validators=[validators.MaxLengthValidator(60)] ) description = forms.CharField(label=_("Precise description"), widget=forms.Textarea) material_type = forms.ChoiceField(label=_("Material type"), choices=[]) volume = forms.IntegerField(label=_("Volume (l)")) weight = forms.IntegerField(label=_("Weight (g)")) find_number = forms.IntegerField(label=_("Find number")) TYPES = [FieldType("material_type", models.MaterialType)] ResultFindFormSet = formset_factory(ResultFindForm, can_delete=True, formset=FormSet) ResultFindFormSet.form_label = _("Resulting finds") class FindDeletionForm(FinalForm): confirm_msg = " " confirm_end_msg = _("Would you like to delete this find?") class UpstreamFindFormSelection(MultiSearchForm, FindFormSelection): form_label = _("Upstream finds") current_model = models.Find pk_key = "resulting_pk" associated_models = {"resulting_pk": models.Find} pk = forms.CharField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-find"), FindSelect, current_model, gallery=True, multiple_select=True, source_full=reverse_lazy("get-find-full"), ), validators=[valid_ids(current_model)], ) class SingleUpstreamFindFormSelection(UpstreamFindFormSelection): current_model = models.Find pk = forms.CharField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-find"), FindSelect, current_model, gallery=True, source_full=reverse_lazy("get-find-full"), ), validators=[valid_ids(current_model)], ) class FindBasketSelect(CustomForm, TableSelect): _model = models.FindBasket form_admin_name = _("Find basket - 001 - Search") form_slug = "findbasket-001-search" search_vector = forms.CharField( label=_("Full text search"), widget=widgets.SearchWidget("archaeological-finds", "findbasket"), ) label = forms.CharField(label=_("Denomination")) class FindBasketFormSelection(CustomFormSearch): SEARCH_AND_SELECT = True form_label = _("Basket search") associated_models = {"pk": models.FindBasket} currents = {"pk": models.FindBasket} pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-findbasket"), FindBasketSelect, models.FindBasket, ), validators=[valid_id(models.FindBasket)], ) class FindBasketForWriteFormSelection(CustomFormSearch): SEARCH_AND_SELECT = True form_label = _("Basket search") associated_models = {"pk": models.FindBasket} currents = {"pk": models.FindBasket} pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy("get-findbasket-write"), FindBasketSelect, models.FindBasket, ), validators=[valid_id(models.FindBasket)], ) class FindBasketForm(IshtarForm): form_label = _("Find basket") associated_models = {"shared_with": IshtarUser, "shared_write_with": IshtarUser} label = forms.CharField( label=_("Label"), validators=[validators.MaxLengthValidator(1000)] ) slug = forms.SlugField(label=_("Slug"), required=False) public = forms.BooleanField(label=_("Is public"), required=False) comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False) shared_with = widgets.Select2MultipleField( model=IshtarUser, remote=True, label=_("Shared (read) with"), required=False, long_widget=True, ) shared_write_with = widgets.Select2MultipleField( model=IshtarUser, remote=True, label=_("Shared (read/edit) with"), required=False, long_widget=True, ) def __init__(self, *args, **kwargs): self.basket_pk = None if "basket_pk" in kwargs: self.basket_pk = kwargs.pop("basket_pk") self.is_admin = None if "user" in kwargs: user = kwargs.pop("user") self.is_admin = getattr(user, "is_superuser", None) super(FindBasketForm, self).__init__(*args, **kwargs) if not self.is_admin: self.fields.pop("slug") self.fields.pop("public") def clean(self): slug = self.cleaned_data.get("slug", None) if ( slug and slug.strip() and models.FindBasket.objects.filter(slug=slug.strip()) .exclude(pk=self.basket_pk) .count() ): raise forms.ValidationError(_("A basket with this slug already " "exists.")) return self.cleaned_data class NewFindBasketForm(forms.ModelForm, IshtarForm): shared_with = widgets.Select2MultipleField( model=IshtarUser, remote=True, label=_("Shared (read) with"), required=False, long_widget=True, ) shared_write_with = widgets.Select2MultipleField( model=IshtarUser, remote=True, label=_("Shared (read/edit) with"), required=False, long_widget=True, ) class Meta: model = models.FindBasket fields = ( "label", "slug", "public", "comment", "shared_with", "shared_write_with", ) def __init__(self, *args, **kwargs): self.user = kwargs.pop("user") self.is_admin = False if getattr(self.user, "user_ptr", None): self.is_admin = getattr(self.user.user_ptr, "is_superuser", None) super(NewFindBasketForm, self).__init__(*args, **kwargs) if not self.is_admin: self.fields.pop("slug") self.fields.pop("public") def clean(self): q = models.FindBasket.objects.filter( user=self.user, label=self.cleaned_data["label"] ) if q.count(): raise forms.ValidationError( _("Another basket already exists with " "this name.") ) slug = self.cleaned_data.get("slug", None) if ( slug and slug.strip() and models.FindBasket.objects.filter(slug=slug.strip()).count() ): raise forms.ValidationError(_("A basket with this slug already " "exists.")) return self.cleaned_data def save(self, commit=True): self.instance.user = self.user return super(NewFindBasketForm, self).save(commit) class SelectFindBasketForm(IshtarForm): form_label = _("Basket") associated_models = {"basket": models.FindBasket} need_user_for_initialization = True basket = forms.IntegerField( label=_("Basket"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-findbasket"), associated_model=models.FindBasket ), validators=[valid_id(models.FindBasket)], ) def __init__(self, *args, **kwargs): self.user = None if "user" in kwargs: self.user = kwargs.pop("user") if hasattr(self.user, "ishtaruser"): self.user = self.user.ishtaruser super(SelectFindBasketForm, self).__init__(*args, **kwargs) class SelectFindBasketWriteForm(IshtarForm): form_label = _("Basket") associated_models = {"basket": models.FindBasket} need_user_for_initialization = True basket = forms.IntegerField( label=_("Basket"), widget=widgets.JQueryAutoComplete( reverse_lazy("autocomplete-findbasket-write"), associated_model=models.FindBasket, ), validators=[valid_id(models.FindBasket)], ) def __init__(self, *args, **kwargs): self.user = None if "user" in kwargs: self.user = kwargs.pop("user") if hasattr(self.user, "ishtaruser"): self.user = self.user.ishtaruser super(SelectFindBasketWriteForm, self).__init__(*args, **kwargs) class FindBasketAddItemForm(forms.Form): basket_id = forms.IntegerField(required=True) item_id = forms.IntegerField(required=True) def save(self, user): try: basket = ( models.FindBasket.objects.filter( Q(user=user) | Q(shared_with=user) | Q(shared_write_with=user) ) .distinct() .get(pk=self.cleaned_data["basket_id"]) ) item = models.Find.objects.get(pk=self.cleaned_data["item_id"]) except models.FindBasket.DoesNotExist or models.Find.DoesNotExist: # something strange... TODO: log it raise PermissionDenied # check rights if ( not user.user_ptr.is_superuser and not user.has_right("view_find") and not (user.has_right("view_own_find") and item.is_own(user)) ): raise PermissionDenied basket.items.add(item) return basket