def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) workflow = getToolByName(self.context, 'portal_workflow') rc = getToolByName(self.context, REFERENCE_CATALOG) action, came_from = WorkflowAction._get_form_workflow_action(self) if action == 'reassign': selected_worksheets = WorkflowAction._get_selected_items(self) selected_worksheet_uids = selected_worksheets.keys() if selected_worksheets: changes = False for uid in selected_worksheet_uids: worksheet = selected_worksheets[uid] # Double-check the state first if workflow.getInfoFor(worksheet, 'review_state') == 'open': worksheet.setAnalyst(form['Analyst'][0][uid]) changes = True if changes: message = self.context.translate(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) else: # default bika_listing.py/WorkflowAction for other transitions WorkflowAction.__call__(self)
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) action, came_from = WorkflowAction._get_form_workflow_action(self) if action == 'submit': objects = WorkflowAction._get_selected_items(self) if not objects: message = self.context.translate( _b("No analyses have been selected")) self.context.plone_utils.addPortalMessage(message, 'info') self.destination_url = self.context.absolute_url() + \ "/batchbook" self.request.response.redirect(self.destination_url) return for ar_uid, ar in objects.items(): for analysis in ar.getAnalyses(full_objects=True): kw = analysis.getKeyword() values = form.get(kw) analysis.setResult(values[0][ar_uid]) if values[0][ar_uid]: doActionFor(analysis, 'submit') message = self.context.translate(_p("Changes saved.")) self.context.plone_utils.addPortalMessage(message, 'info') self.request.response.redirect(self.request.get('URL')) return else: WorkflowAction.__call__(self)
def workflow_action_save_analyses_button(self): form = self.request.form workflow = getToolByName(self.context, 'portal_workflow') action, came_from = WorkflowAction._get_form_workflow_action(self) # AR Manage Analyses: save Analyses ar = self.context sample = ar.getSample() objects = WorkflowAction._get_selected_items(self) if not objects: message = _("No analyses have been selected") self.context.plone_utils.addPortalMessage(message, 'info') self.destination_url = self.context.absolute_url() + "/analyses" self.request.response.redirect(self.destination_url) return Analyses = objects.keys() prices = form.get("Price", [None])[0] specs = {} if form.get("min", None): for service_uid in Analyses: specs[service_uid] = { "min": form["min"][0][service_uid], "max": form["max"][0][service_uid], "error": form["error"][0][service_uid] } else: for service_uid in Analyses: specs[service_uid] = {"min": "", "max": "", "error": ""} new = ar.setAnalyses(Analyses, prices=prices, specs=specs) # link analyses and partitions # If Bika Setup > Analyses > 'Display individual sample # partitions' is checked, no Partitions available. # https://github.com/bikalabs/Bika-LIMS/issues/1030 if 'Partition' in form: for service_uid, service in objects.items(): part_id = form['Partition'][0][service_uid] part = sample[part_id] analysis = ar[service.getKeyword()] analysis.setSamplePartition(part) analysis.reindexObject() if new: for analysis in new: # if the AR has progressed past sample_received, we need to bring it back. ar_state = workflow.getInfoFor(ar, 'review_state') if ar_state in ('attachment_due', 'to_be_verified'): # Apply to AR only; we don't want this transition to cascade. ar.REQUEST['workflow_skiplist'].append( "retract all analyses") workflow.doActionFor(ar, 'retract') ar.REQUEST['workflow_skiplist'].remove( "retract all analyses") ar_state = workflow.getInfoFor(ar, 'review_state') # Then we need to forward new analyses state analysis.updateDueDate() changeWorkflowState(analysis, 'bika_analysis_workflow', ar_state) 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)
def __call__(self): form = self.request.form CheckAuthenticator(form) analysis_uids = form.get("uids", []) if not analysis_uids: self.destination_url = self.context.absolute_url() self.request.response.redirect(self.destination_url) return action, came_from = WorkflowAction._get_form_workflow_action(self) if action == "submit": # Submit the form. Saves the results, methods, etc. # Calls to its parent class AnalysesWorkflowAction self.workflow_action_submit() elif action == "assign": # Assign the analyses self.do_assign(analysis_uids) elif action == "unassign": # Unassign analyses self.do_unassign(analysis_uids) 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)
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) workflow = getToolByName(self.context, 'portal_workflow') rc = getToolByName(self.context, REFERENCE_CATALOG) action, came_from = WorkflowAction._get_form_workflow_action(self) if action == 'reassign': selected_worksheets = WorkflowAction._get_selected_items(self) selected_worksheet_uids = selected_worksheets.keys() if selected_worksheets: changes = False for uid in selected_worksheet_uids: worksheet = selected_worksheets[uid] # Double-check the state first if workflow.getInfoFor(worksheet, 'review_state') == 'open': worksheet.setAnalyst(form['Analyst'][0][uid]) changes = True if changes: message = self.context.translation_service.translate( 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) else: # default bika_listing.py/WorkflowAction for other transitions WorkflowAction.__call__(self)
def workflow_action_preserve(self): form = self.request.form workflow = getToolByName(self.context, 'portal_workflow') action, came_from = WorkflowAction._get_form_workflow_action(self) checkPermission = self.context.portal_membership.checkPermission # Partition Preservation # the partition table shown in AR and Sample views sends it's # action button submits here. objects = WorkflowAction._get_selected_items(self) transitioned = [] incomplete = [] for obj_uid, obj in objects.items(): part = obj # can't transition inactive items if workflow.getInfoFor(part, 'inactive_state', '') == 'inactive': continue if not checkPermission(PreserveSample, part): continue # grab this object's Preserver and DatePreserved from the form Preserver = form['getPreserver'][0][obj_uid].strip() Preserver = Preserver and Preserver or '' DatePreserved = form['getDatePreserved'][0][obj_uid].strip() DatePreserved = DatePreserved and DateTime(DatePreserved) or '' # write them to the sample part.setPreserver(Preserver) part.setDatePreserved(DatePreserved) # transition the object if both values are present if Preserver and DatePreserved: workflow.doActionFor(part, action) transitioned.append(part.id) else: incomplete.append(part.id) part.reindexObject() part.aq_parent.reindexObject() message = None if len(transitioned) > 1: message = _('${items} are waiting to be received.', mapping={'items': safe_unicode(', '.join(transitioned))}) self.context.plone_utils.addPortalMessage(message, 'info') elif len(transitioned) == 1: message = _('${item} is waiting to be received.', mapping={'item': safe_unicode(', '.join(transitioned))}) self.context.plone_utils.addPortalMessage(message, 'info') if not message: message = _('No changes made.') self.context.plone_utils.addPortalMessage(message, 'info') if len(incomplete) > 1: message = _('${items} are missing Preserver or Date Preserved', mapping={'items': safe_unicode(', '.join(incomplete))}) self.context.plone_utils.addPortalMessage(message, 'error') elif len(incomplete) == 1: message = _('${item} is missing Preserver or Preservation Date', mapping={'item': safe_unicode(', '.join(incomplete))}) self.context.plone_utils.addPortalMessage(message, 'error') self.destination_url = self.request.get_header("referer", self.context.absolute_url()) self.request.response.redirect(self.destination_url)
def workflow_action_receive(self): # default bika_listing.py/WorkflowAction, but then # print automatic labels. if 'receive' in self.context.bika_setup.getAutoPrintLabels(): size = self.context.bika_setup.getAutoLabelSize() q = "/sticker?size=%s&items=%s" % (size, self.context.getId()) self.destination_url = self.context.absolute_url() + q WorkflowAction.__call__(self)
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) action, _ = WorkflowAction._get_form_workflow_action(self) if action == 'receive' and 'Type' in form: BiospecimenWorkflowAction.__call__(self) else: WorkflowAction.__call__(self)
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) workflow = getToolByName(self.context, 'portal_workflow') rc = getToolByName(self.context, REFERENCE_CATALOG) uc = getToolByName(self.context, 'uid_catalog') action, came_from = WorkflowAction._get_form_workflow_action(self) if action == 'duplicate': selected_services = WorkflowAction._get_selected_items(self) ## Create a copy of the selected services folder = self.context.bika_setup.bika_analysisservices created = [] for service in selected_services.values(): _id = folder.invokeFactory('AnalysisService', id = 'tmp') dup = folder[_id] dup.setTitle('%s (copy)' % service.Title()) _id = renameAfterCreation(dup) dup.edit( description = service.Description(), PointOfCapture = service.getPointOfCapture(), ReportDryMatter = service.getReportDryMatter(), Unit = service.getUnit(), Precision = service.getPrecision(), Price = service.getPrice(), CorporatePrice = service.getCorporatePrice(), VAT = service.getVAT(), Calculation = service.getCalculation(), Instrument = service.getInstrument(), MaxTimeAllowed = service.getMaxTimeAllowed(), DuplicateVariation = service.getDuplicateVariation(), Category = service.getCategory(), Department = service.getDepartment(), Accredited = service.getAccredited(), Uncertainties = service.getUncertainties(), ResultOptions = service.getResultOptions() ) created.append(_id) if len(created) > 1: message = self.context.translation_service.translate( _('Services ${services} were successfully created.', mapping = {'services': ', '.join(created)})) self.destination_url = self.request.get_header("referer", self.context.absolute_url()) else: message = self.context.translation_service.translate( _('Analysis request ${service} was successfully created.', mapping = {'service': ', '.join(created)})) self.destination_url = dup.absolute_url() + "/base_edit" self.context.plone_utils.addPortalMessage(message, 'info') self.request.response.redirect(self.destination_url) else: # default bika_listing.py/WorkflowAction for other transitions WorkflowAction.__call__(self)
def workflow_action_save_analyses_button(self): form = self.request.form workflow = getToolByName(self.context, 'portal_workflow') action, came_from = WorkflowAction._get_form_workflow_action(self) # AR Manage Analyses: save Analyses ar = self.context sample = ar.getSample() objects = WorkflowAction._get_selected_items(self) if not objects: message = _("No analyses have been selected") self.context.plone_utils.addPortalMessage(message, 'info') self.destination_url = self.context.absolute_url() + "/analyses" self.request.response.redirect(self.destination_url) return Analyses = objects.keys() prices = form.get("Price", [None])[0] specs = {} if form.get("min", None): for service_uid in Analyses: specs[service_uid] = { "min": form["min"][0][service_uid], "max": form["max"][0][service_uid], "error": form["error"][0][service_uid] } else: for service_uid in Analyses: specs[service_uid] = {"min": "", "max": "", "error": ""} new = ar.setAnalyses(Analyses, prices=prices, specs=specs) # link analyses and partitions # If Bika Setup > Analyses > 'Display individual sample # partitions' is checked, no Partitions available. # https://github.com/bikalabs/Bika-LIMS/issues/1030 if 'Partition' in form: for service_uid, service in objects.items(): part_id = form['Partition'][0][service_uid] part = sample[part_id] analysis = ar[service.getKeyword()] analysis.setSamplePartition(part) analysis.reindexObject() if new: for analysis in new: # if the AR has progressed past sample_received, we need to bring it back. ar_state = workflow.getInfoFor(ar, 'review_state') if ar_state in ('attachment_due', 'to_be_verified'): # Apply to AR only; we don't want this transition to cascade. ar.REQUEST['workflow_skiplist'].append("retract all analyses") workflow.doActionFor(ar, 'retract') ar.REQUEST['workflow_skiplist'].remove("retract all analyses") ar_state = workflow.getInfoFor(ar, 'review_state') # Then we need to forward new analyses state analysis.updateDueDate() changeWorkflowState(analysis, 'bika_analysis_workflow', ar_state) 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)
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) workflow = getToolByName(self.context, 'portal_workflow') rc = getToolByName(self.context, REFERENCE_CATALOG) uc = getToolByName(self.context, 'uid_catalog') action, came_from = WorkflowAction._get_form_workflow_action(self) if action == 'duplicate': selected_services = WorkflowAction._get_selected_items(self) ## Create a copy of the selected services folder = self.context.bika_setup.bika_analysisservices created = [] for service in selected_services.values(): _id = folder.invokeFactory('AnalysisService', id='tmp') dup = folder[_id] dup.setTitle('%s (copy)' % service.Title()) _id = renameAfterCreation(dup) dup.edit(description=service.Description(), PointOfCapture=service.getPointOfCapture(), ReportDryMatter=service.getReportDryMatter(), Unit=service.getUnit(), Precision=service.getPrecision(), Price=service.getPrice(), CorporatePrice=service.getCorporatePrice(), VAT=service.getVAT(), Calculation=service.getCalculation(), Instrument=service.getInstrument(), MaxTimeAllowed=service.getMaxTimeAllowed(), DuplicateVariation=service.getDuplicateVariation(), Category=service.getCategory(), Department=service.getDepartment(), Accredited=service.getAccredited(), Uncertainties=service.getUncertainties(), ResultOptions=service.getResultOptions()) created.append(_id) if len(created) > 1: message = self.context.translation_service.translate( _('Services ${services} were successfully created.', mapping={'services': ', '.join(created)})) self.destination_url = self.request.get_header( "referer", self.context.absolute_url()) else: message = self.context.translation_service.translate( _('Analysis request ${service} was successfully created.', mapping={'service': ', '.join(created)})) self.destination_url = dup.absolute_url() + "/base_edit" self.context.plone_utils.addPortalMessage(message, 'info') self.request.response.redirect(self.destination_url) else: # default bika_listing.py/WorkflowAction for other transitions WorkflowAction.__call__(self)
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) action, _ = WorkflowAction._get_form_workflow_action(self) if action == 'receive' and 'Type' in form: BiospecimenWorkflowAction.__call__(self) elif action == 'receive' and 'AliquotType' in form: AliquotWorkflowAction.__call__(self) else: WorkflowAction.__call__(self)
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) action, _ = WorkflowAction._get_form_workflow_action(self) if type(action) in (list, tuple): action = action[0] # Call out to the workflow action method method_name = 'workflow_action_' + action method = getattr(self, method_name, False) if method: method() else: WorkflowAction.__call__(self)
def workflow_action_keep(self): workflow = getToolByName(self.context, 'portal_workflow') action, came_from = WorkflowAction._get_form_workflow_action(self) objects = WorkflowAction._get_selected_items(self) for obj_uid, obj in objects.items(): pitem = obj old_d = pitem.Description() new_message = "\n*** Restored in Inventory at " + time.strftime("%c") + " ***\n" pitem.setDescription(old_d + new_message) pitem.reindexObject() workflow.doActionFor(pitem, action) 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)
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) action, came_from = WorkflowAction._get_form_workflow_action(self) if type(action) in (list, tuple): action = action[0] if type(came_from) in (list, tuple): came_from = came_from[0] # Call out to the workflow action method # Use default bika_listing.py/WorkflowAction for other transitions method_name = 'workflow_action_' + action method = getattr(self, method_name, False) if method: method() else: WorkflowAction.__call__(self)
def workflow_action_sample_due(self): form = self.request.form selected_biospecimens = WorkflowAction._get_selected_items(self) biospecimens = [] for uid in selected_biospecimens.keys(): if not form['Barcode'][0][uid] or \ not form['Type'][0][uid]: continue try: obj = selected_biospecimens.get(uid, None) obj.getField('Barcode').set(obj, form['Barcode'][0][uid]) obj.getField('SampleType').set(obj, form['Type'][0][uid]) obj.setId(form['Barcode'][0][uid]) obj.edit(SampleID=obj.getId()) obj.reindexObject() biospecimens.append(obj) except ReferenceException: continue message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, 'info') for biospecimen in biospecimens: doActionFor(biospecimen, 'sample_due') for partition in biospecimen.objectValues('SamplePartition'): doActionFor(partition, 'sample_due') self.destination_url = self.context.absolute_url() if form['portal_type'] == 'Kit' or \ form['portal_type'] == 'SampleBatch': self.destination_url = form['view_url'] self.destination_url += '/biospecimens' self.request.response.redirect(self.destination_url)
def workflow_action_verify(self): # default bika_listing.py/WorkflowAction, but then go to view screen. self.destination_url = self.context.absolute_url() action, came_from = WorkflowAction._get_form_workflow_action(self) if type(came_from) in (list, tuple): came_from = came_from[0] return self.workflow_action_default(action="verify", came_from=came_from)
def workflow_action_deactivate(self): context = self.context selected_elements = WorkflowAction._get_selected_items(self) catalog = getToolByName(self, 'portal_catalog') # import pdb;pdb.set_trace() for uid in selected_elements.keys(): try: obj = selected_elements.get(uid, None) units = [] if obj.portal_type in ['ManagedStorage', 'UnmanagedStorage']: units.append(obj) else: unit_path = '/'.join(obj.getPhysicalPath()) brains = catalog(portal_type=[ 'StorageUnit', 'UnmanagedStorage', 'ManagedStorage' ], path={ 'query': unit_path, 'level': 0 }) units += [brain.getObject() for brain in brains] for unit in units: review_state = context.portal_workflow.getInfoFor( unit, 'inactive_state') if review_state == 'active': context.portal_workflow.doActionFor(unit, 'deactivate') except ReferenceException: pass self.request.response.redirect(context.absolute_url())
def workflow_action_verify(self): # default bika_listing.py/WorkflowAction, but then go to view screen. self.destination_url = self.context.absolute_url() action, came_from = WorkflowAction._get_form_workflow_action(self) if type(came_from) in (list, tuple): came_from = came_from[0] return self.workflow_action_default(action='verify', came_from=came_from)
def workflow_action_aliquot_receive(self): form = self.request.form selected_aliquots = WorkflowAction._get_selected_items(self) aliquots = [] for uid in selected_aliquots.keys(): if not form["AliquotType"][0][uid] or not form["Volume"][0][uid] or not form["Unit"][0][uid]: continue try: aliquot = selected_aliquots.get(uid, None) aliquot.getField("SampleType").set(aliquot, form["AliquotType"][0][uid]) aliquot.getField("Volume").set(aliquot, form["Volume"][0][uid]) unit = "ml" for u in VOLUME_UNITS: if u["ResultValue"] == form["Unit"][0][uid]: unit = u["ResultText"] aliquot.getField("Unit").set(aliquot, unit) aliquot.reindexObject() aliquots.append(aliquot) except ReferenceException: continue message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, "info") for aliquot in aliquots: doActionFor(aliquot, "receive") for partition in aliquot.objectValues("SamplePartition"): doActionFor(partition, "receive") self.destination_url = self.context.absolute_url() if self.context.portal_type == "Project": self.destination_url += "/aliquots" self.request.response.redirect(self.destination_url)
def workflow_action_schedule_sampling(self): """ This function prevent the transition if the fields "SamplingDate" and "ScheduledSamplingSampler" are uncompleted. :return: bool """ from bika.lims.utils.workflow import schedulesampling message = "Not expected transition." # In Samples Folder we have to get each selected item if interfaces.ISamplesFolder.providedBy(self.context): select_objs = WorkflowAction._get_selected_items(self) message = _("Transition done.") for key in select_objs.keys(): sample = select_objs[key] # Getting the sampler sch_sampl = ( self.request.form.get("getScheduledSamplingSampler", None)[0].get(key) if self.request.form.get("getScheduledSamplingSampler", None) else "" ) # Getting the date sampl_date = ( self.request.form.get("getSamplingDate", None)[0].get(key) if self.request.form.get("getSamplingDate", None) else "" ) # Setting both values sample.setScheduledSamplingSampler(sch_sampl) sample.setSamplingDate(sampl_date) # Transitioning the sample success, errmsg = schedulesampling.doTransition(sample) if errmsg == "missing": message = _( "'Sampling date' and 'Define the Sampler for the" + " scheduled sampling' must be completed and saved " + "in order to schedule a sampling. Element: %s" % sample.getId() ) elif errmsg == "cant_trans": message = _("The item %s can't be transitioned." % sample.getId()) else: message = _("Transition done.") self.context.plone_utils.addPortalMessage(message, "info") else: success, errmsg = schedulesampling.doTransition(self.context) if errmsg == "missing": message = _( "'Sampling date' and 'Define the Sampler for the" + " scheduled sampling' must be completed and saved in " + "order to schedule a sampling." ) elif errmsg == "cant_trans": message = _("The item can't be transitioned.") else: message = _("Transition done.") self.context.plone_utils.addPortalMessage(message, "info") # Reload the page in order to show the portal message self.request.response.redirect(self.context.absolute_url()) return success
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) workflow = getToolByName(self.context, 'portal_workflow') rc = getToolByName(self.context, REFERENCE_CATALOG) action, came_from = WorkflowAction._get_form_workflow_action(self) if action == 'reassign': mtool = getToolByName(self.context, 'portal_membership') if not mtool.checkPermission(ManageWorksheets, self.context): # Redirect to WS list msg = _('You do not have sufficient privileges to ' 'manage worksheets.') self.context.plone_utils.addPortalMessage(msg, 'warning') portal = getToolByName(self.context, 'portal_url').getPortalObject() self.destination_url = portal.absolute_url() + "/worksheets" self.request.response.redirect(self.destination_url) return selected_worksheets = WorkflowAction._get_selected_items(self) selected_worksheet_uids = selected_worksheets.keys() if selected_worksheets: changes = False for uid in selected_worksheet_uids: worksheet = selected_worksheets[uid] # Double-check the state first if workflow.getInfoFor(worksheet, 'review_state') == 'open': worksheet.setAnalyst(form['Analyst'][0][uid]) worksheet.reindexObject(idxs=['getAnalyst']) changes = True if changes: 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) else: # default bika_listing.py/WorkflowAction for other transitions WorkflowAction.__call__(self)
def workflow_action_publish(self): action, came_from = WorkflowAction._get_form_workflow_action(self) if not isActive(self.context): message = _('Item is inactive.') self.context.plone_utils.addPortalMessage(message, 'info') self.request.response.redirect(self.context.absolute_url()) return # AR publish preview self.request.response.redirect(self.context.absolute_url() + "/publish")
def workflow_action_save_partitions_button(self): form = self.request.form # Sample Partitions or AR Manage Analyses: save Partition Table sample = self.context.portal_type == 'Sample' and self.context or\ self.context.getSample() part_prefix = sample.getId() + "-P" nr_existing = len(sample.objectIds()) nr_parts = len(form['PartTitle'][0]) # add missing parts if nr_parts > nr_existing: for i in range(nr_parts - nr_existing): part = _createObjectByType("SamplePartition", sample, tmpID()) part.setDateReceived = DateTime() part.processForm() # remove excess parts if nr_existing > nr_parts: for i in range(nr_existing - nr_parts): part = sample['%s%s' % (part_prefix, nr_existing - i)] analyses = part.getAnalyses() for a in analyses: a.setSamplePartition(None) sample.manage_delObjects([ '%s%s' % (part_prefix, nr_existing - i), ]) # modify part container/preservation for part_uid, part_id in form['PartTitle'][0].items(): part = sample["%s%s" % (part_prefix, part_id.split(part_prefix)[1])] part.edit( Container=form['getContainer'][0][part_uid], Preservation=form['getPreservation'][0][part_uid], ) part.reindexObject() # Adding the Security Seal Intact checkbox's value to the container object container_uid = form['getContainer'][0][part_uid] uc = getToolByName(self.context, 'uid_catalog') cbr = uc(UID=container_uid) if cbr and len(cbr) > 0: container_obj = cbr[0].getObject() else: continue value = form.get('setSecuritySealIntact', {}).get(part_uid, '') == 'on' container_obj.setSecuritySealIntact(value) objects = WorkflowAction._get_selected_items(self) if not objects: message = _("No items have been selected") self.context.plone_utils.addPortalMessage(message, 'info') if self.context.portal_type == 'Sample': # in samples his table is on 'Partitions' tab self.destination_url = self.context.absolute_url() +\ "/partitions" else: # in ar context this table is on 'ManageAnalyses' tab self.destination_url = self.context.absolute_url() +\ "/analyses" self.request.response.redirect(self.destination_url)
def workflow_action_schedule_sampling(self): """ This function prevent the transition if the fields "SamplingDate" and "ScheduledSamplingSampler" are uncompleted. :return: bool """ from bika.lims.utils.workflow import schedulesampling message = 'Not expected transition.' # In Samples Folder we have to get each selected item if interfaces.ISamplesFolder.providedBy(self.context): select_objs = WorkflowAction._get_selected_items(self) message = _('Transition done.') for key in select_objs.keys(): sample = select_objs[key] # Getting the sampler sch_sampl = self.request.form.get( 'getScheduledSamplingSampler', None)[0].get(key) if\ self.request.form.get( 'getScheduledSamplingSampler', None) else '' # Getting the date sampl_date = self.request.form.get( 'getSamplingDate', None)[0].get(key) if\ self.request.form.get( 'getSamplingDate', None) else '' # Setting both values sample.setScheduledSamplingSampler(sch_sampl) sample.setSamplingDate(sampl_date) # Transitioning the sample success, errmsg = schedulesampling.doTransition(sample) if errmsg == 'missing': message = _( "'Sampling date' and 'Define the Sampler for the" + " scheduled sampling' must be completed and saved " + "in order to schedule a sampling. Element: %s" % sample.getId()) elif errmsg == 'cant_trans': message = _( "The item %s can't be transitioned." % sample.getId()) else: message = _('Transition done.') self.context.plone_utils.addPortalMessage(message, 'info') else: success, errmsg = schedulesampling.doTransition(self.context) if errmsg == 'missing': message = _( "'Sampling date' and 'Define the Sampler for the" + " scheduled sampling' must be completed and saved in " + "order to schedule a sampling.") elif errmsg == 'cant_trans': message = _("The item can't be transitioned.") else: message = _('Transition done.') self.context.plone_utils.addPortalMessage(message, 'info') # Reload the page in order to show the portal message self.request.response.redirect(self.context.absolute_url()) return success
def __call__(self): form = self.request.form CheckAuthenticator(form) workflow = getToolByName(self.context, 'portal_workflow') rc = getToolByName(self.context, REFERENCE_CATALOG) action, came_from = WorkflowAction._get_form_workflow_action(self) if action == 'reassign': mtool = getToolByName(self.context, 'portal_membership') if not mtool.checkPermission(ManageWorksheets, self.context): # Redirect to WS list msg = _('You do not have sufficient privileges to ' 'manage worksheets.') self.context.plone_utils.addPortalMessage(msg, 'warning') portal = getToolByName(self.context, 'portal_url').getPortalObject() self.destination_url = portal.absolute_url() + "/worksheets" self.request.response.redirect(self.destination_url) return selected_worksheets = WorkflowAction._get_selected_items(self) selected_worksheet_uids = selected_worksheets.keys() if selected_worksheets: changes = False for uid in selected_worksheet_uids: worksheet = selected_worksheets[uid] # Double-check the state first if workflow.getInfoFor(worksheet, 'review_state') == 'open': worksheet.setAnalyst(form['Analyst'][0][uid]) worksheet.reindexObject(idxs=['getAnalyst']) changes = True if changes: 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) else: # default bika_listing.py/WorkflowAction for other transitions WorkflowAction.__call__(self)
def __call__(self): form = self.request.form CheckAuthenticator(form) action, came_from = WorkflowAction._get_form_workflow_action(self) if action == "reassign": mtool = api.get_tool("portal_membership") if not mtool.checkPermission(ManageWorksheets, self.context): # Redirect to WS list msg = _("You do not have sufficient privileges to " "manage worksheets.") self.context.plone_utils.addPortalMessage(msg, "warning") portal = api.get_portal() self.destination_url = portal.absolute_url() + "/worksheets" self.request.response.redirect(self.destination_url) return selected_worksheets = WorkflowAction._get_selected_items(self) selected_worksheet_uids = selected_worksheets.keys() if selected_worksheets: changes = False for uid in selected_worksheet_uids: worksheet = selected_worksheets[uid] # Double-check the state first if api.get_workflow_status_of(worksheet) == "open": analyst = form["Analyst"][0][uid] worksheet.setAnalyst(analyst) worksheet.reindexObject(idxs=["getAnalyst"]) changes = True if changes: message = _("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) else: # default bika_listing.py/WorkflowAction for other transitions WorkflowAction.__call__(self)
def workflow_action_save_partitions_button(self): form = self.request.form # Sample Partitions or AR Manage Analyses: save Partition Table sample = self.context.portal_type == 'Sample' and self.context or\ self.context.getSample() part_prefix = sample.getId() + "-P" nr_existing = len(sample.objectIds()) nr_parts = len(form['PartTitle'][0]) # add missing parts if nr_parts > nr_existing: for i in range(nr_parts - nr_existing): part = _createObjectByType("SamplePartition", sample, tmpID()) part.setDateReceived = DateTime() part.processForm() # remove excess parts if nr_existing > nr_parts: for i in range(nr_existing - nr_parts): part = sample['%s%s' % (part_prefix, nr_existing - i)] for a in part.getBackReferences("AnalysisSamplePartition"): a.setSamplePartition(None) sample.manage_delObjects(['%s%s' % (part_prefix, nr_existing - i), ]) # modify part container/preservation for part_uid, part_id in form['PartTitle'][0].items(): part = sample["%s%s" % (part_prefix, part_id.split(part_prefix)[1])] part.edit( Container=form['getContainer'][0][part_uid], Preservation=form['getPreservation'][0][part_uid], ) part.reindexObject() # Adding the Security Seal Intact checkbox's value to the container object container_uid = form['getContainer'][0][part_uid] uc = getToolByName(self.context, 'uid_catalog') cbr = uc(UID=container_uid) if cbr and len(cbr) > 0: container_obj = cbr[0].getObject() else: continue value = form.get('setSecuritySealIntact', {}).get(part_uid, '') == 'on' container_obj.setSecuritySealIntact(value) objects = WorkflowAction._get_selected_items(self) if not objects: message = _("No items have been selected") self.context.plone_utils.addPortalMessage(message, 'info') if self.context.portal_type == 'Sample': # in samples his table is on 'Partitions' tab self.destination_url = self.context.absolute_url() +\ "/partitions" else: # in ar context this table is on 'ManageAnalyses' tab self.destination_url = self.context.absolute_url() +\ "/analyses" self.request.response.redirect(self.destination_url)
def workflow_action_publish(self): action, came_from = WorkflowAction._get_form_workflow_action(self) if not isActive(self.context): message = _('Item is inactive.') self.context.plone_utils.addPortalMessage(message, 'info') self.request.response.redirect(self.context.absolute_url()) return # AR publish preview uids = self.request.form.get('uids', [self.context.UID()]) items = ",".join(uids) self.request.response.redirect(self.context.portal_url() + "/analysisrequests/publish?items=" + items)
def workflow_action_copy_to_new(self): # Pass the selected AR UIDs in the request, to ar_add. objects = WorkflowAction._get_selected_items(self) if not objects: message = _("No analyses have been selected") self.context.plone_utils.addPortalMessage(message, 'info') referer = self.request.get_header("referer") self.request.response.redirect(referer) return url = self.context.absolute_url() + "/ar_add" + \ "?ar_count={0}".format(len(objects)) + \ "©_from={0}".format(",".join(reversed(objects.keys()))) self.request.response.redirect(url) return
def workflow_action_copy_to_new(self): # Pass the selected AR UIDs in the request, to ar_add. objects = WorkflowAction._get_selected_items(self) if not objects: message = _("No analyses have been selected") self.context.plone_utils.addPortalMessage(message, 'info') referer = self.request.get_header("referer") self.request.response.redirect(referer) return url = self.context.absolute_url() + "/ar_add" + \ "?ar_count={0}".format(len(objects)) + \ "©_from={0}".format(",".join(objects.keys())) self.request.response.redirect(url) return
def workflow_action_receive(self): action, came_from = WorkflowAction._get_form_workflow_action(self) items = [self.context] if came_from == "workflow_action" else self._get_selected_items().values() trans, dest = self.submitTransition(action, came_from, items) if trans and "receive" in self.context.bika_setup.getAutoPrintStickers(): transitioned = [item.id for item in items] tmpl = self.context.bika_setup.getAutoStickerTemplate() q = "/sticker?autoprint=1&template=%s&items=" % tmpl q += ",".join(transitioned) self.request.response.redirect(self.context.absolute_url() + q) elif trans: 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)
def workflow_action_receive(self): action, came_from = WorkflowAction._get_form_workflow_action(self) items = [self.context,] if came_from == 'workflow_action' \ else self._get_selected_items().values() trans, dest = self.submitTransition(action, came_from, items) if trans and 'receive' in self.context.bika_setup.getAutoPrintStickers(): transitioned = [item.id for item in items] tmpl = self.context.bika_setup.getAutoStickerTemplate() q = "/sticker?template=%s&items=" % tmpl q += ",".join(transitioned) self.request.response.redirect(self.context.absolute_url() + q) elif trans: 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)
def workflow_action_receive(self): action, came_from = WorkflowAction._get_form_workflow_action(self) items = [self.context,] if came_from == 'workflow_action' \ else self._get_selected_items().values() trans, dest = self.submitTransition(action, came_from, items) if trans and 'receive' in self.context.bika_setup.getAutoPrintLabels(): transitioned = [item.id for item in items] size = self.context.bika_setup.getAutoLabelSize() q = "/sticker?size=%s&items=" % size q += ",".join(transitioned) self.request.response.redirect(self.context.absolute_url() + q) elif trans: 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)
def workflow_action_sample_due(self): form = self.request.form selected_biospecimens = WorkflowAction._get_selected_items(self) biospecimens = [] for uid in selected_biospecimens.keys(): if not form['Barcode'][0][uid] or \ not form['Type'][0][uid]: continue try: obj = selected_biospecimens.get(uid, None) if 'Barcode' in form and form['Barcode'][0][uid]: obj.getField('Barcode').set(obj, form['Barcode'][0][uid]) obj.setId(form['Barcode'][0][uid]) if 'Type' in form and form['Type'][0][uid]: obj.getField('SampleType').set(obj, form['Type'][0][uid]) if 'FrozenTime' in form and form['FrozenTime'][0][uid]: if not self.frozen_time_format_is_valid(form['FrozenTime'][0][uid]): self.context.plone_utils.addPortalMessage('Invalid frozen datetime for %s has been removed. Please complete this batch first and then edit the aliquot separately to enter the frozen time.' % form['Barcode'][0][uid], 'error') else: obj.getField('FrozenTime').set(obj, form['FrozenTime'][0][uid]) min_volume = obj.getSampleType().getMinimumVolume() volume_unit = min_volume.split(' ') if min_volume and len(volume_unit) == 2: obj.getField('Volume').set(obj, volume_unit[0]) obj.getField('Unit').set(obj, volume_unit[1]) obj.edit(SampleID=obj.getId()) obj.reindexObject() biospecimens.append(obj) except ReferenceException: continue message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, 'info') for biospecimen in biospecimens: doActionFor(biospecimen, 'sample_due') for partition in biospecimen.objectValues('SamplePartition'): doActionFor(partition, 'sample_due') self.destination_url = self.context.absolute_url() if form['portal_type'] == 'Kit' or \ form['portal_type'] == 'SampleBatch': self.destination_url = form['view_url'] self.destination_url += '/biospecimens' self.request.response.redirect(self.destination_url)
def workflow_action_receive(self): form = self.request.form # print form selected_biospecimens = WorkflowAction._get_selected_items(self) biospecimens = [] for uid in selected_biospecimens.keys(): if not form['Volume'][0][uid] or \ not form['Unit'][0][uid] or \ not form['SubjectID'][0][uid]: continue try: obj = selected_biospecimens.get(uid, None) obj.getField('Volume').set(obj, form['Volume'][0][uid]) obj.getField('SubjectID').set(obj, form['SubjectID'][0][uid]) if 'Unit' in form and form['Unit'][0][uid]: unit = 'ml' for u in VOLUME_UNITS: if u['ResultText'] == form['Unit'][0][uid]: unit = u['ResultText'] obj.getField('Unit').set(obj, unit) location = obj.getStorageLocation() if location: doActionFor(location, 'occupy') obj.reindexObject() biospecimens.append(obj) except ReferenceException: continue message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, 'info') for biospecimen in biospecimens: doActionFor(biospecimen, 'receive') for partition in biospecimen.objectValues('SamplePartition'): doActionFor(partition, 'receive') self.destination_url = self.context.absolute_url() if form['portal_type'] == 'Kit' or \ form['portal_type'] == 'SampleBatch': self.destination_url = form['view_url'] self.destination_url += '/biospecimens' self.request.response.redirect(self.destination_url)
def workflow_action_save_partitions_button(self): form = self.request.form # Sample Partitions or AR Manage Analyses: save Partition Table sample = self.context.portal_type == 'Sample' and self.context or\ self.context.getSample() part_prefix = sample.getId() + "-P" nr_existing = len(sample.objectIds()) nr_parts = len(form['PartTitle'][0]) # add missing parts if nr_parts > nr_existing: for i in range(nr_parts - nr_existing): part = _createObjectByType("SamplePartition", sample, tmpID()) part.setDateReceived = DateTime() part.processForm() # remove excess parts if nr_existing > nr_parts: for i in range(nr_existing - nr_parts): part = sample['%s%s' % (part_prefix, nr_existing - i)] for a in part.getBackReferences("AnalysisSamplePartition"): a.setSamplePartition(None) sample.manage_delObjects([ '%s%s' % (part_prefix, nr_existing - i), ]) # modify part container/preservation for part_uid, part_id in form['PartTitle'][0].items(): part = sample["%s%s" % (part_prefix, part_id.split(part_prefix)[1])] part.edit( Container=form['getContainer'][0][part_uid], Preservation=form['getPreservation'][0][part_uid], ) part.reindexObject() objects = WorkflowAction._get_selected_items(self) if not objects: message = _("No items have been selected") self.context.plone_utils.addPortalMessage(message, 'info') if self.context.portal_type == 'Sample': # in samples his table is on 'Partitions' tab self.destination_url = self.context.absolute_url() +\ "/partitions" else: # in ar context this table is on 'ManageAnalyses' tab self.destination_url = self.context.absolute_url() +\ "/analyses" self.request.response.redirect(self.destination_url)
def workflow_action_receive(self): form = self.request.form # print form selected_biospecimens = WorkflowAction._get_selected_items(self) biospecimens = [] for uid in selected_biospecimens.keys(): if not form['Barcode'][0][uid] or \ not form['Type'][0][uid] or \ not form['Volume'][0][uid] or \ not form['Unit'][0][uid] or \ not form['SubjectID'][0][uid]: continue try: obj = selected_biospecimens.get(uid, None) obj.getField('Barcode').set(obj, form['Barcode'][0][uid]) obj.getField('SampleType').set(obj, form['Type'][0][uid]) obj.getField('Volume').set(obj, form['Volume'][0][uid]) obj.getField('SubjectID').set(obj, form['SubjectID'][0][uid]) unit = 'ml' for u in VOLUME_UNITS: if u['ResultValue'] == form['Unit'][0][uid]: unit = u['ResultText'] obj.getField('Unit').set(obj, unit) obj.reindexObject() biospecimens.append(obj) except ReferenceException: continue message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, 'info') for biospecimen in biospecimens: doActionFor(biospecimen, 'receive') for partition in biospecimen.objectValues('SamplePartition'): doActionFor(partition, 'receive') self.destination_url = self.context.absolute_url() if self.context.portal_type == 'Project': self.destination_url += '/biospecimens' self.request.response.redirect(self.destination_url)
def workflow_action_publish(self): action, came_from = WorkflowAction._get_form_workflow_action(self) if not isActive(self.context): message = _('Item is inactive.') self.context.plone_utils.addPortalMessage(message, 'info') self.request.response.redirect(self.context.absolute_url()) return # publish entire AR. self.context.setDatePublished(DateTime()) transitioned = self.doPublish(self.context, self.request, action, [self.context, ])() if len(transitioned) == 1: message = _( '${items} published.', mapping={'items': safe_unicode(', '.join(transitioned))}) else: message = _("No items were published") self.context.plone_utils.addPortalMessage(message, 'info') self.destination_url = self.request.get_header("referer", self.context.absolute_url()) self.request.response.redirect(self.destination_url)
def workflow_action_aliquot_receive(self): form = self.request.form selected_aliquots = WorkflowAction._get_selected_items(self) aliquots = [] for uid in selected_aliquots.keys(): if not form['AliquotType'][0][uid] or \ not form['Volume'][0][uid] or \ not form['Unit'][0][uid]: continue try: aliquot = selected_aliquots.get(uid, None) aliquot.getField('SampleType').set(aliquot, form['AliquotType'][0][uid]) aliquot.getField('Volume').set(aliquot, form['Volume'][0][uid]) unit = 'ml' for u in VOLUME_UNITS: if u['ResultValue'] == form['Unit'][0][uid]: unit = u['ResultText'] aliquot.getField('Unit').set(aliquot, unit) aliquot.reindexObject() aliquots.append(aliquot) except ReferenceException: continue message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, 'info') for aliquot in aliquots: doActionFor(aliquot, 'receive') for partition in aliquot.objectValues('SamplePartition'): doActionFor(partition, 'receive') self.destination_url = self.context.absolute_url() if self.context.portal_type == 'Project': self.destination_url += '/aliquots' self.request.response.redirect(self.destination_url)
def workflow_action_submit(self): form = self.request.form rc = getToolByName(self.context, REFERENCE_CATALOG) action, came_from = WorkflowAction._get_form_workflow_action(self) checkPermission = self.context.portal_membership.checkPermission if not isActive(self.context): message = _('Item is inactive.') self.context.plone_utils.addPortalMessage(message, 'info') self.request.response.redirect(self.context.absolute_url()) return # calcs.js has kept item_data and form input interim values synced, # so the json strings from item_data will be the same as the form values item_data = {} if 'item_data' in form: if isinstance(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']) selected_analyses = WorkflowAction._get_selected_items(self) results = {} hasInterims = {} # check that the form values match the database # save them if not. for uid, result in self.request.form.get('Result', [{}])[0].items(): # if the AR has ReportDryMatter set, get dry_result from form. dry_result = '' if hasattr(self.context, 'getReportDryMatter') \ and self.context.getReportDryMatter(): for k, v in self.request.form['ResultDM'][0].items(): if uid == k: dry_result = v break 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 results[uid] = result interimFields = item_data[uid] if len(interimFields) > 0: hasInterims[uid] = True else: hasInterims[uid] = False retested = 'retested' in form and uid in form['retested'] remarks = form.get('Remarks', [{}, ])[0].get(uid, '') # Don't save uneccessary things # https://github.com/bikalabs/Bika-LIMS/issues/766: # Somehow, using analysis.edit() fails silently when # logged in as Analyst. if analysis.getInterimFields() != interimFields or \ analysis.getRetested() != retested or \ analysis.getRemarks() != remarks: analysis.setInterimFields(interimFields) analysis.setRetested(retested) analysis.setRemarks(remarks) # save results separately, otherwise capture date is rewritten if analysis.getResult() != result or \ analysis.getResultDM() != dry_result: analysis.setResultDM(dry_result) analysis.setResult(result) methods = self.request.form.get('Method', [{}])[0] instruments = self.request.form.get('Instrument', [{}])[0] analysts = self.request.form.get('Analyst', [{}])[0] # discover which items may be submitted submissable = [] for uid, analysis in selected_analyses.items(): analysis_active = isActive(analysis) # Need to save the instrument? if uid in instruments and analysis_active: # TODO: Add SetAnalysisInstrument permission # allow_setinstrument = sm.checkPermission(SetAnalysisInstrument) allow_setinstrument = True # ---8<----- if allow_setinstrument == True: # The current analysis allows the instrument regards # to its analysis service and method? if (instruments[uid]==''): previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(None); elif analysis.isInstrumentAllowed(instruments[uid]): previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(instruments[uid]) instrument = analysis.getInstrument() instrument.addAnalysis(analysis) # Need to save the method? if uid in methods and analysis_active: # TODO: Add SetAnalysisMethod permission # allow_setmethod = sm.checkPermission(SetAnalysisMethod) allow_setmethod = True # ---8<----- if allow_setmethod == True and analysis.isMethodAllowed(methods[uid]): analysis.setMethod(methods[uid]) # Need to save the analyst? if uid in analysts and analysis_active: analysis.setAnalyst(analysts[uid]); if uid not in results or not results[uid]: continue can_submit = True # guard_submit does a lot of the same stuff, too. # the code there has also been commented. # we must find a better way to allow dependencies to control # this process. # for dependency in analysis.getDependencies(): # 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 if can_submit and analysis not in submissable: 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') if checkPermission(EditResults, self.context): self.destination_url = self.context.absolute_url() + "/manage_results" else: self.destination_url = self.context.absolute_url() self.request.response.redirect(self.destination_url)
def submit(self): """ Saves the form """ form = self.request.form remarks = form.get('Remarks', [{}])[0] results = form.get('Result', [{}])[0] retested = form.get('retested', {}) methods = form.get('Method', [{}])[0] instruments = form.get('Instrument', [{}])[0] analysts = self.request.form.get('Analyst', [{}])[0] uncertainties = self.request.form.get('Uncertainty', [{}])[0] dlimits = self.request.form.get('DetectionLimit', [{}])[0] selected = WorkflowAction._get_selected_items(self) workflow = getToolByName(self.context, 'portal_workflow') rc = getToolByName(self.context, REFERENCE_CATALOG) sm = getSecurityManager() hasInterims = {} # XXX combine data from multiple bika listing tables. item_data = {} if 'item_data' in form: if type(form['item_data']) == list: for i_d in form['item_data']: for i, d in json.loads(i_d).items(): item_data[i] = d else: item_data = json.loads(form['item_data']) # Iterate for each selected analysis and save its data as needed for uid, analysis in selected.items(): allow_edit = sm.checkPermission(EditResults, analysis) analysis_active = isActive(analysis) # Need to save remarks? if uid in remarks and allow_edit and analysis_active: analysis.setRemarks(remarks[uid]) # Retested? if uid in retested and allow_edit and analysis_active: analysis.setRetested(retested[uid]) # Need to save the instrument? if uid in instruments and analysis_active: # TODO: Add SetAnalysisInstrument permission # allow_setinstrument = sm.checkPermission(SetAnalysisInstrument) allow_setinstrument = True # ---8<----- if allow_setinstrument == True: # The current analysis allows the instrument regards # to its analysis service and method? if (instruments[uid] == ''): previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(None) elif analysis.isInstrumentAllowed(instruments[uid]): previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(instruments[uid]) instrument = analysis.getInstrument() instrument.addAnalysis(analysis) if analysis.meta_type == 'ReferenceAnalysis': instrument.setDisposeUntilNextCalibrationTest( False) # Need to save the method? if uid in methods and analysis_active: # TODO: Add SetAnalysisMethod permission # allow_setmethod = sm.checkPermission(SetAnalysisMethod) allow_setmethod = True # ---8<----- if allow_setmethod == True and analysis.isMethodAllowed( methods[uid]): analysis.setMethod(methods[uid]) # Need to save the analyst? if uid in analysts and analysis_active: analysis.setAnalyst(analysts[uid]) # Need to save the uncertainty? if uid in uncertainties and analysis_active: analysis.setUncertainty(uncertainties[uid]) # Need to save the detection limit? if analysis_active and uid in dlimits and dlimits[uid]: analysis.setDetectionLimitOperand(dlimits[uid]) # Need to save results? if uid in results and results[uid] and allow_edit \ and analysis_active: interims = item_data.get(uid, []) analysis.setInterimFields(interims) analysis.setResult(results[uid]) analysis.reindexObject() can_submit = True deps = analysis.getDependencies() \ if hasattr(analysis, 'getDependencies') else [] for dependency in deps: if workflow.getInfoFor(dependency, 'review_state') in \ ('to_be_sampled', 'to_be_preserved', 'sample_due', 'sample_received'): can_submit = False break if can_submit: # doActionFor transitions the analysis to verif pending, # so must only be done when results are submitted. doActionFor(analysis, 'submit') # Maybe some analyses need to be retracted due to a QC failure # Done here because don't know if the last selected analysis is # a valid QC for the instrument used in previous analyses. # If we add this logic in subscribers.analyses, there's the # possibility to retract analyses before the QC being reached. self.retractInvalidAnalyses() message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, 'info') self.destination_url = self.request.get_header( "referer", self.context.absolute_url()) self.request.response.redirect(self.destination_url)
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)
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)
def __call__(self): form = self.request.form plone.protect.CheckAuthenticator(form) workflow = getToolByName(self.context, 'portal_workflow') pc = getToolByName(self.context, 'portal_catalog') rc = getToolByName(self.context, REFERENCE_CATALOG) # use came_from to decide which UI action was clicked. # "workflow_action" is the action name specified in the # portal_workflow transition url. came_from = "workflow_action" action = form.get(came_from, '') if not action: # workflow_action_button is the action name specified in # the bika_listing_view table buttons. came_from = "workflow_action_button" action = form.get(came_from, '') # XXX some browsers agree better than others about our JS ideas. if type(action) == type([]): action = action[0] if not action: if self.destination_url == "": self.destination_url = self.request.get_header("referer", self.context.absolute_url()) self.request.response.redirect(self.destination_url) return if action in ('prepublish', 'publish', 'prepublish'): # We pass a list of AR objects to Publish. # it returns a list of AR IDs which were actually published. ARs_to_publish = [] transitioned = [] if 'paths' in form: for path in form['paths']: item_id = path.split("/")[-1] item_path = path.replace("/" + item_id, '') ar = pc(id = item_id, path = {'query':item_path, 'depth':1})[0].getObject() # can't publish inactive items if not( 'bika_inactive_workflow' in workflow.getChainFor(ar) and \ workflow.getInfoFor(ar, 'inactive_state', '') == 'inactive'): ar.setDatePublished(DateTime()) ARs_to_publish.append(ar) transitioned = Publish(self.context, self.request, action, ARs_to_publish)() if len(transitioned) > 1: message = _('message_items_published', default = '${items} were published.', mapping = {'items': ', '.join(transitioned)}) elif len(transitioned) == 1: message = _('message_item_published', default = '${items} published.', mapping = {'items': ', '.join(transitioned)}) else: message = _('No items were published') message = self.context.translate(message) self.context.plone_utils.addPortalMessage(message, 'info') self.destination_url = self.request.get_header("referer", self.context.absolute_url()) self.request.response.redirect(self.destination_url) else: # default bika_listing.py/WorkflowAction for other transitions WorkflowAction.__call__(self)
def workflow_action_submit(self): form = self.request.form rc = getToolByName(self.context, REFERENCE_CATALOG) action, came_from = WorkflowAction._get_form_workflow_action(self) checkPermission = self.context.portal_membership.checkPermission if not isActive(self.context): message = _('Item is inactive.') self.context.plone_utils.addPortalMessage(message, 'info') self.request.response.redirect(self.context.absolute_url()) return # calcs.js has kept item_data and form input interim values synced, # so the json strings from item_data will be the same as the form values item_data = {} if 'item_data' in form: if isinstance(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']) selected_analyses = WorkflowAction._get_selected_items(self) results = {} hasInterims = {} # check that the form values match the database # save them if not. for uid, result in self.request.form.get('Result', [{}])[0].items(): # Do not save data for analyses that are not selected. if uid not in selected_analyses: continue analysis = selected_analyses[uid] # never save any part of rows with empty result values. # https://jira.bikalabs.com/browse/LIMS-1944: if not result: continue # ignore result if analysis object no longer exists if not analysis: continue # Prevent saving data if the analysis is already transitioned if not (checkPermission(EditResults, analysis) or checkPermission(EditFieldResults, analysis)): title = safe_unicode(analysis.getService().Title()) msgid = _('Result for ${analysis} could not be saved because ' 'it was already submitted by another user.', mapping={'analysis': title}) message = safe_unicode(t(msgid)) self.context.plone_utils.addPortalMessage(message) continue # if the AR has ReportDryMatter set, get dry_result from form. dry_result = '' if hasattr(self.context, 'getReportDryMatter') \ and self.context.getReportDryMatter(): for k, v in self.request.form['ResultDM'][0].items(): if uid == k: dry_result = v break results[uid] = result interimFields = item_data[uid] if len(interimFields) > 0: hasInterims[uid] = True else: hasInterims[uid] = False retested = 'retested' in form and uid in form['retested'] remarks = form.get('Remarks', [{}, ])[0].get(uid, '') # Don't save uneccessary things # https://github.com/bikalabs/Bika-LIMS/issues/766: # Somehow, using analysis.edit() fails silently when # logged in as Analyst. if analysis.getInterimFields() != interimFields or \ analysis.getRetested() != retested or \ analysis.getRemarks() != remarks: analysis.setInterimFields(interimFields) analysis.setRetested(retested) analysis.setRemarks(remarks) # save results separately, otherwise capture date is rewritten if analysis.getResult() != result or \ analysis.getResultDM() != dry_result: analysis.setResultDM(dry_result) analysis.setResult(result) methods = self.request.form.get('Method', [{}])[0] instruments = self.request.form.get('Instrument', [{}])[0] analysts = self.request.form.get('Analyst', [{}])[0] uncertainties = self.request.form.get('Uncertainty', [{}])[0] dlimits = self.request.form.get('DetectionLimit', [{}])[0] # discover which items may be submitted submissable = [] for uid, analysis in selected_analyses.items(): analysis_active = isActive(analysis) # Need to save the instrument? if uid in instruments and analysis_active: # TODO: Add SetAnalysisInstrument permission # allow_setinstrument = sm.checkPermission(SetAnalysisInstrument) allow_setinstrument = True # ---8<----- if allow_setinstrument == True: # The current analysis allows the instrument regards # to its analysis service and method? if (instruments[uid]==''): previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(None); elif analysis.isInstrumentAllowed(instruments[uid]): previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(instruments[uid]) instrument = analysis.getInstrument() instrument.addAnalysis(analysis) # Need to save the method? if uid in methods and analysis_active: # TODO: Add SetAnalysisMethod permission # allow_setmethod = sm.checkPermission(SetAnalysisMethod) allow_setmethod = True # ---8<----- if allow_setmethod == True and analysis.isMethodAllowed(methods[uid]): analysis.setMethod(methods[uid]) # Need to save the analyst? if uid in analysts and analysis_active: analysis.setAnalyst(analysts[uid]) # Need to save the uncertainty? if uid in uncertainties and analysis_active: analysis.setUncertainty(uncertainties[uid]) # Need to save the detection limit? if analysis_active: analysis.setDetectionLimitOperand(dlimits.get(uid, None)) if uid not in results or not results[uid]: continue can_submit = True # guard_submit does a lot of the same stuff, too. # the code there has also been commented. # we must find a better way to allow dependencies to control # this process. # for dependency in analysis.getDependencies(): # 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 if can_submit and analysis not in submissable: submissable.append(analysis) # and then submit them. for analysis in submissable: doActionFor(analysis, 'submit') # LIMS-2366: Finally, when we are done processing all applicable # analyses, we must attempt to initiate the submit transition on the # AR itself. This is for the case where "general retraction" has been # done, or where the last "received" analysis has been removed, and # the AR is in state "received" while there are no "received" analyses # left to trigger the parent transition. if self.context.portal_type == 'Sample': ar = self.context.getAnalysisRequests()[0] elif self.context.portal_type == 'Analysis': ar = self.context.aq_parent else: ar = self.context doActionFor(ar, 'submit') message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, 'info') if checkPermission(EditResults, self.context): self.destination_url = self.context.absolute_url() + "/manage_results" else: self.destination_url = self.context.absolute_url() self.request.response.redirect(self.destination_url)
def retractInvalidAnalyses(self): """ Retract the analyses with validation pending status for which the instrument used failed a QC Test. """ toretract = {} instruments = {} refs = [] rc = getToolByName(self.context, REFERENCE_CATALOG) selected = WorkflowAction._get_selected_items(self) for uid in selected.iterkeys(): # We need to do this instead of using the dict values # directly because all these analyses have been saved before # and don't know if they already had an instrument assigned an = rc.lookupObject(uid) if an.portal_type == 'ReferenceAnalysis': refs.append(an) instrument = an.getInstrument() if instrument and instrument.UID() not in instruments: instruments[instrument.UID()] = instrument for instr in instruments.itervalues(): analyses = instr.getAnalysesToRetract() for a in analyses: if a.UID() not in toretract: toretract[a.UID] = a retracted = [] for analysis in toretract.itervalues(): try: # add a remark to this analysis failedtxt = ulocalized_time(DateTime(), long_format=0) failedtxt = '%s: %s' % (failedtxt, _("Instrument failed reference test")) analysis.setRemarks(failedtxt) # retract the analysis doActionFor(analysis, 'retract') retracted.append(analysis) except: # Already retracted as a dependant from a previous one? pass if len(retracted) > 0: # Create the Retracted Analyses List rep = AnalysesRetractedListReport(self.context, self.request, self.portal_url, 'Retracted analyses', retracted) # Attach the pdf to the ReferenceAnalysis (accessible # from Instrument's Internal Calibration Tests list pdf = rep.toPdf() for ref in refs: ref.setRetractedAnalysesPdfReport(pdf) # Send the email try: rep.sendEmail() except: pass # TODO: mostra una finestra amb els resultats publicats d'AS # que han utilitzat l'instrument des de la seva última # calibració vàlida, amb els emails, telèfons dels # contactes associats per a una intervenció manual pass
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)
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)
def workflow_action_submit(self): form = self.request.form rc = getToolByName(self.context, REFERENCE_CATALOG) action, came_from = WorkflowAction._get_form_workflow_action(self) checkPermission = self.context.portal_membership.checkPermission if not isActive(self.context): message = _("Item is inactive.") self.context.plone_utils.addPortalMessage(message, "info") self.request.response.redirect(self.context.absolute_url()) return # calcs.js has kept item_data and form input interim values synced, # so the json strings from item_data will be the same as the form values item_data = {} if "item_data" in form: if isinstance(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"]) selected_analyses = WorkflowAction._get_selected_items(self) results = {} hasInterims = {} # check that the form values match the database # save them if not. for uid, result in self.request.form.get("Result", [{}])[0].items(): # Do not save data for analyses that are not selected. if uid not in selected_analyses: continue analysis = selected_analyses[uid] # never save any part of rows with empty result values. # https://jira.bikalabs.com/browse/LIMS-1944: if not result: continue # ignore result if analysis object no longer exists if not analysis: continue # Prevent saving data if the analysis is already transitioned if not (checkPermission(EditResults, analysis) or checkPermission(EditFieldResults, analysis)): title = safe_unicode(analysis.getService().Title()) msgid = _( "Result for ${analysis} could not be saved because " "it was already submitted by another user.", mapping={"analysis": title}, ) message = safe_unicode(t(msgid)) self.context.plone_utils.addPortalMessage(message) continue # if the AR has ReportDryMatter set, get dry_result from form. dry_result = "" if hasattr(self.context, "getReportDryMatter") and self.context.getReportDryMatter(): for k, v in self.request.form["ResultDM"][0].items(): if uid == k: dry_result = v break results[uid] = result interimFields = item_data[uid] if len(interimFields) > 0: hasInterims[uid] = True else: hasInterims[uid] = False retested = "retested" in form and uid in form["retested"] remarks = form.get("Remarks", [{}])[0].get(uid, "") # Don't save uneccessary things # https://github.com/bikalabs/Bika-LIMS/issues/766: # Somehow, using analysis.edit() fails silently when # logged in as Analyst. if ( analysis.getInterimFields() != interimFields or analysis.getRetested() != retested or analysis.getRemarks() != remarks ): analysis.setInterimFields(interimFields) analysis.setRetested(retested) analysis.setRemarks(remarks) # save results separately, otherwise capture date is rewritten if analysis.getResult() != result or analysis.getResultDM() != dry_result: analysis.setResultDM(dry_result) analysis.setResult(result) methods = self.request.form.get("Method", [{}])[0] instruments = self.request.form.get("Instrument", [{}])[0] analysts = self.request.form.get("Analyst", [{}])[0] uncertainties = self.request.form.get("Uncertainty", [{}])[0] dlimits = self.request.form.get("DetectionLimit", [{}])[0] # discover which items may be submitted submissable = [] for uid, analysis in selected_analyses.items(): analysis_active = isActive(analysis) # Need to save the instrument? if uid in instruments and analysis_active: # TODO: Add SetAnalysisInstrument permission # allow_setinstrument = sm.checkPermission(SetAnalysisInstrument) allow_setinstrument = True # ---8<----- if allow_setinstrument == True: # The current analysis allows the instrument regards # to its analysis service and method? if instruments[uid] == "": previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(None) elif analysis.isInstrumentAllowed(instruments[uid]): previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(instruments[uid]) instrument = analysis.getInstrument() instrument.addAnalysis(analysis) # Need to save the method? if uid in methods and analysis_active: # TODO: Add SetAnalysisMethod permission # allow_setmethod = sm.checkPermission(SetAnalysisMethod) allow_setmethod = True # ---8<----- if allow_setmethod == True and analysis.isMethodAllowed(methods[uid]): analysis.setMethod(methods[uid]) # Need to save the analyst? if uid in analysts and analysis_active: analysis.setAnalyst(analysts[uid]) # Need to save the uncertainty? if uid in uncertainties and analysis_active: analysis.setUncertainty(uncertainties[uid]) # Need to save the detection limit? if analysis_active: analysis.setDetectionLimitOperand(dlimits.get(uid, None)) if uid not in results or not results[uid]: continue can_submit = True # guard_submit does a lot of the same stuff, too. # the code there has also been commented. # we must find a better way to allow dependencies to control # this process. # for dependency in analysis.getDependencies(): # 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 if can_submit and analysis not in submissable: submissable.append(analysis) # and then submit them. for analysis in submissable: doActionFor(analysis, "submit") # LIMS-2366: Finally, when we are done processing all applicable # analyses, we must attempt to initiate the submit transition on the # AR itself. This is for the case where "general retraction" has been # done, or where the last "received" analysis has been removed, and # the AR is in state "received" while there are no "received" analyses # left to trigger the parent transition. if self.context.portal_type == "Sample": ar = self.context.getAnalysisRequests()[0] elif self.context.portal_type == "Analysis": ar = self.context.aq_parent else: ar = self.context doActionFor(ar, "submit") message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, "info") if checkPermission(EditResults, self.context): self.destination_url = self.context.absolute_url() + "/manage_results" else: self.destination_url = self.context.absolute_url() self.request.response.redirect(self.destination_url)
def workflow_action_verify(self): # default bika_listing.py/WorkflowAction, but then go to view screen. self.destination_url = self.context.absolute_url() WorkflowAction.__call__(self)
def submit(self): """ Saves the form """ form = self.request.form remarks = form.get('Remarks', [{}])[0] results = form.get('Result',[{}])[0] retested = form.get('retested', {}) methods = form.get('Method', [{}])[0] instruments = form.get('Instrument', [{}])[0] analysts = self.request.form.get('Analyst', [{}])[0] uncertainties = self.request.form.get('Uncertainty', [{}])[0] dlimits = self.request.form.get('DetectionLimit', [{}])[0] selected = WorkflowAction._get_selected_items(self) workflow = getToolByName(self.context, 'portal_workflow') rc = getToolByName(self.context, REFERENCE_CATALOG) sm = getSecurityManager() hasInterims = {} # XXX combine data from multiple bika listing tables. item_data = {} if 'item_data' in form: if type(form['item_data']) == list: for i_d in form['item_data']: for i, d in json.loads(i_d).items(): item_data[i] = d else: item_data = json.loads(form['item_data']) # Iterate for each selected analysis and save its data as needed for uid, analysis in selected.items(): allow_edit = sm.checkPermission(EditResults, analysis) analysis_active = isActive(analysis) # Need to save remarks? if uid in remarks and allow_edit and analysis_active: analysis.setRemarks(remarks[uid]) # Retested? if uid in retested and allow_edit and analysis_active: analysis.setRetested(retested[uid]) # Need to save the instrument? if uid in instruments and analysis_active: # TODO: Add SetAnalysisInstrument permission # allow_setinstrument = sm.checkPermission(SetAnalysisInstrument) allow_setinstrument = True # ---8<----- if allow_setinstrument == True: # The current analysis allows the instrument regards # to its analysis service and method? if (instruments[uid]==''): previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(None); elif analysis.isInstrumentAllowed(instruments[uid]): previnstr = analysis.getInstrument() if previnstr: previnstr.removeAnalysis(analysis) analysis.setInstrument(instruments[uid]) instrument = analysis.getInstrument() instrument.addAnalysis(analysis) if analysis.meta_type == 'ReferenceAnalysis': instrument.setDisposeUntilNextCalibrationTest(False) # Need to save the method? if uid in methods and analysis_active: # TODO: Add SetAnalysisMethod permission # allow_setmethod = sm.checkPermission(SetAnalysisMethod) allow_setmethod = True # ---8<----- if allow_setmethod == True and analysis.isMethodAllowed(methods[uid]): analysis.setMethod(methods[uid]) # Need to save the analyst? if uid in analysts and analysis_active: analysis.setAnalyst(analysts[uid]); # Need to save the uncertainty? if uid in uncertainties and analysis_active: analysis.setUncertainty(uncertainties[uid]) # Need to save the detection limit? if analysis_active and uid in dlimits and dlimits[uid]: analysis.setDetectionLimitOperand(dlimits[uid]) # Need to save results? if uid in results and results[uid] and allow_edit \ and analysis_active: interims = item_data.get(uid, []) analysis.setInterimFields(interims) analysis.setResult(results[uid]) analysis.reindexObject() can_submit = True deps = analysis.getDependencies() \ if hasattr(analysis, 'getDependencies') else [] for dependency in deps: if workflow.getInfoFor(dependency, 'review_state') in \ ('to_be_sampled', 'to_be_preserved', 'sample_due', 'sample_received'): can_submit = False break if can_submit: # doActionFor transitions the analysis to verif pending, # so must only be done when results are submitted. doActionFor(analysis, 'submit') # Maybe some analyses need to be retracted due to a QC failure # Done here because don't know if the last selected analysis is # a valid QC for the instrument used in previous analyses. # If we add this logic in subscribers.analyses, there's the # possibility to retract analyses before the QC being reached. self.retractInvalidAnalyses() message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message, 'info') self.destination_url = self.request.get_header("referer", self.context.absolute_url()) self.request.response.redirect(self.destination_url)
def workflow_action_save_analyses_button(self): form = self.request.form workflow = getToolByName(self.context, 'portal_workflow') bsc = self.context.bika_setup_catalog action, came_from = WorkflowAction._get_form_workflow_action(self) # AR Manage Analyses: save Analyses ar = self.context sample = ar.getSample() objects = WorkflowAction._get_selected_items(self) if not objects: message = _("No analyses have been selected") self.context.plone_utils.addPortalMessage(message, 'info') self.destination_url = self.context.absolute_url() + "/analyses" self.request.response.redirect(self.destination_url) return Analyses = objects.keys() prices = form.get("Price", [None])[0] # Hidden analyses? # https://jira.bikalabs.com/browse/LIMS-1324 outs = [] hiddenans = form.get('Hidden', {}) for uid in Analyses: hidden = hiddenans.get(uid, '') hidden = True if hidden == 'on' else False outs.append({'uid': uid, 'hidden': hidden}) ar.setAnalysisServicesSettings(outs) specs = {} if form.get("min", None): for service_uid in Analyses: service = objects[service_uid] keyword = service.getKeyword() specs[service_uid] = { "min": form["min"][0][service_uid], "max": form["max"][0][service_uid], "warn_min": form["warn_min"][0][service_uid], "warn_max": form["warn_max"][0][service_uid], "keyword": keyword, "uid": service_uid, } else: for service_uid in Analyses: service = objects[service_uid] keyword = service.getKeyword() specs[service_uid] = ResultsRangeDict(keyword=keyword, uid=service_uid) new = ar.setAnalyses(Analyses, prices=prices, specs=specs.values()) # link analyses and partitions # If Bika Setup > Analyses > 'Display individual sample # partitions' is checked, no Partitions available. # https://github.com/bikalabs/Bika-LIMS/issues/1030 if 'Partition' in form: for service_uid, service in objects.items(): part_id = form['Partition'][0][service_uid] part = sample[part_id] analysis = ar[service.getKeyword()] analysis.setSamplePartition(part) analysis.reindexObject() partans = part.getAnalyses() partans.append(analysis) part.setAnalyses(partans) part.reindexObject() if new: ar_state = getCurrentState(ar) if wasTransitionPerformed(ar, 'to_be_verified'): # Apply to AR only; we don't want this transition to cascade. ar.REQUEST['workflow_skiplist'].append("retract all analyses") workflow.doActionFor(ar, 'retract') ar.REQUEST['workflow_skiplist'].remove("retract all analyses") ar_state = getCurrentState(ar) for analysis in new: changeWorkflowState(analysis, 'bika_analysis_workflow', ar_state) 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)