Пример #1
0
    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)
Пример #2
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)
Пример #3
0
    def add_object_at(self, object_brain_uid, row, column):
        """Adds an object to the specified position. If an object already exists
        at the given position, return False. Otherwise, return True
        """
        if not self.can_add_object(object_brain_uid, row, column):
            return False

        uid = api.get_uid(object_brain_uid)
        obj = api.get_object(object_brain_uid)

        # If the object does not implement StorageLayoutContainer, then we
        # assume the object is not a container, rather the content that needs to
        # be contained (e.g. a Sample), so we set capacity and utilization to 1
        samples_capacity = 1
        samples_utilization = 1
        if IStorageLayoutContainer.providedBy(obj):
            # This is a container, so infer the capacity and utilization
            samples_capacity = obj.get_samples_capacity()
            samples_utilization = obj.get_samples_utilization()

        row = api.to_int(row)
        column = api.to_int(column)
        layout = [{'uid': uid,
                   'row': row,
                   'column': column,
                   'samples_capacity': samples_capacity,
                   'samples_utilization': samples_utilization,}]
        for item in self.getPositionsLayout():
            if item["row"] == row and item["column"] == column:
                continue
            layout.append(item.copy())
        self.setPositionsLayout(layout)
        self.notify_parent()
        return True
Пример #4
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()))
Пример #5
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()))
Пример #6
0
 def get_layout_containers(self):
     """Returns the containers that belong to this facility and implement
     IStorageLayoutContainer
     """
     return filter(lambda obj: IStorageLayoutContainer.providedBy(obj),
                   self.objectValues())