diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-03-09 11:14:48 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-03-09 11:14:48 +0100 |
commit | b6db29397aa518cd084bba3f5933644680604e01 (patch) | |
tree | b742211e062221e851c04f6ddcf580ac3faf395c | |
parent | 698bc976af6db131a7b0f7468dc12b0313dce198 (diff) | |
download | Ishtar-b6db29397aa518cd084bba3f5933644680604e01.tar.bz2 Ishtar-b6db29397aa518cd084bba3f5933644680604e01.zip |
Container: manage calculated weight
-rw-r--r-- | archaeological_finds/models_finds.py | 15 | ||||
-rw-r--r-- | archaeological_warehouse/migrations/0112_auto_20210308_1628.py | 35 | ||||
-rw-r--r-- | archaeological_warehouse/models.py | 46 | ||||
-rw-r--r-- | archaeological_warehouse/templates/ishtar/sheet_container.html | 15 | ||||
-rw-r--r-- | archaeological_warehouse/tests.py | 67 | ||||
-rw-r--r-- | ishtar_common/migrations/0214_auto_20210308_1628.py | 25 | ||||
-rw-r--r-- | ishtar_common/models.py | 3 |
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> + {% 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, |