def remove_analysis(self, analysis): """Removes a given analysis from the instance """ # Remember assigned attachments # https://github.com/senaite/senaite.core/issues/1025 attachments = analysis.getAttachment() analysis.setAttachment([]) # If assigned to a worksheet, unassign it before deletion worksheet = analysis.getWorksheet() if worksheet: worksheet.removeAnalysis(analysis) # Remove the analysis # Note the analysis might belong to a partition analysis.aq_parent.manage_delObjects(ids=[api.get_id(analysis)]) # Remove orphaned attachments for attachment in attachments: if not attachment.getLinkedAnalyses(): # only delete attachments which are no further linked logger.info("Deleting attachment: {}".format( attachment.getId())) attachment_id = api.get_id(attachment) api.get_parent(attachment).manage_delObjects(attachment_id)
def _apply_filter_by_client(self): # If the current context is a Client, filter Patients by Client UID if IClient.providedBy(self.context): client_uid = api.get_uid(self.context) self.contentFilter['getPrimaryReferrerUID'] = client_uid return # If the current user is a Client contact, filter the Patients in # accordance. For the rest of users (LabContacts), the visibility of # the patients depend on their permissions user = api.get_current_user() roles = user.getRoles() if 'Client' not in roles: return # Are we sure this a ClientContact? # May happen that this is a Plone member, w/o having a ClientContact # assigned or having a LabContact assigned... weird contact = api.get_user_contact(user) if not contact or ILabContact.providedBy(contact): return # Is the parent from the Contact a Client? client = api.get_parent(contact) if not client or not IClient.providedBy(client): return client_uid = api.get_uid(client) self.contentFilter['getPrimaryReferrerUID'] = client_uid
def query_parent_objects(self, context, query=None): """Return the objects of the same type from the parent object :param query: Catalog query to narrow down the objects :type query: dict :returns: Content objects of the same portal type in the parent """ # return the object values if we have no catalog query if query is None: return self.get_parent_objects(context) # avoid undefined reference of catalog in except... catalog = None # try to fetch the results via the catalog try: catalogs = api.get_catalogs_for(context) catalog = catalogs[0] return map(api.get_object, catalog(query)) except (IndexError, UnicodeDecodeError, ParseError, APIError) as e: # fall back to the object values of the parent logger.warn("UniqueFieldValidator: Catalog query {} failed " "for catalog {} ({}) -> returning object values of {}" .format(query, repr(catalog), str(e), repr(api.get_parent(context)))) return self.get_parent_objects(context)
def folderitem(self, obj, item, index): """Applies new properties to the item being rendered in the list :param obj: object to be rendered as a row in the list :param item: dict representation of the obj suitable for the listing :param index: current index within the list of items :type obj: CatalogBrain :type item: dict :type index: int :return: the dict representation of the item :rtype: dict """ brain = obj obj = api.get_object(obj) for column, config in self.columns.items(): key = config.get("column") model = SuperModel(obj) if key == "Parent": value = SuperModel(api.get_parent(obj)) elif key == "Result" and getattr(obj, "getFormattedResult", None): value = obj.getFormattedResult() else: value = model.get(key) # Handle reference columns if isinstance(value, SuperModel): # reference columns are stored in the column config refs = config.get("refs", [DEFAULT_REF]) # resolve the referenced model model = self.resolve_reference_model(value, refs) # get the last selected reference column ref = refs[-1] # get the referenced value value = model.get(ref) if callable(value): value = value() code = config.get("code") if code: # use the referenced instance as the context context = model.instance # execute the code value = self.execute_code(code, obj=obj, context=context, model=model, brain=brain) converter = config.get("converter") if converter: func = queryUtility(IFieldConverter, name=converter) if callable(func): converted_value = func(model.instance, column, value) item["replace"][column] = converted_value item[column] = value return item
def renameAfterCreation(obj): """Rename the content after it was created/added """ # Check if the _bika_id was already set bika_id = getattr(obj, "_bika_id", None) if bika_id is not None: return bika_id # Can't rename without a subtransaction commit when using portal_factory transaction.savepoint(optimistic=True) # The id returned should be normalized already new_id = None # Checking if an adapter exists for this content type. If yes, we will # get new_id from adapter. for name, adapter in getAdapters((obj, ), IIdServer): if new_id: logger.warn(('More than one ID Generator Adapter found for' 'content type -> %s') % obj.portal_type) new_id = adapter.generate_id(obj.portal_type) if not new_id: new_id = generateUniqueId(obj) # TODO: This is a naive check just in current folder # -> this should check globally for duplicate objects with same prefix # N.B. a check like `search_by_prefix` each time would probably slow things # down too much! # -> A solution could be to store all IDs with a certain prefix in a storage parent = api.get_parent(obj) if new_id in parent.objectIds(): # XXX We could do the check in a `while` loop and generate a new one. raise KeyError("The ID {} is already taken in the path {}".format( new_id, api.get_path(parent))) # rename the object to the new id parent.manage_renameObject(obj.id, new_id) return new_id
def renameAfterCreation(obj): """Rename the content after it was created/added """ # Check if the _bika_id was aready set bika_id = getattr(obj, "_bika_id", None) if bika_id is not None: return bika_id # Can't rename without a subtransaction commit when using portal_factory transaction.savepoint(optimistic=True) # The id returned should be normalized already new_id = None # Checking if an adapter exists for this content type. If yes, we will # get new_id from adapter. for name, adapter in getAdapters((obj, ), IIdServer): if new_id: logger.warn(('More than one ID Generator Adapter found for' 'content type -> %s') % obj.portal_type) new_id = adapter.generate_id(obj.portal_type) if not new_id: new_id = generateUniqueId(obj) # TODO: This is a naive check just in current folder # -> this should check globally for duplicate objects with same prefix # N.B. a check like `search_by_prefix` each time would probably slow things # down too much! # -> A solution could be to store all IDs with a certain prefix in a storage. parent = api.get_parent(obj) if new_id in parent.objectIds(): # XXX We could do the check in a `while` loop and generate a new one. raise KeyError("The ID {} is already taken in the path {}".format( new_id, api.get_path(parent))) # rename the object to the new id parent.manage_renameObject(obj.id, new_id) return new_id
def create_retest(analysis): """Creates a retest of the given analysis """ if not IRequestAnalysis.providedBy(analysis): raise ValueError("Type not supported: {}".format(repr(type(analysis)))) # Support multiple retests by prefixing keyword with *-0, *-1, etc. parent = api.get_parent(analysis) keyword = analysis.getKeyword() # Get only those analyses with same keyword as original analyses = parent.getAnalyses(full_objects=True) analyses = filter(lambda an: an.getKeyword() == keyword, analyses) new_id = '{}-{}'.format(keyword, len(analyses)) # Create a copy of the original analysis an_uid = api.get_uid(analysis) retest = create_analysis(parent, analysis, id=new_id, RetestOf=an_uid) retest.setResult("") retest.setResultCaptureDate(None) # Add the retest to the same worksheet, if any worksheet = analysis.getWorksheet() if worksheet: worksheet.addAnalysis(retest) retest.reindexObject() return retest
def query_parent_objects(self, context, query=None): """Return the objects of the same type from the parent object :param query: Catalog query to narrow down the objects :type query: dict :returns: Content objects of the same portal type in the parent """ # return the object values if we have no catalog query if query is None: return self.get_parent_objects(context) # avoid undefined reference of catalog in except... catalog = None # try to fetch the results via the catalog try: catalogs = api.get_catalogs_for(context) catalog = catalogs[0] return map(api.get_object, catalog(query)) except (IndexError, UnicodeDecodeError, ParseError, api.BikaLIMSError) as e: # fall back to the object values of the parent logger.warn("UniqueFieldValidator: Catalog query {} failed " "for catalog {} ({}) -> returning object values of {}" .format(query, repr(catalog), str(e), repr(api.get_parent(context)))) return self.get_parent_objects(context)
def is_update_allowed(obj): """Returns whether the update of the object passed in is supported :param obj: The object to be updated :type obj: ATContentType/DexterityContentType :returns: True if it is allowed to update this object :rtype: bool """ # Do not allow to update the site itself if api.is_portal(obj): return False # Do not allow the update of objects that belong to site root folder parent = api.get_parent(obj) if api.is_portal(parent): return False # Do not allow the update of objects that belong to setup folder if parent == api.get_setup(): return False # Look for an update-specific adapter for this object adapter = queryAdapter(obj, IUpdate) if adapter: return adapter.is_update_allowed() return True
def getClientUID(self): """Return the UID of the client """ client = api.get_parent(self) if not client: return "" return api.get_uid(client)
def _apply_filter_by_client(self): """ If the user has the role Client, the user can not see batches from client objects he/she does not belong to. """ # If the current context is a Client, filter Batches by Client UID if IClient.providedBy(self.context): client_uid = api.get_uid(self.context) self.contentFilter['getClientUID'] = client_uid return # If the current user is a Client contact, filter the Batches in # accordance. For the rest of users (LabContacts), the visibility of # the Batches depend on their permissions user = api.get_current_user() roles = user.getRoles() if 'Client' not in roles: return # Are we sure this a ClientContact? # May happen that this is a Plone member, w/o having a ClientContact # assigned or having a LabContact assigned... weird contact = api.get_user_contact(user) if not contact or ILabContact.providedBy(contact): return # Is the parent from the Contact a Client? client = api.get_parent(contact) if not client or not IClient.providedBy(client): return client_uid = api.get_uid(client) self.contentFilter['getClientUID'] = client_uid
def folderitem(self, obj, item, index): """Applies new properties to item (StorageContainer) that is currently being rendered as a row in the list """ item = super(ContainersView, self).folderitem(obj, item, index) # Get the object (the passed-in "obj" is a brain) obj = api.get_object(obj) # Containers/Positions usage # Samples containers cannot have containers inside! if not IStorageSamplesContainer.providedBy(obj): capacity = obj.get_capacity() taken = len(obj.get_non_available_positions()) percentage = capacity and taken*100/capacity or 0 item["replace"]["ContainersUsage"] = get_progress_bar_html(percentage) item["replace"]["Containers"] = "{:01d} / {:01d} ({:01d}%)"\ .format(taken, capacity, percentage) # append the UID of the primary AR as parent parent = api.get_uid(api.get_parent(obj)) item["parent"] = parent != api.get_uid(self.context) and parent or "" # append partition UIDs of this AR as children containers = obj.get_layout_containers() item["children"] = map(lambda cont: api.get_uid(cont), containers) return item
def notify_parent(self): """Notifies the parent to update the information it holds about this container """ parent = api.get_parent(self) if IStorageLayoutContainer.providedBy(parent): parent.update_object(self)
def is_external_client(client): """Returns whether the client passed is an external client """ if not IClient.providedBy(client): raise TypeError("Type not supported") return api.get_parent(client) == api.get_portal().clients
def __call__(self, value, *args, **kwargs): field = kwargs['field'] fieldname = field.getName() instance = kwargs['instance'] translate = getToolByName(instance, 'translation_service').translate # return directly if nothing changed if value == field.get(instance): return True # We want to use the catalog to speed things up, as using `objectValues` # is very expensive if the parent object contains many items parent_objects = [] # 1. Get the right catalog for this object catalogs = api.get_catalogs_for(instance) catalog = catalogs[0] # 2. Check if the field accessor is indexed field_index = None accessor = field.getAccessor(instance) if accessor: field_index = accessor.__name__ # 3. Check if the field index is in the indexes # Field is indexed, use the catalog instead of objectValues parent_path = api.get_parent_path(instance) portal_type = instance.portal_type catalog_query = {"portal_type": portal_type, "path": {"query": parent_path, "depth": 1}} if field_index and field_index in catalog.indexes(): # We use the field index to reduce the results list catalog_query[field_index] = value parent_objects = map(api.get_object, catalog(catalog_query)) elif fieldname in catalog.indexes(): # We use the fieldname as index to reduce the results list catalog_query[fieldname] = value parent_objects = map(api.get_object, catalog(catalog_query)) else: # fall back to the objectValues :( parent_object = api.get_parent(instance) parent_objects = parent_object.objectValues() for item in parent_objects: if hasattr(item, 'UID') and item.UID() != instance.UID() and \ fieldname in item.Schema() and \ str(item.Schema()[fieldname].get(item)) == str(value): # We have to compare them as strings because # even if a number (as an id) is saved inside # a string widget and string field, it will be # returned as an int. I don't know if it is # caused because is called with # <item.Schema()[fieldname].get(item)>, # but it happens... msg = _("Validation failed: '${value}' is not unique", mapping={'value': safe_unicode(value)}) return to_utf8(translate(msg)) return True
def action_add(self): """Form action to add a new attachment Code taken from bika.lims.content.addARAttachment. """ form = self.request.form parent = api.get_parent(self.context) attachment_file = form.get('AttachmentFile_file', None) AttachmentType = form.get('AttachmentType', '') AttachmentKeys = form.get('AttachmentKeys', '') ReportOption = form.get('ReportOption', 'r') # nothing to do if the attachment file is missing if attachment_file is None: logger.warn( "AttachmentView.action_add_attachment: Attachment file is missing" ) return # create attachment attachment = self.create_attachment(parent, attachment_file, AttachmentType=AttachmentType, AttachmentKeys=AttachmentKeys, ReportOption=ReportOption) # append the new UID to the end of the current order self.set_attachments_order(api.get_uid(attachment)) # handle analysis attachment analysis_uid = form.get("Analysis", None) if analysis_uid: analysis = api.get_object_by_uid(analysis_uid) others = analysis.getAttachment() attachments = [] for other in others: attachments.append(other.UID()) attachments.append(attachment.UID()) analysis.setAttachment(attachments) # The metadata for getAttachmentUIDs need to get updated, # otherwise the attachments are not displayed # https://github.com/senaite/bika.lims/issues/521 analysis.reindexObject() else: others = self.context.getAttachment() attachments = [] for other in others: attachments.append(other.UID()) attachments.append(attachment.UID()) self.context.setAttachment(attachments) if self.request['HTTP_REFERER'].endswith('manage_results'): self.request.response.redirect('{}/manage_results'.format( self.context.absolute_url())) else: self.request.response.redirect(self.context.absolute_url())
def is_object_allowed(self, object_brain_uid): """Returns whether the type of object can be stored or not in this container. This function returns true if the object is allowed, even if the container already contains the object """ # Only children from this container are allowed obj = api.get_object(object_brain_uid) return api.get_uid(api.get_parent(obj)) == api.get_uid(self)
def __call__(self): url = api.get_url(api.get_portal()) current_user = api.get_current_user() contact = api.get_user_contact(current_user) if contact: parent = api.get_parent(contact) url = api.get_url(parent) return self.request.response.redirect(url)
def delete_orphaned_attachments(portal): """Delete attachments where the Analysis was removed https://github.com/senaite/senaite.core/issues/1025 """ attachments = api.search({"portal_type": "Attachment"}) total = len(attachments) logger.info("Integrity checking %d attachments" % total) for num, attachment in enumerate(attachments): obj = api.get_object(attachment) # The method `getRequest` from the attachment tries to get the AR # either directly or from one of the linked Analyses. If it returns # `None`, we can be sure that the attachment is neither assigned # directly to an AR nor to an Analysis. ar = obj.getRequest() if ar is None: obj_id = api.get_id(obj) api.get_parent(obj).manage_delObjects(obj_id) logger.info("Deleted orphaned Attachment {}".format(obj_id))
def to_link(obj, key, value, **kw): """to link """ value = to_string(obj, key, value) if not value: return "" if api.get_portal_type(obj) in LINK_TO_PARENT_TYPES: obj = api.get_parent(obj) url = addTokenToUrl(api.get_url(obj)) return get_link(url, value)
def StorageContentRemovedEventHandler(container, event): """Removes the object from parent's layout (if the parent is a container) """ parent = api.get_parent(container) if not IStorageLayoutContainer.providedBy(parent): return if not parent.remove_object(container): logger.warn("Cannot remove the container '{}' from '{}'".format( container.getId(), parent.getId()))
def delete_attachment(self, attachment): """Delete attachment from the AR or Analysis The attachment will be only deleted if it is not further referenced by another AR/Analysis. """ # Get the holding parent of this attachment parent = None if attachment.getLinkedRequests(): # Holding parent is an AR parent = attachment.getRequest() elif attachment.getLinkedAnalyses(): # Holding parent is an Analysis parent = attachment.getAnalysis() if parent is None: logger.warn( "Attachment {} is nowhere assigned. This should never happen!". format(repr(attachment))) return False # Get the other attachments of the holding parent attachments = parent.getAttachment() # New attachments to set if attachment in attachments: attachments.remove(attachment) # Set the attachments w/o the current attachments parent.setAttachment(attachments) retain = False # Attachment is referenced by another Analysis if attachment.getLinkedAnalyses(): holder = attachment.getAnalysis() logger.info("Attachment {} referenced by {} -> RETAIN".format( repr(attachment), repr(holder))) retain = True # Attachment is referenced by another AR if attachment.getLinkedRequests(): holder = attachment.getRequest() logger.info("Attachment {} referenced by {} -> RETAIN".format( repr(attachment), repr(holder))) retain = True # Delete attachment finally if retain is False: client = api.get_parent(attachment) client.manage_delObjects([ attachment.getId(), ])
def folderitem(self, obj, item, index): obj = api.get_object(obj) item["Description"] = obj.Description() item["replace"]["Title"] = get_link(item["url"], item["Title"]) parent = api.get_parent(obj) if IClient.providedBy(parent): item["Owner"] = api.get_title(parent) else: item["Owner"] = self.context.bika_setup.laboratory.Title() return item
def before_transition_handler(instance, event): """Always update the modification date before a WF transition. This ensures that all cache keys are invalidated. """ parent = api.get_parent(instance) if api.get_portal_type(instance) == "AnalysisRequest": update_ar_modification_dates(instance) elif api.get_portal_type(parent) == "AnalysisRequest": update_ar_modification_dates(parent) else: update_modification_date(instance)
def isVisible(self, field, mode="view", default="visible"): """Renders the PrimaryReferrer field (Client) as readonly when the mode is "edit" and the container is a Client """ if mode == "edit": client = self.context.getClient() if client == api.get_parent(self.context): # We are already inside the parent's context return "hidden" elif client: # We are in another context, read-only return "readonly" return default
def isVisible(self, field, mode="view", default="visible"): """Renders the Client field as hidden if the current mode is "edit" and the Doctor has Batches or Samples assigned already """ if mode == "edit": client = self.context.getClient() if client == api.get_parent(self.context): # We are already inside the parent's context return "hidden" elif client: # We are in another context, read-only return "readonly" return default
def get_current_client(self, default=None): """Returns the client the current user belongs to """ user = api.get_current_user() roles = user.getRoles() if 'Client' not in roles: return default contact = api.get_user_contact(user) if not contact or ILabContact.providedBy(contact): return default client = api.get_parent(contact) if not client or not IClient.providedBy(client): return default return client
def get_current_client(self, default=None): """Returns the client the current user belongs to """ user = api.get_current_user() roles = user.getRoles() if 'Client' not in roles: return default contact = api.get_user_contact(user) if not contact or ILabContact.providedBy(contact): return default client = api.get_parent(contact) if not client or not IClient.providedBy(client): return default return client
def folderitem(self, obj, item, index): """Service triggered each time an item is iterated in folderitems. The use of this service prevents the extra-loops in child objects. :obj: the instance of the class to be foldered :item: dict containing the properties of the object to be used by the template :index: current index of the item """ item["replace"]["Title"] = get_link_for(obj) item["Description"] = obj.Description() retention_period = obj.getRetentionPeriod() if retention_period: hours = retention_period.get("hours", "0") minutes = retention_period.get("minutes", "0") days = retention_period.get("days", "0") item["RetentionPeriod"] = _( "hours: {} minutes: {} days: {}".format(hours, minutes, days)) sample_matrix = obj.getSampleMatrix() item["replace"]["SampleMatrix"] = get_link_for(sample_matrix) container_type = obj.getContainerType() item["replace"]["ContainerType"] = get_link_for(container_type) # Hide sample points assigned to this sample type that do not belong # to the same container (Client or Setup) sample_points = obj.getSamplePoints() path = api.get_path(self.context) setup = api.get_setup() if api.get_parent(self.context) == setup: path = api.get_path(setup.bika_samplepoints) sample_points = filter(lambda sp: api.get_parent_path(sp) == path, sample_points) # Display the links to the sample points links = map(get_link_for, sample_points) item["replace"]["SamplePoints"] = ", ".join(links) return item
def addToJSON(self, analysis, service_uid, item): """ Adds an analysis item to the self.anjson dict that will be used after the page is rendered to generate a QC Chart """ parent = api.get_parent(analysis) qcid = parent.id serviceref = "%s (%s)" % (item['Service'], item['Keyword']) trows = self.anjson.get(serviceref, {}) anrows = trows.get(qcid, []) rr = parent.getResultsRangeDict() cap_date = item['obj'].getResultCaptureDate cap_date = api.is_date(cap_date) and \ cap_date.strftime('%Y-%m-%d %I:%M %p') or '' if service_uid in rr: specs = rr.get(service_uid, None) try: smin = float(specs.get('min', 0)) smax = float(specs.get('max', 0)) error = float(specs.get('error', 0)) target = float(specs.get('result', 0)) result = float(item['Result']) error_amount = ((target / 100) * error) if target > 0 else 0 upper = smax + error_amount lower = smin - error_amount anrow = { 'date': cap_date, 'min': smin, 'max': smax, 'target': target, 'error': error, 'erroramount': error_amount, 'upper': upper, 'lower': lower, 'result': result, 'unit': item['Unit'], 'id': item['uid'] } anrows.append(anrow) trows[qcid] = anrows self.anjson[serviceref] = trows except: pass
def resolve_client(obj, field_name=None): """Tries to resolve the client for the given obj """ if not field_name: field_name = "Client" if IPatient.providedBy(obj) or IDoctor.providedBy(obj): field_name = "PrimaryReferrer" # Try to get the client directly from the field client = obj.getField(field_name).get(obj) if client and IClient.providedBy(client): return client # Maybe the object is being created if obj.isTemporary(): parent = obj.getFolderWhenPortalFactory() else: parent = api.get_parent(obj) # Get the Client from the acquisition chain, if any return get_client_from_chain(parent)
def delete_attachment(self, attachment): """Delete attachment Code taken from bika.lims.content.delARAttachment. """ uid = attachment.UID() parent_ar = attachment.getRequest() parent_an = attachment.getAnalysis() parent = parent_an if parent_an else parent_ar others = parent.getAttachment() # remove references attachments = [] for other in others: if other.UID() != uid: attachments.append(other.UID()) parent.setAttachment(attachments) # delete the attachment finally client = api.get_parent(attachment) client.manage_delObjects([attachment.getId(), ])
def get_exit_url_for(self, reports, action="save"): """Handle the response for the generated reports This method determines based on the generated reports where the browser should redirect the user and what status message to display. :param reports: List of report objects :returns: A single redirect URL """ # view endpoint endpoint = action == "email" and "email" or "reports_listing" # get the report uids clients = [] report_uids = [] parent_titles = [] for report in reports: parent = api.get_parent(report) if hasattr(parent, "getClient"): clients.append(parent.getClient()) report_uids.append(api.get_uid(report)) parent_titles.append(api.get_title(parent)) # generate status message message = _("Generated reports for: {}".format( ", ".join(parent_titles))) self.add_status_message(message, level="info") # generate exit URL exit_url = self.context.absolute_url() if clients: exit_url = "{}/{}?uids={}".format(api.get_url(clients[0]), endpoint, ",".join(report_uids)) return exit_url
def StorageContentModifiedEventHandler(container, event): """Adds the object to the parent's layout (if the parent is a container) We use a ObjectModifiedEvent from zope.lifecycleevent here instead of ObjectAddedEvent or InitializedEvent because: a) ObjectAddedEvent from zope.lifecycleevent is fired as soon as the object is temporarily created, when fields do not have any value set. Since we need the values from "PositionsLayout" field for the parent to get updated in accordance, we cannot use this event. b) InitializedEvent from Products.Archetypes is called as soon as the object is created (with values) after the edit form submission, but this event is not called by senaite.core's api. Hence, this cannot be used because the event will not be fired if the object is created manually unless we do a explicit call to processForm() on creation (which is not always the case). Caveats: Note that we assume the object is at least created by using Plone's default edit form or by using senaite.core's api, but if the object is created manually (e.g. using _createObjectByType), this event will not be fired. """ parent = api.get_parent(container) if not IStorageLayoutContainer.providedBy(parent): # Parent doesn't care about the changes in his children return if parent.has_object(container): if not parent.update_object(container): logger.warn("Cannot update the container '{}' from '{}'".format( container.getId(), parent.getId())) else: # The object is added at the first available position, if any if not parent.add_object(container): logger.warn("Cannot add the container '{}' into '{}'".format( container.getId(), parent.getId()))
def get_variables(context, **kw): """Prepares a dictionary of key->value pairs usable for ID formatting """ # allow portal_type override portal_type = kw.get("portal_type") or api.get_portal_type(context) # The variables map hold the values that might get into the constructed id variables = { 'context': context, 'id': api.get_id(context), 'portal_type': portal_type, 'year': get_current_year(), 'parent': api.get_parent(context), 'seq': 0, } # Augment the variables map depending on the portal type if portal_type == "AnalysisRequest": variables.update({ 'sampleId': context.getSample().getId(), 'sample': context.getSample(), }) elif portal_type == "SamplePartition": variables.update({ 'sampleId': context.aq_parent.getId(), 'sample': context.aq_parent, }) elif portal_type == "Sample": # get the prefix of the assigned sample type sample_id = context.getId() sample_type = context.getSampleType() sampletype_prefix = sample_type.getPrefix() date_now = DateTime() sampling_date = context.getSamplingDate() date_sampled = context.getDateSampled() # Try to get the date sampled and sampling date if sampling_date: samplingDate = DT2dt(sampling_date) else: # No Sample Date? logger.error("Sample {} has no sample date set".format(sample_id)) # fall back to current date samplingDate = DT2dt(date_now) if date_sampled: dateSampled = DT2dt(date_sampled) else: # No Sample Date? logger.error("Sample {} has no sample date set".format(sample_id)) dateSampled = DT2dt(date_now) variables.update({ 'clientId': context.aq_parent.getClientID(), 'dateSampled': dateSampled, 'samplingDate': samplingDate, 'sampleType': sampletype_prefix, }) return variables
def get_parent_objects(self, context): """Return all objects of the same type from the parent object """ parent_object = api.get_parent(context) portal_type = api.get_portal_type(context) return parent_object.objectValues(portal_type)