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

Calculations not triggered in manage results view #403

Merged
merged 7 commits into from
Nov 24, 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 @@ -13,6 +13,7 @@ Changelog

**Fixed**

- #403 Calculations not triggered in manage results view
- #402 Sort Analysis Services correctly based on their Sortkey + Title (Again)
- #398 PR-2315 ID Server does not find the next correct sequence after flushing the number generator
- #399 PR-2318 AR Add fails silently if e.g. the ID of the AR was already taken
Expand Down
1 change: 1 addition & 0 deletions bika/lims/browser/fields/historyawarereferencefield.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def set(self, instance, value, **kwargs):
add = [v for v in uids if v and v not in targetUIDs]

newuids = [t for t in list(targetUIDs) + list(uids) if t not in sub]
newuids = list(set(newuids))
for uid in newuids:
# update version_id of all existing references that aren't
# about to be removed anyway (contents of sub)
Expand Down
12 changes: 4 additions & 8 deletions bika/lims/content/calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,15 +189,11 @@ def setFormula(self, Formula=None):
self.setDependentServices(None)
self.getField('Formula').set(self, Formula)
else:
DependentServices = []
keywords = re.compile(r"\[([^.^\]]+)\]").findall(Formula)
for keyword in keywords:
service = bsc(portal_type="AnalysisService",
getKeyword=keyword)
if service:
DependentServices.append(service[0].getObject())

self.getField('DependentServices').set(self, DependentServices)
brains = bsc(portal_type='AnalysisService',
getKeyword=keywords)
services = [brain.getObject() for brain in brains]
self.getField('DependentServices').set(self, services)
self.getField('Formula').set(self, Formula)

def getMinifiedFormula(self):
Expand Down
98 changes: 97 additions & 1 deletion bika/lims/upgrade/v01_01_006.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,17 @@ def upgrade(tool):

logger.info("Upgrading {0}: {1} -> {2}".format(product, ver_from, version))

# Convert ReferenceField's values into UIDReferenceFields.
UpgradeReferenceFields()

# Calculations not triggered in manage results view
# https://github.com/senaite/bika.lims/issues/355
# Since we've already migrated the ReferenceField DependentServices from
# Calculation (with relation name 'CalculationAnalysisService' above, this
# wouldn't be strictly necessary, but who knows... maybe we've lost the
# at_references too, so just do it.
fix_broken_calculations()

# Indexes and colums were changed as per
# https://github.com/senaite/bika.lims/pull/353
ut.delIndex(CATALOG_ANALYSIS_LISTING, 'getAnalysisRequestUID')
Expand All @@ -44,6 +53,92 @@ def upgrade(tool):
return True


def fix_broken_calculations():
"""Walks-through calculations associated to undergoing analyses and
resets the value for DependentServices field"""

logger.info("Fixing broken calculations (re-assignment of dependents)...")

# Fetch only the subset of analyses that are undergoing.
# Analyses that have been verified or published cannot be updated, so there
# is no sense to check their calculations
review_states = [
'attachment_due',
'not_requested',
'rejected',
'retracted',
'sample_due',
'sample_prep',
'sample_received',
'sample_received',
'sample_registered',
'sampled',
'to_be_preserved',
'to_be_sampled',
]
uc = api.get_tool('uid_catalog')
catalog = get_tool(CATALOG_ANALYSIS_LISTING)
brains = catalog(portal_type='Analysis', review_state=review_states)
for brain in brains:
analysis = brain.getObject()
calculation = analysis.getCalculation()
if not calculation:
continue

dependents = calculation.getDependentServices()
# We don't want eventualities such as [None,]
dependents = filter(None, dependents)
if not dependents:
# Assign the formula again to the calculation. Note the function
# setFormula inferes the dependent services (and stores them) by
# inspecting the keywords set in the formula itself.
# So, instead of doing this job here, we just let setFormula to work
# for us.
formula = calculation.getFormula()
calculation.setFormula(formula)
deps = calculation.getDependentServices()
if not deps:
# Ok, this calculation does not depend on the result of other
# analyses, so we can omit this one, he is already ok
continue

deps = [dep.getKeyword() for dep in deps]
deps = ', '.join(deps)
arid = analysis.getRequestID()
logger.info("Dependents for {}.{}.{}: {}".format(arid,
analysis.getKeyword(),
calculation.Title(),
deps))

# Set the calculation to the analysis again (field Calculation is an
# HistoryAwareReferenceField in Analyses that inherits from
# AbstractRoutineAnalysis
analysis.setCalculation(calculation)

# Check if all is ok
an_deps = analysis.getCalculation().getDependentServices()
if not an_deps:
# Maybe the version of the calculation is an old one. If so, we
# need to use the last version, cause HistoryAwareReferenceField
# will always point to the version assigned to the calculation
# that was associated to the analysis.
uid = calculation.UID()
target_version = analysis.reference_versions[uid]
last_calc = uc(UID=uid)
if not last_calc:
# This should not happen
logger.warn("No calculation found for %s " % calculation.UID())
continue
last_calc = last_calc[0].getObject()
if last_calc.version_id != target_version:
# Ok, this is another version. We have no choice here... we
# need to assign the latest version...
analysis.reference_versions[uid]=last_calc.version_id

# Just in case
analysis.reindexObject()


refs_to_remove = []
objs_to_reindex = []

Expand Down Expand Up @@ -142,7 +237,8 @@ def UpgradeReferenceFields():
]],

['Calculation', [
('DependentServices', 'CalculationDependentServices')
('DependentServices', 'CalculationDependentServices'),
('DependentServices', 'CalculationAnalysisService')
]],

['Instrument', [
Expand Down