#!/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 django.utils.translation import ugettext_lazy as _ import models 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, \ AdministrativeActTreatmentFormSelection, \ AdministrativeActTreatmentModifForm, \ AdministrativeActTreatmentFileForm, \ AdministrativeActTreatmentFileFormSelection, \ AdministrativeActTreatmentFileModifForm, \ DashboardForm as DashboardTreatmentForm, \ DashboardTreatmentFileForm, QAFindTreatmentForm from archaeological_operations.models import Period, ArchaeologicalSite, \ RelationType as OpeRelationType from archaeological_operations.widgets import OAWidget from archaeological_warehouse.models import Warehouse 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, HistorySelect, \ PkWizardSearch from ishtar_common.forms_common import get_town_field from ishtar_common.models import valid_id, valid_ids, get_current_profile, \ SpatialReferenceSystem, Area, OperationType 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', 'DateForm', 'DatingFormSet', 'PreservationForm', 'FindBasketFormSelection', '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', 'DeleteFindBasketForm', 'FindBasketAddItemForm', 'QAFindFormSingle', 'QAFindFormMulti', 'QAFindBasketForm', 'QAFindTreatmentForm' ] logger = logging.getLogger(__name__) class RecordFormSelection(CustomForm, forms.Form): form_label = _("Context record") form_admin_name = _(u"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=_(u"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 = unicode(widget.source) + "?operation__pk={}".format( cr.operation.pk) class FindForm(CustomForm, ManageOldType): file_upload = True form_label = _("Find") form_admin_name = _(u"Find - 020 - General") form_slug = "find-020-general" base_models = ['get_first_base_find', 'object_type', 'material_type', 'communicabilitie'] associated_models = { 'material_type': models.MaterialType, 'object_type': models.ObjectType, 'communicabilitie': models.CommunicabilityType, 'get_first_base_find__batch': models.BatchType, 'get_first_base_find__spatial_reference_system': SpatialReferenceSystem, 'material_type_quality': models.MaterialTypeQualityType, 'object_type_quality': models.ObjectTypeQualityType, 'checked_type': models.CheckedType, } HEADERS = {} HEADERS['label'] = FormHeader(_(u"Identification")) label = forms.CharField( label=_(u"Free ID"), validators=[validators.MaxLengthValidator(60)]) denomination = forms.CharField(label=_(u"Denomination"), required=False) previous_id = forms.CharField(label=_("Previous ID"), required=False) get_first_base_find__excavation_id = forms.CharField( label=_(u"Excavation ID"), required=False) museum_id = forms.CharField(label=_(u"Museum ID"), required=False) seal_number = forms.CharField(label=_(u"Seal number"), required=False) mark = forms.CharField(label=_(u"Mark"), required=False) HEADERS['description'] = FormHeader(_(u"Description")) description = forms.CharField(label=_(u"Description"), widget=forms.Textarea, required=False) get_first_base_find__discovery_date = forms.DateField( label=_(u"Discovery date (exact or TPQ)"), widget=DatePicker, required=False) get_first_base_find__discovery_date_taq = forms.DateField( label=_(u"Discovery date (TAQ)"), widget=DatePicker, required=False) get_first_base_find__batch = forms.ChoiceField( label=_(u"Batch/object"), choices=[], required=False) is_complete = forms.NullBooleanField(label=_(u"Is complete?"), required=False) material_type = widgets.Select2MultipleField( label=_(u"Material types"), required=False ) material_type_quality = forms.ChoiceField( label=_(u"Material type quality"), required=False, choices=[]) object_type = widgets.Select2MultipleField( label=_(u"Object types"), required=False, ) object_type_quality = forms.ChoiceField( label=_(u"Object type quality"), required=False, choices=[]) find_number = forms.IntegerField(label=_(u"Find number"), required=False) min_number_of_individuals = forms.IntegerField( label=_(u"Minimum number of individuals (MNI)"), required=False) decoration = forms.CharField(label=_(u"Decoration"), widget=forms.Textarea, required=False) inscription = forms.CharField(label=_(u"Inscription"), widget=forms.Textarea, required=False) manufacturing_place = forms.CharField( label=_(u"Manufacturing place"), required=False) communicabilitie = widgets.Select2MultipleField( label=_(u"Communicability"), required=False ) comment = forms.CharField(label=_(u"Comment"), required=False, widget=forms.Textarea) dating_comment = forms.CharField( label=_(u"Comment on dating"), required=False, widget=forms.Textarea) HEADERS['length'] = FormHeader(_(u"Dimensions")) length = FloatField(label=_(u"Length (cm)"), required=False) width = FloatField(label=_(u"Width (cm)"), required=False) height = FloatField(label=_(u"Height (cm)"), required=False) diameter = FloatField(label=_(u"Diameter (cm)"), required=False) thickness = FloatField(label=_(u"Thickness (cm)"), required=False) volume = FloatField(label=_(u"Volume (l)"), required=False) weight = FloatField(label=_(u"Weight (g)"), required=False) clutter_long_side = FloatField( label=_(u"Clutter long side (cm)"), required=False) clutter_short_side = FloatField( label=_(u"Clutter short side (cm)"), required=False) clutter_height = FloatField( label=_(u"Clutter height (cm)"), required=False) dimensions_comment = forms.CharField( label=_(u"Dimensions comment"), required=False, widget=forms.Textarea) HEADERS['get_first_base_find__x'] = FormHeader( _(u"Coordinates")) get_first_base_find__x = forms.FloatField(label=_(u"X"), required=False) get_first_base_find__estimated_error_x = \ forms.FloatField(label=_(u"Estimated error for X"), required=False) get_first_base_find__y = forms.FloatField(label=_(u"Y"), required=False) get_first_base_find__estimated_error_y = \ forms.FloatField(label=_(u"Estimated error for Y"), required=False) get_first_base_find__z = forms.FloatField(label=_(u"Z"), required=False) get_first_base_find__estimated_error_z = \ forms.FloatField(label=_(u"Estimated error for Z"), required=False) get_first_base_find__spatial_reference_system = \ forms.ChoiceField(label=_(u"Spatial Reference System"), required=False, choices=[]) get_first_base_find__topographic_localisation = forms.CharField( label=_(u"Point of topographic reference"), required=False, max_length=120 ) HEADERS['checked_type'] = FormHeader(_(u"Sheet")) checked_type = forms.ChoiceField(label=_(u"Check"), required=False) check_date = forms.DateField( initial=get_now, label=_(u"Check date"), widget=DatePicker) TYPES = [ FieldType('material_type', models.MaterialType, is_multiple=True), FieldType('material_type_quality', models.MaterialTypeQualityType), FieldType('object_type', models.ObjectType, is_multiple=True), FieldType('object_type_quality', models.ObjectTypeQualityType), FieldType('communicabilitie', models.CommunicabilityType, is_multiple=True), FieldType('get_first_base_find__batch', models.BatchType), FieldType('get_first_base_find__spatial_reference_system', SpatialReferenceSystem), FieldType('checked_type', models.CheckedType, is_multiple=True), ] 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' ], } def __init__(self, *args, **kwargs): context_record = kwargs.pop('context_record') super(FindForm, self).__init__(*args, **kwargs) if not context_record or \ not context_record.operation.operation_type.judiciary: self.fields.pop('seal_number') def clean(self): 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( unicode(_( u"Discovery date: if a TAQ date is provided a TPQ date has " u"to be informed. If you have a precise date fill only the " u"TPQ - discovery date field.")) ) elif tpq and taq and taq < tpq: raise forms.ValidationError( unicode(_(u"Discovery date: TAQ date must be older than TPQ " u"date."))) 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( unicode(_( u"Clutter: short side cannot be bigger than the long side." )) ) 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( _(u"You should at least provide X, Y and the spatial " u"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( unicode(_(u"Coordinates are not relevant for the spatial " u"reference system used: {}.")).format(e)) return self.cleaned_data class QAFindFormMulti(QAForm): form_admin_name = _(u"Find - Quick action - Modify") form_slug = "find-quickaction-modify" base_models = ['get_first_base_find', 'qa_object_types', 'qa_material_types', 'qa_communicabilities'] associated_models = { 'qa_material_types': models.MaterialType, 'qa_object_types': models.ObjectType, 'qa_communicabilities': models.CommunicabilityType, 'qa_checked_type': models.CheckedType, 'qa_period': Period } MULTI = True REPLACE_FIELDS = [ 'qa_ue', 'qa_manufacturing_place', 'qa_checked_type', 'qa_check_date' ] HEADERS = { 'qa_ue': FormHeader(_(u"Context record")), 'qa_label': FormHeader(_(u"Identification")), 'qa_description': FormHeader(_(u"Description")), 'qa_checked_type': FormHeader(_(u"Sheet")), 'qa_period': FormHeader(_(u"Datation")), } SINGLE_FIELDS = [ 'qa_label', 'qa_denomination', 'qa_previous_id', 'qa_get_first_base_find__excavation_id', 'qa_museum_id', 'qa_seal_number', 'qa_mark' ] qa_ue = forms.IntegerField( label=_(u"Context record"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-contextrecord'), associated_model=ContextRecord), validators=[valid_id(ContextRecord)], required=False) qa_label = forms.CharField( label=_(u"Free ID"), validators=[validators.MaxLengthValidator(60)], required=False) qa_denomination = forms.CharField(label=_(u"Denomination"), required=False) qa_previous_id = forms.CharField(label=_("Previous ID"), required=False) qa_get_first_base_find__excavation_id = forms.CharField( label=_(u"Excavation ID"), required=False) qa_museum_id = forms.CharField(label=_(u"Museum ID"), required=False) qa_seal_number = forms.CharField(label=_(u"Seal number"), required=False) qa_mark = forms.CharField(label=_(u"Mark"), required=False) qa_description = forms.CharField( label=_(u"Description"), widget=forms.Textarea, required=False) qa_material_types = widgets.Select2MultipleField( label=_(u"Material types"), required=False ) qa_object_types = widgets.Select2MultipleField( label=_(u"Object types"), required=False, ) qa_manufacturing_place = forms.CharField( label=_(u"Manufacturing place"), required=False) qa_communicabilities = widgets.Select2MultipleField( label=_(u"Communicability"), required=False ) qa_comment = forms.CharField( label=_(u"Comment"), required=False, widget=forms.Textarea) qa_checked_type = forms.ChoiceField(label=_(u"Check"), required=False) qa_check_date = forms.DateField( label=_(u"Check date"), widget=DatePicker, required=False) qa_period = widgets.Select2MultipleField( label=_("Period"), choices=[], required=False) qa_dating_comment = forms.CharField( label=_(u"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_communicabilities', models.CommunicabilityType, is_multiple=True), FieldType('qa_checked_type', models.CheckedType), FieldType('qa_period', Period, is_multiple=True), ] def _get_qa_ue(self, value): try: value = ContextRecord.objects.get(pk=value).cached_label except ContextRecord.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 = _(u"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): create_or_update = forms.ChoiceField( choices=(('create', _(u"Create")), ('update', _(u"Update"))), initial='create') label = forms.CharField(label="", max_length=None, required=False) basket = forms.ChoiceField(label=_(u"Basket"), required=False, choices=[]) 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) if not self.user: return self.fields['basket'].choices = [ (b.pk, unicode(b)) for b in models.FindBasket.objects.filter(user=self.user) ] def clean(self): if self.cleaned_data['create_or_update'] == 'update': if not self.cleaned_data['basket']: raise forms.ValidationError( _(u"On update, you have to select a basket.")) return self.cleaned_data label = self.cleaned_data['label'].strip() if not label: raise forms.ValidationError(_(u"A label is required.")) if models.FindBasket.objects.filter(user=self.user, label=label).count(): raise forms.ValidationError(_(u"A basket with this label already " u"exists.")) return self.cleaned_data def save(self, items): if self.cleaned_data['create_or_update'] == 'update': basket = models.FindBasket.objects.get( user=self.user, pk=self.cleaned_data['basket']) else: label = self.cleaned_data['label'].strip() basket = models.FindBasket.objects.create( user=self.user, label=label) for item in items: basket.items.add(item) class PreservationForm(CustomForm, ManageOldType): form_label = _("Preservation") form_admin_name = _(u"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=_(u"Integrity / interest"), choices=[], widget=widgets.Select2Multiple, required=False) remarkabilitie = forms.MultipleChoiceField( label=_(u"Remarkability"), choices=[], widget=widgets.Select2Multiple, required=False) conservatory_state = forms.ChoiceField(label=_(u"Conservatory state"), choices=[], required=False) alteration = forms.MultipleChoiceField( label=_(u"Alteration"), choices=[], widget=widgets.Select2Multiple, required=False) alteration_cause = forms.MultipleChoiceField( label=_(u"Alteration cause"), choices=[], widget=widgets.Select2Multiple, required=False) preservation_to_consider = forms.MultipleChoiceField( label=_(u"Recommended treatments"), choices=[], widget=widgets.Select2Multiple, required=False) treatment_emergency = forms.ChoiceField(label=_("Treatment emergency"), choices=[], required=False) estimated_value = FloatField(label=_(u"Estimated value"), required=False) insurance_value = FloatField(label=_(u"Insurance value"), required=False) appraisal_date = forms.DateField( label=_(u"Appraisal date"), widget=DatePicker, required=False) conservatory_comment = forms.CharField( label=_(u"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) self.fields['insurance_value'].label = u"{} ({})".format( unicode(self.fields['insurance_value'].label), get_current_profile().currency) self.fields['estimated_value'].label = u"{} ({})".format( unicode(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=_(u"Start date"), required=False) end_date = forms.IntegerField(label=_(u"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 = _(u"Find - 040 - Dating") DatingFormSet.form_slug = "find-040-dating" class FindSelect(HistorySelect): _model = models.Find form_admin_name = _(u"Find - 001 - Search") form_slug = "find-001-search" search_vector = forms.CharField( label=_(u"Full text search"), widget=widgets.SearchWidget( 'archaeological-finds', 'find' )) base_finds__cache_short_id = forms.CharField(label=_(u"Short ID")) base_finds__cache_complete_id = forms.CharField(label=_(u"Complete ID")) label = forms.CharField(label=_(u"Free ID")) denomination = forms.CharField(label=_(u"Denomination")) base_finds__context_record__town = get_town_field() base_finds__context_record__operation__year = forms.IntegerField( label=_(u"Year")) base_finds__context_record__operation__operation_code = forms.IntegerField( label=_(u"Operation's number (index by year)")) base_finds__context_record__operation__code_patriarche = \ forms.IntegerField( label=_(u"Code PATRIARCHE"), widget=OAWidget ) base_finds__context_record__operation__operation_type = forms.ChoiceField( label=_(u"Operation type"), choices=[] ) base_finds__context_record__town__areas = forms.ChoiceField( label=_(u"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_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)]) base_finds__context_record = forms.IntegerField( label=_("Context record"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-contextrecord'), associated_model=ContextRecord), validators=[valid_id(ContextRecord)]) basket = forms.ChoiceField(label=_(u"Basket"), choices=[]) ope_relation_types = forms.ChoiceField( label=_(u"Search within related operations"), choices=[]) cr_relation_types = forms.ChoiceField( label=_(u"Search within related context records"), choices=[]) datings__period = forms.ChoiceField(label=_(u"Period"), choices=[]) material_types = forms.ChoiceField(label=_(u"Material type"), choices=[]) object_types = forms.ChoiceField(label=_(u"Object type"), choices=[]) preservation_to_considers = forms.ChoiceField( choices=[], label=_(u"Preservation type")) conservatory_state = forms.ChoiceField(label=_(u"Conservatory state"), choices=[]) integrities = forms.ChoiceField(label=_(u"Integrity / interest"), choices=[]) remarkabilities = forms.ChoiceField(label=_(u"Remarkability"), choices=[]) base_finds__find__description = forms.CharField(label=_(u"Description")) base_finds__batch = forms.ChoiceField( label=_(u"Batch/object"), choices=[]) checked_type = forms.ChoiceField(label=_("Check")) documents__image__isnull = forms.NullBooleanField(label=_(u"Has an image?")) TYPES = [ FieldType('datings__period', Period), FieldType('material_types', models.MaterialType), FieldType('conservatory_state', models.ConservatoryState), FieldType('base_finds__batch', models.BatchType), FieldType('object_types', models.ObjectType), 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), ] 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( ) if 'basket' in self.fields: self.fields['basket'].choices = [('', '--')] if self.current_user: self.fields['basket'].choices += [ (b.pk, b.label) for b in models.FindBasket.objects.filter( user=self.current_user).all()] 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): container__location = forms.IntegerField( label=_(u"Warehouse (location)"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse), validators=[valid_id(Warehouse)]) container__responsible = forms.IntegerField( label=_(u"Warehouse (responsible)"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse), validators=[valid_id(Warehouse)]) container__index = forms.IntegerField(label=_(u"Container ID")) container__reference = forms.CharField(label=_(u"Container ref.")) class FindFormSelection(CustomFormSearch): SEARCH_AND_SELECT = True 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, source_full=reverse_lazy('get-find-full')), validators=[valid_id(models.Find)]) class FindFormSelectionWarehouseModule(FindFormSelection): pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy('get-find'), FindSelectWarehouseModule, models.Find, source_full=reverse_lazy('get-find-full')), validators=[valid_id(models.Find)]) class MultipleFindFormSelection(forms.Form): 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, multiple_select=True, source_full=reverse_lazy('get-find-full')), validators=[valid_id(models.Find)]) class MultipleFindFormSelectionWarehouseModule(MultipleFindFormSelection): pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy('get-find'), FindSelectWarehouseModule, models.Find, multiple_select=True, source_full=reverse_lazy('get-find-full')), validators=[valid_id(models.Find)]) class FindMultipleFormSelection(forms.Form): form_label = _(u"Upstream finds") associated_models = {'finds': models.Find} associated_labels = {'finds': _(u"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, 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(_(u"You should at least select one " u"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 unicode(val) == unicode(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 = _(u"Resulting find") associated_models = {'material_type': models.MaterialType} label = forms.CharField( label=_(u"Free ID"), validators=[validators.MaxLengthValidator(60)]) description = forms.CharField(label=_(u"Precise description"), widget=forms.Textarea) material_type = forms.ChoiceField(label=_(u"Material type"), choices=[]) volume = forms.IntegerField(label=_(u"Volume (l)")) weight = forms.IntegerField(label=_(u"Weight (g)")) find_number = forms.IntegerField(label=_(u"Find number")) TYPES = [ FieldType('material_type', models.MaterialType) ] ResultFindFormSet = formset_factory(ResultFindForm, can_delete=True, formset=FormSet) ResultFindFormSet.form_label = _(u"Resulting finds") class FindDeletionForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this find?") class UpstreamFindFormSelection(PkWizardSearch, FindFormSelection): form_label = _(u"Upstream find") current_model = models.Find pk_key = 'resulting_pk' pk = forms.CharField( label="", required=False, widget=widgets.DataTable( reverse_lazy('get-find'), FindSelect, current_model, multiple_select=True, source_full=reverse_lazy('get-find-full')), validators=[valid_ids(current_model)]) def __init__(self, *args, **kwargs): super(UpstreamFindFormSelection, self).__init__(*args, **kwargs) self.fields['pk'].required = True self.fields['resulting_pk'] = self.fields.pop('pk') class FindBasketSelect(CustomForm, TableSelect): _model = models.FindBasket form_admin_name = _(u"Find basket - 001 - Search") form_slug = "findbasket-001-search" search_vector = forms.CharField( label=_(u"Full text search"), widget=widgets.SearchWidget( 'archaeological-finds', 'findbasket' )) label = forms.CharField(label=_(u"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 FindBasketForm(IshtarForm): form_label = _(u"Find basket") label = forms.CharField( label=_(u"Label"), validators=[validators.MaxLengthValidator(1000)]) comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, required=False) class NewFindBasketForm(forms.ModelForm): class Meta: model = models.FindBasket fields = ('label', 'comment') def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') super(NewFindBasketForm, self).__init__(*args, **kwargs) def clean(self): q = models.FindBasket.objects.filter(user=self.user, label=self.cleaned_data['label']) if q.count(): raise forms.ValidationError(_(u"Another basket already exists with " u"this name.")) 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 = _(u"Basket") associated_models = {'basket': models.FindBasket} need_user_for_initialization = True basket = forms.ChoiceField(label=_(u"Basket"), required=True, choices=[]) 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) if not self.user: return self.fields['basket'].choices = [('', '--')] + [ (b.pk, unicode(b)) for b in models.FindBasket.objects.filter( Q(user=self.user) | Q(shared_with=self.user) )] class DeleteFindBasketForm(SelectFindBasketForm): def save(self): try: models.FindBasket.objects.get(pk=self.cleaned_data['basket'], user=self.user).delete() except models.FindBasket.DoesNotExist: # something strange... TODO: log it pass return 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) ).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