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.UID() 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 _create_user(self): """Create a new user """ def error(field, message): if field: message = "%s: %s" % (field, message) self.context.plone_utils.addPortalMessage(message, 'error') return self.request.response.redirect(self.context.absolute_url() + "/login_details") form = self.request.form contact = self.context password = safe_unicode(form.get('password', '')).encode('utf-8') username = safe_unicode(form.get('username', '')).encode('utf-8') confirm = form.get('confirm', '') email = safe_unicode(form.get('email', '')).encode('utf-8') if not username: return error('username', PMF("Input is required but not given.")) if not email: return error('email', PMF("Input is required but not given.")) reg_tool = self.context.portal_registration properties = self.context.portal_properties.site_properties # if properties.validate_email: # password = reg_tool.generatePassword() # else: if password != confirm: return error('password', PMF("Passwords do not match.")) if not password: return error('password', PMF("Input is required but not given.")) if not confirm: return error('password', PMF("Passwords do not match.")) if len(password) < 5: return error('password', PMF("Passwords must contain at least 5 letters.")) try: reg_tool.addMember(username, password, properties={ 'username': username, 'email': email, 'fullname': username }) except ValueError, msg: return error(None, msg)
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_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 __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 __call__(self): if not (getSecurityManager().checkPermission(EditWorksheet, self.context)): self.request.response.redirect(self.context.absolute_url()) return # Deny access to foreign analysts if checkUserManage(self.context, self.request) == False: return [] showRejectionMessage(self.context) translate = self.context.translate form_id = self.form_id form = self.request.form rc = getToolByName(self.context, REFERENCE_CATALOG) if 'submitted' in form: if 'getWorksheetTemplate' in form and form['getWorksheetTemplate']: layout = self.context.getLayout() wst = rc.lookupObject(form['getWorksheetTemplate']) client_title = form.get('client', 'any') self.request['context_uid'] = self.context.UID() self.context.applyWorksheetTemplate(wst, client_title=client_title) if len(self.context.getLayout()) != len(layout): self.context.plone_utils.addPortalMessage( PMF("Changes saved.")) self.request.RESPONSE.redirect( self.context.absolute_url() + "/manage_results") else: self.context.plone_utils.addPortalMessage( _("No analyses were added to this worksheet.")) self.request.RESPONSE.redirect( self.context.absolute_url() + "/add_analyses") self._process_request() if self.request.get('table_only', '') == self.form_id: return self.contents_table() elif self.request.get('rows_only', '') == self.form_id: return self.contents_table() else: return self.template()
def workflow_action_default(self, action, came_from): if came_from == 'workflow_action': # jsonapi, I believe, ends up here. items = [self.context, ] else: # normal bika_listing. items = self._get_selected_items().values() if items: trans, dest = self.submitTransition(action, came_from, items) if trans: message = PMF('Changes saved.') self.context.plone_utils.addPortalMessage(message, 'info') if dest: self.request.response.redirect(dest) return else: message = _('No items selected') self.context.plone_utils.addPortalMessage(message, 'warn') self.request.response.redirect(self.destination_url) return
def workflow_action_default(self, action, came_from): if came_from in ['workflow_action', 'edit']: # If a single item was acted on we will create the item list # manually from this item itself. Otherwise, bika_listing will # pass a list of selected items in the requyest. items = [self.context, ] else: # normal bika_listing. items = self._get_selected_items().values() if items: trans, dest = self.submitTransition(action, came_from, items) if trans: message = PMF('Changes saved.') self.context.plone_utils.addPortalMessage(message, 'info') if dest: self.request.response.redirect(dest) return else: message = _('No items selected') self.context.plone_utils.addPortalMessage(message, 'warn') self.request.response.redirect(self.destination_url) return
def workflow_action_send_to_lab(self): """Redirects the user to the requisition form automatically generated due to the send_to_lab transition """ logger.info("SampleARWorkflowAction.workflow_action_send_to_lab") action, came_from = self._get_form_workflow_action() if not get_field_value(self.context, "Courier"): message = "Cannot send to the lab. Courier is not set" self.context.plone_utils.addPortalMessage(message, "error") self.request.response.redirect(self.context.absolute_url()) return trans, dest = self.submitTransition(action, came_from, [self.context]) if trans: message = PMF('Changes saved.') self.context.plone_utils.addPortalMessage(message, 'info') # TODO Page does not get refreshed when displaying pdf #self.destination_url = '{}/workflow_action?workflow_action=download_requisition'\ # .format(self.context.absolute_url()) self.destination_url = self.context.absolute_url() self.request.response.redirect(self.destination_url) else: return
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)
'MemberDiscountApplies', default=False, write_permission=ManageClients, widget=atapi.BooleanWidget(label=_("Member discount applies"), ), ), atapi.StringField( 'ClientType', required=1, default='noncorporate', write_permission=ManageClients, vocabulary=CLIENT_TYPES, widget=atapi.SelectionWidget(label=_("Client Type"), ), ), atapi.LinesField( 'EmailSubject', schemata=PMF('Preferences'), default=[ 'ar', ], vocabulary=EMAIL_SUBJECT_OPTIONS, widget=atapi.MultiSelectionWidget( description=_('Items to be included in email subject lines'), label=_("Email subject line"), ), ), atapi.ReferenceField( 'DefaultCategories', schemata=PMF('Preferences'), required=0, multiValued=1, vocabulary='getAnalysisCategories',
def __call__(self): form = self.request.form portal = getSite() workbook = None if 'setupexisting' in form and 'existing' in form and form['existing']: fn = form['existing'].split(":") self.dataset_project = fn[0] self.dataset_name = fn[1] path = 'setupdata/%s/%s.xlsx' % \ (self.dataset_name, self.dataset_name) filename = resource_filename(self.dataset_project, path) try: workbook = load_workbook(filename=filename) # , use_iterators=True) except AttributeError: print "" print traceback.format_exc() print "Error while loading ", path elif 'setupfile' in form and 'file' in form and form['file'] and 'projectname' in form and form['projectname']: self.dataset_project = form['projectname'] tmp = tempfile.mktemp() file_content = form['file'].read() open(tmp, 'wb').write(file_content) workbook = load_workbook(filename=tmp) # , use_iterators=True) self.dataset_name = 'uploaded' assert(workbook is not None) adapters = [[name, adapter] for name, adapter in list(getAdapters((self.context, ), ISetupDataImporter))] for sheetname in workbook.get_sheet_names(): transaction.savepoint() ad_name = sheetname.replace(" ", "_") if ad_name in [a[0] for a in adapters]: adapter = [a[1] for a in adapters if a[0] == ad_name][0] adapter(self, workbook, self.dataset_project, self.dataset_name) adapters = [a for a in adapters if a[0] != ad_name] for name, adapter in adapters: transaction.savepoint() adapter(self, workbook, self.dataset_project, self.dataset_name) check = len(self.deferred) while len(self.deferred) > 0: new = self.solve_deferred() logger.info("solved %s of %s deferred references" % ( check - new, check)) if new == check: raise Exception("%s unsolved deferred references: %s" % ( len(self.deferred), self.deferred)) check = new logger.info("Rebuilding bika_setup_catalog") bsc = getToolByName(self.context, 'bika_setup_catalog') bsc.clearFindAndRebuild() logger.info("Rebuilding bika_catalog") bc = getToolByName(self.context, 'bika_catalog') bc.clearFindAndRebuild() logger.info("Rebuilding bika_analysis_catalog") bac = getToolByName(self.context, 'bika_analysis_catalog') bac.clearFindAndRebuild() message = PMF("Changes saved.") self.context.plone_utils.addPortalMessage(message) self.request.RESPONSE.redirect(portal.absolute_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 __init__(self, context, request): super(SamplesView, self).__init__(context, request) request.set('disable_plone.rightcolumn', 1) self.catalog = 'bika_catalog' self.contentFilter = { 'portal_type': 'Sample', 'sort_on': 'created', 'sort_order': 'reverse', 'path': { 'query': "/", 'level': 0 } } self.context_actions = {} self.show_sort_column = False self.show_select_row = False self.show_select_column = True self.allow_edit = True self.form_id = "samples" if self.view_url.find("/samples") > -1: self.request.set('disable_border', 1) else: self.view_url = self.view_url + "/samples" self.icon = self.portal_url + "/++resource++bika.lims.images/sample_big.png" self.title = self.context.translate(_("Samples")) self.description = "" SamplingWorkflowEnabled = self.context.bika_setup.getSamplingWorkflowEnabled( ) mtool = getToolByName(self.context, 'portal_membership') member = mtool.getAuthenticatedMember() user_is_preserver = 'Preserver' in member.getRoles() self.columns = { 'getSampleID': { 'title': _('Sample ID'), 'index': 'getSampleID' }, 'Client': { 'title': _("Client"), 'toggle': True, }, 'Creator': { 'title': PMF('Creator'), 'index': 'Creator', 'toggle': True }, 'Created': { 'title': PMF('Date Created'), 'index': 'created', 'toggle': False }, 'Requests': { 'title': _('Requests'), 'sortable': False, 'toggle': False }, 'getClientReference': { 'title': _('Client Ref'), 'index': 'getClientReference', 'toggle': True }, 'getClientSampleID': { 'title': _('Client SID'), 'index': 'getClientSampleID', 'toggle': True }, 'getSampleTypeTitle': { 'title': _('Sample Type'), 'index': 'getSampleTypeTitle' }, 'getSamplePointTitle': { 'title': _('Sample Point'), 'index': 'getSamplePointTitle', 'toggle': False }, 'getStorageLocation': { 'title': _('Storage Location'), 'toggle': False }, 'SamplingDeviation': { 'title': _('Sampling Deviation'), 'toggle': False }, 'AdHoc': { 'title': _('Ad-Hoc'), 'toggle': False }, 'getSamplingDate': { 'title': _('Sampling Date'), 'index': 'getSamplingDate', 'toggle': True }, 'getDateSampled': { 'title': _('Date Sampled'), 'index': 'getDateSampled', 'toggle': SamplingWorkflowEnabled, 'input_class': 'datepicker_nofuture', 'input_width': '10' }, 'getSampler': { 'title': _('Sampler'), 'toggle': SamplingWorkflowEnabled }, 'getDatePreserved': { 'title': _('Date Preserved'), 'toggle': user_is_preserver, 'input_class': 'datepicker_nofuture', 'input_width': '10' }, 'getPreserver': { 'title': _('Preserver'), 'toggle': user_is_preserver }, 'DateReceived': { 'title': _('Date Received'), 'index': 'getDateReceived', 'toggle': False }, 'state_title': { 'title': _('State'), 'index': 'review_state' }, } self.review_states = [ { 'id': 'default', 'title': _('Active'), 'contentFilter': { 'cancellation_state': 'active', 'sort_on': 'created' }, 'columns': [ 'getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'getSamplingDate', 'getDateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'DateReceived', 'state_title' ] }, { 'id': 'sample_due', 'title': _('Due'), 'contentFilter': { 'review_state': ('to_be_sampled', 'to_be_preserved', 'sample_due'), 'sort_on': 'created', 'sort_order': 'reverse' }, 'columns': [ 'getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSamplingDate', 'getDateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'state_title' ] }, { 'id': 'sample_received', 'title': _('Received'), 'contentFilter': { 'review_state': 'sample_received', 'sort_order': 'reverse', 'sort_on': 'created' }, 'columns': [ 'getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'getSamplingDate', 'getDateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'DateReceived' ] }, { 'id': 'expired', 'title': _('Expired'), 'contentFilter': { 'review_state': 'expired', 'sort_order': 'reverse', 'sort_on': 'created' }, 'columns': [ 'getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'getSamplingDate', 'getDateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'DateReceived' ] }, { 'id': 'disposed', 'title': _('Disposed'), 'contentFilter': { 'review_state': 'disposed', 'sort_order': 'reverse', 'sort_on': 'created' }, 'columns': [ 'getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'getSamplingDate', 'getDateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'DateReceived' ] }, { 'id': 'cancelled', 'title': _('Cancelled'), 'contentFilter': { 'cancellation_state': 'cancelled', 'sort_order': 'reverse', 'sort_on': 'created' }, 'transitions': [ { 'id': 'reinstate' }, ], 'columns': [ 'getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'getSamplingDate', 'DateReceived', 'getDateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'state_title' ] }, ]
def __init__(self, context, request): super(FolderView, self).__init__(context, request) self.catalog = 'bika_catalog' self.contentFilter = { 'portal_type': 'Worksheet', 'review_state': ['open', 'to_be_verified', 'verified', 'rejected'], 'sort_on': 'id', 'sort_order': 'reverse' } self.context_actions = { _('Add'): { 'url': 'worksheet_add', 'icon': '++resource++bika.lims.images/add.png', 'class': 'worksheet_add' } } self.show_table_only = False self.show_sort_column = False self.show_select_row = False self.show_select_all_checkbox = True self.show_select_column = True self.pagesize = 25 self.restrict_results = False request.set('disable_border', 1) self.icon = self.portal_url + "/++resource++bika.lims.images/worksheet_big.png" self.title = self.context.translate(_("Worksheets")) self.description = "" pm = getToolByName(context, "portal_membership") # this is a property of self, because self.getAnalysts returns it self.analysts = getUsers(self, ['Manager', 'LabManager', 'Analyst']) self.analysts = self.analysts.sortedByKey() bsc = getToolByName(context, 'bika_setup_catalog') templates = [ t for t in bsc(portal_type='WorksheetTemplate', inactive_state='active') ] self.templates = [(t.UID, t.Title) for t in templates] self.templates.sort(lambda x, y: cmp(x[1], y[1])) self.instruments = [ (i.UID, i.Title) for i in bsc(portal_type='Instrument', inactive_state='active') ] self.instruments.sort(lambda x, y: cmp(x[1], y[1])) self.templateinstruments = {} for t in templates: i = t.getObject().getInstrument() if i: self.templateinstruments[t.UID] = i.UID() else: self.templateinstruments[t.UID] = '' self.columns = { 'Title': { 'title': _('Worksheet'), 'index': 'sortable_title' }, 'Priority': { 'title': _('Priority'), 'index': 'Priority', 'toggle': True }, 'Analyst': { 'title': _('Analyst'), 'index': 'getAnalyst', 'toggle': True }, 'Template': { 'title': _('Template'), 'toggle': True }, 'Services': { 'title': _('Services'), 'sortable': False, 'toggle': False }, 'SampleTypes': { 'title': _('Sample Types'), 'sortable': False, 'toggle': False }, 'Instrument': { 'title': _('Instrument'), 'sortable': False, 'toggle': False }, 'QC': { 'title': _('QC'), 'sortable': False, 'toggle': False }, 'QCTotals': { 'title': _('QC Samples (Analyses)'), 'sortable': False, 'toggle': False }, 'RoutineTotals': { 'title': _('Routine Samples (Analyses)'), 'sortable': False, 'toggle': False }, 'CreationDate': { 'title': PMF('Date Created'), 'toggle': True, 'index': 'created' }, 'state_title': { 'title': _('State'), 'index': 'review_state' }, } self.review_states = [ { 'id': 'default', 'title': _('All'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': ['open', 'to_be_verified', 'verified'], 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [{ 'id': 'retract' }, { 'id': 'verify' }, { 'id': 'reject' }], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, # getAuthenticatedMember does not work in __init__ # so 'mine' is configured further in 'folderitems' below. { 'id': 'mine', 'title': _('Mine'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': ['open', 'to_be_verified', 'verified', 'rejected'], 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [{ 'id': 'retract' }, { 'id': 'verify' }, { 'id': 'reject' }], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, { 'id': 'open', 'title': _('Open'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': 'open', 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, { 'id': 'to_be_verified', 'title': _('To be verified'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': 'to_be_verified', 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [{ 'id': 'retract' }, { 'id': 'verify' }, { 'id': 'reject' }], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, { 'id': 'verified', 'title': _('Verified'), 'contentFilter': { 'portal_type': 'Worksheet', 'review_state': 'verified', 'sort_on': 'id', 'sort_order': 'reverse' }, 'transitions': [], 'columns': [ 'Title', 'Priority', 'Analyst', 'Template', 'Services', 'SampleTypes', 'Instrument', 'QC', 'QCTotals', 'RoutineTotals', 'CreationDate', 'state_title' ] }, ]
from DateTime import DateTime from AccessControl import ClassSecurityInfo from Products.CMFCore.utils import UniqueObject from Products.CMFCore.permissions import ListFolderContents, \ ModifyPortalContent, View from plone.app import folder from Products.Archetypes.public import * from bika.lims.content.organisation import Organisation from bika.lims.config import ManageBika, PROJECTNAME from bika.lims import PMF, bikaMessageFactory as _ schema = Organisation.schema.copy() + Schema(( StringField('LabURL', schemata = PMF('Address'), write_permission = ManageBika, widget = StringWidget( size = 60, label = _("Lab URL"), description = _("The Laboratory's web address"), ), ), IntegerField('Confidence', schemata = PMF('Accreditation'), widget = IntegerWidget( label = _("Confidence Level %"), description = _("This value is reported at the bottom of all published results"), ), ), BooleanField('LaboratoryAccredited', default = False, schemata = PMF('Accreditation'),
def __init__(self, context, request): super(SamplesView, self).__init__(context, request) request.set('disable_plone.rightcolumn', 1) self.catalog = 'bika_catalog' self.contentFilter = {'portal_type': 'Sample', 'sort_on':'created', 'sort_order': 'reverse', 'path': {'query': "/", 'level': 0 } } # So far we will only print if the sampling workflow is activated if self.context.bika_setup.getSamplingWorkflowEnabled(): self.context_actions = { _('Print sample sheets'): { 'url': 'print_sampling_sheets', 'icon': '++resource++bika.lims.images/print_32.png'} } else: self.context_actions = {} self.show_sort_column = False self.show_select_row = False self.show_select_column = True self.allow_edit = True self.form_id = "samples" if self.view_url.find("/samples") > -1: self.request.set('disable_border', 1) else: self.view_url = self.view_url + "/samples" self.icon = self.portal_url + "/++resource++bika.lims.images/sample_big.png" self.title = self.context.translate(_("Samples")) self.description = "" SamplingWorkflowEnabled = self.context.bika_setup.getSamplingWorkflowEnabled() mtool = getToolByName(self.context, 'portal_membership') member = mtool.getAuthenticatedMember() user_is_preserver = 'Preserver' in member.getRoles() # Check if the filter bar functionality is activated or not self.filter_bar_enabled =\ self.context.bika_setup.getDisplayAdvancedFilterBarForSamples() # Defined in the __init__.py self.columns = { 'getSampleID': { 'title': _('Sample ID'), 'index': 'getSampleID'}, 'Client': { 'title': _("Client"), 'index': 'getClientTitle', 'toggle': True, }, 'Creator': { 'title': PMF('Creator'), 'index': 'Creator', 'toggle': True}, 'Created': { 'title': PMF('Date Created'), 'index': 'created', 'toggle': False}, 'Requests': { 'title': _('Requests'), 'sortable': False, 'toggle': False}, 'getClientReference': { 'title': _('Client Ref'), 'index': 'getClientReference', 'toggle': True}, 'getClientSampleID': { 'title': _('Client SID'), 'index': 'getClientSampleID', 'toggle': True}, 'getSampleTypeTitle': { 'title': _('Sample Type'), 'index': 'getSampleTypeTitle'}, 'getSamplePointTitle': { 'title': _('Sample Point'), 'index': 'getSamplePointTitle', 'toggle': False}, 'getStorageLocation': { 'sortable': False, 'title': _('Storage Location'), 'toggle': False}, 'SamplingDeviation': { 'title': _('Sampling Deviation'), 'sortable': False, 'toggle': False}, 'AdHoc': { 'title': _('Ad-Hoc'), 'sortable': False, 'toggle': False}, 'SamplingDate': { 'title': _('Sampling Date'), 'index': 'getSamplingDate', 'input_class': 'datetimepicker_nofuture autosave', 'input_width': '10', 'toggle': SamplingWorkflowEnabled}, 'DateSampled': { 'title': _('Date Sampled'), 'index': 'getDateSampled', 'toggle': True, 'input_class': 'datetimepicker_nofuture autosave', 'input_width': '10'}, 'getSampler': { 'title': _('Sampler'), 'toggle': SamplingWorkflowEnabled}, 'getScheduledSamplingSampler': { 'title': _('Sampler for scheduled sampling'), 'input_class': 'autosave', 'sortable': False, 'toggle': self.context.bika_setup.getScheduleSamplingEnabled() }, 'getDatePreserved': { 'title': _('Date Preserved'), 'toggle': user_is_preserver, 'input_class': 'datepicker_nofuture', 'input_width': '10'}, 'getPreserver': { 'title': _('Preserver'), 'toggle': user_is_preserver}, 'DateReceived': { 'title': _('Date Received'), 'index': 'getDateReceived', 'toggle': False}, 'state_title': { 'title': _('State'), 'sortable': False, 'index': 'review_state'}, } self.review_states = [ {'id': 'default', 'title': _('Active'), 'contentFilter': {'cancellation_state': 'active', 'sort_on': 'created'}, 'columns': ['getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'SamplingDate', 'getScheduledSamplingSampler', 'DateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'DateReceived', 'state_title']}, {'id': 'to_be_sampled', 'title': _('To be sampled'), 'contentFilter': {'review_state': ('to_be_sampled', 'scheduled_sampling'), 'cancellation_state': 'active', 'sort_on': 'created', 'sort_order': 'reverse'}, 'columns': ['getSampleID', 'Client', 'Requests', 'getClientReference', 'getClientSampleID', 'SamplingDate', 'getScheduledSamplingSampler', 'DateSampled', 'getSampler', 'getPreserver', 'getSampleTypeTitle', 'getSamplePointTitle', 'state_title'], 'transitions': [ {'id': 'schedule_sampling'}, {'id': 'sample'}], }, {'id': 'sample_due', 'title': _('Due'), 'contentFilter': {'review_state': ('to_be_preserved', 'sample_due'), 'sort_on': 'created', 'sort_order': 'reverse'}, 'columns': ['getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'SamplingDate', 'getScheduledSamplingSampler', 'getScheduledSamplingSampler', 'DateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'state_title']}, {'id': 'sample_received', 'title': _('Received'), 'contentFilter': {'review_state':'sample_received', 'sort_order': 'reverse', 'sort_on':'created'}, 'columns': ['getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'SamplingDate', 'getScheduledSamplingSampler', 'DateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'DateReceived']}, {'id':'expired', 'title': _('Expired'), 'contentFilter':{'review_state':'expired', 'sort_order': 'reverse', 'sort_on':'created'}, 'columns': ['getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'SamplingDate', 'getScheduledSamplingSampler', 'DateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'DateReceived']}, {'id':'disposed', 'title': _('Disposed'), 'contentFilter':{'review_state':'disposed', 'sort_order': 'reverse', 'sort_on':'created'}, 'columns': ['getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'SamplingDate', 'getScheduledSamplingSampler', 'DateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'DateReceived']}, {'id':'cancelled', 'title': _('Cancelled'), 'contentFilter': {'cancellation_state': 'cancelled', 'sort_order': 'reverse', 'sort_on':'created'}, 'transitions': [{'id':'reinstate'}, ], 'columns': ['getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'SamplingDate', 'getScheduledSamplingSampler', 'DateReceived', 'DateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'state_title']}, {'id': 'rejected', 'title': _('Rejected'), 'contentFilter': {'review_state': 'rejected', 'sort_order': 'reverse', 'sort_on': 'created'}, 'transitions': [], 'columns': ['getSampleID', 'Client', 'Creator', 'Created', 'Requests', 'getClientReference', 'getClientSampleID', 'getSampleTypeTitle', 'getSamplePointTitle', 'getStorageLocation', 'SamplingDeviation', 'AdHoc', 'SamplingDate', 'DateReceived', 'getDateSampled', 'getSampler', 'getDatePreserved', 'getPreserver', 'state_title']}, ]
from bika.lims.browser.fields import InterimFieldsField from bika.lims.browser.widgets import RecordsWidget as BikaRecordsWidget from bika.lims.interfaces import ICalculation from bika.lims.browser.fields import HistoryAwareReferenceField from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from zope.interface import implements from zope.site.hooks import getSite from zExceptions import Redirect import sys, re from bika.lims import PMF, bikaMessageFactory as _ schema = BikaSchema.copy() + Schema(( InterimFieldsField( 'InterimFields', schemata=PMF('Calculation'), widget=BikaRecordsWidget( label=_("Calculation Interim Fields"), description= _("Define interim fields such as vessel mass, dilution factors, " "should your calculation require them. The field title specified " "here will be used as column headers and field descriptors where " "the interim fields are displayed"), )), HistoryAwareReferenceField( 'DependentServices', schemata=PMF('Calculation'), required=1, multiValued=1, vocabulary_display_path_bound=sys.maxint, allowed_types=('AnalysisService', ),
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)
def _create_user(self): """Create a new user """ def error(field, message): if field: message = "%s: %s" % (field, message) self.context.plone_utils.addPortalMessage(message, 'error') return self.request.response.redirect(self.context.absolute_url() + "/login_details") form = self.request.form contact = self.context password = safe_unicode(form.get('password', '')).encode('utf-8') username = safe_unicode(form.get('username', '')).encode('utf-8') confirm = form.get('confirm', '') email = safe_unicode(form.get('email', '')).encode('utf-8') if not username: return error('username', PMF("Input is required but not given.")) if not email: return error('email', PMF("Input is required but not given.")) reg_tool = self.context.portal_registration # properties = self.context.portal_properties.site_properties # if properties.validate_email: # password = reg_tool.generatePassword() # else: if password != confirm: return error('password', PMF("Passwords do not match.")) if not password: return error('password', PMF("Input is required but not given.")) if not confirm: return error('password', PMF("Passwords do not match.")) if len(password) < 5: return error( 'password', PMF("Passwords must contain at least 5 " "characters.")) # We make use of the existing controlpanel `@@usergroup-userprefs` # view logic to make sure we get all users from all plugins (e.g. LDAP) users_view = UsersOverviewControlPanel(self.context, self.request) users = users_view.doSearch("") for user in users: userid = user.get("id", None) if userid is None: continue user_obj = api.user.get(userid=userid) if user_obj.getUserName() == username: msg = "Username {} already exists, please, choose " \ "another one.".format(username) return error(None, msg) try: reg_tool.addMember(username, password, properties={ 'username': username, 'email': email, 'fullname': username }) except ValueError, msg: return error(None, msg)
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 = bsc(UID=service_uid)[0].getObject() keyword = service.getKeyword() specs[service_uid] = { "min": form["min"][0][service_uid], "max": form["max"][0][service_uid], "error": form["error"][0][service_uid], "keyword": keyword, "uid": service_uid, } else: for service_uid in Analyses: service = bsc(UID=service_uid)[0].getObject() keyword = service.getKeyword() specs[service_uid] = {"min": "", "max": "", "error": "", "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() 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) 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 __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)
security = ClassSecurityInfo() LABEL_AUTO_OPTIONS = DisplayList(( ('None', _('None')), ('register', _('Register')), ('receive', _('Receive')), )) LABEL_AUTO_SIZES = DisplayList(( ('small', _('Small')), ('normal', _('Normal')), )) schema = BikaFolderSchema.copy() + Schema(( IntegerField('PasswordLifetime', schemata = PMF("Security"), required = 1, default = 0, widget = IntegerWidget( label = _("Password lifetime"), description = _("The number of days before a password expires. 0 disables password expiry"), ) ), IntegerField('AutoLogOff', schemata = PMF("Security"), required = 1, default = 0, widget = IntegerWidget( label = _("Automatic log-off"), description = _("The number of minutes before a user is automatically logged off. " "0 disables automatic log-off"),
checkbox_bound=0, label=_('Default Container'), description=_( "Select the default container to be used for this " "analysis service. If the container to be used " "depends on the sample type and preservation " "combination, specify the container in the sample " "type table below"), catalog_name='bika_setup_catalog', base_query={'inactive_state': 'active'}, ), ), PartitionSetupField('PartitionSetup', schemata='Container and Preservation', widget=PartitionSetupWidget( label=PMF("Preservation per sample type"), description=_( "Please specify preservations that differ from the " "analysis service's default preservation per sample " "type here."), ), ), )) schema['id'].widget.visible = False schema['description'].schemata = 'Description' schema['description'].widget.visible = True schema['title'].required = True schema['title'].widget.visible = True schema['title'].schemata = 'Description' schema.moveField('ShortTitle', after='title')
def folderitems(self, full_objects = False): """ >>> portal = layer['portal'] >>> portal_url = portal.absolute_url() >>> from plone.app.testing import SITE_OWNER_NAME >>> from plone.app.testing import SITE_OWNER_PASSWORD Test page batching https://github.com/bikalabs/Bika-LIMS/issues/1276 When visiting the second page, the Water sampletype should be displayed: >>> browser = layer['getBrowser'](portal, loggedIn=True, username=SITE_OWNER_NAME, password=SITE_OWNER_PASSWORD) >>> browser.open(portal_url+"/bika_setup/bika_sampletypes/folder_view?", ... "list_pagesize=10&list_review_state=default&list_pagenumber=2") >>> browser.contents '...Water...' """ #self.contentsMethod = self.context.getFolderContents if not hasattr(self, 'contentsMethod'): self.contentsMethod = getToolByName(self.context, self.catalog) context = aq_inner(self.context) plone_layout = getMultiAdapter((context, self.request), name = u'plone_layout') plone_utils = getToolByName(context, 'plone_utils') plone_view = getMultiAdapter((context, self.request), name = u'plone') portal_properties = getToolByName(context, 'portal_properties') portal_types = getToolByName(context, 'portal_types') workflow = getToolByName(context, 'portal_workflow') site_properties = portal_properties.site_properties norm = getUtility(IIDNormalizer).normalize if self.request.get('show_all', '').lower() == 'true' \ or self.show_all == True \ or self.pagesize == 0: show_all = True else: show_all = False pagenumber = int(self.request.get('pagenumber', 1) or 1) pagesize = self.pagesize start = (pagenumber - 1) * pagesize end = start + pagesize - 1 if (hasattr(self, 'And') and self.And) \ or (hasattr(self, 'Or') and self.Or): # if contentsMethod is capable, we do an AdvancedQuery. if hasattr(self.contentsMethod, 'makeAdvancedQuery'): aq = self.contentsMethod.makeAdvancedQuery(self.contentFilter) if hasattr(self, 'And') and self.And: tmpAnd = And() for q in self.And: tmpAnd.addSubquery(q) aq &= tmpAnd if hasattr(self, 'Or') and self.Or: tmpOr = Or() for q in self.Or: tmpOr.addSubquery(q) aq &= tmpOr brains = self.contentsMethod.evalAdvancedQuery(aq) else: # otherwise, self.contentsMethod must handle contentFilter brains = self.contentsMethod(self.contentFilter) else: brains = self.contentsMethod(self.contentFilter) results = [] self.page_start_index = 0 current_index = -1 for i, obj in enumerate(brains): # we don't know yet if it's a brain or an object path = hasattr(obj, 'getPath') and obj.getPath() or \ "/".join(obj.getPhysicalPath()) if hasattr(obj, 'getObject'): obj = obj.getObject() # check if the item must be rendered or not (prevents from # doing it later in folderitems) and dealing with paging if not self.isItemAllowed(obj): continue # avoid creating unnecessary info for items outside the current # batch; only the path is needed for the "select all" case... # we only take allowed items into account current_index += 1 if not show_all and not (start <= current_index <= end): results.append(dict(path = path, uid = obj.UID())) continue uid = obj.UID() title = obj.Title() description = obj.Description() icon = plone_layout.getIcon(obj) url = obj.absolute_url() relative_url = obj.absolute_url(relative = True) fti = portal_types.get(obj.portal_type) if fti is not None: type_title_msgid = fti.Title() else: type_title_msgid = obj.portal_type url_href_title = '%s at %s: %s' % ( t(type_title_msgid), path, to_utf8(description)) modified = self.ulocalized_time(obj.modified()), # element css classes type_class = 'contenttype-' + \ plone_utils.normalizeString(obj.portal_type) state_class = '' states = {} for w in workflow.getWorkflowsFor(obj): state = w._getWorkflowStateOf(obj).id states[w.state_var] = state state_class += "state-%s " % state results_dict = dict( obj = obj, id = obj.getId(), title = title, uid = uid, path = path, url = url, fti = fti, item_data = json.dumps([]), url_href_title = url_href_title, obj_type = obj.Type, size = obj.getObjSize, modified = modified, icon = icon.html_tag(), type_class = type_class, # a list of lookups for single-value-select fields choices = {}, state_class = state_class, relative_url = relative_url, view_url = url, table_row_class = "", category = 'None', # a list of names of fields that may be edited on this item allow_edit = [], # a list of names of fields that are compulsory (if editable) required = [], # "before", "after" and replace: dictionary (key is column ID) # A snippet of HTML which will be rendered # before/after/instead of the table cell content. before = {}, # { before : "<a href=..>" } after = {}, replace = {}, ) try: self.review_state = workflow.getInfoFor(obj, 'review_state') state_title = workflow.getTitleForStateOnType( self.review_state, obj.portal_type) state_title = t(PMF(state_title)) except: self.review_state = 'active' state_title = None if self.review_state: results_dict['review_state'] = self.review_state for state_var, state in states.items(): if not state_title: state_title = workflow.getTitleForStateOnType( state, obj.portal_type) results_dict[state_var] = state results_dict['state_title'] = state_title # extra classes for individual fields on this item { field_id : "css classes" } results_dict['class'] = {} for name, adapter in getAdapters((obj, ), IFieldIcons): auid = obj.UID() if hasattr(obj, 'UID') and callable(obj.UID) else None if not auid: continue alerts = adapter() # logger.info(str(alerts)) if alerts and auid in alerts: if auid in self.field_icons: self.field_icons[auid].extend(alerts[auid]) else: self.field_icons[auid] = alerts[auid] # Search for values for all columns in obj for key in self.columns.keys(): if hasattr(obj, key): # if the key is already in the results dict # then we don't replace it's value if results_dict.has_key(key): continue value = getattr(obj, key) if callable(value): value = value() results_dict[key] = value results.append(results_dict) return results
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 get_workflow_actions(self): """ Compile a list of possible workflow transitions for items in this Table. """ # cbb return empty list if we are unable to select items if not self.show_select_column: return [] workflow = getToolByName(self.context, 'portal_workflow') # check POST for a specified review_state selection selected_state = self.request.get("%s_review_state"%self.form_id, 'default') # get review_state id=selected_state states = [r for r in self.review_states if r['id'] == selected_state] self.review_state = states and states[0] \ or self.review_states[0] # get all transitions for all items. transitions = {} actions = [] for obj in [i.get('obj', '') for i in self.items]: obj = hasattr(obj, 'getObject') and obj.getObject() or obj for it in workflow.getTransitionsFor(obj): transitions[it['id']] = it # the list is restricted to and ordered by these transitions. if 'transitions' in self.review_state: for transition_dict in self.review_state['transitions']: if transition_dict['id'] in transitions: actions.append(transitions[transition_dict['id']]) else: actions = transitions.values() new_actions = [] # remove any invalid items with a warning for a,action in enumerate(actions): if isinstance(action, dict) \ and 'id' in action: new_actions.append(action) else: logger.warning("bad action in custom_actions: %s. (complete list: %s)."%(action,actions)) # and these are removed if 'hide_transitions' in self.review_state: actions = [a for a in actions if a['id'] not in self.review_state['hide_transitions']] # cheat: until workflow_action is abolished, all URLs defined in # GS workflow setup will be ignored, and the default will apply. # (that means, WorkflowAction-bound URL is called). for i, action in enumerate(actions): actions[i]['url'] = '' # if there is a self.review_state['some_state']['custom_actions'] attribute # on the BikaListingView, add these actions to the list. if 'custom_actions' in self.review_state: for action in self.review_state['custom_actions']: if isinstance(action, dict) \ and 'id' in action: actions.append(action) for a,action in enumerate(actions): actions[a]['title'] = t(PMF(actions[a]['id'] + "_transition_title")) return actions
def translate(id): return t(PMF(id + "_transition_title"))
def get_workflow_actions(self): """ Compile a list of possible workflow transitions for items in this Table. """ # cbb return empty list if we are unable to select items if not self.bika_listing.show_select_column: return [] workflow = getToolByName(self.context, 'portal_workflow') # get all transitions for all items. transitions = {} actions = [] for obj in [i.get('obj', '') for i in self.items]: obj = get_object(obj) for it in workflow.getTransitionsFor(obj): transitions[it['id']] = it # the list is restricted to and ordered by these transitions. if 'transitions' in self.bika_listing.review_state: for tdict in self.bika_listing.review_state['transitions']: if tdict['id'] in transitions: actions.append(transitions[tdict['id']]) else: actions = transitions.values() new_actions = [] # remove any invalid items with a warning for a, action in enumerate(actions): if isinstance(action, dict) \ and 'id' in action: new_actions.append(action) else: logger.warning( "bad action in review_state['transitions']: %s. " "(complete list: %s)." % (action, actions)) actions = new_actions # and these are removed if 'hide_transitions' in self.bika_listing.review_state: hidden_transitions = self.bika_listing.review_state[ 'hide_transitions'] actions = [a for a in actions if a['id'] not in hidden_transitions] # cheat: until workflow_action is abolished, all URLs defined in # GS workflow setup will be ignored, and the default will apply. # (that means, WorkflowAction-bound URL is called). for i, action in enumerate(actions): actions[i]['url'] = '' # if there is a self.review_state['some_state']['custom_transitions'] # attribute on the BikaListingView, add these actions to the list. if 'custom_transitions' in self.bika_listing.review_state: for action in self.bika_listing.review_state['custom_transitions']: if isinstance(action, dict) and 'id' in action: actions.append(action) for a, action in enumerate(actions): actions[a]['title'] = t(PMF(actions[a]['title'])) return actions