diff --git a/CHANGES.rst b/CHANGES.rst index 7f16b25ee9..56faadad32 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,7 @@ Changelog 2.0.0rc3 (unreleased) --------------------- +- #1727 Cleanup Controlpanel Items - #1726 Content rules control panel templates styled - #1724 Purge stale metadata and indexes from analysis catalog - #1720 Fix UnicodeDecodeError for Instrument Import Log View diff --git a/src/bika/lims/__init__.py b/src/bika/lims/__init__.py index 9022d9dbbf..327c9f2c4e 100644 --- a/src/bika/lims/__init__.py +++ b/src/bika/lims/__init__.py @@ -94,7 +94,6 @@ def initialize(context): from bika.lims.content.containertype import ContainerType # noqa from bika.lims.content.department import Department # noqa from bika.lims.content.duplicateanalysis import DuplicateAnalysis # noqa - from bika.lims.content.identifiertype import IdentifierType # noqa from bika.lims.content.instrument import Instrument # noqa from bika.lims.content.instrumentcalibration import InstrumentCalibration # noqa from bika.lims.content.instrumentcertification import InstrumentCertification # noqa @@ -149,7 +148,6 @@ def initialize(context): from bika.lims.controlpanel.bika_containers import Containers # noqa from bika.lims.controlpanel.bika_containertypes import ContainerTypes # noqa from bika.lims.controlpanel.bika_departments import Departments # noqa - from bika.lims.controlpanel.bika_identifiertypes import IdentifierTypes # noqa from bika.lims.controlpanel.bika_instrumentlocations import InstrumentLocations # noqa from bika.lims.controlpanel.bika_instruments import Instruments # noqa from bika.lims.controlpanel.bika_instrumenttypes import InstrumentTypes # noqa diff --git a/src/bika/lims/controlpanel/bika_analysiscategories.py b/src/bika/lims/controlpanel/bika_analysiscategories.py index 7cffc67b82..b6d1326a52 100644 --- a/src/bika/lims/controlpanel/bika_analysiscategories.py +++ b/src/bika/lims/controlpanel/bika_analysiscategories.py @@ -86,8 +86,7 @@ def __init__(self, context, request): }), ("SortKey", { "title": _("Sort Key"), - "attr": "getSortKey", - "sortable": False + "sortable": True }), )) @@ -125,6 +124,7 @@ def folderitem(self, obj, item, index): item["replace"]["Title"] = get_link(url, value=title) item["Description"] = description + item["SortKey"] = obj.getSortKey() department = obj.getDepartment() if department: diff --git a/src/bika/lims/controlpanel/bika_analysisservices.py b/src/bika/lims/controlpanel/bika_analysisservices.py index ae04f3ffec..e2f2953afc 100644 --- a/src/bika/lims/controlpanel/bika_analysisservices.py +++ b/src/bika/lims/controlpanel/bika_analysisservices.py @@ -19,16 +19,7 @@ # Some rights reserved, see README and LICENSE. import collections -from senaite.core.interfaces import IHideActionsMenu -from transaction import savepoint -from Products.ATContentTypes.content.schemata import finalizeATCTSchema -from Products.Archetypes import atapi -from Products.CMFCore.utils import getToolByName -from Products.CMFPlone.utils import _createObjectByType -from Products.CMFPlone.utils import safe_unicode -from Products.Five.browser import BrowserView -from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView @@ -45,6 +36,15 @@ from plone.app.folder.folder import ATFolder from plone.app.folder.folder import ATFolderSchema from plone.app.layout.globals.interfaces import IViewView +from Products.Archetypes import atapi +from Products.ATContentTypes.content.schemata import finalizeATCTSchema +from Products.CMFCore.utils import getToolByName +from Products.CMFPlone.utils import _createObjectByType +from Products.CMFPlone.utils import safe_unicode +from Products.Five.browser import BrowserView +from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile +from senaite.core.interfaces import IHideActionsMenu +from transaction import savepoint from zope.i18n.locales import locales from zope.interface.declarations import implements @@ -249,7 +249,6 @@ def __init__(self, context, request): "sortable": False}), ("SortKey", { "title": _("Sort Key"), - "attr": "getSortKey", "sortable": False}), )) @@ -396,6 +395,10 @@ def folderitem(self, obj, item, index): unit = obj.getUnit() item["Unit"] = unit and format_supsub(unit) or "" + # Sort key + sortkey = obj.getSortKey() + item["SortKey"] = sortkey + # Icons after_icons = "" if obj.getAccredited(): diff --git a/src/bika/lims/controlpanel/bika_artemplates.py b/src/bika/lims/controlpanel/bika_artemplates.py index 948bd4c208..04236a4883 100644 --- a/src/bika/lims/controlpanel/bika_artemplates.py +++ b/src/bika/lims/controlpanel/bika_artemplates.py @@ -126,5 +126,6 @@ class ARTemplates(ATFolder): displayContentsTab = False schema = schema + schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(ARTemplates, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_batchlabels.py b/src/bika/lims/controlpanel/bika_batchlabels.py index 0657874409..8c099d4b23 100644 --- a/src/bika/lims/controlpanel/bika_batchlabels.py +++ b/src/bika/lims/controlpanel/bika_batchlabels.py @@ -18,16 +18,18 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi -from bika.lims import api +import collections + from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView from bika.lims.config import PROJECTNAME from bika.lims.interfaces import IBatchLabels from bika.lims.permissions import AddBatchLabel from bika.lims.utils import get_link -from plone.app.folder.folder import ATFolder, ATFolderSchema +from plone.app.folder.folder import ATFolder +from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements @@ -36,52 +38,72 @@ class BatchLabelsView(BikaListingView): def __init__(self, context, request): super(BatchLabelsView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'BatchLabel', - 'sort_on': 'sortable_title'} - self.context_actions = {_('Add'): - {'url': 'createObject?type_name=BatchLabel', - 'permission': AddBatchLabel, - 'icon': '++resource++bika.lims.images/add.png'}} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "BatchLabel", + "sort_on": "sortable_title", + } + self.context_actions = { + _("Add"): { + "url": "createObject?type_name=BatchLabel", + "permission": AddBatchLabel, + "icon": "++resource++bika.lims.images/add.png"} + } + self.title = self.context.translate(_("Batch Labels")) - self.icon = self.portal_url + "/++resource++bika.lims.images/batchlabel_big.png" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/batchlabel_big.png" + ) self.description = "" self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Label'), - 'index':'sortable_title'}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Label"), + "index": "sortable_title"}), + )) self.review_states = [ - {'id':'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id':'deactivate'}, ], - 'columns': ['Title']}, - {'id':'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id':'activate'}, ], - 'columns': ['Title']}, - {'id':'all', - 'title': _('All'), - 'contentFilter':{}, - 'columns': ['Title']}, + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): - item["replace"]["Title"] = get_link(item["url"], item["Title"]) + item["replace"]["Title"] = get_link( + item["url"], item["Title"]) return item + schema = ATFolderSchema.copy() + + class BatchLabels(ATFolder): implements(IBatchLabels, IHideActionsMenu) displayContentsTab = False schema = schema -schemata.finalizeATCTSchema(schema, folderish = True, moveDiscussion = False) + +schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(BatchLabels, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_containers.py b/src/bika/lims/controlpanel/bika_containers.py index 9ad79a59d2..6b8603d57a 100644 --- a/src/bika/lims/controlpanel/bika_containers.py +++ b/src/bika/lims/controlpanel/bika_containers.py @@ -18,8 +18,8 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi +import collections + from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView @@ -28,7 +28,10 @@ from bika.lims.permissions import AddContainer from bika.lims.utils import get_link from bika.lims.utils import get_link_for -from plone.app.folder.folder import ATFolder, ATFolderSchema +from plone.app.folder.folder import ATFolder +from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements @@ -37,63 +40,71 @@ class ContainersView(BikaListingView): def __init__(self, context, request): super(ContainersView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'Container', - 'sort_on': 'sortable_title'} - self.context_actions = {_('Add'): - {'url': 'createObject?type_name=Container', - 'permission': AddContainer, - 'icon': '++resource++bika.lims.images/add.png'}} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "Container", + "sort_on": "sortable_title", + } + + self.context_actions = { + _("Add"): { + "url": "createObject?type_name=Container", + "permission": AddContainer, + "icon": "++resource++bika.lims.images/add.png"} + } + self.title = self.context.translate(_("Containers")) - self.icon = self.portal_url + "/++resource++bika.lims.images/container_big.png" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/container_big.png" + ) + self.description = "" self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Container'), - 'index':'sortable_title'}, - 'Description': {'title': _('Description'), - 'index': 'description', - 'toggle': True}, - 'ContainerType': {'title': _('Container Type'), - 'toggle': True}, - 'Capacity': {'title': _('Capacity'), - 'toggle': True}, - 'Pre-preserved': {'title': _('Pre-preserved'), - 'toggle': True}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Container"), + "index": "sortable_title"}), + ("Description", { + "title": _("Description"), + "index": "description", + "toggle": True}), + ("ContainerType", { + "title": _("Container Type"), + "toggle": True}), + ("Capacity", { + "title": _("Capacity"), + "toggle": True}), + ("Pre-preserved", { + "title": _("Pre-preserved"), + "toggle": True}), + )) - self.review_states = [ # leave these titles and ids alone - {'id':'default', - 'contentFilter': {'is_active': True}, - 'title': _('Active'), - 'transitions': [{'id':'deactivate'}, ], - 'columns': ['Title', - 'Description', - 'ContainerType', - 'Capacity', - 'Pre-preserved']}, - {'id':'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id':'activate'}, ], - 'columns': ['Title', - 'Description', - 'ContainerType', - 'Capacity', - 'Pre-preserved']}, - {'id':'all', - 'title': _('All'), - 'contentFilter':{}, - 'transitions': [], - 'columns': ['Title', - 'Description', - 'ContainerType', - 'Capacity', - 'Pre-preserved']}, + self.review_states = [ + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): @@ -108,19 +119,23 @@ def folderitem(self, obj, item, index): }) if obj.getPrePreserved(): - item["after"]["Pre-preserved"] = get_link_for(obj.getPreservation()) + item["after"]["Pre-preserved"] = get_link_for( + obj.getPreservation()) + + item["replace"]["Title"] = get_link( + item["url"], item["Title"]) - item["replace"]["Title"] = get_link(item["url"], item["Title"]) return item schema = ATFolderSchema.copy() + class Containers(ATFolder): implements(IContainers, IHideActionsMenu) displayContentsTab = False schema = schema -schemata.finalizeATCTSchema(schema, folderish = True, moveDiscussion = False) +schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(Containers, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_containertypes.py b/src/bika/lims/controlpanel/bika_containertypes.py index f739d9b2e9..5b42b0f613 100644 --- a/src/bika/lims/controlpanel/bika_containertypes.py +++ b/src/bika/lims/controlpanel/bika_containertypes.py @@ -18,8 +18,8 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi +import collections + from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView @@ -27,7 +27,10 @@ from bika.lims.interfaces import IContainerTypes from bika.lims.permissions import AddContainerType from bika.lims.utils import get_link -from plone.app.folder.folder import ATFolder, ATFolderSchema +from plone.app.folder.folder import ATFolder +from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements @@ -36,53 +39,69 @@ class ContainerTypesView(BikaListingView): def __init__(self, context, request): super(ContainerTypesView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'ContainerType', - 'sort_on': 'sortable_title'} - self.context_actions = {_('Add'): - {'url': 'createObject?type_name=ContainerType', - 'permission': AddContainerType, - 'icon': '++resource++bika.lims.images/add.png'}} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "ContainerType", + "sort_on": "sortable_title", + } + + self.context_actions = { + _('Add'): { + 'url': 'createObject?type_name=ContainerType', + 'permission': AddContainerType, + 'icon': '++resource++bika.lims.images/add.png'} + } + self.title = self.context.translate(_("Container Types")) - self.icon = self.portal_url + "/++resource++bika.lims.images/container_big.png" self.description = "" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/container_big.png" + ) self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Container Type'), - 'index':'sortable_title'}, - 'Description': {'title': _('Description'), - 'index': 'description', - 'toggle': True}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Title"), + "index": "sortable_title"}), + ("Description", { + "title": _("Description"), + "index": "Description", + "toggle": True, + }), + )) self.review_states = [ - {'id':'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id':'deactivate'}, ], - 'columns': ['Title', - 'Description']}, - {'id':'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id':'activate'}, ], - 'columns': ['Title', - 'Description']}, - {'id':'all', - 'title': _('All'), - 'contentFilter':{}, - 'columns': ['Title', - 'Description']}, + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): obj = api.get_object(obj) item["Description"] = obj.Description() - item["replace"]["Title"] = get_link(item["url"], item["Title"]) + item["replace"]["Title"] = get_link( + item["url"], item["Title"]) return item @@ -95,6 +114,5 @@ class ContainerTypes(ATFolder): schema = schema -schemata.finalizeATCTSchema(schema, folderish = True, moveDiscussion = False) +schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(ContainerTypes, PROJECTNAME) - diff --git a/src/bika/lims/controlpanel/bika_identifiertypes.py b/src/bika/lims/controlpanel/bika_identifiertypes.py deleted file mode 100644 index 91157de462..0000000000 --- a/src/bika/lims/controlpanel/bika_identifiertypes.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of SENAITE.CORE. -# -# SENAITE.CORE is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Copyright 2018-2020 by it's authors. -# Some rights reserved, see README and LICENSE. - -from bika.lims.config import PROJECTNAME -from bika.lims.interfaces import IIdentifierTypes -from plone.app.folder.folder import ATFolder -from plone.app.folder.folder import ATFolderSchema -from Products.Archetypes.public import registerType -from Products.ATContentTypes.content import schemata -from senaite.core.interfaces import IHideActionsMenu -from zope.interface.declarations import implements - - -schema = ATFolderSchema.copy() - - -class IdentifierTypes(ATFolder): - implements(IIdentifierTypes, IHideActionsMenu) - displayContentsTab = False - schema = schema - - -schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) - -registerType(IdentifierTypes, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_idserver.py b/src/bika/lims/controlpanel/bika_idserver.py deleted file mode 100644 index 3736fd975e..0000000000 --- a/src/bika/lims/controlpanel/bika_idserver.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of SENAITE.CORE. -# -# SENAITE.CORE is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Copyright 2018-2020 by it's authors. -# Some rights reserved, see README and LICENSE. - -from AccessControl import ClassSecurityInfo -from App.class_init import InitializeClass -from OFS.SimpleItem import SimpleItem -from Products.CMFCore import permissions -from Products.CMFCore.utils import getToolByName -from bika.lims import bikaMessageFactory as _ -from bika.lims.utils import t -from bika.lims.interfaces import IIdServer -from zope.interface.declarations import implements -from hashlib import sha1 -import App,os,sys,random,time,urllib,hmac - -try: - from zope.component.hooks import getSite -except: - # Plone < 4.3 - from zope.app.component.hooks import getSite - -class IDServerUnavailable(Exception): - pass - -class bika_idserver(object): - - implements(IIdServer) - security = ClassSecurityInfo() - - security.declarePublic('generate_id') - def generate_id(self, portal_type, batch_size = None): - """ Generate a new id for 'portal_type' - """ - plone = getSite() - portal_id = plone.getId() - - if portal_type == 'News Item': - portal_type = 'NewsItem' - - idserver_url = os.environ.get('IDServerURL') - try: - if batch_size: - # GET - f = urllib.urlopen('%s/%s%s?%s' % ( - idserver_url, - portal_id, - portal_type, - urllib.urlencode({'batch_size': batch_size})) - ) - else: - f = urllib.urlopen('%s/%s%s' % ( - idserver_url, portal_id, portal_type - ) - ) - id = f.read() - f.close() - except: - from sys import exc_info - info = exc_info() - import zLOG; zLOG.LOG('INFO', 0, '', 'generate_id raised exception: %s, %s \n idserver_url: %s' % (info[0], info[1], idserver_url)) - raise IDServerUnavailable(_('ID Server unavailable')) - return id diff --git a/src/bika/lims/controlpanel/bika_instruments.py b/src/bika/lims/controlpanel/bika_instruments.py index 585aadda46..68c0e07fa2 100644 --- a/src/bika/lims/controlpanel/bika_instruments.py +++ b/src/bika/lims/controlpanel/bika_instruments.py @@ -20,8 +20,6 @@ import collections -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView @@ -31,10 +29,11 @@ from bika.lims.utils import get_link from plone.app.folder.folder import ATFolder from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements - # TODO: Separate content and view into own modules! diff --git a/src/bika/lims/controlpanel/bika_instrumenttypes.py b/src/bika/lims/controlpanel/bika_instrumenttypes.py index c3d13ad61d..8b3f07b235 100644 --- a/src/bika/lims/controlpanel/bika_instrumenttypes.py +++ b/src/bika/lims/controlpanel/bika_instrumenttypes.py @@ -18,8 +18,8 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi +import collections + from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView @@ -27,7 +27,10 @@ from bika.lims.interfaces import IInstrumentTypes from bika.lims.permissions import AddInstrumentType from bika.lims.utils import get_link -from plone.app.folder.folder import ATFolder, ATFolderSchema +from plone.app.folder.folder import ATFolder +from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements @@ -36,44 +39,62 @@ class InstrumentTypesView(BikaListingView): def __init__(self, context, request): super(InstrumentTypesView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'InstrumentType', - 'sort_on': 'sortable_title'} - self.context_actions = {_('Add'): - {'url': 'createObject?type_name=InstrumentType', - 'permission': AddInstrumentType, - 'icon': '++resource++bika.lims.images/add.png'}} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "InstrumentType", + "sort_on": "sortable_title", + } + + self.context_actions = { + _('Add'): { + 'url': 'createObject?type_name=InstrumentType', + 'permission': AddInstrumentType, + 'icon': '++resource++bika.lims.images/add.png'} + } + self.title = self.context.translate(_("Instrument Types")) - self.icon = "++resource++bika.lims.images/instrumenttype_big.png" self.description = "" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/instrumenttype_big.png" + ) self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Title'), - 'index': 'sortable_title'}, - 'Description': {'title': _('Description'), - 'index': 'description', - 'toggle': True}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Title"), + "index": "sortable_title"}), + ("Description", { + "title": _("Description"), + "index": "Description", + "toggle": True, + }), + )) self.review_states = [ - {'id':'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id':'deactivate'}, ], - 'columns': ['Title', 'Description']}, - {'id':'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id':'activate'}, ], - 'columns': ['Title', 'Description']}, - {'id':'all', - 'title': _('All'), - 'contentFilter':{}, - 'columns': ['Title', 'Description']}, + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): @@ -91,5 +112,6 @@ class InstrumentTypes(ATFolder): displayContentsTab = False schema = schema -schemata.finalizeATCTSchema(schema, folderish = True, moveDiscussion = False) + +schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(InstrumentTypes, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_labproducts.py b/src/bika/lims/controlpanel/bika_labproducts.py index 11c989867a..d0c398a024 100644 --- a/src/bika/lims/controlpanel/bika_labproducts.py +++ b/src/bika/lims/controlpanel/bika_labproducts.py @@ -18,87 +18,96 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi +import collections + from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView from bika.lims.config import PROJECTNAME from bika.lims.interfaces import ILabProducts from bika.lims.permissions import AddLabProduct -from plone.app.folder.folder import ATFolder, ATFolderSchema +from bika.lims.utils import get_link +from plone.app.folder.folder import ATFolder +from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements -from bika.lims.utils import get_link - class LabProductsView(BikaListingView): def __init__(self, context, request): super(LabProductsView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'LabProduct', - 'sort_on': 'sortable_title'} - self.context_actions = {_('Add'): - {'url': 'createObject?type_name=LabProduct', - 'permission': AddLabProduct, - 'icon': '++resource++bika.lims.images/add.png'}} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "LabProduct", + "sort_on": "sortable_title", + } + + self.context_actions = { + _("Add"): { + "url": "createObject?type_name=LabProduct", + "permission": AddLabProduct, + "icon": "++resource++bika.lims.images/add.png"} + } + self.title = self.context.translate(_("Lab Products")) - self.icon = self.portal_url + "/++resource++bika.lims.images/product_big.png" self.description = "" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/product_big.png" + ) self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Title'), - 'index': 'sortable_title', - 'toggle': True}, - 'Volume': {'title': _('Volume'), - 'toggle': True}, - 'Unit': {'title': _('Unit'), - 'toggle': True}, - 'Price': {'title': _('Price'), - 'index': 'price', - 'toggle': True}, - 'VATAmount': {'title': _('VAT Amount'), - 'toggle': True}, - 'TotalPrice': {'title': _('Total Price'), - 'index': 'price_total', - 'toggle': True}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Title"), + "index": "sortable_title", + "toggle": True}), + ("Volume", { + "title": _("Volume"), + "toggle": True}), + ("Unit", { + "title": _("Unit"), + "toggle": True}), + ("Price", { + "title": _("Price"), + "index": "price", + "toggle": True}), + ("VATAmount", { + "title": _("VAT Amount"), + "toggle": True}), + ("TotalPrice", { + "title": _("Total Price"), + "index": "price_total", + "toggle": True}), + )) + self.review_states = [ - {'id':'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id':'deactivate'}, ], - 'columns': ['Title', - 'Volume', - 'Unit', - 'Price', - 'VATAmount', - 'TotalPrice']}, - {'id':'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id':'activate'}, ], - 'columns': ['Title', - 'Volume', - 'Unit', - 'Price', - 'VATAmount', - 'TotalPrice']}, - {'id':'all', - 'title': _('All'), - 'contentFilter':{}, - 'columns': ['Title', - 'Volume', - 'Unit', - 'Price', - 'VATAmount', - 'TotalPrice']}, + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): @@ -115,10 +124,13 @@ def folderitem(self, obj, item, index): schema = ATFolderSchema.copy() + + class LabProducts(ATFolder): implements(ILabProducts, IHideActionsMenu) displayContentsTab = False schema = schema -schemata.finalizeATCTSchema(schema, folderish = True, moveDiscussion = False) + +schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(LabProducts, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_manufacturers.py b/src/bika/lims/controlpanel/bika_manufacturers.py index 2410a302d9..896ac206cb 100644 --- a/src/bika/lims/controlpanel/bika_manufacturers.py +++ b/src/bika/lims/controlpanel/bika_manufacturers.py @@ -18,16 +18,19 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi -from bika.lims import bikaMessageFactory as _ +import collections + from bika.lims import api +from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView from bika.lims.config import PROJECTNAME from bika.lims.interfaces import IManufacturers from bika.lims.permissions import AddManufacturer from bika.lims.utils import get_link -from plone.app.folder.folder import ATFolder, ATFolderSchema +from plone.app.folder.folder import ATFolder +from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements @@ -36,44 +39,62 @@ class ManufacturersView(BikaListingView): def __init__(self, context, request): super(ManufacturersView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'Manufacturer', - 'sort_on': 'sortable_title'} - self.context_actions = {_('Add'): - {'url': 'createObject?type_name=Manufacturer', - 'permission': AddManufacturer, - 'icon': '++resource++bika.lims.images/add.png'}} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "Manufacturer", + "sort_on": "sortable_title", + } + + self.context_actions = { + _("Add"): { + "url": "createObject?type_name=Manufacturer", + "permission": AddManufacturer, + "icon": "++resource++bika.lims.images/add.png"} + } + self.title = self.context.translate(_("Manufacturers")) - self.icon = "++resource++bika.lims.images/manufacturer_big.png" self.description = "" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/manufacturer_big.png" + ) self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Title'), - 'index': 'sortable_title'}, - 'Description': {'title': _('Description'), - 'index': 'description', - 'toggle': True}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Manufacturer"), + "index": "sortable_title"}), + ("Description", { + "title": _("Description"), + "index": "Description", + "toggle": True, + }), + )) self.review_states = [ - {'id':'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id':'deactivate'}, ], - 'columns': ['Title', 'Description']}, - {'id':'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id':'activate'}, ], - 'columns': ['Title', 'Description']}, - {'id':'all', - 'title': _('All'), - 'contentFilter':{}, - 'columns': ['Title', 'Description']}, + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): @@ -91,5 +112,6 @@ class Manufacturers(ATFolder): displayContentsTab = False schema = schema -schemata.finalizeATCTSchema(schema, folderish = True, moveDiscussion = False) + +schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(Manufacturers, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_preservations.py b/src/bika/lims/controlpanel/bika_preservations.py index e7aec04cfc..5141a84dea 100644 --- a/src/bika/lims/controlpanel/bika_preservations.py +++ b/src/bika/lims/controlpanel/bika_preservations.py @@ -18,8 +18,8 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi +import collections + from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView @@ -27,7 +27,10 @@ from bika.lims.interfaces import IPreservations from bika.lims.permissions import AddPreservation from bika.lims.utils import get_link -from plone.app.folder.folder import ATFolder, ATFolderSchema +from plone.app.folder.folder import ATFolder +from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements @@ -36,53 +39,69 @@ class PreservationsView(BikaListingView): def __init__(self, context, request): super(PreservationsView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'Preservation', - 'sort_on': 'sortable_title'} - self.context_actions = {_('Add'): - {'url': 'createObject?type_name=Preservation', - 'permission': AddPreservation, - 'icon': '++resource++bika.lims.images/add.png'}} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "Preservation", + "sort_on": "sortable_title", + } + + self.context_actions = { + _("Add"): { + "url": "createObject?type_name=Preservation", + "permission": AddPreservation, + "icon": "++resource++bika.lims.images/add.png"} + } + self.title = self.context.translate(_("Preservations")) - self.icon = self.portal_url + "/++resource++bika.lims.images/preservation_big.png" self.description = "" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/preservation_big.png" + ) self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Preservation'), - 'index':'sortable_title'}, - 'Description': {'title': _('Description'), - 'index': 'description', - 'toggle': True}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Preservation"), + "index": "sortable_title"}), + ("Description", { + "title": _("Description"), + "index": "Description", + "toggle": True, + }), + )) self.review_states = [ - {'id':'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id':'deactivate'}, ], - 'columns': ['Title', - 'Description']}, - {'id':'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id':'activate'}, ], - 'columns': ['Title', - 'Description']}, - {'id':'all', - 'title': _('All'), - 'contentFilter':{}, - 'columns': ['Title', - 'Description']}, + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): obj = api.get_object(obj) item["Description"] = obj.Description() - item["replace"]["Title"] = get_link(item["url"], item["Title"]) + item["replace"]["Title"] = get_link( + item["url"], item["Title"]) return item @@ -94,5 +113,6 @@ class Preservations(ATFolder): displayContentsTab = False schema = schema -schemata.finalizeATCTSchema(schema, folderish = True, moveDiscussion = False) + +schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(Preservations, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_reflexrulefolder.py b/src/bika/lims/controlpanel/bika_reflexrulefolder.py index 13f874d3d0..dfe95bb00b 100644 --- a/src/bika/lims/controlpanel/bika_reflexrulefolder.py +++ b/src/bika/lims/controlpanel/bika_reflexrulefolder.py @@ -18,20 +18,20 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi -from Products.CMFCore import permissions -from Products.CMFCore.utils import getToolByName +import collections + from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView from bika.lims.config import PROJECTNAME from bika.lims.interfaces import IReflexRuleFolder -from bika.lims.permissions import ManageBika, AddReflexRule +from bika.lims.permissions import AddReflexRule from bika.lims.utils import get_link from bika.lims.utils import get_link_for from plone.app.folder.folder import ATFolder from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements @@ -40,21 +40,35 @@ class ReflexRuleFolderView(BikaListingView): def __init__(self, context, request): super(ReflexRuleFolderView, self).__init__(context, request) + self.catalog = "portal_catalog" + self.contentFilter = { - 'portal_type': 'ReflexRule', - 'path': { + "portal_type": "ReflexRule", + "path": { "query": "/".join(self.context.getPhysicalPath()), "level": 0 }, } + self.context_actions = { + _("Add"): { + "url": "createObject?type_name=ReflexRule", + "permission": AddReflexRule, + "icon": "++resource++bika.lims.images/add.png"} + } + self.show_select_row = False self.show_select_column = True - self.icon = self.portal_url +\ - "/++resource++bika.lims.images/reflexrule_big.png" + self.pagesize = 25 + self.title = self.context.translate(_("Reflex rules folder")) self.description = "" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/reflexrule_big.png" + ) + self.columns = { 'Title': { 'title': _('Reflex Rule'), @@ -65,41 +79,37 @@ def __init__(self, context, request): 'index': 'sortable_title' } } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Reflex Rule"), + "index": "sortable_title"}), + ("Method", { + "title": _("Method"), + "index": "sortable_title" + }), + )) + self.review_states = [ - {'id': 'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'columns': ['Title', 'Method', ]}, - {'id': 'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'columns': ['Title', 'Method', ]}, - {'id': 'all', - 'title': _('All'), - 'contentFilter': {}, - 'columns': ['Title', 'Method', ]}, + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] - def __call__(self): - mtool = getToolByName(self.context, 'portal_membership') - if mtool.checkPermission( - permissions.ModifyPortalContent, - self.context): - self.context_actions[_('Add Reflex rule')] = { - 'url': 'createObject?type_name=ReflexRule', - 'permission': AddReflexRule, - 'icon': '++resource++bika.lims.images/add.png' - } - if not mtool.checkPermission(ManageBika, self.context): - self.show_select_column = False - self.review_states = [ - {'id': 'default', - 'title': _('All'), - 'contentFilter': {}, - 'columns': ['Title']} - ] - return super(ReflexRuleFolderView, self).__call__() - def folderitem(self, obj, item, index): obj = api.get_object(obj) method = obj.getMethod() @@ -120,9 +130,5 @@ class ReflexRuleFolder(ATFolder): schema = schema -schemata.finalizeATCTSchema( - schema, - folderish=True, - moveDiscussion=False) - +schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(ReflexRuleFolder, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_sampleconditions.py b/src/bika/lims/controlpanel/bika_sampleconditions.py index 932371b2e2..f797499d0a 100644 --- a/src/bika/lims/controlpanel/bika_sampleconditions.py +++ b/src/bika/lims/controlpanel/bika_sampleconditions.py @@ -79,25 +79,23 @@ def __init__(self, context, request): self.review_states = [ { - 'id': 'default', - 'title': _('All'), - 'contentFilter': {}, - 'transitions': [{'id': 'empty'}, ], + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], "columns": self.columns.keys(), }, { - 'id': 'active', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id': 'deactivate'}, ], + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], "columns": self.columns.keys(), }, { - 'id': 'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id': 'activate'}, ], + "id": "all", + "title": _("All"), + "contentFilter": {}, "columns": self.columns.keys(), - - } + }, ] def folderitem(self, obj, item, index): diff --git a/src/bika/lims/controlpanel/bika_samplematrices.py b/src/bika/lims/controlpanel/bika_samplematrices.py index 167c6310d9..78eb06ba79 100644 --- a/src/bika/lims/controlpanel/bika_samplematrices.py +++ b/src/bika/lims/controlpanel/bika_samplematrices.py @@ -18,6 +18,8 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. +import collections + from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView from bika.lims.config import PROJECTNAME @@ -36,51 +38,66 @@ class SampleMatricesView(BikaListingView): def __init__(self, context, request): super(SampleMatricesView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'SampleMatrix', - 'sort_on': 'sortable_title'} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "SampleMatrix", + "sort_on": "sortable_title", + } + self.context_actions = {_('Add'): { 'url': 'createObject?type_name=SampleMatrix', 'permission': AddSampleMatrix, 'icon': '++resource++bika.lims.images/add.png' }} + self.title = self.context.translate(_("Sample Matrices")) - self.icon = self.portal_url + \ - "/++resource++bika.lims.images/samplematrix_big.png" self.description = "" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/samplematrix_big.png" + ) self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Sample Matrix'), - 'index': 'sortable_title'}, - 'Description': {'title': _('Description'), - 'index': 'description', - 'toggle': True}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Sample Matrix"), + "index": "sortable_title"}), + ("Description", { + "title": _("Description"), + "index": "Description", + "toggle": True, + }), + )) self.review_states = [ - {'id': 'default', - 'title': _('All'), - 'contentFilter': {}, - 'transitions': [{'id': 'empty'}, ], - 'columns': ['Title', 'Description']}, - {'id': 'active', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id': 'deactivate'}, ], - 'columns': ['Title', 'Description']}, - {'id': 'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id': 'activate'}, ], - 'columns': ['Title', 'Description']} + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): - item["replace"]["Title"] = get_link(item["url"], item["Title"]) + item["replace"]["Title"] = get_link( + item["url"], item["Title"]) return item diff --git a/src/bika/lims/controlpanel/bika_samplepoints.py b/src/bika/lims/controlpanel/bika_samplepoints.py index 267cf1776f..b9e4621c12 100644 --- a/src/bika/lims/controlpanel/bika_samplepoints.py +++ b/src/bika/lims/controlpanel/bika_samplepoints.py @@ -19,30 +19,21 @@ # Some rights reserved, see README and LICENSE. import collections -import json - -import plone -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi -from Products.CMFCore.permissions import ModifyPortalContent -from Products.CMFCore.utils import getToolByName -from Products.CMFPlone.utils import safe_unicode -from plone.app.folder.folder import ATFolder -from plone.app.folder.folder import ATFolderSchema -from senaite.core.interfaces import IHideActionsMenu -from zope.interface.declarations import implements from bika.lims import api from bika.lims import bikaMessageFactory as _ -from bika.lims.api.security import check_permission -from bika.lims.browser import BrowserView from bika.lims.browser.bika_listing import BikaListingView from bika.lims.catalog import SETUP_CATALOG from bika.lims.config import PROJECTNAME from bika.lims.interfaces import ISamplePoints from bika.lims.permissions import AddSamplePoint from bika.lims.utils import get_link_for - +from plone.app.folder.folder import ATFolder +from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata +from senaite.core.interfaces import IHideActionsMenu +from zope.interface.declarations import implements # TODO: Separate content and view into own modules! @@ -140,92 +131,6 @@ def folderitem(self, obj, item, index): return item -class ajax_SamplePoints(BrowserView): - """ The autocomplete data source for sample point selection widgets. - Returns a JSON list of sample point titles. - - Request parameters: - - - sampletype: if specified, it's expected to be the title - of a SamplePoint object. Optionally, the string 'Lab: ' might be - prepended, to distinguish between Lab and Client objects. - - - term: the string which will be searched against all SamplePoint - titles. - - - _authenticator: The plone.protect authenticator. - """ - - def filter_list(self, items, searchterm): - if searchterm and len(searchterm) < 3: - # Items that start with A or AA - res = [s.getObject() for s in items - if s.title.lower().startswith(searchterm)] - if not res: - # or, items that contain A or AA - res = [s.getObject() for s in items - if s.title.lower().find(searchterm) > -1] - else: - # or, items that contain searchterm. - res = [s.getObject() for s in items - if s.title.lower().find(searchterm) > -1] - return res - - def __call__(self): - plone.protect.CheckAuthenticator(self.request) - bsc = getToolByName(self.context, 'bika_setup_catalog') - term = safe_unicode(self.request.get('term', '')).lower() - items = [] - if not term: - return json.dumps(items) - # Strip "Lab: " from sample point title - term = term.replace("%s: " % _("Lab"), "") - sampletype = safe_unicode(self.request.get("sampletype", "")) - if sampletype and len(sampletype) > 1: - st = bsc( - portal_type="SampleType", - title=sampletype, - is_active=True, - ) - if not st: - return json.dumps([]) - st = st[0].getObject() - items = [o.Title() for o in st.getSamplePoints()] - - if not items: - client_items = lab_items = [] - - # User (client) sample points - if self.context.portal_type in ("Client", "AnalysisRequest"): - if self.context.portal_type == "Client": - client_path = self.context.getPhysicalPath() - else: - client_path = self.context.aq_parent.getPhysicalPath() - client_items = list( - bsc(portal_type="SamplePoint", - path={"query": "/".join(client_path), "level": 0}, - is_active=True, - sort_on="sortable_title")) - - # Global (lab) sample points - sample_points = self.context.bika_setup.bika_samplepoints - lab_path = sample_points.getPhysicalPath() - lab_items = list( - bsc(portal_type="SamplePoint", - path={"query": "/".join(lab_path), "level": 0}, - is_active=True, - sort_on="sortable_title")) - client_items = [callable(s.Title) and s.Title() or s.title - for s in self.filter_list(client_items, term)] - lab_items = [callable(s.Title) and s.Title() or s.title - for s in self.filter_list(lab_items, term)] - lab_items = ["%s: %s" % (_("Lab"), safe_unicode(i)) - for i in lab_items] - items = client_items + lab_items - - return json.dumps(items) - - schema = ATFolderSchema.copy() diff --git a/src/bika/lims/controlpanel/bika_sampletypes.py b/src/bika/lims/controlpanel/bika_sampletypes.py index 1b9cd43397..9e6c7b803c 100644 --- a/src/bika/lims/controlpanel/bika_sampletypes.py +++ b/src/bika/lims/controlpanel/bika_sampletypes.py @@ -19,29 +19,21 @@ # Some rights reserved, see README and LICENSE. import collections -import json - -import plone -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi -from Products.CMFCore.permissions import ModifyPortalContent -from Products.CMFCore.utils import getToolByName -from Products.CMFPlone.utils import safe_unicode -from plone.app.folder.folder import ATFolder -from plone.app.folder.folder import ATFolderSchema -from senaite.core.interfaces import IHideActionsMenu -from zope.interface.declarations import implements from bika.lims import api from bika.lims import bikaMessageFactory as _ -from bika.lims.api.security import check_permission -from bika.lims.browser import BrowserView from bika.lims.browser.bika_listing import BikaListingView from bika.lims.catalog import SETUP_CATALOG from bika.lims.config import PROJECTNAME from bika.lims.interfaces import ISampleTypes from bika.lims.permissions import AddSampleType from bika.lims.utils import get_link_for +from plone.app.folder.folder import ATFolder +from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata +from senaite.core.interfaces import IHideActionsMenu +from zope.interface.declarations import implements # TODO: Separate content and view into own modules! @@ -161,6 +153,18 @@ def folderitem(self, obj, item, index): container_type = obj.getContainerType() item["replace"]["ContainerType"] = get_link_for(container_type) + # Hazardous + hazardous = obj.getHazardous() + item["getHazardous"] = hazardous + + # Prefix + prefix = obj.getPrefix() + item["getPrefix"] = prefix + + # Minimum Volume + vol = obj.getMinimumVolume() + item["getMinimumVolume"] = vol + # Hide sample points assigned to this sample type that do not belong # to the same container (Client or Setup) sample_points = obj.getSamplePoints() @@ -179,65 +183,6 @@ def folderitem(self, obj, item, index): return item -class ajax_SampleTypes(BrowserView): - """Autocomplete data source for sample types field - - return JSON data [string,string] - if "samplepoint" is in the request, it's expected to be a title string - The objects returned will be filtered by samplepoint's SampleTypes. - if no items are found, all items are returned. - - If term is a one or two letters, return items that begin with them - If there aren't any, return items that contain them - """ - def __call__(self): - plone.protect.CheckAuthenticator(self.request) - bsc = getToolByName(self.context, "bika_setup_catalog") - term = safe_unicode(self.request.get("term", "")).lower() - items = [] - if not term: - return json.dumps(items) - samplepoint = safe_unicode(self.request.get("samplepoint", "")) - # Strip "Lab: " from sample point titles - samplepoint = samplepoint.replace("%s: " % _("Lab"), "") - if samplepoint and len(samplepoint) > 1: - sp = bsc( - portal_type="SamplePoint", - is_active=True, - title=samplepoint - ) - if not sp: - return json.dumps([]) - sp = sp[0].getObject() - items = sp.getSampleTypes() - if not items: - items = bsc( - portal_type="SampleType", - is_active=True, - sort_on="sortable_title", - ) - if term and len(term) < 3: - # Items that start with A or AA - items = [ - s.getObject() for s in items - if s.title.lower().startswith(term) - ] - if not items: - # or, items that contain A or AA - items = [ - s.getObject() for s in items - if s.title.lower().find(term) > -1] - else: - # or, items that contain term. - items = [ - s.getObject() for s in items - if s.title.lower().find(term) > -1] - - items = [callable(s.Title) and s.Title() or s.title - for s in items] - return json.dumps(items) - - schema = ATFolderSchema.copy() diff --git a/src/bika/lims/controlpanel/bika_samplingdeviations.py b/src/bika/lims/controlpanel/bika_samplingdeviations.py index c644b6445b..47a86fab91 100644 --- a/src/bika/lims/controlpanel/bika_samplingdeviations.py +++ b/src/bika/lims/controlpanel/bika_samplingdeviations.py @@ -65,7 +65,7 @@ def __init__(self, context, request): self.columns = collections.OrderedDict(( ("Title", { - "title": _("Sampling Deviationn"), + "title": _("Sampling Deviation"), "index": "sortable_title"}), ("Description", { "title": _("Description"), diff --git a/src/bika/lims/controlpanel/bika_samplingrounds.py b/src/bika/lims/controlpanel/bika_samplingrounds.py deleted file mode 100644 index da97ad498b..0000000000 --- a/src/bika/lims/controlpanel/bika_samplingrounds.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of SENAITE.CORE. -# -# SENAITE.CORE is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Copyright 2018-2020 by it's authors. -# Some rights reserved, see README and LICENSE. - -from plone.dexterity.content import Container -from plone.supermodel import model -from zope.interface import implements - - -# TODO: Legacy type. Remove after 1.3.3 -class ISamplingRounds(model.Schema): - """ A Sampling Rounds container. - """ - - -# TODO: Legacy type. Remove after 1.3.3 -class SamplingRounds(Container): - implements(ISamplingRounds) - displayContentsTab = False diff --git a/src/bika/lims/controlpanel/bika_setupitems.py b/src/bika/lims/controlpanel/bika_setupitems.py deleted file mode 100644 index 2437ad581b..0000000000 --- a/src/bika/lims/controlpanel/bika_setupitems.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of SENAITE.CORE. -# -# SENAITE.CORE is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Copyright 2018-2020 by it's authors. -# Some rights reserved, see README and LICENSE. - -from bika.lims import bikaMessageFactory as _ -from bika.lims.browser.bika_listing import BikaListingView - - -class BikaSetupItemsView(BikaListingView): - - def __init__(self, context, request, typename, iconfilename): - super(BikaSetupItemsView, self).__init__(context, request) - self.show_select_column = True - self.icon = self.portal_url + "/++resource++bika.lims.images/" + iconfilename - self.catalog = 'bika_setup_catalog' - self.contentFilter = { - 'portal_type': typename, - 'sort_on': 'sortable_title' - } - self.context_actions = { - _('Add'): { - 'url': 'createObject?type_name='+typename, - 'icon': '++resource++bika.lims.images/add.png' - } - } - self.columns = { - 'Title': { - 'title': _('Title'), - 'index': 'sortable_title', - 'replace_url': 'absolute_url' - }, - 'Description': { - 'title': _('Description'), - 'index': 'description', - 'attr': 'Description' - }, - } - self.review_states = [ - {'id': 'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id': 'deactivate'}, ], - 'columns': ['Title', 'Description']}, - {'id': 'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id': 'activate'}, ], - 'columns': ['Title', 'Description']}, - {'id': 'all', - 'title': _('All'), - 'contentFilter': {}, - 'columns': ['Title', 'Description']}, - ] diff --git a/src/bika/lims/controlpanel/bika_srtemplates.py b/src/bika/lims/controlpanel/bika_srtemplates.py deleted file mode 100644 index 233dc97730..0000000000 --- a/src/bika/lims/controlpanel/bika_srtemplates.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of SENAITE.CORE. -# -# SENAITE.CORE is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Copyright 2018-2020 by it's authors. -# Some rights reserved, see README and LICENSE. - -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi -from plone.app.folder.folder import ATFolder -from plone.app.folder.folder import ATFolderSchema -from senaite.core.interfaces import IHideActionsMenu -from zope.interface.declarations import implements - -from bika.lims.config import PROJECTNAME -from bika.lims.interfaces import ISamplingRoundTemplates - -schema = ATFolderSchema.copy() - - -# TODO: Legacy type. Remove after 1.3.3 -class SRTemplates(ATFolder): - implements(ISamplingRoundTemplates, IHideActionsMenu) - displayContentsTab = False - schema = schema - - -schemata.finalizeATCTSchema(schema, folderish = True, moveDiscussion = False) -atapi.registerType(SRTemplates, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_storagelocations.py b/src/bika/lims/controlpanel/bika_storagelocations.py index a25d16a845..9b4bcd494d 100644 --- a/src/bika/lims/controlpanel/bika_storagelocations.py +++ b/src/bika/lims/controlpanel/bika_storagelocations.py @@ -18,87 +18,105 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -import json +import collections -import plone -from Products.ATContentTypes.content import schemata -from Products.Archetypes import PloneMessageFactory as _p -from Products.Archetypes import atapi -from Products.CMFCore.utils import getToolByName -from Products.CMFPlone.utils import safe_unicode from bika.lims import api from bika.lims import bikaMessageFactory as _ -from bika.lims.browser import BrowserView from bika.lims.browser.bika_listing import BikaListingView from bika.lims.config import PROJECTNAME from bika.lims.interfaces import IClient from bika.lims.interfaces import IStorageLocations from bika.lims.permissions import AddStorageLocation from bika.lims.utils import get_link +from bika.lims.utils import get_link_for from plone.app.folder.folder import ATFolder from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements -from bika.lims.utils import get_link - class StorageLocationsView(BikaListingView): def __init__(self, context, request): super(StorageLocationsView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'StorageLocation', - 'sort_on': 'sortable_title'} - self.context_actions = {_('Add'): - {'url': 'createObject?type_name=StorageLocation', - 'permission': AddStorageLocation, - 'icon': '++resource++bika.lims.images/add.png'}} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "StorageLocation", + "sort_on": "sortable_title", + } + + self.context_actions = { + _("Add"): { + "url": "createObject?type_name=StorageLocation", + "permission": AddStorageLocation, + "icon": "++resource++bika.lims.images/add.png"} + } + self.title = self.context.translate(_("Storage Locations")) - self.icon = self.portal_url + "/++resource++bika.lims.images/storagelocation_big.png" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/storagelocation_big.png" + ) self.description = "" self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Storage Location'), - 'index':'sortable_title'}, - 'Description': {'title': _('Description'), - 'index': 'description', - 'toggle': True}, - 'SiteTitle': {'title': _p('Site Title'), - 'toggle': True}, - 'SiteCode': {'title': _p('Site Code'), - 'toggle': True}, - 'LocationTitle': {'title': _p('Location Title'), - 'toggle': True}, - 'LocationCode': {'title': _p('Location Code'), - 'toggle': True}, - 'ShelfTitle': {'title': _p('Shelf Title'), - 'toggle': True}, - 'ShelfCode': {'title': _p('Shelf Code'), - 'toggle': True}, - 'Owner': {'title': _p('Owner'), - 'toggle': True}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Storage Location"), + "index": "sortable_title"}), + ("Description", { + "title": _("Description"), + "index": "description", + "toggle": True}), + ("SiteTitle", { + "title": _("Site Title"), + "toggle": True}), + ("SiteCode", { + "title": _("Site Code"), + "toggle": True}), + ("LocationTitle", { + "title": _("Location Title"), + "toggle": True}), + ("LocationCode", { + "title": _("Location Code"), + "toggle": True}), + ("ShelfTitle", { + "title": _("Shelf Title"), + "toggle": True}), + ("ShelfCode", { + "title": _("Shelf Code"), + "toggle": True}), + ("Owner", { + "title": _("Owner"), + "toggle": True}), + )) self.review_states = [ - {'id':'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id':'deactivate'}, ], - 'columns': ['Title', 'Description', 'Owner', 'SiteTitle', 'SiteCode', 'LocationTitle', 'LocationCode', 'ShelfTitle', 'ShelfCode']}, - {'id':'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id':'activate'}, ], - 'columns': ['Title', 'Description', 'Owner', 'SiteTitle', 'SiteCodeShelfCode' ]}, - {'id':'all', - 'title': _('All'), - 'contentFilter':{}, - 'columns': ['Title', 'Description', 'Owner', 'SiteTitle', 'SiteCodeShelfCode' ]}, + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {"is_active": False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): @@ -106,11 +124,22 @@ def folderitem(self, obj, item, index): item["Description"] = obj.Description() item["replace"]["Title"] = get_link(item["url"], item["Title"]) + item["SiteTitle"] = obj.getSiteTitle() + item["SiteCode"] = obj.getSiteCode() + item["LocationTitle"] = obj.getLocationTitle() + item["LocationCode"] = obj.getLocationCode() + item["ShelfTitle"] = obj.getShelfTitle() + item["ShelfCode"] = obj.getShelfCode() + parent = api.get_parent(obj) if IClient.providedBy(parent): item["Owner"] = api.get_title(parent) + item["replace"]["Owner"] = get_link_for(parent) else: - item["Owner"] = self.context.bika_setup.laboratory.Title() + lab = self.context.bika_setup.laboratory + item["Owner"] = lab.Title() + item["replace"]["Owner"] = get_link_for(lab) + return item @@ -122,75 +151,6 @@ class StorageLocations(ATFolder): displayContentsTab = False schema = schema -schemata.finalizeATCTSchema(schema, folderish = True, moveDiscussion = False) -atapi.registerType(StorageLocations, PROJECTNAME) - - -class ajax_StorageLocations(BrowserView): - """ The autocomplete data source for storage location selection widgets. - Returns a JSON list of storage location titles. - Request parameters: - - - term: the string which will be searched against all Storage Location - titles. - - - _authenticator: The plone.protect authenticator. - - """ - - def filter_list(self, items, searchterm): - if searchterm and len(searchterm) < 3: - # Items that start with A or AA - res = [s.getObject() - for s in items - if s.title.lower().startswith(searchterm)] - if not res: - # or, items that contain A or AA - res = [s.getObject() - for s in items - if s.title.lower().find(searchterm) > -1] - else: - # or, items that contain searchterm. - res = [s.getObject() - for s in items - if s.title.lower().find(searchterm) > -1] - return res - - def __call__(self): - plone.protect.CheckAuthenticator(self.request) - bsc = getToolByName(self.context, 'bika_setup_catalog') - term = safe_unicode(self.request.get('term', '')).lower() - if not term: - return json.dumps([]) - - client_items = lab_items = [] - - # User (client) storage locations - if self.context.portal_type == 'Client': - client_path = self.context.getPhysicalPath() - client_items = list( - bsc(portal_type = "StorageLocation", - path = {"query": "/".join(client_path), "level" : 0 }, - is_active = True, - sort_on='sortable_title')) - - # Global (lab) storage locations - lab_path = \ - self.context.bika_setup.bika_storagelocations.getPhysicalPath() - lab_items = list( - bsc(portal_type = "StorageLocation", - path = {"query": "/".join(lab_path), "level" : 0 }, - is_active = True, - sort_on='sortable_title')) - - client_items = [callable(s.Title) and s.Title() or s.title - for s in self.filter_list(client_items, term)] - lab_items = [callable(s.Title) and s.Title() or s.title - for s in self.filter_list(lab_items, term)] - lab_items = ["%s: %s" % (_("Lab"), safe_unicode(i)) - for i in lab_items] - - items = client_items + lab_items - - return json.dumps(items) +schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) +atapi.registerType(StorageLocations, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/bika_subgroups.py b/src/bika/lims/controlpanel/bika_subgroups.py index d7ed71b85d..a3d1ee44cd 100644 --- a/src/bika/lims/controlpanel/bika_subgroups.py +++ b/src/bika/lims/controlpanel/bika_subgroups.py @@ -18,9 +18,9 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. +import collections + from AccessControl.SecurityInfo import ClassSecurityInfo -from Products.ATContentTypes.content import schemata -from Products.Archetypes import atapi from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.bika_listing import BikaListingView @@ -30,6 +30,8 @@ from bika.lims.utils import get_link from plone.app.folder.folder import ATFolder from plone.app.folder.folder import ATFolderSchema +from Products.Archetypes import atapi +from Products.ATContentTypes.content import schemata from senaite.core.interfaces import IHideActionsMenu from zope.interface.declarations import implements @@ -38,55 +40,73 @@ class SubGroupsView(BikaListingView): def __init__(self, context, request): super(SubGroupsView, self).__init__(context, request) - self.catalog = 'bika_setup_catalog' - self.contentFilter = {'portal_type': 'SubGroup', - 'sort_on': 'sortable_title'} + + self.catalog = "bika_setup_catalog" + + self.contentFilter = { + "portal_type": "SubGroup", + "sort_on": "sortable_title", + } self.context_actions = { - _('Add'): { - 'url': 'createObject?type_name=SubGroup', - 'permission': AddSubGroup, - 'icon': '++resource++bika.lims.images/add.png' + _("Add"): { + "url": "createObject?type_name=SubGroup", + "permission": AddSubGroup, + "icon": "++resource++bika.lims.images/add.png" } } - self.icon = self.portal_url + \ - "/++resource++bika.lims.images/batch_big.png" + self.title = self.context.translate(_("Sub-groups")) self.description = "" + self.icon = "{}/{}".format( + self.portal_url, + "/++resource++bika.lims.images/batch_big.png" + ) self.show_select_row = False self.show_select_column = True self.pagesize = 25 - self.columns = { - 'Title': {'title': _('Sub-group'), - 'index': 'sortable_title'}, - 'Description': {'title': _('Description'), - 'index': 'description', - 'toggle': True}, - 'SortKey': {'title': _('Sort Key')}, - } + self.columns = collections.OrderedDict(( + ("Title", { + "title": _("Attachment Type"), + "index": "sortable_title"}), + ("Description", { + "title": _("Description"), + "index": "Description", + "toggle": True, + }), + ("SortKey", { + "title": _("Sort Key"), + "toggle": True, + }), + )) self.review_states = [ - {'id': 'default', - 'title': _('Active'), - 'contentFilter': {'is_active': True}, - 'transitions': [{'id': 'deactivate'}, ], - 'columns': ['Title', 'Description', 'SortKey']}, - {'id': 'inactive', - 'title': _('Inactive'), - 'contentFilter': {'is_active': False}, - 'transitions': [{'id': 'activate'}, ], - 'columns': ['Title', 'Description', 'SortKey']}, - {'id': 'all', - 'title': _('All'), - 'contentFilter': {}, - 'columns': ['Title', 'Description', 'SortKey']}, + { + "id": "default", + "title": _("Active"), + "contentFilter": {"is_active": True}, + "transitions": [{"id": "deactivate"}, ], + "columns": self.columns.keys(), + }, { + "id": "inactive", + "title": _("Inactive"), + "contentFilter": {'is_active': False}, + "transitions": [{"id": "activate"}, ], + "columns": self.columns.keys(), + }, { + "id": "all", + "title": _("All"), + "contentFilter": {}, + "columns": self.columns.keys(), + }, ] def folderitem(self, obj, item, index): obj = api.get_object(obj) item["Description"] = obj.Description() item["replace"]["Title"] = get_link(item["url"], item["Title"]) + item["SortKey"] = obj.getSortKey() return item @@ -99,5 +119,6 @@ class SubGroups(ATFolder): displayContentsTab = False schema = schema + schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(SubGroups, PROJECTNAME) diff --git a/src/bika/lims/controlpanel/configure.zcml b/src/bika/lims/controlpanel/configure.zcml index b002664551..4d1a00a2d3 100644 --- a/src/bika/lims/controlpanel/configure.zcml +++ b/src/bika/lims/controlpanel/configure.zcml @@ -244,32 +244,6 @@ layer="bika.lims.interfaces.IBikaLIMS" /> - - - - - - - - - diff --git a/src/bika/lims/utils/__init__.py b/src/bika/lims/utils/__init__.py index 92ea505a08..abbe3d7e70 100644 --- a/src/bika/lims/utils/__init__.py +++ b/src/bika/lims/utils/__init__.py @@ -23,39 +23,38 @@ import re import tempfile import urllib2 +from email import Encoders +from email.MIMEBase import MIMEBase +from time import time + from AccessControl import ModuleSecurityInfo from AccessControl import allow_module from AccessControl import getSecurityManager from Acquisition import aq_inner from Acquisition import aq_parent -from email import Encoders -from time import time - -import types +from bika.lims import api +from bika.lims import logger +from bika.lims.browser import BrowserView +from bika.lims.interfaces import IClient +from bika.lims.interfaces import IClientAwareMixin from DateTime import DateTime +from plone.protect.utils import addTokenToUrl +from plone.registry.interfaces import IRegistry +from plone.subrequest import subrequest from Products.Archetypes.interfaces.field import IComputedField from Products.Archetypes.public import DisplayList -from Products.CMFCore.WorkflowCore import WorkflowException from Products.CMFCore.utils import getToolByName +from Products.CMFCore.WorkflowCore import WorkflowException from Products.CMFPlone.utils import safe_unicode from Products.DCWorkflow.events import AfterTransitionEvent -from bika.lims import api -from bika.lims import logger -from bika.lims.browser import BrowserView -from email.MIMEBase import MIMEBase -from plone.memoize import ram -from plone.registry.interfaces import IRegistry -from plone.subrequest import subrequest -from weasyprint import CSS, HTML +from weasyprint import CSS +from weasyprint import HTML from weasyprint import default_url_fetcher from zope.component import queryUtility from zope.event import notify from zope.i18n import translate from zope.i18n.locales import locales -from bika.lims.interfaces import IClient -from bika.lims.interfaces import IClientAwareMixin - ModuleSecurityInfo('email.Utils').declarePublic('formataddr') allow_module('csv') @@ -126,19 +125,6 @@ def __call__(self, message): self.logger.warning(message) -ModuleSecurityInfo('Products.bika.utils').declarePublic('printfile') - - -def printfile(portal, from_addr, to_addrs, msg): - - """ set the path, then the cmd 'lpr filepath' - temp_path = 'C:/Zope2/Products/Bika/version.txt' - - os.system('lpr "%s"' %temp_path) - """ - pass - - def getUsers(context, roles, allow_empty=True): """ Present a DisplayList containing users in the specified list of roles @@ -695,6 +681,9 @@ def get_link(href, value=None, **kwargs): return "" anchor_value = value and value or href attr = render_html_attributes(**kwargs) + # Add a CSRF token + if href.startswith("http"): + href = addTokenToUrl(href) return '{}'.format(href, attr, anchor_value)