| 1 |  |  | # -*- coding: utf-8 -*- | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | # This file is part of SENAITE.CORE | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | # Copyright 2018 by it's authors. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | # Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | import re | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | import sys | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | from AccessControl import ClassSecurityInfo | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | from Products.ATContentTypes.lib.historyaware import HistoryAwareMixin | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | from Products.ATExtensions.ateapi import RecordsField | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  | from Products.Archetypes.public import (BaseFolder, DisplayList, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |                                         ReferenceField, Schema, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |                                         SelectionWidget, StringField, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |                                         registerType) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  | from Products.Archetypes.references import HoldingReference | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  | from Products.CMFCore.utils import getToolByName | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  | from Products.CMFPlone.utils import _createObjectByType, safe_unicode | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  | from bika.lims import api, logger | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  | from bika.lims import bikaMessageFactory as _ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  | from bika.lims.browser.fields import UIDReferenceField | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  | from bika.lims.browser.fields.remarksfield import RemarksField | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  | from bika.lims.browser.widgets import RemarksWidget | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  | from bika.lims.catalog.analysis_catalog import CATALOG_ANALYSIS_LISTING | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  | from bika.lims.config import PROJECTNAME, WORKSHEET_LAYOUT_OPTIONS | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  | from bika.lims.content.bikaschema import BikaSchema | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  | from bika.lims.idserver import renameAfterCreation | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  | from bika.lims.interfaces import (IAnalysisRequest, IDuplicateAnalysis, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |                                   IReferenceAnalysis, IReferenceSample, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |                                   IRoutineAnalysis, IWorksheet) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  | from bika.lims.interfaces.analysis import IRequestAnalysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  | from bika.lims.permissions import EditWorksheet, ManageWorksheets | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  | from bika.lims.utils import changeWorkflowState, tmpID, to_int | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  | from bika.lims.utils import to_utf8 as _c | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  | from bika.lims.workflow import doActionFor, skip, isTransitionAllowed, \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |     ActionHandlerPool, push_reindex_to_actions_pool | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  | from zope.interface import implements | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  | ALL_ANALYSES_TYPES = "all" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  | ALLOWED_ANALYSES_TYPES = ["a", "b", "c", "d"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  | schema = BikaSchema.copy() + Schema(( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |     UIDReferenceField( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |         'WorksheetTemplate', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         allowed_types=('WorksheetTemplate',), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |     ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |     RecordsField( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |         'Layout', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |         required=1, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |         subfields=('position', 'type', 'container_uid', 'analysis_uid'), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |         subfield_types={'position': 'int'}, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |     ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     # all layout info lives in Layout; Analyses is used for back references. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |     ReferenceField( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |         'Analyses', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         required=1, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |         multiValued=1, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |         allowed_types=('Analysis', 'DuplicateAnalysis', 'ReferenceAnalysis', 'RejectAnalysis'), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |         relationship='WorksheetAnalysis', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |     ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |     StringField( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |         'Analyst', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |         searchable=True, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |     ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |     ReferenceField( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |         'Method', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |         required=0, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |         vocabulary_display_path_bound=sys.maxint, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |         vocabulary='_getMethodsVoc', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |         allowed_types=('Method',), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |         relationship='WorksheetMethod', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |         referenceClass=HoldingReference, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |         widget=SelectionWidget( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |             format='select', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |             label=_("Method"), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |             visible=False, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |         ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |     ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |     # TODO Remove. Instruments must be assigned directly to each analysis. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |     ReferenceField( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |         'Instrument', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |         required=0, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |         allowed_types=('Instrument',), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |         vocabulary='_getInstrumentsVoc', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |         relationship='WorksheetInstrument', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |         referenceClass=HoldingReference, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |     ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |     RemarksField( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |         'Remarks', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |         searchable=True, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |         widget=RemarksWidget( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |             label=_("Remarks"), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |         ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |     ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |     StringField( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |         'ResultsLayout', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |         default='1', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |         vocabulary=WORKSHEET_LAYOUT_OPTIONS, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |     ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  | ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  | ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  | schema['id'].required = 0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  | schema['id'].widget.visible = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  | schema['title'].required = 0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  | schema['title'].widget.visible = {'edit': 'hidden', 'view': 'invisible'} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  | class Worksheet(BaseFolder, HistoryAwareMixin): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |     """A worksheet is a logical group of Analyses accross ARs | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |     security = ClassSecurityInfo() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |     implements(IWorksheet) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |     displayContentsTab = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |     schema = schema | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |     _at_rename_after_creation = True | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |     def _renameAfterCreation(self, check_auto_id=False): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |         from bika.lims.idserver import renameAfterCreation | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |         renameAfterCreation(self) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |     def Title(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |         return safe_unicode(self.getId()).encode('utf-8') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |     def setLayout(self, value): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |         Sets the worksheet layout, keeping it sorted by position | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |         :param value: the layout to set | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |         new_layout = sorted(value, key=lambda k: k['position']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |         self.getField('Layout').set(self, new_layout) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |     def addAnalyses(self, analyses): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |         """Adds a collection of analyses to the Worksheet at once | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |         actions_pool = ActionHandlerPool.get_instance() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |         actions_pool.queue_pool() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  |         for analysis in analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |             self.addAnalysis(api.get_object(analysis)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |         actions_pool.resume() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |     def addAnalysis(self, analysis, position=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |         """- add the analysis to self.Analyses(). | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |            - position is overruled if a slot for this analysis' parent exists | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |            - if position is None, next available pos is used. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  |         # Cannot add an analysis if not open, unless a retest | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |         if api.get_review_status(self) != "open": | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  |             retracted = analysis.getRetestOf() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  |             if retracted not in self.getAnalyses(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |                 return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |         # Cannot add an analysis that is assigned already | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |         if analysis.getWorksheet(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |             return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |         # Just in case | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |         analyses = self.getAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 |  |  |         if analysis in analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |             analyses = filter(lambda an: an != analysis, analyses) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |             self.setAnalyses(analyses) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  |             self.updateLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  |         # Cannot add an analysis if the assign transition is not possible | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |         if not isTransitionAllowed(analysis, "assign"): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 |  |  |             return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |         # Assign the instrument from the worksheet to the analysis, if possible | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |         instrument = self.getInstrument() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  |         if instrument and analysis.isInstrumentAllowed(instrument): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  |             # TODO Analysis Instrument + Method assignment | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 |  |  |             methods = instrument.getMethods() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  |             if methods: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 |  |  |                 # Set the first method assigned to the selected instrument | 
            
                                                                                                            
                            
            
                                    
            
            
                | 187 |  |  |                 analysis.setMethod(methods[0]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 188 |  |  |             analysis.setInstrument(instrument) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 189 |  |  |         elif not instrument: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 190 |  |  |             # If the ws doesn't have an instrument try to set the method | 
            
                                                                                                            
                            
            
                                    
            
            
                | 191 |  |  |             method = self.getMethod() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 192 |  |  |             if method and analysis.isMethodAllowed(method): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 193 |  |  |                 analysis.setMethod(method) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 194 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 195 |  |  |         # Transition analysis to "assigned" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 196 |  |  |         actions_pool = ActionHandlerPool.get_instance() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 197 |  |  |         actions_pool.queue_pool() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 198 |  |  |         doActionFor(analysis, "assign") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 199 |  |  |         self.setAnalyses(analyses + [analysis]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 200 |  |  |         self.addToLayout(analysis, position) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 201 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 202 |  |  |         # Try to rollback the worksheet to prevent inconsistencies | 
            
                                                                                                            
                            
            
                                    
            
            
                | 203 |  |  |         doActionFor(self, "rollback_to_open") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 204 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 205 |  |  |         # Reindex Worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 206 |  |  |         idxs = ["getAnalysesUIDs"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 207 |  |  |         push_reindex_to_actions_pool(self, idxs=idxs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 208 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 209 |  |  |         # Reindex Analysis Request, if any | 
            
                                                                                                            
                            
            
                                    
            
            
                | 210 |  |  |         if IRequestAnalysis.providedBy(analysis): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 211 |  |  |             idxs = ['assigned_state', 'getDueDate'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 212 |  |  |             push_reindex_to_actions_pool(analysis.getRequest(), idxs=idxs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 213 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 214 |  |  |         # Resume the actions pool | 
            
                                                                                                            
                            
            
                                    
            
            
                | 215 |  |  |         actions_pool.resume() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 216 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 217 |  |  |     def removeAnalysis(self, analysis): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 218 |  |  |         """ Unassigns the analysis passed in from the worksheet. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 219 |  |  |         Delegates to 'unassign' transition for the analysis passed in | 
            
                                                                                                            
                            
            
                                    
            
            
                | 220 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 221 |  |  |         if analysis.getWorksheet() == self: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 222 |  |  |             doActionFor(analysis, "unassign") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 223 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 224 |  |  |     def addToLayout(self, analysis, position=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 225 |  |  |         """ Adds the analysis passed in to the worksheet's layout | 
            
                                                                                                            
                            
            
                                    
            
            
                | 226 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 227 |  |  |         # TODO Redux | 
            
                                                                                                            
                            
            
                                    
            
            
                | 228 |  |  |         layout = self.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 229 |  |  |         container_uid = self.get_container_for(analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 230 |  |  |         if IRequestAnalysis.providedBy(analysis) and \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 231 |  |  |                 not IDuplicateAnalysis.providedBy(analysis): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 232 |  |  |             container_uids = map(lambda slot: slot['container_uid'], layout) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 233 |  |  |             if container_uid in container_uids: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 234 |  |  |                 position = [int(slot['position']) for slot in layout if | 
            
                                                                                                            
                            
            
                                    
            
            
                | 235 |  |  |                             slot['container_uid'] == container_uid][0] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 236 |  |  |             elif not position: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 237 |  |  |                 used_positions = [0, ] + [int(slot['position']) for slot in | 
            
                                                                                                            
                            
            
                                    
            
            
                | 238 |  |  |                                           layout] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 239 |  |  |                 position = [pos for pos in range(1, max(used_positions) + 2) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 240 |  |  |                             if pos not in used_positions][0] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 241 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 242 |  |  |         an_type = self.get_analysis_type(analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 243 |  |  |         self.setLayout(layout + [{'position': position, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 244 |  |  |                                   'type': an_type, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 245 |  |  |                                   'container_uid': container_uid, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 246 |  |  |                                   'analysis_uid': api.get_uid(analysis)}, ]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 247 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 248 |  |  |     def purgeLayout(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 249 |  |  |         """ Purges the layout of not assigned analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 250 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 251 |  |  |         uids = map(api.get_uid, self.getAnalyses()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 252 |  |  |         layout = filter(lambda slot: slot.get("analysis_uid", None) in uids, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 253 |  |  |                         self.getLayout()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 254 |  |  |         self.setLayout(layout) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 255 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 256 |  |  |     def _getMethodsVoc(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 257 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 258 |  |  |         This function returns the registered methods in the system as a | 
            
                                                                                                            
                            
            
                                    
            
            
                | 259 |  |  |         vocabulary. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 260 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 261 |  |  |         bsc = getToolByName(self, 'bika_setup_catalog') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 262 |  |  |         items = [(i.UID, i.Title) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 263 |  |  |                  for i in bsc(portal_type='Method', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 264 |  |  |                               inactive_state='active')] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 265 |  |  |         items.sort(lambda x, y: cmp(x[1], y[1])) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 266 |  |  |         items.insert(0, ('', _("Not specified"))) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 267 |  |  |         return DisplayList(list(items)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 268 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 269 |  |  |     def _getInstrumentsVoc(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 270 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 271 |  |  |         This function returns the registered instruments in the system as a | 
            
                                                                                                            
                            
            
                                    
            
            
                | 272 |  |  |         vocabulary. The instruments are filtered by the selected method. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 273 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 274 |  |  |         cfilter = {'portal_type': 'Instrument', 'inactive_state': 'active'} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 275 |  |  |         if self.getMethod(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 276 |  |  |             cfilter['getMethodUIDs'] = {"query": self.getMethod().UID(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 277 |  |  |                                         "operator": "or"} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 278 |  |  |         bsc = getToolByName(self, 'bika_setup_catalog') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 279 |  |  |         items = [('', 'No instrument')] + [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 280 |  |  |             (o.UID, o.Title) for o in | 
            
                                                                                                            
                            
            
                                    
            
            
                | 281 |  |  |             bsc(cfilter)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 282 |  |  |         o = self.getInstrument() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 283 |  |  |         if o and o.UID() not in [i[0] for i in items]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 284 |  |  |             items.append((o.UID(), o.Title())) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 285 |  |  |         items.sort(lambda x, y: cmp(x[1], y[1])) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 286 |  |  |         return DisplayList(list(items)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 287 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 288 |  |  |     def addReferenceAnalyses(self, reference, services, slot=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 289 |  |  |         """ Creates and add reference analyses to the slot by using the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 290 |  |  |         reference sample and service uids passed in. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 291 |  |  |         If no destination slot is defined, the most suitable slot will be used, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 292 |  |  |         typically a new slot at the end of the worksheet will be added. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 293 |  |  |         :param reference: reference sample to which ref analyses belong | 
            
                                                                                                            
                            
            
                                    
            
            
                | 294 |  |  |         :param service_uids: he uid of the services to create analyses from | 
            
                                                                                                            
                            
            
                                    
            
            
                | 295 |  |  |         :param slot: slot where reference analyses must be stored | 
            
                                                                                                            
                            
            
                                    
            
            
                | 296 |  |  |         :return: the list of reference analyses added | 
            
                                                                                                            
                            
            
                                    
            
            
                | 297 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 298 |  |  |         service_uids = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 299 |  |  |         for service in services: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 300 |  |  |             if api.is_uid(service): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 301 |  |  |                 service_uids.append(service) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 302 |  |  |             else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 303 |  |  |                 service_uids.append(api.get_uid(service)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 304 |  |  |         service_uids = list(set(service_uids)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 305 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 306 |  |  |         # Cannot add a reference analysis if not open | 
            
                                                                                                            
                            
            
                                    
            
            
                | 307 |  |  |         if api.get_workflow_status_of(self) != "open": | 
            
                                                                                                            
                            
            
                                    
            
            
                | 308 |  |  |             return [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 309 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 310 |  |  |         slot_to = to_int(slot) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 311 |  |  |         if slot_to < 0: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 312 |  |  |             return [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 313 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 314 |  |  |         if not slot_to: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 315 |  |  |             # Find the suitable slot to add these references | 
            
                                                                                                            
                            
            
                                    
            
            
                | 316 |  |  |             slot_to = self.get_suitable_slot_for_reference(reference) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 317 |  |  |             return self.addReferenceAnalyses(reference, service_uids, slot_to) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 318 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 319 |  |  |         processed = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 320 |  |  |         for analysis in self.get_analyses_at(slot_to): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 321 |  |  |             if api.get_review_status(analysis) != "retracted": | 
            
                                                                                                            
                            
            
                                    
            
            
                | 322 |  |  |                 service = analysis.getAnalysisService() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 323 |  |  |                 processed.append(api.get_uid(service)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 324 |  |  |         query = dict(portal_type="AnalysisService", UID=service_uids, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 325 |  |  |                      sort_on="sortable_title") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 326 |  |  |         services = filter(lambda service: api.get_uid(service) not in processed, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 327 |  |  |                           api.search(query, "bika_setup_catalog")) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 328 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 329 |  |  |         # Ref analyses from the same slot must have the same group id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 330 |  |  |         ref_gid = self.nextRefAnalysesGroupID(reference) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 331 |  |  |         ref_analyses = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 332 |  |  |         for service in services: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 333 |  |  |             service_obj = api.get_object(service) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 334 |  |  |             ref_analysis = self.add_reference_analysis(reference, service_obj, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 335 |  |  |                                                         slot_to, ref_gid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 336 |  |  |             if not ref_analysis: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 337 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 338 |  |  |             ref_analyses.append(ref_analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 339 |  |  |         return ref_analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 340 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 341 |  |  |     def add_reference_analysis(self, reference, service, slot, ref_gid=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 342 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 343 |  |  |         Creates a reference analysis in the destination slot (dest_slot) passed | 
            
                                                                                                            
                            
            
                                    
            
            
                | 344 |  |  |         in, by using the reference and service_uid. If the analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 345 |  |  |         passed in is not an IReferenceSample or has dependent services, returns | 
            
                                                                                                            
                            
            
                                    
            
            
                | 346 |  |  |         None. If no reference analyses group id (refgid) is set, the value will | 
            
                                                                                                            
                            
            
                                    
            
            
                | 347 |  |  |         be generated automatically. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 348 |  |  |         :param reference: reference sample to create an analysis from | 
            
                                                                                                            
                            
            
                                    
            
            
                | 349 |  |  |         :param service: the service object to create an analysis from | 
            
                                                                                                            
                            
            
                                    
            
            
                | 350 |  |  |         :param slot: slot where the reference analysis must be stored | 
            
                                                                                                            
                            
            
                                    
            
            
                | 351 |  |  |         :param refgid: the reference analyses group id to be set | 
            
                                                                                                            
                            
            
                                    
            
            
                | 352 |  |  |         :return: the reference analysis or None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 353 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 354 |  |  |         if not reference or not service: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 355 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 356 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 357 |  |  |         if not IReferenceSample.providedBy(reference): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 358 |  |  |             logger.warning('Cannot create reference analysis from a non ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 359 |  |  |                            'reference sample: {}'.format(reference.getId())) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 360 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 361 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 362 |  |  |         calc = service.getCalculation() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 363 |  |  |         if calc and calc.getDependentServices(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 364 |  |  |             logger.warning('Cannot create reference analyses with dependent' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 365 |  |  |                            'services: {}'.format(service.getId())) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 366 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 367 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 368 |  |  |         # Create the reference analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 369 |  |  |         ref_analysis = reference.addReferenceAnalysis(service) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 370 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 371 |  |  |         # Set ReferenceAnalysesGroupID (same id for the analyses from | 
            
                                                                                                            
                            
            
                                    
            
            
                | 372 |  |  |         # the same Reference Sample and same Worksheet) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 373 |  |  |         gid = ref_gid and ref_gid or self.nextRefAnalysesGroupID(reference) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 374 |  |  |         ref_analysis.setReferenceAnalysesGroupID(gid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 375 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 376 |  |  |         # Add the reference analysis into the worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 377 |  |  |         self.setAnalyses(self.getAnalyses() + [ref_analysis, ]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 378 |  |  |         self.addToLayout(ref_analysis, slot) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 379 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 380 |  |  |         # Reindex | 
            
                                                                                                            
                            
            
                                    
            
            
                | 381 |  |  |         ref_analysis.reindexObject(idxs=["getAnalyst", "getWorksheetUID", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 382 |  |  |                                          "getReferenceAnalysesGroupID"]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 383 |  |  |         self.reindexObject(idxs=["getAnalysesUIDs"]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 384 |  |  |         return ref_analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 385 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 386 |  |  |     def nextRefAnalysesGroupID(self, reference): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 387 |  |  |         """ Returns the next ReferenceAnalysesGroupID for the given reference | 
            
                                                                                                            
                            
            
                                    
            
            
                | 388 |  |  |             sample. Gets the last reference analysis registered in the system | 
            
                                                                                                            
                            
            
                                    
            
            
                | 389 |  |  |             for the specified reference sample and increments in one unit the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 390 |  |  |             suffix. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 391 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 392 |  |  |         prefix = reference.id + "-" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 393 |  |  |         if not IReferenceSample.providedBy(reference): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 394 |  |  |             # Not a ReferenceSample, so this is a duplicate | 
            
                                                                                                            
                            
            
                                    
            
            
                | 395 |  |  |             prefix = reference.id + "-D" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 396 |  |  |         bac = getToolByName(reference, 'bika_analysis_catalog') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 397 |  |  |         ids = bac.Indexes['getReferenceAnalysesGroupID'].uniqueValues() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 398 |  |  |         rr = re.compile("^" + prefix + "[\d+]+$") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 399 |  |  |         ids = [int(i.split(prefix)[1]) for i in ids if i and rr.match(i)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 400 |  |  |         ids.sort() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 401 |  |  |         _id = ids[-1] if ids else 0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 402 |  |  |         suffix = str(_id + 1).zfill(int(3)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 403 |  |  |         if not IReferenceSample.providedBy(reference): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 404 |  |  |             # Not a ReferenceSample, so this is a duplicate | 
            
                                                                                                            
                            
            
                                    
            
            
                | 405 |  |  |             suffix = str(_id + 1).zfill(2) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 406 |  |  |         return '%s%s' % (prefix, suffix) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 407 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 408 |  |  |     def addDuplicateAnalyses(self, src_slot, dest_slot=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 409 |  |  |         """ Creates and add duplicate analyes from the src_slot to the dest_slot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 410 |  |  |         If no destination slot is defined, the most suitable slot will be used, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 411 |  |  |         typically a new slot at the end of the worksheet will be added. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 412 |  |  |         :param src_slot: slot that contains the analyses to duplicate | 
            
                                                                                                            
                            
            
                                    
            
            
                | 413 |  |  |         :param dest_slot: slot where the duplicate analyses must be stored | 
            
                                                                                                            
                            
            
                                    
            
            
                | 414 |  |  |         :return: the list of duplicate analyses added | 
            
                                                                                                            
                            
            
                                    
            
            
                | 415 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 416 |  |  |         # Duplicate analyses can only be added if the state of the ws is open | 
            
                                                                                                            
                            
            
                                    
            
            
                | 417 |  |  |         # unless we are adding a retest | 
            
                                                                                                            
                            
            
                                    
            
            
                | 418 |  |  |         if api.get_workflow_status_of(self) != "open": | 
            
                                                                                                            
                            
            
                                    
            
            
                | 419 |  |  |             return [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 420 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 421 |  |  |         slot_from = to_int(src_slot, 0) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 422 |  |  |         if slot_from < 1: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 423 |  |  |             return [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 424 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 425 |  |  |         slot_to = to_int(dest_slot, 0) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 426 |  |  |         if slot_to < 0: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 427 |  |  |             return [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 428 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 429 |  |  |         if not slot_to: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 430 |  |  |             # Find the suitable slot to add these duplicates | 
            
                                                                                                            
                            
            
                                    
            
            
                | 431 |  |  |             slot_to = self.get_suitable_slot_for_duplicate(slot_from) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 432 |  |  |             return self.addDuplicateAnalyses(src_slot, slot_to) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 433 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 434 |  |  |         processed = map(lambda an: api.get_uid(an.getAnalysis()), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 435 |  |  |                         self.get_analyses_at(slot_to)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 436 |  |  |         src_analyses = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 437 |  |  |         for analysis in self.get_analyses_at(slot_from): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 438 |  |  |             if api.get_uid(analysis) in processed: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 439 |  |  |                 if api.get_workflow_status_of(analysis) != "retracted": | 
            
                                                                                                            
                            
            
                                    
            
            
                | 440 |  |  |                     continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 441 |  |  |             src_analyses.append(analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 442 |  |  |         ref_gid = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 443 |  |  |         duplicates = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 444 |  |  |         for analysis in src_analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 445 |  |  |             duplicate = self.add_duplicate_analysis(analysis, slot_to, ref_gid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 446 |  |  |             if not duplicate: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 447 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 448 |  |  |             # All duplicates from the same slot must have the same group id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 449 |  |  |             ref_gid = ref_gid or duplicate.getReferenceAnalysesGroupID() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 450 |  |  |             duplicates.append(duplicate) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 451 |  |  |         return duplicates | 
            
                                                                                                            
                            
            
                                    
            
            
                | 452 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 453 |  |  |     def add_duplicate_analysis(self, src_analysis, destination_slot, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 454 |  |  |                                ref_gid=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 455 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 456 |  |  |         Creates a duplicate of the src_analysis passed in. If the analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 457 |  |  |         passed in is not an IRoutineAnalysis, is retracted or has dependent | 
            
                                                                                                            
                            
            
                                    
            
            
                | 458 |  |  |         services, returns None.If no reference analyses group id (ref_gid) is | 
            
                                                                                                            
                            
            
                                    
            
            
                | 459 |  |  |         set, the value will be generated automatically. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 460 |  |  |         :param src_analysis: analysis to create a duplicate from | 
            
                                                                                                            
                            
            
                                    
            
            
                | 461 |  |  |         :param destination_slot: slot where duplicate analysis must be stored | 
            
                                                                                                            
                            
            
                                    
            
            
                | 462 |  |  |         :param ref_gid: the reference analysis group id to be set | 
            
                                                                                                            
                            
            
                                    
            
            
                | 463 |  |  |         :return: the duplicate analysis or None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 464 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 465 |  |  |         if not src_analysis: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 466 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 467 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 468 |  |  |         if not IRoutineAnalysis.providedBy(src_analysis): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 469 |  |  |             logger.warning('Cannot create duplicate analysis from a non ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 470 |  |  |                            'routine analysis: {}'.format(src_analysis.getId())) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 471 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 472 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 473 |  |  |         if api.get_review_status(src_analysis) == 'retracted': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 474 |  |  |             logger.warning('Cannot create duplicate analysis from a retracted' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 475 |  |  |                            'analysis: {}'.format(src_analysis.getId())) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 476 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 477 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 478 |  |  |         # TODO Workflow - Duplicate Analyses - Consider duplicates with deps | 
            
                                                                                                            
                            
            
                                    
            
            
                | 479 |  |  |         # Removing this check from here and ensuring that duplicate.getSiblings | 
            
                                                                                                            
                            
            
                                    
            
            
                | 480 |  |  |         # returns the analyses sorted by priority (duplicates from same | 
            
                                                                                                            
                            
            
                                    
            
            
                | 481 |  |  |         # AR > routine analyses from same AR > duplicates from same WS > | 
            
                                                                                                            
                            
            
                                    
            
            
                | 482 |  |  |         # routine analyses from same WS) should be almost enough | 
            
                                                                                                            
                            
            
                                    
            
            
                | 483 |  |  |         calc = src_analysis.getCalculation() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 484 |  |  |         if calc and calc.getDependentServices(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 485 |  |  |             logger.warning('Cannot create duplicate analysis from an' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 486 |  |  |                            'analysis with dependent services: {}' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 487 |  |  |                            .format(src_analysis.getId())) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 488 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 489 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 490 |  |  |         # Create the duplicate | 
            
                                                                                                            
                            
            
                                    
            
            
                | 491 |  |  |         duplicate = _createObjectByType("DuplicateAnalysis", self, tmpID()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 492 |  |  |         duplicate.setAnalysis(src_analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 493 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 494 |  |  |         # Set ReferenceAnalysesGroupID (same id for the analyses from | 
            
                                                                                                            
                            
            
                                    
            
            
                | 495 |  |  |         # the same Reference Sample and same Worksheet) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 496 |  |  |         if not ref_gid: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 497 |  |  |             ref_gid = self.nextRefAnalysesGroupID(duplicate.getSample()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 498 |  |  |         duplicate.setReferenceAnalysesGroupID(ref_gid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 499 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 500 |  |  |         # Add the duplicate into the worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 501 |  |  |         self.addToLayout(duplicate, destination_slot) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 502 |  |  |         self.setAnalyses(self.getAnalyses() + [duplicate, ]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 503 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 504 |  |  |         # Reindex | 
            
                                                                                                            
                            
            
                                    
            
            
                | 505 |  |  |         duplicate.reindexObject(idxs=["getAnalyst", "getWorksheetUID", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 506 |  |  |                                       "getReferenceAnalysesGroupID"]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 507 |  |  |         self.reindexObject(idxs=["getAnalysesUIDs"]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 508 |  |  |         return duplicate | 
            
                                                                                                            
                            
            
                                    
            
            
                | 509 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 510 |  |  |     def get_suitable_slot_for_duplicate(self, src_slot): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 511 |  |  |         """Returns the suitable position for a duplicate analysis, taking into | 
            
                                                                                                            
                            
            
                                    
            
            
                | 512 |  |  |         account if there is a WorksheetTemplate assigned to this worksheet. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 513 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 514 |  |  |         By default, returns a new slot at the end of the worksheet unless there | 
            
                                                                                                            
                            
            
                                    
            
            
                | 515 |  |  |         is a slot defined for a duplicate of the src_slot in the worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 516 |  |  |         template layout not yet used. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 517 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 518 |  |  |         :param src_slot: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 519 |  |  |         :return: suitable slot position for a duplicate of src_slot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 520 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 521 |  |  |         slot_from = to_int(src_slot, 0) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 522 |  |  |         if slot_from < 1: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 523 |  |  |             return -1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 524 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 525 |  |  |         # Are the analyses from src_slot suitable for duplicates creation? | 
            
                                                                                                            
                            
            
                                    
            
            
                | 526 |  |  |         container = self.get_container_at(slot_from) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 527 |  |  |         if not container or not IAnalysisRequest.providedBy(container): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 528 |  |  |             # We cannot create duplicates from analyses other than routine ones, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 529 |  |  |             # those that belong to an Analysis Request. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 530 |  |  |             return -1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 531 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 532 |  |  |         occupied = self.get_slot_positions(type='all') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 533 |  |  |         wst = self.getWorksheetTemplate() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 534 |  |  |         if not wst: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 535 |  |  |             # No worksheet template assigned, add a new slot at the end of | 
            
                                                                                                            
                            
            
                                    
            
            
                | 536 |  |  |             # the worksheet with the duplicate there | 
            
                                                                                                            
                            
            
                                    
            
            
                | 537 |  |  |             slot_to = max(occupied) + 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 538 |  |  |             return slot_to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 539 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 540 |  |  |         # If there is a match with the layout defined in the Worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 541 |  |  |         # Template, use that slot instead of adding a new one at the end of | 
            
                                                                                                            
                            
            
                                    
            
            
                | 542 |  |  |         # the worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 543 |  |  |         layout = wst.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 544 |  |  |         for pos in layout: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 545 |  |  |             if pos['type'] != 'd' or to_int(pos['dup']) != slot_from: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 546 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 547 |  |  |             slot_to = int(pos['pos']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 548 |  |  |             if slot_to in occupied: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 549 |  |  |                 # Not an empty slot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 550 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 551 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 552 |  |  |             # This slot is empty, use it instead of adding a new | 
            
                                                                                                            
                            
            
                                    
            
            
                | 553 |  |  |             # slot at the end of the worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 554 |  |  |             return slot_to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 555 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 556 |  |  |         # Add a new slot at the end of the worksheet, but take into account | 
            
                                                                                                            
                            
            
                                    
            
            
                | 557 |  |  |         # that a worksheet template is assigned, so we need to take care to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 558 |  |  |         # not override slots defined by its layout | 
            
                                                                                                            
                            
            
                                    
            
            
                | 559 |  |  |         occupied.append(len(layout)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 560 |  |  |         slot_to = max(occupied) + 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 561 |  |  |         return slot_to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 562 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 563 |  |  |     def get_suitable_slot_for_reference(self, reference): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 564 |  |  |         """Returns the suitable position for reference analyses, taking into | 
            
                                                                                                            
                            
            
                                    
            
            
                | 565 |  |  |         account if there is a WorksheetTemplate assigned to this worksheet. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 566 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 567 |  |  |         By default, returns a new slot at the end of the worksheet unless there | 
            
                                                                                                            
                            
            
                                    
            
            
                | 568 |  |  |         is a slot defined for a reference of the same type (blank or control) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 569 |  |  |         in the worksheet template's layout that hasn't been used yet. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 570 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 571 |  |  |         :param reference: ReferenceSample the analyses will be created from | 
            
                                                                                                            
                            
            
                                    
            
            
                | 572 |  |  |         :return: suitable slot position for reference analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 573 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 574 |  |  |         if not IReferenceSample.providedBy(reference): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 575 |  |  |             return -1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 576 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 577 |  |  |         occupied = self.get_slot_positions(type='all') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 578 |  |  |         wst = self.getWorksheetTemplate() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 579 |  |  |         if not wst: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 580 |  |  |             # No worksheet template assigned, add a new slot at the end of the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 581 |  |  |             # worksheet with the reference analyses there | 
            
                                                                                                            
                            
            
                                    
            
            
                | 582 |  |  |             slot_to = max(occupied) + 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 583 |  |  |             return slot_to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 584 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 585 |  |  |         # If there is a match with the layout defined in the Worksheet Template, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 586 |  |  |         # use that slot instead of adding a new one at the end of the worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 587 |  |  |         slot_type = reference.getBlank() and 'b' or 'c' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 588 |  |  |         layout = wst.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 589 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 590 |  |  |         for pos in layout: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 591 |  |  |             if pos['type'] != slot_type: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 592 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 593 |  |  |             slot_to = int(pos['pos']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 594 |  |  |             if slot_to in occupied: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 595 |  |  |                 # Not an empty slot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 596 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 597 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 598 |  |  |             # This slot is empty, use it instead of adding a new slot at the end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 599 |  |  |             # of the worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 600 |  |  |             return slot_to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 601 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 602 |  |  |         # Add a new slot at the end of the worksheet, but take into account | 
            
                                                                                                            
                            
            
                                    
            
            
                | 603 |  |  |         # that a worksheet template is assigned, so we need to take care to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 604 |  |  |         # not override slots defined by its layout | 
            
                                                                                                            
                            
            
                                    
            
            
                | 605 |  |  |         occupied.append(len(layout)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 606 |  |  |         slot_to = max(occupied) + 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 607 |  |  |         return slot_to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 608 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 609 |  |  |     def get_duplicates_for(self, analysis): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 610 |  |  |         """Returns the duplicates from the current worksheet that were created | 
            
                                                                                                            
                            
            
                                    
            
            
                | 611 |  |  |         by using the analysis passed in as the source | 
            
                                                                                                            
                            
            
                                    
            
            
                | 612 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 613 |  |  |         :param analysis: routine analyses used as the source for the duplicates | 
            
                                                                                                            
                            
            
                                    
            
            
                | 614 |  |  |         :return: a list of duplicates generated from the analysis passed in | 
            
                                                                                                            
                            
            
                                    
            
            
                | 615 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 616 |  |  |         if not analysis: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 617 |  |  |             return list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 618 |  |  |         uid = api.get_uid(analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 619 |  |  |         return filter(lambda dup: api.get_uid(dup.getAnalysis()) == uid, | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 620 |  |  |                       self.getDuplicateAnalyses()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 621 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 622 |  |  |     def get_analyses_at(self, slot): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 623 |  |  |         """Returns the list of analyses assigned to the slot passed in, sorted by | 
            
                                                                                                            
                            
            
                                    
            
            
                | 624 |  |  |         the positions they have within the slot. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 625 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 626 |  |  |         :param slot: the slot where the analyses are located | 
            
                                                                                                            
                            
            
                                    
            
            
                | 627 |  |  |         :type slot: int | 
            
                                                                                                            
                            
            
                                    
            
            
                | 628 |  |  |         :return: a list of analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 629 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 630 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 631 |  |  |         # ensure we have an integer | 
            
                                                                                                            
                            
            
                                    
            
            
                | 632 |  |  |         slot = to_int(slot) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 633 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 634 |  |  |         if slot < 1: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 635 |  |  |             return list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 636 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 637 |  |  |         analyses = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 638 |  |  |         layout = self.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 639 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 640 |  |  |         for pos in layout: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 641 |  |  |             layout_slot = to_int(pos['position']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 642 |  |  |             uid = pos['analysis_uid'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 643 |  |  |             if layout_slot != slot or not uid: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 644 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 645 |  |  |             analyses.append(api.get_object_by_uid(uid)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 646 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 647 |  |  |         return analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 648 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 649 |  |  |     def get_container_at(self, slot): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 650 |  |  |         """Returns the container object assigned to the slot passed in | 
            
                                                                                                            
                            
            
                                    
            
            
                | 651 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 652 |  |  |         :param slot: the slot where the analyses are located | 
            
                                                                                                            
                            
            
                                    
            
            
                | 653 |  |  |         :type slot: int | 
            
                                                                                                            
                            
            
                                    
            
            
                | 654 |  |  |         :return: the container (analysis request, reference sample, etc.) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 655 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 656 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 657 |  |  |         # ensure we have an integer | 
            
                                                                                                            
                            
            
                                    
            
            
                | 658 |  |  |         slot = to_int(slot) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 659 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 660 |  |  |         if slot < 1: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 661 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 662 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 663 |  |  |         layout = self.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 664 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 665 |  |  |         for pos in layout: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 666 |  |  |             layout_slot = to_int(pos['position']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 667 |  |  |             uid = pos['container_uid'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 668 |  |  |             if layout_slot != slot or not uid: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 669 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 670 |  |  |             return api.get_object_by_uid(uid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 671 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 672 |  |  |         return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 673 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 674 |  |  |     def get_slot_positions(self, type='a'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 675 |  |  |         """Returns a list with the slots occupied for the type passed in. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 676 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 677 |  |  |         Allowed type of analyses are: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 678 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 679 |  |  |             'a'   (routine analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 680 |  |  |             'b'   (blank analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 681 |  |  |             'c'   (control) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 682 |  |  |             'd'   (duplicate) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 683 |  |  |             'all' (all analyses) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 684 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 685 |  |  |         :param type: type of the analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 686 |  |  |         :return: list of slot positions | 
            
                                                                                                            
                            
            
                                    
            
            
                | 687 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 688 |  |  |         if type not in ALLOWED_ANALYSES_TYPES and type != ALL_ANALYSES_TYPES: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 689 |  |  |             return list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 690 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 691 |  |  |         layout = self.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 692 |  |  |         slots = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 693 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 694 |  |  |         for pos in layout: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 695 |  |  |             if type != ALL_ANALYSES_TYPES and pos['type'] != type: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 696 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 697 |  |  |             slots.append(to_int(pos['position'])) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 698 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 699 |  |  |         # return a unique list of sorted slot positions | 
            
                                                                                                            
                            
            
                                    
            
            
                | 700 |  |  |         return sorted(set(slots)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 701 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 702 |  |  |     def get_slot_position(self, container, type='a'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 703 |  |  |         """Returns the slot where the analyses from the type and container passed | 
            
                                                                                                            
                            
            
                                    
            
            
                | 704 |  |  |         in are located within the worksheet. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 705 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 706 |  |  |         :param container: the container in which the analyses are grouped | 
            
                                                                                                            
                            
            
                                    
            
            
                | 707 |  |  |         :param type: type of the analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 708 |  |  |         :return: the slot position | 
            
                                                                                                            
                            
            
                                    
            
            
                | 709 |  |  |         :rtype: int | 
            
                                                                                                            
                            
            
                                    
            
            
                | 710 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 711 |  |  |         if not container or type not in ALLOWED_ANALYSES_TYPES: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 712 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 713 |  |  |         uid = api.get_uid(container) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 714 |  |  |         layout = self.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 715 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 716 |  |  |         for pos in layout: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 717 |  |  |             if pos['type'] != type or pos['container_uid'] != uid: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 718 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 719 |  |  |             return to_int(pos['position']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 720 |  |  |         return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 721 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 722 |  |  |     def get_analysis_type(self, instance): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 723 |  |  |         """Returns the string used in slots to differentiate amongst analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 724 |  |  |         types | 
            
                                                                                                            
                            
            
                                    
            
            
                | 725 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 726 |  |  |         if IDuplicateAnalysis.providedBy(instance): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 727 |  |  |             return 'd' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 728 |  |  |         elif IReferenceAnalysis.providedBy(instance): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 729 |  |  |             return instance.getReferenceType() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 730 |  |  |         elif IRoutineAnalysis.providedBy(instance): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 731 |  |  |             return 'a' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 732 |  |  |         return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 733 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 734 |  |  |     def get_container_for(self, instance): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 735 |  |  |         """Returns the container id used in slots to group analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 736 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 737 |  |  |         if IReferenceAnalysis.providedBy(instance): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 738 |  |  |             return api.get_uid(instance.getSample()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 739 |  |  |         return instance.getRequestUID() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 740 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 741 |  |  |     def get_slot_position_for(self, instance): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 742 |  |  |         """Returns the slot where the instance passed in is located. If not | 
            
                                                                                                            
                            
            
                                    
            
            
                | 743 |  |  |         found, returns None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 744 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 745 |  |  |         analysis_type = self.get_analysis_type(instance) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 746 |  |  |         container = self.get_container_for(instance) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 747 |  |  |         slot = self.get_slot_position(container, analysis_type) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 748 |  |  |         analyses = self.get_analyses_at(slot) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 749 |  |  |         return instance in analyses and slot or None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 750 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 751 |  |  |     def resolve_available_slots(self, worksheet_template, type='a'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 752 |  |  |         """Returns the available slots from the current worksheet that fits | 
            
                                                                                                            
                            
            
                                    
            
            
                | 753 |  |  |         with the layout defined in the worksheet_template and type of analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 754 |  |  |         passed in. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 755 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 756 |  |  |         Allowed type of analyses are: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 757 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 758 |  |  |             'a' (routine analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 759 |  |  |             'b' (blank analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 760 |  |  |             'c' (control) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 761 |  |  |             'd' (duplicate) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 762 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 763 |  |  |         :param worksheet_template: the worksheet template to match against | 
            
                                                                                                            
                            
            
                                    
            
            
                | 764 |  |  |         :param type: type of analyses to restrict that suit with the slots | 
            
                                                                                                            
                            
            
                                    
            
            
                | 765 |  |  |         :return: a list of slots positions | 
            
                                                                                                            
                            
            
                                    
            
            
                | 766 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 767 |  |  |         if not worksheet_template or type not in ALLOWED_ANALYSES_TYPES: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 768 |  |  |             return list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 769 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 770 |  |  |         ws_slots = self.get_slot_positions(type) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 771 |  |  |         layout = worksheet_template.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 772 |  |  |         slots = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 773 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 774 |  |  |         for row in layout: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 775 |  |  |             # skip rows that do not match with the given type | 
            
                                                                                                            
                            
            
                                    
            
            
                | 776 |  |  |             if row['type'] != type: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 777 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 778 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 779 |  |  |             slot = to_int(row['pos']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 780 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 781 |  |  |             if slot in ws_slots: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 782 |  |  |                 # We only want those that are empty | 
            
                                                                                                            
                            
            
                                    
            
            
                | 783 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 784 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 785 |  |  |             slots.append(slot) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 786 |  |  |         return slots | 
            
                                                                                                            
                            
            
                                    
            
            
                | 787 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 788 |  |  |     def _apply_worksheet_template_routine_analyses(self, wst): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 789 |  |  |         """Add routine analyses to worksheet according to the worksheet template | 
            
                                                                                                            
                            
            
                                    
            
            
                | 790 |  |  |         layout passed in w/o overwriting slots that are already filled. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 791 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 792 |  |  |         If the template passed in has an instrument assigned, only those | 
            
                                                                                                            
                            
            
                                    
            
            
                | 793 |  |  |         routine analyses that allows the instrument will be added. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 794 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 795 |  |  |         If the template passed in has a method assigned, only those routine | 
            
                                                                                                            
                            
            
                                    
            
            
                | 796 |  |  |         analyses that allows the method will be added | 
            
                                                                                                            
                            
            
                                    
            
            
                | 797 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 798 |  |  |         :param wst: worksheet template used as the layout | 
            
                                                                                                            
                            
            
                                    
            
            
                | 799 |  |  |         :returns: None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 800 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 801 |  |  |         bac = api.get_tool("bika_analysis_catalog") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 802 |  |  |         services = wst.getService() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 803 |  |  |         wst_service_uids = [s.UID() for s in services] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 804 |  |  |         query = { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 805 |  |  |             "portal_type": "Analysis", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 806 |  |  |             "getServiceUID": wst_service_uids, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 807 |  |  |             "review_state": "unassigned", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 808 |  |  |             "isSampleReceived": True, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 809 |  |  |             "cancellation_state": "active", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 810 |  |  |             "sort_on": "getPrioritySortkey" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 811 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 812 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 813 |  |  |         # Filter analyses their Analysis Requests have been received | 
            
                                                                                                            
                            
            
                                    
            
            
                | 814 |  |  |         analyses = bac(query) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 815 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 816 |  |  |         # No analyses, nothing to do | 
            
                                                                                                            
                            
            
                                    
            
            
                | 817 |  |  |         if not analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 818 |  |  |             return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 819 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 820 |  |  |         # Available slots for routine analyses. Sort reverse, cause we need a | 
            
                                                                                                            
                            
            
                                    
            
            
                | 821 |  |  |         # stack for sequential assignment of slots | 
            
                                                                                                            
                            
            
                                    
            
            
                | 822 |  |  |         available_slots = self.resolve_available_slots(wst, 'a') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 823 |  |  |         available_slots.sort(reverse=True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 824 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 825 |  |  |         # If there is an instrument assigned to this Worksheet Template, take | 
            
                                                                                                            
                            
            
                                    
            
            
                | 826 |  |  |         # only the analyses that allow this instrument into consideration. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 827 |  |  |         instrument = wst.getInstrument() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 828 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 829 |  |  |         # If there is method assigned to the Worksheet Template, take only the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 830 |  |  |         # analyses that allow this method into consideration. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 831 |  |  |         method = wst.getRestrictToMethod() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 832 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 833 |  |  |         # This worksheet is empty? | 
            
                                                                                                            
                            
            
                                    
            
            
                | 834 |  |  |         num_routine_analyses = len(self.getRegularAnalyses()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 835 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 836 |  |  |         # Group Analyses by Analysis Requests | 
            
                                                                                                            
                            
            
                                    
            
            
                | 837 |  |  |         ar_analyses = dict() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 838 |  |  |         ar_slots = dict() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 839 |  |  |         ar_fixed_slots = dict() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 840 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 841 |  |  |         for brain in analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 842 |  |  |             obj = api.get_object(brain) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 843 |  |  |             arid = obj.getRequestID() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 844 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 845 |  |  |             if instrument and not obj.isInstrumentAllowed(instrument): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 846 |  |  |                 # Exclude those analyses for which the worksheet's template | 
            
                                                                                                            
                            
            
                                    
            
            
                | 847 |  |  |                 # instrument is not allowed | 
            
                                                                                                            
                            
            
                                    
            
            
                | 848 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 849 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 850 |  |  |             if method and not obj.isMethodAllowed(method): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 851 |  |  |                 # Exclude those analyses for which the worksheet's template | 
            
                                                                                                            
                            
            
                                    
            
            
                | 852 |  |  |                 # method is not allowed | 
            
                                                                                                            
                            
            
                                    
            
            
                | 853 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 854 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 855 |  |  |             slot = ar_slots.get(arid, None) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 856 |  |  |             if not slot: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 857 |  |  |                 # We haven't processed other analyses that belong to the same | 
            
                                                                                                            
                            
            
                                    
            
            
                | 858 |  |  |                 # Analysis Request as the current one. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 859 |  |  |                 if len(available_slots) == 0 and num_routine_analyses == 0: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 860 |  |  |                     # No more slots available for this worksheet/template, so | 
            
                                                                                                            
                            
            
                                    
            
            
                | 861 |  |  |                     # we cannot add more analyses to this WS. Also, there is no | 
            
                                                                                                            
                            
            
                                    
            
            
                | 862 |  |  |                     # chance to process a new analysis with an available slot. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 863 |  |  |                     break | 
            
                                                                                                            
                            
            
                                    
            
            
                | 864 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 865 |  |  |                 if num_routine_analyses == 0: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 866 |  |  |                     # This worksheet is empty, but there are slots still | 
            
                                                                                                            
                            
            
                                    
            
            
                | 867 |  |  |                     # available, assign the next available slot to this analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 868 |  |  |                     slot = available_slots.pop() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 869 |  |  |                 else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 870 |  |  |                     # This worksheet is not empty and there are slots still | 
            
                                                                                                            
                            
            
                                    
            
            
                | 871 |  |  |                     # available. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 872 |  |  |                     slot = self.get_slot_position(obj.getRequest()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 873 |  |  |                     if slot: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 874 |  |  |                         # Prefixed slot position | 
            
                                                                                                            
                            
            
                                    
            
            
                | 875 |  |  |                         ar_fixed_slots[arid] = slot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 876 |  |  |                         if arid not in ar_analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 877 |  |  |                             ar_analyses[arid] = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 878 |  |  |                         ar_analyses[arid].append(obj) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 879 |  |  |                         continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 880 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 881 |  |  |                     # This worksheet does not contain any other analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 882 |  |  |                     # belonging to the same Analysis Request as the current | 
            
                                                                                                            
                            
            
                                    
            
            
                | 883 |  |  |                     if len(available_slots) == 0: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 884 |  |  |                         # There is the chance to process a new analysis that | 
            
                                                                                                            
                            
            
                                    
            
            
                | 885 |  |  |                         # belongs to an Analysis Request that is already | 
            
                                                                                                            
                            
            
                                    
            
            
                | 886 |  |  |                         # in this worksheet. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 887 |  |  |                         continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 888 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 889 |  |  |                     # Assign the next available slot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 890 |  |  |                     slot = available_slots.pop() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 891 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 892 |  |  |             ar_slots[arid] = slot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 893 |  |  |             if arid not in ar_analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 894 |  |  |                 ar_analyses[arid] = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 895 |  |  |             ar_analyses[arid].append(obj) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 896 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 897 |  |  |         # Sort the analysis requests by sortable_title, so the ARs will appear | 
            
                                                                                                            
                            
            
                                    
            
            
                | 898 |  |  |         # sorted in natural order. Since we will add the analysis with the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 899 |  |  |         # exact slot where they have to be displayed, we need to sort the slots | 
            
                                                                                                            
                            
            
                                    
            
            
                | 900 |  |  |         # too and assign them to each group of analyses in natural order | 
            
                                                                                                            
                            
            
                                    
            
            
                | 901 |  |  |         sorted_ar_ids = sorted(ar_analyses.keys()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 902 |  |  |         slots = sorted(ar_slots.values(), reverse=True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 903 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 904 |  |  |         # Add regular analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 905 |  |  |         for ar_id in sorted_ar_ids: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 906 |  |  |             slot = ar_fixed_slots.get(ar_id, None) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 907 |  |  |             if not slot: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 908 |  |  |                 slot = slots.pop() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 909 |  |  |             ar_ans = ar_analyses[ar_id] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 910 |  |  |             for ar_an in ar_ans: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 911 |  |  |                 self.addAnalysis(ar_an, slot) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 912 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 913 |  |  |     def _apply_worksheet_template_duplicate_analyses(self, wst): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 914 |  |  |         """Add duplicate analyses to worksheet according to the worksheet template | 
            
                                                                                                            
                            
            
                                    
            
            
                | 915 |  |  |         layout passed in w/o overwrite slots that are already filled. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 916 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 917 |  |  |         If the slot where the duplicate must be located is available, but the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 918 |  |  |         slot where the routine analysis should be found is empty, no duplicate | 
            
                                                                                                            
                            
            
                                    
            
            
                | 919 |  |  |         will be generated for that given slot. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 920 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 921 |  |  |         :param wst: worksheet template used as the layout | 
            
                                                                                                            
                            
            
                                    
            
            
                | 922 |  |  |         :returns: None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 923 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 924 |  |  |         wst_layout = wst.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 925 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 926 |  |  |         for row in wst_layout: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 927 |  |  |             if row['type'] != 'd': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 928 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 929 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 930 |  |  |             src_pos = to_int(row['dup']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 931 |  |  |             dest_pos = to_int(row['pos']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 932 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 933 |  |  |             self.addDuplicateAnalyses(src_pos, dest_pos) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 934 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 935 |  |  |     def _resolve_reference_sample(self, reference_samples=None, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 936 |  |  |                                   service_uids=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 937 |  |  |         """Returns the reference sample from reference_samples passed in that fits | 
            
                                                                                                            
                            
            
                                    
            
            
                | 938 |  |  |         better with the service uid requirements. This is, the reference sample | 
            
                                                                                                            
                            
            
                                    
            
            
                | 939 |  |  |         that covers most (or all) of the service uids passed in and has less | 
            
                                                                                                            
                            
            
                                    
            
            
                | 940 |  |  |         number of remaining service_uids. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 941 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 942 |  |  |         If no reference_samples are set, returns None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 943 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 944 |  |  |         If no service_uids are set, returns the first reference_sample | 
            
                                                                                                            
                            
            
                                    
            
            
                | 945 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 946 |  |  |         :param reference_samples: list of reference samples | 
            
                                                                                                            
                            
            
                                    
            
            
                | 947 |  |  |         :param service_uids: list of service uids | 
            
                                                                                                            
                            
            
                                    
            
            
                | 948 |  |  |         :return: the reference sample that fits better with the service uids | 
            
                                                                                                            
                            
            
                                    
            
            
                | 949 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 950 |  |  |         if not reference_samples: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 951 |  |  |             return None, list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 952 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 953 |  |  |         if not service_uids: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 954 |  |  |             # Since no service filtering has been defined, there is no need to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 955 |  |  |             # look for the best choice. Return the first one | 
            
                                                                                                            
                            
            
                                    
            
            
                | 956 |  |  |             sample = reference_samples[0] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 957 |  |  |             spec_uids = sample.getSupportedServices(only_uids=True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 958 |  |  |             return sample, spec_uids | 
            
                                                                                                            
                            
            
                                    
            
            
                | 959 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 960 |  |  |         best_score = [0, 0] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 961 |  |  |         best_sample = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 962 |  |  |         best_supported = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 963 |  |  |         for sample in reference_samples: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 964 |  |  |             specs_uids = sample.getSupportedServices(only_uids=True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 965 |  |  |             supported = [uid for uid in specs_uids if uid in service_uids] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 966 |  |  |             matches = len(supported) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 967 |  |  |             overlays = len(service_uids) - matches | 
            
                                                                                                            
                            
            
                                    
            
            
                | 968 |  |  |             overlays = 0 if overlays < 0 else overlays | 
            
                                                                                                            
                            
            
                                    
            
            
                | 969 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 970 |  |  |             if overlays == 0 and matches == len(service_uids): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 971 |  |  |                 # Perfect match.. no need to go further | 
            
                                                                                                            
                            
            
                                    
            
            
                | 972 |  |  |                 return sample, supported | 
            
                                                                                                            
                            
            
                                    
            
            
                | 973 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 974 |  |  |             if not best_sample \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 975 |  |  |                     or matches > best_score[0] \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 976 |  |  |                     or (matches == best_score[0] and overlays < best_score[1]): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 977 |  |  |                 best_sample = sample | 
            
                                                                                                            
                            
            
                                    
            
            
                | 978 |  |  |                 best_score = [matches, overlays] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 979 |  |  |                 best_supported = supported | 
            
                                                                                                            
                            
            
                                    
            
            
                | 980 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 981 |  |  |         return best_sample, best_supported | 
            
                                                                                                            
                            
            
                                    
            
            
                | 982 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 983 |  |  |     def _resolve_reference_samples(self, wst, type): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 984 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 985 |  |  |         Resolves the slots and reference samples in accordance with the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 986 |  |  |         Worksheet Template passed in and the type passed in. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 987 |  |  |         Returns a list of dictionaries | 
            
                                                                                                            
                            
            
                                    
            
            
                | 988 |  |  |         :param wst: Worksheet Template that defines the layout | 
            
                                                                                                            
                            
            
                                    
            
            
                | 989 |  |  |         :param type: type of analyses ('b' for blanks, 'c' for controls) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 990 |  |  |         :return: list of dictionaries | 
            
                                                                                                            
                            
            
                                    
            
            
                | 991 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 992 |  |  |         if not type or type not in ['b', 'c']: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 993 |  |  |             return [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 994 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 995 |  |  |         bc = api.get_tool("bika_catalog") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 996 |  |  |         wst_type = type == 'b' and 'blank_ref' or 'control_ref' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 997 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 998 |  |  |         slots_sample = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 999 |  |  |         available_slots = self.resolve_available_slots(wst, type) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1000 |  |  |         wst_layout = wst.getLayout() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1001 |  |  |         for row in wst_layout: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1002 |  |  |             slot = int(row['pos']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1003 |  |  |             if slot not in available_slots: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1004 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1005 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1006 |  |  |             ref_definition_uid = row.get(wst_type, None) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1007 |  |  |             if not ref_definition_uid: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1008 |  |  |                 # Only reference analyses with reference definition can be used | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1009 |  |  |                 # in worksheet templates | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1010 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1011 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1012 |  |  |             samples = bc(portal_type='ReferenceSample', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1013 |  |  |                          review_state='current', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1014 |  |  |                          inactive_state='active', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1015 |  |  |                          getReferenceDefinitionUID=ref_definition_uid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1016 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1017 |  |  |             # We only want the reference samples that fit better with the type | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1018 |  |  |             # and with the analyses defined in the Template | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1019 |  |  |             services = wst.getService() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1020 |  |  |             services = [s.UID() for s in services] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1021 |  |  |             candidates = list() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1022 |  |  |             for sample in samples: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1023 |  |  |                 obj = api.get_object(sample) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1024 |  |  |                 if (type == 'b' and obj.getBlank()) or \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1025 |  |  |                         (type == 'c' and not obj.getBlank()): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1026 |  |  |                     candidates.append(obj) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1027 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1028 |  |  |             sample, uids = self._resolve_reference_sample(candidates, services) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1029 |  |  |             if not sample: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1030 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1031 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1032 |  |  |             slots_sample.append({'slot': slot, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1033 |  |  |                                  'sample': sample, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1034 |  |  |                                  'supported_services': uids}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1035 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1036 |  |  |         return slots_sample | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1037 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1038 |  |  |     def _apply_worksheet_template_reference_analyses(self, wst, type='all'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1039 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1040 |  |  |         Add reference analyses to worksheet according to the worksheet template | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1041 |  |  |         layout passed in. Does not overwrite slots that are already filled. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1042 |  |  |         :param wst: worksheet template used as the layout | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1043 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1044 |  |  |         if type == 'all': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1045 |  |  |             self._apply_worksheet_template_reference_analyses(wst, 'b') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1046 |  |  |             self._apply_worksheet_template_reference_analyses(wst, 'c') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1047 |  |  |             return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1048 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1049 |  |  |         if type not in ['b', 'c']: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1050 |  |  |             return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1051 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1052 |  |  |         references = self._resolve_reference_samples(wst, type) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1053 |  |  |         for reference in references: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1054 |  |  |             slot = reference['slot'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1055 |  |  |             sample = reference['sample'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1056 |  |  |             services = reference['supported_services'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1057 |  |  |             self.addReferenceAnalyses(sample, services, slot) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1058 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1059 |  |  |     def applyWorksheetTemplate(self, wst): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1060 |  |  |         """ Add analyses to worksheet according to wst's layout. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1061 |  |  |             Will not overwrite slots which are filled already. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1062 |  |  |             If the selected template has an instrument assigned, it will | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1063 |  |  |             only be applied to those analyses for which the instrument | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1064 |  |  |             is allowed, the same happens with methods. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1065 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1066 |  |  |         # Store the Worksheet Template field | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1067 |  |  |         self.getField('WorksheetTemplate').set(self, wst) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1068 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1069 |  |  |         if not wst: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1070 |  |  |             return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1071 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1072 |  |  |         # Apply the template for routine analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1073 |  |  |         self._apply_worksheet_template_routine_analyses(wst) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1074 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1075 |  |  |         # Apply the template for duplicate analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1076 |  |  |         self._apply_worksheet_template_duplicate_analyses(wst) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1077 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1078 |  |  |         # Apply the template for reference analyses (blanks and controls) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1079 |  |  |         self._apply_worksheet_template_reference_analyses(wst) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1080 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1081 |  |  |         # Assign the instrument | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1082 |  |  |         instrument = wst.getInstrument() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1083 |  |  |         if instrument: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1084 |  |  |             self.setInstrument(instrument, True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1085 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1086 |  |  |         # Assign the method | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1087 |  |  |         method = wst.getRestrictToMethod() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1088 |  |  |         if method: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1089 |  |  |             self.setMethod(method, True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1090 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1091 |  |  |     def getInstrumentTitle(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1092 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1093 |  |  |         Returns the instrument title | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1094 |  |  |         :returns: instrument's title | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1095 |  |  |         :rtype: string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1096 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1097 |  |  |         instrument = self.getInstrument() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1098 |  |  |         if instrument: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1099 |  |  |             return instrument.Title() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1100 |  |  |         return '' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1101 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1102 |  |  |     def getWorksheetTemplateUID(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1103 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1104 |  |  |         Returns the template's UID assigned to this worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1105 |  |  |         :returns: worksheet's UID | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1106 |  |  |         :rtype: UID as string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1107 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1108 |  |  |         ws = self.getWorksheetTemplate() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1109 |  |  |         if ws: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1110 |  |  |             return ws.UID() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1111 |  |  |         return '' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1112 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1113 |  |  |     def getWorksheetTemplateTitle(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1114 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1115 |  |  |         Returns the template's Title assigned to this worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1116 |  |  |         :returns: worksheet's Title | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1117 |  |  |         :rtype: string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1118 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1119 |  |  |         ws = self.getWorksheetTemplate() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1120 |  |  |         if ws: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1121 |  |  |             return ws.Title() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1122 |  |  |         return '' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1123 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1124 |  |  |     def getWorksheetTemplateURL(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1125 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1126 |  |  |         Returns the template's URL assigned to this worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1127 |  |  |         :returns: worksheet's URL | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1128 |  |  |         :rtype: string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1129 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1130 |  |  |         ws = self.getWorksheetTemplate() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1131 |  |  |         if ws: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1132 |  |  |             return ws.absolute_url_path() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1133 |  |  |         return '' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1134 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1135 |  |  |     def getWorksheetServices(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1136 |  |  |         """get list of analysis services present on this worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1137 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1138 |  |  |         services = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1139 |  |  |         for analysis in self.getAnalyses(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1140 |  |  |             service = analysis.getAnalysisService() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1141 |  |  |             if service and service not in services: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1142 |  |  |                 services.append(service) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1143 |  |  |         return services | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1144 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1145 |  |  |     def getQCAnalyses(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1146 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1147 |  |  |         Return the Quality Control analyses. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1148 |  |  |         :returns: a list of QC analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1149 |  |  |         :rtype: List of ReferenceAnalysis/DuplicateAnalysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1150 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1151 |  |  |         qc_types = ['ReferenceAnalysis', 'DuplicateAnalysis'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1152 |  |  |         analyses = self.getAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1153 |  |  |         return [a for a in analyses if a.portal_type in qc_types] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1154 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1155 |  |  |     def getDuplicateAnalyses(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1156 |  |  |         """Return the duplicate analyses assigned to the current worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1157 |  |  |         :return: List of DuplicateAnalysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1158 |  |  |         :rtype: List of IDuplicateAnalysis objects""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1159 |  |  |         ans = self.getAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1160 |  |  |         duplicates = [an for an in ans if IDuplicateAnalysis.providedBy(an)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1161 |  |  |         return duplicates | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1162 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1163 |  |  |     def getReferenceAnalyses(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1164 |  |  |         """Return the reference analyses (controls) assigned to the current | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1165 |  |  |         worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1166 |  |  |         :return: List of reference analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1167 |  |  |         :rtype: List of IReferenceAnalysis objects""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1168 |  |  |         ans = self.getAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1169 |  |  |         references = [an for an in ans if IReferenceAnalysis.providedBy(an)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1170 |  |  |         return references | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1171 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1172 |  |  |     def getRegularAnalyses(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1173 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1174 |  |  |         Return the analyses assigned to the current worksheet that are directly | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1175 |  |  |         associated to an Analysis Request but are not QC analyses. This is all | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1176 |  |  |         analyses that implement IRoutineAnalysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1177 |  |  |         :return: List of regular analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1178 |  |  |         :rtype: List of ReferenceAnalysis/DuplicateAnalysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1179 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1180 |  |  |         qc_types = ['ReferenceAnalysis', 'DuplicateAnalysis'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1181 |  |  |         analyses = self.getAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1182 |  |  |         return [a for a in analyses if a.portal_type not in qc_types] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1183 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1184 |  |  |     def getNumberOfQCAnalyses(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1185 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1186 |  |  |         Returns the number of Quality Control analyses. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1187 |  |  |         :returns: number of QC analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1188 |  |  |         :rtype: integer | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1189 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1190 |  |  |         return len(self.getQCAnalyses()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1191 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1192 |  |  |     def getNumberOfRegularAnalyses(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1193 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1194 |  |  |         Returns the number of Regular analyses. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1195 |  |  |         :returns: number of analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1196 |  |  |         :rtype: integer | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1197 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1198 |  |  |         return len(self.getRegularAnalyses()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1199 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1200 |  |  |     def getNumberOfQCSamples(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1201 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1202 |  |  |         Returns the number of Quality Control samples. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1203 |  |  |         :returns: number of QC samples | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1204 |  |  |         :rtype: integer | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1205 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1206 |  |  |         qc_analyses = self.getQCAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1207 |  |  |         qc_samples = [a.getSample().UID() for a in qc_analyses] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1208 |  |  |         # discarding any duplicate values | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1209 |  |  |         return len(set(qc_samples)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1210 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1211 |  |  |     def getNumberOfRegularSamples(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1212 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1213 |  |  |         Returns the number of regular samples. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1214 |  |  |         :returns: number of regular samples | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1215 |  |  |         :rtype: integer | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1216 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1217 |  |  |         analyses = self.getRegularAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1218 |  |  |         samples = [a.getSample().UID() for a in analyses] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1219 |  |  |         # discarding any duplicate values | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1220 |  |  |         return len(set(samples)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1221 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1222 |  |  |     def setInstrument(self, instrument, override_analyses=False): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1223 |  |  |         """ Sets the specified instrument to the Analysis from the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1224 |  |  |             Worksheet. Only sets the instrument if the Analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1225 |  |  |             allows it, according to its Analysis Service and Method. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1226 |  |  |             If an analysis has already assigned an instrument, it won't | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1227 |  |  |             be overriden. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1228 |  |  |             The Analyses that don't allow the instrument specified will | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1229 |  |  |             not be modified. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1230 |  |  |             Returns the number of analyses affected | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1231 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1232 |  |  |         analyses = [an for an in self.getAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1233 |  |  |                     if (not an.getInstrument() or override_analyses) and | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1234 |  |  |                     an.isInstrumentAllowed(instrument)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1235 |  |  |         total = 0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1236 |  |  |         for an in analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1237 |  |  |             # An analysis can be done using differents Methods. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1238 |  |  |             # Un method can be supported by more than one Instrument, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1239 |  |  |             # but not all instruments support one method. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1240 |  |  |             # We must force to set the instrument's method too. Otherwise, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1241 |  |  |             # the WS manage results view will display the an's default | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1242 |  |  |             # method and its instruments displaying, only the instruments | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1243 |  |  |             # for the default method in the picklist. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1244 |  |  |             instr_methods = instrument.getMethods() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1245 |  |  |             meth = instr_methods[0] if instr_methods else None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1246 |  |  |             if meth and an.isMethodAllowed(meth): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1247 |  |  |                 if an.getMethod() not in instr_methods: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1248 |  |  |                     an.setMethod(meth) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1249 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1250 |  |  |             an.setInstrument(instrument) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1251 |  |  |             total += 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1252 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1253 |  |  |         self.getField('Instrument').set(self, instrument) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1254 |  |  |         return total | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1255 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1256 |  |  |     def setMethod(self, method, override_analyses=False): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1257 |  |  |         """ Sets the specified method to the Analyses from the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1258 |  |  |             Worksheet. Only sets the method if the Analysis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1259 |  |  |             allows to keep the integrity. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1260 |  |  |             If an analysis has already been assigned to a method, it won't | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1261 |  |  |             be overriden. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1262 |  |  |             Returns the number of analyses affected. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1263 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1264 |  |  |         analyses = [an for an in self.getAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1265 |  |  |                     if (not an.getMethod() or | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1266 |  |  |                         not an.getInstrument() or | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1267 |  |  |                         override_analyses) and an.isMethodAllowed(method)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1268 |  |  |         total = 0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1269 |  |  |         for an in analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1270 |  |  |             success = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1271 |  |  |             if an.isMethodAllowed(method): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1272 |  |  |                 success = an.setMethod(method) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1273 |  |  |             if success is True: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1274 |  |  |                 total += 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1275 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1276 |  |  |         self.getField('Method').set(self, method) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1277 |  |  |         return total | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1278 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1279 |  |  |     def getAnalystName(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1280 |  |  |         """ Returns the name of the currently assigned analyst | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1281 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1282 |  |  |         mtool = getToolByName(self, 'portal_membership') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1283 |  |  |         analyst = self.getAnalyst().strip() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1284 |  |  |         analyst_member = mtool.getMemberById(analyst) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1285 |  |  |         if analyst_member is not None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1286 |  |  |             return analyst_member.getProperty('fullname') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1287 |  |  |         return analyst | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1288 |  |  |  | 
            
                                                                                                            
                            
            
                                                                    
                                                                                                        
            
            
                | 1289 |  | View Code Duplication |     def getObjectWorkflowStates(self): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1290 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1291 |  |  |         This method is used as a metacolumn. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1292 |  |  |         Returns a dictionary with the workflow id as key and workflow state as | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1293 |  |  |         value. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1294 |  |  |         :returns: {'review_state':'active',...} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1295 |  |  |         :rtype: dict | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1296 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1297 |  |  |         workflow = getToolByName(self, 'portal_workflow') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1298 |  |  |         states = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1299 |  |  |         for w in workflow.getWorkflowsFor(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1300 |  |  |             state = w._getWorkflowStateOf(self).id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1301 |  |  |             states[w.state_var] = state | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1302 |  |  |         return states | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1303 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1304 |  |  |     # TODO Workflow - Worksheet - Move to workflow.worksheet.events | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1305 |  |  |     def workflow_script_reject(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1306 |  |  |         """Copy real analyses to RejectAnalysis, with link to real | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1307 |  |  |            create a new worksheet, with the original analyses, and new | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1308 |  |  |            duplicates and references to match the rejected | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1309 |  |  |            worksheet. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1310 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1311 |  |  |         if skip(self, "reject"): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1312 |  |  |             return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1313 |  |  |         workflow = self.portal_workflow | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1314 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1315 |  |  |         def copy_src_fields_to_dst(src, dst): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1316 |  |  |             # These will be ignored when copying field values between analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1317 |  |  |             ignore_fields = [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1318 |  |  |                 'UID', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1319 |  |  |                 'id', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1320 |  |  |                 'title', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1321 |  |  |                 'allowDiscussion', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1322 |  |  |                 'subject', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1323 |  |  |                 'description', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1324 |  |  |                 'location', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1325 |  |  |                 'contributors', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1326 |  |  |                 'creators', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1327 |  |  |                 'effectiveDate', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1328 |  |  |                 'expirationDate', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1329 |  |  |                 'language', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1330 |  |  |                 'rights', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1331 |  |  |                 'creation_date', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1332 |  |  |                 'modification_date', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1333 |  |  |                 'Layout',    # ws | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1334 |  |  |                 'Analyses',  # ws | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1335 |  |  |             ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1336 |  |  |             fields = src.Schema().fields() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1337 |  |  |             for field in fields: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1338 |  |  |                 fieldname = field.getName() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1339 |  |  |                 if fieldname in ignore_fields: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1340 |  |  |                     continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1341 |  |  |                 getter = getattr(src, 'get' + fieldname, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1342 |  |  |                                  src.Schema().getField(fieldname).getAccessor(src)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1343 |  |  |                 setter = getattr(dst, 'set' + fieldname, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1344 |  |  |                                  dst.Schema().getField(fieldname).getMutator(dst)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1345 |  |  |                 if getter is None or setter is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1346 |  |  |                     # ComputedField | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1347 |  |  |                     continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1348 |  |  |                 setter(getter()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1349 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1350 |  |  |         analysis_positions = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1351 |  |  |         for item in self.getLayout(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1352 |  |  |             analysis_positions[item['analysis_uid']] = item['position'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1353 |  |  |         old_layout = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1354 |  |  |         new_layout = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1355 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1356 |  |  |         # New worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1357 |  |  |         worksheets = self.aq_parent | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1358 |  |  |         new_ws = _createObjectByType('Worksheet', worksheets, tmpID()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1359 |  |  |         new_ws.unmarkCreationFlag() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1360 |  |  |         new_ws_id = renameAfterCreation(new_ws) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1361 |  |  |         copy_src_fields_to_dst(self, new_ws) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1362 |  |  |         new_ws.edit( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1363 |  |  |             Number=new_ws_id, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1364 |  |  |             Remarks=self.getRemarks() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1365 |  |  |         ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1366 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1367 |  |  |         # Objects are being created inside other contexts, but we want their | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1368 |  |  |         # workflow handlers to be aware of which worksheet this is occurring in. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1369 |  |  |         # We save the worksheet in request['context_uid']. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1370 |  |  |         # We reset it again below....  be very sure that this is set to the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1371 |  |  |         # UID of the containing worksheet before invoking any transitions on | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1372 |  |  |         # analyses. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1373 |  |  |         self.REQUEST['context_uid'] = new_ws.UID() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1374 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1375 |  |  |         # loop all analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1376 |  |  |         analyses = self.getAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1377 |  |  |         new_ws_analyses = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1378 |  |  |         old_ws_analyses = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1379 |  |  |         for analysis in analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1380 |  |  |             # Skip published or verified analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1381 |  |  |             review_state = workflow.getInfoFor(analysis, 'review_state', '') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1382 |  |  |             if review_state in ['published', 'verified', 'retracted']: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1383 |  |  |                 old_ws_analyses.append(analysis.UID()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1384 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1385 |  |  |                 # XXX where does position come from? | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1386 |  |  |                 old_layout.append({'position': position, | 
                            
                    |  |  |  | 
                                                                                        
                                                                                            
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1387 |  |  |                                    'type': 'a', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1388 |  |  |                                    'analysis_uid': analysis.UID(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1389 |  |  |                                    'container_uid': analysis.aq_parent.UID()}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1390 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1391 |  |  |             # Normal analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1392 |  |  |             # - Create matching RejectAnalysis inside old WS | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1393 |  |  |             # - Link analysis to new WS in same position | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1394 |  |  |             # - Copy all field values | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1395 |  |  |             # - Clear analysis result, and set Retested flag | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1396 |  |  |             if analysis.portal_type == 'Analysis': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1397 |  |  |                 reject = _createObjectByType('RejectAnalysis', self, tmpID()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1398 |  |  |                 reject.unmarkCreationFlag() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1399 |  |  |                 copy_src_fields_to_dst(analysis, reject) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1400 |  |  |                 reject.setAnalysis(analysis) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1401 |  |  |                 reject.reindexObject() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1402 |  |  |                 analysis.edit( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1403 |  |  |                     Result=None, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1404 |  |  |                     Retested=True, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1405 |  |  |                 ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1406 |  |  |                 analysis.reindexObject() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1407 |  |  |                 position = analysis_positions[analysis.UID()] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1408 |  |  |                 old_ws_analyses.append(reject.UID()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1409 |  |  |                 old_layout.append({'position': position, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1410 |  |  |                                    'type': 'r', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1411 |  |  |                                    'analysis_uid': reject.UID(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1412 |  |  |                                    'container_uid': self.UID()}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1413 |  |  |                 new_ws_analyses.append(analysis.UID()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1414 |  |  |                 new_layout.append({'position': position, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1415 |  |  |                                    'type': 'a', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1416 |  |  |                                    'analysis_uid': analysis.UID(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1417 |  |  |                                    'container_uid': analysis.aq_parent.UID()}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1418 |  |  |             # Reference analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1419 |  |  |             # - Create a new reference analysis in the new worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1420 |  |  |             # - Transition the original analysis to 'rejected' state | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1421 |  |  |             if analysis.portal_type == 'ReferenceAnalysis': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1422 |  |  |                 service_uid = analysis.getServiceUID() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1423 |  |  |                 reference = analysis.aq_parent | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1424 |  |  |                 new_reference = reference.addReferenceAnalysis(service_uid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1425 |  |  |                 reference_type = new_reference.getReferenceType() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1426 |  |  |                 new_analysis_uid = api.get_uid(new_reference) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1427 |  |  |                 position = analysis_positions[analysis.UID()] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1428 |  |  |                 old_ws_analyses.append(analysis.UID()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1429 |  |  |                 old_layout.append({'position': position, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1430 |  |  |                                    'type': reference_type, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1431 |  |  |                                    'analysis_uid': analysis.UID(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1432 |  |  |                                    'container_uid': reference.UID()}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1433 |  |  |                 new_ws_analyses.append(new_analysis_uid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1434 |  |  |                 new_layout.append({'position': position, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1435 |  |  |                                    'type': reference_type, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1436 |  |  |                                    'analysis_uid': new_analysis_uid, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1437 |  |  |                                    'container_uid': reference.UID()}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1438 |  |  |                 workflow.doActionFor(analysis, 'reject') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1439 |  |  |                 analysis.reindexObject() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1440 |  |  |             # Duplicate analyses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1441 |  |  |             # - Create a new duplicate inside the new worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1442 |  |  |             # - Transition the original analysis to 'rejected' state | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1443 |  |  |             if analysis.portal_type == 'DuplicateAnalysis': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1444 |  |  |                 duplicate_id = new_ws.generateUniqueId('DuplicateAnalysis') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1445 |  |  |                 new_duplicate = _createObjectByType('DuplicateAnalysis', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1446 |  |  |                                                     new_ws, duplicate_id) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1447 |  |  |                 new_duplicate.unmarkCreationFlag() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1448 |  |  |                 copy_src_fields_to_dst(analysis, new_duplicate) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1449 |  |  |                 new_duplicate.reindexObject() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1450 |  |  |                 position = analysis_positions[analysis.UID()] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1451 |  |  |                 old_ws_analyses.append(analysis.UID()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1452 |  |  |                 old_layout.append({'position': position, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1453 |  |  |                                    'type': 'd', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1454 |  |  |                                    'analysis_uid': analysis.UID(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1455 |  |  |                                    'container_uid': self.UID()}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1456 |  |  |                 new_ws_analyses.append(new_duplicate.UID()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1457 |  |  |                 new_layout.append({'position': position, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1458 |  |  |                                    'type': 'd', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1459 |  |  |                                    'analysis_uid': new_duplicate.UID(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1460 |  |  |                                    'container_uid': new_ws.UID()}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1461 |  |  |                 workflow.doActionFor(analysis, 'reject') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1462 |  |  |                 analysis.reindexObject() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1463 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1464 |  |  |         new_ws.setAnalyses(new_ws_analyses) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1465 |  |  |         new_ws.setLayout(new_layout) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1466 |  |  |         new_ws.replaces_rejected_worksheet = self.UID() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1467 |  |  |         for analysis in new_ws.getAnalyses(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1468 |  |  |             review_state = workflow.getInfoFor(analysis, 'review_state', '') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1469 |  |  |             if review_state == 'to_be_verified': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1470 |  |  |                 # TODO Workflow - Analysis Retest transition within a Worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1471 |  |  |                 changeWorkflowState(analysis, "bika_analysis_workflow", "assigned") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1472 |  |  |         self.REQUEST['context_uid'] = self.UID() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1473 |  |  |         self.setLayout(old_layout) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1474 |  |  |         self.setAnalyses(old_ws_analyses) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1475 |  |  |         self.replaced_by = new_ws.UID() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1476 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1477 |  |  |     # TODO Workflow - Worksheet - Remove this function | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1478 |  |  |     def checkUserManage(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1479 |  |  |         """ Checks if the current user has granted access to this worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1480 |  |  |             and if has also privileges for managing it. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1481 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1482 |  |  |         granted = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1483 |  |  |         can_access = self.checkUserAccess() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1484 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1485 |  |  |         if can_access is True: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1486 |  |  |             pm = getToolByName(self, 'portal_membership') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1487 |  |  |             edit_allowed = pm.checkPermission(EditWorksheet, self) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1488 |  |  |             if edit_allowed: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1489 |  |  |                 # Check if the current user is the WS's current analyst | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1490 |  |  |                 member = pm.getAuthenticatedMember() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1491 |  |  |                 analyst = self.getAnalyst().strip() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1492 |  |  |                 if analyst != _c(member.getId()): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1493 |  |  |                     # Has management privileges? | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1494 |  |  |                     if pm.checkPermission(ManageWorksheets, self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1495 |  |  |                         granted = True | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1496 |  |  |                 else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1497 |  |  |                     granted = True | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1498 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1499 |  |  |         return granted | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1500 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1501 |  |  |     # TODO Workflow - Worksheet - Remove this function | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1502 |  |  |     def checkUserAccess(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1503 |  |  |         """ Checks if the current user has granted access to this worksheet. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1504 |  |  |             Returns False if the user has no access, otherwise returns True | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1505 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1506 |  |  |         # Deny access to foreign analysts | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1507 |  |  |         allowed = True | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1508 |  |  |         pm = getToolByName(self, "portal_membership") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1509 |  |  |         member = pm.getAuthenticatedMember() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1510 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1511 |  |  |         analyst = self.getAnalyst().strip() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1512 |  |  |         if analyst != _c(member.getId()): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1513 |  |  |             roles = member.getRoles() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1514 |  |  |             restrict = 'Manager' not in roles \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1515 |  |  |                 and 'LabManager' not in roles \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1516 |  |  |                 and 'LabClerk' not in roles \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1517 |  |  |                 and 'RegulatoryInspector' not in roles \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1518 |  |  |                 and self.bika_setup.getRestrictWorksheetUsersAccess() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1519 |  |  |             allowed = not restrict | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1520 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1521 |  |  |         return allowed | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1522 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1523 |  |  |     def setAnalyst(self, analyst): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1524 |  |  |         for analysis in self.getAnalyses(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1525 |  |  |             analysis.setAnalyst(analyst) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1526 |  |  |         self.Schema().getField('Analyst').set(self, analyst) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1527 |  |  |         self.reindexObject() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1528 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1529 |  |  |     def getAnalysesUIDs(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1530 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1531 |  |  |         Returns the analyses UIDs from the analyses assigned to this worksheet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1532 |  |  |         :returns: a list of UIDs | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1533 |  |  |         :rtype: a list of strings | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1534 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1535 |  |  |         analyses = self.getAnalyses() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1536 |  |  |         if isinstance(analyses, list): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1537 |  |  |             return [an.UID() for an in analyses] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1538 |  |  |         return [] | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 1539 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 1540 |  |  |     def getProgressPercentage(self): | 
            
                                                                        
                            
            
                                    
            
            
                | 1541 |  |  |         """Returns the progress percentage of this worksheet | 
            
                                                                        
                            
            
                                    
            
            
                | 1542 |  |  |         """ | 
            
                                                                        
                            
            
                                    
            
            
                | 1543 |  |  |         state = api.get_workflow_status_of(self) | 
            
                                                                        
                            
            
                                    
            
            
                | 1544 |  |  |         if state == "verified": | 
            
                                                                        
                            
            
                                    
            
            
                | 1545 |  |  |             return 100 | 
            
                                                                        
                            
            
                                    
            
            
                | 1546 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 1547 |  |  |         steps = 0 | 
            
                                                                        
                            
            
                                    
            
            
                | 1548 |  |  |         query = dict(getWorksheetUID=api.get_uid(self)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1549 |  |  |         analyses = api.search(query, CATALOG_ANALYSIS_LISTING) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1550 |  |  |         max_steps = len(analyses) * 2 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1551 |  |  |         for analysis in analyses: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1552 |  |  |             an_state = analysis.review_state | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1553 |  |  |             if an_state in ["rejected", "retracted", "cancelled"]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1554 |  |  |                 steps += 2 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1555 |  |  |             elif an_state in ["verified", "published"]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1556 |  |  |                 steps += 2 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1557 |  |  |             elif an_state == "to_be_verified": | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1558 |  |  |                 steps += 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1559 |  |  |         if steps == 0: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1560 |  |  |             return 0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1561 |  |  |         if steps > max_steps: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1562 |  |  |             return 100 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1563 |  |  |         return (steps * 100)/max_steps | 
            
                                                                                                            
                            
            
                                    
            
            
                | 1564 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 1565 |  |  | registerType(Worksheet, PROJECTNAME) | 
            
                                                        
            
                                    
            
            
                | 1566 |  |  |  |