summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archaeological_finds/models_finds.py15
-rw-r--r--archaeological_warehouse/migrations/0112_auto_20210308_1628.py35
-rw-r--r--archaeological_warehouse/models.py46
-rw-r--r--archaeological_warehouse/templates/ishtar/sheet_container.html15
-rw-r--r--archaeological_warehouse/tests.py67
-rw-r--r--ishtar_common/migrations/0214_auto_20210308_1628.py25
-rw-r--r--ishtar_common/models.py3
7 files changed, 204 insertions, 2 deletions
diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py
index c3faf93d0..066bdb239 100644
--- a/archaeological_finds/models_finds.py
+++ b/archaeological_finds/models_finds.py
@@ -21,6 +21,7 @@ from collections import OrderedDict
import datetime
import uuid
+from django.apps import apps
from django.conf import settings
from django.contrib.gis.db import models
from django.contrib.postgres.indexes import GinIndex
@@ -2680,12 +2681,26 @@ class Find(BulkUpdatedItem, ValueGetter, DocumentItem, BaseHistorizedItem,
return True
def save(self, *args, **kwargs):
+ old_container = None
+ # fetch in db
+ if self.pk:
+ old_container = self.__class__.objects.filter(
+ pk=self.pk).values_list("container_id", flat=True)[0]
super(Find, self).save(*args, **kwargs)
self.skip_history_when_saving = True
if self.container_ref and not self.container:
self.container = self.container_ref
+ if self.container and self.container._calculate_weight():
+ self.container.save()
+ elif not self.container and old_container:
+ # force recalculation of weight when a find is removed
+ Container = apps.get_model("archaeological_warehouse.Container")
+ old_container = Container.objects.get(pk=old_container)
+ if old_container._calculate_weight():
+ old_container.save()
+
updated = self.update_external_id(save=False)
if updated:
self._cached_label_checked = False
diff --git a/archaeological_warehouse/migrations/0112_auto_20210308_1628.py b/archaeological_warehouse/migrations/0112_auto_20210308_1628.py
new file mode 100644
index 000000000..b1241b076
--- /dev/null
+++ b/archaeological_warehouse/migrations/0112_auto_20210308_1628.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.27 on 2021-03-08 16:28
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_warehouse', '0111_auto_20210225_1039'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='container',
+ name='cached_weight',
+ field=models.FloatField(blank=True, null=True, verbose_name='Cached weight (g)'),
+ ),
+ migrations.AddField(
+ model_name='container',
+ name='calculated_weight',
+ field=models.FloatField(blank=True, null=True, verbose_name='Calculated weight (g)'),
+ ),
+ migrations.AddField(
+ model_name='container',
+ name='weight',
+ field=models.FloatField(blank=True, null=True, verbose_name='Weight (g)'),
+ ),
+ migrations.AddField(
+ model_name='containertype',
+ name='tare_weight',
+ field=models.FloatField(blank=True, null=True, verbose_name='Tare weight (g)'),
+ ),
+ ]
diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py
index b2fa7853c..089a021af 100644
--- a/archaeological_warehouse/models.py
+++ b/archaeological_warehouse/models.py
@@ -36,7 +36,7 @@ from django.apps import apps
from ishtar_common.data_importer import post_importer_action, \
pre_importer_action
from ishtar_common.model_managers import ExternalIdManager, UUIDModelManager
-from ishtar_common.models import ValueGetter
+from ishtar_common.models import ValueGetter, get_current_profile
from ishtar_common.models_common import GeneralType, \
LightHistorizedItem, OwnPerms, Address, post_save_cache, \
DashboardFormItem, document_attached_changed, SearchAltName, \
@@ -590,6 +590,7 @@ class ContainerType(GeneralType):
width = models.IntegerField(_("Width (mm)"), blank=True, null=True)
height = models.IntegerField(_("Height (mm)"), blank=True, null=True)
volume = models.FloatField(_("Volume (l)"), blank=True, null=True)
+ tare_weight = models.FloatField(_("Tare weight (g)"), blank=True, null=True)
reference = models.CharField(_("Ref."), max_length=300, blank=True,
null=True)
order = models.IntegerField(_("Order"), default=10)
@@ -758,7 +759,8 @@ class Container(DocumentItem, Merge, LightHistorizedItem,
"location__name": _("Warehouse")
}
GEO_LABEL = "cached_label"
- CACHED_LABELS = ['cached_division', 'cached_label', 'cached_location', ]
+ CACHED_LABELS = ['cached_division', 'cached_label', 'cached_location',
+ 'cached_weight']
# alternative names of fields for searches
ALT_NAMES = {
@@ -960,6 +962,13 @@ class Container(DocumentItem, Merge, LightHistorizedItem,
related_name="children", blank=True, null=True)
index = models.IntegerField(_("Container ID"), blank=True, null=True,
db_index=True)
+ weight = models.FloatField(_("Weight (g)"), blank=True, null=True)
+ calculated_weight = models.FloatField(
+ _("Calculated weight (g)"), blank=True, null=True)
+ cached_weight = models.FloatField(
+ _("Cached weight (g)"), blank=True, null=True,
+ help_text=_("Entered weight if available otherwise calculated weight.")
+ )
old_reference = models.TextField(_("Old reference"), blank=True, default="")
external_id = models.TextField(_("External ID"), blank=True, default="")
auto_external_id = models.BooleanField(
@@ -1066,6 +1075,37 @@ class Container(DocumentItem, Merge, LightHistorizedItem,
cached_label = " - ".join(items)
return cached_label
+ def _generate_cached_weight(self):
+ return self.weight if self.weight else self.calculated_weight
+
+ def _calculate_weight(self) -> bool:
+ """
+ Calculate the weight of the contained finds + tare weight of the
+ container
+ :return: True if calculated weight is changed
+ """
+ profile = get_current_profile()
+ if profile.calculate_weight_on_full and self.finds.filter(
+ weight__isnull=True).count():
+ weight = None
+ else:
+ weight = sum(
+ w for w in self.finds.filter(weight__isnull=False).values_list(
+ "weight", flat=True).all())
+ weight += self.container_type.tare_weight \
+ if self.container_type.tare_weight else 0
+ if weight != self.calculated_weight:
+ self.calculated_weight = weight
+ return True
+ return False
+
+ @property
+ def get_calculated_weight_percent(self):
+ if not self.calculated_weight or not self.weight:
+ return (self.calculated_weight
+ - self.weight) / self.calculated_weight * 100
+ return 0
+
@property
def get_cached_division(self):
return self._generate_cached_division()
@@ -1564,6 +1604,8 @@ class Container(DocumentItem, Merge, LightHistorizedItem,
self._update_warehouse_max_division()
updated = False
+ updated += self._calculate_weight()
+
if not self.index and not self.container_type.stationary:
self.skip_history_when_saving = True
q = Container.objects.filter(
diff --git a/archaeological_warehouse/templates/ishtar/sheet_container.html b/archaeological_warehouse/templates/ishtar/sheet_container.html
index 98b640936..686bd08ff 100644
--- a/archaeological_warehouse/templates/ishtar/sheet_container.html
+++ b/archaeological_warehouse/templates/ishtar/sheet_container.html
@@ -111,6 +111,20 @@
{% endif %}
{% include "ishtar/blocks/sheet_creation_section.html" %}
{% field_flex "Old reference" item.old_reference %}
+ {% if item.get_calculated_weight_percent > 5 %}
+ <div class="alert alert-warning" role="alert">
+ <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> &nbsp;
+ {% trans "Calculated weight is bigger than entered weight (over 5%)." %}
+ </div>
+ {% field_flex "Weight (g)" item.weight %}
+ {% field_flex "Calculated weight (g)" item.calculated_weight %}
+ {% else %}
+ {% if item.weight %}
+ {% field_flex "Weight (g)" item.weight %}
+ {% elif item.calculated_weight %}
+ {% field_flex "Calculated weight (g)" item.calculated_weight %}
+ {% endif %}
+ {% endif %}
{% field_flex_full "Comment" item.comment "<pre>" "</pre>" %}
{% include "ishtar/blocks/sheet_json.html" %}
</div>
@@ -124,6 +138,7 @@
{% field_flex "Width (mm)" container_type.width %}
{% field_flex "Height (mm)" container_type.height %}
{% field_flex "Volume (l)" container_type.volume %}
+ {% field_flex "Tare weight (g)" container_type.tare_weight %}
{% field_flex "Reference" container_type.reference %}
</div>
{% endif %}
diff --git a/archaeological_warehouse/tests.py b/archaeological_warehouse/tests.py
index b65b68351..dc1744312 100644
--- a/archaeological_warehouse/tests.py
+++ b/archaeological_warehouse/tests.py
@@ -1144,3 +1144,70 @@ class ContainerTest(FindInit, TestCase):
container_1.get_material_types_code(),
"|".join(sorted([mat0.code, mat1.code, mat2.code])))
+ def test_calculated_weight(self):
+ self.create_finds()
+ self.create_finds()
+ self.create_finds()
+ find0 = self.finds[0]
+ find1 = self.finds[1]
+ find1.weight = 600
+ find1.save()
+ find2 = self.finds[2]
+ find2.weight = 700
+ find2.save()
+
+ ct = models.ContainerType.objects.all()[0]
+ ct.tare_weight = 200
+ ct.save()
+ container_1 = models.Container.objects.create(
+ reference="Test 1",
+ location=self.main_warehouse,
+ container_type=ct)
+ container_1.save()
+ self.assertEqual(container_1.calculated_weight, 200)
+ self.assertEqual(container_1.cached_weight, 200)
+ find0.container = container_1
+ find0.save()
+ container_1 = models.Container.objects.get(pk=container_1.pk)
+ # no weight -> tare weight
+ self.assertEqual(container_1.calculated_weight, 200)
+ self.assertEqual(container_1.cached_weight, 200)
+
+ find1.container = container_1
+ find1.save()
+ container_1 = models.Container.objects.get(pk=container_1.pk)
+ # tare weight + find1 weight
+ self.assertEqual(container_1.calculated_weight, 800)
+ self.assertEqual(container_1.cached_weight, 800)
+
+ find2.container = container_1
+ find2.save()
+ container_1 = models.Container.objects.get(pk=container_1.pk)
+ # tare weight + find1 weight + find2 weight
+ self.assertEqual(container_1.calculated_weight, 1500)
+ self.assertEqual(container_1.cached_weight, 1500)
+
+ profile, created = IshtarSiteProfile.objects.get_or_create(
+ slug='default', active=True)
+ profile.calculate_weight_on_full = True
+ profile.save()
+
+ container_1.save()
+ container_1 = models.Container.objects.get(pk=container_1.pk)
+ # a find with no weight is inside the container
+ self.assertEqual(container_1.calculated_weight, None)
+ self.assertEqual(container_1.cached_weight, None)
+
+ find0.container = None
+ find0.save()
+ # once the find with no weight is removed the weight is recalculated
+ container_1 = models.Container.objects.get(pk=container_1.pk)
+ self.assertEqual(container_1.calculated_weight, 1500)
+ self.assertEqual(container_1.cached_weight, 1500)
+
+ find0.container = container_1
+ find0.save()
+ container_1 = models.Container.objects.get(pk=container_1.pk)
+ self.assertEqual(container_1.calculated_weight, None)
+ self.assertEqual(container_1.cached_weight, None)
+
diff --git a/ishtar_common/migrations/0214_auto_20210308_1628.py b/ishtar_common/migrations/0214_auto_20210308_1628.py
new file mode 100644
index 000000000..eb9f01740
--- /dev/null
+++ b/ishtar_common/migrations/0214_auto_20210308_1628.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.27 on 2021-03-08 16:28
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0213_auto_20210302_0950'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='calculate_weight_on_full',
+ field=models.BooleanField(default=False, verbose_name='Container - calculate weight only when all find has a weight'),
+ ),
+ migrations.AlterField(
+ model_name='customform',
+ name='user_types',
+ field=models.ManyToManyField(blank=True, help_text='Deprecated - use profile types', to='ishtar_common.PersonType'),
+ ),
+ ]
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 0e5a39c1f..180acd626 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -748,6 +748,9 @@ class IshtarSiteProfile(models.Model, Cached):
"Only manage association of operations, context records "
"and finds.")
)
+ calculate_weight_on_full = models.BooleanField(
+ _("Container - calculate weight only when all find has a weight"),
+ default=False)
config = models.CharField(
_("Alternate configuration"), max_length=200,
choices=ALTERNATE_CONFIGS_CHOICES,