From 3858edde6ee822c3d26676d5aa5d59aaf80abeec Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Tue, 26 Nov 2024 12:07:48 +0100 Subject: [PATCH] Improve performance of analysis verification (#2643) * Add verification check * Omit the current processed analysis from the check * Changelog updated * Count the length correctly * Skip reference/duplicates * docstring added * Integrate transition chain shortcut * Removed UID lookup from chains --- CHANGES.rst | 1 + src/bika/lims/workflow/analysis/events.py | 41 ++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 5a1c45f280..d8d2de51d9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,7 @@ Changelog 2.6.0 (unreleased) ------------------ +- #2643 Improve performance of analysis verification - #2645 Tabbed content view - #2624 Added "Maximum holding time" setting to services and analyses - #2637 Do not remove inactive services from profiles and templates diff --git a/src/bika/lims/workflow/analysis/events.py b/src/bika/lims/workflow/analysis/events.py index 30c6ff0669..6154269e00 100644 --- a/src/bika/lims/workflow/analysis/events.py +++ b/src/bika/lims/workflow/analysis/events.py @@ -27,6 +27,8 @@ from bika.lims.interfaces.analysis import IRequestAnalysis from bika.lims.utils.analysis import create_retest from bika.lims.workflow import doActionFor +from bika.lims.workflow.analysis import STATE_REJECTED +from bika.lims.workflow.analysis import STATE_RETRACTED from DateTime import DateTime from zope.interface import alsoProvides @@ -229,7 +231,7 @@ def after_verify(analysis): ws.reindexObject() # Promote transition to Analysis Request if Sample auto-verify is enabled - if IRequestAnalysis.providedBy(analysis): + if IRequestAnalysis.providedBy(analysis) and check_all_verified(analysis): setup = api.get_setup() if setup.getAutoVerifySamples(): doActionFor(analysis.getRequest(), "verify") @@ -238,6 +240,43 @@ def after_verify(analysis): reindex_request(analysis) +def check_all_verified(analysis): + """Checks if all analyses are verified + + NOTE: This check is provided solely for performance reasons of the `verify` + transition, because it is a less expensive calculation than executing the + `doActionFor` method on the sample for each verified analysis. + + The worst case that can happen is that the sample does not get + automatically verified and needs to be transitioned manually. + + :param analysis: The current verified analysis + :returns: True if all other routine analyses of the sample are verified + """ + + parent = api.get_parent(analysis) + sample = analysis.getRequest() + uid = api.get_uid(analysis) + + def is_valid(an): + state = api.get_review_status(an) + return state not in [STATE_REJECTED, STATE_RETRACTED] + + # get all *valid* analyses of the sample + analyses = filter(is_valid, sample.getAnalyses()) + # get all *verified* analyses of the sample + verified = sample.getAnalyses(object_provides=IVerified.__identifier__) + + # NOTE: We remove the current processed routine analysis (if not a WS + # duplicate/reference analysis), because it is either not yet + # verified or processed already in multi-verify scenarios. + if sample == parent: + analyses = filter(lambda x: api.get_uid(x) != uid, analyses) + verified = filter(lambda x: api.get_uid(x) != uid, verified) + + return len(analyses) == len(verified) + + def after_publish(analysis): """Function triggered after a "publish" transition is performed. """