diff --git a/CHANGES.rst b/CHANGES.rst index c55f3d55a1..2e016ed85a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,7 @@ Changelog **Added** +- #1544 Progress indicator for Batch listing - #1536 Integrated Setup and Profiles from senaite.lims - #1534 Integrate browser resources from senaite.lims - #1529 Moved contentmenu provider into core diff --git a/bika/lims/browser/analysisrequest/analysisrequests.py b/bika/lims/browser/analysisrequest/analysisrequests.py index 55eb107c4a..ef8ebb6831 100644 --- a/bika/lims/browser/analysisrequest/analysisrequests.py +++ b/bika/lims/browser/analysisrequest/analysisrequests.py @@ -84,7 +84,8 @@ def __init__(self, context, request): "sortable": True, }), ("Progress", { "title": "Progress", - "sortable": False, + "index": "getProgress", + "sortable": True, "toggle": True}), ("getId", { "title": _("Sample ID"), @@ -573,7 +574,8 @@ def folderitem(self, obj, item, index): item["getAnalysesNum"] = "" # Progress - progress_perc = self.get_progress_percentage(obj) + progress_perc = obj.getProgress + item["Progress"] = progress_perc item["replace"]["Progress"] = get_progress_bar_html(progress_perc) item["BatchID"] = obj.getBatchID @@ -732,32 +734,6 @@ def folderitem(self, obj, item, index): return item - def get_progress_percentage(self, ar_brain): - """Returns the percentage of completeness of the Analysis Request - """ - review_state = ar_brain.review_state - if review_state == "published": - return 100 - - numbers = ar_brain.getAnalysesNum - - num_analyses = numbers[1] or 0 - if not num_analyses: - return 0 - - # [verified, total, not_submitted, to_be_verified] - num_to_be_verified = numbers[3] or 0 - num_verified = numbers[0] or 0 - - # 2 steps per analysis (submit, verify) plus one step for publish - max_num_steps = (num_analyses * 2) + 1 - num_steps = num_to_be_verified + (num_verified * 2) - if not num_steps: - return 0 - if num_steps > max_num_steps: - return 100 - return (num_steps * 100) / max_num_steps - @property def copy_to_new_allowed(self): mtool = api.get_tool("portal_membership") diff --git a/bika/lims/browser/batchfolder.py b/bika/lims/browser/batchfolder.py index d97b4528ba..9d94b68c00 100644 --- a/bika/lims/browser/batchfolder.py +++ b/bika/lims/browser/batchfolder.py @@ -21,12 +21,13 @@ import collections from bika.lims import api -from bika.lims.api.security import check_permission from bika.lims import bikaMessageFactory as _ +from bika.lims.api.security import check_permission from bika.lims.browser.bika_listing import BikaListingView from bika.lims.interfaces import IClient from bika.lims.permissions import AddBatch from bika.lims.utils import get_link +from bika.lims.utils import get_progress_bar_html class BatchFolderContentsView(BikaListingView): @@ -41,7 +42,7 @@ def __init__(self, context, request): "portal_type": "Batch", "sort_on": "created", "sort_order": "descending", - "is_active": True + "is_active": True, } self.context_actions = {} @@ -59,6 +60,11 @@ def __init__(self, context, request): ("Title", { "title": _("Title"), "index": "title", }), + ("Progress", { + "title": _("Progress"), + "index": "getProgress", + "sortable": True, + "toggle": True}), ("BatchID", { "title": _("Batch ID"), "index": "getId", }), @@ -167,6 +173,11 @@ def folderitem(self, obj, item, index): created = api.get_creation_date(obj) date = obj.getBatchDate() + # total sample progress + progress = obj.getProgress() + item["Progress"] = progress + item["replace"]["Progress"] = get_progress_bar_html(progress) + item["BatchID"] = bid item["ClientBatchID"] = cbid item["replace"]["BatchID"] = get_link(url, bid) diff --git a/bika/lims/catalog/__init__.py b/bika/lims/catalog/__init__.py index 708ca3290f..152332bce6 100644 --- a/bika/lims/catalog/__init__.py +++ b/bika/lims/catalog/__init__.py @@ -22,6 +22,7 @@ from .analysisrequest_catalog import CATALOG_ANALYSIS_REQUEST_LISTING # noqa from .analysis_catalog import CATALOG_ANALYSIS_LISTING # noqa from .autoimportlogs_catalog import CATALOG_AUTOIMPORTLOGS_LISTING # noqa +from .bika_catalog import BIKA_CATALOG # noqa from .worksheet_catalog import CATALOG_WORKSHEET_LISTING # noqa from .report_catalog import CATALOG_REPORT_LISTING # noqa from .bikasetup_catalog import SETUP_CATALOG # noqa diff --git a/bika/lims/catalog/analysisrequest_catalog.py b/bika/lims/catalog/analysisrequest_catalog.py index 8bb69662b2..a0ef71c40f 100644 --- a/bika/lims/catalog/analysisrequest_catalog.py +++ b/bika/lims/catalog/analysisrequest_catalog.py @@ -116,6 +116,7 @@ "getSamplingWorkflowEnabled", "assigned_state", "getInternalUse", + "getProgress", ] # Adding basic indexes diff --git a/bika/lims/content/analysisrequest.py b/bika/lims/content/analysisrequest.py index 5d594d1d16..123118f3c4 100644 --- a/bika/lims/content/analysisrequest.py +++ b/bika/lims/content/analysisrequest.py @@ -131,6 +131,7 @@ IMG_SRC_RX = re.compile(r' max_num_steps: + return 100 + return (num_steps * 100) / max_num_steps + registerType(AnalysisRequest, PROJECTNAME) diff --git a/bika/lims/content/batch.py b/bika/lims/content/batch.py index 7236c0c010..a1032bc02c 100644 --- a/bika/lims/content/batch.py +++ b/bika/lims/content/batch.py @@ -249,5 +249,16 @@ def getLabelNames(self): labels = [label.getObject().title for label in uc(UID=uids)] return labels + def getProgress(self): + """Returns the progress in percent of all samples + """ + total_progress = 0 + samples = self.getAnalysisRequests() + total = len(samples) + if total > 0: + sample_progresses = map(lambda s: s.getProgress(), samples) + total_progress = sum(sample_progresses) / total + return total_progress + registerType(Batch, PROJECTNAME) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 277ee69cf5..0b2f95908d 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -213,6 +213,7 @@ ("bika_catalog", "getDateReceived"), ("bika_catalog", "getDateSampled"), ("bika_catalog", "review_state"), + ("bika_catalog", "getProgress"), ("bika_setup_catalog", "path"), ("bika_setup_catalog", "UID"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index da3cc29183..27d26a4aa8 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -18,14 +18,15 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. +import re from collections import defaultdict from operator import itemgetter -import re import transaction from bika.lims import api from bika.lims import logger from bika.lims.api.mail import is_valid_email_address +from bika.lims.catalog import BIKA_CATALOG from bika.lims.catalog import CATALOG_ANALYSIS_LISTING from bika.lims.catalog import CATALOG_ANALYSIS_REQUEST_LISTING from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG @@ -39,6 +40,7 @@ from bika.lims.upgrade import upgradestep from bika.lims.upgrade.utils import UpgradeUtils from Products.Archetypes.config import UID_CATALOG +from Products.ZCatalog.ProgressHandler import ZLogHandler from zope.interface import alsoProvides version = "1.3.3" # Remember version number in metadata.xml and setup.py @@ -388,6 +390,13 @@ def upgrade(tool): # https://github.com/senaite/senaite.core/pull/1542 fix_email_address(portal) + # Add metadata for progress bar + # https://github.com/senaite/senaite.core/pull/1544 + # Add progress metadata column for Samples + add_metadata(portal, CATALOG_ANALYSIS_REQUEST_LISTING, "getProgress", True) + # Add progress metadata column for Batches + add_metadata(portal, BIKA_CATALOG, "getProgress", True) + logger.info("{0} upgraded to version {1}".format(product, version)) return True @@ -863,6 +872,21 @@ def fix_email_address(portal, portal_types=None, catalog_id="portal_catalog"): logger.info("Fixing email addresses [DONE]") +def add_metadata(portal, catalog_id, column, refresh_catalog=False): + logger.info("Adding '{}' metadata to '{}' ...".format(column, catalog_id)) + catalog = api.get_tool(catalog_id) + if column in catalog.schema(): + logger.info("Metadata '{}' already in catalog '{}' [SKIP]" + .format(column, catalog_id)) + return + catalog.addColumn(column) + + if refresh_catalog: + logger.info("Refreshing catalog '{}' ...".format(catalog_id)) + handler = ZLogHandler(steps=100) + catalog.refreshCatalog(pghandler=handler) + + def remove_arimports(portal): """Removes arimports folder """ @@ -876,3 +900,4 @@ def remove_arimports(portal): portal.manage_delObjects(arimports.getId()) logger.info("Removing AR Imports folder [DONE]") +