예제 #1
0
def ObjectInitializedEventHandler(instance, event):

    wf_tool = getToolByName(instance, 'portal_workflow')

    ar = instance.getRequest()
    ar_state = wf_tool.getInfoFor(ar, 'review_state')
    ar_ws_state = wf_tool.getInfoFor(ar, 'worksheetanalysis_review_state')

    # Set the state of the analysis depending on the state of the AR.
    if ar_state in ('sample_registered', 'to_be_sampled', 'sampled',
                    'to_be_preserved', 'sample_due', 'sample_received'):
        changeWorkflowState(instance, "bika_analysis_workflow", ar_state)
    elif ar_state in ('to_be_verified'):
        # Apply to AR only; we don't want this transition to cascade.
        if 'workflow_skiplist' not in ar.REQUEST:
            ar.REQUEST['workflow_skiplist'] = []
        ar.REQUEST['workflow_skiplist'].append("retract all analyses")
        wf_tool.doActionFor(ar, 'retract')
        ar.REQUEST['workflow_skiplist'].remove("retract all analyses")

    if ar_ws_state == 'assigned':
        # TODO workflow: analysis request can be 'assigned'?
        wf_tool.doActionFor(ar, 'unassign')
        skip(ar, 'unassign', unskip=True)

    return
예제 #2
0
파일: analysis.py 프로젝트: xispa/bika.lims
def ObjectInitializedEventHandler(instance, event):

    wf_tool = getToolByName(instance, 'portal_workflow')

    ar = instance.getRequest()
    ar_state = wf_tool.getInfoFor(ar, 'review_state')
    ar_ws_state = wf_tool.getInfoFor(ar, 'worksheetanalysis_review_state')

    # Set the state of the analysis depending on the state of the AR.
    if ar_state in ('sample_registered',
                    'to_be_sampled',
                    'sampled',
                    'to_be_preserved',
                    'sample_due',
                    'sample_received'):
        changeWorkflowState(instance, "bika_analysis_workflow", ar_state)
    elif ar_state in ('to_be_verified'):
        # Apply to AR only; we don't want this transition to cascade.
        if 'workflow_skiplist' not in ar.REQUEST:
            ar.REQUEST['workflow_skiplist'] = []
        ar.REQUEST['workflow_skiplist'].append("retract all analyses")
        wf_tool.doActionFor(ar, 'retract')
        ar.REQUEST['workflow_skiplist'].remove("retract all analyses")

    if ar_ws_state == 'assigned':
        # TODO workflow: analysis request can be 'assigned'?
        wf_tool.doActionFor(ar, 'unassign')
        skip(ar, 'unassign', unskip=True)

    return
예제 #3
0
파일: analysis.py 프로젝트: cpang2/bikalims
def ObjectInitializedEventHandler(instance, event):

    # This is the easiest place to assign IRoutineAnalysis,
    # since other anlaysis types subclass Analysis.
    # (noLongerProvides cannot un-provide interfaces on the class itself)
    if instance.portal_type == 'Analysis':
        alsoProvides(instance, IRoutineAnalysis)

    wf_tool = getToolByName(instance, 'portal_workflow')

    ar = instance.aq_parent
    ar_state = wf_tool.getInfoFor(ar, 'review_state')
    ar_ws_state = wf_tool.getInfoFor(ar, 'worksheetanalysis_review_state')

    # Set the state of the analysis depending on the state of the AR.
    if ar_state in ('sample_registered', 'to_be_sampled', 'sampled',
                    'to_be_preserved', 'sample_due', 'sample_received'):
        changeWorkflowState(instance, "bika_analysis_workflow", ar_state)
    elif ar_state in ('to_be_verified'):
        # Apply to AR only; we don't want this transition to cascade.
        if 'workflow_skiplist' not in ar.REQUEST:
            ar.REQUEST['workflow_skiplist'] = []
        ar.REQUEST['workflow_skiplist'].append("retract all analyses")
        wf_tool.doActionFor(ar, 'retract')
        ar.REQUEST['workflow_skiplist'].remove("retract all analyses")

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

    instance.updateDueDate()

    return
예제 #4
0
 def workflow_script_submit(self):
     if skip(self, "submit"):
         return
     workflow = getToolByName(self, "portal_workflow")
     self.reindexObject(idxs=["review_state", ])
     # If all analyses on the worksheet have been submitted,
     # then submit the worksheet.
     ws = self.getBackReferences('WorksheetAnalysis')
     ws = ws[0]
     # if the worksheet analyst is not assigned, the worksheet can't  be transitioned.
     if ws.getAnalyst() and not skip(ws, "submit", peek=True):
         all_submitted = True
         for a in ws.getAnalyses():
             if workflow.getInfoFor(a, 'review_state') in \
                ('sample_due', 'sample_received', 'assigned',):
                 all_submitted = False
                 break
         if all_submitted:
             workflow.doActionFor(ws, 'submit')
     # If no problem with attachments, do 'attach' action.
     can_attach = True
     if not self.getAttachment():
         service = self.getService()
         if service.getAttachmentOption() == 'r':
             can_attach = False
     if can_attach:
         workflow.doActionFor(self, 'attach')
예제 #5
0
    def workflow_script_verify(self):
        if skip(self, "verify"):
            return
        workflow = getToolByName(self, "portal_workflow")
        self.reindexObject(idxs=["review_state"])

        # If all other analyses on the worksheet are verified,
        # then verify the worksheet.
        ws = self.getBackReferences("WorksheetAnalysis")
        if ws and len(ws) > 0:
            ws = ws[0]
            ws_state = workflow.getInfoFor(ws, "review_state")
            if ws_state == "to_be_verified" and not skip(ws, "verify", peek=True):
                all_verified = True
                for a in ws.getAnalyses():
                    if workflow.getInfoFor(a, "review_state") in (
                        "sample_due",
                        "sample_received",
                        "attachment_due",
                        "to_be_verified",
                        "assigned",
                    ):
                        all_verified = False
                        break
                if all_verified:
                    if not "verify all analyses" in self.REQUEST["workflow_skiplist"]:
                        self.REQUEST["workflow_skiplist"].append("verify all analyses")
                    workflow.doActionFor(ws, "verify")
예제 #6
0
    def workflow_script_attach(self):
        if skip(self, "attach"):
            return
        workflow = getToolByName(self, "portal_workflow")
        self.reindexObject(idxs=["review_state"])
        # If all analyses on the worksheet have been attached,
        # then attach the worksheet.
        ws = self.getBackReferences("WorksheetAnalysis")
        ws = ws[0]
        ws_state = workflow.getInfoFor(ws, "review_state")
        if ws_state == "attachment_due" and not skip(ws, "attach", peek=True):
            can_attach = True
            for a in ws.getAnalyses():
                if workflow.getInfoFor(a, "review_state") in (
                    "to_be_sampled",
                    "to_be_preserved",
                    "sample_due",
                    "sample_received",
                    "attachment_due",
                    "assigned",
                ):
                    can_attach = False
                    break
            if can_attach:
                workflow.doActionFor(ws, "attach")

        return
예제 #7
0
 def workflow_script_submit(self):
     if skip(self, "submit"):
         return
     workflow = getToolByName(self, "portal_workflow")
     self.reindexObject(idxs=["review_state", ])
     # If all analyses on the worksheet have been submitted,
     # then submit the worksheet.
     ws = self.getBackReferences('WorksheetAnalysis')
     ws = ws[0]
     # if the worksheet analyst is not assigned, the worksheet can't  be transitioned.
     if ws.getAnalyst() and not skip(ws, "submit", peek=True):
         all_submitted = True
         for a in ws.getAnalyses():
             if workflow.getInfoFor(a, 'review_state') in \
                ('sample_due', 'sample_received', 'assigned',):
                 all_submitted = False
                 break
         if all_submitted:
             workflow.doActionFor(ws, 'submit')
     # If no problem with attachments, do 'attach' action.
     can_attach = True
     if not self.getAttachment():
         service = self.getService()
         if service.getAttachmentOption() == 'r':
             can_attach = False
     if can_attach:
         workflow.doActionFor(self, 'attach')
예제 #8
0
파일: analysis.py 프로젝트: doun/Bika-LIMS
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

    workflow = getToolByName(instance, 'portal_workflow')

    ar = instance.aq_parent
    ar_state = workflow.getInfoFor(ar, 'review_state')
    ar_ws_state = workflow.getInfoFor(ar, 'worksheetanalysis_review_state')

    # Set the state of the analysis depending on the state of the AR.
    if ar_state in ('sample_registered', 'to_be_sampled', 'sampled',
                    'to_be_preserved', 'sample_due', 'sample_received'):
        changeWorkflowState(instance, "bika_analysis_workflow", ar_state)
    elif ar_state in ('to_be_verified'):
        # Apply to AR only; we don't want this transition to cascade.
        if 'workflow_skiplist' not in ar.REQUEST:
            ar.REQUEST['workflow_skiplist'] = []
        ar.REQUEST['workflow_skiplist'].append("retract all analyses")
        workflow.doActionFor(ar, 'retract')
        ar.REQUEST['workflow_skiplist'].remove("retract all analyses")

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

    instance.updateDueDate()

    return
예제 #9
0
 def workflow_script_verify(self):
     if skip(self, "verify"):
         return
     workflow = getToolByName(self, 'portal_workflow')
     # If all other analyses on the worksheet are verified,
     # then verify the worksheet.
     ws = self.getBackReferences('WorksheetAnalysis')
     if ws and len(ws) > 0:
         ws = ws[0]
         ws_state = workflow.getInfoFor(ws, 'review_state')
         if ws_state == 'to_be_verified' and not skip(ws, "verify",
                                                      peek=True):
             all_verified = True
             for a in ws.getAnalyses():
                 if workflow.getInfoFor(a, 'review_state') in \
                         ('sample_due', 'sample_received', 'attachment_due',
                          'to_be_verified', 'assigned'):
                     all_verified = False
                     break
             if all_verified:
                 if "verify all analyses" \
                         not in self.REQUEST['workflow_skiplist']:
                     self.REQUEST["workflow_skiplist"].append(
                         "verify all analyses")
                 workflow.doActionFor(ws, "verify")
     self.reindexObject()
예제 #10
0
 def workflow_script_verify(self):
     if skip(self, "verify"):
         return
     workflow = getToolByName(self, 'portal_workflow')
     self.reindexObject(idxs=[
         "review_state",
     ])
     # If all other analyses on the worksheet are verified,
     # then verify the worksheet.
     ws = self.getBackReferences('WorksheetAnalysis')
     ws = ws[0]
     ws_state = workflow.getInfoFor(ws, 'review_state')
     if ws_state == 'to_be_verified' and not skip(ws, "verify", peek=True):
         all_verified = True
         for a in ws.getAnalyses():
             if workflow.getInfoFor(a, 'review_state') in \
                ('to_be_sampled', 'to_be_preserved', 'sample_due',
                 'sample_received', 'attachment_due', 'to_be_verified', 'assigned'):
                 all_verified = False
                 break
         if all_verified:
             if not "verify all analyses" in self.REQUEST[
                     'workflow_skiplist']:
                 self.REQUEST["workflow_skiplist"].append(
                     "verify all analyses")
             workflow.doActionFor(ws, "verify")
예제 #11
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)
예제 #12
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)
예제 #13
0
    def workflow_script_unassign(self):
        if skip(self, "unassign"):
            return
        workflow = getToolByName(self, 'portal_workflow')
        self.reindexObject(idxs=["review_state", ])
        rc = getToolByName(self, REFERENCE_CATALOG)
        wsUID = self.REQUEST['context_uid']
        ws = rc.lookupObject(wsUID)

        # 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 = False

        analyses = ws.getAnalyses()

        # We flag this worksheet as empty if there is ONE UNASSIGNED
        # analysis left: worksheet.removeAnalysis() hasn't removed it from
        # the layout yet at this stage.
        if len(analyses) == 1 \
           and workflow.getInfoFor(analyses[0], 'review_state') == 'unassigned':
            ws_empty = True

        for a in analyses:
            a_state = workflow.getInfoFor(a, 'review_state')
            if a_state in \
               ('assigned', 'sample_due', 'sample_received',):
                can_submit = False
            else:
                if not ws.getAnalyst():
                    can_submit = False
            if a_state in \
               ('assigned', 'sample_due', 'sample_received', 'attachment_due',):
                can_attach = False
            if a_state in \
               ('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 self).
            if can_submit and workflow.getInfoFor(ws, 'review_state') == 'open':
                workflow.doActionFor(ws, 'submit')
                skip(ws, 'submit', unskip=True)
            if can_attach and workflow.getInfoFor(ws, 'review_state') == 'attachment_due':
                workflow.doActionFor(ws, 'attach')
                skip(ws, 'attach', unskip=True)
            if can_verify and workflow.getInfoFor(ws, 'review_state') == 'to_be_verified':
                self.REQUEST["workflow_skiplist"].append('verify all analyses')
                workflow.doActionFor(ws, 'verify')
                skip(ws, 'verify', unskip=True)
        else:
            if workflow.getInfoFor(ws, 'review_state') != 'open':
                workflow.doActionFor(ws, 'retract')
                skip(ws, 'retract', unskip=True)
예제 #14
0
    def workflow_script_unassign(self):
        if skip(self, "unassign"):
            return
        workflow = getToolByName(self, 'portal_workflow')
        self.reindexObject(idxs=["review_state", ])
        rc = getToolByName(self, REFERENCE_CATALOG)
        wsUID = self.REQUEST['context_uid']
        ws = rc.lookupObject(wsUID)

        # 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 = False

        analyses = ws.getAnalyses()

        # We flag this worksheet as empty if there is ONE UNASSIGNED
        # analysis left: worksheet.removeAnalysis() hasn't removed it from
        # the layout yet at this stage.
        if len(analyses) == 1 \
           and workflow.getInfoFor(analyses[0], 'review_state') == 'unassigned':
            ws_empty = True

        for a in analyses:
            a_state = workflow.getInfoFor(a, 'review_state')
            if a_state in \
               ('assigned', 'sample_due', 'sample_received',):
                can_submit = False
            else:
                if not ws.getAnalyst():
                    can_submit = False
            if a_state in \
               ('assigned', 'sample_due', 'sample_received', 'attachment_due',):
                can_attach = False
            if a_state in \
               ('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 self).
            if can_submit and workflow.getInfoFor(ws, 'review_state') == 'open':
                workflow.doActionFor(ws, 'submit')
                skip(ws, 'submit', unskip=True)
            if can_attach and workflow.getInfoFor(ws, 'review_state') == 'attachment_due':
                workflow.doActionFor(ws, 'attach')
                skip(ws, 'attach', unskip=True)
            if can_verify and workflow.getInfoFor(ws, 'review_state') == 'to_be_verified':
                self.REQUEST["workflow_skiplist"].append('verify all analyses')
                workflow.doActionFor(ws, 'verify')
                skip(ws, 'verify', unskip=True)
        else:
            if workflow.getInfoFor(ws, 'review_state') != 'open':
                workflow.doActionFor(ws, 'retract')
                skip(ws, 'retract', unskip=True)
예제 #15
0
 def workflow_script_retract(self):
     if skip(self, "retract"):
         return
     workflow = getToolByName(self, 'portal_workflow')
     self.reindexObject(idxs=["review_state", ])
     # Escalate action to the Worksheet.
     ws = self.getBackReferences('WorksheetAnalysis')
     ws = ws[0]
     if not skip(ws, "retract", peek=True):
         if workflow.getInfoFor(ws, 'review_state') == 'open':
             skip(ws, "retract")
         else:
             if not "retract all analyses" in self.REQUEST['workflow_skiplist']:
                 self.REQUEST["workflow_skiplist"].append("retract all analyses")
             workflow.doActionFor(ws, 'retract')
예제 #16
0
 def workflow_script_retract(self):
     if skip(self, "retract"):
         return
     workflow = getToolByName(self, 'portal_workflow')
     self.reindexObject(idxs=["review_state", ])
     # Escalate action to the Worksheet.
     ws = self.getBackReferences('WorksheetAnalysis')
     ws = ws[0]
     if not skip(ws, "retract", peek=True):
         if workflow.getInfoFor(ws, 'review_state') == 'open':
             skip(ws, "retract")
         else:
             if not "retract all analyses" in self.REQUEST['workflow_skiplist']:
                 self.REQUEST["workflow_skiplist"].append("retract all analyses")
             workflow.doActionFor(ws, 'retract')
예제 #17
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
예제 #18
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
예제 #19
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
예제 #20
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
예제 #21
0
    def workflow_script_attach(self):
        if skip(self, "attach"):
            return
        workflow = getToolByName(self, 'portal_workflow')
        self.reindexObject(idxs=["review_state", ])

        # If all analyses on the worksheet have been attached,
        # then attach the worksheet.
        ws = self.getBackReferences('WorksheetAnalysis')
        ws = ws[0]
        ws_state = workflow.getInfoFor(ws, 'review_state')
        if ws_state == 'attachment_due' and not skip(ws, "attach", peek=True):
            can_attach = True
            for a in ws.getAnalyses():
                if workflow.getInfoFor(a, 'review_state') in \
                   ('sample_due', 'sample_received', 'attachment_due', 'assigned',):
                    can_attach = False
                    break
            if can_attach:
                workflow.doActionFor(ws, 'attach')
예제 #22
0
    def workflow_script_attach(self):
        if skip(self, "attach"):
            return
        workflow = getToolByName(self, 'portal_workflow')
        self.reindexObject(idxs=["review_state", ])

        # If all analyses on the worksheet have been attached,
        # then attach the worksheet.
        ws = self.getBackReferences('WorksheetAnalysis')
        ws = ws[0]
        ws_state = workflow.getInfoFor(ws, 'review_state')
        if ws_state == 'attachment_due' and not skip(ws, "attach", peek=True):
            can_attach = True
            for a in ws.getAnalyses():
                if workflow.getInfoFor(a, 'review_state') in \
                   ('sample_due', 'sample_received', 'attachment_due', 'assigned',):
                    can_attach = False
                    break
            if can_attach:
                workflow.doActionFor(ws, 'attach')
예제 #23
0
def AfterTransitionEventHandler(instance, event):

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

    debug_mode = App.config.getConfiguration().debug_mode
    if not debug_mode:
        return

    if not skip(instance, event.transition.id, peek=True):
        logger.debug("Started transition %s on %s" % (event.transition.id, instance))
예제 #24
0
파일: analysis.py 프로젝트: Ammy2/Bika-LIMS
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

    if instance.portal_type == 'Analysis':
        alsoProvides(instance, IRoutineAnalysis)

    workflow = getToolByName(instance, 'portal_workflow')

    ar = instance.aq_parent
    ar_state = workflow.getInfoFor(ar, 'review_state')
    ar_ws_state = workflow.getInfoFor(ar, 'worksheetanalysis_review_state')

    # Set the state of the analysis depending on the state of the AR.
    if ar_state in ('sample_registered',
                    'to_be_sampled',
                    'sampled',
                    'to_be_preserved',
                    'sample_due',
                    'sample_received'):
        changeWorkflowState(instance, "bika_analysis_workflow", ar_state)
    elif ar_state in ('to_be_verified'):
        # Apply to AR only; we don't want this transition to cascade.
        if 'workflow_skiplist' not in ar.REQUEST:
            ar.REQUEST['workflow_skiplist'] = []
        ar.REQUEST['workflow_skiplist'].append("retract all analyses")
        workflow.doActionFor(ar, 'retract')
        ar.REQUEST['workflow_skiplist'].remove("retract all analyses")

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

    instance.updateDueDate()

    return
예제 #25
0
def AfterTransitionEventHandler(instance, event):

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

    debug_mode = App.config.getConfiguration().debug_mode
    if not debug_mode:
        return

    if not skip(instance, event.transition.id, peek=True):
        logger.debug("Started transition %s on %s" %
                     (event.transition.id, instance))
예제 #26
0
def ObjectInitializedEventHandler(instance, event):

    # This is the easiest place to assign IRoutineAnalysis,
    # since other anlaysis types subclass Analysis.
    # (noLongerProvides cannot un-provide interfaces on the class itself)
    if instance.portal_type == 'Analysis':
        alsoProvides(instance, IRoutineAnalysis)

    wf_tool = getToolByName(instance, 'portal_workflow')

    ar = instance.aq_parent
    ar_state = wf_tool.getInfoFor(ar, 'review_state')
    ar_ws_state = wf_tool.getInfoFor(ar, 'worksheetanalysis_review_state')

    # Set the state of the analysis depending on the state of the AR.
    if ar_state in ('sample_registered',
                    'to_be_sampled',
                    'sampled',
                    'to_be_preserved',
                    'sample_due',
                    'sample_received'):
        changeWorkflowState(instance, "bika_analysis_workflow", ar_state)
    elif ar_state in ('to_be_verified'):
        # Apply to AR only; we don't want this transition to cascade.
        if 'workflow_skiplist' not in ar.REQUEST:
            ar.REQUEST['workflow_skiplist'] = []
        ar.REQUEST['workflow_skiplist'].append("retract all analyses")
        wf_tool.doActionFor(ar, 'retract')
        ar.REQUEST['workflow_skiplist'].remove("retract all analyses")

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

    instance.updateDueDate()

    return
예제 #27
0
    def workflow_script_assign(self):
        if skip(self, "assign"):
            return
        workflow = getToolByName(self, "portal_workflow")
        self.reindexObject(idxs=["review_state"])
        rc = getToolByName(self, REFERENCE_CATALOG)
        wsUID = self.REQUEST["context_uid"]
        ws = rc.lookupObject(wsUID)

        # retract the worksheet to 'open'
        ws_state = workflow.getInfoFor(ws, "review_state")
        if ws_state != "open":
            if "workflow_skiplist" not in self.REQUEST:
                self.REQUEST["workflow_skiplist"] = ["retract all analyses"]
            else:
                self.REQUEST["workflow_skiplist"].append("retract all analyses")
            workflow.doActionFor(ws, "retract")
예제 #28
0
    def workflow_script_assign(self):
        if skip(self, "assign"):
            return
        workflow = getToolByName(self, 'portal_workflow')
        self.reindexObject(idxs=["review_state", ])
        rc = getToolByName(self, REFERENCE_CATALOG)
        wsUID = self.REQUEST['context_uid']
        ws = rc.lookupObject(wsUID)

        # retract the worksheet to 'open'
        ws_state = workflow.getInfoFor(ws, 'review_state')
        if ws_state != 'open':
            if 'workflow_skiplist' not in self.REQUEST:
                self.REQUEST['workflow_skiplist'] = ['retract all analyses', ]
            else:
                self.REQUEST["workflow_skiplist"].append('retract all analyses')
            workflow.doActionFor(ws, 'retract')
예제 #29
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
예제 #30
0
파일: workflow.py 프로젝트: xispa/bika.lims
    def __call__(self):
        form = self.request.form
        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)


        if action == 'submit':
            # Submit the form. Saves the results, methods, etc.
            self.submit()

        ## assign
        elif action == 'assign':
            if not self.context.checkUserManage():
                self.request.response.redirect(self.context.absolute_url())
                return

            analysis_uids = form.get("uids", [])
            if analysis_uids:
                # We retrieve the analyses from the database sorted by AR ID
                # ascending, so the positions of the ARs inside the WS are
                # consistent with the order of the ARs
                catalog = get_tool(CATALOG_ANALYSIS_LISTING)
                brains = catalog({'UID': analysis_uids,
                                  'sort_on': 'getRequestID'})

                # Now, we need the analyses within a request ID to be sorted by
                # sortkey (sortable_title index), so it will appear in the same
                # order as they appear in Analyses list from AR view
                curr_arid = None
                curr_brains = []
                sorted_brains = []
                for brain in brains:
                    arid = brain.getRequestID
                    if curr_arid != arid:
                        # Sort the brains we've collected until now, that belong to
                        # the same Analysis Request
                        curr_brains.sort(key=attrgetter('getPrioritySortkey'))
                        sorted_brains.extend(curr_brains)
                        curr_arid = arid
                        curr_brains = []

                    # Now we are inside the same AR
                    curr_brains.append(brain)
                    continue

                # Sort the last set of brains we've collected
                curr_brains.sort(key=attrgetter('getPrioritySortkey'))
                sorted_brains.extend(curr_brains)

                # Add analyses in the worksheet
                for brain in sorted_brains:
                    analysis = brain.getObject()
                    self.context.addAnalysis(analysis)

            self.destination_url = self.context.absolute_url()
            self.request.response.redirect(self.destination_url)
        ## unassign
        elif action == 'unassign':
            if not self.context.checkUserManage():
                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)

            message = PMF("Changes saved.")
            self.context.plone_utils.addPortalMessage(message, 'info')
            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()
            return self.workflow_action_default(action='verify',
                                                came_from=came_from)
        else:
            # default bika_listing.py/WorkflowAction for other transitions
            WorkflowAction.__call__(self)
예제 #31
0
    def __call__(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(form)
        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)

        if action == 'submit':

            # Submit the form. Saves the results, methods, etc.
            self.submit()

        ## assign
        elif action == 'assign':
            if not self.context.checkUserManage():
                self.request.response.redirect(self.context.absolute_url())
                return

            analyses = WorkflowAction._get_selected_items(self).values()

            if analyses:
                analyses = sorted(analyses, key=methodcaller('getRequestID'))
                for analysis in analyses:
                    if self.isAddable(analysis):
                        self.context.addAnalysis(analysis)

            self.destination_url = self.context.absolute_url()
            self.request.response.redirect(self.destination_url)
        ## unassign
        elif action == 'unassign':
            if not self.context.checkUserManage():
                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)

            message = PMF("Changes saved.")
            self.context.plone_utils.addPortalMessage(message, 'info')
            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()
            return self.workflow_action_default(action='verify',
                                                came_from=came_from)
        else:
            # default bika_listing.py/WorkflowAction for other transitions
            WorkflowAction.__call__(self)
예제 #32
0
def AfterTransitionEventHandler(instance, event):

    # Note: Don't have dependencies or dependents, not on an AR
    #----------------------------------------------------------

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

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    if action_id == "attach":
        wf = getToolByName(instance, 'portal_workflow')
        instance.reindexObject(idxs = ["review_state", ])

        # If all analyses on the worksheet have been attached,
        # then attach the worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        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 \
                   ('sample_due', 'sample_received', 'attachment_due', 'assigned',):
                    can_attach = False
                    break
            if can_attach:
                wf.doActionFor(ws, 'attach')

        return

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

    wf = getToolByName(instance, 'portal_workflow')

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

        # If all analyses on the worksheet have been submitted,
        # then submit the worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        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 \
                   ('sample_due', 'sample_received', '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:
            wf.doActionFor(instance, 'attach')

    elif action_id == "retract":
        instance.reindexObject(idxs = ["review_state", ])
        # Escalate action to the Worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        ws = ws[0]
        if not skip(ws, action_id, peek=True):
            if wf.getInfoFor(ws, 'review_state') == 'open':
                skip(ws, action_id)
            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", ])

        # If all other analyses on the worksheet are verified,
        # then verify the worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        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 \
                   ('sample_due', 'sample_received', 'attachment_due', 'to_be_verified', '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 == "assign":
        instance.reindexObject(idxs = ["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')

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

        # 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 \
               ('assigned', 'sample_due', 'sample_received',):
                can_submit = False
            else:
                if not ws.getAnalyst():
                    can_submit = False
            if a_state in \
               ('assigned', 'sample_due', 'sample_received', 'attachment_due',):
                can_attach = False
            if a_state in \
               ('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')
                unskip(ws, 'submit', unskip=True)
            if can_attach and wf.getInfoFor(ws, 'review_state') == 'attachment_due':
                wf.doActionFor(ws, 'attach')
                unskip(ws, 'attach', 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')
                unskip(ws, 'verify', unskip=True)
        else:
            if wf.getInfoFor(ws, 'review_state') != 'open':
                wf.doActionFor(ws, 'retract')
                unskip(ws, 'retract', unskip=True)

    return
예제 #33
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)


        if action == 'submit':

            # Submit the form. Saves the results, methods, etc.
            self.submit()

        ## assign
        elif action == 'assign':
            if not self.context.checkUserManage():
                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 self.context.checkUserManage():
                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)

            message = PMF("Changes saved.")
            self.context.plone_utils.addPortalMessage(message, 'info')
            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()
            return self.workflow_action_default(action='verify',
                                                came_from='edit')
        else:
            # default bika_listing.py/WorkflowAction for other transitions
            WorkflowAction.__call__(self)
예제 #34
0
def ObjectRemovedEventHandler(instance, event):
    # TODO Workflow - Review all this function and normalize
    # May need to promote the AR's review_state
    # if all other analyses are at a higher state than this one was.
    workflow = getToolByName(instance, 'portal_workflow')
    ar = instance.getRequest()
    can_submit = True
    can_attach = True
    can_verify = True
    can_publish = True

    # We add this manually here, because during admin/ZMI removal,
    # it may possibly not be added by the workflow code.
    if not 'workflow_skiplist' in instance.REQUEST:
        instance.REQUEST['workflow_skiplist'] = []

    for a in ar.getAnalyses():
        a_state = a.review_state
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',):
            can_submit = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received', 'attachment_due',):
            can_attach = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified',):
            can_verify = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified', 'verified',):
            can_publish = False

    # Note: AR adds itself to the skiplist so we have to take it off again
    #       to allow multiple promotions (maybe by more than one deleted instance).
    if can_submit and workflow.getInfoFor(ar,
                                          'review_state') == 'sample_received':
        try:
            workflow.doActionFor(ar, 'submit')
        except WorkflowException:
            pass
        skip(ar, 'submit', unskip=True)
    if can_attach and workflow.getInfoFor(ar,
                                          'review_state') == 'attachment_due':
        try:
            workflow.doActionFor(ar, 'attach')
        except WorkflowException:
            pass
        skip(ar, 'attach', unskip=True)
    if can_verify and workflow.getInfoFor(ar,
                                          'review_state') == 'to_be_verified':
        instance.REQUEST["workflow_skiplist"].append('verify all analyses')
        try:
            workflow.doActionFor(ar, 'verify')
        except WorkflowException:
            pass
        skip(ar, 'verify', unskip=True)
    if can_publish and workflow.getInfoFor(ar, 'review_state') == 'verified':
        instance.REQUEST["workflow_skiplist"].append('publish all analyses')
        try:
            workflow.doActionFor(ar, 'publish')
        except WorkflowException:
            pass
        skip(ar, 'publish', unskip=True)

    return
예제 #35
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
예제 #36
0
def ObjectRemovedEventHandler(instance, event):

    # May need to promote the AR's review_state
    # if all other analyses are at a higher state than this one was.
    workflow = getToolByName(instance, 'portal_workflow')
    ar = instance.aq_parent
    can_submit = True
    can_attach = True
    can_verify = True
    can_publish = True

    # We add this manually here, because during admin/ZMI removal,
    # it may possibly not be added by the workflow code.
    if not 'workflow_skiplist' in instance.REQUEST:
        instance.REQUEST['workflow_skiplist'] = []

    for a in ar.getAnalyses():
        a_state = a.review_state
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',):
            can_submit = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received', 'attachment_due',):
            can_attach = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified',):
            can_verify = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified', 'verified',):
            can_publish = False

    # Note: AR adds itself to the skiplist so we have to take it off again
    #       to allow multiple promotions (maybe by more than one deleted instance).
    if can_submit and workflow.getInfoFor(ar, 'review_state') == 'sample_received':
        try:
            workflow.doActionFor(ar, 'submit')
        except WorkflowException:
            pass
        skip(ar, 'submit', unskip=True)
    if can_attach and workflow.getInfoFor(ar, 'review_state') == 'attachment_due':
        try:
            workflow.doActionFor(ar, 'attach')
        except WorkflowException:
            pass
        skip(ar, 'attach', unskip=True)
    if can_verify and workflow.getInfoFor(ar, 'review_state') == 'to_be_verified':
        instance.REQUEST["workflow_skiplist"].append('verify all analyses')
        try:
            workflow.doActionFor(ar, 'verify')
        except WorkflowException:
            pass
        skip(ar, 'verify', unskip=True)
    if can_publish and workflow.getInfoFor(ar, 'review_state') == 'verified':
        instance.REQUEST["workflow_skiplist"].append('publish all analyses')
        try:
            workflow.doActionFor(ar, 'publish')
        except WorkflowException:
            pass
        skip(ar, 'publish', unskip=True)

    ar_ws_state = workflow.getInfoFor(ar, 'worksheetanalysis_review_state')
    if ar_ws_state == 'unassigned':
        if not ar.getAnalyses(worksheetanalysis_review_state = 'unassigned'):
            if ar.getAnalyses(worksheetanalysis_review_state = 'assigned'):
                try:
                    workflow.doActionFor(ar, 'assign')
                except WorkflowException:
                    pass
                skip(ar, 'assign', unskip=True)

    return
예제 #37
0
    def __call__(self):
        form = self.request.form
        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)

        if action == 'submit':
            # Submit the form. Saves the results, methods, etc.
            self.submit()

        ## assign
        elif action == 'assign':
            if not self.context.checkUserManage():
                self.request.response.redirect(self.context.absolute_url())
                return

            analysis_uids = form.get("uids", [])
            if analysis_uids:
                # We retrieve the analyses from the database sorted by AR ID
                # ascending, so the positions of the ARs inside the WS are
                # consistent with the order of the ARs
                catalog = get_tool(CATALOG_ANALYSIS_LISTING)
                brains = catalog({
                    'UID': analysis_uids,
                    'sort_on': 'getRequestID'
                })

                # Now, we need the analyses within a request ID to be sorted by
                # sortkey (sortable_title index), so it will appear in the same
                # order as they appear in Analyses list from AR view
                curr_arid = None
                curr_brains = []
                sorted_brains = []
                for brain in brains:
                    arid = brain.getRequestID
                    if curr_arid != arid:
                        # Sort the brains we've collected until now, that belong to
                        # the same Analysis Request
                        curr_brains.sort(key=attrgetter('getPrioritySortkey'))
                        sorted_brains.extend(curr_brains)
                        curr_arid = arid
                        curr_brains = []

                    # Now we are inside the same AR
                    curr_brains.append(brain)
                    continue

                # Sort the last set of brains we've collected
                curr_brains.sort(key=attrgetter('getPrioritySortkey'))
                sorted_brains.extend(curr_brains)

                # Add analyses in the worksheet
                for brain in sorted_brains:
                    analysis = brain.getObject()
                    self.context.addAnalysis(analysis)

            self.destination_url = self.context.absolute_url()
            self.request.response.redirect(self.destination_url)
        ## unassign
        elif action == 'unassign':
            if not self.context.checkUserManage():
                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)

            message = PMF("Changes saved.")
            self.context.plone_utils.addPortalMessage(message, 'info')
            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()
            return self.workflow_action_default(action='verify',
                                                came_from=came_from)
        else:
            # default bika_listing.py/WorkflowAction for other transitions
            WorkflowAction.__call__(self)
예제 #38
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
예제 #39
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
예제 #40
0
def ObjectRemovedEventHandler(instance, event):

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

    # May need to promote the AR's review_state
    #  if all other analyses are at a higher state than this one was.
    wf = getToolByName(instance, 'portal_workflow')
    ar = instance.aq_parent
    ar_UID = ar.UID()
    can_submit = True
    can_attach = True
    can_verify = True
    can_publish = True

    for a in ar.getAnalyses():
        a_state = a.review_state
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',):
            can_submit = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received', 'attachment_due',):
            can_attach = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified',):
            can_verify = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified', 'verified',):
            can_publish = False

    # Note: AR adds itself to the skiplist so we have to take it off again
    #       to allow multiple promotions (maybe by more than one deleted instance).
    if can_submit and wf.getInfoFor(ar, 'review_state') == 'sample_received':
        wf.doActionFor(ar, 'submit')
        skip(ar, 'submit', unskip=True)
    if can_attach and wf.getInfoFor(ar, 'review_state') == 'attachment_due':
        wf.doActionFor(ar, 'attach')
        skip(ar, 'attach', unskip=True)
    if can_verify and wf.getInfoFor(ar, 'review_state') == 'to_be_verified':
        instance.REQUEST["workflow_skiplist"].append('verify all analyses')
        wf.doActionFor(ar, 'verify')
        skip(ar, 'verify', unskip=True)
    if can_publish and wf.getInfoFor(ar, 'review_state') == 'verified':
        instance.REQUEST["workflow_skiplist"].append('publish all analyses')
        wf.doActionFor(ar, 'publish')
        skip(ar, 'publish', unskip=True)

    ar_ws_state = wf.getInfoFor(ar, 'worksheetanalysis_review_state')
    if ar_ws_state == 'unassigned':
        if not ar.getAnalyses(worksheetanalysis_review_state = 'unassigned'):
            if ar.getAnalyses(worksheetanalysis_review_state = 'assigned'):
                wf.doActionFor(ar, 'assign')
                skip(ar, 'assign', unskip=True)

    return
예제 #41
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
예제 #42
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)

        if action == 'submit':

            # Submit the form. Saves the results, methods, etc.
            self.submit()

        ## assign
        elif action == 'assign':
            if not self.context.checkUserManage():
                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 self.context.checkUserManage():
                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)

            message = PMF("Changes saved.")
            self.context.plone_utils.addPortalMessage(message, 'info')
            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()
            return self.workflow_action_default(action='verify',
                                                came_from=came_from)
        else:
            # default bika_listing.py/WorkflowAction for other transitions
            WorkflowAction.__call__(self)
예제 #43
0
파일: sample.py 프로젝트: zubryan/Bika-LIMS
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
예제 #44
0
def AfterTransitionEventHandler(instance, event):

    # Note: Don't have dependencies or dependents, not on an AR
    #----------------------------------------------------------

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

    action_id = event.transition.id

    if skip(instance, action_id):
        return

    wf = getToolByName(instance, 'portal_workflow')

    if action_id == "attach":
        instance.reindexObject(idxs = ["review_state", ])

        # If all analyses on the worksheet have been attached,
        # then attach the worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        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',):
                    can_attach = False
                    break
            if can_attach:
                wf.doActionFor(ws, 'attach')

        return

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

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

        # If all analyses on the worksheet have been submitted,
        # then submit the worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        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',):
                    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:
            wf.doActionFor(instance, 'attach')

    elif action_id == "retract":
        instance.reindexObject(idxs = ["review_state", ])
        # Escalate action to the Worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        ws = ws[0]
        if skip(ws, action_id, peek=True):
            if wf.getInfoFor(ws, 'review_state') == 'open':
                skip(ws, action_id)
            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", ])

        # If all other analyses on the worksheet are verified,
        # then verify the worksheet.
        ws = instance.getBackReferences('WorksheetAnalysis')
        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'):
                    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 == "assign":
        instance.reindexObject(idxs = ["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')

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

        # 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 \
               ('assigned', 'sample_due', 'sample_received',):
                can_submit = False
            else:
                if not ws.getAnalyst():
                    can_submit = False
            if a_state in \
               ('assigned', 'sample_due', 'sample_received', 'attachment_due',):
                can_attach = False
            if a_state in \
               ('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, 'submit', unskip=True)
            if can_attach and wf.getInfoFor(ws, 'review_state') == 'attachment_due':
                wf.doActionFor(ws, 'attach')
                skip(ws, 'attach', 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, 'verify', unskip=True)
        else:
            if wf.getInfoFor(ws, 'review_state') != 'open':
                wf.doActionFor(ws, 'retract')
                skip(ws, 'retract', unskip=True)

    return
예제 #45
0
파일: analysis.py 프로젝트: doun/Bika-LIMS
def ObjectRemovedEventHandler(instance, event):

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

    # May need to promote the AR's review_state
    #  if all other analyses are at a higher state than this one was.
    workflow = getToolByName(instance, 'portal_workflow')
    ar = instance.aq_parent
    can_submit = True
    can_attach = True
    can_verify = True
    can_publish = True

    # We add this manually here, because during admin/ZMI removal,
    # it may possibly not be added by the workflow code.
    if not 'workflow_skiplist' in instance.REQUEST:
        instance.REQUEST['workflow_skiplist'] = []

    for a in ar.getAnalyses():
        a_state = a.review_state
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',):
            can_submit = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received', 'attachment_due',):
            can_attach = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified',):
            can_verify = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified', 'verified',):
            can_publish = False

    # Note: AR adds itself to the skiplist so we have to take it off again
    #       to allow multiple promotions (maybe by more than one deleted instance).
    if can_submit and workflow.getInfoFor(ar,
                                          'review_state') == 'sample_received':
        try:
            workflow.doActionFor(ar, 'submit')
        except WorkflowException:
            pass
        skip(ar, 'submit', unskip=True)
    if can_attach and workflow.getInfoFor(ar,
                                          'review_state') == 'attachment_due':
        try:
            workflow.doActionFor(ar, 'attach')
        except WorkflowException:
            pass
        skip(ar, 'attach', unskip=True)
    if can_verify and workflow.getInfoFor(ar,
                                          'review_state') == 'to_be_verified':
        instance.REQUEST["workflow_skiplist"].append('verify all analyses')
        try:
            workflow.doActionFor(ar, 'verify')
        except WorkflowException:
            pass
        skip(ar, 'verify', unskip=True)
    if can_publish and workflow.getInfoFor(ar, 'review_state') == 'verified':
        instance.REQUEST["workflow_skiplist"].append('publish all analyses')
        try:
            workflow.doActionFor(ar, 'publish')
        except WorkflowException:
            pass
        skip(ar, 'publish', unskip=True)

    ar_ws_state = workflow.getInfoFor(ar, 'worksheetanalysis_review_state')
    if ar_ws_state == 'unassigned':
        if not ar.getAnalyses(worksheetanalysis_review_state='unassigned'):
            if ar.getAnalyses(worksheetanalysis_review_state='assigned'):
                try:
                    workflow.doActionFor(ar, 'assign')
                except WorkflowException:
                    pass
                skip(ar, 'assign', unskip=True)

    return
예제 #46
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
예제 #47
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
예제 #48
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)