def search_analysis_container(container_ids): """Searches an analysis container (Sample or Worksheet) for the id. The priority for searches is as follows: Sample ID, Worksheet ID, Client Sample ID """ # Try by Sample ID (only received samples can be submitted) query = dict(portal_type="AnalysisRequest", getId=container_ids, review_state="sample_received") sample = api.search(query, CATALOG_ANALYSIS_REQUEST_LISTING) if sample: return api.get_object(sample[0]) # Try by Worksheet ID (only open worksheets) query = dict(portal_type="Worksheet", review_state="open", getId=container_ids) worksheet = api.search(query, CATALOG_WORKSHEET_LISTING) if worksheet: return api.get_object(worksheet[0]) # Try by Client Sample ID query = dict(portal_type="AnalysisRequest", getClientSampleID=container_ids, review_state="sample_received") sample = api.search(query, CATALOG_ANALYSIS_REQUEST_LISTING) if sample: return api.get_object(sample[0]) return None
def to_service_uid(uid_brain_obj_str): """Resolves the passed in element to a valid uid. Returns None if the value cannot be resolved to a valid uid """ if api.is_uid(uid_brain_obj_str) and uid_brain_obj_str != "0": return uid_brain_obj_str if api.is_object(uid_brain_obj_str): obj = api.get_object(uid_brain_obj_str) if IAnalysisService.providedBy(obj): return api.get_uid(obj) elif IRoutineAnalysis.providedBy(obj): return obj.getServiceUID() else: logger.error("Type not supported: {}".format(obj.portal_type)) return None if isinstance(uid_brain_obj_str, six.string_types): # Maybe is a keyword? query = dict(portal_type="AnalysisService", getKeyword=uid_brain_obj_str) brains = api.search(query, SETUP_CATALOG) if len(brains) == 1: return api.get_uid(brains[0]) # Or maybe a title query = dict(portal_type="AnalysisService", title=uid_brain_obj_str) brains = api.search(query, SETUP_CATALOG) if len(brains) == 1: return api.get_uid(brains[0]) return None
def search(self, query): """search the catalog """ logger.info("Catalog query={}".format(query)) # Support to set the catalog as a request parameter catalogs = _.to_list(req.get("catalog", None)) if catalogs: return senaiteapi.search(query, catalog=catalogs) # Delegate to the search API of Bika LIMS return senaiteapi.search(query)
def update_rejection_permissions(portal): """Adds the permission 'Reject Analysis Request' and update the permission mappings accordingly """ updated = update_rejection_permissions_for(portal, "bika_ar_workflow", "Reject Analysis Request") if updated: brains = api.search(dict(portal_type="AnalysisRequest"), CATALOG_ANALYSIS_REQUEST_LISTING) update_rolemappings_for(brains, "bika_ar_workflow") updated = update_rejection_permissions_for(portal, "bika_sample_workflow", "Reject Sample") if updated: brains = api.search(dict(portal_type="Sample"), "bika_catalog") update_rolemappings_for(brains, "bika_sample_workflow")
def returnBills(self): """Create's user for patient to login """ aRequest_query_results = api.search({"portal_type": "AnalysisRequest","Complete":True}) logger.info("Results: {0}".format(len(aRequest_query_results))) response = {'status': 'processed'} results = [] if len(aRequest_query_results) > 0: for sample_r in aRequest_query_results: sample = api.get_object(sample_r) sample_object = {} try: sample_object['title'] = sample.Title() sample_object['subtotal'] = sample.getSubtotal() # logger.info('{0}: {1}'.format(sample.Title(),sample.getSubtotal())) except Exception as e: logger.info("Failed to get sample object properties {0}".format(e)) results.append(sample_object) if len(results) > 0: response.update({'status': 'success'}) response.update({'results':results}) return response
def __call__(self): parms = [] # Base query query = dict(portal_type="Analysis", sort_on='getClientTitle') # Filter by client self.add_filter_by_client(query, parms) # Filter by date self.add_filter_by_date(query, parms) # Filter analyses by review_state self.add_filter_by_review_state(query, parms) # Filter analyses by cancellation state self.add_filter_by_cancellation_state(query, parms) # Fetch and fill data data = OrderedDict() analyses = api.search(query, CATALOG_ANALYSIS_LISTING) total_num_analyses = len(analyses) total_num_ars = 0 for analysis in analyses: client = analysis.getClientTitle data_client = data.get(client, {}) request = analysis.getRequestID requests = data_client.get("requests", []) if request not in requests: requests += [request] data_client["requests"] = requests total_num_ars += 1 data_client["analyses"] = data_client.get("analyses", 0) + 1 data[client] = data_client # Generate datalines data_lines = list() for client, data in data.items(): ars_count = len(data.get('requests', [])) ans_count = data.get('analyses', 0) data_lines.append([{"value": client}, {"value": ars_count}, {"value": ans_count}]) if self.request.get('output_format', '') == 'CSV': return self.generate_csv(data_lines) self.report_content = { 'headings': self.headings, 'parms': parms, 'formats': self.formats, 'datalines': data_lines, 'footings': [ [{'value': _('Total'), 'class': 'total_label'}, {'value': total_num_ars}, {'value': total_num_analyses},],] } return {'report_title': t(self.headings['header']), 'report_data': self.template()}
def resume(self): """Resumes the pool and reindex all objects processed """ self.num_calls -= 1 if self.num_calls > 0: return logger.info("Resume actions for {} objects".format(len(self))) # Fetch the objects from the pool processed = list() for brain in api.search(dict(UID=self.objects.keys()), UID_CATALOG): uid = api.get_uid(brain) if uid in processed: # This object has been processed already, do nothing continue # Reindex the object obj = api.get_object(brain) idxs = self.get_indexes(uid) idxs_str = idxs and ', '.join(idxs) or "-- All indexes --" logger.info("Reindexing {}: {}".format(obj.getId(), idxs_str)) obj.reindexObject(idxs=idxs) processed.append(uid) # Cleanup the pool logger.info("Objects processed: {}".format(len(processed))) self.objects = collections.OrderedDict()
def reindex_client_fields(portal): logger.info("Reindexing client fields ...") fields_to_reindex = [ "getClientUID", "getClientID", "getClientTitle", "getClientURL" ] # We only need to reindex those that might be associated to a Client object. # There is no need to reindex objects that already belong to a Client. # Batches were correctly indexed in previous upgrade step portal_types = [ "AnalysisProfile", "AnalysisSpec", "ARTemplate", "SamplePoint" ] query = dict(portal_type=portal_types) brains = api.search(query, UID_CATALOG) total = len(brains) for num, brain in enumerate(brains): if num and num % 100 == 0: logger.info("Reindexing client fields: {}/{}".format(num, total)) obj = api.get_object(brain) obj.reindexObject(idxs=fields_to_reindex) logger.info("Reindexing client fields ... [DONE]")
def reindex_supplier_manufacturers_titles(portal): logger.info("Reindexing title indexes for Suppliers and Manufacturers ...") query = dict(portal_type="Supplier") for brain in api.search(query, SETUP_CATALOG): obj = api.get_object(brain) obj.reindexObject(idxs=["title", "sortable_title"]) logger.info("Reindexing title indexes for Suppliers and Manufacturers ... [DONE]")
def get_methods_vocabulary(self, analysis_brain): """Returns a vocabulary with all the methods available for the passed in analysis, either those assigned to an instrument that are capable to perform the test (option "Allow Entry of Results") and those assigned manually in the associated Analysis Service. The vocabulary is a list of dictionaries. Each dictionary has the following structure: {'ResultValue': <method_UID>, 'ResultText': <method_Title>} :param analysis_brain: A single Analysis brain :type analysis_brain: CatalogBrain :returns: A list of dicts """ uids = analysis_brain.getAllowedMethodUIDs query = { 'portal_type': 'Method', 'inactive_state': 'active', 'UID': uids } brains = api.search(query, 'bika_setup_catalog') if not brains: return [{'ResultValue': '', 'ResultText': _('None')}] return map( lambda brain: { 'ResultValue': brain.UID, 'ResultText': brain.Title }, brains)
def getInstruments(self): """Get the allowed instruments """ query = {"portal_type": "Instrument", "inactive_state": "active"} if self.getRestrictToMethod(): query.update({ "getMethodUIDs": { "query": api.get_uid(self.getRestrictToMethod()), "operator": "or", } }) instruments = api.search(query, "bika_setup_catalog") items = map(lambda i: (i.UID, i.Title), instruments) instrument = self.getInstrument() if instrument: instrument_uids = map(api.get_uid, instruments) if api.get_uid(instrument) not in instrument_uids: items.append( (api.get_uid(instrument), api.get_title(instrument))) items.sort(lambda x, y: cmp(x[1], y[1])) items.insert(0, ("", _("No instrument"))) return DisplayList(list(items))
def reset_samples_usage(self, recursive=True): """Resets the sample usage values (capacity and utilization) for this container. It looks through all children to reset the values. If recursive is set to True, the function reset the samples usage for contained containers too. """ items = filter(self.is_taken, self.getPositionsLayout()) items = map(lambda item: item.get["uid"], items) uids = filter(api.is_uid, items) if not uids: return query = dict(UID=uids) uids_usage = {} for brain in api.search(query, "uid_catalog"): obj = api.get_object(brain) if not IStorageLayoutContainer.providedBy(obj): continue if recursive: obj.reset_samples_usage(recursive=recursive) uids_usage[api.get_uid(obj)] = { "samples_utilization": obj.get_samples_utilization(), "samples_capacity": obj.get_samples_capacity() } new_items = list() for layout_item in self.getPositionsLayout(): item = layout_item.copy() usage = uids_usage.get(item.get("uid"), None) if usage: item.update(usage) new_items.append(item) self.setPositionsLayout(new_items)
def search_analysis_from(container, keywords): """Searches an analysis with the specified keyword within the container """ # Base query query = dict(getKeyword=keywords, portal_type="Analysis", review_state=["unassigned", "assigned"]) # Build the query container = api.get_object(container) container_uid = api.get_uid(container) if IAnalysisRequest.providedBy(container): query.update({"getAncestorsUIDs": container_uid}) elif IWorksheet.providedBy(container): query.update({"getWorksheetUID": container_uid}) else: path = api.get_path(container) raise ValueError("Could not get analyses from {}".format(path)) # Search for a unique result analyses = api.search(query, CATALOG_ANALYSIS_LISTING) if len(analyses) == 1: return api.get_object(analyses[0]) return None
def get_sample_container_info(self): """Returns the storage container this Sample is stored in """ # Search the container the sample is stored in query = { "portal_type": "StorageSamplesContainer", "get_samples_uids": api.get_uid(self.context) } brains = api.search(query, SENAITE_STORAGE_CATALOG) if not brains: return None # Get the data info from the container container = api.get_object(brains[0]) position = container.get_object_position(self.context) position = container.position_to_alpha(position[0], position[1]) return { "uid": api.get_uid(container), "id": api.get_id(container), "title": api.get_title(container), "url": api.get_url(container), "position": position, "full_title": container.get_full_title(), "when": wf.getTransitionDate(self.context, "store"), }
def decouple_analyses_from_sample_workflow(portal): logger.info("Decoupling analyses from sample workflow ...") add_index(portal, catalog_id=CATALOG_ANALYSIS_LISTING, index_name="isSampleReceived", index_attribute="isSampleReceived", index_metatype="BooleanIndex") wf_id = "bika_analysis_workflow" affected_rs = [ "sample_registered", "to_be_sampled", "sampled", "sample_due", "sample_received", "to_be_preserved", "not_requested", "registered" ] wf_tool = api.get_tool("portal_workflow") workflow = wf_tool.getWorkflowById(wf_id) query = dict(portal_type=["Analysis", "DuplicateAnalysis"], review_state=affected_rs) brains = api.search(query, CATALOG_ANALYSIS_LISTING) total = len(brains) for num, brain in enumerate(brains): # Set state analysis = api.get_object(brain) target_state = analysis.getWorksheet() and "assigned" or "unassigned" if num % 100 == 0: logger.info("Restoring state to '{}': {}/{}".format( target_state, num, total)) changeWorkflowState(analysis, wf_id, target_state) # Update role mappings workflow.updateRoleMappingsFor(analysis) # Reindex analysis.reindexObject()
def get_sample_uids(self): """Returns the sample UIDs for which the current Doctor has at least one Analysis Request assigned.""" query = dict(getDoctorUID=api.get_uid(self.context)) ars = api.search(query, CATALOG_ANALYSIS_REQUEST_LISTING) uids = map(lambda brain: brain.getSampleUID, ars) or list() return list(set(uids))
def remove_orphan_reference_analyses(portal): logger.info("Removing orphan reference analyses ...") wf_id = "bika_referenceanalysis_workflow" wf_tool = api.get_tool("portal_workflow") workflow = wf_tool.getWorkflowById(wf_id) query = dict(portal_type="ReferenceAnalysis", review_state="unassigned") brains = api.search(query, CATALOG_ANALYSIS_LISTING) total = len(brains) for num, brain in enumerate(brains): orphan = api.get_object(brain) worksheet = orphan.getWorksheet() if worksheet: logger.info("Reassigning orphan reference: {}/{}".format( num, total)) # This one has a worksheet! reindex and do nothing changeWorkflowState(orphan, wf_id, "assigned") # Update role mappings workflow.updateRoleMappingsFor(orphan) # Reindex orphan.reindexObject() continue elif orphan.getInstrument(): # This is a calibration test, do nothing! if not brain.getInstrumentUID: orphan.reindexObject() total -= 1 continue if num % 100 == 0: logger.info("Removing orphan reference analysis: {}/{}".format( num, total)) # Remove the duplicate orphan.aq_parent.manage_delObjects([orphan.getId()])
def get_ar(sample_id): query = dict(portal_type='AnalysisRequest', getId=sample_id) brains = api.search(query, CATALOG_ANALYSIS_REQUEST_LISTING) try: return api.get_object(brains[0]) except IndexError: pass
def _children_are_ready(obj, transition_id, dettached_states=None): """Returns true if the children of the object passed in (worksheet) have been all transitioned in accordance with the 'transition_id' passed in. If detached_states is provided, children with those states are dismissed, so they will not be taken into account in the evaluation. Nevertheless, at least one child with for which the transition_id performed is required for this function to return true (if all children are in detached states, it always return False). """ query = dict(getWorksheetUID=api.get_uid(obj)) brains = api.search(query, CATALOG_ANALYSIS_LISTING) if not brains: return False detached_count = 0 for brain in brains: if dettached_states and brain.review_state in dettached_states: detached_count += 1 # dismiss the brain and skip the rest of the checks continue if not api.is_active(brain): return False analysis = api.get_object(brain) if not wasTransitionPerformed(analysis, transition_id): return False if detached_count == len(brains): # If all brains are in a detached state, it means that the # condition of at least having one child for which the # transition is performed is not satisfied so return False return False return True
def _get_instruments_brains(self): """Returns all active Instruments :returns: list of brains """ query = {"portal_type": "Instrument", "is_active": True} return api.search(query, "bika_setup_catalog")
def __call__(self): # Get the id of the action to be performed action = self.get_action() if not action: return self.redirect(message=_("No action defined."), level="error") # Get the UIDs of the objects the action needs to be done against uids = self.get_uids() if not uids: return self.redirect(message=_("No items selected."), level="warning") # Find out if there is an adapter registered for the current context # able to handle the requested action adapter_name = "workflow_action_{}".format(action) adapter = queryMultiAdapter((self.context, self.request), interface=IWorkflowActionAdapter, name=adapter_name) if not adapter: # No adapter found, use the generic one adapter = WorkflowActionGenericAdapter(self.context, self.request) else: adapter_module = adapter.__module__ adapter_class = adapter.__class__.__name__ logger.info("Action '{}' managed by {}.{}".format( action, adapter_module, adapter_class)) # Handle the action if IWorkflowActionUIDsAdapter.providedBy(adapter): return adapter(action, uids) objects = api.search(dict(UID=uids), UID_CATALOG) objects = map(api.get_object, objects) return adapter(action, objects)
def update_partitions_role_mappings(portal): """Updates the rolemappings for existing partitions that are in a suitable state, so they can be detached from the primary sample they belong to """ logger.info("Updating role mappings of partitions ...") wf_tool = api.get_tool("portal_workflow") workflow = wf_tool.getWorkflowById("bika_ar_workflow") # States that allow detach transition as defined in workflow definition in # order to query and update role mappings of objects that matter allowed_states = [ "to_be_preserved", "sample_due", "sample_received", "to_be_verified", "verified" ] query = dict(portal_type="AnalysisRequest", isRootAncestor=False, review_state=allowed_states) brains = api.search(query, CATALOG_ANALYSIS_REQUEST_LISTING) total = len(brains) for num, brain in enumerate(brains): if num and num % 100 == 0: logger.info("Updating role mappings of partitions: {}/{}".format( num, total)) partition = api.get_object(brain) workflow.updateRoleMappingsFor(partition) partition.reindexObjectSecurity() logger.info("Updating role mappings of partitions [DONE]")
def reindex_labcontact_sortable_title(portal): logger.info("Reindexing sortable_title for LabContacts ...") query = dict(portal_type="LabContact") for brain in api.search(query, SETUP_CATALOG): obj = api.get_object(brain) obj.reindexObject(idxs=["sortable_title"]) logger.info("Reindexing sortable_title for LabContacts ... [DONE]")
def isQCValid(self): """ Returns True if the results of the last batch of QC Analyses performed against this instrument was within the valid range. For a given Reference Sample, more than one Reference Analyses assigned to this same instrument can be performed and the Results Capture Date might slightly differ amongst them. Thus, this function gets the latest QC Analysis performed, looks for siblings (through RefAnalysisGroupID) and if the results for all them are valid, then returns True. If there is one single Reference Analysis from the group with an out-of-range result, the function returns False """ query = { "portal_type": "ReferenceAnalysis", "getInstrumentUID": self.UID(), "sort_on": "getResultCaptureDate", "sort_order": "reverse", "sort_limit": 1, } brains = api.search(query, CATALOG_ANALYSIS_LISTING) if len(brains) == 0: # There are no Reference Analyses assigned to this instrument yet return True # Look for siblings. These are the QC Analyses that were created # together with this last ReferenceAnalysis and for the same Reference # Sample. If they were added through "Add Reference Analyses" in a # Worksheet, they typically appear in the same slot. group_id = brains[0].getReferenceAnalysesGroupID query = { "portal_type": "ReferenceAnalysis", "getInstrumentUID": self.UID(), "getReferenceAnalysesGroupID": group_id, } brains = api.search(query, CATALOG_ANALYSIS_LISTING) for brain in brains: analysis = api.get_object(brain) results_range = analysis.getResultsRange() if not results_range: continue # Is out of range? out_of_range = is_out_of_range(analysis)[0] if out_of_range: return False # By default, in range return True
def setup_catalogs(portal): """Setup Plone catalogs """ logger.info("*** Setup Catalogs ***") # Setup catalogs by type for type_name, catalogs in CATALOGS_BY_TYPE: at = api.get_tool("archetype_tool") # get the current registered catalogs current_catalogs = at.getCatalogsByType(type_name) # get the desired catalogs this type should be in desired_catalogs = map(api.get_tool, catalogs) # check if the catalogs changed for this portal_type if set(current_catalogs).difference(desired_catalogs): # fetch the brains to reindex brains = api.search({"portal_type": type_name}) # updated the catalogs at.setCatalogsByType(type_name, catalogs) logger.info("*** Assign '%s' type to Catalogs %s" % (type_name, catalogs)) for brain in brains: obj = api.get_object(brain) logger.info("*** Reindexing '%s'" % repr(obj)) obj.reindexObject() # Setup catalog indexes to_index = [] for catalog, name, attribute, meta_type in INDEXES: c = api.get_tool(catalog) indexes = c.indexes() if name in indexes: logger.info("*** Index '%s' already in Catalog [SKIP]" % name) continue logger.info("*** Adding Index '%s' for field '%s' to catalog ..." % (meta_type, name)) c.addIndex(name, meta_type) to_index.append((c, name)) logger.info("*** Added Index '%s' for field '%s' to catalog [DONE]" % (meta_type, name)) for catalog, name in to_index: logger.info("*** Indexing new index '%s' ..." % name) catalog.manage_reindexIndex(name) logger.info("*** Indexing new index '%s' [DONE]" % name) # Setup catalog metadata columns for catalog, name in COLUMNS: c = api.get_tool(catalog) if name not in c.schema(): logger.info("*** Adding Column '%s' to catalog '%s' ..." % (name, catalog)) c.addColumn(name) logger.info("*** Added Column '%s' to catalog '%s' [DONE]" % (name, catalog)) else: logger.info("*** Column '%s' already in catalog '%s' [SKIP]" % (name, catalog)) continue
def get_brain(self, uid, catalog): if not api.is_uid(uid): return None query = dict(UID=uid) brains = api.search(query, catalog) if brains and len(brains) == 1: return brains[0] return None
def getMethodsDisplayList(self): """Returns a display list with the active methods """ query = dict(portal_type="Method", inactive_state="active") items = api.search(query, "bika_setup_catalog") items = map(lambda brain: (brain.UID, brain.Title), items) items.sort(lambda x, y: cmp(x[1], y[1])) return DisplayList(list(items))
def getBatches(self, full_objects=False): """Returns the Batches (Clinic Cases) this Patient is assigned to """ query = dict(portal_type="Batch", getPatientUID=api.get_uid(self)) batches = api.search(query, BIKA_CATALOG) if full_objects: return map(api.get_object, batches) return batches
def move_doctors_to_clients(portal): """Moves the doctors into their assigned Client, if any """ logger.info("Moving Doctors inside Clients...") query = {"portal_type": "Doctor"} doctors = map(api.get_object, api.search(query, "portal_catalog")) map(move_doctor_to_client, doctors) logger.info("Moving Doctors inside Clients [DONE]")
def do_unassign(self, analysis_uids): actions = ActionHandlerPool.get_instance() actions.queue_pool() # Remove duplicates first query = dict(UID=analysis_uids, portal_type="DuplicateAnalysis") for brain in api.search(query, CATALOG_ANALYSIS_LISTING): doActionFor(api.get_object(brain), "unassign") # Now remove the rest query = dict(UID=analysis_uids) for brain in api.search(query, CATALOG_ANALYSIS_LISTING): doActionFor(api.get_object(brain), "unassign") actions.resume() message = _("Changes saved.") self.context.plone_utils.addPortalMessage(message, 'info') self.destination_url = self.context.absolute_url() self.request.response.redirect(self.destination_url)
def getBatches(self, full_objects=False): """ Returns the Batches this Doctor is assigned to :return: """ query = dict(portal_type='Batch', getDoctorUID=self.UID()) brains = api.search(query, 'bika_catalog') if full_objects: return map(lambda brain: api.get_object(brain), brains) return brains
def getAnalysisRequests(self, full_objects=False): """ Returns the Analysis Requests this Doctor is assigned to :return: """ query = dict(portal_type='AnalysisRequest', getDoctorUID=self.UID()) brains = api.search(query, CATALOG_ANALYSIS_REQUEST_LISTING) if full_objects: return map(lambda brain: api.get_object(brain), brains) return brains
def getSamples(self, **kwargs): """Return samples taken from this Patient """ catalog = api.get_tool(CATALOG_ANALYSIS_REQUEST_LISTING, context=self) query = dict([(k, v) for k, v in kwargs.items() if k in catalog.indexes()]) query["getPatientUID"] = api.get_uid(self) brains = api.search(query, CATALOG_ANALYSIS_REQUEST_LISTING) if not kwargs.get("full_objects", False): return brains return map(api.get_object, brains)
def search_catalogs(portal_type): """Returns brains which share the same portal_type """ catalog_names = ['portal_catalog', 'bika_setup_catalog', 'bika_catalog'] UIDs = [] all_brains = [] for catalog_name in catalog_names: catalog = api.get_tool(catalog_name) brains = api.search({"portal_type": portal_type}, catalog=catalog_name) for brain in brains: if brain.UID not in UIDs: all_brains.append(brain) UIDs.append(brain.UID) return all_brains
def get_clients_vocabulary(self): client = api.get_current_client() if client: # Current user is a client contact. Load only this client return DisplayList([(api.get_uid(client), api.get_title(client))]) # Current user is not a client contact. Load all active clients query = dict(portal_type="Client", is_active=True) clients = api.search(query, "portal_catalog") clients = map(lambda cl: [api.get_uid(cl), api.get_title(cl)], clients) clients.sort(lambda x, y: cmp(x[1].lower(), y[1].lower())) # Lab personnel can set a Patient to be visible for all Clients clients.insert(0, ['', '']) return DisplayList(clients)
def setup_patients_ownership(portal): """Set the role "Owner" to all the client contacts that belong to the same client as the patient, if any """ logger.info("Applying Patients ownership ...") brains = api.search(dict(portal_type="Patient"), CATALOG_PATIENTS) total = len(brains) for num, brain in enumerate(brains): if num % 100 == 0: logger.info("Applying Patients Ownership {}/{}".format(num, total)) purge_owners_for(api.get_object(brain)) if num % 1000 == 0: commit_transaction() commit_transaction()
def get_clients_vocabulary(self): """ Vocabulary list with clients :return: A DisplayList object """ if self.getBatches() or self.getAnalysisRequests(): # Allow to change the client if there are no ARs associated client = self.getPrimaryReferrer() if not client: # Maybe all Batches and ARs assigned to this Doctor belong to # the same Client.. If so, just assign this client by default client_uids = map(lambda ar: ar.getClientUID, self.getAnalysisRequests()) client_uids = list(set(client_uids)) if len(client_uids) > 1: # More than one client assigned! return DisplayList([('', '')]) clients = map(lambda batch: batch.getClient(), self.getBatches(full_objects=True)) client_uids += map(lambda client: api.get_uid(client), clients) client_uids = list(set(client_uids)) if len(client_uids) > 1: # More than one client assigned! return DisplayList([('', '')]) client = api.get_object_by_uid(client_uids[0]) return DisplayList([(api.get_uid(client), client.Title())]) # If the current user is a client contact, do not display other clients client = api.get_current_client() if client: return DisplayList([(api.get_uid(client), client.Title())]) # Search for clients query = dict(portal_type='Client', is_active=True, sort_order='ascending', sort_on='title') brains = api.search(query, 'portal_catalog') clients = map(lambda brain: [api.get_uid(brain), brain.Title], brains) clients.insert(0, ['', '']) return DisplayList(clients)
def __call__(self): plone.protect.CheckAuthenticator(self.request) searchTerm = 'searchTerm' in self.request and self.request['searchTerm'].lower() or '' page = self.request['page'] nr_rows = self.request['rows'] sord = self.request['sord'] sidx = self.request['sidx'] rows = [] query = dict(portal_type="Doctor", is_active=True) client = self.get_current_client() if client: # Search those Doctors that are assigned to the same client or # that do not have any client assigned query["getPrimaryReferrerUID"] = [api.get_uid(client), None] doctors = api.search(query, 'portal_catalog') for doctor in doctors: doctor_id = doctor.id doctor_title = doctor.Title search_val = ('{} {}'.format(doctor_id, doctor_title)).lower() if searchTerm not in search_val: continue rows.append({'Title': doctor.Title() or '', 'DoctorID': doctor.getDoctorID(), 'DoctorSysID': doctor.id, 'DoctorUID': doctor.UID()}) rows = sorted(rows, cmp=lambda x, y: cmp(x.lower(), y.lower()), key = itemgetter(sidx and sidx or 'Title')) if sord == 'desc': rows.reverse() pages = len(rows) / int(nr_rows) pages += divmod(len(rows), int(nr_rows))[1] and 1 or 0 ret = {'pages': page, 'total': pages, 'records': len(rows), 'rows': rows[(int(page) - 1) * int(nr_rows): int(page) * int(nr_rows)]} return json.dumps(ret)
def __call__(self, value, *args, **kwargs): # avoid the catalog query if the option is not selected if not api.get_bika_setup().ClientPatientIDUnique: return True query = dict(getClientPatientID=value) patients = api.search(query, CATALOG_PATIENTS) instance = kwargs.get('instance') # If there are no patients with this Client Patient ID # then it is valid if not patients: return True # If there is only one patient with this Client Patient ID # and it is the patient being edited then it also valid if len(patients) == 1 and api.get_uid(patients[0]) == api.get_uid(instance): return True trans = getToolByName(instance, 'translation_service').translate msg = _( "Validation failed: '${value}' is not unique", mapping={ 'value': safe_unicode(value) }) return to_utf8(trans(msg))
def purge_owners_for(batch): """Remove role "Owner" from all those client contacts that do not belong to the same Client the batch is assigned to and assigns the role "Owner" to the client contacts assigned to the batch """ # Add role "Owner" for this batch to all contacts from this Client assign_owners_for(batch) # Unassign role "Owner" from contacts that belong to another Client batch_client = batch.getClient() batch_client_uid = batch_client and api.get_uid(batch_client) or None for client in api.search(dict(portal_type="Client"), "portal_catalog"): if api.get_uid(client) == batch_client_uid: continue client = api.get_object(client) contacts = client.objectValues("Contact") users = map(lambda contact: contact.getUser(), contacts) users = filter(None, users) for user in users: security.revoke_local_roles_for(batch, ["Owner"], user=user) batch.reindexObjectSecurity()
def setup_catalogs(catalogs_by_type, indexes_by_catalog, columns_by_catalog): """Setup Plone catalogs """ logger.info("Setup Catalogs ...") # Setup catalogs by type for type_name, catalogs in catalogs_by_type: at = api.get_tool("archetype_tool") # get the current registered catalogs current_catalogs = at.getCatalogsByType(type_name) # get the desired catalogs this type should be in desired_catalogs = map(api.get_tool, catalogs) # check if the catalogs changed for this portal_type if set(desired_catalogs).difference(current_catalogs): # fetch the brains to reindex brains = api.search({"portal_type": type_name}) # updated the catalogs at.setCatalogsByType(type_name, catalogs) logger.info("Assign '%s' type to Catalogs %s" % (type_name, catalogs)) for brain in brains: obj = api.get_object(brain) logger.info("Reindexing '%s'" % repr(obj)) obj.reindexObject() # Setup catalog indexes to_index = [] for catalog, name, meta_type in indexes_by_catalog: c = api.get_tool(catalog) indexes = c.indexes() if name in indexes: logger.info("Index '%s' already in Catalog [SKIP]" % name) continue logger.info("Adding Index '%s' for field '%s' to catalog '%s" % (meta_type, name, catalog)) if meta_type == "ZCTextIndex": addZCTextIndex(c, name) else: c.addIndex(name, meta_type) to_index.append((c, name)) logger.info("Added Index '%s' for field '%s' to catalog [DONE]" % (meta_type, name)) for catalog, name in to_index: logger.info("Indexing new index '%s' ..." % name) catalog.manage_reindexIndex(name) logger.info("Indexing new index '%s' [DONE]" % name) # Setup catalog metadata columns for catalog, name in columns_by_catalog: c = api.get_tool(catalog) if name not in c.schema(): logger.info("Adding Column '%s' to catalog '%s' ..." % (name, catalog)) c.addColumn(name) logger.info("Added Column '%s' to catalog '%s' [DONE]" % (name, catalog)) else: logger.info("Column '%s' already in catalog '%s' [SKIP]" % (name, catalog)) continue