diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2020-04-17 13:20:42 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-02-28 12:15:20 +0100 |
commit | 52257bb404da82db28d497c3ece6de4b959e1fb9 (patch) | |
tree | ebd3f208b1d812a068939cc6ee0b6d4a376316b2 /archaeological_warehouse | |
parent | bc3b4054f96072443871553cfeed49a81d469cd8 (diff) | |
download | Ishtar-52257bb404da82db28d497c3ece6de4b959e1fb9.tar.bz2 Ishtar-52257bb404da82db28d497c3ece6de4b959e1fb9.zip |
Fix statistics for warehouse
Diffstat (limited to 'archaeological_warehouse')
4 files changed, 196 insertions, 127 deletions
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 %} -<div class="row"> - <div class="offset-lg-4 col-lg-4 offset-md-3 col-md-6 offset-sm-1 col-sm-10 col-12"> - <div class="card"> - {% include "ishtar/blocks/window_image.html" %} - <div class="card-body"> - <p class="card-text"> - <p class="window-refs"> - <strong>{{ item.name|default:"" }}</strong> - </p> - <p class="window-refs"> - {{ item.warehouse_type|default:"" }} - </p> - {% include "ishtar/blocks/sheet_external_id.html" %} - </p> + +{% if output != "ODT" and output != "PDF"%} +<ul class="nav nav-tabs" id="{{window_id}}-tabs" role="tablist"> + <li class="nav-item"> + <a class="nav-link active" id="{{window_id}}-general-tab" + data-toggle="tab" href="#{{window_id}}-general" role="tab" + aria-controls="{{window_id}}-general" aria-selected="true"> + {% trans "General" %} + </a> + </li> + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-content-tab" + data-toggle="tab" href="#{{window_id}}-content" role="tab" + aria-controls="{{window_id}}-content" aria-selected="true"> + {% trans "Content" %} + </a> + </li> + <li class="nav-item"> + <a class="nav-link" id="{{window_id}}-stats-tab" + data-toggle="tab" href="#{{window_id}}-stats" role="tab" + aria-controls="{{window_id}}-stats" aria-selected="false"> + {% trans "Statistics" %} + </a> + </li> +</ul> +{% endif %} + +<div class="tab-content" id="{{window_id}}-tab-content"> + + <div class="tab-pane fade show active" id="{{window_id}}-general" + role="tabpanel" aria-labelledby="{{window_id}}-general-tab"> + <div class="row"> + <div class="offset-lg-4 col-lg-4 offset-md-3 col-md-6 offset-sm-1 col-sm-10 col-12"> + <div class="card"> + {% include "ishtar/blocks/window_image.html" %} + <div class="card-body"> + <div class="card-text"> + <p class="window-refs"> + <strong>{{ item.name|default:"" }}</strong> + </p> + <p class="window-refs"> + {{ item.warehouse_type|default:"" }} + </p> + {% include "ishtar/blocks/sheet_external_id.html" %} + </div> + </div> + </div> </div> </div> - </div> -</div> -<div class='row'> - {% 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 "<pre>" "</pre>" %} - {% include "ishtar/blocks/sheet_json.html" %} -</div> + <div class='row'> + {% 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 "<pre>" "</pre>" %} + {% include "ishtar/blocks/sheet_json.html" %} + </div> -{% 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 %} -<h3>{% trans "Localisation"%}</h3> -<div class='row'> - {% with geo_item=item %} - {% if PROFILE.locate_warehouses %}{% include "ishtar/blocks/sheet_simple_map.html"%}{% endif %} - <div class="col-12 col-lg-6 flex-wrap"> - {% 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 %} + <h3>{% trans "Localisation"%}</h3> + <div class='row'> + {% with geo_item=item %} + {% if PROFILE.locate_warehouses %}{% include "ishtar/blocks/sheet_simple_map.html"%}{% endif %} + <div class="col-12 col-lg-6 flex-wrap"> + {% if PROFILE.locate_warehouses %}{% include "ishtar/blocks/sheet_coordinates.html"%}{% endif %} + {% with full=True %}{% include "ishtar/blocks/sheet_address_section.html" %}{% endwith %} + </div> + {% endwith %} + </div> + {% endif %} </div> - {% endwith %} -</div> -{% endif %} - -{% if item.containers.count %} -<h4>{% trans "Containers" %}</h4> -{% dynamic_table_document '' 'containers' 'location_id' item.pk 'TABLE_COLS' output %} -{% endif %} + <div class="tab-pane fade" id="{{window_id}}-content" + role="tabpanel" aria-labelledby="{{window_id}}-content-tab"> + {% if item.containers.count %} + <h4>{% trans "Containers" %}</h4> + {% dynamic_table_document '' 'containers' 'location_id' item.pk 'TABLE_COLS' output %} + {% else %} + <div class="alert alert-info"> + <i class="fa fa-exclamation-triangle"></i> + {% trans "No container inside this warehouse" %} + </div> + {% endif %} + </div> -<h3>{% trans "Statistics" %}</h3> -<small class="centered"><em>{% trans "These numbers are updated hourly" %}</em></small> - -<h4>{% trans "Finds" %}</h4> -<div class='row'> - {% 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 %} -</div> + <div class="tab-pane fade" id="{{window_id}}-stats" + role="tabpanel" aria-labelledby="{{window_id}}-stats-tab"> + <h3>{% trans "Statistics" %}</h3> + <small class="centered"><em>{% trans "These numbers are updated hourly" %}</em></small> + + <h4>{% trans "Finds" %}</h4> + <div class='row'> + {% 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 %} + </div> -{% if item.number_of_finds_by_place %} -<h4>{% trans "Finds by location in the warehouse" %}</h4> -{% for items in item.number_of_finds_by_place %} -{% if items %} -<table class='table table-striped datatables' - id="{{window_id}}-find-by-loca-{{forloop.counter}}"> - <thead> - <tr>{% for location_type in item.location_types %} - <th class="text-center">{{location_type|title}}</th>{% endfor %} - <th class="text-center">{% trans "Total" %}</th> - </tr> - </thead> - <tbody> - {% for item in items %} - <tr> - {% for local in item.0 %}<td>{{local}}</td>{% endfor %} - <td class="text-right">{{item.1}}</td> - </tr> - {% endfor %} - </tbody> -</table> -{% endif %} -{% endfor %} -{% endif %} + {% if item.number_of_finds_by_place %} + <h4>{% trans "Finds by location in the warehouse" %}</h4> + {% for items in item.number_of_finds_by_place %} + {% if items %} + <table class='table table-striped datatables' + id="{{window_id}}-find-by-loca-{{forloop.counter}}"> + <thead> + <tr>{% for location_type in item.location_types %} + <th class="text-center">{{location_type|title}}</th>{% endfor %} + <th class="text-center">{% trans "Total" %}</th> + </tr> + </thead> + <tbody> + {% for item in items %} + <tr> + {% for local in item.0 %}<td>{{local}}</td>{% endfor %} + <td class="text-right">{{item.1}}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% endif %} + {% endfor %} + {% endif %} + + <h4>{% trans "Containers" %}</h4> + <div class='row'> + {% trans "Number of containers" as number_of_containers_label %} + {% field_flex_2 number_of_containers_label item.number_of_containers %} + </div> -<h4>{% trans "Containers" %}</h4> -<div class='row'> - {% 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 %} + <h4>{% trans "Containers by location in the warehouse" %}</h4> + {% for items in item.number_of_containers_by_place %} + {% if items %} + <table class='table table-striped datatables' + id="{{window_id}}-container-by-loca-{{forloop.counter}}"> + <thead> + <tr>{% for location_type in item.location_types %} + <th class="text-center">{{location_type|title}}</th>{% endfor %} + <th class="text-center">{% trans "Total" %}</th> + </tr> + </thead> + <tbody> + {% for item in items %} + <tr> + {% for local in item.0 %}<td class="text-center">{{local}}</td>{% endfor %} + <td class="text-center">{{item.1}}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% endif %} + {% endfor %} + {% endif %} + </div> </div> -{% if item.number_of_containers_by_place %} -<h4>{% trans "Containers by location in the warehouse" %}</h4> -{% for items in item.number_of_containers_by_place %} -{% if items %} -<table class='table table-striped datatables' - id="{{window_id}}-container-by-loca-{{forloop.counter}}"> - <thead> - <tr>{% for location_type in item.location_types %} - <th class="text-center">{{location_type|title}}</th>{% endfor %} - <th class="text-center">{% trans "Total" %}</th> - </tr> - </thead> - <tbody> - {% for item in items %} - <tr> - {% for local in item.0 %}<td class="text-center">{{local}}</td>{% endfor %} - <td class="text-center">{{item.1}}</td> - </tr> - {% endfor %} - </tbody> -</table> -{% endif %} -{% endfor %} -{% endif %} - <script type="text/javascript"> $(document).ready( function () { datatable_options = { diff --git a/archaeological_warehouse/templates/ishtar/wizard/wizard_warehouse_divisions.html b/archaeological_warehouse/templates/ishtar/wizard/wizard_warehouse_divisions.html index dff23bc6c..2b11e9235 100644 --- a/archaeological_warehouse/templates/ishtar/wizard/wizard_warehouse_divisions.html +++ b/archaeological_warehouse/templates/ishtar/wizard/wizard_warehouse_divisions.html @@ -3,6 +3,6 @@ {% block form_head %} <div class="alert alert-info"> <i class="fa fa-exclamation-triangle"></i> - {% trans "Default division for this warehouse. Theses divisions are only used for imports." %}<br/> + {% trans "Default division for this warehouse. Theses divisions are only used for imports and statistics." %}<br/> </div> {% endblock %} |