예제 #1
0
    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)
예제 #2
0
    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
예제 #3
0
    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)
예제 #4
0
    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
예제 #5
0
파일: idserver.py 프로젝트: xispa/bika.lims
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
예제 #6
0
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
예제 #7
0
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
예제 #8
0
    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)
예제 #9
0
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
예제 #10
0
 def getClientUID(self):
     """Return the UID of the client
     """
     client = api.get_parent(self)
     if not client:
         return ""
     return api.get_uid(client)
예제 #11
0
    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
예제 #12
0
    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
예제 #13
0
 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)
예제 #14
0
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
예제 #15
0
    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
예제 #16
0
    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())
예제 #17
0
 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)
예제 #18
0
    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)
예제 #19
0
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))
예제 #20
0
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)
예제 #21
0
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()))
예제 #22
0
    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(),
            ])
예제 #23
0
    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
예제 #24
0
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)
예제 #25
0
    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
예제 #26
0
    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
예제 #27
0
    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
예제 #28
0
    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
예제 #29
0
    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
예제 #30
0
 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
예제 #31
0
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)
예제 #32
0
    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(), ])
예제 #33
0
    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
예제 #34
0
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()))
예제 #35
0
파일: idserver.py 프로젝트: xispa/bika.lims
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
예제 #36
0
 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)