summaryrefslogtreecommitdiff
path: root/archaeological_finds
diff options
context:
space:
mode:
Diffstat (limited to 'archaeological_finds')
-rw-r--r--archaeological_finds/forms_treatments.py52
-rw-r--r--archaeological_finds/migrations/0158_statementcondition_add_fields.py57
-rw-r--r--archaeological_finds/models_treatments.py157
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()