Skip to content

Commit a210ca3

Browse files
xisparamonski
authored andcommitted
PR-1942 Feature/Instrument certification interval + Traceback after adding calibration certificate (#459)
* Refactoring isCalibrationInProgress implemented method to InstrumentCalibration. Added Doctest. Use this method in Instruments Conflicts: bika/lims/content/instrument.py bika/lims/content/instrumentcalibration.py bika/lims/tests/test_textual_doctests.py * Added isValid method to instrument certification instruments use this method now as well Conflicts: bika/lims/content/instrumentcertification.py * Added helpers to get the days/weeks until expiration Conflicts: bika/lims/content/instrumentcertification.py * Improved Instrument Listing Table wrapped strings into messagefactory. Return immediately weeks and dates from the certificate. Conflicts: bika/lims/controlpanel/bika_instruments.py * Refactored getLatestValidCalibration Conflicts: bika/lims/content/instrument.py bika/lims/content/instrumentcalibration.py * Refactored instrument1.getLatestValidCertification Conflicts: bika/lims/content/instrument.py * PEP8 for instruments Conflicts: bika/lims/content/instrument.py * better expiration and validity calculation Conflicts: bika/lims/content/instrumentcalibration.py bika/lims/content/instrumentcertification.py * Added interval field to instrument certification Instrument Certificaitons can now have an expiration interval, which automatically calculates the ValidTo field value. Added doctest to test the new behavior. Conflicts: bika/lims/content/instrumentcertification.py * PEP8 for instrument validations Also added missing interface IInstrumentValidation Conflicts: bika/lims/content/instrumentvalidation.py * Added missing zope interfaces Test for implemented interface in doctest Conflicts: bika/lims/content/instrumentcalibration.py bika/lims/interfaces/__init__.py * Docstring formatting only * Refactored isValidationInProgress + tests Conflicts: bika/lims/content/instrumentvalidation.py * test always with new DateTime's * Doctested instrument validations Conflicts: bika/lims/content/instrument.py * renamed doctest Conflicts: bika/lims/tests/test_textual_doctests.py * Fixed ValidTo setter method wipe out the original value of the 'ValidTo' field to ensure the calculated valued don't get overwritten later in the edit process. Conflicts: bika/lims/content/instrumentcertification.py * Remove duplicated imports * Moved instrument certs and validations test and remove old instrument doctest * Changelog * Better changelog
1 parent 83c7b46 commit a210ca3

8 files changed

+98
-171
lines changed

CHANGES.rst

+2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ Changelog
1212

1313
**Changed**
1414

15+
- #459 PR-1942 Feature/instrument certification interval refactoring
1516
- #431 Make ARAnalysesField setter to accept Analysis/Service objects
1617

1718
**Fixed**
1819

20+
- #459 Traceback in Instruments list after adding a calibration certificate
1921
- #454 Click on some analyses pops up a new page instead of object log
2022
- #452 Traceback error when deleting attachment from Analysis Request
2123
- #450 Traceback after clicking "Manage Results" in a WS w/o Analyses assigned

bika/lims/content/instrument.py

+74-90
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
from bika.lims.content.bikaschema import BikaSchema
5656
from bika.lims.content.bikaschema import BikaFolderSchema
5757
from bika.lims import bikaMessageFactory as _
58-
from bika.lims import deprecated
5958

6059
schema = BikaFolderSchema.copy() + BikaSchema.copy() + Schema((
6160

@@ -514,7 +513,7 @@ def getCertifications(self):
514513
""" Returns the certifications of the instrument. Both internal
515514
and external certifitions
516515
"""
517-
return [c for c in self.objectValues('InstrumentCertification') if c]
516+
return self.objectValues('InstrumentCertification')
518517

519518
def getValidCertifications(self):
520519
""" Returns the certifications fully valid
@@ -616,128 +615,111 @@ def isOutOfDate(self):
616615
""" Returns if the current instrument is out-of-date regards to
617616
its certifications
618617
"""
619-
cert = self.getLatestValidCertification()
620-
today = date.today()
621-
if cert and cert.getValidTo():
622-
validto = cert.getValidTo().asdatetime().date();
623-
if validto > today:
624-
return False
618+
certification = self.getLatestValidCertification()
619+
if certification:
620+
return not certification.isValid()
625621
return True
626622

627623
def isValidationInProgress(self):
628624
""" Returns if the current instrument is under validation progress
629625
"""
630626
validation = self.getLatestValidValidation()
631-
today = date.today()
632-
if validation and validation.getDownTo():
633-
validfrom = validation.getDownFrom().asdatetime().date()
634-
validto = validation.getDownTo().asdatetime().date()
635-
if validfrom <= today <= validto:
636-
return True
627+
if validation:
628+
return validation.isValidationInProgress()
637629
return False
638630

639631
def isCalibrationInProgress(self):
640632
""" Returns if the current instrument is under calibration progress
641633
"""
642-
for calibration in self.getCalibrations():
643-
if calibration.isCalibrationInProgress():
644-
return True
634+
calibration = self.getLatestValidCalibration()
635+
if calibration is not None:
636+
return calibration.isCalibrationInProgress()
645637
return False
646638

647639
def getCertificateExpireDate(self):
648640
""" Returns the current instrument's data expiration certificate
649641
"""
650-
cert = self.getLatestValidCertification()
651-
if cert == None:
652-
return ''
653-
date = cert.getValidTo()
654-
return date
642+
certification = self.getLatestValidCertification()
643+
if certification:
644+
return certification.getValidTo()
645+
return None
655646

656647
def getWeeksToExpire(self):
657-
""" Returns the amount of weeks untils it's certification expire
648+
""" Returns the amount of weeks and days untils it's certification expire
658649
"""
659-
cert = self.getLatestValidCertification()
660-
if cert == None:
661-
return ''
662-
date = cert.getValidTo().asdatetime().date();
663-
return date - date.today()
650+
certification = self.getLatestValidCertification()
651+
if certification:
652+
return certification.getWeeksAndDaysToExpire()
653+
return 0, 0
664654

665655
def getLatestValidCertification(self):
666-
""" Returns the latest valid certification. If no latest valid
667-
certification found, returns None
656+
"""Returns the certification with the most remaining days until expiration.
657+
If no certification was found, it returns None.
668658
"""
669-
saved_cert = None
670-
lastfrom = None
671-
lastto = None
672-
for cert in self.getCertifications():
673-
if not cert.isValid():
674-
continue
675-
validfrom = cert.getValidFrom() if cert else None
676-
validto = cert.getValidTo() if validfrom else None
677-
if not validfrom or not validto:
678-
continue
679-
validfrom = validfrom.asdatetime().date()
680-
validto = validto.asdatetime().date()
681-
if not saved_cert \
682-
or validto > lastto \
683-
or (validto == lastto and validfrom > lastfrom):
684-
saved_cert = cert
685-
lastfrom = validfrom
686-
lastto = validto
687-
return saved_cert
659+
660+
# 1. get all certifications
661+
certifications = self.getCertifications()
662+
663+
# 2. filter out certifications, which are invalid
664+
valid_certifications = filter(lambda x: x.isValid(), certifications)
665+
666+
# 3. sort by the remaining days to expire, e.g. [10, 7, 6, 1]
667+
def sort_func(x, y):
668+
return cmp(x.getDaysToExpire(), y.getDaysToExpire())
669+
sorted_certifications = sorted(valid_certifications, cmp=sort_func, reverse=True)
670+
671+
# 4. return the certification with the most remaining days
672+
if len(sorted_certifications) > 0:
673+
return sorted_certifications[0]
674+
return None
688675

689676
def getLatestValidValidation(self):
690-
""" Returns the latest *done* validation. If no latest *done*
691-
validation found, returns None
677+
"""Returns the validation with the most remaining days in validation.
678+
If no validation was found, it returns None.
692679
"""
693-
validation = None
694-
lastfrom = None
695-
lastto = None
696-
for v in self.getValidations():
697-
if v.isValidationInProgress() or v.isFutureValidation():
698-
continue
699-
validfrom = v.getDownFrom() if v else None
700-
validto = v.getDownTo() if validfrom else None
701-
if not validfrom or not validto:
702-
continue
703-
validfrom = validfrom.asdatetime().date()
704-
validto = validto.asdatetime().date()
705-
if not validation \
706-
or validto > lastto \
707-
or (validto == lastto and validfrom > lastfrom):
708-
validation = v
709-
lastfrom = validfrom
710-
lastto = validto
711-
return validation
680+
# 1. get all validations
681+
validations = self.getValidations()
682+
683+
# 2. filter out validations, which are not in progress
684+
active_validations = filter(lambda x: x.isValidationInProgress(), validations)
685+
686+
# 3. sort by the remaining days in validation, e.g. [10, 7, 6, 1]
687+
def sort_func(x, y):
688+
return cmp(x.getRemainingDaysInValidation(), y.getRemainingDaysInValidation())
689+
sorted_validations = sorted(active_validations, cmp=sort_func, reverse=True)
690+
691+
# 4. return the validation with the most remaining days
692+
if len(sorted_validations) > 0:
693+
return sorted_validations[0]
694+
return None
712695

713696
def getLatestValidCalibration(self):
714-
""" Returns the latest *done* calibration. If no latest *done*
715-
calibration found, returns None
697+
"""Returns the calibration with the most remaining days in calibration.
698+
If no calibration was found, it returns None.
716699
"""
717-
calibration = None
718-
lastto = None
719-
for cal in self.getCalibrations():
720-
if cal.isCalibrationInProgress() or cal.isFutureCalibration():
721-
continue
722-
validfrom = cal.getDownFrom() if cal else None
723-
validto = cal.getDownTo() if validfrom else None
724-
if not validfrom or not validto:
725-
continue
726-
validto = validto.asdatetime().date()
727-
if calibration is None or validto > lastto:
728-
calibration = cal
729-
lastto = validto
730-
return calibration
700+
# 1. get all calibrations
701+
calibrations = self.getCalibrations()
702+
703+
# 2. filter out calibrations, which are not in progress
704+
active_calibrations = filter(lambda x: x.isCalibrationInProgress(), calibrations)
705+
706+
# 3. sort by the remaining days in calibration, e.g. [10, 7, 6, 1]
707+
def sort_func(x, y):
708+
return cmp(x.getRemainingDaysInCalibration(), y.getRemainingDaysInCalibration())
709+
sorted_calibrations = sorted(active_calibrations, cmp=sort_func, reverse=True)
710+
711+
# 4. return the calibration with the most remaining days
712+
if len(sorted_calibrations) > 0:
713+
return sorted_calibrations[0]
714+
return None
731715

732716
def getValidations(self):
733-
"""
734-
Return all the validations objects related with the instrument
717+
""" Return all the validations objects related with the instrument
735718
"""
736719
return self.objectValues('InstrumentValidation')
737720

738721
def getDocuments(self):
739-
"""
740-
Return all the multifile objects related with the instrument
722+
""" Return all the multifile objects related with the instrument
741723
"""
742724
return self.objectValues('Multifile')
743725

@@ -839,6 +821,8 @@ def addReferences(self, reference, service_uids):
839821
wf.doActionFor(ref_analysis, 'assign')
840822
addedanalyses.append(ref_analysis)
841823

824+
self.setAnalyses(self.getAnalyses() + addedanalyses)
825+
842826
# Initialize LatestReferenceAnalyses cache
843827
self.cleanReferenceAnalysesCache()
844828

bika/lims/content/instrumentcalibration.py

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from Products.Archetypes.atapi import DisplayList
1515
from Products.Archetypes.atapi import registerType
1616
from Products.CMFCore.utils import getToolByName
17-
from Products.CMFCore.utils import getToolByName
1817

1918
from zope.interface import implements
2019

bika/lims/content/instrumentcertification.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
from Products.CMFCore.utils import getToolByName
3030
from bika.lims import bikaMessageFactory as _
3131
# bika.lims imports
32-
from bika.lims import logger
3332
from bika.lims.browser.widgets import ComboBoxWidget
3433
from bika.lims.browser.widgets import DateTimeWidget
3534
from bika.lims.browser.widgets import ReferenceWidget
35+
from bika.lims import logger
3636
from bika.lims.config import PROJECTNAME
3737
from bika.lims.content.bikaschema import BikaSchema
3838
from bika.lims.interfaces import IInstrumentCertification

bika/lims/controlpanel/bika_instruments.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def folderitems(self):
110110
items[x]['Model'] = obj.getModel()
111111

112112
data = obj.getCertificateExpireDate()
113-
if not data:
113+
if data is None:
114114
items[x]['ExpiryDate'] = _("No date set")
115115
else:
116116
items[x]['ExpiryDate'] = data.asdatetime().strftime(self.date_format_short)
@@ -123,7 +123,6 @@ def folderitems(self):
123123
items[x]['WeeksToExpire'] = weeks_to_expire
124124

125125
methods = obj.getMethods()
126-
items[x]["Methods"] = methods
127126
urls = []
128127
titles = []
129128
for method in methods:

bika/lims/docs/Instruments.rst

-45
This file was deleted.

bika/lims/interfaces/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,10 @@ class IInstrumentCertification(Interface):
314314
"""Instrument Certification
315315
"""
316316

317+
class IInstrumentValidation(Interface):
318+
"""Instrument Validation
319+
"""
320+
317321
class IAnalysisSpecs(Interface):
318322
""
319323

0 commit comments

Comments
 (0)