From 52257bb404da82db28d497c3ece6de4b959e1fb9 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Fri, 17 Apr 2020 13:20:42 +0200 Subject: Fix statistics for warehouse --- .../migrations/0105_auto_20200407_1414.py | 6 + archaeological_finds/models_finds.py | 2 +- .../migrations/0103_auto_container_views.py | 13 +- archaeological_warehouse/models.py | 57 +++-- .../templates/ishtar/sheet_warehouse.html | 251 ++++++++++++--------- .../ishtar/wizard/wizard_warehouse_divisions.html | 2 +- 6 files changed, 203 insertions(+), 128 deletions(-) diff --git a/archaeological_finds/migrations/0105_auto_20200407_1414.py b/archaeological_finds/migrations/0105_auto_20200407_1414.py index b4c05ee8a..1f9bc88d3 100644 --- a/archaeological_finds/migrations/0105_auto_20200407_1414.py +++ b/archaeological_finds/migrations/0105_auto_20200407_1414.py @@ -23,4 +23,10 @@ class Migration(migrations.Migration): name='collection', field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='archaeological_warehouse.Warehouse', verbose_name='Collection'), ), + migrations.AlterField( + model_name='materialtype', + name='code', + field=models.CharField(blank=True, max_length=100, null=True, + verbose_name='Code'), + ), ] diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py index 646ae8088..c18b2f4f1 100644 --- a/archaeological_finds/models_finds.py +++ b/archaeological_finds/models_finds.py @@ -55,7 +55,7 @@ from archaeological_warehouse.models import Warehouse class MaterialType(HierarchicalType): - code = models.CharField(_("Code"), max_length=10, blank=True, null=True) + code = models.CharField(_("Code"), max_length=100, blank=True, null=True) recommendation = models.TextField(_("Recommendation"), blank=True, null=True) diff --git a/archaeological_warehouse/migrations/0103_auto_container_views.py b/archaeological_warehouse/migrations/0103_auto_container_views.py index f49b7be1f..eb2b32e5e 100644 --- a/archaeological_warehouse/migrations/0103_auto_container_views.py +++ b/archaeological_warehouse/migrations/0103_auto_container_views.py @@ -2,7 +2,7 @@ # Generated by Django 1.11.27 on 2020-04-08 18:23 from __future__ import unicode_literals -from django.db import migrations +from django.db import migrations, models import archaeological_warehouse.models import archaeological_finds.models @@ -35,4 +35,15 @@ class Migration(migrations.Migration): migrations.RunSQL( archaeological_finds.models.FindInsideContainer.CREATE_SQL), migrations.RunPython(migrate_to_collections), + migrations.CreateModel( + name='ContainerTree', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, + serialize=False, verbose_name='ID')), + ], + options={ + 'db_table': 'containers_tree', + 'managed': False, + }, + ), ] diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index a99db2ef7..41ec901a4 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -208,7 +208,7 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem, @property def number_of_finds(self): from archaeological_finds.models import Find - return Find.objects.filter(container__responsible=self).count() + return Find.objects.filter(container_ref__location=self).count() @property def number_of_finds_hosted(self): @@ -223,14 +223,16 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem, if not remaining_division: return [current_path] current_division = remaining_division.pop(0) - q = ContainerLocalisation.objects.filter( - division=current_division, + + base_q = Container.objects.filter( + container_type=current_division, + location=self ) + q = base_q for div, ref in current_path: - q = q.filter( - container__division__division=div, - container__division__reference=ref - ) + q = base_q.filter( + parent__container_type=div, + parent__reference=ref) res = [] old_ref = None if not q.count(): @@ -252,26 +254,28 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem, :return: ordered list of available paths. Each path is a list of tuple with the WarehouseDivisionLink and the reference. """ - divisions = list( - WarehouseDivisionLink.objects.filter(warehouse=self - ).order_by('order').all()) + divisions = [ + wd.container_type + for wd in WarehouseDivisionLink.objects.filter( + warehouse=self).order_by('order').all() + ] return self._get_divisions([], divisions) - def _number_of_items_by_place(self, model, division_key='division'): + def _number_of_items_by_place(self, model, division_key): res = {} paths = self.available_division_tuples[:] for path in paths: - q = model.objects cpath = [] for division, ref in path: + q = model.objects cpath.append(ref) attrs = { - division_key + "__division": division, - division_key + "__reference": ref + division_key + "container_type": division, + division_key + "reference": ref } q = q.filter(**attrs) if tuple(cpath) not in res: - res[tuple(cpath)] = q.count() + res[tuple(cpath)] = q.distinct().count() res = [(k, res[k]) for k in res] final_res, current_res, depth = [], [], 1 len_divisions = WarehouseDivisionLink.objects.filter( @@ -283,7 +287,7 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem, depth = len(path) if path[-1] == '-': continue - path = list(path) + ['' for idx in range(len_divisions - len(path))] + path = list(path) + ['' for __ in range(len_divisions - len(path))] current_res.append((path, nb)) final_res.append(current_res[:]) return final_res @@ -291,14 +295,15 @@ class Warehouse(Address, DocumentItem, GeoItem, QRCodeItem, DashboardFormItem, def _number_of_finds_by_place(self): from archaeological_finds.models import Find return self._number_of_items_by_place( - Find, division_key='container__division') + Find, division_key='inside_container__container__') @property def number_of_finds_by_place(self, update=False): return self._get_or_set_stats('_number_of_finds_by_place', update) def _number_of_containers_by_place(self): - return self._number_of_items_by_place(Container) + return self._number_of_items_by_place( + ContainerTree, 'container_parent__') @property def number_of_containers_by_place(self, update=False): @@ -421,7 +426,7 @@ class WarehouseDivisionLink(models.Model): return self.warehouse.uuid, self.container_type.txt_idx -class ContainerTree: +class ContainerTree(models.Model): CREATE_SQL = """ CREATE VIEW containers_tree AS WITH RECURSIVE rel_tree AS ( @@ -458,6 +463,17 @@ class ContainerTree: DROP VIEW IF EXISTS container_tree; DROP VIEW IF EXISTS containers_tree; """ + container = models.OneToOneField( + "archaeological_warehouse.Container", verbose_name=_("Container"), + related_name="container_tree_child", primary_key=True) + container_parent = models.ForeignKey( + "archaeological_warehouse.Container", + verbose_name=_("Container parent"), + related_name="container_tree_parent") + + class Meta: + managed = False + db_table = 'containers_tree' class Container(DocumentItem, Merge, LightHistorizedItem, QRCodeItem, GeoItem, @@ -795,8 +811,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, QRCodeItem, GeoItem, @classmethod def get_query_owns(cls, ishtaruser): return Q(history_creator=ishtaruser.user_ptr) | \ - Q(location__person_in_charge__ishtaruser=ishtaruser) | \ - Q(responsible__person_in_charge__ishtaruser=ishtaruser) + Q(location__person_in_charge__ishtaruser=ishtaruser) def get_precise_points(self): precise_points = super(Container, self).get_precise_points() diff --git a/archaeological_warehouse/templates/ishtar/sheet_warehouse.html b/archaeological_warehouse/templates/ishtar/sheet_warehouse.html index feb8b786a..1307425ff 100644 --- a/archaeological_warehouse/templates/ishtar/sheet_warehouse.html +++ b/archaeological_warehouse/templates/ishtar/sheet_warehouse.html @@ -8,124 +8,167 @@ {% block content %} -
-
-
- {% include "ishtar/blocks/window_image.html" %} -
-

-

- {{ item.name|default:"" }} -

-

- {{ item.warehouse_type|default:"" }} -

- {% include "ishtar/blocks/sheet_external_id.html" %} -

+ +{% if output != "ODT" and output != "PDF"%} + +{% endif %} + +
+ +
+
+
+
+ {% include "ishtar/blocks/window_image.html" %} +
+
+

+ {{ item.name|default:"" }} +

+

+ {{ item.warehouse_type|default:"" }} +

+ {% include "ishtar/blocks/sheet_external_id.html" %} +
+
+
-
-
-
- {% include "ishtar/blocks/sheet_creation_section.html" %} - {% field_flex_detail "Person in charge" item.person_in_charge %} - {% field_flex_detail "Organization" item.organization %} - {% trans "Default divisions" as def_div_label %} - {% field_flex def_div_label item.location_types|join:", " %} - {% field_flex_full "Comment" item.comment "
" "
" %} - {% include "ishtar/blocks/sheet_json.html" %} -
+
+ {% include "ishtar/blocks/sheet_creation_section.html" %} + {% field_flex_detail "Person in charge" item.person_in_charge %} + {% field_flex_detail "Organization" item.organization %} + {% trans "Default divisions" as def_div_label %} + {% field_flex def_div_label item.location_types|join:", " %} + {% field_flex_full "Comment" item.comment "
" "
" %} + {% include "ishtar/blocks/sheet_json.html" %} +
-{% if item.point_2d or item.multi_polygon or item.get_address or item.get_address_complement or item.get_postal_code or item.get_town %} -

{% trans "Localisation"%}

-
- {% with geo_item=item %} - {% if PROFILE.locate_warehouses %}{% include "ishtar/blocks/sheet_simple_map.html"%}{% endif %} -
- {% if PROFILE.locate_warehouses %}{% include "ishtar/blocks/sheet_coordinates.html"%}{% endif %} - {% with full=True %}{% include "ishtar/blocks/sheet_address_section.html" %}{% endwith %} + {% if item.point_2d or item.multi_polygon or item.get_address or item.get_address_complement or item.get_postal_code or item.get_town %} +

{% trans "Localisation"%}

+
+ {% with geo_item=item %} + {% if PROFILE.locate_warehouses %}{% include "ishtar/blocks/sheet_simple_map.html"%}{% endif %} +
+ {% if PROFILE.locate_warehouses %}{% include "ishtar/blocks/sheet_coordinates.html"%}{% endif %} + {% with full=True %}{% include "ishtar/blocks/sheet_address_section.html" %}{% endwith %} +
+ {% endwith %} +
+ {% endif %}
- {% endwith %} -
-{% endif %} - -{% if item.containers.count %} -

{% trans "Containers" %}

-{% dynamic_table_document '' 'containers' 'location_id' item.pk 'TABLE_COLS' output %} -{% endif %} +
+ {% if item.containers.count %} +

{% trans "Containers" %}

+ {% dynamic_table_document '' 'containers' 'location_id' item.pk 'TABLE_COLS' output %} + {% else %} +
+ + {% trans "No container inside this warehouse" %} +
+ {% endif %} +
-

{% trans "Statistics" %}

-{% trans "These numbers are updated hourly" %} - -

{% trans "Finds" %}

-
- {% trans "Number of attached finds" as number_of_attached_finds_label %} - {% field_flex_2 number_of_attached_finds_label item.number_of_finds %} - {% trans "Number of hosted finds" as number_of_hosted_finds_label %} - {% field_flex_2 number_of_hosted_finds_label item.number_of_finds_hosted %} -
+
+

{% trans "Statistics" %}

+ {% trans "These numbers are updated hourly" %} + +

{% trans "Finds" %}

+
+ {% trans "Number of attached finds" as number_of_attached_finds_label %} + {% field_flex_2 number_of_attached_finds_label item.number_of_finds %} + {% trans "Number of hosted finds" as number_of_hosted_finds_label %} + {% field_flex_2 number_of_hosted_finds_label item.number_of_finds_hosted %} +
-{% if item.number_of_finds_by_place %} -

{% trans "Finds by location in the warehouse" %}

-{% for items in item.number_of_finds_by_place %} -{% if items %} - - - {% for location_type in item.location_types %} - {% endfor %} - - - - - {% for item in items %} - - {% for local in item.0 %}{% endfor %} - - - {% endfor %} - -
{{location_type|title}}{% trans "Total" %}
{{local}}{{item.1}}
-{% endif %} -{% endfor %} -{% endif %} + {% if item.number_of_finds_by_place %} +

{% trans "Finds by location in the warehouse" %}

+ {% for items in item.number_of_finds_by_place %} + {% if items %} + + + {% for location_type in item.location_types %} + {% endfor %} + + + + + {% for item in items %} + + {% for local in item.0 %}{% endfor %} + + + {% endfor %} + +
{{location_type|title}}{% trans "Total" %}
{{local}}{{item.1}}
+ {% endif %} + {% endfor %} + {% endif %} + +

{% trans "Containers" %}

+
+ {% trans "Number of containers" as number_of_containers_label %} + {% field_flex_2 number_of_containers_label item.number_of_containers %} +
-

{% trans "Containers" %}

-
- {% trans "Number of containers" as number_of_containers_label %} - {% field_flex_2 number_of_containers_label item.number_of_containers %} + {% if item.number_of_containers_by_place %} +

{% trans "Containers by location in the warehouse" %}

+ {% for items in item.number_of_containers_by_place %} + {% if items %} + + + {% for location_type in item.location_types %} + {% endfor %} + + + + + {% for item in items %} + + {% for local in item.0 %}{% endfor %} + + + {% endfor %} + +
{{location_type|title}}{% trans "Total" %}
{{local}}{{item.1}}
+ {% endif %} + {% endfor %} + {% endif %} +
-{% if item.number_of_containers_by_place %} -

{% trans "Containers by location in the warehouse" %}

-{% for items in item.number_of_containers_by_place %} -{% if items %} - - - {% for location_type in item.location_types %} - {% endfor %} - - - - - {% for item in items %} - - {% for local in item.0 %}{% endfor %} - - - {% endfor %} - -
{{location_type|title}}{% trans "Total" %}
{{local}}{{item.1}}
-{% endif %} -{% endfor %} -{% endif %} -