diff options
Diffstat (limited to 'archaeological_finds')
| -rw-r--r-- | archaeological_finds/forms_treatments.py | 52 | ||||
| -rw-r--r-- | archaeological_finds/migrations/0158_statementcondition_add_fields.py | 57 | ||||
| -rw-r--r-- | archaeological_finds/models_treatments.py | 157 |
3 files changed, 240 insertions, 26 deletions
diff --git a/archaeological_finds/forms_treatments.py b/archaeological_finds/forms_treatments.py index aacd73bc8..8832426f5 100644 --- a/archaeological_finds/forms_treatments.py +++ b/archaeological_finds/forms_treatments.py @@ -1259,6 +1259,9 @@ class QAStatementCondition(ManageOldType, forms.Form): "qa_conservatory_states", "qa_museum_marking_type", "qa_museum_inventory_marking_presence", + "qa_object_types", + "qa_material_types", + "qa_technical_processes", ] associated_models = { "qa_alterations": models.AlterationType, @@ -1269,6 +1272,9 @@ class QAStatementCondition(ManageOldType, forms.Form): "qa_integrities": models.IntegrityType, "follow_up_action": models.FollowUpActionType, "statement_condition_type_id": models.StatementConditionType, + "qa_object_types": models.ObjectType, + "qa_material_types": models.MaterialType, + "qa_technical_processes": models.TechnicalProcessType, "qa_museum_marking_type": models.MarkingType, "qa_museum_inventory_marking_presence": models.InventoryMarkingPresence, "qa_museum_inventory_conformity_id": models.InventoryConformity, @@ -1309,7 +1315,29 @@ class QAStatementCondition(ManageOldType, forms.Form): observations = forms.CharField(label=_("Observations"), widget=forms.Textarea, required=False) - HEADERS["qa_description"] = FormHeader(_("Find")) + HEADERS["qa_denomination"] = FormHeader(_("Find")) + qa_denomination = forms.CharField( + label=_("Denomination"), widget=forms.Textarea, + required=False) + qa_object_types = widgets.Select2MultipleField( + label=_("Object types"), + required=False, + ) + qa_object_type_quality_id = forms.ChoiceField( + label=_("Object type quality"), choices=[], required=False) + qa_material_types = widgets.Select2MultipleField( + label=_("Material types"), required=False + ) + qa_material_type_quality_id = forms.ChoiceField( + label=_("Material type quality"), choices=[], required=False + ) + qa_material_comment = forms.CharField( + label=_("Comment on the material"), widget=forms.Textarea, required=False + ) + qa_technical_processes = widgets.Select2MultipleField( + label=_("Technical processes"), + required=False, + ) qa_description = forms.CharField( label=_("Description"), widget=forms.Textarea, required=False ) @@ -1341,6 +1369,9 @@ class QAStatementCondition(ManageOldType, forms.Form): qa_museum_inventory_quantity = forms.IntegerField(label=_("Inventory quantity"), required=False, max_value=32000) qa_museum_observed_quantity = forms.IntegerField( label=_("Observed quantity"), required=False) + qa_quantity_comment = forms.CharField( + label=_("Comment on quantity"), widget=forms.Textarea, + required=False) qa_length = FloatField( label=_("Length (cm)"), widget=widgets.CentimeterMeterWidget, required=False ) @@ -1397,6 +1428,10 @@ class QAStatementCondition(ManageOldType, forms.Form): widget=widgets.Select2Multiple, required=False, ) + qa_conservatory_states_details = forms.CharField( + label=_("Conservatory state details"), required=False, + widget=forms.Textarea + ) qa_alterations = forms.MultipleChoiceField( label=_("Alteration"), choices=[], @@ -1409,6 +1444,10 @@ class QAStatementCondition(ManageOldType, forms.Form): widget=widgets.Select2Multiple, required=False, ) + qa_alteration_comment = forms.CharField( + label=_("Details regards alterations"), required=False, + widget=forms.Textarea + ) qa_recommended_treatments = forms.MultipleChoiceField( label=_("Recommended treatments"), choices=[], @@ -1436,6 +1475,14 @@ class QAStatementCondition(ManageOldType, forms.Form): empty_first=False), FieldType("qa_treatment_emergency_id", models.TreatmentEmergencyType), FieldType("qa_museum_inventory_conformity_id", models.InventoryConformity), + FieldType("qa_object_types", models.ObjectType, + is_multiple=True), + FieldType("qa_material_types", models.MaterialType, + is_multiple=True), + FieldType("qa_technical_processes", models.TechnicalProcessType, + is_multiple=True), + FieldType("qa_object_type_quality_id", models.ObjectTypeQualityType), + FieldType("qa_material_type_quality_id", models.MaterialTypeQualityType), ] PROFILE_FILTER = { "museum": ["qa_museum_observed_quantity", "qa_museum_marking_type", @@ -1459,7 +1506,7 @@ class QAStatementCondition(ManageOldType, forms.Form): def save(self): data = copy(self.cleaned_data) data["find_id"] = self.current_item.pk - applied = data.pop("applied") + applied = data["applied"] follow_up_actions = data.pop("follow_up_action") # remove m2m fields m2m = {} @@ -1497,5 +1544,4 @@ class QAStatementCondition(ManageOldType, forms.Form): if applied == "D": # draft exit return - st.applied = applied st.apply_validation() diff --git a/archaeological_finds/migrations/0158_statementcondition_add_fields.py b/archaeological_finds/migrations/0158_statementcondition_add_fields.py index 9b227b73d..9cee74f3b 100644 --- a/archaeological_finds/migrations/0158_statementcondition_add_fields.py +++ b/archaeological_finds/migrations/0158_statementcondition_add_fields.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.21 on 2026-06-26 15:38 +# Generated by Django 4.2.21 on 2026-06-27 16:03 from django.db import migrations, models import django.db.models.deletion @@ -18,6 +18,21 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name='statementcondition', + name='alteration_comment', + field=models.TextField(blank=True, default='', verbose_name='Details regards alterations'), + ), + migrations.AddField( + model_name='statementcondition', + name='conservatory_states_details', + field=models.TextField(blank=True, default='', verbose_name='Conservatory state details'), + ), + migrations.AddField( + model_name='statementcondition', + name='denomination', + field=models.TextField(blank=True, default='', verbose_name='Denomination'), + ), + migrations.AddField( + model_name='statementcondition', name='in_charge', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.person', verbose_name='In charge'), ), @@ -33,6 +48,21 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name='statementcondition', + name='material_comment', + field=models.TextField(blank=True, default='', verbose_name='Comment on the material'), + ), + migrations.AddField( + model_name='statementcondition', + name='material_type_quality', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='statement_conditions', to='archaeological_finds.materialtypequalitytype', verbose_name='Material type quality'), + ), + migrations.AddField( + model_name='statementcondition', + name='material_types', + field=models.ManyToManyField(blank=True, related_name='statement_conditions', to='archaeological_finds.materialtype', verbose_name='Material types'), + ), + migrations.AddField( + model_name='statementcondition', name='museum_conformity_comment', field=models.TextField(blank=True, default='', verbose_name='Comment on conformity'), ), @@ -48,6 +78,26 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name='statementcondition', + name='object_type_quality', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='statement_conditions', to='archaeological_finds.objecttypequalitytype', verbose_name='Object type quality'), + ), + migrations.AddField( + model_name='statementcondition', + name='object_types', + field=models.ManyToManyField(blank=True, related_name='statement_conditions', to='archaeological_finds.objecttype', verbose_name='Object types'), + ), + migrations.AddField( + model_name='statementcondition', + name='quantity_comment', + field=models.TextField(blank=True, default='', verbose_name='Comment on quantity'), + ), + migrations.AddField( + model_name='statementcondition', + name='technical_processes', + field=models.ManyToManyField(blank=True, related_name='statement_conditions', to='archaeological_finds.technicalprocesstype', verbose_name='Technical processes'), + ), + migrations.AddField( + model_name='statementcondition', name='verification_officers', field=models.TextField(blank=True, default='', verbose_name='Verification officers'), ), @@ -56,4 +106,9 @@ class Migration(migrations.Migration): name='applied', field=models.CharField(choices=[('D', 'Draft'), ('V', 'Validated')], default='D', verbose_name='Input status'), ), + migrations.AlterField( + model_name='statementcondition', + name='treatment', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='statement_conditions', to='archaeological_finds.treatment', verbose_name='Treatment'), + ), ] diff --git a/archaeological_finds/models_treatments.py b/archaeological_finds/models_treatments.py index e9cb727ea..c454c0610 100644 --- a/archaeological_finds/models_treatments.py +++ b/archaeological_finds/models_treatments.py @@ -61,6 +61,7 @@ from ishtar_common.models import ( SearchVectorConfig, ValueGetter, ) +from ishtar_common.data_importer import post_importer_action from ishtar_common.models_common import ( CompleteIdentifierItem, IdentifierItem, @@ -1700,6 +1701,7 @@ class StatementCondition( # associated find OVERLOADED_FIELDS = ( "description", + "denomination", "conservatory_comment", "length", "width", @@ -1717,15 +1719,24 @@ class StatementCondition( "find_number", "mark_text", "mark", + "object_type_quality_id", + "material_type_quality_id", + "material_comment", "museum_inventory_conformity_id", "museum_conformity_comment", "museum_inventory_quantity", "museum_observed_quantity", + "quantity_comment", + "conservatory_states_details", + "alteration_comment", ) OVERLOADED_M2M_FIELDS = ( + "object_types", + "material_types", "integrities", "conservatory_states", "recommended_treatments", + "technical_processes", "alterations", "alteration_causes", "museum_marking_type", @@ -1742,24 +1753,58 @@ class StatementCondition( last = models.BooleanField(_("Last"), default=True) find = models.ForeignKey(Find, verbose_name=_("Find"), on_delete=models.CASCADE, related_name="statement_conditions") + statement_condition_type = models.ForeignKey( + StatementConditionType, verbose_name=_("Type"), on_delete=models.PROTECT) treatment = models.ForeignKey( Treatment, verbose_name=_("Treatment"), on_delete=models.SET_NULL, null=True, blank=True, related_name="statement_conditions") - campaign_number = models.TextField(_("Campaign/observation number"), default="", - blank=True) - report_number = models.TextField(_("Report number"), default="", blank=True) - verification_officers = models.TextField(_("Verification officers"), default="", blank=True) in_charge = models.ForeignKey( Person, verbose_name=_("In charge"), null=True, blank=True, on_delete=models.SET_NULL) - statement_condition_type = models.ForeignKey( - StatementConditionType, verbose_name=_("Type"), on_delete=models.PROTECT) + verification_officers = models.TextField(_("Verification officers"), default="", blank=True) + campaign_number = models.TextField(_("Campaign/observation number"), default="", + blank=True) + report_number = models.TextField(_("Report number"), default="", blank=True) follow_up_actions = models.ManyToManyField( FollowUpActionType, verbose_name=_("Follow-up actions"), blank=True ) observations = models.TextField(_("Observations"), blank=True, default="") # find field + denomination = models.TextField(_("Denomination"), blank=True, default="") + object_types = models.ManyToManyField( + "ObjectType", verbose_name=_("Object types"),blank=True, + related_name="statement_conditions" + ) + object_type_quality = models.ForeignKey( + "ObjectTypeQualityType", + verbose_name=_("Object type quality"), + related_name="statement_conditions", + on_delete=models.SET_NULL, + blank=True, + null=True, + ) + material_types = models.ManyToManyField( + "MaterialType", verbose_name=_("Material types"), + related_name="statement_conditions", blank=True + ) + material_type_quality = models.ForeignKey( + "MaterialTypeQualityType", + verbose_name=_("Material type quality"), + related_name="statement_conditions", + on_delete=models.SET_NULL, + blank=True, + null=True, + ) + material_comment = models.TextField( + _("Comment on the material"), blank=True, default="" + ) + technical_processes = models.ManyToManyField( + "TechnicalProcessType", + verbose_name=_("Technical processes"), + related_name="statement_conditions", + blank=True, + ) description = models.TextField(_("Description"), blank=True, default="") # find fields - museum @@ -1789,6 +1834,9 @@ class StatementCondition( museum_observed_quantity = models.PositiveSmallIntegerField( _("Observed quantity"), blank=True, null=True ) + quantity_comment = models.TextField( + _("Comment on quantity"), blank=True, default="" + ) length = models.FloatField(_("Length (cm)"), blank=True, null=True) width = models.FloatField(_("Width (cm)"), blank=True, null=True) height = models.FloatField(_("Height (cm)"), blank=True, null=True) @@ -1815,12 +1863,23 @@ class StatementCondition( verbose_name=_("Integrity"), blank=True, ) + conservatory_states = models.ManyToManyField( + "ConservatoryState", + verbose_name=_("Conservatory states"), + blank=True, + ) + conservatory_states_details = models.TextField( + _("Conservatory state details"), blank=True, default="" + ) alterations = models.ManyToManyField( "AlterationType", verbose_name=_("Alteration"), blank=True ) alteration_causes = models.ManyToManyField( "AlterationCauseType", verbose_name=_("Alteration cause"), blank=True, ) + alteration_comment = models.TextField( + _("Details regards alterations"), blank=True, default="" + ) recommended_treatments = models.ManyToManyField( "RecommendedTreatmentType", verbose_name=_("Recommended treatments"), @@ -1833,11 +1892,6 @@ class StatementCondition( blank=True, null=True, ) - conservatory_states = models.ManyToManyField( - "ConservatoryState", - verbose_name=_("Conservatory states"), - blank=True, - ) conservatory_comment = models.TextField( _("Conservatory comment"), blank=True, default="" ) @@ -1898,6 +1952,44 @@ class StatementCondition( def _get_base_image_path(self): return f"{self.SLUG}/{self.date.year}" + @post_importer_action + def set_default_from_find(self, context, v): + """ + Set statement condition attributes from find + """ + if not v: + return + initial = self.get_initial_from_find(self.find, prefix="") + for key, value in initial.items(): + if not value: + continue + if key in self.OVERLOADED_FIELDS: + # simple attr + current_value = getattr(self, key) + if current_value: # attr set + continue + setattr(self, key, value) + continue + # m2m + if getattr(self, key).exists(): # attr set + continue + getattr(self, key).add(*value) + return + + set_default_from_find.post_save = True + + @post_importer_action + def set_apply_validation(self, context, v): + """ + Apply validation to find. + """ + if not v: + return + self.apply_validation() + return self + + set_apply_validation.post_save = True + @property def is_last(self): return not self.__class__.objects.filter( @@ -1953,6 +2045,18 @@ class StatementCondition( ) return initial + def _check_initial(self): + """ + Verify that there is only one initial statement condition + for this find. If there is many, set only the older to initial. + """ + q = self.__class__.objects.filter(find_id=self.find_id, + initial=True) + if q.count() < 2: + return + older = q.order_by("date", "pk").all()[0] + q.exclude(pk=older.pk).update(initial=False) + def _check_apply_validation(self): if not self.pk: # no previous state so apply immediatly @@ -1979,6 +2083,7 @@ class StatementCondition( obj.last = False obj.in_charge = None obj.treatment = None + obj.date = obj.find.created for k in ("campaign_number", "report_number", "observations", "verification_officers"): setattr(obj, k, "") @@ -1993,6 +2098,17 @@ class StatementCondition( continue getattr(obj, attr).add(*value) + @staticmethod + def _get_m2m(item: "MainItem", attr: str) -> list: + """ + Get m2m ids from one item. + """ + return list( + sorted( + list(getattr(item, attr).values_list("id", flat=True)) + ) + ) + def apply_validation(self): """ Copy statement condition fields to the associated find @@ -2005,16 +2121,8 @@ class StatementCondition( for attr in self.OVERLOADED_FIELDS: setattr(self.find, attr, getattr(self, attr)) for attr in self.OVERLOADED_M2M_FIELDS: - m2m = list( - sorted( - list(getattr(self.find, attr).values_list("id", flat=True)) - ) - ) - new_m2m = list( - sorted( - list(getattr(self, attr).values_list("id", flat=True)) - ) - ) + m2m = self._get_m2m(self.find, attr) + new_m2m = self._get_m2m(self, attr) if m2m == new_m2m: continue getattr(self.find, attr).clear() @@ -2063,9 +2171,14 @@ class StatementCondition( def save(self, *args, **kwargs): apply_validation = False - if self.applied in ("V", "T"): + if self.pk and self.applied == "V" and \ + self.__class__.objects.filter( + pk=self.pk).values_list("applied", flat=True)[0] == "D": + raise + # only apply when "applied" is from D to V apply_validation = self._check_apply_validation() super().save(*args, **kwargs) + self._check_initial() if apply_validation: self.apply_validation() |
