summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archaeological_finds/forms_treatments.py15
-rw-r--r--archaeological_finds/models_finds.py9
-rw-r--r--archaeological_finds/models_treatments.py129
-rw-r--r--archaeological_finds/templates/ishtar/blocks/sheet_statement_condition.html4
-rw-r--r--archaeological_finds/views.py23
-rw-r--r--ishtar_common/templates/ishtar/forms/error.html9
-rw-r--r--ishtar_common/templates/ishtar/forms/success.html2
-rw-r--r--ishtar_common/urls.py5
-rw-r--r--ishtar_common/views.py4
9 files changed, 158 insertions, 42 deletions
diff --git a/archaeological_finds/forms_treatments.py b/archaeological_finds/forms_treatments.py
index 53a928fd8..fa9a03118 100644
--- a/archaeological_finds/forms_treatments.py
+++ b/archaeological_finds/forms_treatments.py
@@ -1258,7 +1258,7 @@ class QAStatementCondition(ManageOldType, forms.Form):
"qa_integrities",
"qa_conservatory_states",
"qa_museum_marking_type",
- "qa_museum_inventory_marking_presence"
+ "qa_museum_inventory_marking_presence",
]
associated_models = {
"qa_alterations": models.AlterationType,
@@ -1271,6 +1271,7 @@ class QAStatementCondition(ManageOldType, forms.Form):
"statement_condition_type_id": models.StatementConditionType,
"qa_museum_marking_type": models.MarkingType,
"qa_museum_inventory_marking_presence": models.InventoryMarkingPresence,
+ "qa_museum_inventory_conformity_id": models.InventoryConformity,
}
HEADERS = {}
pk = forms.IntegerField(required=False, widget=forms.HiddenInput)
@@ -1323,9 +1324,18 @@ class QAStatementCondition(ManageOldType, forms.Form):
widget=widgets.Select2Multiple,
required=False,
)
+ qa_mark_text = forms.CharField(label=_("Transcription of the marking"), required=False)
+ qa_mark = forms.CharField(label=_("Marking details"), widget=forms.Textarea, required=False)
+ qa_museum_inventory_conformity_id = forms.ChoiceField(
+ label=_("Conformity with inventory"), required=False, choices=[]
+ )
+ qa_museum_conformity_comment = forms.CharField(
+ label=_("Comment on conformity"), widget=forms.Textarea, required=False
+ )
- HEADERS["find_number"] = FormHeader(_("Dimensions / Quantities"))
+ HEADERS["qa_find_number"] = FormHeader(_("Dimensions / Quantities"))
qa_find_number = forms.IntegerField(label=_("Number of remains"), required=False)
+ 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_length = FloatField(
@@ -1422,6 +1432,7 @@ class QAStatementCondition(ManageOldType, forms.Form):
FieldType("statement_condition_type_id", models.StatementConditionType,
empty_first=False),
FieldType("qa_treatment_emergency_id", models.TreatmentEmergencyType),
+ FieldType("qa_museum_inventory_conformity_id", models.InventoryConformity),
]
PROFILE_FILTER = {
"museum": ["qa_museum_observed_quantity", "qa_museum_marking_type",
diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py
index dc62789d5..7e789a578 100644
--- a/archaeological_finds/models_finds.py
+++ b/archaeological_finds/models_finds.py
@@ -2855,12 +2855,17 @@ class Find(
first_statement_condition = previous = q.all()[0]
else: # if no initial is set get diff from the find
previous = self
+ # remove "_id" on fields
+ overloaded_fields = [
+ attr[:-len("_id")] if attr.endswith("_id") else attr
+ for attr in StatementCondition.OVERLOADED_FIELDS
+ ]
for idx, state in enumerate(statement_conditions_list):
diff = {}
initial = {} if not idx else None
- for field in StatementCondition._meta.get_fields():
+ for field in StatementCondition.get_model_fields():
attr = field.name
- if attr in StatementCondition.OVERLOADED_FIELDS:
+ if attr in overloaded_fields:
previous_value = getattr(previous, attr) or None
value = getattr(state, attr) or None
if previous_value == value:
diff --git a/archaeological_finds/models_treatments.py b/archaeological_finds/models_treatments.py
index 5a0fdde32..4a687e56e 100644
--- a/archaeological_finds/models_treatments.py
+++ b/archaeological_finds/models_treatments.py
@@ -18,6 +18,7 @@
# See the file COPYING for details.
import datetime
+import itertools
# nosec: used to build a controlled XML
import lxml.etree # nosec
import lxml.builder # nosec
@@ -1714,6 +1715,11 @@ class StatementCondition(
"dimensions_comment",
"treatment_emergency_id",
"find_number",
+ "mark_text",
+ "mark",
+ "museum_inventory_conformity_id",
+ "museum_conformity_comment",
+ "museum_inventory_quantity",
"museum_observed_quantity",
)
OVERLOADED_M2M_FIELDS = (
@@ -1753,38 +1759,8 @@ class StatementCondition(
observations = models.TextField(_("Observations"), blank=True, default="")
# find field
- integrities = models.ManyToManyField(
- "IntegrityType",
- verbose_name=_("Integrity"),
- blank=True,
- )
- conservatory_states = models.ManyToManyField(
- "ConservatoryState",
- verbose_name=_("Conservatory states"),
- blank=True,
- )
- recommended_treatments = models.ManyToManyField(
- "RecommendedTreatmentType",
- verbose_name=_("Recommended treatments"),
- blank=True,
- )
- treatment_emergency = models.ForeignKey(
- "TreatmentEmergencyType",
- verbose_name=_("Treatment emergency"),
- on_delete=models.SET_NULL,
- blank=True,
- null=True,
- )
- conservatory_comment = models.TextField(
- _("Conservatory comment"), blank=True, default=""
- )
- alterations = models.ManyToManyField(
- "AlterationType", verbose_name=_("Alteration"), blank=True
- )
- alteration_causes = models.ManyToManyField(
- "AlterationCauseType", verbose_name=_("Alteration cause"), blank=True,
- )
description = models.TextField(_("Description"), blank=True, default="")
+
# find fields - museum
museum_inventory_marking_presence = models.ManyToManyField(
"InventoryMarkingPresence", blank=True, related_name="statement_conditions",
@@ -1803,6 +1779,7 @@ class StatementCondition(
)
museum_conformity_comment = models.TextField(_("Comment on conformity"), blank=True,
default="")
+
# find field - dimensions
find_number = models.IntegerField(_("Number of remains"), blank=True, null=True)
museum_inventory_quantity = models.PositiveSmallIntegerField(
@@ -1814,11 +1791,11 @@ class StatementCondition(
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)
- volume = models.FloatField(_("Volume (l)"), blank=True, null=True)
- weight = models.FloatField(_("Weight (g)"), blank=True, null=True)
+ thickness = models.FloatField(_("Thickness (cm)"), blank=True, null=True)
diameter = models.FloatField(_("Diameter (cm)"), blank=True, null=True)
circumference = models.FloatField(_("Circumference (cm)"), blank=True, null=True)
- thickness = models.FloatField(_("Thickness (cm)"), blank=True, null=True)
+ volume = models.FloatField(_("Volume (l)"), blank=True, null=True)
+ weight = models.FloatField(_("Weight (g)"), blank=True, null=True)
clutter_long_side = models.FloatField(
_("Clutter - long side (cm)"), blank=True, null=True
)
@@ -1831,6 +1808,38 @@ class StatementCondition(
dimensions_comment = models.TextField(
_("Dimensions comment"), blank=True, default=""
)
+ # conservation
+ integrities = models.ManyToManyField(
+ "IntegrityType",
+ verbose_name=_("Integrity"),
+ blank=True,
+ )
+ alterations = models.ManyToManyField(
+ "AlterationType", verbose_name=_("Alteration"), blank=True
+ )
+ alteration_causes = models.ManyToManyField(
+ "AlterationCauseType", verbose_name=_("Alteration cause"), blank=True,
+ )
+ recommended_treatments = models.ManyToManyField(
+ "RecommendedTreatmentType",
+ verbose_name=_("Recommended treatments"),
+ blank=True,
+ )
+ treatment_emergency = models.ForeignKey(
+ "TreatmentEmergencyType",
+ verbose_name=_("Treatment emergency"),
+ on_delete=models.SET_NULL,
+ blank=True,
+ null=True,
+ )
+ conservatory_states = models.ManyToManyField(
+ "ConservatoryState",
+ verbose_name=_("Conservatory states"),
+ blank=True,
+ )
+ conservatory_comment = models.TextField(
+ _("Conservatory comment"), blank=True, default=""
+ )
# documents
documents = models.ManyToManyField(
Document,
@@ -1863,6 +1872,25 @@ class StatementCondition(
lbl += f" - {self.find}"
return lbl
+ @classmethod
+ def get_model_fields(cls):
+ """
+ Get fields sorted by declaration
+ """
+ # django's Field class defines custom __eq__ and __lt__ methods that
+ # reference an internal creation_counter. This allows to construct a
+ # list of all the fields on the model, and simply use sorted to get
+ # them in the order.
+ sortable_private_fields = [
+ f for f in cls._meta.private_fields
+ if isinstance(f, Field)
+ ]
+ return sorted(
+ itertools.chain(
+ cls._meta.concrete_fields, sortable_private_fields,
+ cls._meta.many_to_many)
+ )
+
def pk_str(self):
return str(self.pk)
@@ -1935,6 +1963,7 @@ class StatementCondition(
obj.initial = True
obj.last = False
obj.verification_officer = None
+ obj.treatment = None
for k in ("campaign_number", "report_number", "observations"):
setattr(obj, k, "")
# reinit with find fields
@@ -1994,6 +2023,38 @@ class StatementCondition(
# set last field and applied state
self.__class__.objects.filter(pk=self.pk).update(last=True, applied=self.applied)
+ def delete(self, using=None, keep_parents=False) -> bool:
+ self._error = None
+ find_id, initial = self.find_id, self.initial
+ q_has_statements = self.__class__.objects.filter(
+ find_id=find_id, initial=False)
+ if initial and q_has_statements.count():
+ # don't delete initial if there is statement condition
+ self._error = _("Initial state cannot be deleted if there is other statement condition.")
+ return
+ nb, __ = super().delete(using=using, keep_parents=keep_parents)
+ if not nb:
+ self._error = _("An unknow error occured.")
+ return
+ if initial: # no more statements conditions associated
+ return True
+ if not q_has_statements.count():
+ # no current statement condition left for this find
+ # delete initial
+ q_initial = self.__class__.objects.filter(
+ find_id=find_id, initial=True)
+ if q_initial.count():
+ q_initial.all()[0].delete()
+ return True
+
+ last = q_has_statements.order_by("-date").all()[0]
+ if last.last:
+ return True # last is the last
+ last.last = True
+ last.save()
+ q_has_statements.exclude(pk=last.pk).update(last=False)
+ return True
+
def save(self, *args, **kwargs):
apply_validation = False
if self.applied in ("V", "T"):
diff --git a/archaeological_finds/templates/ishtar/blocks/sheet_statement_condition.html b/archaeological_finds/templates/ishtar/blocks/sheet_statement_condition.html
index 23667852c..c994f3888 100644
--- a/archaeological_finds/templates/ishtar/blocks/sheet_statement_condition.html
+++ b/archaeological_finds/templates/ishtar/blocks/sheet_statement_condition.html
@@ -19,11 +19,9 @@
<a class="wait-button btn btn-success" href="/document/create/?statementcondition={{statement_condition.pk}}" title="Ajouter un document / une image">
<i class="fa fa-plus"></i> doc./image
</a>
- {% if statement_condition.applied == "D" %}
- <a class="btn btn-danger wait-button" href="#" data-target="{% url 'find-statement-condition-delete' statement_condition.pk %}" title="{% trans 'Delete' %}">
+ <a class="btn-qa btn btn-danger" href="#" data-target="{% url 'find-statement-condition-delete' statement_condition.pk %}" title="{% trans 'Delete' %}">
<i class="fa fa-trash" aria-hidden="true"></i>
</a>
- {% endif %}
</div>
</div>
{% endif %}
diff --git a/archaeological_finds/views.py b/archaeological_finds/views.py
index cde528a05..a805fb64b 100644
--- a/archaeological_finds/views.py
+++ b/archaeological_finds/views.py
@@ -19,6 +19,7 @@
from collections import OrderedDict
import json
+import urllib.parse
from django.conf import settings
from django.core.exceptions import PermissionDenied
@@ -1631,4 +1632,24 @@ def statement_condition_form(request, find_pk, statement_condition_pk=None,
"url": reverse(url, args=url_args)
})
-statement_condition_delete_form = statement_condition_form
+
+def statement_condition_delete_form(
+ request, statement_condition_pk=None, current_right=None):
+ try:
+ item = models.StatementCondition.objects.get(pk=statement_condition_pk)
+ except models.StatementCondition.DoesNotExist:
+ raise Http404()
+ # permission not provided
+ if not current_right:
+ raise PermissionDenied()
+ # specificaly check permission for own item, otherwise already checked
+ if "_own_" in current_right:
+ if not request.user.has_perm(current_right, item.find):
+ raise PermissionDenied()
+ if item.delete():
+ return HttpResponseRedirect(reverse("success"))
+ error = ""
+ if hasattr(item, "_error") and item._error:
+ error = urllib.parse.quote_plus(str(item._error))
+ return HttpResponseRedirect(
+ reverse("error") + f"?message={error}")
diff --git a/ishtar_common/templates/ishtar/forms/error.html b/ishtar_common/templates/ishtar/forms/error.html
new file mode 100644
index 000000000..7bedbabf2
--- /dev/null
+++ b/ishtar_common/templates/ishtar/forms/error.html
@@ -0,0 +1,9 @@
+{% extends "ishtar/forms/success.html" %}
+{% load i18n inline_formset table_form %}
+{% block main_content %}
+{% if message %}
+{{ message }}
+{% else %}
+{% trans "An error has been encountered. It may be necessary to refresh the table/sheet." %}
+{% endif %}
+{% endblock %}
diff --git a/ishtar_common/templates/ishtar/forms/success.html b/ishtar_common/templates/ishtar/forms/success.html
index a3885a813..21bd27dcb 100644
--- a/ishtar_common/templates/ishtar/forms/success.html
+++ b/ishtar_common/templates/ishtar/forms/success.html
@@ -29,11 +29,13 @@ $(document).ready(function(){
</button>
</div>
<div class="modal-body form-row">
+ {% block main_content %}
{% if message %}
{{ message }}
{% else %}
{% trans "Changes made successfully. It may be necessary to refresh the table/sheet." %}
{% endif %}
+ {% endblock %}
</div>
</div>
</div>
diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py
index 827e85a7a..201e4fdbc 100644
--- a/ishtar_common/urls.py
+++ b/ishtar_common/urls.py
@@ -414,6 +414,11 @@ urlpatterns = [
views.SuccessView.as_view(),
name="success",
),
+ re_path(
+ r"^error(?:/(?P<context>[a-z-]+)(?:/(?P<arg>[0-9a-z-|]+))?)?/$",
+ views.ErrorView.as_view(),
+ name="error",
+ ),
]
menu = Menu(None)
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index dbaf8626b..03ab3f3f4 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -3258,6 +3258,10 @@ class SuccessView(TemplateView):
return data
+class ErrorView(SuccessView):
+ template_name = "ishtar/forms/error.html"
+
+
class BookmarkList(
SearchQueryMixin, JSONResponseMixin, LoginRequiredMixin, TemplateView
):