#!/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, \ DashboardForm as DashboardTreatmentForm, N1TreatmentForm,\ DashboardTreatmentFileForm, 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, DocumentItemSelect 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 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', 'DashboardTreatmentForm', 'DashboardTreatmentFileForm', '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', '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', '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', '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__x'] = FormHeader(_("Coordinates")) get_first_base_find__x = forms.FloatField(label=_("X"), required=False) get_first_base_find__estimated_error_x = \ forms.FloatField(label=_("Estimated error for X"), required=False) get_first_base_find__y = forms.FloatField(label=_("Y"), required=False) get_first_base_find__estimated_error_y = \ forms.FloatField(label=_("Estimated error for Y"), required=False) get_first_base_find__z = forms.FloatField(label=_("Z"), required=False) get_first_base_find__estimated_error_z = \ forms.FloatField(label=_("Estimated error for Z"), required=False) get_first_base_find__spatial_reference_system = \ forms.ChoiceField(label=_("Spatial Reference System"), required=False, choices=[]) 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), ] PROFILE_FILTER = { 'mapping': [ 'get_first_base_find__x', 'get_first_base_find__y', 'get_first_base_find__z', 'get_first_base_find__estimated_error_x', 'get_first_base_find__estimated_error_y', 'get_first_base_find__estimated_error_z', 'get_first_base_find__spatial_reference_system' ], #'warehouse': [ # 'collection' #] } 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")), } 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) 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 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=[]) 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=[]) dating_type = forms.ChoiceField(label=_("Dating type"), 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(DocumentItemSelect, 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__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__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), ] 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