Ejemplo n.º 1
0
    def __call__(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(form)
        action, came_from = WorkflowAction._get_form_workflow_action(self)

        if action == 'submit':

            objects = WorkflowAction._get_selected_items(self)
            if not objects:
                message = self.context.translate(
                    _b("No analyses have been selected"))
                self.context.plone_utils.addPortalMessage(message, 'info')
                self.destination_url = self.context.absolute_url() + \
                    "/batchbook"
                self.request.response.redirect(self.destination_url)
                return

            for ar_uid, ar in objects.items():
                for analysis in ar.getAnalyses(full_objects=True):
                    kw = analysis.getKeyword()
                    values = form.get(kw)
                    analysis.setResult(values[0][ar_uid])
                    if values[0][ar_uid]:
                        doActionFor(analysis, 'submit')

            message = self.context.translate(_p("Changes saved."))
            self.context.plone_utils.addPortalMessage(message, 'info')
            self.request.response.redirect(self.request.get('URL'))
            return

        else:

            WorkflowAction.__call__(self)
Ejemplo n.º 2
0
    def __call__(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(form)
        workflow = getToolByName(self.context, 'portal_workflow')

        if self.destination_url == "":
            self.destination_url = self.request.get_header(
                "referer", self.context.absolute_url())
        action, came_from = self._get_form_workflow_action()

        # transition the context object (plone edit bar dropdown)
        if came_from == "workflow_action":
            obj = self.context
            # the only actions allowed on inactive/cancelled
            # items are "reinstate" and "activate"
            if not isActive(obj) and action not in ('reinstate', 'activate'):
                message = self.context.translate(_('Item is inactive.'))
                self.context.plone_utils.addPortalMessage(message, 'info')
                self.request.response.redirect(self.destination_url)
                return
            if not skip(obj, action, peek=True):
                allowed_transitions = []
                for t in workflow.getTransitionsFor(obj):
                    allowed_transitions.append(t['id'])
                if action in allowed_transitions:
                    workflow.doActionFor(obj, action)
            self.request.response.redirect(self.destination_url)
            return

        # transition selected items from the bika_listing/Table.
        transitioned = []
        selected_items = self._get_selected_items()
        for uid, item in selected_items.items():
            # the only actions allowed on inactive/cancelled
            # items are "reinstate" and "activate"
            if not isActive(item) and action not in ('reinstate', 'activate'):
                continue
            if not skip(item, action, peek=True):
                allowed_transitions = []
                for t in workflow.getTransitionsFor(item):
                    allowed_transitions.append(t['id'])
                if action in allowed_transitions:
                    doActionFor(item, action)
                    transitioned.append(item.Title())

        if len(transitioned) > 0:
            message = self.context.translate(PMF('Changes saved.'))
            self.context.plone_utils.addPortalMessage(message, 'info')

        # automatic label printing
        if action == 'receive' and 'receive' in self.portal.bika_setup.getAutoPrintLabels(
        ):
            q = "/sticker?size=%s&items=" % (
                self.portal.bika_setup.getAutoLabelSize())
            # selected_items is a list of UIDs (stickers for AR_add use IDs)
            q += ",".join([i.getId() for i in selected_items.values()])
            self.request.response.redirect(self.context.absolute_url() + q)
        else:
            self.request.response.redirect(self.destination_url)
Ejemplo n.º 3
0
    def __call__(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(form)
        workflow = getToolByName(self.context, 'portal_workflow')

        if self.destination_url == "":
            self.destination_url = self.request.get_header("referer",
                                   self.context.absolute_url())
        action, came_from = self._get_form_workflow_action()

        # transition the context object (plone edit bar dropdown)
        if came_from == "workflow_action":
            obj = self.context
            # the only actions allowed on inactive/cancelled
            # items are "reinstate" and "activate"
            if not isActive(obj) and action not in ('reinstate', 'activate'):
                message = self.context.translate(_('Item is inactive.'))
                self.context.plone_utils.addPortalMessage(message, 'info')
                self.request.response.redirect(self.destination_url)
                return
            if not skip(obj, action, peek=True):
                allowed_transitions = []
                for t in workflow.getTransitionsFor(obj):
                    allowed_transitions.append(t['id'])
                if action in allowed_transitions:
                    workflow.doActionFor(obj, action)
            self.request.response.redirect(self.destination_url)
            return

        # transition selected items from the bika_listing/Table.
        transitioned = []
        selected_items = self._get_selected_items()
        for uid, item in selected_items.items():
            # the only actions allowed on inactive/cancelled
            # items are "reinstate" and "activate"
            if not isActive(item) and action not in ('reinstate', 'activate'):
                continue
            if not skip(item, action, peek=True):
                allowed_transitions = []
                for t in workflow.getTransitionsFor(item):
                    allowed_transitions.append(t['id'])
                if action in allowed_transitions:
                    doActionFor(item, action)
                    transitioned.append(item.Title())

        if len(transitioned) > 0:
            message = self.context.translate(PMF('Changes saved.'))
            self.context.plone_utils.addPortalMessage(message, 'info')

        # automatic label printing
        if action == 'receive' and 'receive' in self.context.bika_setup.getAutoPrintLabels():
            q = "/sticker?size=%s&items=" % (self.context.bika_setup.getAutoLabelSize())
            # selected_items is a list of UIDs (stickers for AR_add use IDs)
            q += ",".join([i.getId() for i in selected_items.values()])
            self.request.response.redirect(self.context.absolute_url() + q)
        else:
            self.request.response.redirect(self.destination_url)
Ejemplo n.º 4
0
    def submitTransition(self, action, came_from, items):
        """ Performs the action's transition for the specified items
            Returns (numtransitions, destination), where:
            - numtransitions: the number of objects successfully transitioned.
                If no objects have been successfully transitioned, gets 0 value
            - destination: the destination url to be loaded immediately
        """
        dest = None
        transitioned = []
        workflow = getToolByName(self.context, 'portal_workflow')

        # transition selected items from the bika_listing/Table.
        for item in items:
            # the only actions allowed on inactive/cancelled
            # items are "reinstate" and "activate"
            if not isActive(item) and action not in ('reinstate', 'activate'):
                continue
            if not skip(item, action, peek=True):
                allowed_transitions = [it['id'] for it in \
                                       workflow.getTransitionsFor(item)]
                if action in allowed_transitions:
                    success, message = doActionFor(item, action)
                    if success:
                        transitioned.append(item.id)
                    else:
                        self.context.plone_utils.addPortalMessage(message, 'error')
        # automatic label printing
        if transitioned and action == 'receive' \
            and 'receive' in self.portal.bika_setup.getAutoPrintStickers():
            q = "/sticker?template=%s&items=" % (self.portal.bika_setup.getAutoStickerTemplate())
            # selected_items is a list of UIDs (stickers for AR_add use IDs)
            q += ",".join(transitioned)
            dest = self.context.absolute_url() + q

        return len(transitioned), dest
Ejemplo n.º 5
0
def ObjectInitializedEventHandler(instance, event):

    # This handler fires for DuplicateAnalysis because
    # DuplicateAnalysis also provides IAnalysis.
    # DuplicateAnalysis doesn't have analysis_workflow.
    if instance.portal_type == "DuplicateAnalysis":
        return

    # 'receive' instance if AR is received.
    # Adding a new instance to an AR retracts the AR to 'sample_received'
    # AR may have to be unassigned too

    ar = instance.aq_parent
    ar_UID = ar.UID()
    wf = getToolByName(instance, 'portal_workflow')
    ar_state = wf.getInfoFor(ar, 'review_state')
    ar_ws_state = wf.getInfoFor(ar, 'worksheetanalysis_review_state')

    if ar_state not in ('sample_registered', 'sampled', 'to_be_sampled',
                        'to_be_preserved', 'sample_due'):
        try:
            wf.doActionFor(instance, 'receive')
        except WorkflowException:
            pass

    # Note: AR adds itself to the skiplist so we have to take it off again
    #       to allow possible promotions if other analyses are deleted.
    if ar_state not in ('sample_registered', 'sampled', 'to_be_sampled',
                        'to_be_preserved', 'sample_due', 'sample_received'):
        if not instance.REQUEST.has_key('workflow_skiplist'):
            instance.REQUEST['workflow_skiplist'] = [
                'retract all analyses',
            ]
        else:
            instance.REQUEST["workflow_skiplist"].append(
                'retract all analyses')
        doActionFor(ar, 'retract')
        skip(ar, 'retract', unskip=True)

    if ar_ws_state == 'assigned':
        wf.doActionFor(ar, 'unassign')
        skip(ar, 'unassign', unskip=True)

    return
Ejemplo n.º 6
0
def ObjectInitializedEventHandler(instance, event):

    # This handler fires for DuplicateAnalysis because
    # DuplicateAnalysis also provides IAnalysis.
    # DuplicateAnalysis doesn't have analysis_workflow.
    if instance.portal_type == "DuplicateAnalysis":
        return

    # 'receive' instance if AR is received.
    # Adding a new instance to an AR retracts the AR to 'sample_received'
    # AR may have to be unassigned too

    ar = instance.aq_parent
    ar_UID = ar.UID()
    wf = getToolByName(instance, 'portal_workflow')
    ar_state = wf.getInfoFor(ar, 'review_state')
    ar_ws_state = wf.getInfoFor(ar, 'worksheetanalysis_review_state')

    if ar_state not in ('sample_registered', 'sampled',
                        'to_be_sampled', 'to_be_preserved',
                        'sample_due'):
        try:
            wf.doActionFor(instance, 'receive')
        except WorkflowException:
            pass

    # Note: AR adds itself to the skiplist so we have to take it off again
    #       to allow possible promotions if other analyses are deleted.
    if ar_state not in ('sample_registered', 'sampled',
                        'to_be_sampled', 'to_be_preserved',
                        'sample_due', 'sample_received'):
        if not instance.REQUEST.has_key('workflow_skiplist'):
            instance.REQUEST['workflow_skiplist'] = ['retract all analyses', ]
        else:
            instance.REQUEST["workflow_skiplist"].append('retract all analyses')
        doActionFor(ar, 'retract')
        skip(ar, 'retract', unskip=True)

    if ar_ws_state == 'assigned':
        wf.doActionFor(ar, 'unassign')
        skip(ar, 'unassign', unskip=True)

    return
Ejemplo n.º 7
0
def AfterTransitionEventHandler(instance, event):
    # creation doesn't have a 'transition'
    if not event.transition:
        return

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    workflow = getToolByName(instance, 'portal_workflow')

    if action_id == "attach":
        instance.reindexObject(idxs = ["review_state", ])
        # Don't cascade. Shouldn't be attaching WSs for now (if ever).
        return

    elif action_id == "submit":
        # Don't cascade. Shouldn't be submitting WSs directly for now,
        # except edge cases where all analyses are already submitted,
        # but instance was held back until an analyst was assigned.
        instance.reindexObject(idxs = ["review_state", ])
        can_attach = True
        for a in instance.getAnalyses():
            if workflow.getInfoFor(a, 'review_state') in \
               ('to_be_sampled', 'to_be_preserved', 'sample_due',
                'sample_received', 'attachment_due', 'assigned',):
                # Note: referenceanalyses and duplicateanalyses can still have review_state = "assigned".
                can_attach = False
                break
        if can_attach:
            doActionFor(instance, 'attach')

    elif action_id == "retract":
        instance.reindexObject(idxs = ["review_state", ])
        if not "retract all analyses" in instance.REQUEST['workflow_skiplist']:
            # retract all analyses in this instance.
            # (NB: don't retract if it's verified)
            analyses = instance.getAnalyses()
            for analysis in analyses:
                if workflow.getInfoFor(analysis, 'review_state', '') not in ('attachment_due', 'to_be_verified',):
                    continue
                doActionFor(analysis, 'retract')

    elif action_id == "verify":
        instance.reindexObject(idxs = ["review_state", ])

        if not "verify all analyses" in instance.REQUEST['workflow_skiplist']:
            # verify all analyses in this instance.
            analyses = instance.getSortedAnalyses()
            for analysis in analyses:
                if workflow.getInfoFor(analysis, 'review_state', '') != 'to_be_verified':
                    continue

                doActionFor(analysis, "verify")
            if "verify all analyses" in instance.REQUEST['workflow_skiplist']:
                instance.REQUEST['workflow_skiplist'].remove("verify all analyses")

    return
Ejemplo n.º 8
0
def AfterTransitionEventHandler(instance, event):

    # creation doesn't have a 'transition'
    if not event.transition:
        return

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    workflow = getToolByName(instance, 'portal_workflow')
    membership_tool = getToolByName(instance, 'portal_membership')
    member = membership_tool.getAuthenticatedMember()
    sample = instance.aq_parent
    sample_state = workflow.getInfoFor(sample, 'review_state')

    if action_id == "sample":
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        for analysis in analyses:
            doActionFor(analysis, action_id)
        # if all our siblings are now up to date, promote sample and ARs.
        parts = sample.objectValues("SamplePartition")
        if parts:
            lower_states = ['to_be_sampled',]
            escalate = True
            for part in parts:
                pstate = workflow.getInfoFor(part, 'review_state')
                if pstate in lower_states:
                    escalate = False
            if escalate:
                doActionFor(sample, action_id)
                for ar in sample.getAnalysisRequests():
                    doActionFor(ar, action_id)

    elif action_id == "to_be_preserved":
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        for analysis in analyses:
            doActionFor(analysis, action_id)
        # if all our siblings are now up to date, promote sample and ARs.
        parts = sample.objectValues("SamplePartition")
        if parts:
            lower_states = ['to_be_sampled', 'to_be_preserved',]
            escalate = True
            for part in parts:
                if workflow.getInfoFor(part, 'review_state') in lower_states:
                    escalate = False
            if escalate:
                doActionFor(sample, action_id)
                for ar in sample.getAnalysisRequests():
                    doActionFor(ar, action_id)

    elif action_id == "sample_due":
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        for analysis in analyses:
            doActionFor(analysis, action_id)
        # if all our siblings are now up to date, promote sample and ARs.
        parts = sample.objectValues("SamplePartition")
        if parts:
            lower_states = ['to_be_preserved',]
            escalate = True
            for part in parts:
                pstate =  workflow.getInfoFor(part, 'review_state')
                if pstate in lower_states:
                    escalate = False
            if escalate:
                doActionFor(sample, action_id)
                for ar in sample.getAnalysisRequests():
                    doActionFor(ar, action_id)

    elif action_id == "preserve":
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        if analyses:
            for analysis in analyses:
                doActionFor(analysis, action_id)
        # if all our siblings are now up to date, promote sample and ARs.
        parts = sample.objectValues("SamplePartition")
        if parts:
            lower_states = ['to_be_sampled', 'to_be_preserved', ]
            escalate = True
            for part in parts:
                if workflow.getInfoFor(part, 'review_state') in lower_states:
                    escalate = False
            if escalate:
                doActionFor(sample, action_id)
                for ar in sample.getAnalysisRequests():
                    doActionFor(ar, action_id)

    elif action_id == "receive":
        if sample.getSamplingDate() > DateTime():
            raise WorkflowException
        instance.setDateReceived(DateTime())
        instance.reindexObject(idxs = ["getDateReceived", ])
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        for analysis in analyses:
            doActionFor(analysis, action_id)
        # if all sibling partitions are received, promote sample
        if not skip(sample, action_id, peek=True):
            due = [sp for sp in sample.objectValues("SamplePartition")
                   if workflow.getInfoFor(sp, 'review_state') == 'sample_due']
            if sample_state == 'sample_due' and not due:
                doActionFor(sample, 'receive')

    elif action_id == "expire":
        instance.setDateExpired(DateTime())
        instance.reindexObject(idxs = ["review_state", "getDateExpired", ])

    #---------------------
    # Secondary workflows:
    #---------------------

    elif action_id == "reinstate":
        instance.reindexObject(idxs = ["cancellation_state", ])
        sample_c_state = workflow.getInfoFor(sample, 'cancellation_state')

        # if all sibling partitions are active, activate sample
        if not skip(sample, action_id, peek=True):
            cancelled = [sp for sp in sample.objectValues("SamplePartition")
                         if workflow.getInfoFor(sp, 'cancellation_state') == 'cancelled']
            if sample_c_state == 'cancelled' and not cancelled:
                workflow.doActionFor(sample, 'reinstate')

    elif action_id == "cancel":
        instance.reindexObject(idxs = ["cancellation_state", ])
        sample_c_state = workflow.getInfoFor(sample, 'cancellation_state')

        # if all sibling partitions are cancelled, cancel sample
        if not skip(sample, action_id, peek=True):
            active = [sp for sp in sample.objectValues("SamplePartition")
                      if workflow.getInfoFor(sp, 'cancellation_state') == 'active']
            if sample_c_state == 'active' and not active:
                workflow.doActionFor(sample, 'cancel')

    return
Ejemplo n.º 9
0
    def retractInvalidAnalyses(self):
        """ Retract the analyses with validation pending status for which
            the instrument used failed a QC Test.
        """
        toretract = {}
        instruments = {}
        refs = []
        rc = getToolByName(self.context, REFERENCE_CATALOG)
        selected = WorkflowAction._get_selected_items(self)
        for uid in selected.iterkeys():
            # We need to do this instead of using the dict values
            # directly because all these analyses have been saved before
            # and don't know if they already had an instrument assigned
            an = rc.lookupObject(uid)
            if an.portal_type == 'ReferenceAnalysis':
                refs.append(an)
                instrument = an.getInstrument()
                if instrument and instrument.UID() not in instruments:
                    instruments[instrument.UID()] = instrument

        for instr in instruments.itervalues():
            analyses = instr.getAnalysesToRetract()
            for a in analyses:
                if a.UID() not in toretract:
                    toretract[a.UID] = a

        retracted = []
        for analysis in toretract.itervalues():
            try:
                # add a remark to this analysis
                failedtxt = ulocalized_time(DateTime(), long_format=0)
                failedtxt = '%s: %s' % (failedtxt, _("Instrument failed reference test"))
                analysis.setRemarks(failedtxt)

                # retract the analysis
                doActionFor(analysis, 'retract')
                retracted.append(analysis)
            except:
                # Already retracted as a dependant from a previous one?
                pass

        if len(retracted) > 0:
            # Create the Retracted Analyses List
            rep = AnalysesRetractedListReport(self.context,
                                               self.request,
                                               self.portal_url,
                                               'Retracted analyses',
                                               retracted)

            # Attach the pdf to the ReferenceAnalysis (accessible
            # from Instrument's Internal Calibration Tests list
            pdf = rep.toPdf()
            for ref in refs:
                ref.setRetractedAnalysesPdfReport(pdf)

            # Send the email
            try:
                rep.sendEmail()
            except:
                pass

            # TODO: mostra una finestra amb els resultats publicats d'AS
            # que han utilitzat l'instrument des de la seva última
            # calibració vàlida, amb els emails, telèfons dels
            # contactes associats per a una intervenció manual
            pass
Ejemplo n.º 10
0
    def submit(self):
        """ Saves the form
        """

        form = self.request.form
        remarks = form.get('Remarks', [{}])[0]
        results = form.get('Result',[{}])[0]
        retested = form.get('retested', {})
        methods = form.get('Method', [{}])[0]
        instruments = form.get('Instrument', [{}])[0]
        analysts = self.request.form.get('Analyst', [{}])[0]
        uncertainties = self.request.form.get('Uncertainty', [{}])[0]
        dlimits = self.request.form.get('DetectionLimit', [{}])[0]
        selected = WorkflowAction._get_selected_items(self)
        workflow = getToolByName(self.context, 'portal_workflow')
        rc = getToolByName(self.context, REFERENCE_CATALOG)
        sm = getSecurityManager()

        hasInterims = {}
        # XXX combine data from multiple bika listing tables.
        item_data = {}
        if 'item_data' in form:
            if type(form['item_data']) == list:
                for i_d in form['item_data']:
                    for i, d in json.loads(i_d).items():
                        item_data[i] = d
            else:
                item_data = json.loads(form['item_data'])

        # Iterate for each selected analysis and save its data as needed
        for uid, analysis in selected.items():

            allow_edit = sm.checkPermission(EditResults, analysis)
            analysis_active = isActive(analysis)

            # Need to save remarks?
            if uid in remarks and allow_edit and analysis_active:
                analysis.setRemarks(remarks[uid])

            # Retested?
            if uid in retested and allow_edit and analysis_active:
                analysis.setRetested(retested[uid])

            # Need to save the instrument?
            if uid in instruments and analysis_active:
                # TODO: Add SetAnalysisInstrument permission
                # allow_setinstrument = sm.checkPermission(SetAnalysisInstrument)
                allow_setinstrument = True
                # ---8<-----
                if allow_setinstrument == True:
                    # The current analysis allows the instrument regards
                    # to its analysis service and method?
                    if (instruments[uid]==''):
                        previnstr = analysis.getInstrument()
                        if previnstr:
                            previnstr.removeAnalysis(analysis)
                        analysis.setInstrument(None);
                    elif analysis.isInstrumentAllowed(instruments[uid]):
                        previnstr = analysis.getInstrument()
                        if previnstr:
                            previnstr.removeAnalysis(analysis)
                        analysis.setInstrument(instruments[uid])
                        instrument = analysis.getInstrument()
                        instrument.addAnalysis(analysis)
                        if analysis.meta_type == 'ReferenceAnalysis':
                            instrument.setDisposeUntilNextCalibrationTest(False)

            # Need to save the method?
            if uid in methods and analysis_active:
                # TODO: Add SetAnalysisMethod permission
                # allow_setmethod = sm.checkPermission(SetAnalysisMethod)
                allow_setmethod = True
                # ---8<-----
                if allow_setmethod == True and analysis.isMethodAllowed(methods[uid]):
                    analysis.setMethod(methods[uid])

            # Need to save the analyst?
            if uid in analysts and analysis_active:
                analysis.setAnalyst(analysts[uid]);

            # Need to save the uncertainty?
            if uid in uncertainties and analysis_active:
                analysis.setUncertainty(uncertainties[uid])

            # Need to save the detection limit?
            if analysis_active and uid in dlimits and dlimits[uid]:
                analysis.setDetectionLimitOperand(dlimits[uid])

            # Need to save results?
            if uid in results and results[uid] and allow_edit \
                and analysis_active:
                interims = item_data.get(uid, [])
                analysis.setInterimFields(interims)
                analysis.setResult(results[uid])
                analysis.reindexObject()

                can_submit = True
                deps = analysis.getDependencies() \
                        if hasattr(analysis, 'getDependencies') else []
                for dependency in deps:
                    if workflow.getInfoFor(dependency, 'review_state') in \
                       ('to_be_sampled', 'to_be_preserved',
                        'sample_due', 'sample_received'):
                        can_submit = False
                        break
                if can_submit:
                    # doActionFor transitions the analysis to verif pending,
                    # so must only be done when results are submitted.
                    doActionFor(analysis, 'submit')

        # Maybe some analyses need to be retracted due to a QC failure
        # Done here because don't know if the last selected analysis is
        # a valid QC for the instrument used in previous analyses.
        # If we add this logic in subscribers.analyses, there's the
        # possibility to retract analyses before the QC being reached.
        self.retractInvalidAnalyses()

        message = PMF("Changes saved.")
        self.context.plone_utils.addPortalMessage(message, 'info')
        self.destination_url = self.request.get_header("referer",
                               self.context.absolute_url())
        self.request.response.redirect(self.destination_url)
Ejemplo n.º 11
0
def AfterTransitionEventHandler(instance, event):

    # creation doesn't have a 'transition'
    if not event.transition:
        return

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    workflow = getToolByName(instance, "portal_workflow")
    membership_tool = getToolByName(instance, "portal_membership")
    member = membership_tool.getAuthenticatedMember()
    parts = instance.objectValues("SamplePartition")

    if action_id == "sample":
        # This action can happen in the Sample UI.  So we transition all
        # instance partitions that are still 'to_be_sampled'
        tbs = [sp for sp in parts if workflow.getInfoFor(sp, "review_state") == "to_be_sampled"]
        for sp in tbs:
            doActionFor(sp, action_id)
        # All associated AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, action_id)
            ar.reindexObject()

    elif action_id == "to_be_preserved":
        # Transition our children
        tbs = [sp for sp in parts if workflow.getInfoFor(sp, "review_state") == "to_be_preserved"]
        for sp in tbs:
            doActionFor(sp, action_id)
        # All associated AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, action_id)
            ar.reindexObject()

    elif action_id == "sample_due":
        # All associated AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, action_id)
            ar.reindexObject()

    elif action_id == "preserve":
        # This action can happen in the Sample UI.  So we transition all
        # instance partitions that are still 'to_be_preserved'
        tbs = [sp for sp in parts if workflow.getInfoFor(sp, "review_state") == "to_be_preserved"]
        for sp in tbs:
            doActionFor(sp, action_id)
        # All associated AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, action_id)
            ar.reindexObject()

    elif action_id == "receive":

        instance.setDateReceived(DateTime())
        instance.reindexObject(idxs=["review_state", "getDateReceived"])

        # Receive all instance partitions that are still 'sample_due'
        sample_due = [sp for sp in parts if workflow.getInfoFor(sp, "review_state") == "sample_due"]
        for sp in sample_due:
            workflow.doActionFor(sp, "receive")

        # when a instance is received, all associated
        # AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, "receive")

    elif action_id == "expire":
        instance.setDateExpired(DateTime())
        instance.reindexObject(idxs=["review_state", "getDateExpired"])

    # ---------------------
    # Secondary workflows:
    # ---------------------

    elif action_id == "reinstate":
        instance.reindexObject(idxs=["cancellation_state"])

        # Re-instate all instance partitions
        for sp in [sp for sp in parts if workflow.getInfoFor(sp, "cancellation_state") == "cancelled"]:
            workflow.doActionFor(sp, "reinstate")

        # reinstate all ARs for this instance.
        ars = instance.getAnalysisRequests()
        for ar in ars:
            if not skip(ar, action_id, peek=True):
                ar_state = workflow.getInfoFor(ar, "cancellation_state")
                if ar_state == "cancelled":
                    workflow.doActionFor(ar, "reinstate")

    elif action_id == "cancel":
        instance.reindexObject(idxs=["cancellation_state"])

        # Cancel all partitions
        for sp in [sp for sp in parts if workflow.getInfoFor(sp, "cancellation_state") == "active"]:
            workflow.doActionFor(sp, "cancel")

        # cancel all ARs for this instance.
        ars = instance.getAnalysisRequests()
        for ar in ars:
            if not skip(ar, action_id, peek=True):
                ar_state = workflow.getInfoFor(ar, "cancellation_state")
                if ar_state == "active":
                    workflow.doActionFor(ar, "cancel")

    return
Ejemplo n.º 12
0
def AfterTransitionEventHandler(instance, event):

    # creation doesn't have a 'transition'
    if not event.transition:
        return

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    workflow = getToolByName(instance, 'portal_workflow')

    if action_id == "attach":
        instance.reindexObject(idxs = ["review_state", ])
        # Don't cascade. Shouldn't be attaching ARs for now (if ever).
        return

    elif action_id == "sampled":
        # transition our sample
        sample = instance.getSample()
        if not skip(sample, action_id, peek=True):
            workflow.doActionFor(sample, action_id)

    elif action_id == "to_be_preserved":
        pass

    elif action_id == "sample_due":
        pass

    elif action_id == "preserved":
        # transition our sample
        sample = instance.getSample()
        if not skip(sample, action_id, peek=True):
            workflow.doActionFor(sample, action_id)

    elif action_id == "receive":
        instance.setDateReceived(DateTime())
        instance.reindexObject(idxs = ["review_state", "getDateReceived", ])

        # receive the AR's sample
        sample = instance.getSample()
        if not skip(sample, action_id, peek=True):
            # unless this is a secondary AR
            if workflow.getInfoFor(sample, 'review_state') == 'sample_due':
                workflow.doActionFor(sample, 'receive')

        # receive all analyses in this AR.
        analyses = instance.getAnalyses(review_state = 'sample_due')
        for analysis in analyses:
            if not skip(analysis, action_id):
                workflow.doActionFor(analysis.getObject(), 'receive')

    elif action_id == "submit":
        instance.reindexObject(idxs = ["review_state", ])
        # Don't cascade. Shouldn't be submitting ARs directly for now.

    elif action_id == "retract":
        instance.reindexObject(idxs = ["review_state", ])
        if not "retract all analyses" in instance.REQUEST['workflow_skiplist']:
            # retract all analyses in this AR.
            # (NB: don't retract if it's verified)
            analyses = instance.getAnalyses(review_state = ('attachment_due', 'to_be_verified',))
            for analysis in analyses:
                doActionFor(analysis.getObject(), 'retract')

    elif action_id == "verify":
        instance.reindexObject(idxs = ["review_state", ])
        if not "verify all analyses" in instance.REQUEST['workflow_skiplist']:
            # verify all analyses in this AR.
            analyses = instance.getAnalyses(review_state = 'to_be_verified')
            for analysis in analyses:
                doActionFor(analysis.getObject(), "verify")

    elif action_id == "publish":
        instance.reindexObject(idxs = ["review_state", "getDatePublished", ])
        if not "publish all analyses" in instance.REQUEST['workflow_skiplist']:
            # publish all analyses in this AR. (except not requested ones)
            analyses = instance.getAnalyses(review_state = 'verified')
            for analysis in analyses:
                doActionFor(analysis.getObject(), "publish")

    #---------------------
    # Secondary workflows:
    #---------------------

    elif action_id == "reinstate":
        instance.reindexObject(idxs = ["cancellation_state", ])
        # activate all analyses in this AR.
        analyses = instance.getAnalyses(cancellation_state = 'cancelled')
        for analysis in analyses:
            doActionFor(analysis.getObject(), 'reinstate')

    elif action_id == "cancel":
        instance.reindexObject(idxs = ["cancellation_state", ])
        # deactivate all analyses in this AR.
        analyses = instance.getAnalyses(cancellation_state = 'active')
        for analysis in analyses:
            doActionFor(analysis.getObject(), 'cancel')

    return
Ejemplo n.º 13
0
def AfterTransitionEventHandler(instance, event):

    # creation doesn't have a 'transition'
    if not event.transition:
        return

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    workflow = getToolByName(instance, 'portal_workflow')
    membership_tool = getToolByName(instance, 'portal_membership')
    member = membership_tool.getAuthenticatedMember()
    parts = instance.objectValues('SamplePartition')

    if action_id == "sample":
        # This action can happen in the Sample UI.  So we transition all
        # instance partitions that are still 'to_be_sampled'
        tbs = [
            sp for sp in parts
            if workflow.getInfoFor(sp, 'review_state') == 'to_be_sampled'
        ]
        for sp in tbs:
            doActionFor(sp, action_id)
        # All associated AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, action_id)
            ar.reindexObject()

    elif action_id == "to_be_preserved":
        # Transition our children
        tbs = [
            sp for sp in parts
            if workflow.getInfoFor(sp, 'review_state') == 'to_be_preserved'
        ]
        for sp in tbs:
            doActionFor(sp, action_id)
        # All associated AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, action_id)
            ar.reindexObject()

    elif action_id == "sample_due":
        # All associated AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, action_id)
            ar.reindexObject()

    elif action_id == "preserve":
        # This action can happen in the Sample UI.  So we transition all
        # instance partitions that are still 'to_be_preserved'
        tbs = [
            sp for sp in parts
            if workflow.getInfoFor(sp, 'review_state') == 'to_be_preserved'
        ]
        for sp in tbs:
            doActionFor(sp, action_id)
        # All associated AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, action_id)
            ar.reindexObject()

    elif action_id == "receive":

        instance.setDateReceived(DateTime())
        instance.reindexObject(idxs=["review_state", "getDateReceived"])

        # Receive all instance partitions that are still 'sample_due'
        sample_due = [
            sp for sp in parts
            if workflow.getInfoFor(sp, 'review_state') == 'sample_due'
        ]
        for sp in sample_due:
            workflow.doActionFor(sp, 'receive')

        # when a instance is received, all associated
        # AnalysisRequests are also transitioned
        for ar in instance.getAnalysisRequests():
            doActionFor(ar, "receive")

    elif action_id == "expire":
        instance.setDateExpired(DateTime())
        instance.reindexObject(idxs=[
            "review_state",
            "getDateExpired",
        ])

    #---------------------
    # Secondary workflows:
    #---------------------

    elif action_id == "reinstate":
        instance.reindexObject(idxs=[
            "cancellation_state",
        ])

        # Re-instate all instance partitions
        for sp in [
                sp for sp in parts
                if workflow.getInfoFor(sp, 'cancellation_state') == 'cancelled'
        ]:
            workflow.doActionFor(sp, 'reinstate')

        # reinstate all ARs for this instance.
        ars = instance.getAnalysisRequests()
        for ar in ars:
            if not skip(ar, action_id, peek=True):
                ar_state = workflow.getInfoFor(ar, 'cancellation_state')
                if ar_state == 'cancelled':
                    workflow.doActionFor(ar, 'reinstate')

    elif action_id == "cancel":
        instance.reindexObject(idxs=[
            "cancellation_state",
        ])

        # Cancel all partitions
        for sp in [
                sp for sp in parts
                if workflow.getInfoFor(sp, 'cancellation_state') == 'active'
        ]:
            workflow.doActionFor(sp, 'cancel')

        # cancel all ARs for this instance.
        ars = instance.getAnalysisRequests()
        for ar in ars:
            if not skip(ar, action_id, peek=True):
                ar_state = workflow.getInfoFor(ar, 'cancellation_state')
                if ar_state == 'active':
                    workflow.doActionFor(ar, 'cancel')

    return
Ejemplo n.º 14
0
def AfterTransitionEventHandler(instance, event):

    # creation doesn't have a 'transition'
    if not event.transition:
        return

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    workflow = getToolByName(instance, 'portal_workflow')

    if action_id == "attach":
        instance.reindexObject(idxs=[
            "review_state",
        ])
        # Don't cascade. Shouldn't be attaching ARs for now (if ever).
        return

    elif action_id == "sample":
        # transition our sample
        sample = instance.getSample()
        if not skip(sample, action_id, peek=True):
            workflow.doActionFor(sample, action_id)

    elif action_id == "to_be_preserved":
        pass

    elif action_id == "sample_due":
        pass

    elif action_id == "preserve":
        # transition our sample
        sample = instance.getSample()
        if not skip(sample, action_id, peek=True):
            workflow.doActionFor(sample, action_id)

    elif action_id == "receive":
        instance.setDateReceived(DateTime())
        instance.reindexObject(idxs=[
            "review_state",
            "getDateReceived",
        ])

        # receive the AR's sample
        sample = instance.getSample()
        if not skip(sample, action_id, peek=True):
            # unless this is a secondary AR
            if workflow.getInfoFor(sample, 'review_state') == 'sample_due':
                workflow.doActionFor(sample, 'receive')

        # receive all analyses in this AR.
        analyses = instance.getAnalyses(review_state='sample_due')
        for analysis in analyses:
            if not skip(analysis, action_id):
                workflow.doActionFor(analysis.getObject(), 'receive')

        # Possibly receive the AR's batch
        batch = instance.getBatch()
        if batch:
            try:
                workflow.doActionFor(batch, action_id)
            except:
                pass

    elif action_id == "submit":
        instance.reindexObject(idxs=[
            "review_state",
        ])

        # Possibly submit the AR's batch
        batch = instance.getBatch()
        if batch:
            try:
                workflow.doActionFor(batch, action_id)
            except:
                pass

    elif action_id == "retract":
        instance.reindexObject(idxs=[
            "review_state",
        ])
        if not "retract all analyses" in instance.REQUEST['workflow_skiplist']:
            # retract all analyses in this AR.
            # (NB: don't retract if it's verified)
            analyses = instance.getAnalyses(review_state=(
                'attachment_due',
                'to_be_verified',
            ))
            for analysis in analyses:
                doActionFor(analysis.getObject(), 'retract')

    elif action_id == "verify":
        instance.reindexObject(idxs=[
            "review_state",
        ])
        if not "verify all analyses" in instance.REQUEST['workflow_skiplist']:
            # verify all analyses in this AR.
            analyses = instance.getAnalyses(review_state='to_be_verified')
            for analysis in analyses:
                doActionFor(analysis.getObject(), "verify")

        # Possibly verify the AR's batch
        batch = instance.getBatch()
        if batch:
            try:
                workflow.doActionFor(batch, action_id)
            except:
                pass

    elif action_id == "publish":
        instance.reindexObject(idxs=[
            "review_state",
            "getDatePublished",
        ])
        if not "publish all analyses" in instance.REQUEST['workflow_skiplist']:
            # publish all analyses in this AR. (except not requested ones)
            analyses = instance.getAnalyses(review_state='verified')
            for analysis in analyses:
                doActionFor(analysis.getObject(), "publish")

    #---------------------
    # Secondary workflows:
    #---------------------

    elif action_id == "reinstate":
        instance.reindexObject(idxs=[
            "cancellation_state",
        ])
        # activate all analyses in this AR.
        analyses = instance.getAnalyses(cancellation_state='cancelled')
        for analysis in analyses:
            doActionFor(analysis.getObject(), 'reinstate')

    elif action_id == "cancel":
        instance.reindexObject(idxs=[
            "cancellation_state",
        ])
        # deactivate all analyses in this AR.
        analyses = instance.getAnalyses(cancellation_state='active')
        for analysis in analyses:
            doActionFor(analysis.getObject(), 'cancel')

    return
Ejemplo n.º 15
0
def AfterTransitionEventHandler(instance, event):

    # DuplicateAnalysis doesn't have analysis_workflow.
    if instance.portal_type == "DuplicateAnalysis":
        return

    # creation doesn't have a 'transition'
    if not event.transition:
        return

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    service = instance.getService()
    wf = getToolByName(instance, 'portal_workflow')
    ar = instance.aq_parent
    part = instance.getSamplePartition()

    if action_id == "attach":
        instance.reindexObject(idxs = ["review_state", ])
        # Dependencies are already at least 'to_be_verified', ignore them.
        #----------------------------------------------------------------
        # Check our dependents:
        # If    it is 'attachment_due'
        # And   it's attachments are OK
        # And   all it's dependencies are at least 'to_be_verified'
        # Then: 'attach' it.:
        dependents = instance.getDependents()
        for dependent in dependents:
            if not skip(dependent, 'attach', peek=True):
                can_attach = True
                if wf.getInfoFor(dependent, 'review_state') != 'attachment_due':
                    can_attach = False
                else:
                    if not dependent.getAttachment():
                        service = dependent.getService()
                        if service.getAttachmentOption() == 'r':
                            can_attach = False
                if can_attach:
                    dependencies = dependent.getDependencies()
                    for dependency in dependencies:
                        if wf.getInfoFor(dependency, 'review_state') in \
                           ('to_be_sampled', 'to_be_preserved', 'sample_due',
                            'sample_received', 'attachment_due',):
                            can_attach = False
                            break
                if can_attach:
                    doActionFor(dependent, 'attach')

        # If all analyses in this AR have been attached
        # escalate the action to the parent AR
        ar_state = wf.getInfoFor(ar, 'review_state')
        if ar_state == 'attachment_due' and not skip(ar, 'attach', peek=True):
            can_attach = True
            for a in ar.getAnalyses():
                if a.review_state in \
                   ('to_be_sampled', 'to_be_preserved',
                    'sample_due', 'sample_received', 'attachment_due',):
                    can_attach = False
                    break
            if can_attach:
                wf.doActionFor(ar, 'attach')

        # If assigned to a worksheet and all analyses on the worksheet have been attached,
        # then attach the worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        if ws:
            ws = ws[0]
            ws_state = wf.getInfoFor(ws, 'review_state')
            if ws_state == 'attachment_due' and not skip(ws, action_id, peek=True):
                can_attach = True
                for a in ws.getAnalyses():
                    if wf.getInfoFor(a, 'review_state') in \
                       ('to_be_sampled', 'to_be_preserved', 'sample_due',
                        'sample_received', 'attachment_due', 'assigned',):
                        # Note: referenceanalyses and duplicateanalyses can still have review_state = "assigned".
                        can_attach = False
                        break
                if can_attach:
                    wf.doActionFor(ws, 'attach')

        return

    #------------------------------------------------------
    # End of "attach" code, back to your basic nightmare...
    #------------------------------------------------------


    elif action_id == "receive":
        instance.updateDueDate()
        instance.reindexObject()

    elif action_id == "submit":
        instance.reindexObject(idxs = ["review_state", ])
        # Dependencies are submitted already, ignore them.
        #-------------------------------------------------
        # Submit our dependents
        # Need to check for result and status of dependencies first
        dependents = instance.getDependents()
        for dependent in dependents:
            if not skip(dependent, action_id, peek=True):
                can_submit = True
                if not dependent.getResult():
                    can_submit = False
                else:
                    interim_fields = False
                    service = dependent.getService()
                    calculation = service.getCalculation()
                    if calculation:
                        interim_fields = calculation.getInterimFields()
                    if interim_fields:
                        can_submit = False
                if can_submit:
                    dependencies = dependent.getDependencies()
                    for dependency in dependencies:
                        if wf.getInfoFor(dependency, 'review_state') in \
                           ('to_be_sampled', 'to_be_preserved',
                            'sample_due', 'sample_received',):
                            can_submit = False
                if can_submit:
                    wf.doActionFor(dependent, 'submit')

        # If all analyses in this AR have been submitted
        # escalate the action to the parent AR
        if not skip(ar, action_id, peek=True):
            all_submitted = True
            for a in ar.getAnalyses():
                if a.review_state in \
                   ('to_be_sampled', 'to_be_preserved',
                    'sample_due', 'sample_received',):
                    all_submitted = False
                    break
            if all_submitted:
                wf.doActionFor(ar, 'submit')

        # If assigned to a worksheet and all analyses on the worksheet have been submitted,
        # then submit the worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        if ws:
            ws = ws[0]
            # if the worksheet analyst is not assigned, the worksheet can't  be transitioned.
            if ws.getAnalyst() and not skip(ws, action_id, peek=True):
                all_submitted = True
                for a in ws.getAnalyses():
                    if wf.getInfoFor(a, 'review_state') in \
                       ('to_be_sampled', 'to_be_preserved',
                        'sample_due', 'sample_received', 'assigned',):
                        # Note: referenceanalyses and duplicateanalyses can still have review_state = "assigned".
                        all_submitted = False
                        break
                if all_submitted:
                    wf.doActionFor(ws, 'submit')

        # If no problem with attachments, do 'attach' action for this instance.
        can_attach = True
        if not instance.getAttachment():
            service = instance.getService()
            if service.getAttachmentOption() == 'r':
                can_attach = False
        if can_attach:
            dependencies = instance.getDependencies()
            for dependency in dependencies:
                if wf.getInfoFor(dependency, 'review_state') in \
                   ('to_be_sampled', 'to_be_preserved', 'sample_due',
                    'sample_received', 'attachment_due',):
                    can_attach = False
        if can_attach:
            wf.doActionFor(instance, 'attach')

    elif action_id == "retract":
        instance.reindexObject(idxs = ["review_state", ])
        # retract our dependencies
        if not "retract all dependencies" in instance.REQUEST['workflow_skiplist']:
            for dependency in instance.getDependencies():
                if not skip(dependency, action_id, peek=True):
                    if wf.getInfoFor(dependency, 'review_state') in ('attachment_due', 'to_be_verified',):
                        # (NB: don't retract if it's verified)
                        wf.doActionFor(dependency, 'retract')
        # Retract our dependents
        for dep in instance.getDependents():
            if not skip(dep, action_id, peek=True):
                if wf.getInfoFor(dep, 'review_state') != 'sample_received':
                    instance.REQUEST["workflow_skiplist"].append("retract all dependencies")
                    wf.doActionFor(dep, 'retract')
                    instance.REQUEST["workflow_skiplist"].remove("retract all dependencies")
        # Escalate action to the parent AR
        if not skip(ar, action_id, peek=True):
            if wf.getInfoFor(ar, 'review_state') == 'sample_received':
                skip(ar, action_id)
            else:
                if not "retract all analyses" in instance.REQUEST['workflow_skiplist']:
                    instance.REQUEST["workflow_skiplist"].append("retract all analyses")
                wf.doActionFor(ar, 'retract')
        # Escalate action to the Worksheet (if it's on one).
        ws = instance.getBackReferences('WorksheetAnalysis')
        if ws:
            ws = ws[0]
            if not skip(ws, action_id, peek=True):
                if wf.getInfoFor(ws, 'review_state') == 'open':
                    skip(ws, 'retract')
                else:
                    if not "retract all analyses" in instance.REQUEST['workflow_skiplist']:
                        instance.REQUEST["workflow_skiplist"].append("retract all analyses")
                    wf.doActionFor(ws, 'retract')

    elif action_id == "verify":
        instance.reindexObject(idxs = ["review_state", ])

        # Don't verify our dependencies, they're done (or will be done by AR).
        #---------------------------------------------------------------------
        # Check for dependents, ensure all their dependencies
        # have been verified, and submit/verify them
        for dependent in instance.getDependents():
            if not skip(dependent, action_id, peek=True):
                if dependent.getResult():
                    review_state = wf.getInfoFor(dependent, 'review_state')
                    interim_fields = False
                    service = dependent.getService()
                    calculation = service.getCalculation()
                    if calculation:
                        interim_fields = calculation.getInterimFields()
                    dependencies = dependent.getDependencies()
                    if interim_fields:
                        if review_state == 'sample_received':
                            can_submit = True
                            for dependency in dependencies:
                                if wf.getInfoFor(dependency, 'review_state') in \
                                    ('to_be_sampled', 'to_be_preserved',
                                     'sample_due', 'sample_received',
                                     'attachment_due', 'to_be_verified'):
                                    can_submit = False
                                    break
                            if can_submit:
                                wf.doActionFor(dependent, 'submit')
                    else:
                        if review_state == 'to_be_verified':
                            can_verify = True
                            for dependency in dependencies:
                                if wf.getInfoFor(dependency, 'review_state') in \
                                    ('to_be_sampled', 'to_be_preserved',
                                     'sample_due', 'sample_received',
                                     'attachment_due', 'to_be_verified'):
                                    can_verify = False
                                    break
                            if can_verify:
                                wf.doActionFor(dependent, 'verify')

        # If all analyses in this AR are verified
        # escalate the action to the parent AR
        if not skip(ar, action_id, peek=True):
            all_verified = True
            for a in ar.getAnalyses():
                if a.review_state in \
                   ('to_be_sampled', 'to_be_preserved', 'sample_due',
                    'sample_received', 'attachment_due', 'to_be_verified'):
                    all_verified = False
                    break
            if all_verified:
                if not "verify all analyses" in instance.REQUEST['workflow_skiplist']:
                    instance.REQUEST["workflow_skiplist"].append("verify all analyses")
                wf.doActionFor(ar, "verify")

        # If this is on a worksheet and all it's other analyses are verified,
        # then verify the worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        if ws:
            ws = ws[0]
            ws_state = wf.getInfoFor(ws, 'review_state')
            if ws_state == 'to_be_verified' and not skip(ws, action_id, peek=True):
                all_verified = True
                for a in ws.getAnalyses():
                    if wf.getInfoFor(a, 'review_state') in \
                       ('to_be_sampled', 'to_be_preserved', 'sample_due',
                        'sample_received', 'attachment_due', 'to_be_verified',
                        'assigned'):
                        # Note: referenceanalyses and duplicateanalyses can
                        # still have review_state = "assigned".
                        all_verified = False
                        break
                if all_verified:
                    if not "verify all analyses" in instance.REQUEST['workflow_skiplist']:
                        instance.REQUEST["workflow_skiplist"].append("verify all analyses")
                    wf.doActionFor(ws, "verify")

    elif action_id == "publish":
        endtime = DateTime()
        instance.setDateAnalysisPublished(endtime)
        starttime = instance.aq_parent.getDateReceived()
        starttime = starttime or instance.created()
        service = instance.getService()
        maxtime = service.getMaxTimeAllowed()
        # set the instance duration value to default values
        # in case of no calendars or max hours
        if maxtime:
            duration = (endtime - starttime) * 24 * 60
            maxtime_delta = int(maxtime.get('hours', 0)) * 86400
            maxtime_delta += int(maxtime.get('hours', 0)) * 3600
            maxtime_delta += int(maxtime.get('minutes', 0)) * 60
            earliness = duration - maxtime_delta
        else:
            earliness = 0
            duration = 0
        instance.setDuration(duration)
        instance.setEarliness(earliness)
        instance.reindexObject()

    #---------------------
    # Secondary workflows:
    #---------------------

    elif action_id == "cancel":
        instance.reindexObject(idxs = ["worksheetanalysis_review_state", ])
        # If it is assigned to a worksheet, unassign it.
        if wf.getInfoFor(instance, 'worksheetanalysis_review_state') == 'assigned':
            ws = instance.getBackReferences("WorksheetAnalysis")[0]
            skip(instance, action_id, unskip=True)
            ws.removeAnalysis(instance)

    elif action_id == "assign":
        instance.reindexObject(idxs = ["worksheetanalysis_review_state", ])
        rc = getToolByName(instance, REFERENCE_CATALOG)
        wsUID = instance.REQUEST['context_uid']
        ws = rc.lookupObject(wsUID)

        # retract the worksheet to 'open'
        ws_state = wf.getInfoFor(ws, 'review_state')
        if ws_state != 'open':
            if not instance.REQUEST.has_key('workflow_skiplist'):
                instance.REQUEST['workflow_skiplist'] = ['retract all analyses', ]
            else:
                instance.REQUEST["workflow_skiplist"].append('retract all analyses')
            wf.doActionFor(ws, 'retract')

        # If all analyses in this AR have been assigned,
        # escalate the action to the parent AR
        if not skip(ar, action_id, peek=True):
            if not ar.getAnalyses(worksheetanalysis_review_state = 'unassigned'):
                wf.doActionFor(ar, 'assign')

    elif action_id == "unassign":
        instance.reindexObject(idxs = ["worksheetanalysis_review_state", ])
        rc = getToolByName(instance, REFERENCE_CATALOG)
        wsUID = instance.REQUEST['context_uid']
        ws = rc.lookupObject(wsUID)

        # Escalate the action to the parent AR if it is assigned
        # Note: AR adds itself to the skiplist so we have to take it off again
        #       to allow multiple promotions/demotions (maybe by more than one instance).
        if wf.getInfoFor(ar, 'worksheetanalysis_review_state') == 'assigned':
            wf.doActionFor(ar, 'unassign')
            skip(ar, action_id, unskip=True)

        # If it has been duplicated on the worksheet, delete the duplicates.
        dups = instance.getBackReferences("DuplicateAnalysisAnalysis")
        for dup in dups:
            ws.removeAnalysis(dup)

        # May need to promote the Worksheet's review_state
        #  if all other analyses are at a higher state than this one was.
        # (or maybe retract it if there are no analyses left)
        # Note: duplicates, controls and blanks have 'assigned' as a review_state.
        can_submit = True
        can_attach = True
        can_verify = True
        ws_empty = True

        for a in ws.getAnalyses():
            ws_empty = False
            a_state = wf.getInfoFor(a, 'review_state')
            if a_state in \
               ('to_be_sampled', 'to_be_preserved', 'assigned',
                'sample_due', 'sample_received',):
                can_submit = False
            else:
                if not ws.getAnalyst():
                    can_submit = False
            if a_state in \
               ('to_be_sampled', 'to_be_preserved', 'assigned',
                'sample_due', 'sample_received', 'attachment_due',):
                can_attach = False
            if a_state in \
               ('to_be_sampled', 'to_be_preserved', 'assigned', 'sample_due',
                'sample_received', 'attachment_due', 'to_be_verified',):
                can_verify = False

        if not ws_empty:
        # Note: WS adds itself to the skiplist so we have to take it off again
        #       to allow multiple promotions (maybe by more than one instance).
            if can_submit and wf.getInfoFor(ws, 'review_state') == 'open':
                wf.doActionFor(ws, 'submit')
                skip(ws, action_id, unskip=True)
            if can_attach and wf.getInfoFor(ws, 'review_state') == 'attachment_due':
                wf.doActionFor(ws, 'attach')
                skip(ws, action_id, unskip=True)
            if can_verify and wf.getInfoFor(ws, 'review_state') == 'to_be_verified':
                instance.REQUEST["workflow_skiplist"].append('verify all analyses')
                wf.doActionFor(ws, 'verify')
                skip(ws, action_id, unskip=True)
        else:
            if wf.getInfoFor(ws, 'review_state') != 'open':
                wf.doActionFor(ws, 'retract')
                skip(ws, 'retract', unskip=True)

    return
Ejemplo n.º 16
0
def AfterTransitionEventHandler(instance, event):

    # creation doesn't have a 'transition'
    if not event.transition:
        return

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    workflow = getToolByName(instance, 'portal_workflow')

    if action_id == "attach":
        instance.reindexObject(idxs=[
            "review_state",
        ])
        # Don't cascade. Shouldn't be attaching WSs for now (if ever).
        return

    elif action_id == "submit":
        # Don't cascade. Shouldn't be submitting WSs directly for now,
        # except edge cases where all analyses are already submitted,
        # but instance was held back until an analyst was assigned.
        instance.reindexObject(idxs=[
            "review_state",
        ])
        can_attach = True
        for a in instance.getAnalyses():
            if workflow.getInfoFor(a, 'review_state') in \
               ('to_be_sampled', 'to_be_preserved', 'sample_due',
                'sample_received', 'attachment_due', 'assigned',):
                # Note: referenceanalyses and duplicateanalyses can still have review_state = "assigned".
                can_attach = False
                break
        if can_attach:
            doActionFor(instance, 'attach')

    elif action_id == "retract":
        instance.reindexObject(idxs=[
            "review_state",
        ])
        if not "retract all analyses" in instance.REQUEST['workflow_skiplist']:
            # retract all analyses in this instance.
            # (NB: don't retract if it's verified)
            analyses = instance.getAnalyses()
            for analysis in analyses:
                if workflow.getInfoFor(analysis, 'review_state', '') not in (
                        'attachment_due',
                        'to_be_verified',
                ):
                    continue
                doActionFor(analysis, 'retract')

    elif action_id == "verify":
        instance.reindexObject(idxs=[
            "review_state",
        ])
        if not "verify all analyses" in instance.REQUEST['workflow_skiplist']:
            # verify all analyses in this instance.
            analyses = instance.getAnalyses()
            for analysis in analyses:
                if workflow.getInfoFor(analysis, 'review_state',
                                       '') != 'to_be_verified':
                    continue
                doActionFor(analysis, "verify")

    return
Ejemplo n.º 17
0
    def workflow_action_submit(self):
        uids = self.get_selected_uids()
        if not uids:
            message = _('No items selected.')
            self.context.plone_utils.addPortalMessage(message, 'info')
            self.request.response.redirect(self.context.absolute_url())
            return

        if not is_active(self.context):
            message = _('Item is inactive.')
            self.context.plone_utils.addPortalMessage(message, 'info')
            self.request.response.redirect(self.context.absolute_url())
            return

        form = self.request.form
        remarks = form.get('Remarks', [{}])[0]
        results = form.get('Result', [{}])[0]
        retested = form.get('retested', {})
        methods = form.get('Method', [{}])[0]
        instruments = form.get('Instrument', [{}])[0]
        analysts = self.request.form.get('Analyst', [{}])[0]
        uncertainties = self.request.form.get('Uncertainty', [{}])[0]
        dlimits = self.request.form.get('DetectionLimit', [{}])[0]

        # XXX combine data from multiple bika listing tables.
        # TODO: Is this necessary?
        item_data = {}
        if 'item_data' in form:
            if type(form['item_data']) == list:
                for i_d in form['item_data']:
                    for i, d in json.loads(i_d).items():
                        item_data[i] = d
            else:
                item_data = json.loads(form['item_data'])

        # Store affected Analysis Requests
        affected_ars = set()

        # Store affected Worksheets
        affected_ws = set()

        # Store invalid instruments-ref.analyses
        invalid_instrument_refs = dict()

        # We manually query by all analyses uids at once here instead of using
        # _get_selected_items from the base class, cause that function fetches
        # the objects by uid, but sequentially one by one
        query = dict(UID=uids)
        for brain in api.search(query, CATALOG_ANALYSIS_LISTING):
            uid = api.get_uid(brain)
            analysis = api.get_object(brain)

            # If not active, do nothing
            if not is_active(brain):
                continue

            # Need to save remarks?
            if uid in remarks:
                analysis.setRemarks(remarks[uid])

            # Retested?
            if uid in retested:
                analysis.setRetested(retested[uid])

            # Need to save the instrument?
            if uid in instruments:
                instrument = instruments[uid] or None
                analysis.setInstrument(instrument)
                if instrument and IReferenceAnalysis.providedBy(analysis):
                    if is_out_of_range(analysis):
                        # This reference analysis is out of range, so we have
                        # to retract all analyses assigned to this same
                        # instrument that are awaiting for verification
                        if uid not in invalid_instrument_refs:
                            invalid_instrument_refs[uid] = set()
                        invalid_instrument_refs[uid].add(analysis)
                    else:
                        # The reference result is valid, so make the instrument
                        # available again for further analyses
                        instrument.setDisposeUntilNextCalibrationTest(False)

            # Need to save the method?
            if uid in methods:
                method = methods[uid] or None
                analysis.setMethod(method)

            # Need to save the analyst?
            if uid in analysts:
                analysis.setAnalyst(analysts[uid])

            # Need to save the uncertainty?
            if uid in uncertainties:
                analysis.setUncertainty(uncertainties[uid])

            # Need to save the detection limit?
            if uid in dlimits and dlimits[uid]:
                analysis.setDetectionLimitOperand(dlimits[uid])

            # Need to save results?
            submitted = False
            if uid in results and results[uid]:
                interims = item_data.get(uid, [])
                analysis.setInterimFields(interims)
                analysis.setResult(results[uid])

                # Can the analysis be submitted?
                # An analysis can only be submitted if all its dependencies
                # are valid and have been submitted already
                can_submit = True
                invalid_states = [
                    'to_be_sampled', 'to_be_preserved', 'sample_due',
                    'sample_received'
                ]
                for dependency in analysis.getDependencies():
                    if in_state(dependency, invalid_states):
                        can_submit = False
                        break
                if can_submit:
                    # doActionFor transitions the analysis to verif pending,
                    # so must only be done when results are submitted.
                    doActionFor(analysis, 'submit')
                    submitted = True
                    if IRequestAnalysis.providedBy(analysis):
                        # Store the AR uids to be reindexed later.
                        affected_ars.add(brain.getParentUID)

                    if brain.worksheetanalysis_review_state == 'assigned':
                        worksheet_uid = analysis.getWorksheetUID()
                        if worksheet_uid:
                            affected_ws.add(worksheet_uid)

            if not submitted:
                # Analysis has not been submitted, so we need to reindex the
                # object manually, to update catalog's metadata.
                analysis.reindexObject()

        # If a reference analysis with an out-of-range result and instrument
        # assigned has been submitted, retract then routine analyses that are
        # awaiting for verification and with same instrument associated
        retracted = list()
        for invalid_instrument_uid in invalid_instrument_refs.keys():
            query = dict(
                getInstrumentUID=invalid_instrument_uid,
                portal_type=['Analysis', 'DuplicateAnalysis'],
                review_state='to_be_verified',
                cancellation_state='active',
            )
            brains = api.search(query, CATALOG_ANALYSIS_LISTING)
            for brain in brains:
                analysis = api.get_object(brain)
                failed_msg = '{0}: {1}'.format(
                    ulocalized_time(DateTime(), long_format=1),
                    _("Instrument failed reference test"))
                an_remarks = analysis.getRemarks()
                analysis.setRemarks('. '.join([an_remarks, failed_msg]))
                doActionFor(analysis, 'retract')
                retracted.append(analysis)

        # If some analyses have been retracted because instrument failed a
        # reference test, then generate a pdf report
        if retracted:
            # Create the Retracted Analyses List
            report = AnalysesRetractedListReport(self.context, self.request,
                                                 self.portal_url,
                                                 'Retracted analyses',
                                                 retracted)

            # Attach the pdf to all ReferenceAnalysis that failed (accessible
            # from Instrument's Internal Calibration Tests list
            pdf = report.toPdf()
            for ref in invalid_instrument_refs.values():
                ref.setRetractedAnalysesPdfReport(pdf)

            # Send the email
            try:
                report.sendEmail()
            except:
                pass

        # Finally, when we are done processing all applicable analyses, we must
        # attempt to initiate the submit transition on the ARs and Worksheets
        # the processed analyses belong to.
        # We stick only to affected_ars, and affected_ws

        # Reindex the Analysis Requests for which at least one Analysis has
        # been submitted. We do this here because one AR can contain multiple
        # Analyses, so better to just reindex the AR once instead of each time.
        # AR Catalog contains some metadata that that rely on the Analyses an
        # Analysis Request contains.
        if affected_ars:
            query = dict(UID=list(affected_ars), portal_type="AnalysisRequest")
            for ar_brain in api.search(query,
                                       CATALOG_ANALYSIS_REQUEST_LISTING):
                if ar_brain.review_state == 'to_be_verified':
                    continue
                ar = api.get_object(ar_brain)
                if isTransitionAllowed(ar, "submit"):
                    doActionFor(ar, "submit")
                else:
                    ar.reindexObject()

        if affected_ws:
            query = dict(UID=list(affected_ws), portal_type="Worksheet")
            for ws_brain in api.search(query, CATALOG_WORKSHEET_LISTING):
                if ws_brain.review_state == 'to_be_verified':
                    continue
                ws = api.get_object(ws_brain)
                if isTransitionAllowed(ws, "submit"):
                    doActionFor(ws, "submit")

        message = PMF("Changes saved.")
        self.context.plone_utils.addPortalMessage(message, 'info')
        self.destination_url = self.request.get_header(
            "referer", self.context.absolute_url())
        self.request.response.redirect(self.destination_url)
Ejemplo n.º 18
0
    def submit(self):
        """ Saves the form
        """

        form = self.request.form
        remarks = form.get('Remarks', [{}])[0]
        results = form.get('Result', [{}])[0]
        retested = form.get('retested', {})
        methods = form.get('Method', [{}])[0]
        instruments = form.get('Instrument', [{}])[0]
        analysts = self.request.form.get('Analyst', [{}])[0]
        uncertainties = self.request.form.get('Uncertainty', [{}])[0]
        dlimits = self.request.form.get('DetectionLimit', [{}])[0]
        selected = WorkflowAction._get_selected_items(self)
        workflow = getToolByName(self.context, 'portal_workflow')
        rc = getToolByName(self.context, REFERENCE_CATALOG)
        sm = getSecurityManager()

        hasInterims = {}
        # XXX combine data from multiple bika listing tables.
        item_data = {}
        if 'item_data' in form:
            if type(form['item_data']) == list:
                for i_d in form['item_data']:
                    for i, d in json.loads(i_d).items():
                        item_data[i] = d
            else:
                item_data = json.loads(form['item_data'])

        # Iterate for each selected analysis and save its data as needed
        for uid, analysis in selected.items():

            allow_edit = sm.checkPermission(EditResults, analysis)
            analysis_active = isActive(analysis)

            # Need to save remarks?
            if uid in remarks and allow_edit and analysis_active:
                analysis.setRemarks(remarks[uid])

            # Retested?
            if uid in retested and allow_edit and analysis_active:
                analysis.setRetested(retested[uid])

            # Need to save the instrument?
            if uid in instruments and analysis_active:
                # TODO: Add SetAnalysisInstrument permission
                # allow_setinstrument = sm.checkPermission(SetAnalysisInstrument)
                allow_setinstrument = True
                # ---8<-----
                if allow_setinstrument == True:
                    # The current analysis allows the instrument regards
                    # to its analysis service and method?
                    if (instruments[uid] == ''):
                        previnstr = analysis.getInstrument()
                        if previnstr:
                            previnstr.removeAnalysis(analysis)
                        analysis.setInstrument(None)
                    elif analysis.isInstrumentAllowed(instruments[uid]):
                        previnstr = analysis.getInstrument()
                        if previnstr:
                            previnstr.removeAnalysis(analysis)
                        analysis.setInstrument(instruments[uid])
                        instrument = analysis.getInstrument()
                        instrument.addAnalysis(analysis)
                        if analysis.meta_type == 'ReferenceAnalysis':
                            instrument.setDisposeUntilNextCalibrationTest(
                                False)

            # Need to save the method?
            if uid in methods and analysis_active:
                # TODO: Add SetAnalysisMethod permission
                # allow_setmethod = sm.checkPermission(SetAnalysisMethod)
                allow_setmethod = True
                # ---8<-----
                if allow_setmethod == True and analysis.isMethodAllowed(
                        methods[uid]):
                    analysis.setMethod(methods[uid])

            # Need to save the analyst?
            if uid in analysts and analysis_active:
                analysis.setAnalyst(analysts[uid])

            # Need to save the uncertainty?
            if uid in uncertainties and analysis_active:
                analysis.setUncertainty(uncertainties[uid])

            # Need to save the detection limit?
            if analysis_active and uid in dlimits and dlimits[uid]:
                analysis.setDetectionLimitOperand(dlimits[uid])

            # Need to save results?
            if uid in results and results[uid] and allow_edit \
                and analysis_active:
                interims = item_data.get(uid, [])
                analysis.setInterimFields(interims)
                analysis.setResult(results[uid])
                analysis.reindexObject()

                can_submit = True
                deps = analysis.getDependencies() \
                        if hasattr(analysis, 'getDependencies') else []
                for dependency in deps:
                    if workflow.getInfoFor(dependency, 'review_state') in \
                       ('to_be_sampled', 'to_be_preserved',
                        'sample_due', 'sample_received'):
                        can_submit = False
                        break
                if can_submit:
                    # doActionFor transitions the analysis to verif pending,
                    # so must only be done when results are submitted.
                    doActionFor(analysis, 'submit')

        # Maybe some analyses need to be retracted due to a QC failure
        # Done here because don't know if the last selected analysis is
        # a valid QC for the instrument used in previous analyses.
        # If we add this logic in subscribers.analyses, there's the
        # possibility to retract analyses before the QC being reached.
        self.retractInvalidAnalyses()

        message = PMF("Changes saved.")
        self.context.plone_utils.addPortalMessage(message, 'info')
        self.destination_url = self.request.get_header(
            "referer", self.context.absolute_url())
        self.request.response.redirect(self.destination_url)
Ejemplo n.º 19
0
    def retractInvalidAnalyses(self):
        """ Retract the analyses with validation pending status for which
            the instrument used failed a QC Test.
        """
        toretract = {}
        instruments = {}
        refs = []
        rc = getToolByName(self.context, REFERENCE_CATALOG)
        selected = WorkflowAction._get_selected_items(self)
        for uid in selected.iterkeys():
            # We need to do this instead of using the dict values
            # directly because all these analyses have been saved before
            # and don't know if they already had an instrument assigned
            an = rc.lookupObject(uid)
            if an.portal_type == 'ReferenceAnalysis':
                refs.append(an)
                instrument = an.getInstrument()
                if instrument and instrument.UID() not in instruments:
                    instruments[instrument.UID()] = instrument

        for instr in instruments.itervalues():
            analyses = instr.getAnalysesToRetract()
            for a in analyses:
                if a.UID() not in toretract:
                    toretract[a.UID] = a

        retracted = []
        for analysis in toretract.itervalues():
            try:
                # add a remark to this analysis
                failedtxt = ulocalized_time(DateTime(), long_format=0)
                failedtxt = '%s: %s' % (failedtxt,
                                        _("Instrument failed reference test"))
                analysis.setRemarks(failedtxt)

                # retract the analysis
                doActionFor(analysis, 'retract')
                retracted.append(analysis)
            except:
                # Already retracted as a dependant from a previous one?
                pass

        if len(retracted) > 0:
            # Create the Retracted Analyses List
            rep = AnalysesRetractedListReport(self.context, self.request,
                                              self.portal_url,
                                              'Retracted analyses', retracted)

            # Attach the pdf to the ReferenceAnalysis (accessible
            # from Instrument's Internal Calibration Tests list
            pdf = rep.toPdf()
            for ref in refs:
                ref.setRetractedAnalysesPdfReport(pdf)

            # Send the email
            try:
                rep.sendEmail()
            except:
                pass

            # TODO: mostra una finestra amb els resultats publicats d'AS
            # que han utilitzat l'instrument des de la seva última
            # calibració vàlida, amb els emails, telèfons dels
            # contactes associats per a una intervenció manual
            pass
Ejemplo n.º 20
0
def AfterTransitionEventHandler(instance, event):

    # creation doesn't have a 'transition'
    if not event.transition:
        return

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    workflow = getToolByName(instance, 'portal_workflow')
    membership_tool = getToolByName(instance, 'portal_membership')
    member = membership_tool.getAuthenticatedMember()
    sample = instance.aq_parent
    sample_state = workflow.getInfoFor(sample, 'review_state')

    if action_id == "sample":
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        for analysis in analyses:
            doActionFor(analysis, action_id)
        # if all our siblings are now up to date, promote sample and ARs.
        parts = sample.objectValues("SamplePartition")
        if parts:
            lower_states = [
                'to_be_sampled',
            ]
            escalate = True
            for part in parts:
                pstate = workflow.getInfoFor(part, 'review_state')
                if pstate in lower_states:
                    escalate = False
            if escalate:
                doActionFor(sample, action_id)
                for ar in sample.getAnalysisRequests():
                    doActionFor(ar, action_id)

    elif action_id == "to_be_preserved":
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        for analysis in analyses:
            doActionFor(analysis, action_id)
        # if all our siblings are now up to date, promote sample and ARs.
        parts = sample.objectValues("SamplePartition")
        if parts:
            lower_states = [
                'to_be_sampled',
                'to_be_preserved',
            ]
            escalate = True
            for part in parts:
                if workflow.getInfoFor(part, 'review_state') in lower_states:
                    escalate = False
            if escalate:
                doActionFor(sample, action_id)
                for ar in sample.getAnalysisRequests():
                    doActionFor(ar, action_id)

    elif action_id == "sample_due":
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        for analysis in analyses:
            doActionFor(analysis, action_id)
        # if all our siblings are now up to date, promote sample and ARs.
        parts = sample.objectValues("SamplePartition")
        if parts:
            lower_states = [
                'to_be_preserved',
            ]
            escalate = True
            for part in parts:
                pstate = workflow.getInfoFor(part, 'review_state')
                if pstate in lower_states:
                    escalate = False
            if escalate:
                doActionFor(sample, action_id)
                for ar in sample.getAnalysisRequests():
                    doActionFor(ar, action_id)

    elif action_id == "preserve":
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        if analyses:
            for analysis in analyses:
                doActionFor(analysis, action_id)
        # if all our siblings are now up to date, promote sample and ARs.
        parts = sample.objectValues("SamplePartition")
        if parts:
            lower_states = [
                'to_be_sampled',
                'to_be_preserved',
            ]
            escalate = True
            for part in parts:
                if workflow.getInfoFor(part, 'review_state') in lower_states:
                    escalate = False
            if escalate:
                doActionFor(sample, action_id)
                for ar in sample.getAnalysisRequests():
                    doActionFor(ar, action_id)

    elif action_id == "receive":
        if sample.getSamplingDate() > DateTime():
            raise WorkflowException
        instance.setDateReceived(DateTime())
        instance.reindexObject(idxs=[
            "getDateReceived",
        ])
        # Transition our analyses
        analyses = instance.getBackReferences('AnalysisSamplePartition')
        for analysis in analyses:
            doActionFor(analysis, action_id)
        # if all sibling partitions are received, promote sample
        if not skip(sample, action_id, peek=True):
            due = [
                sp for sp in sample.objectValues("SamplePartition")
                if workflow.getInfoFor(sp, 'review_state') == 'sample_due'
            ]
            if sample_state == 'sample_due' and not due:
                doActionFor(sample, 'receive')

    elif action_id == "expire":
        instance.setDateExpired(DateTime())
        instance.reindexObject(idxs=[
            "review_state",
            "getDateExpired",
        ])

    #---------------------
    # Secondary workflows:
    #---------------------

    elif action_id == "reinstate":
        instance.reindexObject(idxs=[
            "cancellation_state",
        ])
        sample_c_state = workflow.getInfoFor(sample, 'cancellation_state')

        # if all sibling partitions are active, activate sample
        if not skip(sample, action_id, peek=True):
            cancelled = [
                sp for sp in sample.objectValues("SamplePartition")
                if workflow.getInfoFor(sp, 'cancellation_state') == 'cancelled'
            ]
            if sample_c_state == 'cancelled' and not cancelled:
                workflow.doActionFor(sample, 'reinstate')

    elif action_id == "cancel":
        instance.reindexObject(idxs=[
            "cancellation_state",
        ])
        sample_c_state = workflow.getInfoFor(sample, 'cancellation_state')

        # if all sibling partitions are cancelled, cancel sample
        if not skip(sample, action_id, peek=True):
            active = [
                sp for sp in sample.objectValues("SamplePartition")
                if workflow.getInfoFor(sp, 'cancellation_state') == 'active'
            ]
            if sample_c_state == 'active' and not active:
                workflow.doActionFor(sample, 'cancel')

    return
Ejemplo n.º 21
0
    def __call__(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(form)
        self.context = aq_inner(self.context)
        workflow = getToolByName(self.context, 'portal_workflow')
        checkPermission = self.context.portal_membership.checkPermission
        context = self.context
        context_url = context.absolute_url()

        # use came_from to decide which UI action was clicked.
        # "workflow_action" is the action name specified in the
        # portal_workflow transition url.
        came_from = "workflow_action"
        action = form.get(came_from, '')
        if not action and not form.get('bika_listing_filter_bar_submit', ''):
            # workflow_action_button is the action name specified in
            # the bika_listing_view table buttons.
            came_from = "workflow_action_button"
            action = form.get('workflow_action_id', '')
            if not action:
                if self.destination_url == "":
                    self.destination_url = self.request.get_header("referer",
                                                                   context_url)
                self.request.response.redirect(self.destination_url)
                return

        if action == "sample":
            objects = AnalysisRequestWorkflowAction._get_selected_items(self)
            transitioned = {'to_be_preserved': [], 'sample_due': []}
            dsfn = 'getDateSampled'
            for obj_uid, obj in objects.items():
                if obj.portal_type == "AnalysisRequest":
                    ar = obj
                    sample = obj.getSample()
                else:
                    # If it is a Sample, then fieldname is DateSampled
                    dsfn = 'DateSampled'
                    sample = obj
                    ar = sample.aq_parent
                # can't transition inactive items
                if workflow.getInfoFor(sample, 'inactive_state', '') == 'inactive':
                    continue

                # grab this object's Sampler and DateSampled from the form
                # (if the columns are available and edit controls exist)
                if 'getSampler' in form:
                    try:
                        Sampler = form['getSampler'][0][obj_uid].strip()
                    except KeyError:
                        continue
                    Sampler = Sampler and Sampler or ''
                    sample.setSampler(Sampler)
                    sample.reindexObject()

                if dsfn in form:
                    try:
                        DateSampled = form[dsfn][0][obj_uid].strip()
                    except KeyError:
                        continue
                    DateSampled = DateSampled and DateTime(DateSampled) or ''
                    sample.setDateSampled(DateSampled)
                    sample.reindexObject()

                # write them to the sample
                if not sample.getSampler():
                    # Make the message more specific if the reason for not
                    # transitioning is that no Sampler has been selected
                    message = _('Sampler is required for the Sampling transition of ${sample}',
                                mapping={'sample': sample.Title()})
                    self.context.plone_utils.addPortalMessage(message, 'info')
                    continue
                if not sample.getDateSampled():
                    continue
                Sampler = sample.getSampler()
                DateSampled = sample.getDateSampled()

                sample.reindexObject()
                ars = sample.getAnalysisRequests()
                # Analyses and AnalysisRequets have calculated fields
                # that are indexed; re-index all these objects.
                for ar in ars:
                    ar.reindexObject()
                    analyses = sample.getAnalyses({'review_state': 'to_be_sampled'})
                    for a in analyses:
                        a.getObject().reindexObject()

                # transition the object if both values are present
                if Sampler and DateSampled:
                    workflow.doActionFor(sample, action)
                    new_state = workflow.getInfoFor(sample, 'review_state')
                    doActionFor(ar, action)
                    transitioned[new_state].append(sample.Title())

            message = None
            for state in transitioned:
                tlist = transitioned[state]
                if len(tlist) > 1:
                    if state == 'to_be_preserved':
                        message = _('${items} are waiting for preservation.',
                                    mapping={'items': ', '.join(tlist)})
                    else:
                        message = _('${items} are waiting to be received.',
                                    mapping={'items': ', '.join(tlist)})
                    self.context.plone_utils.addPortalMessage(message, 'info')
                elif len(tlist) == 1:
                    if state == 'to_be_preserved':
                        message = _('${item} is waiting for preservation.',
                                    mapping={'item': ', '.join(tlist)})
                    else:
                        message = _('${item} is waiting to be received.',
                                    mapping={'item': ', '.join(tlist)})
                    self.context.plone_utils.addPortalMessage(message, 'info')

            if not message:
                message = _('No changes made.')
                self.context.plone_utils.addPortalMessage(message, 'info')
            self.destination_url = self.request.get_header("referer",
                                                           context_url)
            self.request.response.redirect(self.destination_url)

        elif action == "preserve":
            objects = AnalysisRequestWorkflowAction._get_selected_items(self)
            transitioned = {}
            not_transitioned = []
            Preserver = str()
            DatePreserved = str()
            for obj_uid, obj in objects.items():
                if obj.portal_type == "AnalysisRequest":
                    ar = obj
                    sample = obj.getSample()
                else:
                    sample = obj
                    ar = sample.aq_parent
                # can't transition inactive items
                if workflow.getInfoFor(sample, 'inactive_state', '') == 'inactive':
                    continue
                if not checkPermission(PreserveSample, sample):
                    continue

                # grab this object's Preserver and DatePreserved from the form
                # (if the columns are available and edit controls exist)
                if 'getPreserver' in form and 'getDatePreserved' in form:
                    try:
                        Preserver = form['getPreserver'][0][obj_uid].strip()
                        DatePreserved = form['getDatePreserved'][0][obj_uid].strip()
                    except KeyError:
                        continue
                    Preserver = Preserver and Preserver or ''
                    DatePreserved = DatePreserved and DateTime(DatePreserved) or ''
                else:
                    continue

                for sp in sample.objectValues("SamplePartition"):
                    if workflow.getInfoFor(sp, 'review_state') == 'to_be_preserved':
                        sp.setDatePreserved(DatePreserved)
                        sp.setPreserver(Preserver)
                for sp in sample.objectValues("SamplePartition"):
                    if workflow.getInfoFor(sp, 'review_state') == 'to_be_preserved':
                        if Preserver and DatePreserved:
                            doActionFor(sp, action)
                            transitioned[sp.aq_parent.Title()] = sp.Title()
                        else:
                            not_transitioned.append(sp)

            if len(transitioned.keys()) > 1:
                message = _('${items}: partitions are waiting to be received.',
                            mapping={'items': ', '.join(transitioned.keys())})
            else:
                message = _('${item}: ${part} is waiting to be received.',
                            mapping={'item': ', '.join(transitioned.keys()),
                                     'part': ', '.join(transitioned.values()), })
            self.context.plone_utils.addPortalMessage(message, 'info')

            # And then the sample itself
            if Preserver and DatePreserved and not not_transitioned:
                doActionFor(sample, action)
                # message = _('${item} is waiting to be received.',
                #            mapping = {'item': sample.Title()})
                # message = t(message)
                # self.context.plone_utils.addPortalMessage(message, 'info')

            self.destination_url = self.request.get_header(
                "referer", self.context.absolute_url())
            self.request.response.redirect(self.destination_url)

        elif action in ('prepublish', 'publish', 'republish'):
            # We pass a list of AR objects to Publish.
            # it returns a list of AR IDs which were actually published.
            objects = AnalysisRequestWorkflowAction._get_selected_items(self)
            its = []
            for uid, obj in objects.items():
                if isActive(obj):
                    its.append(uid)
            its = ",".join(its)
            q = "/publish?items=" + its
            self.destination_url = self.context.absolute_url() + q
            self.request.response.redirect(self.destination_url)

        else:
            AnalysisRequestWorkflowAction.__call__(self)
Ejemplo n.º 22
0
    def __call__(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(form)
        workflow = getToolByName(self.context, 'portal_workflow')
        pc = getToolByName(self.context, 'portal_catalog')
        rc = getToolByName(self.context, REFERENCE_CATALOG)
        translate = self.context.translation_service.translate
        checkPermission = self.context.portal_membership.checkPermission

        # use came_from to decide which UI action was clicked.
        # "workflow_action" is the action name specified in the
        # portal_workflow transition url.
        came_from = "workflow_action"
        action = form.get(came_from, '')
        if not action:
            # workflow_action_button is the action name specified in
            # the bika_listing_view table buttons.
            came_from = "workflow_action_button"
            action = form.get('workflow_action_id', '')
            if not action:
                if self.destination_url == "":
                    self.destination_url = self.request.get_header(
                        "referer", self.context.absolute_url())
                self.request.response.redirect(self.destination_url)
                return

        if action == "sampled":
            objects = AnalysisRequestWorkflowAction._get_selected_items(self)
            transitioned = {'to_be_preserved': [], 'sample_due': []}
            for obj_uid, obj in objects.items():
                if obj.portal_type == "AnalysisRequest":
                    ar = obj
                    sample = obj.getSample()
                else:
                    sample = obj
                    ar = sample.aq_parent
                # can't transition inactive items
                if workflow.getInfoFor(sample, 'inactive_state',
                                       '') == 'inactive':
                    continue
                if not checkPermission(SampleSample, sample):
                    continue

                # grab this object's Sampler and DateSampled from the form
                # (if the columns are available and edit controls exist)
                if 'getSampler' in form and 'getDateSampled' in form:
                    try:
                        Sampler = form['getSampler'][0][obj_uid].strip()
                        DateSampled = form['getDateSampled'][0][obj_uid].strip(
                        )
                    except KeyError:
                        continue
                    Sampler = Sampler and Sampler or ''
                    DateSampled = DateSampled and DateTime(DateSampled) or ''
                else:
                    continue

                # write them to the sample
                sample.setSampler(Sampler)
                sample.setDateSampled(DateSampled)

                # transition the object if both values are present
                if Sampler and DateSampled:
                    workflow.doActionFor(sample, 'sampled')
                    new_state = workflow.getInfoFor(sample, 'review_state')
                    transitioned[new_state].append(sample.Title())
                doActionFor(ar, 'sampled')

            message = None
            for state in transitioned:
                t = transitioned[state]
                if len(t) > 1:
                    if state == 'to_be_preserved':
                        message = _('${items} are waiting for preservation.',
                                    mapping={'items': ', '.join(t)})
                    else:
                        message = _('${items} are waiting to be received.',
                                    mapping={'items': ', '.join(t)})
                    message = self.context.translate(message)
                    self.context.plone_utils.addPortalMessage(message, 'info')
                elif len(t) == 1:
                    if state == 'to_be_preserved':
                        message = _('${item} is waiting for preservation.',
                                    mapping={'item': ', '.join(t)})
                    else:
                        message = _('${item} is waiting to be received.',
                                    mapping={'item': ', '.join(t)})
                    message = self.context.translate(message)
                    self.context.plone_utils.addPortalMessage(message, 'info')
            if not message:
                message = _('No changes made.')
                message = self.context.translate(message)
                self.context.plone_utils.addPortalMessage(message, 'info')
            self.destination_url = self.request.get_header(
                "referer", self.context.absolute_url())
            self.request.response.redirect(self.destination_url)

        elif action == "preserved":
            objects = AnalysisRequestWorkflowAction._get_selected_items(self)
            transitioned = {}
            not_transitioned = []
            for obj_uid, obj in objects.items():
                if obj.portal_type == "AnalysisRequest":
                    ar = obj
                    sample = obj.getSample()
                else:
                    sample = obj
                    ar = sample.aq_parent
                # can't transition inactive items
                if workflow.getInfoFor(sample, 'inactive_state',
                                       '') == 'inactive':
                    continue
                if not checkPermission(PreserveSample, sample):
                    continue

                # grab this object's Preserver and DatePreserved from the form
                # (if the columns are available and edit controls exist)
                if 'getPreserver' in form and 'getDatePreserved' in form:
                    try:
                        Preserver = form['getPreserver'][0][obj_uid].strip()
                        DatePreserved = form['getDatePreserved'][0][
                            obj_uid].strip()
                    except KeyError:
                        continue
                    Preserver = Preserver and Preserver or ''
                    DatePreserved = DatePreserved and DateTime(
                        DatePreserved) or ''
                else:
                    continue

                for sp in sample.objectValues("SamplePartition"):
                    if workflow.getInfoFor(
                            sp, 'review_state') == 'to_be_preserved':
                        sp.setDatePreserved(DatePreserved)
                        sp.setPreserver(Preserver)
                for sp in sample.objectValues("SamplePartition"):
                    if workflow.getInfoFor(
                            sp, 'review_state') == 'to_be_preserved':
                        if Preserver and DatePreserved:
                            doActionFor(sp, 'preserved')
                            transitioned[sp.aq_parent.Title()] = sp.Title()
                        else:
                            not_transitioned.append(sp)

            if len(transitioned.keys()) > 1:
                message = _('${items}: partitions are waiting to be received.',
                            mapping={'items': ', '.join(transitioned.keys())})
            else:
                message = _('${item}: ${part} is waiting to be received.',
                            mapping={
                                'item': ', '.join(transitioned.keys()),
                                'part': ', '.join(transitioned.values()),
                            })
            message = self.context.translate(message)
            self.context.plone_utils.addPortalMessage(message, 'info')

            # And then the sample itself
            if Preserver and DatePreserved and not not_transitioned:
                doActionFor(sample, 'preserved')
                #message = _('${item} is waiting to be received.',
                #            mapping = {'item': sample.Title()})
                #message = self.context.translate(message)
                #self.context.plone_utils.addPortalMessage(message, 'info')

            self.destination_url = self.request.get_header(
                "referer", self.context.absolute_url())
            self.request.response.redirect(self.destination_url)

        elif action in ('prepublish', 'publish', 'republish'):
            # We pass a list of AR objects to Publish.
            # it returns a list of AR IDs which were actually published.
            ARs_to_publish = []
            transitioned = []
            if 'paths' in form:
                for path in form['paths']:
                    item_id = path.split("/")[-1]
                    item_path = path.replace("/" + item_id, '')
                    ar = pc(id=item_id, path={
                        'query': item_path,
                        'depth': 1
                    })[0].getObject()
                    # can't publish inactive items
                    if not(
                        'bika_inactive_workflow' in workflow.getChainFor(ar) and \
                        workflow.getInfoFor(ar, 'inactive_state', '') == 'inactive'):
                        ar.setDatePublished(DateTime())
                        ARs_to_publish.append(ar)

                transitioned = Publish(self.context, self.request, action,
                                       ARs_to_publish)()

            if len(transitioned) > 1:
                message = _('${items} were published.',
                            mapping={'items': ', '.join(transitioned)})
            elif len(transitioned) == 1:
                message = _('${item} published.',
                            mapping={'item': ', '.join(transitioned)})
            else:
                message = _('No items were published')
            message = translate(message)
            self.context.plone_utils.addPortalMessage(message, 'info')
            self.destination_url = self.request.get_header(
                "referer", self.context.absolute_url())
            self.request.response.redirect(self.destination_url)
        else:
            AnalysisRequestWorkflowAction.__call__(self)
Ejemplo n.º 23
0
    def __call__(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(form)
        self.context = aq_inner(self.context)
        workflow = getToolByName(self.context, 'portal_workflow')
        bc = getToolByName(self.context, 'bika_catalog')
        rc = getToolByName(self.context, REFERENCE_CATALOG)
        translate = self.context.translate
        checkPermission = self.context.portal_membership.checkPermission

        # use came_from to decide which UI action was clicked.
        # "workflow_action" is the action name specified in the
        # portal_workflow transition url.
        came_from = "workflow_action"
        action = form.get(came_from, '')
        if not action:
            # workflow_action_button is the action name specified in
            # the bika_listing_view table buttons.
            came_from = "workflow_action_button"
            action = form.get('workflow_action_id', '')
            if not action:
                if self.destination_url == "":
                    self.destination_url = self.request.get_header("referer",
                                           self.context.absolute_url())
                self.request.response.redirect(self.destination_url)
                return

        if action == "sample":
            objects = AnalysisRequestWorkflowAction._get_selected_items(self)
            transitioned = {'to_be_preserved':[], 'sample_due':[]}
            for obj_uid, obj in objects.items():
                if obj.portal_type == "AnalysisRequest":
                    ar = obj
                    sample = obj.getSample()
                else:
                    sample = obj
                    ar = sample.aq_parent
                # can't transition inactive items
                if workflow.getInfoFor(sample, 'inactive_state', '') == 'inactive':
                    continue

                # grab this object's Sampler and DateSampled from the form
                # (if the columns are available and edit controls exist)
                if 'getSampler' in form and 'getDateSampled' in form:
                    try:
                        Sampler = form['getSampler'][0][obj_uid].strip()
                        DateSampled = form['getDateSampled'][0][obj_uid].strip()
                    except KeyError:
                        continue
                    Sampler = Sampler and Sampler or ''
                    DateSampled = DateSampled and DateTime(DateSampled) or ''
                else:
                    continue

                # write them to the sample
                sample.setSampler(Sampler)
                sample.setDateSampled(DateSampled)
                sample.reindexObject()
                ars = sample.getAnalysisRequests()
                # Analyses and AnalysisRequets have calculated fields
                # that are indexed; re-index all these objects.
                for ar in ars:
                    ar.reindexObject()
                    analyses = sample.getAnalyses({'review_state':'to_be_sampled'})
                    for a in analyses:
                        a.getObject().reindexObject()

                # transition the object if both values are present
                if Sampler and DateSampled:
                    workflow.doActionFor(sample, action)
                    new_state = workflow.getInfoFor(sample, 'review_state')
                    doActionFor(ar, action)
                    transitioned[new_state].append(sample.Title())

            message = None
            for state in transitioned:
                tlist = transitioned[state]
                if len(tlist) > 1:
                    if state == 'to_be_preserved':
                        message = _('${items} are waiting for preservation.',
                                    mapping = {'items': ', '.join(tlist)})
                    else:
                        message = _('${items} are waiting to be received.',
                                    mapping = {'items': ', '.join(tlist)})
                    self.context.plone_utils.addPortalMessage(message, 'info')
                elif len(tlist) == 1:
                    if state == 'to_be_preserved':
                        message = _('${item} is waiting for preservation.',
                                    mapping = {'item': ', '.join(tlist)})
                    else:
                        message = _('${item} is waiting to be received.',
                                    mapping = {'item': ', '.join(tlist)})
                    self.context.plone_utils.addPortalMessage(message, 'info')
            if not message:
                message = _('No changes made.')
                self.context.plone_utils.addPortalMessage(message, 'info')
            self.destination_url = self.request.get_header("referer",
                                   self.context.absolute_url())
            self.request.response.redirect(self.destination_url)

        elif action == "preserve":
            objects = AnalysisRequestWorkflowAction._get_selected_items(self)
            transitioned = {}
            not_transitioned = []
            for obj_uid, obj in objects.items():
                if obj.portal_type == "AnalysisRequest":
                    ar = obj
                    sample = obj.getSample()
                else:
                    sample = obj
                    ar = sample.aq_parent
                # can't transition inactive items
                if workflow.getInfoFor(sample, 'inactive_state', '') == 'inactive':
                    continue
                if not checkPermission(PreserveSample, sample):
                    continue

                # grab this object's Preserver and DatePreserved from the form
                # (if the columns are available and edit controls exist)
                if 'getPreserver' in form and 'getDatePreserved' in form:
                    try:
                        Preserver = form['getPreserver'][0][obj_uid].strip()
                        DatePreserved = form['getDatePreserved'][0][obj_uid].strip()
                    except KeyError:
                        continue
                    Preserver = Preserver and Preserver or ''
                    DatePreserved = DatePreserved and DateTime(DatePreserved) or ''
                else:
                    continue

                for sp in sample.objectValues("SamplePartition"):
                    if workflow.getInfoFor(sp, 'review_state') == 'to_be_preserved':
                        sp.setDatePreserved(DatePreserved)
                        sp.setPreserver(Preserver)
                for sp in sample.objectValues("SamplePartition"):
                    if workflow.getInfoFor(sp, 'review_state') == 'to_be_preserved':
                        if Preserver and DatePreserved:
                            doActionFor(sp, action)
                            transitioned[sp.aq_parent.Title()] = sp.Title()
                        else:
                            not_transitioned.append(sp)

            if len(transitioned.keys()) > 1:
                message = _('${items}: partitions are waiting to be received.',
                        mapping = {'items': ', '.join(transitioned.keys())})
            else:
                message = _('${item}: ${part} is waiting to be received.',
                        mapping = {'item': ', '.join(transitioned.keys()),
                                   'part': ', '.join(transitioned.values()),})
            self.context.plone_utils.addPortalMessage(message, 'info')

            # And then the sample itself
            if Preserver and DatePreserved and not not_transitioned:
                doActionFor(sample, action)
                #message = _('${item} is waiting to be received.',
                #            mapping = {'item': sample.Title()})
                #message = t(message)
                #self.context.plone_utils.addPortalMessage(message, 'info')

            self.destination_url = self.request.get_header(
                "referer", self.context.absolute_url())
            self.request.response.redirect(self.destination_url)

        elif action in ('prepublish', 'publish', 'republish'):
            # We pass a list of AR objects to Publish.
            # it returns a list of AR IDs which were actually published.
            objects = AnalysisRequestWorkflowAction._get_selected_items(self)
            ARs_to_publish = []
            transitioned = []
            for obj_uid, obj in objects.items():
                if isActive(obj):
                    obj.setDatePublished(DateTime())
                    ARs_to_publish.append(obj)

            transitioned = self.doPublish(self.context,
                                   self.request,
                                   action,
                                   ARs_to_publish)()

            if len(transitioned) > 1:
                message = _('${items} were published.',
                            mapping = {'items': ', '.join(transitioned)})
            elif len(transitioned) == 1:
                message = _('${item} published.',
                            mapping = {'item': ', '.join(transitioned)})
            else:
                message = _('No items were published')
            self.context.plone_utils.addPortalMessage(message, 'info')
            self.destination_url = self.request.get_header("referer",
                                   self.context.absolute_url())
            self.request.response.redirect(self.destination_url)

        else:
            AnalysisRequestWorkflowAction.__call__(self)
Ejemplo n.º 24
0
    def __call__(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(form)
        workflow = getToolByName(self.context, 'portal_workflow')
        rc = getToolByName(self.context, REFERENCE_CATALOG)
        bsc = getToolByName(self.context, 'bika_setup_catalog')
        bac = getToolByName(self.context, 'bika_analysis_catalog')
        action, came_from = WorkflowAction._get_form_workflow_action(self)

        # XXX combine data from multiple bika listing tables.
        item_data = {}
        if 'item_data' in form:
            if type(form['item_data']) == list:
                for i_d in form['item_data']:
                    for i, d in json.loads(i_d).items():
                        item_data[i] = d
            else:
                item_data = json.loads(form['item_data'])

        if action == 'submit' and self.request.form.has_key("Result"):
            selected_analyses = WorkflowAction._get_selected_items(self)
            results = {}
            hasInterims = {}

            # first save results for entire form
            for uid, result in self.request.form['Result'][0].items():
                if uid in selected_analyses:
                    analysis = selected_analyses[uid]
                else:
                    analysis = rc.lookupObject(uid)
                if not analysis:
                    # ignore result if analysis object no longer exists
                    continue
                if not(getSecurityManager().checkPermission(EditResults, analysis)):
                    # or changes no longer allowed
                    continue
                if not isActive(analysis):
                    # or it's cancelled
                    continue
                results[uid] = result
                service = analysis.getService()
                interimFields = item_data[uid]
                if len(interimFields) > 0:
                    hasInterims[uid] = True
                else:
                    hasInterims[uid] = False
                unit = service.getUnit()
                analysis.edit(
                    Result = result,
                    InterimFields = interimFields,
                    Retested = form.has_key('retested') and \
                               form['retested'].has_key(uid),
                    Unit = unit and unit or '')

            # discover which items may be submitted
            submissable = []
            for uid, analysis in selected_analyses.items():
                if uid not in results:
                    continue
                can_submit = True
                if hasattr(analysis, 'getDependencies'):
                    dependencies = analysis.getDependencies()
                    for dependency in dependencies:
                        dep_state = workflow.getInfoFor(dependency, 'review_state')
                        if hasInterims[uid]:
                            if dep_state in ('to_be_sampled', 'to_be_preserved',
                                             'sample_due', 'sample_received',
                                             'attachment_due', 'to_be_verified',):
                                can_submit = False
                                break
                        else:
                            if dep_state in ('to_be_sampled', 'to_be_preserved',
                                             'sample_due', 'sample_received',):
                                can_submit = False
                                break
                    for dependency in dependencies:
                        if workflow.getInfoFor(dependency, 'review_state') in \
                           ('to_be_sampled', 'to_be_preserved',
                            'sample_due', 'sample_received'):
                            can_submit = False
                if can_submit:
                    submissable.append(analysis)

            # and then submit them.
            for analysis in submissable:
                doActionFor(analysis, 'submit')

            message = PMF("Changes saved.")
            self.context.plone_utils.addPortalMessage(message, 'info')
            self.destination_url = self.request.get_header("referer",
                                   self.context.absolute_url())
            self.request.response.redirect(self.destination_url)
        ## assign
        elif action == 'assign':
            if not(getSecurityManager().checkPermission(EditWorksheet, self.context)):
                self.request.response.redirect(self.context.absolute_url())
                return

            selected_analyses = WorkflowAction._get_selected_items(self)
            selected_analysis_uids = selected_analyses.keys()

            if selected_analyses:
                for uid in selected_analysis_uids:
                    analysis = rc.lookupObject(uid)
                    # Double-check the state first
                    if (workflow.getInfoFor(analysis, 'worksheetanalysis_review_state') == 'unassigned'
                    and workflow.getInfoFor(analysis, 'review_state') == 'sample_received'
                    and workflow.getInfoFor(analysis, 'cancellation_state') == 'active'):
                        self.context.addAnalysis(analysis)

            self.destination_url = self.context.absolute_url()
            self.request.response.redirect(self.destination_url)
        ## unassign
        elif action == 'unassign':
            if not(getSecurityManager().checkPermission(EditWorksheet, self.context)):
                self.request.response.redirect(self.context.absolute_url())
                return

            selected_analyses = WorkflowAction._get_selected_items(self)
            selected_analysis_uids = selected_analyses.keys()

            for analysis_uid in selected_analysis_uids:
                try:
                    analysis = bac(UID=analysis_uid)[0].getObject()
                except IndexError:
                    # Duplicate analyses are removed when their analyses
                    # get removed, so indexerror is expected.
                    continue
                if skip(analysis, action, peek=True):
                    continue
                self.context.removeAnalysis(analysis)

            self.destination_url = self.context.absolute_url()
            self.request.response.redirect(self.destination_url)
        ## verify
        elif action == 'verify':
            # default bika_listing.py/WorkflowAction, but then go to view screen.
            self.destination_url = self.context.absolute_url()
            WorkflowAction.__call__(self)
        else:
            # default bika_listing.py/WorkflowAction for other transitions
            WorkflowAction.__call__(self)