#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2016-2025 Étienne Loks # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # See the file COPYING for details. import datetime import logging from collections import OrderedDict from bootstrap_datepicker.widgets import DateField from django import forms from django.core import validators from ishtar_common.utils import ugettext_lazy as _ from ishtar_common.forms import FormHeader from archaeological_finds import models from archaeological_operations.forms import AdministrativeActForm, \ AdministrativeActOpeFormSelection, AdministrativeActModifForm from archaeological_operations.models import ActType, AdministrativeAct from archaeological_warehouse.models import Warehouse, Container from ishtar_common import widgets from ishtar_common.forms import reverse_lazy, TableSelect, FinalForm, \ ManageOldType, CustomForm, FieldType, IshtarForm, \ DocumentItemSelect, MultiSearchForm from ishtar_common.models import Person, valid_id, valid_ids, Organization, \ get_current_profile logger = logging.getLogger(__name__) # Treatment class TreatmentSelect(DocumentItemSelect): _model = models.Treatment form_admin_name = _("Treatment - 001 - Search") form_slug = "treatment-001-search" search_vector = forms.CharField( label=_("Full text search"), widget=widgets.SearchWidget( 'archaeological-finds', 'treatment' )) label = forms.CharField(label=_("Label")) reference = forms.CharField(label=_("Reference")) year = forms.IntegerField(label=_("Year")) index = forms.IntegerField(label=_("Index")) scientific_monitoring_manager = forms.IntegerField( widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person-permissive'), associated_model=Person), label=_("Scientific monitoring manager")) treatment_types = forms.ChoiceField(label=_("Treatment type"), choices=[]) label = forms.CharField(label=_("Label"), max_length=200, required=False) reference = forms.CharField( label=_("Reference"), max_length=200, required=False) treatment_status = forms.ChoiceField(label=_("Status"), choices=[]) input_status = forms.ChoiceField(label=_("Input status"), choices=[]) location = forms.IntegerField( label=_("Location"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse), validators=[valid_id(Warehouse)]) scientific_monitoring_manager = forms.IntegerField( label=_("Scientific monitoring manager"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person), ) person = forms.IntegerField( label=_("Responsible of the treatment"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person), ) organization = forms.IntegerField( label=_("Organization"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization'), associated_model=Organization), ) TYPES = [ FieldType('treatment_status', models.TreatmentStatus), FieldType('input_status', models.TreatmentInputStatus), FieldType('treatment_type', models.TreatmentType), ] TYPES += DocumentItemSelect.TYPES def __init__(self, *args, **kwargs): super(TreatmentSelect, self).__init__(*args, **kwargs) self.fields['treatment_types'].choices = \ models.TreatmentType.get_types() self.fields['treatment_types'].help_text = \ models.TreatmentType.get_help() class TreatmentFormSelection(CustomForm, forms.Form): SEARCH_AND_SELECT = True form_label = _("Treatment search") associated_models = {'pk': models.Treatment} currents = {'pk': models.Treatment} pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy('get-treatment'), TreatmentSelect, models.Treatment, gallery=True, ), validators=[valid_id(models.Treatment)]) class TreatmentInputStatusSelect(forms.Select): def render(self, name, value, attrs=None, renderer=None): rendered = super().render(name, value, attrs, renderer) executed_id = [ str(t.pk) for t in models.TreatmentInputStatus.objects.filter( executed=True).all()] if not executed_id: return rendered message = '  ' message += str(_("Once validated, this input status is not reversible.")) message += " " + str( _("Depending on the type of treatment, container change and find " "separation/grouping will be carried out on a database basis.") ) rendered += """
%(message)s
""" % {"name": name, "id": name.replace("-", "_"), "exec_list": "','".join(executed_id), "message": message} return rendered class BaseTreatmentForm(CustomForm, ManageOldType): UPSTREAM_IS_MANY = False DOWNSTREAM_IS_MANY = False form_label = _("Treatment") form_admin_name = _("Treatment - 020 - General") form_slug = "treatment-020-general" base_models = ['treatment_type'] associated_models = { 'treatment_type': models.TreatmentType, 'person': Person, 'scientific_monitoring_manager': Person, 'location': Warehouse, 'organization': Organization, 'container': Container, 'treatment_status': models.TreatmentStatus, 'input_status': models.TreatmentInputStatus, } HEADERS = { "treatment_type": FormHeader(_("General")), "location": FormHeader(_("Location/responsability")), "start_date": FormHeader(_("Details")), } file_upload = True need_user_for_initialization = True treatment_type = widgets.Select2MultipleField( label=_("Treatment type"), choices=[], widget=widgets.CheckboxSelectMultiple) year = forms.IntegerField(label=_("Year"), initial=lambda: datetime.datetime.now().year, validators=[validators.MinValueValidator(1000), validators.MaxValueValidator(2100)]) label = forms.CharField(label=_("Label"), max_length=200, required=False) reference = forms.CharField( label=_("Reference"), max_length=200, required=False) treatment_status = forms.ChoiceField(label=_("Status"), choices=[]) input_status = forms.ChoiceField(label=_("Input status"), choices=[], widget=TreatmentInputStatusSelect) location = forms.IntegerField( label=_("Location"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse, new=True), validators=[valid_id(Warehouse)]) container = forms.IntegerField( label=_("Destination container (relevant for treatment that change " "location)"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-container'), associated_model=Container, new=True), validators=[valid_id(Container)], required=False) scientific_monitoring_manager = forms.IntegerField( label=_("Scientific monitoring manager"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person, new=True), validators=[valid_id(Person)], required=False) person = forms.IntegerField( label=_("Responsible of the treatment"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person, new=True), validators=[valid_id(Person)], required=False) organization = forms.IntegerField( label=_("Organization"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization'), associated_model=Organization, new=True), validators=[valid_id(Organization)], required=False) # external_id = forms.CharField( # label=_("External ref."), max_length=200, required=False) start_date = DateField(label=_("Start date"), required=False, initial=datetime.date.today) end_date = DateField(label=_("End date"), required=False) goal = forms.CharField(label=_("Goal"), widget=forms.Textarea, required=False) description = forms.CharField(label=_("Description"), widget=forms.Textarea, required=False) comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False) estimated_cost = forms.FloatField(label=_("Estimated cost ({currency})"), required=False) quoted_cost = forms.FloatField(label=_("Quoted cost ({currency})"), required=False) realized_cost = forms.FloatField(label=_("Realized cost ({currency})"), required=False) insurance_cost = forms.FloatField(label=_("Insurance cost ({currency})"), required=False) executed = forms.BooleanField(required=False, disabled=True, widget=forms.HiddenInput) TYPES = [ FieldType('treatment_status', models.TreatmentStatus, True), FieldType('input_status', models.TreatmentInputStatus, True), FieldType( 'treatment_type', models.TreatmentType, is_multiple=True, extra_args={'dct': {'upstream_is_many': False, 'downstream_is_many': False}}) ] def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') current_profile = get_current_profile() has_default_location = kwargs.get("data", None) or ( "initial" in kwargs and kwargs["initial"].get("location", None)) super().__init__(*args, **kwargs) if not has_default_location and \ current_profile.default_location_for_treatment_id: self.fields["location"].initial = \ current_profile.default_location_for_treatment_id if current_profile.default_location_for_treatment.organization: self.fields["organization"].initial = \ current_profile.default_location_for_treatment.organization_id # set current currency currency = current_profile.currency for key in ('estimated_cost', 'quoted_cost', 'realized_cost', 'insurance_cost'): self.fields[key].label = self.fields[key].label.format( currency=currency) initial = kwargs.get('initial', {}) if initial.get('executed', False): self.fields['input_status'].choices = \ models.TreatmentInputStatus.get_types( empty_first=False, dct={'executed': True}) q = Person.objects.filter(ishtaruser__pk=self.user.pk) if q.count(): person = q.all()[0] self.fields['scientific_monitoring_manager'].initial = person.pk # self.fields['target_is_basket'].widget.choices = \ # ((False, _("Single find")), (True, _("Basket"))) # TODO """ self.fields['basket'].required = False self.fields['basket'].help_text = \ _("Leave it blank if you want to select a single item") fields = OrderedDict() basket = self.fields.pop('basket') for key, value in self.fields.items(): if key == 'description': fields['index'] = basket fields[key] = value self.fields = fields """ def clean(self, *args, **kwargs): data = self.cleaned_data try: treatment_types = [ models.TreatmentType.objects.get( pk=pk, upstream_is_many=self.UPSTREAM_IS_MANY, downstream_is_many=self.DOWNSTREAM_IS_MANY) for pk in data.get('treatment_type', [])] except models.TreatmentType.DoesNotExist: raise forms.ValidationError(_("Unknow treatment type")) change_current_location = [ str(tp) for tp in treatment_types if tp.change_current_location ] restore_reference_location = [ str(tp) for tp in treatment_types if tp.restore_reference_location ] change_ref_location = [ str(tp) for tp in treatment_types if tp.change_reference_location ] if (change_ref_location or change_current_location) and \ restore_reference_location: if change_ref_location: raise forms.ValidationError( str( _("{} is not compatible with {} " "treatment(s).")).format( ' ; '.join(restore_reference_location), ' ; '.join(change_ref_location), ) ) else: raise forms.ValidationError( str( _("{} is not compatible with {} " "treatment(s).")).format( ' ; '.join(restore_reference_location), ' ; '.join(change_current_location) ) ) if data.get('container', None) \ and not change_ref_location\ and not change_current_location: raise forms.ValidationError( _("The container field is attached to the treatment but " "no treatment with container change is defined.")) if not data.get('container', None) and ( change_ref_location or change_current_location): raise forms.ValidationError( _("A treatment with location change is defined, the container " "field must be filled.")) if not data.get('person', None) and not data.get('organization', None): raise forms.ValidationError( _("A responsible or an organization must be defined.")) return data class N1TreatmentForm(BaseTreatmentForm): UPSTREAM_IS_MANY = True form_admin_name = _("Treatment n-1 - 020 - General") form_slug = "treatment-020-n1-general" TYPES = [ FieldType('treatment_status', models.TreatmentStatus, True), FieldType('input_status', models.TreatmentInputStatus, True, extra_args={'dct': {"executed": True}}), FieldType( 'treatment_type', models.TreatmentType, is_multiple=True, extra_args={'dct': {'upstream_is_many': True, 'downstream_is_many': False}}) ] class OneNTreatmentForm(BaseTreatmentForm): DOWNSTREAM_IS_MANY = True form_admin_name = _("Treatment 1-n - 020 - General") form_slug = "treatment-020-1n-general" TYPES = [ FieldType('treatment_status', models.TreatmentStatus, True), FieldType('input_status', models.TreatmentInputStatus, True, extra_args={'dct': {"executed": True}}), FieldType( 'treatment_type', models.TreatmentType, is_multiple=True, extra_args={'dct': {'upstream_is_many': False, 'downstream_is_many': True}}) ] class TreatmentModifyForm(BaseTreatmentForm): index = forms.IntegerField(label=_("Index")) id = forms.IntegerField(label=' ', widget=forms.HiddenInput, required=False) def __init__(self, *args, **kwargs): super(TreatmentModifyForm, self).__init__(*args, **kwargs) fields = OrderedDict() idx = self.fields.pop('index') for key, value in self.fields.items(): fields[key] = value if key == 'year': fields['index'] = idx # fields.pop('target_is_basket') self.fields = fields def clean(self, *args, **kwargs): super(TreatmentModifyForm, self).clean(*args, **kwargs) cleaned_data = self.cleaned_data year = cleaned_data.get('year') pk = cleaned_data.get('id') index = cleaned_data.get('index') q = models.Treatment.objects \ .filter(year=year, index=index).exclude(pk=pk) if index and q.count(): raise forms.ValidationError( _("Another treatment with this index exists for {}." ).format(year)) return cleaned_data class TreatmentFormFileChoice(CustomForm, forms.Form): form_label = _("Associated request") form_admin_name = _("Treatment - 010 - Request choice") form_slug = "treatment-010-requestchoice" associated_models = {'file': models.TreatmentFile, } currents = {'file': models.TreatmentFile} file = forms.IntegerField( label=_("Treatment request"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-treatmentfile'), associated_model=models.TreatmentFile), validators=[valid_id(models.TreatmentFile)], required=False) class TreatmentDeletionForm(FinalForm): confirm_msg = _( "Are you sure you want to delete this treatment? All changes " "made to the associated finds since this treatment record will be " "lost!") confirm_end_msg = _("Would you like to delete this treatment?") class QABasePackagingForm(IshtarForm): create_treatment = forms.BooleanField( label=_("Create a treatment"), required=False, widget=widgets.CheckboxInput ) treatment_type = forms.ChoiceField( label=_("Treatment type"), choices=[], required=False ) year = forms.IntegerField( label=_("Year"), initial=lambda: datetime.datetime.now().year, validators=[validators.MinValueValidator(1000), validators.MaxValueValidator(2100)], required=False) start_date = DateField(label=_("Precise date"), required=False, initial=lambda: datetime.datetime.today()) person = forms.IntegerField( label=_("Responsible"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person, new=True), validators=[valid_id(Person)], required=False) organization = forms.IntegerField( label=_("Organization"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization'), associated_model=Organization, new=True), validators=[valid_id(Organization)], required=False) def __init__(self, *args, **kwargs): self.confirm = False 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') tt_change_ref_loca = list( models.TreatmentType.objects.filter( available=True, change_reference_location=True, change_current_location=False ).all()) self.treatment_type_ref_choices = "".join( "".format(tt.pk, str(tt)) for tt in tt_change_ref_loca ) tt_change_current_loca = list( models.TreatmentType.objects.filter( available=True, change_current_location=True, change_reference_location=False ).all()) self.treatment_type_current_choices = "".join( "".format(tt.pk, str(tt)) for tt in tt_change_current_loca ) tt_change_both_loca = list( models.TreatmentType.objects.filter( available=True, change_current_location=True, change_reference_location=True ).all()) self.treatment_type_all_choices = "".join( "".format(tt.pk, str(tt)) for tt in tt_change_both_loca ) super().__init__(*args, **kwargs) # treatment type is dynamic put all for check self.fields['treatment_type'].choices = [ (tt.pk, str(tt)) for tt in set( tt_change_ref_loca + tt_change_current_loca + tt_change_both_loca) ] if not self.user: return q = Person.objects.filter(ishtaruser__pk=self.user.pk) if q.count(): person = q.all()[0] self.fields['person'].initial = person.pk def clean(self): if not self.cleaned_data['create_treatment']: return self.cleaned_data year = self.cleaned_data['year'] if not year: if self.cleaned_data['start_date']: self.cleaned_data['year'] = self.cleaned_data['start_date'].year else: raise forms.ValidationError(_("At least a year is required.")) if not self.cleaned_data.get('treatment_type', None): raise forms.ValidationError(_("Treatment type is required.")) return self.cleaned_data class QAFindTreatmentForm(QABasePackagingForm): container = forms.IntegerField( label=_("Container"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-container'), associated_model=Container, new=True), validators=[valid_id(Container)]) container_to_change = forms.ChoiceField( label=_("Change "), required=True, choices=( ('current-and-reference', _("reference and current containers")), ('reference', _("the reference container")), ('current', _("the current container")), ) ) def save(self, items, user): container = Container.objects.get(pk=self.cleaned_data['container']) container_to_change = self.cleaned_data.get('container_to_change', '') container_attrs = [] if container_to_change in ('reference', 'current-and-reference'): container_attrs.append('container_ref') if container_to_change in ('current', 'current-and-reference'): container_attrs.append('container') if self.cleaned_data['create_treatment']: treat_type = models.TreatmentType.objects.get( pk=self.cleaned_data['treatment_type']) treat_input_status = models.TreatmentInputStatus.get_validated_state() treat_status = models.TreatmentStatus.get_completed_state() t = models.Treatment.objects.create( container=container, year=self.cleaned_data['year'], start_date=self.cleaned_data['start_date'], location=container.location, person_id=self.cleaned_data['person'], organization_id=self.cleaned_data['organization'], history_modifier=user, input_status=treat_input_status, treatment_status=treat_status, ) t.treatment_types.add(treat_type) t.save(items=items) t.move_finds_to_new_container(container_attrs=container_attrs) else: for find in items: changed = False for container_attr in container_attrs: if getattr(find, container_attr) == container: continue setattr(find, container_attr, container) changed = True if changed: find.history_modifier = user find.save() # administrative act treatment class AdministrativeActTreatmentSelect(TableSelect): _model = AdministrativeAct search_vector = forms.CharField( label=_("Full text search"), widget=widgets.SearchWidget( 'archaeological-operations', 'administrativeact', 'administrativeacttreatment', )) year = forms.IntegerField(label=_("Year")) index = forms.IntegerField(label=_("Index")) act_type = forms.ChoiceField(label=_("Act type"), choices=[]) indexed = forms.NullBooleanField(label=_("Indexed?")) act_object = forms.CharField(label=_("Object"), max_length=300) signature_date = DateField(label=_("Signature date")) treatment__name = forms.CharField( label=_("Treatment name"), max_length=200) treatment__year = forms.IntegerField(label=_("Treatment year")) treatment__index = forms.IntegerField(label=_("Treatment index")) treatment__reference = forms.CharField( max_length=200, label=_("Treatment reference")) treatment__treatment_types = forms.ChoiceField(label=_("Treatment type"), choices=[]) history_modifier = forms.IntegerField( label=_("Modified by"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person', args=['0', 'user']), associated_model=Person), validators=[valid_id(Person)]) def __init__(self, *args, **kwargs): super(AdministrativeActTreatmentSelect, self).__init__(*args, **kwargs) self.fields['act_type'].choices = ActType.get_types( dct={"intented_to_treatment": True}) self.fields['act_type'].help_text = ActType.get_help( dct={"intented_to_treatment": True}) self.fields['treatment__treatment_types'].choices = \ models.TreatmentType.get_types() self.fields['treatment__treatment_types'].help_text = \ models.TreatmentType.get_help() class AdministrativeActTreatmentFormSelection( AdministrativeActOpeFormSelection): pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy('get-administrativeacttreatment'), AdministrativeActTreatmentSelect, AdministrativeAct), validators=[valid_id(AdministrativeAct)]) class AdministrativeActTreatmentForm(AdministrativeActForm): form_admin_name = _("Administrative act - Treatment - General") form_slug = "adminact-treatment-general" act_type = forms.ChoiceField(label=_("Act type"), choices=[]) TYPES = [ FieldType('act_type', ActType, extra_args={"dct": {"intented_to_treatment": True}}), ] class AdministrativeActTreatmentModifForm( AdministrativeActModifForm, AdministrativeActTreatmentForm): pk = forms.IntegerField(required=False, widget=forms.HiddenInput) index = forms.IntegerField(label=_("Index"), required=False) # treatment requests class TreatmentFileSelect(DocumentItemSelect): _model = models.TreatmentFile form_admin_name = _("Treatment file - 001 - Search") form_slug = "treatmentfile-001-search" search_vector = forms.CharField( label=_("Full text search"), widget=widgets.SearchWidget( 'archaeological-finds', 'treatmentfile' )) name = forms.CharField(label=_("Name")) internal_reference = forms.CharField(label=_("Internal ref.")) year = forms.IntegerField(label=_("Year")) index = forms.IntegerField(label=_("Index")) type = forms.ChoiceField(label=_("Type"), choices=[]) in_charge = forms.IntegerField( label=_("In charge"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person), validators=[valid_id(Person)]) applicant = forms.IntegerField( label=_("Applicant"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person), validators=[valid_id(Person)]) applicant_organisation = forms.IntegerField( label=_("Applicant organisation"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization'), associated_model=Organization), validators=[valid_id(Organization)]) end_date = DateField(label=_("End date"), required=False) exhibition_start = DateField(label=_("Exhibition start date")) exhibition_end = DateField(label=_("Exhibition end date")) def __init__(self, *args, **kwargs): super(TreatmentFileSelect, self).__init__(*args, **kwargs) self.fields['type'].choices = models.TreatmentFileType.get_types() self.fields['type'].help_text = models.TreatmentFileType.get_help() class TreatmentFileFormSelection(CustomForm, forms.Form): SEARCH_AND_SELECT = True form_label = _("Treatment request search") associated_models = {'pk': models.TreatmentFile} currents = {'pk': models.TreatmentFile} pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy('get-treatmentfile'), TreatmentFileSelect, models.TreatmentFile), validators=[valid_id(models.TreatmentFile)]) class TreatmentFileFormSelectionMultiple(MultiSearchForm): form_label = _("Treatment request search") associated_models = {'pks': models.TreatmentFile} pk = forms.CharField( label="", required=False, widget=widgets.DataTable( reverse_lazy('get-treatmentfile'), TreatmentFileSelect, models.TreatmentFile, multiple_select=True ), validators=[valid_ids(models.TreatmentFile)]) class TreatmentFileForm(CustomForm, ManageOldType): form_admin_name = _("Treatment file - 010 - General") form_slug = "treatmentfile-010-general" form_label = _("Treatment request") base_models = ['treatment_type_type'] associated_models = { 'type': models.TreatmentFileType, 'in_charge': Person, 'applicant': Person, 'applicant_organisation': Organization, } need_user_for_initialization = True name = forms.CharField(label=_("Name"), max_length=1000, required=False) year = forms.IntegerField(label=_("Year"), initial=lambda: datetime.datetime.now().year, validators=[validators.MinValueValidator(1000), validators.MaxValueValidator(2100)]) internal_reference = forms.CharField( label=_("Internal ref."), max_length=60, required=False) external_id = forms.CharField( label=_("External ref."), max_length=200, required=False) type = forms.ChoiceField( label=_("Type"), choices=[]) in_charge = forms.IntegerField( label=_("Responsible"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person, new=True), validators=[valid_id(Person)]) applicant = forms.IntegerField( label=_("Applicant"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person, new=True), validators=[valid_id(Person)], required=False) applicant_organisation = forms.IntegerField( label=_("Applicant organisation"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization'), associated_model=Organization, new=True), validators=[valid_id(Organization)], required=False) associated_basket_id = forms.IntegerField( label=_("Associated basket"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-findbasket'), associated_model=models.FindBasket), required=False) exhibition_name = forms.CharField(label=_("Exhibition name"), max_length=200, required=False) exhibition_start_date = DateField(label=_("Exhibition start date"), required=False) exhibition_end_date = DateField(label=_("Exhibition end date"), required=False) comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False) reception_date = DateField( label=_("Reception date"), required=False, initial=lambda: datetime.datetime.now() ) creation_date = DateField(label=_("Start date"), required=False, initial=lambda: datetime.datetime.now()) end_date = DateField(label=_("End date"), required=False) TYPES = [ FieldType('type', models.TreatmentFileType), ] CONDITIONAL_FIELDS = ( (("type", "txt_idx", "loan-for-exhibition"), ("exhibition_name", "exhibition_start_date", "exhibition_end_date")), ) def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') super(TreatmentFileForm, self).__init__(*args, **kwargs) q = Person.objects.filter(ishtaruser__pk=self.user.pk) if q.count(): person = q.all()[0] self.fields['in_charge'].initial = person.pk self.fields['type'].choices = models.TreatmentFileType.get_types( initial=[self.init_data.get('type')], empty_first=False ) self.fields['type'].help_text = models.TreatmentFileType.get_help() class TreatmentFileModifyForm(TreatmentFileForm): index = forms.IntegerField(label=_("Index")) id = forms.IntegerField(label=' ', widget=forms.HiddenInput, required=False) def __init__(self, *args, **kwargs): super(TreatmentFileModifyForm, self).__init__(*args, **kwargs) fields = OrderedDict() idx = self.fields.pop('index') for key, value in self.fields.items(): fields[key] = value if key == 'year': fields['index'] = idx self.fields = fields def clean(self, *args, **kwargs): super(TreatmentFileModifyForm, self).clean(*args, **kwargs) cleaned_data = self.cleaned_data year = cleaned_data.get('year') pk = cleaned_data.get('id') index = cleaned_data.get('index') q = models.TreatmentFile.objects \ .filter(year=year, index=index).exclude(pk=pk) if index and q.count(): raise forms.ValidationError( _("Another treatment request with this index exists for {}." ).format(year)) return cleaned_data class TreatmentFileDeletionForm(FinalForm): confirm_msg = _("Are you sure you want to delete this treatment request?") confirm_end_msg = _("Would you like to delete this treatment request?") class AdministrativeActTreatmentFileSelect(TableSelect): _model = AdministrativeAct search_vector = forms.CharField( label=_("Full text search"), widget=widgets.SearchWidget( 'archaeological-operations', 'administrativeact', 'administrativeacttreatmentfile', )) year = forms.IntegerField(label=_("Year")) index = forms.IntegerField(label=_("Index")) act_type = forms.ChoiceField(label=_("Act type"), choices=[]) indexed = forms.NullBooleanField(label=_("Indexed?")) act_object = forms.CharField(label=_("Object"), max_length=300) signature_date = DateField(label=_("Signature date")) treatment_file__name = forms.CharField( label=_("Treatment request name"), max_length=200) treatment_file__year = forms.IntegerField( label=_("Treatment request year")) treatment_file__index = forms.IntegerField( label=_("Treatment request index")) treatment_file__internal_reference = forms.CharField( max_length=200, label=_("Treatment request internal reference")) treatment_file__type = forms.ChoiceField( label=_("Treatment request type"), choices=[]) history_modifier = forms.IntegerField( label=_("Modified by"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person', args=['0', 'user']), associated_model=Person), validators=[valid_id(Person)]) def __init__(self, *args, **kwargs): super(AdministrativeActTreatmentFileSelect, self).__init__(*args, **kwargs) self.fields['act_type'].choices = ActType.get_types( dct={"intented_to_treatment_request": True}) self.fields['act_type'].help_text = ActType.get_help( dct={"intented_to_treatment_request": True}) self.fields['treatment_file__type'].choices = \ models.TreatmentFileType.get_types() self.fields['treatment_file__type'].help_text = \ models.TreatmentFileType.get_help() class AdministrativeActTreatmentFileFormSelection( AdministrativeActOpeFormSelection): pk = forms.IntegerField( label="", required=False, widget=widgets.DataTable( reverse_lazy('get-administrativeacttreatmentfile'), AdministrativeActTreatmentFileSelect, AdministrativeAct), validators=[valid_id(AdministrativeAct)]) class AdministrativeActTreatmentFileForm(AdministrativeActForm): form_admin_name = _("Administrative act - Treatment request - General") form_slug = "adminact-treatmentfile-general" act_type = forms.ChoiceField(label=_("Act type"), choices=[]) TYPES = [ FieldType('act_type', ActType, extra_args={"dct": {"intented_to_treatment_request": True}}), ] class AdministrativeActTreatmentFileModifForm( AdministrativeActModifForm, AdministrativeActTreatmentFileForm): pk = forms.IntegerField(required=False, widget=forms.HiddenInput) index = forms.IntegerField(label=_("Index"), required=False) # Exhibitions class ExhibitionSelect(DocumentItemSelect): _model = models.Exhibition form_admin_name = _("Exhibition - 001 - Search") form_slug = "exhibition-001-search" search_vector = forms.CharField( label=_("Full text search"), widget=widgets.SearchWidget( 'archaeological-finds', 'Exhibition' )) name = forms.CharField(label=_("Name")) exhibition_type = forms.ChoiceField(label=_("Type"), choices=[]) year = forms.IntegerField(label=_("Year")) reference = forms.CharField(label=_("Reference")) in_charge = forms.IntegerField( label=_("In charge"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person), validators=[valid_id(Person)]) description = forms.CharField(label=_("Description")) comment = forms.CharField(label=_("Comment")) TYPES = [ FieldType("exhibition_type", models.ExhibitionType), ] class ExhibitionFormSelection(CustomForm, forms.Form): SEARCH_AND_SELECT = True form_label = _("Exhibition search") associated_models = {'pk': models.Exhibition} currents = {'pk': models.Exhibition} pk = forms.CharField( label="", required=False, widget=widgets.DataTable( reverse_lazy('get-exhibition'), ExhibitionSelect, models.Exhibition, ), validators=[valid_ids(models.Exhibition)]) class ExhibitionForm(forms.ModelForm, CustomForm, ManageOldType): form_label = _("Exhibition") form_admin_name = _("Exhibition - 020 - Main form") form_slug = "exhibition-20-general" extra_form_modals = ["person"] pk = forms.IntegerField(label="", required=False, widget=forms.HiddenInput) name = forms.CharField(label=_("Name"), max_length=500) exhibition_type = forms.ChoiceField(label=_("Type"), choices=[]) year = forms.IntegerField(label=_("Year"), initial=lambda: datetime.datetime.now().year, validators=[validators.MinValueValidator(1000), validators.MaxValueValidator(2100)]) reference = forms.CharField( label=_("Reference"), max_length=500, required=False) in_charge = forms.IntegerField( label=_("Responsible"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person, new=True), validators=[valid_id(Person)], required=False) associated_basket_id = forms.IntegerField( label=_("Associated basket"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-findbasket'), associated_model=models.FindBasket), required=False) description = forms.CharField(label=_("Description"), widget=forms.Textarea, required=False) comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False) class Meta: model = models.Exhibition fields = [ "pk", "name", "exhibition_type", "year", "reference", "in_charge", "comment", "associated_basket_id", ] HEADERS = { "name": FormHeader(_("General")), } TYPES = [ FieldType("exhibition_type", models.ExhibitionType, empty_first=False), ] def __init__(self, *args, **kwargs): self.user = kwargs.pop("user") super().__init__(*args, **kwargs) type_field = self.fields["exhibition_type"] if len(type_field.choices) == 1: type_field.initial = type_field.choices[0][0] type_field.widget.attrs["readonly"] = True def clean_in_charge(self): return self._clean_model_field("in_charge", Person) def clean_exhibition_type(self): return self._clean_model_field("exhibition_type", models.ExhibitionType) def save(self, *args, **kwargs): obj = super().save(*args, **kwargs) obj = models.Exhibition.objects.get(pk=obj.pk) if self.user and not obj.history_creator: obj.history_creator = self.user obj.history_modifier = self.user obj.skip_history_when_saving = True obj.save() return obj class QANewExhibitionLoanForm(IshtarForm): extra_form_modals = [ "applicant_organisation", "exhibition_location", "insurance_provider", "in_charge" ] qa_exhibition_start = DateField(label=_("Exhibition start date")) qa_exhibition_end = DateField(label=_("Exhibition end date")) qa_applicant_organisation = forms.IntegerField( label=_("Beneficiary of the loan"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization'), associated_model=Organization, # new=True ), validators=[valid_id(Organization)]) qa_in_charge = forms.IntegerField( label=_("Scientific manager of the exhibition"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person'), associated_model=Person, # new=True ), validators=[valid_id(Person)]) qa_exhibition_location = forms.IntegerField( label=_("Exhibition location"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-warehouse'), associated_model=Warehouse, # new=True ), validators=[valid_id(Warehouse)], help_text=_("The exhibition location must have an organization attached.") ) qa_insurance_provider = forms.IntegerField( label=_("Insurance provider"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization'), associated_model=Organization, # new=True ), validators=[valid_id(Organization)], 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.exhibition = kwargs.pop('items')[0] super().__init__(*args, **kwargs) def clean(self): data = self.cleaned_data if not self.exhibition.associated_basket_id: raise forms.ValidationError( _("Cannot create loan when no basket is associated to this" " exhibition.")) return data def save(self): basket = self.exhibition.associated_basket if not basket: return values = { "year": self.cleaned_data["qa_exhibition_start"].year, "type": self.exhibition.exhibition_type.treatment_file_type, "exhibition_name": self.exhibition.name, "exhibition_start_date": self.cleaned_data["qa_exhibition_start"], "exhibition_end_date": self.cleaned_data["qa_exhibition_end"], "history_creator": self.user.user_ptr, "history_modifier": self.user.user_ptr, } try: exhibition_location = Warehouse.objects.get( pk=self.cleaned_data["qa_exhibition_location"] ) except Warehouse.DoesNotExist: return loan_name = f"{self.exhibition.name} | {exhibition_location}" values["name"] = loan_name values["exhibition_location"] = exhibition_location new_basket = basket.duplicate() basket_label = f"{_('Exhibition')} | {loan_name}" new_basket.label = basket_label new_basket.save() values["associated_basket_id"] = new_basket.id try: values["in_charge"] = Person.objects.get( pk=self.cleaned_data["qa_in_charge"] ) except Person.DoesNotExist: return if self.cleaned_data.get("qa_insurance_provider", None): try: values["insurance_provider"] = Organization.objects.get( pk=self.cleaned_data["qa_insurance_provider"] ) except Organization.DoesNotExist: return try: values["applicant_organisation"] = Organization.objects.get( pk=self.cleaned_data["qa_applicant_organisation"] ) except Organization.DoesNotExist: return obj = models.TreatmentFile.objects.create(**values) self.exhibition.treatment_files.add(obj) return obj