From bd69f6e6c2cb7c4f9d9efb0154b14fba998a1bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 1 Dec 2017 12:10:22 +0100 Subject: [PATCH 1/5] Unable to verify calculated analyses when retracted dependencies --- bika/lims/content/abstractanalysis.py | 8 +++- bika/lims/content/abstractroutineanalysis.py | 42 +++++++++++++++----- bika/lims/content/analysis.py | 28 ++++++++++--- bika/lims/content/duplicateanalysis.py | 23 +++++++++-- bika/lims/content/referenceanalysis.py | 2 +- bika/lims/workflow/__init__.py | 7 ++++ bika/lims/workflow/analysis/__init__.py | 2 + 7 files changed, 90 insertions(+), 22 deletions(-) diff --git a/bika/lims/content/abstractanalysis.py b/bika/lims/content/abstractanalysis.py index 875f05c347..1b0c6aceca 100644 --- a/bika/lims/content/abstractanalysis.py +++ b/bika/lims/content/abstractanalysis.py @@ -411,8 +411,12 @@ def getDependents(self): raise NotImplementedError("getDependents is not implemented.") @security.public - def getDependencies(self): - """Return a list of analyses who we depend on to calculate our result. + def getDependencies(self, retracted=False): + """Return a list of siblings who we depend on to calculate our result. + :param retracted: If false retracted/rejected analyses are dismissed + :type retracted: bool + :return: Analyses the current analysis depends on + :rtype: list of IAnalysis """ raise NotImplementedError("getDependencies is not implemented.") diff --git a/bika/lims/content/abstractroutineanalysis.py b/bika/lims/content/abstractroutineanalysis.py index d87728fc9c..123733e1f0 100644 --- a/bika/lims/content/abstractroutineanalysis.py +++ b/bika/lims/content/abstractroutineanalysis.py @@ -22,10 +22,11 @@ from bika.lims.interfaces import IAnalysis, IRoutineAnalysis, \ ISamplePrepWorkflow from bika.lims.interfaces.analysis import IRequestAnalysis -from bika.lims.workflow import doActionFor +from bika.lims.workflow import doActionFor, getCurrentState from bika.lims.workflow import getTransitionDate from bika.lims.workflow import skip from bika.lims.workflow import wasTransitionPerformed +from bika.lims.workflow.analysis import STATE_RETRACTED, STATE_REJECTED from zope.interface import implements # The physical sample partition linked to the Analysis. @@ -416,17 +417,28 @@ def getResultsRange(self, specification=None): return rr @security.public - def getSiblings(self): - """Return the siblings analyses, using the parent to which the current - analysis belongs to as the source""" + def getSiblings(self, retracted=False): + """ + Return the siblings analyses, using the parent to which the current + analysis belongs to as the source + :param retracted: If false, retracted/rejected siblings are dismissed + :type retracted: bool + :return: list of siblings for this analysis + :rtype: list of IAnalysis + """ raise NotImplementedError("getSiblings is not implemented.") @security.public - def getDependents(self): - """Return of siblings who depend on us to calculate their result + def getDependents(self, retracted=False): + """ + Returns a list of siblings who depend on us to calculate their result. + :param retracted: If false, retracted/rejected dependents are dismissed + :type retracted: bool + :return: Analyses the current analysis depends on + :rtype: list of IAnalysis """ dependents = [] - for sibling in self.getSiblings(): + for sibling in self.getSiblings(retracted=retracted): calculation = sibling.getCalculation() if not calculation: continue @@ -437,16 +449,24 @@ def getDependents(self): return dependents @security.public - def getDependencies(self): - """Return a list of siblings who we depend on to calculate our result. + def getDependencies(self, retracted=False): + """ + Return a list of siblings who we depend on to calculate our result. + :param retracted: If false retracted/rejected dependencies are dismissed + :type retracted: bool + :return: Analyses the current analysis depends on + :rtype: list of IAnalysis """ calc = self.getCalculation() if not calc: return [] dependencies = [] - for sibling in self.getSiblings(): - deps = [dep.UID() for dep in sibling.getDependents()] + for sibling in self.getSiblings(retracted=retracted): + # We get all analyses that depend on me, also if retracted (maybe + # I am one of those that are retracted!) + deps = sibling.getDependents(retracted=True) + deps = [dep.UID() for dep in deps] if self.UID() in deps: dependencies.append(sibling) return dependencies diff --git a/bika/lims/content/analysis.py b/bika/lims/content/analysis.py index 8d25f056e3..f4315ae70f 100644 --- a/bika/lims/content/analysis.py +++ b/bika/lims/content/analysis.py @@ -11,6 +11,8 @@ from bika.lims.content.abstractroutineanalysis import AbstractRoutineAnalysis from bika.lims.content.abstractroutineanalysis import schema from bika.lims.interfaces import IRoutineAnalysis, ISamplePrepWorkflow +from bika.lims.workflow import getCurrentState, in_state +from bika.lims.workflow.analysis import STATE_RETRACTED, STATE_REJECTED from zope.interface import implements schema = schema.copy() + Schema(( @@ -32,15 +34,31 @@ def getSample(self): return sample @security.public - def getSiblings(self): + def getSiblings(self, retracted=False): + """ + Returns the list of analyses of the Analysis Request to which this + analysis belongs to, but with the current analysis excluded. + :param retracted: If false, retracted/rejected siblings are dismissed + :type retracted: bool + :return: list of siblings for this analysis + :rtype: list of IAnalysis + """ """Returns the list of analyses of the Analysis Request to which this analysis belongs to, but with the current analysis excluded """ - siblings = [] request = self.getRequest() - if request: - ans = request.getAnalyses(full_objects=True) - siblings = [an for an in ans if an.UID() != self.UID()] + if not request: + return [] + + siblings = [] + retracted_states = [STATE_RETRACTED, STATE_REJECTED] + ans = request.getAnalyses(full_objects=True) + for sibling in ans: + if sibling.UID() == self.UID(): + continue + if retracted == False and in_state(sibling, retracted_states): + continue + siblings.append(sibling) return siblings diff --git a/bika/lims/content/duplicateanalysis.py b/bika/lims/content/duplicateanalysis.py index 4339ff606b..23eb5560b4 100644 --- a/bika/lims/content/duplicateanalysis.py +++ b/bika/lims/content/duplicateanalysis.py @@ -14,6 +14,8 @@ from bika.lims.interfaces import IDuplicateAnalysis from bika.lims.interfaces.analysis import IRequestAnalysis from bika.lims.subscribers import skip +from bika.lims.workflow import in_state +from bika.lims.workflow.analysis import STATE_RETRACTED, STATE_REJECTED from bika.lims.workflow.duplicateanalysis import events from zope.interface import implements @@ -70,7 +72,16 @@ def getWorksheet(self): return self.aq_parent @security.public - def getSiblings(self): + def getSiblings(self, retracted=False): + """ + Return the list of duplicate analyses that share the same Request and + are included in the same Worksheet as the current analysis. The current + duplicate is excluded from the list. + :param retracted: If false, retracted/rejected siblings are dismissed + :type retracted: bool + :return: list of siblings for this analysis + :rtype: list of IAnalysis + """ """Returns the list of duplicate analyses that share the same Request and are included in the same Worksheet as the current. The current duplicate is excluded from the list @@ -81,6 +92,7 @@ def getSiblings(self): return [] siblings = [] + retracted_states = [STATE_RETRACTED, STATE_REJECTED] analyses = worksheet.getAnalyses() for analysis in analyses: if analysis.UID() == self.UID(): @@ -89,8 +101,13 @@ def getSiblings(self): if IRequestAnalysis.providedBy(analysis): # We exclude here all analyses that do not have an analysis # request associated (e.g. IReferenceAnalysis) - if analysis.getRequestUID() == requestuid: - siblings.append(analysis) + if analysis.getRequestUID() != requestuid: + continue + + if retracted == False and in_state(analysis, retracted_states): + continue + + siblings.append(analysis) return siblings @security.public diff --git a/bika/lims/content/referenceanalysis.py b/bika/lims/content/referenceanalysis.py index 4dfb838967..ca39453bec 100644 --- a/bika/lims/content/referenceanalysis.py +++ b/bika/lims/content/referenceanalysis.py @@ -135,7 +135,7 @@ def getServiceDefaultInstrumentURL(self): return ins.absolute_url_path() return '' - def getDependencies(self): + def getDependencies(self, retracted=False): """It doesn't make sense for a ReferenceAnalysis to use dependencies, since them are only used in calculations for routine analyses diff --git a/bika/lims/workflow/__init__.py b/bika/lims/workflow/__init__.py index f959304c3b..2b95a9cb49 100644 --- a/bika/lims/workflow/__init__.py +++ b/bika/lims/workflow/__init__.py @@ -376,6 +376,13 @@ def getCurrentState(obj, stateflowid='review_state'): wf = getToolByName(obj, 'portal_workflow') return wf.getInfoFor(obj, stateflowid, '') +def in_state(obj, states, stateflowid='review_state'): + """ Returns if the object passed matches with the states passed in + """ + if not states: + return False + obj_state = getCurrentState(obj, stateflowid=stateflowid) + return obj_state in states def getTransitionActor(obj, action_id): """Returns the actor that performed a given transition. If transition has diff --git a/bika/lims/workflow/analysis/__init__.py b/bika/lims/workflow/analysis/__init__.py index e69de29bb2..cfe775729c 100644 --- a/bika/lims/workflow/analysis/__init__.py +++ b/bika/lims/workflow/analysis/__init__.py @@ -0,0 +1,2 @@ +STATE_REJECTED = 'rejected' +STATE_RETRACTED = 'retracted' From 0d94b0c4830c2b3eb7273e57d2119e0f5ba268f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 1 Dec 2017 12:15:41 +0100 Subject: [PATCH 2/5] Changelog --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index fadc6a36b0..b627766dd4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -17,6 +17,7 @@ Changelog **Fixed** +- #437 Cannot verify calculated analyses when retracted dependencies - #436 Auto Import View has an Add Button displayed, but shouldn't - #436 Clicking on the Add Button of Instrument Certifications opens an arbitrary Add form - #433 Analyses not sorted by sortkey in Analysis Request' manage analyses view From 0287160a9bb81d00f5a13e0aacac5b4ce258f0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 1 Dec 2017 12:29:30 +0100 Subject: [PATCH 3/5] Changlog --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index b627766dd4..1c2755cab5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -17,7 +17,7 @@ Changelog **Fixed** -- #437 Cannot verify calculated analyses when retracted dependencies +- #439 Cannot verify calculated analyses when retracted dependencies - #436 Auto Import View has an Add Button displayed, but shouldn't - #436 Clicking on the Add Button of Instrument Certifications opens an arbitrary Add form - #433 Analyses not sorted by sortkey in Analysis Request' manage analyses view From f647ff04369d03183a30399eb21256283dafc8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 1 Dec 2017 13:00:17 +0100 Subject: [PATCH 4/5] Compare bool with is --- bika/lims/content/analysis.py | 2 +- bika/lims/content/duplicateanalysis.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bika/lims/content/analysis.py b/bika/lims/content/analysis.py index f4315ae70f..5d484176aa 100644 --- a/bika/lims/content/analysis.py +++ b/bika/lims/content/analysis.py @@ -56,7 +56,7 @@ def getSiblings(self, retracted=False): for sibling in ans: if sibling.UID() == self.UID(): continue - if retracted == False and in_state(sibling, retracted_states): + if retracted is False and in_state(sibling, retracted_states): continue siblings.append(sibling) return siblings diff --git a/bika/lims/content/duplicateanalysis.py b/bika/lims/content/duplicateanalysis.py index 23eb5560b4..e0560d7229 100644 --- a/bika/lims/content/duplicateanalysis.py +++ b/bika/lims/content/duplicateanalysis.py @@ -104,7 +104,7 @@ def getSiblings(self, retracted=False): if analysis.getRequestUID() != requestuid: continue - if retracted == False and in_state(analysis, retracted_states): + if retracted is False and in_state(analysis, retracted_states): continue siblings.append(analysis) From 1b44e72c95fc2231f1991a5da58795115b4edb5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 1 Dec 2017 15:09:07 +0100 Subject: [PATCH 5/5] Cosmetic changes --- bika/lims/content/analysis.py | 8 +++++--- bika/lims/content/duplicateanalysis.py | 27 ++++++++++++++------------ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/bika/lims/content/analysis.py b/bika/lims/content/analysis.py index 5d484176aa..be182ce232 100644 --- a/bika/lims/content/analysis.py +++ b/bika/lims/content/analysis.py @@ -43,9 +43,6 @@ def getSiblings(self, retracted=False): :return: list of siblings for this analysis :rtype: list of IAnalysis """ - """Returns the list of analyses of the Analysis Request to which this - analysis belongs to, but with the current analysis excluded - """ request = self.getRequest() if not request: return [] @@ -55,10 +52,15 @@ def getSiblings(self, retracted=False): ans = request.getAnalyses(full_objects=True) for sibling in ans: if sibling.UID() == self.UID(): + # Exclude me from the list continue + if retracted is False and in_state(sibling, retracted_states): + # Exclude retracted analyses continue + siblings.append(sibling) + return siblings diff --git a/bika/lims/content/duplicateanalysis.py b/bika/lims/content/duplicateanalysis.py index e0560d7229..a1137bb8ef 100644 --- a/bika/lims/content/duplicateanalysis.py +++ b/bika/lims/content/duplicateanalysis.py @@ -82,10 +82,6 @@ def getSiblings(self, retracted=False): :return: list of siblings for this analysis :rtype: list of IAnalysis """ - """Returns the list of duplicate analyses that share the same Request - and are included in the same Worksheet as the current. The current - duplicate is excluded from the list - """ worksheet = self.getWorksheet() requestuid = self.getRequestUID() if not requestuid or not worksheet: @@ -98,16 +94,23 @@ def getSiblings(self, retracted=False): if analysis.UID() == self.UID(): # Exclude me from the list continue - if IRequestAnalysis.providedBy(analysis): - # We exclude here all analyses that do not have an analysis - # request associated (e.g. IReferenceAnalysis) - if analysis.getRequestUID() != requestuid: - continue - if retracted is False and in_state(analysis, retracted_states): - continue + if IRequestAnalysis.providedBy(analysis) is False: + # Exclude analyses that do not have an analysis request + # associated + continue + + if analysis.getRequestUID() != requestuid: + # Exclude those analyses that does not belong to the same + # analysis request I belong to + continue + + if retracted is False and in_state(analysis, retracted_states): + # Exclude retracted analyses + continue + + siblings.append(analysis) - siblings.append(analysis) return siblings @security.public