diff options
| author | Étienne Loks <etienne.loks@iggdrasil.net> | 2020-09-25 15:26:38 +0200 | 
|---|---|---|
| committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-02-28 12:15:20 +0100 | 
| commit | 011fff384002b8e75dc69e46b884cb2b9e42b140 (patch) | |
| tree | 62333f93d1363591ea60b2e6b82bf9988bfc0cda | |
| parent | 2d35da2cd7c32dc0938d5235838d5488b319e8c9 (diff) | |
| download | Ishtar-011fff384002b8e75dc69e46b884cb2b9e42b140.tar.bz2 Ishtar-011fff384002b8e75dc69e46b884cb2b9e42b140.zip  | |
Containers: fix statistics on warehouse sheet
| -rw-r--r-- | archaeological_warehouse/migrations/0104_auto_20200925_1024.py | 31 | ||||
| -rw-r--r-- | archaeological_warehouse/models.py | 102 | ||||
| -rw-r--r-- | archaeological_warehouse/templates/ishtar/sheet_warehouse.html | 4 | ||||
| -rw-r--r-- | ishtar_common/models.py | 9 | 
4 files changed, 106 insertions, 40 deletions
diff --git a/archaeological_warehouse/migrations/0104_auto_20200925_1024.py b/archaeological_warehouse/migrations/0104_auto_20200925_1024.py new file mode 100644 index 000000000..f82b25b19 --- /dev/null +++ b/archaeological_warehouse/migrations/0104_auto_20200925_1024.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.27 on 2020-09-25 10:24 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + +    dependencies = [ +        ('archaeological_warehouse', '0103_auto_container_views'), +    ] + +    operations = [ +        migrations.AddField( +            model_name='historicalwarehouse', +            name='max_division_number', +            field=models.IntegerField(default=0, help_text='Automatically generated', verbose_name='Number maximum of division'), +        ), +        migrations.AddField( +            model_name='warehouse', +            name='max_division_number', +            field=models.IntegerField(default=0, help_text='Automatically generated', verbose_name='Number maximum of division'), +        ), +        migrations.AlterField( +            model_name='container', +            name='container_type', +            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='containers', to='archaeological_warehouse.ContainerType', verbose_name='Container type'), +        ), +    ] diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index 096ff0b6c..870f10d95 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -25,7 +25,7 @@ from django.conf import settings  from django.contrib.gis.db import models  from django.contrib.postgres.indexes import GinIndex  from django.core.urlresolvers import reverse -from django.db.models import Q, Max +from django.db.models import Q, Max, Count  from django.db.models.signals import post_save, post_delete, m2m_changed  from django.template.defaultfilters import slugify  from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy @@ -131,6 +131,9 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem,      external_id = models.TextField(_("External ID"), blank=True, null=True)      auto_external_id = models.BooleanField(          _("External ID is set automatically"), default=False) +    max_division_number = models.IntegerField( +        _("Number maximum of division"), default=0, +        help_text=_("Automatically generated"))      SUB_ADDRESSES = ["organization", "person_in_charge"]      class Meta: @@ -190,10 +193,11 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem,      @property      def location_types(self): +        if not self.max_division_number: +            return []          return [ -            wd.container_type.label -            for wd in WarehouseDivisionLink.objects.filter( -                warehouse=self).order_by('order').all() if wd.container_type +            "{} {}".format(_("Division"), idx + 1) +            for idx in range(self.max_division_number)          ]      @property @@ -227,33 +231,53 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem,      def _get_divisions(self, current_path, remaining_division, depth=0):          if not remaining_division:              return [current_path] -        current_division = remaining_division.pop(0) +        remaining_division.pop(0) -        base_q = Container.objects.filter( -            container_type=current_division, -            location=self -        ) -        q = base_q -        for div, ref in current_path: -            q = base_q.filter( -                parent__container_type=div, -                parent__reference=ref) +        query_location = "location" +        for __ in range(depth): +            query_location = "parent__" + query_location +        base_q = Container.objects.filter(**{query_location: self}) + +        q = base_q.annotate(nb_children=Count("children__id")).exclude( +            nb_children=0) + +        if not current_path: +            q = q.annotate(nb_parent=Count("parent__id")).filter( +                nb_parent=0) + +        for idx, p in enumerate(reversed(current_path)): +            parent_id, __ = p +            key = "parent__" * (idx + 1) + "id" +            q = q.filter(**{key: parent_id})          res = [] -        old_ref = None +        old_ref, ct = None, None          if not q.count():              return [current_path] -        for ref in q.values('reference').order_by('reference').all(): -            if ref['reference'] == old_ref: +        q = q.values( +            'id', 'reference', 'container_type__label', 'container_type_id' +        ).order_by('container_type__label', 'reference') + +        DIVISION_TEMPLATE = """<a class="display_details" +    href="#" onclick="load_window('/show-container/{id}/')"> +    <i class="fa fa-info-circle" aria-hidden="true"></i></a> +    {container} {ref}""" +        for ref in q.all(): +            if ref['reference'] == old_ref and \ +                    ref["container_type__label"] == ct:                  continue              old_ref = ref['reference'] +            ct = ref["container_type__label"]              cpath = current_path[:] -            cpath.append((current_division, ref['reference'])) +            lbl = DIVISION_TEMPLATE.format( +                id=ref["id"], container=ref["container_type__label"], +                ref=ref['reference']) +            cpath.append((ref["id"], lbl))              remaining_division = list(                  ContainerType.objects.filter(                      containers__parent__reference=ref['reference'], -                    containers__parent__container_type=current_division, -                    containers__location=self, -                    stationary=True).distinct()) +                    containers__parent__container_type_id=ref[ +                        "container_type_id"], +                    containers__location=self).distinct())              for r in self._get_divisions(cpath, remaining_division[:],                                           depth + 1):                  res.append(r) @@ -263,7 +287,7 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem,      def available_division_tuples(self):          """          :return: ordered list of available paths. Each path is a list of -        tuple with the container type and the reference. +        tuple with the container type and the full reference.          """          top_divisions = list(              ContainerType.objects.filter( @@ -278,20 +302,16 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem,          paths = self.available_division_tuples[:]          for path in paths:              cpath = [] -            cdiv_path = [] -            for division, ref in path: -                cpath.append(ref) -                cdiv_path.append(division) +            for container_id, lbl in path: +                cpath.append((container_id, lbl))                  if tuple(cpath) in res:                      continue                  q = model.objects -                reversed_cdiv = list(reversed(cdiv_path)) -                for idx, new_ref in enumerate(reversed(cpath)): -                    division = reversed_cdiv[idx] +                for idx, p in enumerate(reversed(cpath)): +                    container_id, __ = p                      div_key = division_key + "parent__" * idx                      attrs = { -                        div_key + "container_type": division, -                        div_key + "reference": new_ref +                        div_key + "id": container_id                      }                      q = q.filter(**attrs)                  if count_filter: @@ -300,16 +320,18 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem,          res = [(k, res[k]) for k in res]          final_res, current_res, depth = [], [], 1 -        len_divisions = WarehouseDivisionLink.objects.filter( -            warehouse=self).count() +        len_divisions = self.max_division_number          for path, nb in sorted(res, key=lambda x: (len(x[0]), x[0])): +            if len(path) > len_divisions: +                continue              if depth != len(path):                  final_res.append(current_res[:])                  current_res = []                  depth = len(path)              if path[-1] == '-':                  continue -            path = list(path) + ['' for __ in range(len_divisions - len(path))] +            path = [k[1] for k in path] +            path = path + ['' for __ in range(len_divisions - len(path))]              current_res.append((path, nb))          final_res.append(current_res[:])          return final_res @@ -1173,10 +1195,22 @@ class Container(DocumentItem, Merge, LightHistorizedItem, QRCodeItem, GeoItem,              else:                  self.index = 1 +    def _update_warehouse_max_division(self): +        number = 0 +        parent = self.parent_id +        while parent: +            number += 1 +            parent = Container.objects.filter(pk=parent).values_list( +                "parent_id")[0][0] +        if number > self.location.max_division_number: +            self.location.max_division_number = number +            self.location.save() +      def save(self, *args, **kwargs):          self.pre_save()          super(Container, self).save(*args, **kwargs)          self._change_child_location(self) +        self._update_warehouse_max_division()          updated = False          if not self.index: diff --git a/archaeological_warehouse/templates/ishtar/sheet_warehouse.html b/archaeological_warehouse/templates/ishtar/sheet_warehouse.html index dcaa12215..b6f93cc57 100644 --- a/archaeological_warehouse/templates/ishtar/sheet_warehouse.html +++ b/archaeological_warehouse/templates/ishtar/sheet_warehouse.html @@ -144,7 +144,7 @@              <tbody>              {% for item in items %}              <tr> -                {% for local in item.0 %}<td>{{local}}</td>{% endfor %} +                {% for local in item.0 %}<td>{{local|safe}}</td>{% endfor %}                  <td class="text-right">{{item.1}}</td>              </tr>              {% endfor %} @@ -175,7 +175,7 @@              <tbody>              {% for item in items %}              <tr> -                {% for local in item.0 %}<td class="text-center">{{local}}</td>{% endfor %} +                {% for local in item.0 %}<td>{{local|safe}}</td>{% endfor %}                  <td class="text-center">{{item.1}}</td>              </tr>              {% endfor %} diff --git a/ishtar_common/models.py b/ishtar_common/models.py index d26a64e38..2d3320e2e 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -3406,15 +3406,16 @@ class DashboardFormItem(object):      def _get_or_set_stats(self, funcname, update,                            timeout=settings.CACHE_TIMEOUT,                            expected_type=None): +        values = {} +        from_cache = False          model_name = self._meta.app_label + "." + self._meta.model_name          sc, __ = StatsCache.objects.get_or_create(              model=model_name, model_pk=self.pk          )          now = datetime.datetime.now() -        values = {} -        from_cache = False -        if not update and sc.values and funcname in sc.values and ( -                sc.updated + datetime.timedelta(seconds=timeout)) > now: +        if not settings.DEBUG and ( +                not update and sc.values and funcname in sc.values and ( +                sc.updated + datetime.timedelta(seconds=timeout)) > now):              values = sc.values              from_cache = True          if funcname not in values:  | 
