Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue-408: Calculation referring to additional python module not triggered #457

Merged
merged 6 commits into from
Dec 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Changelog

**Fixed**

- #457 Calculation referring to additional python module not triggered
- #459 Traceback in Instruments list after adding a calibration certificate
- #454 Click on some analyses pops up a new page instead of object log
- #452 Traceback error when deleting attachment from Analysis Request
Expand Down
75 changes: 30 additions & 45 deletions bika/lims/browser/calcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,33 @@
# Copyright 2011-2016 by it's authors.
# Some rights reserved. See LICENSE.txt, AUTHORS.txt.

import json
import math
import plone

from zope.component import adapts
from zope.component import getAdapters
from zope.interface import implements

from Products.Archetypes.config import REFERENCE_CATALOG
from Products.CMFCore.utils import getToolByName
from Products.PythonScripts.standard import html_quote

from bika.lims import bikaMessageFactory as _
from bika.lims.browser import BrowserView
from bika.lims.interfaces import IAnalysis
from bika.lims.interfaces import IFieldIcons
from bika.lims import bikaMessageFactory as _
from bika.lims.utils import t, isnumber
from bika.lims import logger
from bika.lims.utils import to_utf8
from Products.Archetypes.config import REFERENCE_CATALOG
from Products.CMFCore.utils import getToolByName
from Products.PythonScripts.standard import html_quote
from bika.lims.utils.analysis import format_numeric_result
from zope.component import adapts
from zope.component import getAdapters
from zope.interface import implements

import json
import math
import plone


class CalculationResultAlerts(object):

"""This uses IAnalysis.ResultOutOfRange on values in request.

To validate results at ajax calculation time, make more adapters like this
one, from IFieldIcons. Any existing IAnalysis/IFieldIcon adapters
(AnalysisOutOfRange) have already been called.
"""

adapts(IAnalysis)
implements(IFieldIcons)

Expand Down Expand Up @@ -62,10 +61,9 @@ def __call__(self, result=None, specification=None, **kwargs):


class ajaxCalculateAnalysisEntry(BrowserView):

""" This view is called by javascript when an analysis' result or interim
field value is entered. Returns a JSON dictionary, or None if no
action is required or possible.
"""This view is called by javascript when an analysis' result or interim
field value is entered.
Returns a JSON dictionary, or None if no action is required or possible.
"""

def __init__(self, context, request):
Expand Down Expand Up @@ -94,18 +92,17 @@ def calculate(self, uid=None):
Result['result'] = ""

if calculation:
"""We need first to create the map of available parameters
acording to the interims, analyses and wildcards:

'''
We need first to create the map of available parameters
acording to the interims, analyses and wildcards:
params = {
<as-1-keyword> : <analysis_result>,
<as-1-keyword>.<wildcard-1> : <wildcard_1_value>,
<as-1-keyword>.<wildcard-2> : <wildcard_2_value>,
<interim-1> : <interim_result>,
...
}
'''
"""

# Get dependent analyses results and wildcard values to the
# mapping. If dependent analysis without result found,
Expand All @@ -124,17 +121,17 @@ def calculate(self, uid=None):
else:
# Retrieve the result and DLs from the analysis
analysisvalues = {
'keyword': dependency.getKeyword(),
'result': dependency.getResult(),
'ldl': dependency.getLowerDetectionLimit(),
'udl': dependency.getUpperDetectionLimit(),
'keyword': dependency.getKeyword(),
'result': dependency.getResult(),
'ldl': dependency.getLowerDetectionLimit(),
'udl': dependency.getUpperDetectionLimit(),
'belowldl': dependency.isBelowLowerDetectionLimit(),
'aboveudl': dependency.isAboveUpperDetectionLimit(),
}
if analysisvalues['result']=='':
if analysisvalues['result'] == '':
unsatisfied = True
break;
key = analysisvalues.get('keyword',dependency.getKeyword())
break
key = analysisvalues.get('keyword', dependency.getKeyword())

# Analysis result
# All result mappings must be float, or they are ignored.
Expand Down Expand Up @@ -215,7 +212,7 @@ def calculate(self, uid=None):
'context': self.context},
{'mapping': mapping})
# calculate
result = eval(formula)
result = eval(formula, calculation._getGlobals())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This calculation._getGlobals() is a good trick!

Result['result'] = result
self.current_results[uid]['result'] = result
except TypeError as e:
Expand Down Expand Up @@ -258,18 +255,6 @@ def calculate(self, uid=None):
else:
self.alerts[uid] = [alert, ]

if analysis.portal_type == 'ReferenceAnalysis':
# The analysis is a Control or Blank. We might use the
# reference results instead other specs
_uid = analysis.getServiceUID()
specs = analysis.aq_parent.getResultsRangeDict().get(_uid, {})

else:
# Get the specs directly from the analysis. The getResultsRange
# function already takes care about which are the specs to be used:
# AR, client or lab.
specs = analysis.getResultsRange()

# format result
try:
Result['formatted_result'] = format_numeric_result(analysis,
Expand Down Expand Up @@ -322,8 +307,8 @@ def calculate(self, uid=None):
anvals = self.current_results[uid]
isldl = anvals.get('isldl', False)
isudl = anvals.get('isudl', False)
ldl = anvals.get('ldl',0)
udl = anvals.get('udl',0)
ldl = anvals.get('ldl', 0)
udl = anvals.get('udl', 0)
ldl = float(ldl) if isnumber(ldl) else 0
udl = float(udl) if isnumber(udl) else 10000000
belowldl = (isldl or flres < ldl)
Expand Down
25 changes: 13 additions & 12 deletions bika/lims/content/calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
import inspect
import math
import re
import sys

import transaction

from zope.interface import implements

from AccessControl import ClassSecurityInfo
from Products.ATContentTypes.lib.historyaware import HistoryAwareMixin
from Products.ATExtensions.field import RecordsField
Expand All @@ -21,22 +23,21 @@
from Products.Archetypes.atapi import TextAreaWidget
from Products.Archetypes.atapi import TextField
from Products.Archetypes.atapi import registerType
from Products.Archetypes.references import HoldingReference
from Products.CMFCore.WorkflowCore import WorkflowException
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.utils import safe_unicode

from bika.lims import bikaMessageFactory as _
from bika.lims.api import get_object_by_uid
from bika.lims.browser.fields import HistoryAwareReferenceField
from bika.lims.browser.fields import InterimFieldsField
from bika.lims.browser.fields.uidreferencefield import UIDReferenceField, \
get_backreferences
from bika.lims.browser.fields.uidreferencefield import UIDReferenceField
from bika.lims.browser.fields.uidreferencefield import get_backreferences
from bika.lims.browser.widgets import RecordsWidget
from bika.lims.browser.widgets import RecordsWidget as BikaRecordsWidget
from bika.lims.config import PROJECTNAME
from bika.lims.content.bikaschema import BikaSchema
from bika.lims.interfaces.calculation import ICalculation
from zope.interface import implements


schema = BikaSchema.copy() + Schema((

Expand Down Expand Up @@ -232,12 +233,12 @@ def getCalculationDependencies(self, flat=False, deps=None):

def getCalculationDependants(self):
"""Return a flat list of services who depend on this calculation.
This refers only to services who's Calculation UIDReferenceField
have the value set to point to this calculation.
It has nothing to do with the services referenced in the
calculation's Formula.

This refers only to services who's Calculation UIDReferenceField have
the value set to point to this calculation.

It has nothing to do with the services referenced in the calculation's
Formula.
"""
deps = []
backrefs = get_backreferences(self, 'AnalysisServiceCalculation')
Expand Down