From 97524e7b23db415aa45a45556aedaa5b9bc8295a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 19:43:19 +0100 Subject: [PATCH 01/96] Cleanup getClientUID fields (added IClientBindable and ClientBindable) --- bika/lims/browser/analysisrequest/add2.py | 1 + .../widgets/srtemplateartemplateswidget.py | 1 + bika/lims/content/abstractroutineanalysis.py | 32 ++++------ bika/lims/content/analysisprofile.py | 9 +-- bika/lims/content/analysisspec.py | 7 +-- bika/lims/content/artemplate.py | 10 +--- bika/lims/content/attachment.py | 12 +--- bika/lims/content/batch.py | 22 ++----- bika/lims/content/clientbindable.py | 58 +++++++++++++++++++ bika/lims/content/report.py | 25 +------- bika/lims/content/samplepoint.py | 6 +- bika/lims/interfaces/__init__.py | 17 +++++- bika/lims/interfaces/analysis.py | 12 ++-- 13 files changed, 114 insertions(+), 98 deletions(-) create mode 100644 bika/lims/content/clientbindable.py diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index c525e72c6c..ee99845d6e 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -1117,6 +1117,7 @@ def get_specification_info(self, obj): "results_range": results_range, "sample_type_uid": obj.getSampleTypeUID(), "sample_type_title": obj.getSampleTypeTitle(), + # FIXME "client_uid": obj.getClientUID(), }) diff --git a/bika/lims/browser/widgets/srtemplateartemplateswidget.py b/bika/lims/browser/widgets/srtemplateartemplateswidget.py index a1d41df0af..fcfae43030 100644 --- a/bika/lims/browser/widgets/srtemplateartemplateswidget.py +++ b/bika/lims/browser/widgets/srtemplateartemplateswidget.py @@ -75,6 +75,7 @@ def isItemAllowed(self, obj): if self.clientUID is None: self.clientUID = self.context.aq_parent.aq_parent.UID() # Only display client's and lab's arts + # FIXME if obj.aq_parent.aq_inner.meta_type == 'Client': obj_client = obj.getClientUID() if obj_client != self.clientUID: diff --git a/bika/lims/content/abstractroutineanalysis.py b/bika/lims/content/abstractroutineanalysis.py index dc21d0c8e0..14985a487c 100644 --- a/bika/lims/content/abstractroutineanalysis.py +++ b/bika/lims/content/abstractroutineanalysis.py @@ -29,6 +29,7 @@ from bika.lims.content.abstractanalysis import AbstractAnalysis from bika.lims.content.abstractanalysis import schema from bika.lims.content.analysisspec import ResultsRangeDict +from bika.lims.content.clientbindable import ClientBindable from bika.lims.content.reflexrule import doReflexRuleAction from bika.lims.interfaces import IAnalysis from bika.lims.interfaces import ICancellable @@ -124,7 +125,7 @@ )) -class AbstractRoutineAnalysis(AbstractAnalysis): +class AbstractRoutineAnalysis(AbstractAnalysis, ClientBindable): implements(IAnalysis, IRequestAnalysis, IRoutineAnalysis, ICancellable) security = ClassSecurityInfo() displayContentsTab = False @@ -166,38 +167,27 @@ def getRequestURL(self): if request: return request.absolute_url_path() - @security.public - def getClientTitle(self): - """Used to populate catalog values. - Returns the Title of the client for this analysis' AR. + def getClient(self): + """Returns the Client this analysis is bound to, if any """ request = self.getRequest() - if request: - client = request.getClient() - if client: - return client.Title() + return request and request.getClient() or None @security.public - def getClientUID(self): + def getClientTitle(self): """Used to populate catalog values. - Returns the UID of the client for this analysis' AR. + Returns the Title of the client for this analysis' AR. """ - request = self.getRequest() - if request: - client = request.getClient() - if client: - return client.UID() + client = self.getClient() + return client and client.Title() or None @security.public def getClientURL(self): """This method is used to populate catalog values Returns the URL of the client for this analysis' AR. """ - request = self.getRequest() - if request: - client = request.getClient() - if client: - return client.absolute_url_path() + client = self.getClient() + return client and client.absolute_url_path() or None @security.public def getClientOrderNumber(self): diff --git a/bika/lims/content/analysisprofile.py b/bika/lims/content/analysisprofile.py index 0bed7e5583..ac0186dfba 100644 --- a/bika/lims/content/analysisprofile.py +++ b/bika/lims/content/analysisprofile.py @@ -33,6 +33,8 @@ from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from Products.Archetypes.public import * + +from bika.lims.content.clientbindable import ClientBindable from bika.lims.interfaces import IAnalysisProfile, IDeactivable from Products.Archetypes.references import HoldingReference from Products.ATExtensions.field import RecordsField @@ -41,6 +43,7 @@ from zope.interface import Interface, implements import sys from bika.lims.interfaces import IAnalysisProfile +from bika.lims.interfaces import IClient schema = BikaSchema.copy() + Schema(( StringField('ProfileKey', @@ -145,7 +148,8 @@ schema['description'].widget.visible = True IdField = schema['id'] -class AnalysisProfile(BaseContent): + +class AnalysisProfile(BaseContent, ClientBindable): security = ClassSecurityInfo() schema = schema displayContentsTab = False @@ -156,9 +160,6 @@ def _renameAfterCreation(self, check_auto_id=False): from bika.lims.idserver import renameAfterCreation renameAfterCreation(self) - def getClientUID(self): - return self.aq_parent.UID() - def getAnalysisServiceSettings(self, uid): """ Returns a dictionary with the settings for the analysis service that match with the uid provided. diff --git a/bika/lims/content/analysisspec.py b/bika/lims/content/analysisspec.py index 790b13129f..a7b5ac90b6 100644 --- a/bika/lims/content/analysisspec.py +++ b/bika/lims/content/analysisspec.py @@ -25,6 +25,7 @@ from bika.lims.browser.widgets import AnalysisSpecificationWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema +from bika.lims.content.clientbindable import ClientBindable from bika.lims.interfaces import IAnalysisSpec, IDeactivable from Products.Archetypes import atapi from Products.Archetypes.public import BaseFolder @@ -40,6 +41,7 @@ from zope.i18n import translate from zope.interface import implements +from bika.lims.interfaces import IClient schema = Schema(( @@ -131,7 +133,7 @@ schema['title'].required = True -class AnalysisSpec(BaseFolder, HistoryAwareMixin): +class AnalysisSpec(BaseFolder, HistoryAwareMixin, ClientBindable): """Analysis Specification """ implements(IAnalysisSpec, IDeactivable) @@ -208,9 +210,6 @@ def getSampleTypes(self, active_only=True): lambda brain: (brain.UID, brain.Title), results) return DisplayList(sampletypes) - def getClientUID(self): - return self.aq_parent.UID() - atapi.registerType(AnalysisSpec, PROJECTNAME) diff --git a/bika/lims/content/artemplate.py b/bika/lims/content/artemplate.py index 0109eaa45c..d623757935 100644 --- a/bika/lims/content/artemplate.py +++ b/bika/lims/content/artemplate.py @@ -30,6 +30,7 @@ from bika.lims.browser.widgets import RemarksWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema +from bika.lims.content.clientbindable import ClientBindable from bika.lims.interfaces import IARTemplate, IDeactivable from Products.Archetypes.public import BaseContent from Products.Archetypes.public import BooleanField @@ -299,7 +300,7 @@ schema["title"]._validationLayer() -class ARTemplate(BaseContent): +class ARTemplate(BaseContent, ClientBindable): security = ClassSecurityInfo() schema = schema displayContentsTab = False @@ -326,13 +327,6 @@ def AnalysisProfiles(self, instance=None): items = [["", ""]] + list(items) return DisplayList(items) - def getClientUID(self): - """This populates the getClientUID catalog - If the parent is the system bika_artemplates folder, - then that folder's UID must be returned in this index. - """ - return self.aq_parent.UID() - def getAnalysisServiceSettings(self, uid): """Returns a dictionary with the settings for the analysis service that match with the uid provided. diff --git a/bika/lims/content/attachment.py b/bika/lims/content/attachment.py index 6a9b390842..63da206f2e 100644 --- a/bika/lims/content/attachment.py +++ b/bika/lims/content/attachment.py @@ -27,6 +27,7 @@ from bika.lims.config import ATTACHMENT_REPORT_OPTIONS from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema +from bika.lims.content.clientbindable import ClientBindable from bika.lims.interfaces.analysis import IRequestAnalysis from DateTime import DateTime from plone.app.blob.field import FileField @@ -96,7 +97,7 @@ schema["title"].required = False -class Attachment(BaseFolder): +class Attachment(BaseFolder, ClientBindable): """Attachments are stored per client and can be linked to ARs or Analyses """ security = ClassSecurityInfo() @@ -136,15 +137,6 @@ def getAttachmentTypeUID(self): return "" return api.get_uid(attachment_type) - @security.public - def getClientUID(self): - """Return the UID of the client - """ - client = api.get_parent(self) - if not client: - return "" - return api.get_uid(client) - @security.public def getLinkedRequests(self): """Lookup linked Analysis Requests diff --git a/bika/lims/content/batch.py b/bika/lims/content/batch.py index 52c46c9b05..6f12b1ed27 100644 --- a/bika/lims/content/batch.py +++ b/bika/lims/content/batch.py @@ -30,6 +30,7 @@ from bika.lims.catalog import CATALOG_ANALYSIS_REQUEST_LISTING from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaFolderSchema +from bika.lims.content.clientbindable import ClientBindable from bika.lims.interfaces import IBatch from bika.lims.interfaces import ICancellable from bika.lims.interfaces import IClient @@ -142,7 +143,7 @@ def BatchDate(instance): schema.moveField('Client', after='title') -class Batch(ATFolder): +class Batch(ATFolder, ClientBindable): """A Batch combines multiple ARs into a logical unit """ implements(IBatch, ICancellable) @@ -159,8 +160,9 @@ def _renameAfterCreation(self, check_auto_id=False): def getClient(self): """Retrieves the Client the current Batch is assigned to """ - # The schema's field Client is only used to allow the user to assign - # the batch to a client in edit form. The entered value is used in + # We override here getClient from ClientBindable because te schema's + # field Client is only used to allow the user to assign the batch to a + # client in edit form. The entered value is used in # ObjectModifiedEventHandler to move the batch to the Client's folder, # so the value stored in the Schema's is not used anymore # See https://github.com/senaite/senaite.core/pull/1450 @@ -169,20 +171,6 @@ def getClient(self): return client return None - def getClientTitle(self): - client = self.getClient() - if client: - return client.Title() - return "" - - def getClientUID(self): - """This index is required on batches so that batch listings can be - filtered by client - """ - client = self.getClient() - if client: - return client.UID() - def getContactTitle(self): return "" diff --git a/bika/lims/content/clientbindable.py b/bika/lims/content/clientbindable.py new file mode 100644 index 0000000000..1db1072ae2 --- /dev/null +++ b/bika/lims/content/clientbindable.py @@ -0,0 +1,58 @@ +from AccessControl import ClassSecurityInfo +from Products.Archetypes.BaseObject import BaseObject +from zope.interface import implements + +from bika.lims import api +from bika.lims.interfaces import IClient +from bika.lims.interfaces import IClientBindable + + +class ClientBindable(BaseObject): + implements(IClientBindable) + + security = ClassSecurityInfo() + + @security.public + def getClient(self): + """Returns the Client the object is bound to, if any + """ + # Look for the parent + if IClient.providedBy(self.aq_parent): + return self.aq_parent + + # Look in Schema + client_field = self.Schema().get("Client", default=None) + if client_field: + client = client_field.get(self) + client = api.get_object(client, None) + if client and IClient.providedBy(client): + return client + + # No client bound + return None + + @security.public + def getClientUID(self): + """Returns the Client UID the object is bound to, if any + """ + client = self.getClient() + return client and api.get_uid(client) or "" + + @security.public + def getClientID(self): + """Returns the Client ID the object is bound to, if any + """ + client = self.getClient() + return client and api.get_id(client) or "" + + @security.public + def getClientTitle(self): + """Returns the Client Title the object is bound to, if any + """ + client = self.getClient() + return client and client.Title() or "" + + @security.public + def getClientURL(self): + client = self.getClient() + return client and client.absolute_url_path() or "" diff --git a/bika/lims/content/report.py b/bika/lims/content/report.py index 51fe10e17f..ad6ed99c43 100644 --- a/bika/lims/content/report.py +++ b/bika/lims/content/report.py @@ -27,6 +27,7 @@ from bika.lims.content.bikaschema import BikaSchema from bika.lims.config import PROJECTNAME from bika.lims import bikaMessageFactory as _ +from bika.lims.content.clientbindable import ClientBindable from bika.lims.utils import t from bika.lims.browser import ulocalized_time from bika.lims.utils import user_fullname @@ -56,7 +57,7 @@ schema['id'].required = False schema['title'].required = False -class Report(BaseFolder): +class Report(BaseFolder, ClientBindable): security = ClassSecurityInfo() displayContentsTab = False schema = schema @@ -71,13 +72,6 @@ def current_date(self): """ return current date """ return DateTime() - @security.public - def getClientUID(self): - client = self.getClient() - if client: - return client.UID() - return '' - @security.public def getCreatorFullName(self): return user_fullname(self, self.Creator()) @@ -89,19 +83,4 @@ def getFileSize(self): return '%sKb' % (file.get_size() / 1024) return '' - @security.public - def getClientURL(self): - client = self.getClient() - if client: - return client.absolute_url_path() - return '' - - @security.public - def getClientTitle(self): - client = self.getClient() - if client: - return client.Title() - return '' - - atapi.registerType(Report, PROJECTNAME) diff --git a/bika/lims/content/samplepoint.py b/bika/lims/content/samplepoint.py index d0202aaac2..d62ca5c9c5 100644 --- a/bika/lims/content/samplepoint.py +++ b/bika/lims/content/samplepoint.py @@ -44,6 +44,7 @@ ReferenceWidget as BikaReferenceWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema +from bika.lims.content.clientbindable import ClientBindable from bika.lims.interfaces import IDeactivable from plone.app.blob.field import FileField as BlobFileField from zope.interface import implements @@ -125,7 +126,7 @@ schema['description'].schemata = 'default' -class SamplePoint(BaseContent, HistoryAwareMixin): +class SamplePoint(BaseContent, HistoryAwareMixin, ClientBindable): implements(IDeactivable) security = ClassSecurityInfo() displayContentsTab = False @@ -202,9 +203,6 @@ def setSampleTypes(self, value, **kw): def getSampleTypes(self, **kw): return self.Schema()['SampleTypes'].get(self) - def getClientUID(self): - return self.aq_parent.UID() - registerType(SamplePoint, PROJECTNAME) diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index 96d5b93674..26e752cf38 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -1012,4 +1012,19 @@ def get_object_info(self): applied when the value of current field changes. - field_values: contains default values for other fields to be applied when the value of the current field changes. - """ \ No newline at end of file + """ + + +class IClientBindable(Interface): + """Marker interface for objects that can be bound to a Client, either + because they can be added inside a Client folder or because it can be + assigned through a Reference field + """ + + def getClient(self): + """Returns the client this object is bound to, if any + """ + + def getClientUID(self): + """Returns the client UID this object is bound to, if any + """ diff --git a/bika/lims/interfaces/analysis.py b/bika/lims/interfaces/analysis.py index 88bc2ee8c6..f5b61a5926 100644 --- a/bika/lims/interfaces/analysis.py +++ b/bika/lims/interfaces/analysis.py @@ -59,16 +59,16 @@ def getClient(self): :rtype: IClient""" def getClientID(self): - """Returns the UID of the Client assigned to the Analysis Request this - analysis belongs to. Returns None if there is no Request nor a Client + """Returns the ID of the Client assigned to the Analysis Request this + analysis belongs to. Returns empty if there is no Request nor a Client assigned to this analysis - :return: the UID of the Client + :return: the ID of the Client :rtype: str """ def getClientUID(self): """Returns the UID of the Client assigned to the Analysis Request this - analysis belongs to. Returns None if there is no Request nor a Client + analysis belongs to. Returns empty if there is no Request nor a Client assigned to this analysis :return: the UID of the Client :rtype: str @@ -76,7 +76,7 @@ def getClientUID(self): def getClientTitle(self): """Returns the name of the Client assigned to the Analysis Request this - analysis belongs to. Returns None if there is no Request nor a Client + analysis belongs to. Returns empty if there is no Request nor a Client assigned to this analysis :return: the name of the Client :rtype: str @@ -84,7 +84,7 @@ def getClientTitle(self): def getClientURL(self): """Returns the absolute url path of the Client assigned to the Analysis - Request this analysis belongs to. Returns None if there is no Request + Request this analysis belongs to. Returns empty if there is no Request nor a Client assigned to this analysis :return: the url path of the Client :type: str From a33ee843077e6b1e3034a4029bf684f7b9239655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 19:45:20 +0100 Subject: [PATCH 02/96] Cleanup getClientUID search criteria for Add form --- bika/lims/browser/analysisrequest/add2.py | 32 +++++------------------ 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index ee99845d6e..f9d20f4554 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -45,8 +45,9 @@ from bika.lims import logger from bika.lims.api.analysisservice import get_calculation_dependencies_for from bika.lims.api.analysisservice import get_service_dependencies_for -from bika.lims.interfaces import IGetDefaultFieldValueARAddHook, \ - IAddSampleFieldsFlush, IAddSampleObjectInfo +from bika.lims.interfaces import IAddSampleFieldsFlush +from bika.lims.interfaces import IAddSampleObjectInfo +from bika.lims.interfaces import IGetDefaultFieldValueARAddHook from bika.lims.utils import tmpID from bika.lims.utils.analysisrequest import create_analysisrequest as crar from bika.lims.workflow import ActionHandlerPool @@ -826,25 +827,6 @@ def get_client_info(self, obj): # UID of the client uid = api.get_uid(obj) - # Bika Setup folder - bika_setup = api.get_bika_setup() - - # bika samplepoints - bika_samplepoints = bika_setup.bika_samplepoints - bika_samplepoints_uid = api.get_uid(bika_samplepoints) - - # bika artemplates - bika_artemplates = bika_setup.bika_artemplates - bika_artemplates_uid = api.get_uid(bika_artemplates) - - # bika analysisprofiles - bika_analysisprofiles = bika_setup.bika_analysisprofiles - bika_analysisprofiles_uid = api.get_uid(bika_analysisprofiles) - - # bika analysisspecs - bika_analysisspecs = bika_setup.bika_analysisspecs - bika_analysisspecs_uid = api.get_uid(bika_analysisspecs) - # catalog queries for UI field filtering filter_queries = { "Contact": { @@ -857,16 +839,16 @@ def get_client_info(self, obj): "getParentUID": [uid] }, "SamplePoint": { - "getClientUID": [uid, bika_samplepoints_uid], + "getClientUID": [uid, ""], }, "Template": { - "getClientUID": [uid, bika_artemplates_uid], + "getClientUID": [uid, ""], }, "Profiles": { - "getClientUID": [uid, bika_analysisprofiles_uid], + "getClientUID": [uid, ""], }, "Specification": { - "getClientUID": [uid, bika_analysisspecs_uid], + "getClientUID": [uid, ""], }, "SamplingRound": { "getParentUID": [uid], From 49a07b6efa8cb9e55a15a8a01175df90c7af42c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 19:51:35 +0100 Subject: [PATCH 03/96] No fixme anymore --- bika/lims/browser/analysisrequest/add2.py | 1 - bika/lims/browser/widgets/srtemplateartemplateswidget.py | 1 - 2 files changed, 2 deletions(-) diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index f9d20f4554..aa756577c7 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -1099,7 +1099,6 @@ def get_specification_info(self, obj): "results_range": results_range, "sample_type_uid": obj.getSampleTypeUID(), "sample_type_title": obj.getSampleTypeTitle(), - # FIXME "client_uid": obj.getClientUID(), }) diff --git a/bika/lims/browser/widgets/srtemplateartemplateswidget.py b/bika/lims/browser/widgets/srtemplateartemplateswidget.py index fcfae43030..a1d41df0af 100644 --- a/bika/lims/browser/widgets/srtemplateartemplateswidget.py +++ b/bika/lims/browser/widgets/srtemplateartemplateswidget.py @@ -75,7 +75,6 @@ def isItemAllowed(self, obj): if self.clientUID is None: self.clientUID = self.context.aq_parent.aq_parent.UID() # Only display client's and lab's arts - # FIXME if obj.aq_parent.aq_inner.meta_type == 'Client': obj_client = obj.getClientUID() if obj_client != self.clientUID: From 7fe9b8e948ddf3d31bbff47fb20beb9dbc6aa6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 20:08:31 +0100 Subject: [PATCH 04/96] Sanitize AnalysisRequest content type regarding Client fields --- bika/lims/content/analysisrequest.py | 49 ++++++++-------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/bika/lims/content/analysisrequest.py b/bika/lims/content/analysisrequest.py index 0113fb8977..b753364bb2 100644 --- a/bika/lims/content/analysisrequest.py +++ b/bika/lims/content/analysisrequest.py @@ -49,9 +49,12 @@ from bika.lims.config import PROJECTNAME from bika.lims.content.analysisspec import ResultsRangeDict from bika.lims.content.bikaschema import BikaSchema +from bika.lims.content.clientbindable import ClientBindable from bika.lims.interfaces import IAnalysisRequest from bika.lims.interfaces import IAnalysisRequestPartition +from bika.lims.interfaces import IBatch from bika.lims.interfaces import ICancellable +from bika.lims.interfaces import IClient from bika.lims.interfaces import ISubmitted from bika.lims.permissions import FieldEditBatch from bika.lims.permissions import FieldEditClient @@ -1097,14 +1100,6 @@ }, ), ), - # TODO-catalog: move all these computed fields to methods - ComputedField( - 'ClientUID', - expression='here.aq_parent.UID()', - widget=ComputedWidget( - visible=False, - ), - ), ComputedField( 'SampleTypeTitle', @@ -1192,27 +1187,6 @@ "if here.getBatch() else ''", widget=ComputedWidget(visible=False), ), - ComputedField( - 'ClientUID', - expression="here.getClient().UID() if here.getClient() else ''", - widget=ComputedWidget(visible=False), - ), - ComputedField( - 'ClientID', - expression="here.getClient().getClientID() if here.getClient() else ''", - widget=ComputedWidget(visible=False), - ), - ComputedField( - 'ClientTitle', - expression="here.getClient().Title() if here.getClient() else ''", - widget=ComputedWidget(visible=False), - ), - ComputedField( - 'ClientURL', - expression="here.getClient().absolute_url_path() " \ - "if here.getClient() else ''", - widget=ComputedWidget(visible=False), - ), ComputedField( 'ContactUsername', expression="here.getContact().getUsername() " \ @@ -1419,7 +1393,7 @@ schema.moveField("PrimaryAnalysisRequest", before="Client") -class AnalysisRequest(BaseFolder): +class AnalysisRequest(BaseFolder, ClientBindable): implements(IAnalysisRequest, ICancellable) security = ClassSecurityInfo() displayContentsTab = False @@ -1458,14 +1432,17 @@ def Description(self): return safe_unicode(descr).encode('utf-8') def getClient(self): - if self.aq_parent.portal_type == 'Client': + """Returns the client this object is bound to. We override getClient + from ClientBindable because the "Client" schema field is only used to + allow the user to set the client while creating the Sample through + Sample Add form, but cannot be changed afterwards. The Sample is + created directly inside the selected client folder on submit + """ + if IClient.providedBy(self.aq_parent): return self.aq_parent - if self.aq_parent.portal_type == 'Batch': + if IBatch.providedBy(self.aq_parent): return self.aq_parent.getClient() - return '' - - def getClientPath(self): - return "/".join(self.aq_parent.getPhysicalPath()) + return None def getProfilesTitle(self): return [profile.Title() for profile in self.getProfiles()] From 44532fcb9fef34755d6a37c9d428e83d0896cde7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 20:08:46 +0100 Subject: [PATCH 05/96] BatchReferenceWidgetVocabulary -> ClientBindableReferenceWidgetVocabulary --- bika/lims/adapters/configure.zcml | 9 ++++----- bika/lims/adapters/referencewidgetvocabulary.py | 6 ++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/bika/lims/adapters/configure.zcml b/bika/lims/adapters/configure.zcml index eadc8ad223..bdbd4fd577 100644 --- a/bika/lims/adapters/configure.zcml +++ b/bika/lims/adapters/configure.zcml @@ -19,14 +19,13 @@ provides="bika.lims.interfaces.IReferenceWidgetVocabulary" /> - + + factory="bika.lims.adapters.referencewidgetvocabulary.ClientBindableReferenceWidgetVocabulary" + provides="bika.lims.interfaces.IReferenceWidgetVocabulary" /> + + + + + diff --git a/bika/lims/adapters/referencewidgetvocabulary.py b/bika/lims/adapters/referencewidgetvocabulary.py index c2242fcd5a..912156cd0b 100644 --- a/bika/lims/adapters/referencewidgetvocabulary.py +++ b/bika/lims/adapters/referencewidgetvocabulary.py @@ -22,6 +22,8 @@ from bika.lims import api from bika.lims import logger +from bika.lims.interfaces import IClient +from bika.lims.interfaces import IClientBindable from bika.lims.interfaces import IReferenceWidgetVocabulary, IAnalysisRequest from bika.lims.utils import to_unicode as _u from bika.lims.utils import to_utf8 as _c @@ -259,24 +261,38 @@ def __call__(self): return brains -class ClientBindableReferenceWidgetVocabulary(DefaultReferenceWidgetVocabulary): +class ClientBoundReferenceWidgetVocabulary(DefaultReferenceWidgetVocabulary): + """Injects search criteria (filters) in the query when the current context + is, belongs or is associated to a Client + """ def get_raw_query(self): """Returns the raw query to use for current search, based on the base query + update query """ - query = super(ClientBindableReferenceWidgetVocabulary, self).get_raw_query() - if IAnalysisRequest.providedBy(self.context): - + query = super(ClientBoundReferenceWidgetVocabulary, self).get_raw_query() + client_uid = self.get_client_uid(self.context) + if client_uid: # Apply the search criteria for this client - client = self.context.getClient() if "Contact" in self.get_portal_types(query): - query["getParentUID"] = [api.get_uid(client)] + query["getParentUID"] = [client_uid] else: - query["getClientUID"] = [api.get_uid(client), ""] + query["getClientUID"] = [client_uid, ""] return query + def get_client_uid(self, obj): + """Returns the client uid the current object belongs to + """ + if IClient.providedBy(obj): + return api.get_uid(obj) + elif IClientBindable.providedBy(obj): + return obj.getClientUID() + elif api.is_portal(obj): + return None + return self.get_client_uid(obj.aq_parent) + + def get_portal_types(self, query): """Return the list of portal types from the query passed-in """ diff --git a/bika/lims/browser/client/__init__.py b/bika/lims/browser/client/__init__.py index 25b917dfd0..e44f0293ec 100644 --- a/bika/lims/browser/client/__init__.py +++ b/bika/lims/browser/client/__init__.py @@ -30,5 +30,3 @@ from views.contacts import ClientContactsView from views.contacts import ClientContactVocabularyFactory from views.samplingrounds import ClientSamplingRoundsView - -from ajax import ReferenceWidgetVocabulary diff --git a/bika/lims/browser/client/ajax.py b/bika/lims/browser/client/ajax.py deleted file mode 100644 index d0de763154..0000000000 --- a/bika/lims/browser/client/ajax.py +++ /dev/null @@ -1,41 +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-2019 by it's authors. -# Some rights reserved, see README and LICENSE. - -import json - -from bika.lims.adapters.referencewidgetvocabulary import \ - DefaultReferenceWidgetVocabulary - - -class ReferenceWidgetVocabulary(DefaultReferenceWidgetVocabulary): - """Implements IReferenceWidgetVocabulary for Clients - """ - - def __call__(self): - base_query = json.loads(self.request['base_query']) - portal_type = base_query.get('portal_type', []) - if 'Contact' in portal_type: - base_query['getClientUID'] = [self.context.UID(), ] - # If ensure_ascii is false, a result may be a unicode instance. This - # usually happens if the input contains unicode strings or the encoding - # parameter is used. - # see: https://github.com/senaite/senaite.core/issues/605 - self.request['base_query'] = json.dumps(base_query, ensure_ascii=False) - return DefaultReferenceWidgetVocabulary.__call__(self) diff --git a/bika/lims/browser/client/configure.zcml b/bika/lims/browser/client/configure.zcml index 49898e54b3..3edad7d5d4 100644 --- a/bika/lims/browser/client/configure.zcml +++ b/bika/lims/browser/client/configure.zcml @@ -11,13 +11,6 @@ name="getContacts" /> - - Date: Fri, 22 Nov 2019 22:00:44 +0100 Subject: [PATCH 10/96] Make ARReport ClientBindable --- bika/lims/content/arreport.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bika/lims/content/arreport.py b/bika/lims/content/arreport.py index eb82fea40c..4a1f36320a 100644 --- a/bika/lims/content/arreport.py +++ b/bika/lims/content/arreport.py @@ -26,6 +26,7 @@ from bika.lims.browser.widgets import ReferenceWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema +from bika.lims.content.clientbindable import ClientBindable from bika.lims.interfaces import IARReport from plone.app.blob.field import BlobField from Products.Archetypes import atapi @@ -136,7 +137,7 @@ schema["title"].required = False -class ARReport(BaseFolder): +class ARReport(BaseFolder, ClientBindable): """An AnalysisRequest report, containing the report itself in pdf and html format. It includes information about the date when was published, from whom, the report recipients (and their emails) and the publication mode From ae47c2023f226e996a196875a2a60607f6fce1c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 22:32:41 +0100 Subject: [PATCH 11/96] Omit search filter for non-bindable portal_types --- bika/lims/adapters/configure.zcml | 19 +++++---- .../adapters/referencewidgetvocabulary.py | 40 ++++++++++++++----- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/bika/lims/adapters/configure.zcml b/bika/lims/adapters/configure.zcml index 69136e0f7b..0b97c5af30 100644 --- a/bika/lims/adapters/configure.zcml +++ b/bika/lims/adapters/configure.zcml @@ -19,20 +19,23 @@ provides="bika.lims.interfaces.IReferenceWidgetVocabulary" /> - - + + - - + factory=".referencewidgetvocabulary.ClientAwareReferenceWidgetVocabulary" + provides="bika.lims.interfaces.IReferenceWidgetVocabulary" /> diff --git a/bika/lims/adapters/referencewidgetvocabulary.py b/bika/lims/adapters/referencewidgetvocabulary.py index 912156cd0b..e418357398 100644 --- a/bika/lims/adapters/referencewidgetvocabulary.py +++ b/bika/lims/adapters/referencewidgetvocabulary.py @@ -261,26 +261,48 @@ def __call__(self): return brains -class ClientBoundReferenceWidgetVocabulary(DefaultReferenceWidgetVocabulary): +class ClientAwareReferenceWidgetVocabulary(DefaultReferenceWidgetVocabulary): """Injects search criteria (filters) in the query when the current context is, belongs or is associated to a Client """ + # portal_types that might be bound to a client + client_bound_types = [ + "Contact", + "Batch", + "AnalysisProfile", + "AnalysisSpec", + "ARTemplate", + "SamplePoint" + ] + def get_raw_query(self): """Returns the raw query to use for current search, based on the base query + update query """ - query = super(ClientBoundReferenceWidgetVocabulary, self).get_raw_query() - client_uid = self.get_client_uid(self.context) - if client_uid: - # Apply the search criteria for this client - if "Contact" in self.get_portal_types(query): - query["getParentUID"] = [client_uid] - else: - query["getClientUID"] = [client_uid, ""] + query = super(ClientAwareReferenceWidgetVocabulary, self).get_raw_query() + + if self.requires_client_filter(query): + client_uid = self.get_client_uid(self.context) + if client_uid: + # Apply the search criteria for this client + # Contact is the only object bound to a Client that is stored + # in portal_catalog. And in this catalog, getClientUID does not + # exist, rather getParentUID + if "Contact" in self.get_portal_types(query): + query["getParentUID"] = [client_uid] + else: + query["getClientUID"] = [client_uid, ""] return query + def requires_client_filter(self, query): + """Returns whether the query passed in requires a filter by client + """ + portal_types = self.get_portal_types(query) + bound = map(lambda pt: pt in self.client_bound_types, portal_types) + return any(bound) + def get_client_uid(self, obj): """Returns the client uid the current object belongs to """ From 779254b3dc0dd0000dd4b6c75e3eacba57dd2d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 22:34:05 +0100 Subject: [PATCH 12/96] Sample edit form - some selection widgets empty (CHANGES) --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index dca13e2ddb..22f21c619d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -18,6 +18,7 @@ Changelog **Fixed** +- #1477 Sample edit form - some selection widgets empty - #1474 Adding Control Reference to Worksheet causes print fail - #1473 Hidden settings of analysis services lost on Sample creation - #1472 Secondary samples - removal of analysis profile not possible From 28674eee609cbe0464322cf3587d4bd04e90f735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 22:47:03 +0100 Subject: [PATCH 13/96] Typo --- bika/lims/upgrade/v01_03_003.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 65304cbde7..06ea20cb28 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -50,12 +50,13 @@ def upgrade(tool): setup.runImportStepFromProfile(profile, "propertiestool") # Reindex client's related fields (getClientUID, getClientTitle, etc.) - # https://github.com/senaite/senaite.core/pull/1476 + # https://github.com/senaite/senaite.core/pull/1477 reindex_client_fields(portal) logger.info("{0} upgraded to version {1}".format(product, version)) return True + def reindex_client_fields(portal): logger.info("Reindexing client fields ...") fields_to_reindex = [ From 4283628da4c0473ffe01f50b40406e6fde4ce78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 23:06:54 +0100 Subject: [PATCH 14/96] Fix test --- bika/lims/content/clientbindable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/content/clientbindable.py b/bika/lims/content/clientbindable.py index 5f896508a6..0e472194e7 100644 --- a/bika/lims/content/clientbindable.py +++ b/bika/lims/content/clientbindable.py @@ -55,7 +55,7 @@ def getClientID(self): """Returns the Client ID the object is bound to, if any """ client = self.getClient() - return client and api.get_id(client) or "" + return client and client.getClientID() or "" @security.public def getClientTitle(self): From f78ac4c38922d89a3d44e268fba4a9c4bbd59fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 23:28:21 +0100 Subject: [PATCH 15/96] Removal of unnecessary functions (provided by ClientBindable) --- bika/lims/content/abstractroutineanalysis.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/bika/lims/content/abstractroutineanalysis.py b/bika/lims/content/abstractroutineanalysis.py index 14985a487c..0f304d45ba 100644 --- a/bika/lims/content/abstractroutineanalysis.py +++ b/bika/lims/content/abstractroutineanalysis.py @@ -173,22 +173,6 @@ def getClient(self): request = self.getRequest() return request and request.getClient() or None - @security.public - def getClientTitle(self): - """Used to populate catalog values. - Returns the Title of the client for this analysis' AR. - """ - client = self.getClient() - return client and client.Title() or None - - @security.public - def getClientURL(self): - """This method is used to populate catalog values - Returns the URL of the client for this analysis' AR. - """ - client = self.getClient() - return client and client.absolute_url_path() or None - @security.public def getClientOrderNumber(self): """Used to populate catalog values. From 1f8369d1adf9b210341051f08af5acbcc3ee7be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 22 Nov 2019 23:46:48 +0100 Subject: [PATCH 16/96] Cleanup of code that is no longer necessary --- bika/lims/browser/analysisrequest/add2.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index 21e5538091..7c88d1920e 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -996,17 +996,6 @@ def get_sampletype_info(self, obj): """ info = self.get_base_info(obj) - # Bika Setup folder - bika_setup = api.get_bika_setup() - - # bika samplepoints - bika_samplepoints = bika_setup.bika_samplepoints - bika_samplepoints_uid = api.get_uid(bika_samplepoints) - - # bika analysisspecs - bika_analysisspecs = bika_setup.bika_analysisspecs - bika_analysisspecs_uid = api.get_uid(bika_analysisspecs) - # client client = self.get_client() client_uid = client and api.get_uid(client) or "" From 0472ab010b0f57c1f712afc14efb1a5e71015a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 25 Nov 2019 11:30:27 +0100 Subject: [PATCH 17/96] ClientBindable -> ClientAwareMixin --- bika/lims/adapters/referencewidgetvocabulary.py | 4 ++-- bika/lims/content/abstractroutineanalysis.py | 4 ++-- bika/lims/content/analysisprofile.py | 4 ++-- bika/lims/content/analysisrequest.py | 6 +++--- bika/lims/content/analysisspec.py | 4 ++-- bika/lims/content/arreport.py | 4 ++-- bika/lims/content/artemplate.py | 4 ++-- bika/lims/content/attachment.py | 4 ++-- bika/lims/content/batch.py | 6 +++--- bika/lims/content/clientbindable.py | 6 +++--- bika/lims/content/report.py | 4 ++-- bika/lims/content/samplepoint.py | 4 ++-- bika/lims/interfaces/__init__.py | 2 +- 13 files changed, 28 insertions(+), 28 deletions(-) diff --git a/bika/lims/adapters/referencewidgetvocabulary.py b/bika/lims/adapters/referencewidgetvocabulary.py index e418357398..7f0d2d4381 100644 --- a/bika/lims/adapters/referencewidgetvocabulary.py +++ b/bika/lims/adapters/referencewidgetvocabulary.py @@ -23,7 +23,7 @@ from bika.lims import api from bika.lims import logger from bika.lims.interfaces import IClient -from bika.lims.interfaces import IClientBindable +from bika.lims.interfaces import IClientAwareMixin from bika.lims.interfaces import IReferenceWidgetVocabulary, IAnalysisRequest from bika.lims.utils import to_unicode as _u from bika.lims.utils import to_utf8 as _c @@ -308,7 +308,7 @@ def get_client_uid(self, obj): """ if IClient.providedBy(obj): return api.get_uid(obj) - elif IClientBindable.providedBy(obj): + elif IClientAwareMixin.providedBy(obj): return obj.getClientUID() elif api.is_portal(obj): return None diff --git a/bika/lims/content/abstractroutineanalysis.py b/bika/lims/content/abstractroutineanalysis.py index 0f304d45ba..2afe999fe0 100644 --- a/bika/lims/content/abstractroutineanalysis.py +++ b/bika/lims/content/abstractroutineanalysis.py @@ -29,7 +29,7 @@ from bika.lims.content.abstractanalysis import AbstractAnalysis from bika.lims.content.abstractanalysis import schema from bika.lims.content.analysisspec import ResultsRangeDict -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.content.reflexrule import doReflexRuleAction from bika.lims.interfaces import IAnalysis from bika.lims.interfaces import ICancellable @@ -125,7 +125,7 @@ )) -class AbstractRoutineAnalysis(AbstractAnalysis, ClientBindable): +class AbstractRoutineAnalysis(AbstractAnalysis, ClientAwareMixin): implements(IAnalysis, IRequestAnalysis, IRoutineAnalysis, ICancellable) security = ClassSecurityInfo() displayContentsTab = False diff --git a/bika/lims/content/analysisprofile.py b/bika/lims/content/analysisprofile.py index ac0186dfba..31e6871a9c 100644 --- a/bika/lims/content/analysisprofile.py +++ b/bika/lims/content/analysisprofile.py @@ -34,7 +34,7 @@ from bika.lims.content.bikaschema import BikaSchema from Products.Archetypes.public import * -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.interfaces import IAnalysisProfile, IDeactivable from Products.Archetypes.references import HoldingReference from Products.ATExtensions.field import RecordsField @@ -149,7 +149,7 @@ IdField = schema['id'] -class AnalysisProfile(BaseContent, ClientBindable): +class AnalysisProfile(BaseContent, ClientAwareMixin): security = ClassSecurityInfo() schema = schema displayContentsTab = False diff --git a/bika/lims/content/analysisrequest.py b/bika/lims/content/analysisrequest.py index b753364bb2..b176914067 100644 --- a/bika/lims/content/analysisrequest.py +++ b/bika/lims/content/analysisrequest.py @@ -49,7 +49,7 @@ from bika.lims.config import PROJECTNAME from bika.lims.content.analysisspec import ResultsRangeDict from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.interfaces import IAnalysisRequest from bika.lims.interfaces import IAnalysisRequestPartition from bika.lims.interfaces import IBatch @@ -1393,7 +1393,7 @@ schema.moveField("PrimaryAnalysisRequest", before="Client") -class AnalysisRequest(BaseFolder, ClientBindable): +class AnalysisRequest(BaseFolder, ClientAwareMixin): implements(IAnalysisRequest, ICancellable) security = ClassSecurityInfo() displayContentsTab = False @@ -1433,7 +1433,7 @@ def Description(self): def getClient(self): """Returns the client this object is bound to. We override getClient - from ClientBindable because the "Client" schema field is only used to + from ClientAwareMixin because the "Client" schema field is only used to allow the user to set the client while creating the Sample through Sample Add form, but cannot be changed afterwards. The Sample is created directly inside the selected client folder on submit diff --git a/bika/lims/content/analysisspec.py b/bika/lims/content/analysisspec.py index a7b5ac90b6..5cbf68286b 100644 --- a/bika/lims/content/analysisspec.py +++ b/bika/lims/content/analysisspec.py @@ -25,7 +25,7 @@ from bika.lims.browser.widgets import AnalysisSpecificationWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.interfaces import IAnalysisSpec, IDeactivable from Products.Archetypes import atapi from Products.Archetypes.public import BaseFolder @@ -133,7 +133,7 @@ schema['title'].required = True -class AnalysisSpec(BaseFolder, HistoryAwareMixin, ClientBindable): +class AnalysisSpec(BaseFolder, HistoryAwareMixin, ClientAwareMixin): """Analysis Specification """ implements(IAnalysisSpec, IDeactivable) diff --git a/bika/lims/content/arreport.py b/bika/lims/content/arreport.py index 4a1f36320a..79d17db527 100644 --- a/bika/lims/content/arreport.py +++ b/bika/lims/content/arreport.py @@ -26,7 +26,7 @@ from bika.lims.browser.widgets import ReferenceWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.interfaces import IARReport from plone.app.blob.field import BlobField from Products.Archetypes import atapi @@ -137,7 +137,7 @@ schema["title"].required = False -class ARReport(BaseFolder, ClientBindable): +class ARReport(BaseFolder, ClientAwareMixin): """An AnalysisRequest report, containing the report itself in pdf and html format. It includes information about the date when was published, from whom, the report recipients (and their emails) and the publication mode diff --git a/bika/lims/content/artemplate.py b/bika/lims/content/artemplate.py index d623757935..4f31e280cd 100644 --- a/bika/lims/content/artemplate.py +++ b/bika/lims/content/artemplate.py @@ -30,7 +30,7 @@ from bika.lims.browser.widgets import RemarksWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.interfaces import IARTemplate, IDeactivable from Products.Archetypes.public import BaseContent from Products.Archetypes.public import BooleanField @@ -300,7 +300,7 @@ schema["title"]._validationLayer() -class ARTemplate(BaseContent, ClientBindable): +class ARTemplate(BaseContent, ClientAwareMixin): security = ClassSecurityInfo() schema = schema displayContentsTab = False diff --git a/bika/lims/content/attachment.py b/bika/lims/content/attachment.py index 63da206f2e..a7a99ac5ce 100644 --- a/bika/lims/content/attachment.py +++ b/bika/lims/content/attachment.py @@ -27,7 +27,7 @@ from bika.lims.config import ATTACHMENT_REPORT_OPTIONS from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.interfaces.analysis import IRequestAnalysis from DateTime import DateTime from plone.app.blob.field import FileField @@ -97,7 +97,7 @@ schema["title"].required = False -class Attachment(BaseFolder, ClientBindable): +class Attachment(BaseFolder, ClientAwareMixin): """Attachments are stored per client and can be linked to ARs or Analyses """ security = ClassSecurityInfo() diff --git a/bika/lims/content/batch.py b/bika/lims/content/batch.py index 6f12b1ed27..5fde49c0a0 100644 --- a/bika/lims/content/batch.py +++ b/bika/lims/content/batch.py @@ -30,7 +30,7 @@ from bika.lims.catalog import CATALOG_ANALYSIS_REQUEST_LISTING from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaFolderSchema -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.interfaces import IBatch from bika.lims.interfaces import ICancellable from bika.lims.interfaces import IClient @@ -143,7 +143,7 @@ def BatchDate(instance): schema.moveField('Client', after='title') -class Batch(ATFolder, ClientBindable): +class Batch(ATFolder, ClientAwareMixin): """A Batch combines multiple ARs into a logical unit """ implements(IBatch, ICancellable) @@ -160,7 +160,7 @@ def _renameAfterCreation(self, check_auto_id=False): def getClient(self): """Retrieves the Client the current Batch is assigned to """ - # We override here getClient from ClientBindable because te schema's + # We override here getClient from ClientAwareMixin because te schema's # field Client is only used to allow the user to assign the batch to a # client in edit form. The entered value is used in # ObjectModifiedEventHandler to move the batch to the Client's folder, diff --git a/bika/lims/content/clientbindable.py b/bika/lims/content/clientbindable.py index 0e472194e7..3588894a9d 100644 --- a/bika/lims/content/clientbindable.py +++ b/bika/lims/content/clientbindable.py @@ -4,11 +4,11 @@ from bika.lims import api from bika.lims.interfaces import IClient -from bika.lims.interfaces import IClientBindable +from bika.lims.interfaces import IClientAwareMixin -class ClientBindable(BaseObject): - implements(IClientBindable) +class ClientAwareMixin(BaseObject): + implements(IClientAwareMixin) security = ClassSecurityInfo() diff --git a/bika/lims/content/report.py b/bika/lims/content/report.py index ad6ed99c43..fb865566de 100644 --- a/bika/lims/content/report.py +++ b/bika/lims/content/report.py @@ -27,7 +27,7 @@ from bika.lims.content.bikaschema import BikaSchema from bika.lims.config import PROJECTNAME from bika.lims import bikaMessageFactory as _ -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.utils import t from bika.lims.browser import ulocalized_time from bika.lims.utils import user_fullname @@ -57,7 +57,7 @@ schema['id'].required = False schema['title'].required = False -class Report(BaseFolder, ClientBindable): +class Report(BaseFolder, ClientAwareMixin): security = ClassSecurityInfo() displayContentsTab = False schema = schema diff --git a/bika/lims/content/samplepoint.py b/bika/lims/content/samplepoint.py index d62ca5c9c5..9e37051266 100644 --- a/bika/lims/content/samplepoint.py +++ b/bika/lims/content/samplepoint.py @@ -44,7 +44,7 @@ ReferenceWidget as BikaReferenceWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientBindable +from bika.lims.content.clientbindable import ClientAwareMixin from bika.lims.interfaces import IDeactivable from plone.app.blob.field import FileField as BlobFileField from zope.interface import implements @@ -126,7 +126,7 @@ schema['description'].schemata = 'default' -class SamplePoint(BaseContent, HistoryAwareMixin, ClientBindable): +class SamplePoint(BaseContent, HistoryAwareMixin, ClientAwareMixin): implements(IDeactivable) security = ClassSecurityInfo() displayContentsTab = False diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index 26e752cf38..c668cd52a2 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -1015,7 +1015,7 @@ def get_object_info(self): """ -class IClientBindable(Interface): +class IClientAwareMixin(Interface): """Marker interface for objects that can be bound to a Client, either because they can be added inside a Client folder or because it can be assigned through a Reference field From 71e40397fa1d870d9cc6c815f6f18860fcb2a0dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 25 Nov 2019 13:36:58 +0100 Subject: [PATCH 18/96] Better way of returning a Client from acquisition chain --- .../adapters/referencewidgetvocabulary.py | 29 ++++------- bika/lims/content/clientbindable.py | 20 ++------ bika/lims/utils/__init__.py | 50 +++++++++++++++++++ 3 files changed, 65 insertions(+), 34 deletions(-) diff --git a/bika/lims/adapters/referencewidgetvocabulary.py b/bika/lims/adapters/referencewidgetvocabulary.py index 7f0d2d4381..3e681de45a 100644 --- a/bika/lims/adapters/referencewidgetvocabulary.py +++ b/bika/lims/adapters/referencewidgetvocabulary.py @@ -20,14 +20,14 @@ import json +from zope.interface import implements + from bika.lims import api from bika.lims import logger -from bika.lims.interfaces import IClient -from bika.lims.interfaces import IClientAwareMixin -from bika.lims.interfaces import IReferenceWidgetVocabulary, IAnalysisRequest +from bika.lims.interfaces import IReferenceWidgetVocabulary +from bika.lims.utils import get_client from bika.lims.utils import to_unicode as _u from bika.lims.utils import to_utf8 as _c -from zope.interface import implements class DefaultReferenceWidgetVocabulary(object): @@ -282,8 +282,11 @@ def get_raw_query(self): """ query = super(ClientAwareReferenceWidgetVocabulary, self).get_raw_query() - if self.requires_client_filter(query): - client_uid = self.get_client_uid(self.context) + if self.is_client_aware(query): + + client = get_client(self.context) + client_uid = client and api.get_uid(client) or None + if client_uid: # Apply the search criteria for this client # Contact is the only object bound to a Client that is stored @@ -296,25 +299,13 @@ def get_raw_query(self): return query - def requires_client_filter(self, query): + def is_client_aware(self, query): """Returns whether the query passed in requires a filter by client """ portal_types = self.get_portal_types(query) bound = map(lambda pt: pt in self.client_bound_types, portal_types) return any(bound) - def get_client_uid(self, obj): - """Returns the client uid the current object belongs to - """ - if IClient.providedBy(obj): - return api.get_uid(obj) - elif IClientAwareMixin.providedBy(obj): - return obj.getClientUID() - elif api.is_portal(obj): - return None - return self.get_client_uid(obj.aq_parent) - - def get_portal_types(self, query): """Return the list of portal types from the query passed-in """ diff --git a/bika/lims/content/clientbindable.py b/bika/lims/content/clientbindable.py index 3588894a9d..42397a89cf 100644 --- a/bika/lims/content/clientbindable.py +++ b/bika/lims/content/clientbindable.py @@ -5,6 +5,7 @@ from bika.lims import api from bika.lims.interfaces import IClient from bika.lims.interfaces import IClientAwareMixin +from bika.lims.utils import chain class ClientAwareMixin(BaseObject): @@ -16,10 +17,10 @@ class ClientAwareMixin(BaseObject): def getClient(self): """Returns the Client the object is bound to, if any """ - # Look for the parent - client = self._infere_client() - if client: - return client + # Look in the acquisition chain + for obj in chain(self): + if IClient.providedBy(obj): + return obj # Look in Schema client_field = self.Schema().get("Client", default=None) @@ -32,17 +33,6 @@ def getClient(self): # No client bound return None - def _infere_client(self, obj=None): - """Inferes the client the object belongs to by walking through parents - """ - if not obj: - obj = self - if IClient.providedBy(obj): - return obj - elif api.is_portal(obj): - return None - return self._infere_client(obj.aq_parent) - @security.public def getClientUID(self): """Returns the Client UID the object is bound to, if any diff --git a/bika/lims/utils/__init__.py b/bika/lims/utils/__init__.py index 457dc53e03..475d8e3730 100644 --- a/bika/lims/utils/__init__.py +++ b/bika/lims/utils/__init__.py @@ -26,6 +26,8 @@ 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 @@ -51,6 +53,9 @@ 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') @@ -899,3 +904,48 @@ def to_choices(display_list): "ResultValue": item[0], "ResultText": item[1]}, display_list.items()) + + +def chain(obj): + """Generator to walk the acquistion chain of object, considering that it + could be a function. + """ + + # Walk up the acquisition chain of the object, to be able to check + # each one for IWorkspace. + + # If the thing we are accessing is actually a bound method on an + # instance, then after we've checked the method itself, get the + # instance it's bound to using im_self, so that we can continue to + # walk up the acquistion chain from it (incidentally, this is why we + # can't juse use aq_chain()). + + context = aq_inner(obj) + + while context is not None: + yield context + + func_object = getattr(context, 'im_self', None) + if func_object is not None: + context = aq_inner(func_object) + else: + # Don't use aq_inner() since portal_factory (and probably other) + # things, depends on being able to wrap itself in a fake context. + context = aq_parent(context) + + +def get_client(obj): + """Returns the client the object passed-in belongs to, if any + + This walks the acquisition chain up until we find something which + provides either IClient or IClientAwareMixin + """ + for obj in chain(obj): + if IClient.providedBy(obj): + return obj + elif IClientAwareMixin.providedBy(obj): + # ClientAwareMixin can return a Client, even if there is no client + # in the acquisition chain + return obj.getClient() + + return None From a423dd4fa28d8c75d04d630a7fa0cde4a9b0402d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 25 Nov 2019 13:52:27 +0100 Subject: [PATCH 19/96] Replace clientbindable namespace --- bika/lims/content/abstractroutineanalysis.py | 2 +- bika/lims/content/analysisprofile.py | 2 +- bika/lims/content/analysisrequest.py | 2 +- bika/lims/content/analysisspec.py | 2 +- bika/lims/content/arreport.py | 2 +- bika/lims/content/artemplate.py | 2 +- bika/lims/content/attachment.py | 2 +- bika/lims/content/batch.py | 2 +- bika/lims/content/{clientbindable.py => clientawaremixin.py} | 0 bika/lims/content/report.py | 2 +- bika/lims/content/samplepoint.py | 2 +- 11 files changed, 10 insertions(+), 10 deletions(-) rename bika/lims/content/{clientbindable.py => clientawaremixin.py} (100%) diff --git a/bika/lims/content/abstractroutineanalysis.py b/bika/lims/content/abstractroutineanalysis.py index 2afe999fe0..8e160b40d7 100644 --- a/bika/lims/content/abstractroutineanalysis.py +++ b/bika/lims/content/abstractroutineanalysis.py @@ -29,7 +29,7 @@ from bika.lims.content.abstractanalysis import AbstractAnalysis from bika.lims.content.abstractanalysis import schema from bika.lims.content.analysisspec import ResultsRangeDict -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.content.reflexrule import doReflexRuleAction from bika.lims.interfaces import IAnalysis from bika.lims.interfaces import ICancellable diff --git a/bika/lims/content/analysisprofile.py b/bika/lims/content/analysisprofile.py index 31e6871a9c..42c4f2a8a6 100644 --- a/bika/lims/content/analysisprofile.py +++ b/bika/lims/content/analysisprofile.py @@ -34,7 +34,7 @@ from bika.lims.content.bikaschema import BikaSchema from Products.Archetypes.public import * -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.interfaces import IAnalysisProfile, IDeactivable from Products.Archetypes.references import HoldingReference from Products.ATExtensions.field import RecordsField diff --git a/bika/lims/content/analysisrequest.py b/bika/lims/content/analysisrequest.py index b176914067..c9e20c53e5 100644 --- a/bika/lims/content/analysisrequest.py +++ b/bika/lims/content/analysisrequest.py @@ -49,7 +49,7 @@ from bika.lims.config import PROJECTNAME from bika.lims.content.analysisspec import ResultsRangeDict from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.interfaces import IAnalysisRequest from bika.lims.interfaces import IAnalysisRequestPartition from bika.lims.interfaces import IBatch diff --git a/bika/lims/content/analysisspec.py b/bika/lims/content/analysisspec.py index 5cbf68286b..114d74ba7d 100644 --- a/bika/lims/content/analysisspec.py +++ b/bika/lims/content/analysisspec.py @@ -25,7 +25,7 @@ from bika.lims.browser.widgets import AnalysisSpecificationWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.interfaces import IAnalysisSpec, IDeactivable from Products.Archetypes import atapi from Products.Archetypes.public import BaseFolder diff --git a/bika/lims/content/arreport.py b/bika/lims/content/arreport.py index 79d17db527..b6ca51e35f 100644 --- a/bika/lims/content/arreport.py +++ b/bika/lims/content/arreport.py @@ -26,7 +26,7 @@ from bika.lims.browser.widgets import ReferenceWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.interfaces import IARReport from plone.app.blob.field import BlobField from Products.Archetypes import atapi diff --git a/bika/lims/content/artemplate.py b/bika/lims/content/artemplate.py index 4f31e280cd..4e61f9b88a 100644 --- a/bika/lims/content/artemplate.py +++ b/bika/lims/content/artemplate.py @@ -30,7 +30,7 @@ from bika.lims.browser.widgets import RemarksWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.interfaces import IARTemplate, IDeactivable from Products.Archetypes.public import BaseContent from Products.Archetypes.public import BooleanField diff --git a/bika/lims/content/attachment.py b/bika/lims/content/attachment.py index a7a99ac5ce..2b25511687 100644 --- a/bika/lims/content/attachment.py +++ b/bika/lims/content/attachment.py @@ -27,7 +27,7 @@ from bika.lims.config import ATTACHMENT_REPORT_OPTIONS from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.interfaces.analysis import IRequestAnalysis from DateTime import DateTime from plone.app.blob.field import FileField diff --git a/bika/lims/content/batch.py b/bika/lims/content/batch.py index 5fde49c0a0..1d9969af83 100644 --- a/bika/lims/content/batch.py +++ b/bika/lims/content/batch.py @@ -30,7 +30,7 @@ from bika.lims.catalog import CATALOG_ANALYSIS_REQUEST_LISTING from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaFolderSchema -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.interfaces import IBatch from bika.lims.interfaces import ICancellable from bika.lims.interfaces import IClient diff --git a/bika/lims/content/clientbindable.py b/bika/lims/content/clientawaremixin.py similarity index 100% rename from bika/lims/content/clientbindable.py rename to bika/lims/content/clientawaremixin.py diff --git a/bika/lims/content/report.py b/bika/lims/content/report.py index fb865566de..1f2ee267be 100644 --- a/bika/lims/content/report.py +++ b/bika/lims/content/report.py @@ -27,7 +27,7 @@ from bika.lims.content.bikaschema import BikaSchema from bika.lims.config import PROJECTNAME from bika.lims import bikaMessageFactory as _ -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.utils import t from bika.lims.browser import ulocalized_time from bika.lims.utils import user_fullname diff --git a/bika/lims/content/samplepoint.py b/bika/lims/content/samplepoint.py index 9e37051266..c15c44536f 100644 --- a/bika/lims/content/samplepoint.py +++ b/bika/lims/content/samplepoint.py @@ -44,7 +44,7 @@ ReferenceWidget as BikaReferenceWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientbindable import ClientAwareMixin +from bika.lims.content.clientawaremixin import ClientAwareMixin from bika.lims.interfaces import IDeactivable from plone.app.blob.field import FileField as BlobFileField from zope.interface import implements From a03c694a5363693f5e8af37ba7fd2f9dfa16e334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 25 Nov 2019 15:00:52 +0100 Subject: [PATCH 20/96] Use six for isinstance --- bika/lims/adapters/referencewidgetvocabulary.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bika/lims/adapters/referencewidgetvocabulary.py b/bika/lims/adapters/referencewidgetvocabulary.py index 3e681de45a..f2420e1efb 100644 --- a/bika/lims/adapters/referencewidgetvocabulary.py +++ b/bika/lims/adapters/referencewidgetvocabulary.py @@ -19,6 +19,7 @@ # Some rights reserved, see README and LICENSE. import json +import six from zope.interface import implements @@ -310,6 +311,6 @@ def get_portal_types(self, query): """Return the list of portal types from the query passed-in """ portal_types = query.get("portal_type", []) - if isinstance(portal_types, basestring): + if isinstance(portal_types, six.string_types): portal_types = [portal_types] return portal_types From dbd7edafc9349a5064bbecddf3558cfe532d7607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 26 Nov 2019 17:50:19 +0100 Subject: [PATCH 21/96] Filter Templates field when Sample Type is selected in Sample Add form When user selects a SampleType in Add Sample Form, Templates that have a Sample Type assigned, but not the same as the one selected, are not displayed for selection. This commit also includes some clean-up of indexes and metadata that are no longer used. --- CHANGES.rst | 1 + bika/lims/browser/analysisrequest/add2.py | 19 ++++-- bika/lims/content/samplepoint.py | 20 ++---- bika/lims/setuphandlers.py | 8 +-- bika/lims/upgrade/v01_03_003.py | 74 +++++++++++++++++++++++ 5 files changed, 95 insertions(+), 27 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index bdcb34d790..6309d5ffb3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,7 @@ Changelog **Added** +- #1481 Filter Templates field when Sample Type is selected in Sample Add form - #1466 Support for "readonly" and "hidden" visibility modes in ReferenceWidget diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index 7c88d1920e..ebbb6cf7be 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -1008,16 +1008,24 @@ def get_sampletype_info(self, obj): }) # catalog queries for UI field filtering + sample_type_uid = api.get_uid(obj) filter_queries = { + # Display Sample Points that have this sample type assigned plus + # those that do not have a sample type assigned "SamplePoint": { - "getSampleTypeTitles": [obj.Title(), ''], + "getSampleTypeUID": [sample_type_uid, ''], "getClientUID": [client_uid, ""], - "sort_order": "descending", }, + # Display Specifications that have this sample type assigned only "Specification": { - "getSampleTypeTitle": obj.Title(), + "getSampleTypeUID": sample_type_uid, + "getClientUID": [client_uid, ""], + }, + # Display AR Templates that have this sample type assigned plus + # those that do not have a sample type assigned + "Template": { + "getSampleTypeUID": [api.get_uid(obj), ""], "getClientUID": [client_uid, ""], - "sort_order": "descending", } } info["filter_queries"] = filter_queries @@ -1147,7 +1155,8 @@ def ajax_get_flush_settings(self): ], "SampleType": [ "SamplePoint", - "Specification" + "Specification", + "Template", ], "PrimarySample": [ "Batch" diff --git a/bika/lims/content/samplepoint.py b/bika/lims/content/samplepoint.py index c15c44536f..9e88666e76 100644 --- a/bika/lims/content/samplepoint.py +++ b/bika/lims/content/samplepoint.py @@ -141,26 +141,14 @@ def _renameAfterCreation(self, check_auto_id=False): def Title(self): return safe_unicode(self.getField('title').get(self)).encode('utf-8') - def getSampleTypeTitles(self): - """Returns a list of sample type titles + def getSampleTypeTitle(self): + """Returns a comma separated list of sample type titles """ sample_types = self.getSampleTypes() sample_type_titles = map(lambda obj: obj.Title(), sample_types) - - # N.B. This is used only for search purpose, because the catalog does - # not add an entry to the Keywordindex for an empty list. - # - # => This "empty" category allows to search for values with a certain - # sample type set OR with no sample type set. - # (see bika.lims.browser.analysisrequest.add2.get_sampletype_info) if not sample_type_titles: - return [""] - return sample_type_titles - - def getSampleTypeTitle(self): - """Returns a comma separated list of sample type titles - """ - return ",".join(self.getSampleTypeTitles()) + return "" + return ",".join(sample_type_titles) def SampleTypesVocabulary(self): from bika.lims.content.sampletype import SampleTypes diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 7390a44a24..6b06472309 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -149,8 +149,6 @@ ("bika_catalog", "getExpiryDate", "", "DateIndex"), ("bika_catalog", "getId", "", "FieldIndex"), ("bika_catalog", "getReferenceDefinitionUID", "", "FieldIndex"), - ("bika_catalog", "getSampleTypeTitle", "", "FieldIndex"), - ("bika_catalog", "getSampleTypeUID", "", "FieldIndex"), ("bika_catalog", "getSupportedServices", "", "KeywordIndex"), ("bika_catalog", "id", "getId", "FieldIndex"), ("bika_catalog", "isValid", "", "BooleanIndex"), @@ -202,8 +200,9 @@ ("bika_setup_catalog", "getPrice", "", "FieldIndex"), ("bika_setup_catalog", "getSamplePointTitle", "", "KeywordIndex"), ("bika_setup_catalog", "getSamplePointUID", "", "FieldIndex"), + # Sorting of listings: Sample Points, Specifications ("bika_setup_catalog", "getSampleTypeTitle", "", "FieldIndex"), - ("bika_setup_catalog", "getSampleTypeTitles", "", "KeywordIndex"), + # Filter in Add2: Sample Points, Specifications, Templates ("bika_setup_catalog", "getSampleTypeUID", "", "FieldIndex"), ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), @@ -238,7 +237,6 @@ ("bika_catalog", "getClientTitle"), ("bika_catalog", "getClientID"), ("bika_catalog", "getClientBatchID"), - ("bika_catalog", "getSampleTypeTitle"), ("bika_catalog", "getDateReceived"), ("bika_catalog", "getDateSampled"), ("bika_catalog", "review_state"), @@ -283,8 +281,6 @@ ("bika_setup_catalog", "getPrice"), ("bika_setup_catalog", "getSamplePointTitle"), ("bika_setup_catalog", "getSamplePointUID"), - ("bika_setup_catalog", "getSampleTypeTitle"), - ("bika_setup_catalog", "getSampleTypeUID"), ("bika_setup_catalog", "getServiceUID"), ("bika_setup_catalog", "getTotalPrice"), ("bika_setup_catalog", "getUnit"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 06ea20cb28..90fa46c731 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -29,6 +29,39 @@ version = "1.3.3" # Remember version number in metadata.xml and setup.py profile = "profile-{0}:default".format(product) +INDEXES_TO_REMOVE = [ + # Only used in add2 to filter Sample Points by Sample Type when a Sample + # Type was selected. Now, getSampleTypeUID is used instead because of + # https://github.com/senaite/senaite.core/pull/1481 + ("bika_setup_catalog", "getSampleTypeTitles"), + + # Only used for when Sample and SamplePartition objects + # existed. The following are the portal types stored in bika_catalog: + # Batch, BatchFolder and ReferenceSample + # and there are no searches by getSampleTypeTitle for none of them + ("bika_catalog", "getSampleTypeTitle"), + + # Not used neither for searches nor filtering of any of the content types + # stored in bika_catalog (Batch, BatchFolder and ReferenceSample) + ("bika_catalog", "getSampleTypeUID") +] + +METADATA_TO_REMOVE = [ + # Not used anywhere. In SamplePoints and Specifications listings, the + # SampleType object is waken-up instead of calling the metadata + ("bika_setup_catalog", "getSampleTypeTitle"), + + # getSampleTypeUID (as metadata field) is only used for analyses and + # samples (AnalysisRequest), and none of the two are stored in setup_catalog + ("bika_setup_catalog", "getSampleTypeUID"), + + # Only used for when Sample and SamplePartition objects existed. + # The following are the portal types stored in bika_catalog: + # Batch, BatchFolder and ReferenceSample + # and "getSampleTypeTitle" metadata is not used for none of them + ("bika_catalog", "getSampleTypeTitle") +] + @upgradestep(product, version) def upgrade(tool): @@ -49,6 +82,11 @@ def upgrade(tool): # https://github.com/senaite/senaite.core/pull/1469 setup.runImportStepFromProfile(profile, "propertiestool") + # Remove stale indexes and metadata + # https://github.com/senaite/senaite.core/pull/1481 + remove_stale_indexes(portal) + remove_stale_metadata(portal) + # Reindex client's related fields (getClientUID, getClientTitle, etc.) # https://github.com/senaite/senaite.core/pull/1477 reindex_client_fields(portal) @@ -87,3 +125,39 @@ def reindex_client_fields(portal): obj.reindexObject(idxs=fields_to_reindex) logger.info("Reindexing client fields ... [DONE]") + + +def remove_stale_indexes(portal): + logger.info("Removing stale indexes ...") + for catalog, index in INDEXES_TO_REMOVE: + del_index(catalog, index) + logger.info("Removing stale indexes ... [DONE]") + + +def remove_stale_metadata(portal): + logger.info("Removing stale metadata ...") + for catalog, column in METADATA_TO_REMOVE: + del_metadata(catalog, column) + logger.info("Removing stale metadata ... [DONE]") + + +def del_index(catalog_id, index_name): + logger.info("Removing '{}' index from '{}' ..." + .format(index_name, catalog_id)) + catalog = api.get_tool(catalog_id) + if index_name not in catalog.indexes(): + logger.info("Index '{}' not in catalog '{}' [SKIP]" + .format(index_name, catalog_id)) + return + catalog.delIndex(index_name) + + +def del_metadata(catalog_id, column): + logger.info("Removing '{}' metadata from '{}' ..." + .format(column, catalog_id)) + catalog = api.get_tool(catalog_id) + if column not in catalog.schema(): + logger.info("Metadata '{}' not in catalog '{}' [SKIP]" + .format(column, catalog_id)) + return + catalog.delColumn(column) From ba9473067e9718fe2c4befbcb38abbcbd193d506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Wed, 27 Nov 2019 22:47:00 +0100 Subject: [PATCH 22/96] getSampleTypeUID index refactoring --- bika/lims/browser/analysisrequest/add2.py | 4 +- bika/lims/catalog/indexers/bikasetup.py | 17 +++++ bika/lims/catalog/indexers/configure.zcml | 3 + bika/lims/content/analysisspec.py | 35 ++-------- bika/lims/content/artemplate.py | 10 +-- bika/lims/content/samplepoint.py | 54 ++++------------ bika/lims/content/sampletype.py | 79 +++++++++++++++++------ bika/lims/interfaces/__init__.py | 14 ++++ bika/lims/setuphandlers.py | 2 +- bika/lims/upgrade/v01_03_003.py | 35 +++++++++- 10 files changed, 148 insertions(+), 105 deletions(-) create mode 100644 bika/lims/catalog/indexers/bikasetup.py diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index a9745ea8e3..0bef224842 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -1018,7 +1018,7 @@ def get_sampletype_info(self, obj): # Display Sample Points that have this sample type assigned plus # those that do not have a sample type assigned "SamplePoint": { - "getSampleTypeUID": [sample_type_uid, ''], + "getSampleTypeUID": [sample_type_uid, None], "getClientUID": [client_uid, ""], }, # Display Specifications that have this sample type assigned only @@ -1029,7 +1029,7 @@ def get_sampletype_info(self, obj): # Display AR Templates that have this sample type assigned plus # those that do not have a sample type assigned "Template": { - "getSampleTypeUID": [sample_type_uid, ""], + "getSampleTypeUID": [sample_type_uid, None], "getClientUID": [client_uid, ""], } } diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py new file mode 100644 index 0000000000..dfb2958256 --- /dev/null +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -0,0 +1,17 @@ +from Products.Archetypes.interfaces import IBaseObject +from plone.indexer import indexer + +from bika.lims.interfaces import IBikaSetupCatalog +from bika.lims.interfaces import ISampleTypeAwareMixin + + +@indexer(ISampleTypeAwareMixin, IBikaSetupCatalog) +def getSampleTypeUID(instance): + """Returns the list of SampleType UIDs the instance is assigned to + + This is a KeywordIndex, so it will be indexed as a list, even if only one + SampleType can be assigned to the instance. Moreover, if the instance has no + SampleType assigned, it returns a tuple with a None value. This allows + searches for `MissingValue` entries too. + """ + return instance.getSampleTypeUID() or (None, ) diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index a32374eabe..d95dcbc4cf 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -24,6 +24,9 @@ + + + diff --git a/bika/lims/content/analysisspec.py b/bika/lims/content/analysisspec.py index 114d74ba7d..d8824e372b 100644 --- a/bika/lims/content/analysisspec.py +++ b/bika/lims/content/analysisspec.py @@ -26,22 +26,19 @@ from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.content.clientawaremixin import ClientAwareMixin +from bika.lims.content.sampletype import SampleTypeAwareMixin from bika.lims.interfaces import IAnalysisSpec, IDeactivable from Products.Archetypes import atapi from Products.Archetypes.public import BaseFolder -from Products.Archetypes.public import ComputedField -from Products.Archetypes.public import ComputedWidget from Products.Archetypes.public import ReferenceWidget from Products.Archetypes.public import Schema from Products.Archetypes.utils import DisplayList from Products.ATContentTypes.lib.historyaware import HistoryAwareMixin from Products.ATExtensions.field.records import RecordsField -from Products.CMFCore.utils import getToolByName from Products.CMFPlone.utils import safe_unicode from zope.i18n import translate from zope.interface import implements -from bika.lims.interfaces import IClient schema = Schema(( @@ -55,21 +52,6 @@ ), ), - ComputedField( - 'SampleTypeTitle', - expression="context.getSampleType().Title() if context.getSampleType() else ''", - widget=ComputedWidget( - visible=False, - ), - ), - - ComputedField( - 'SampleTypeUID', - expression="context.getSampleType().UID() if context.getSampleType() else ''", - widget=ComputedWidget( - visible=False, - ), - ), )) + BikaSchema.copy() + Schema(( RecordsField( @@ -119,21 +101,14 @@ "in lists and results reports instead of the real result.") ), ), - - ComputedField( - 'ClientUID', - expression="context.aq_parent.UID()", - widget=ComputedWidget( - visible=False, - ), - ), )) schema['description'].widget.visible = True schema['title'].required = True -class AnalysisSpec(BaseFolder, HistoryAwareMixin, ClientAwareMixin): +class AnalysisSpec(BaseFolder, HistoryAwareMixin, ClientAwareMixin, + SampleTypeAwareMixin): """Analysis Specification """ implements(IAnalysisSpec, IDeactivable) @@ -155,9 +130,7 @@ def Title(self): if self.title: title = self.title else: - sampletype = self.getSampleType() - if sampletype: - title = sampletype.Title() + title = self.getSampleTypeTitle() or "" return safe_unicode(title).encode('utf-8') def contextual_title(self): diff --git a/bika/lims/content/artemplate.py b/bika/lims/content/artemplate.py index 4e61f9b88a..1c24a8bc31 100644 --- a/bika/lims/content/artemplate.py +++ b/bika/lims/content/artemplate.py @@ -31,6 +31,7 @@ from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.content.clientawaremixin import ClientAwareMixin +from bika.lims.content.sampletype import SampleTypeAwareMixin from bika.lims.interfaces import IARTemplate, IDeactivable from Products.Archetypes.public import BaseContent from Products.Archetypes.public import BooleanField @@ -96,13 +97,6 @@ showOn=True, ), ), - ComputedField( - "SampleTypeUID", - expression="context.Schema()['SampleType'].get(context) and context.Schema()['SampleType'].get(context).UID() or ''", - widget=ComputedWidget( - visible=False, - ), - ), BooleanField( "Composite", default=False, @@ -300,7 +294,7 @@ schema["title"]._validationLayer() -class ARTemplate(BaseContent, ClientAwareMixin): +class ARTemplate(BaseContent, ClientAwareMixin, SampleTypeAwareMixin): security = ClassSecurityInfo() schema = schema displayContentsTab = False diff --git a/bika/lims/content/samplepoint.py b/bika/lims/content/samplepoint.py index 9e88666e76..6efff397af 100644 --- a/bika/lims/content/samplepoint.py +++ b/bika/lims/content/samplepoint.py @@ -34,6 +34,10 @@ from Products.Archetypes.public import registerType from Products.CMFCore.utils import getToolByName from Products.CMFPlone.utils import safe_unicode +from plone.app.blob.field import FileField as BlobFileField +from zope.interface import implements + +from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims import deprecated from bika.lims.browser.fields import CoordinateField @@ -45,9 +49,8 @@ from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.content.clientawaremixin import ClientAwareMixin +from bika.lims.content.sampletype import SampleTypeAwareMixin from bika.lims.interfaces import IDeactivable -from plone.app.blob.field import FileField as BlobFileField -from zope.interface import implements schema = BikaSchema.copy() + Schema(( CoordinateField( @@ -98,6 +101,11 @@ description=_("The list of sample types that can be collected " "at this sample point. If no sample types are " "selected, then all sample types are available."), + catalog_name='bika_setup_catalog', + base_query={"is_active": True, + "sort_on": "sortable_title", + "sort_order": "ascending"}, + showOn=True, ), ), @@ -126,7 +134,8 @@ schema['description'].schemata = 'default' -class SamplePoint(BaseContent, HistoryAwareMixin, ClientAwareMixin): +class SamplePoint(BaseContent, HistoryAwareMixin, ClientAwareMixin, + SampleTypeAwareMixin): implements(IDeactivable) security = ClassSecurityInfo() displayContentsTab = False @@ -141,19 +150,6 @@ def _renameAfterCreation(self, check_auto_id=False): def Title(self): return safe_unicode(self.getField('title').get(self)).encode('utf-8') - def getSampleTypeTitle(self): - """Returns a comma separated list of sample type titles - """ - sample_types = self.getSampleTypes() - sample_type_titles = map(lambda obj: obj.Title(), sample_types) - if not sample_type_titles: - return "" - return ",".join(sample_type_titles) - - def SampleTypesVocabulary(self): - from bika.lims.content.sampletype import SampleTypes - return SampleTypes(self, allow_blank=False) - def setSampleTypes(self, value, **kw): """ For the moment, we're manually trimming the sampletype<>samplepoint relation to be equal on both sides, here. @@ -188,31 +184,5 @@ def setSampleTypes(self, value, **kw): return ret - def getSampleTypes(self, **kw): - return self.Schema()['SampleTypes'].get(self) - registerType(SamplePoint, PROJECTNAME) - - -@deprecated("bika.lims.content.samplepoint.SamplePoints function will be removed in senaite.core 1.2.0") -def SamplePoints(self, instance=None, allow_blank=True, lab_only=True): - instance = instance or self - bsc = getToolByName(instance, 'bika_setup_catalog') - items = [] - contentFilter = { - 'portal_type': 'SamplePoint', - 'is_active': True, - 'sort_on': 'sortable_title'} - if lab_only: - lab_path = instance.bika_setup.bika_samplepoints.getPhysicalPath() - contentFilter['path'] = {"query": "/".join(lab_path), "level": 0} - for sp in bsc(contentFilter): - sp = sp.getObject() - if sp.aq_parent.portal_type == 'Client': - sp_title = "{}: {}".format(sp.aq_parent.Title(), sp.Title()) - else: - sp_title = sp.Title() - items.append((sp.UID(), sp_title)) - items = allow_blank and [['', '']] + list(items) or list(items) - return DisplayList(items) diff --git a/bika/lims/content/sampletype.py b/bika/lims/content/sampletype.py index 01269926f0..e196ca9f36 100644 --- a/bika/lims/content/sampletype.py +++ b/bika/lims/content/sampletype.py @@ -34,9 +34,11 @@ from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.interfaces import ISampleType, IDeactivable +from bika.lims.interfaces import ISampleTypeAwareMixin from bika.lims.vocabularies import getStickerTemplates from magnitude import mg from zope.interface import implements +from bika.lims import api SMALL_DEFAULT_STICKER = 'small_default' LARGE_DEFAULT_STICKER = 'large_default' @@ -56,6 +58,56 @@ def sticker_templates(): return voc +class SampleTypeAwareMixin(BaseObject): + implements(ISampleTypeAwareMixin) + + def getSampleType(self): + """Returns the sample type(s) assigned to this object, if any + """ + if ISampleType.providedBy(self): + return self + + field = self._get_field() + if not field: + return None + + sample_type = field.get(self) + return sample_type or None + + def getSampleTypeUID(self): + """Returns the UID(s) of the Sample Type(s) assigned to this object + """ + sample_type = self.getSampleType() + if isinstance(sample_type, (list, tuple)): + return map(api.get_uid, sample_type) + elif sample_type: + return api.get_uid(sample_type) + return None + + def getSampleTypeTitle(self): + """Returns the title or a comma separated list of sample type titles + """ + sample_type = self.getSampleType() + if isinstance(sample_type, (list, tuple)): + title = map(api.get_title, sample_type) + return ",".join(title) + elif sample_type: + return api.get_title(sample_type) + return None + + def _get_field(self): + """Returns the field that stores the SampleType object, if any + """ + field = self.getField("SampleType", None) + if not field: + field = self.getField("SampleTypes", None) + + if not field: + return None + + return field + + schema = BikaSchema.copy() + Schema(( DurationField('RetentionPeriod', required = 1, @@ -119,13 +171,17 @@ def sticker_templates(): required = 0, multiValued = 1, allowed_types = ('SamplePoint',), - vocabulary = 'SamplePointsVocabulary', relationship = 'SampleTypeSamplePoint', widget = brw( label=_("Sample Points"), description =_("The list of sample points from which this sample " "type can be collected. If no sample points are " "selected, then all sample points are available."), + catalog_name='bika_setup_catalog', + base_query={"is_active": True, + "sort_on": "sortable_title", + "sort_order": "ascending"}, + showOn=True, ), ), ComputedField( @@ -181,7 +237,8 @@ def sticker_templates(): schema['description'].schemata = 'default' schema['description'].widget.visible = True -class SampleType(BaseContent, HistoryAwareMixin): + +class SampleType(BaseContent, HistoryAwareMixin, SampleTypeAwareMixin): implements(ISampleType, IDeactivable) security = ClassSecurityInfo() @@ -221,10 +278,6 @@ def getDefaultLifetime(self): settings = getToolByName(self, 'bika_setup') return settings.getDefaultSampleLifetime() - def SamplePointsVocabulary(self): - from bika.lims.content.samplepoint import SamplePoints - return SamplePoints(self, allow_blank=False, lab_only=False) - def setSamplePoints(self, value, **kw): """ For the moment, we're manually trimming the sampletype<>samplepoint relation to be equal on both sides, here. @@ -257,9 +310,6 @@ def setSamplePoints(self, value, **kw): return ret - def getSamplePoints(self, **kw): - return self.Schema()['SamplePoints'].get(self) - def SampleMatricesVocabulary(self): from bika.lims.content.samplematrix import SampleMatrices return SampleMatrices(self, allow_blank=True) @@ -367,14 +417,3 @@ def _set_sticker_subfield(self, subfield, value): registerType(SampleType, PROJECTNAME) - -def SampleTypes(self, instance=None, allow_blank=False): - instance = instance or self - bsc = getToolByName(instance, 'bika_setup_catalog') - items = [] - for st in bsc(portal_type='SampleType', - is_active=True, - sort_on = 'sortable_title'): - items.append((st.UID, st.Title)) - items = allow_blank and [['','']] + list(items) or list(items) - return DisplayList(items) diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index 3116794db7..cd64656bff 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -999,3 +999,17 @@ def getClient(self): def getClientUID(self): """Returns the client UID this object is bound to, if any """ + + +class ISampleTypeAwareMixin(Interface): + """Marker interface for objects that can be assigned to one, or multiple + SampleType objects through a ReferenceField + """ + + def getSampleType(self): + """Returns the sample type(s) assigned to this object, if any + """ + + def getSampleTypeUID(self): + """Returns the UID(s) of the Sample Type(s) assigned to this object + """ diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index b333331fc5..736402e279 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -203,7 +203,7 @@ # Sorting of listings: Sample Points, Specifications ("bika_setup_catalog", "getSampleTypeTitle", "", "FieldIndex"), # Filter in Add2: Sample Points, Specifications, Templates - ("bika_setup_catalog", "getSampleTypeUID", "", "FieldIndex"), + ("bika_setup_catalog", "getSampleTypeUID", "", "KeywordIndex"), ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), ("bika_setup_catalog", "getTotalPrice", "", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index ed97847ae6..3072d537f9 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -30,6 +30,12 @@ version = "1.3.3" # Remember version number in metadata.xml and setup.py profile = "profile-{0}:default".format(product) +INDEXES_TO_ADD = [ + # We changed the type of this index from FieldIndex to KeywordIndex + # https://github.com/senaite/senaite.core/pull/1481 + ("bika_setup_catalog", "getSampleTypeUID", "KeywordIndex"), +] + INDEXES_TO_REMOVE = [ # Only used in add2 to filter Sample Points by Sample Type when a Sample # Type was selected. Now, getSampleTypeUID is used instead because of @@ -44,7 +50,11 @@ # Not used neither for searches nor filtering of any of the content types # stored in bika_catalog (Batch, BatchFolder and ReferenceSample) - ("bika_catalog", "getSampleTypeUID") + ("bika_catalog", "getSampleTypeUID"), + + # We remove this index because we changed it's type to KeywordIndex + # https://github.com/senaite/senaite.core/pull/1481 + ("bika_setup_catalog", "getSampleTypeUID") ] METADATA_TO_REMOVE = [ @@ -88,6 +98,10 @@ def upgrade(tool): remove_stale_indexes(portal) remove_stale_metadata(portal) + # Add new indexes + # https://github.com/senaite/senaite.core/pull/1481 + add_new_indexes(portal) + # Reindex client's related fields (getClientUID, getClientTitle, etc.) # https://github.com/senaite/senaite.core/pull/1477 reindex_client_fields(portal) @@ -166,3 +180,22 @@ def del_metadata(catalog_id, column): .format(column, catalog_id)) return catalog.delColumn(column) + + +def add_new_indexes(portal): + logger.info("Adding new indexes ...") + for catalog_id, index_name, index_metatype in INDEXES_TO_ADD: + add_index(catalog_id, index_name, index_metatype) + logger.info("Adding new indexes ... [DONE]") + + +def add_index(catalog_id, index_name, index_metatype): + logger.info("Adding '{}' index to '{}' ...".format(index_name, catalog_id)) + catalog = api.get_tool(catalog_id) + if index_name in catalog.indexes(): + logger.info("Index '{}' already in catalog '{}' [SKIP]" + .format(index_name, catalog_id)) + return + catalog.addIndex(index_name, index_metatype) + logger.info("Indexing new index '{}' ...".format(index_name)) + catalog.manage_reindexIndex(index_name) From 64b2486ed581e4814ff2b58c0e8e9a40d56d9bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 09:24:41 +0100 Subject: [PATCH 23/96] Remove SampleTypeVocabulary (no longer used) --- bika/lims/content/samplepoint.py | 1 - bika/lims/vocabularies/__init__.py | 10 ---------- bika/lims/vocabularies/configure.zcml | 5 ----- 3 files changed, 16 deletions(-) diff --git a/bika/lims/content/samplepoint.py b/bika/lims/content/samplepoint.py index 6efff397af..e2ba5cfeef 100644 --- a/bika/lims/content/samplepoint.py +++ b/bika/lims/content/samplepoint.py @@ -94,7 +94,6 @@ required=0, multiValued=1, allowed_types=('SampleType',), - vocabulary='SampleTypesVocabulary', relationship='SamplePointSampleType', widget=BikaReferenceWidget( label=_("Sample Types"), diff --git a/bika/lims/vocabularies/__init__.py b/bika/lims/vocabularies/__init__.py index 8346228e23..3ffcc0eeac 100644 --- a/bika/lims/vocabularies/__init__.py +++ b/bika/lims/vocabularies/__init__.py @@ -214,16 +214,6 @@ def __init__(self): SamplePointVocabularyFactory = SamplePointVocabulary() -class SampleTypeVocabulary(BikaContentVocabulary): - def __init__(self): - BikaContentVocabulary.__init__(self, - ['bika_setup/bika_sampletypes', ], - ['SampleType', ]) - - -SampleTypeVocabularyFactory = SampleTypeVocabulary() - - class AnalysisServiceVocabulary(BikaContentVocabulary): def __init__(self): BikaContentVocabulary.__init__(self, diff --git a/bika/lims/vocabularies/configure.zcml b/bika/lims/vocabularies/configure.zcml index 0c7b10385a..57ccb9bf27 100644 --- a/bika/lims/vocabularies/configure.zcml +++ b/bika/lims/vocabularies/configure.zcml @@ -50,11 +50,6 @@ name="bika.lims.vocabularies.StorageLocations" /> - - Date: Thu, 28 Nov 2019 09:44:45 +0100 Subject: [PATCH 24/96] Index: getSampleTypeUID --> sampletype_uids --- bika/lims/browser/analysisrequest/add2.py | 6 +++--- bika/lims/catalog/indexers/bikasetup.py | 2 +- bika/lims/catalog/indexers/configure.zcml | 6 +++++- bika/lims/content/analysisrequest.py | 2 +- bika/lims/setuphandlers.py | 2 +- bika/lims/upgrade/v01_03_003.py | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index 0bef224842..5760dd976b 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -1018,18 +1018,18 @@ def get_sampletype_info(self, obj): # Display Sample Points that have this sample type assigned plus # those that do not have a sample type assigned "SamplePoint": { - "getSampleTypeUID": [sample_type_uid, None], + "sampletype_uids": [sample_type_uid, None], "getClientUID": [client_uid, ""], }, # Display Specifications that have this sample type assigned only "Specification": { - "getSampleTypeUID": sample_type_uid, + "sampletype_uids": sample_type_uid, "getClientUID": [client_uid, ""], }, # Display AR Templates that have this sample type assigned plus # those that do not have a sample type assigned "Template": { - "getSampleTypeUID": [sample_type_uid, None], + "sampletype_uids": [sample_type_uid, None], "getClientUID": [client_uid, ""], } } diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index dfb2958256..6b7a0e3159 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -6,7 +6,7 @@ @indexer(ISampleTypeAwareMixin, IBikaSetupCatalog) -def getSampleTypeUID(instance): +def sampletype_uids(instance): """Returns the list of SampleType UIDs the instance is assigned to This is a KeywordIndex, so it will be indexed as a list, even if only one diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index d95dcbc4cf..58fe0514a8 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -25,7 +25,11 @@ - + + + diff --git a/bika/lims/content/analysisrequest.py b/bika/lims/content/analysisrequest.py index 2982dff1e0..227d7ead22 100644 --- a/bika/lims/content/analysisrequest.py +++ b/bika/lims/content/analysisrequest.py @@ -690,7 +690,7 @@ 'width': '30', 'label': _('Title'), 'align': 'left'}, - {'columnName': 'SampleTypeTitle', + {'columnName': 'getSampleTypeTitle', 'width': '70', 'label': _('SampleType'), 'align': 'left'}, diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 736402e279..489dae7fc2 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -203,7 +203,7 @@ # Sorting of listings: Sample Points, Specifications ("bika_setup_catalog", "getSampleTypeTitle", "", "FieldIndex"), # Filter in Add2: Sample Points, Specifications, Templates - ("bika_setup_catalog", "getSampleTypeUID", "", "KeywordIndex"), + ("bika_setup_catalog", "sampletype_uids", "", "KeywordIndex"), ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), ("bika_setup_catalog", "getTotalPrice", "", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 3072d537f9..07a0ec8d6b 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -33,7 +33,7 @@ INDEXES_TO_ADD = [ # We changed the type of this index from FieldIndex to KeywordIndex # https://github.com/senaite/senaite.core/pull/1481 - ("bika_setup_catalog", "getSampleTypeUID", "KeywordIndex"), + ("bika_setup_catalog", "sampletype_uids", "KeywordIndex"), ] INDEXES_TO_REMOVE = [ From c0838ab65a02d5383da7de90fa71c1dcf213089f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 10:35:12 +0100 Subject: [PATCH 25/96] Added code header --- bika/lims/catalog/indexers/bikasetup.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 6b7a0e3159..e9ee811f1c 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -1,4 +1,23 @@ -from Products.Archetypes.interfaces import IBaseObject +# -*- 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-2019 by it's authors. +# Some rights reserved, see README and LICENSE. + from plone.indexer import indexer from bika.lims.interfaces import IBikaSetupCatalog From 244dc3199534324e6b1652237f209b9ce11996fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 10:35:29 +0100 Subject: [PATCH 26/96] Added some comments --- bika/lims/catalog/indexers/configure.zcml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 58fe0514a8..55e6990556 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -24,13 +24,14 @@ + - + + From 49cbaa5472b663d8af83461cf6dfc48b41309aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 10:35:48 +0100 Subject: [PATCH 27/96] security.public and titles separated with ", " --- bika/lims/content/sampletype.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bika/lims/content/sampletype.py b/bika/lims/content/sampletype.py index e196ca9f36..da2ea2c533 100644 --- a/bika/lims/content/sampletype.py +++ b/bika/lims/content/sampletype.py @@ -61,6 +61,9 @@ def sticker_templates(): class SampleTypeAwareMixin(BaseObject): implements(ISampleTypeAwareMixin) + security = ClassSecurityInfo() + + @security.public def getSampleType(self): """Returns the sample type(s) assigned to this object, if any """ @@ -74,6 +77,7 @@ def getSampleType(self): sample_type = field.get(self) return sample_type or None + @security.public def getSampleTypeUID(self): """Returns the UID(s) of the Sample Type(s) assigned to this object """ @@ -84,13 +88,14 @@ def getSampleTypeUID(self): return api.get_uid(sample_type) return None + @security.public def getSampleTypeTitle(self): """Returns the title or a comma separated list of sample type titles """ sample_type = self.getSampleType() if isinstance(sample_type, (list, tuple)): title = map(api.get_title, sample_type) - return ",".join(title) + return ", ".join(title) elif sample_type: return api.get_title(sample_type) return None From 0006e314ce252868be48f9fc30bf6f42afa1d49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 10:37:55 +0100 Subject: [PATCH 28/96] Organize imports --- bika/lims/content/analysisspec.py | 23 ++++++++++++----------- bika/lims/content/artemplate.py | 28 +++++++++++++++------------- bika/lims/content/samplepoint.py | 3 --- bika/lims/content/sampletype.py | 10 ++++++---- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/bika/lims/content/analysisspec.py b/bika/lims/content/analysisspec.py index d8824e372b..4a3fccc4f1 100644 --- a/bika/lims/content/analysisspec.py +++ b/bika/lims/content/analysisspec.py @@ -19,26 +19,27 @@ # Some rights reserved, see README and LICENSE. from AccessControl import ClassSecurityInfo -from bika.lims import api -from bika.lims import bikaMessageFactory as _ -from bika.lims.browser.fields import UIDReferenceField -from bika.lims.browser.widgets import AnalysisSpecificationWidget -from bika.lims.config import PROJECTNAME -from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientawaremixin import ClientAwareMixin -from bika.lims.content.sampletype import SampleTypeAwareMixin -from bika.lims.interfaces import IAnalysisSpec, IDeactivable +from Products.ATContentTypes.lib.historyaware import HistoryAwareMixin +from Products.ATExtensions.field.records import RecordsField from Products.Archetypes import atapi from Products.Archetypes.public import BaseFolder from Products.Archetypes.public import ReferenceWidget from Products.Archetypes.public import Schema from Products.Archetypes.utils import DisplayList -from Products.ATContentTypes.lib.historyaware import HistoryAwareMixin -from Products.ATExtensions.field.records import RecordsField from Products.CMFPlone.utils import safe_unicode from zope.i18n import translate from zope.interface import implements +from bika.lims import api +from bika.lims import bikaMessageFactory as _ +from bika.lims.browser.fields import UIDReferenceField +from bika.lims.browser.widgets import AnalysisSpecificationWidget +from bika.lims.config import PROJECTNAME +from bika.lims.content.bikaschema import BikaSchema +from bika.lims.content.clientawaremixin import ClientAwareMixin +from bika.lims.content.sampletype import SampleTypeAwareMixin +from bika.lims.interfaces import IAnalysisSpec +from bika.lims.interfaces import IDeactivable schema = Schema(( diff --git a/bika/lims/content/artemplate.py b/bika/lims/content/artemplate.py index 1c24a8bc31..72f8b260ca 100644 --- a/bika/lims/content/artemplate.py +++ b/bika/lims/content/artemplate.py @@ -21,18 +21,7 @@ import sys from AccessControl import ClassSecurityInfo -from bika.lims import api -from bika.lims import bikaMessageFactory as _ -from bika.lims.browser.fields.remarksfield import RemarksField -from bika.lims.browser.widgets import ARTemplateAnalysesWidget -from bika.lims.browser.widgets import ARTemplatePartitionsWidget -from bika.lims.browser.widgets import ReferenceWidget -from bika.lims.browser.widgets import RemarksWidget -from bika.lims.config import PROJECTNAME -from bika.lims.content.bikaschema import BikaSchema -from bika.lims.content.clientawaremixin import ClientAwareMixin -from bika.lims.content.sampletype import SampleTypeAwareMixin -from bika.lims.interfaces import IARTemplate, IDeactivable +from Products.ATExtensions.field.records import RecordsField from Products.Archetypes.public import BaseContent from Products.Archetypes.public import BooleanField from Products.Archetypes.public import BooleanWidget @@ -43,10 +32,23 @@ from Products.Archetypes.public import Schema from Products.Archetypes.public import registerType from Products.Archetypes.references import HoldingReference -from Products.ATExtensions.field.records import RecordsField from Products.CMFCore.utils import getToolByName from zope.interface import implements +from bika.lims import api +from bika.lims import bikaMessageFactory as _ +from bika.lims.browser.fields.remarksfield import RemarksField +from bika.lims.browser.widgets import ARTemplateAnalysesWidget +from bika.lims.browser.widgets import ARTemplatePartitionsWidget +from bika.lims.browser.widgets import ReferenceWidget +from bika.lims.browser.widgets import RemarksWidget +from bika.lims.config import PROJECTNAME +from bika.lims.content.bikaschema import BikaSchema +from bika.lims.content.clientawaremixin import ClientAwareMixin +from bika.lims.content.sampletype import SampleTypeAwareMixin +from bika.lims.interfaces import IARTemplate +from bika.lims.interfaces import IDeactivable + schema = BikaSchema.copy() + Schema(( ReferenceField( "SamplePoint", diff --git a/bika/lims/content/samplepoint.py b/bika/lims/content/samplepoint.py index e2ba5cfeef..e2bdd30f81 100644 --- a/bika/lims/content/samplepoint.py +++ b/bika/lims/content/samplepoint.py @@ -25,7 +25,6 @@ from Products.Archetypes.public import BaseContent from Products.Archetypes.public import BooleanField from Products.Archetypes.public import BooleanWidget -from Products.Archetypes.public import DisplayList from Products.Archetypes.public import FileWidget from Products.Archetypes.public import ReferenceField from Products.Archetypes.public import Schema @@ -37,9 +36,7 @@ from plone.app.blob.field import FileField as BlobFileField from zope.interface import implements -from bika.lims import api from bika.lims import bikaMessageFactory as _ -from bika.lims import deprecated from bika.lims.browser.fields import CoordinateField from bika.lims.browser.fields import DurationField from bika.lims.browser.widgets import CoordinateWidget diff --git a/bika/lims/content/sampletype.py b/bika/lims/content/sampletype.py index da2ea2c533..d77207379f 100644 --- a/bika/lims/content/sampletype.py +++ b/bika/lims/content/sampletype.py @@ -25,6 +25,10 @@ from Products.Archetypes.references import HoldingReference from Products.CMFCore.utils import getToolByName from Products.CMFPlone.utils import safe_unicode +from magnitude import mg +from zope.interface import implements + +from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims import logger from bika.lims.browser.fields import DurationField @@ -33,12 +37,10 @@ from bika.lims.browser.widgets.referencewidget import ReferenceWidget as brw from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.interfaces import ISampleType, IDeactivable +from bika.lims.interfaces import IDeactivable +from bika.lims.interfaces import ISampleType from bika.lims.interfaces import ISampleTypeAwareMixin from bika.lims.vocabularies import getStickerTemplates -from magnitude import mg -from zope.interface import implements -from bika.lims import api SMALL_DEFAULT_STICKER = 'small_default' LARGE_DEFAULT_STICKER = 'large_default' From bdfe66a7c110d9c0eb78e40636e74a162db629a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 10:43:16 +0100 Subject: [PATCH 29/96] Add getSampleTypesTitle in ISampleTypeAwareMixin interface --- bika/lims/interfaces/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index cd64656bff..b74fc273d7 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -1013,3 +1013,7 @@ def getSampleType(self): def getSampleTypeUID(self): """Returns the UID(s) of the Sample Type(s) assigned to this object """ + + def getSampleTypeTitle(self): + """Returns the title or a comma separated list of sample type titles + """ From da45ff6b2a106b3680e603f2ee4d3bca69972730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 10:47:33 +0100 Subject: [PATCH 30/96] Remove stupid conditional --- bika/lims/content/sampletype.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bika/lims/content/sampletype.py b/bika/lims/content/sampletype.py index d77207379f..532769a9e1 100644 --- a/bika/lims/content/sampletype.py +++ b/bika/lims/content/sampletype.py @@ -109,9 +109,6 @@ def _get_field(self): if not field: field = self.getField("SampleTypes", None) - if not field: - return None - return field From c31731465c43d932c9ff68d5e56dc1e17d3b2121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 15:08:11 +0100 Subject: [PATCH 31/96] Redux getAccredited index and metadata --- bika/lims/browser/accreditation.py | 21 ++++++++++++++++--- .../analysisrequest/templates/ar_add2.pt | 1 - bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 14 +++++++++++-- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/bika/lims/browser/accreditation.py b/bika/lims/browser/accreditation.py index a98da71538..07a4e28211 100644 --- a/bika/lims/browser/accreditation.py +++ b/bika/lims/browser/accreditation.py @@ -19,11 +19,13 @@ # Some rights reserved, see README and LICENSE. from Products.CMFPlone.utils import safe_unicode +from plone.app.content.browser.interfaces import IFolderContentsView +from zope.interface import implements + +from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.controlpanel.bika_analysisservices import AnalysisServicesView from bika.lims.utils import t -from plone.app.content.browser.interfaces import IFolderContentsView -from zope.interface import implements class AccreditationView(AnalysisServicesView): @@ -34,7 +36,6 @@ def __init__(self, context, request): self.contentFilter = { 'portal_type': 'AnalysisService', 'sort_on': 'sortable_title', - 'getAccredited': True, 'is_active': True} self.context_actions = {} self.title = self.context.translate(_("Accreditation")) @@ -102,3 +103,17 @@ def selected_cats(self, items): if 'category' in item and item['category'] not in cats: cats.append(item['category']) return cats + + def search(self, searchterm="", ignorecase=True): + # Boil out those that are not accredited + # There is no need to keep a `getAccredited` index in the catalog only + # for this view. Since we don't expect a lot of items from this content + # type (AnalysisService), so is fine to wake-up them + brains = super(AccreditationView, self).search(searchterm, ignorecase) + out_brains = [] + for brain in brains: + obj = api.get_object(brain) + if obj.getAccredited(): + out_brains.append(brain) + return out_brains + diff --git a/bika/lims/browser/analysisrequest/templates/ar_add2.pt b/bika/lims/browser/analysisrequest/templates/ar_add2.pt index 5e2aebce05..c5aaabe3ba 100644 --- a/bika/lims/browser/analysisrequest/templates/ar_add2.pt +++ b/bika/lims/browser/analysisrequest/templates/ar_add2.pt @@ -412,7 +412,6 @@ Date: Thu, 28 Nov 2019 20:06:50 +0100 Subject: [PATCH 32/96] Remove getAnalyst index from setup_catalog --- bika/lims/setuphandlers.py | 1 - bika/lims/upgrade/v01_03_003.py | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 2317900dfc..203dba8f01 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -167,7 +167,6 @@ ("bika_setup_catalog", "UID", "", "FieldIndex"), ("bika_setup_catalog", "allowedRolesAndUsers", "", "KeywordIndex"), ("bika_setup_catalog", "created", "", "DateIndex"), - ("bika_setup_catalog", "getAnalyst", "", "FieldIndex"), ("bika_setup_catalog", "getAvailableMethodUIDs", "", "KeywordIndex"), ("bika_setup_catalog", "getBlank", "", "FieldIndex"), ("bika_setup_catalog", "getCalculationTitle", "", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 0ca6ae7b8c..2e1e3b5401 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -61,6 +61,11 @@ # contain too many items, they are now filtered by waking-up the object # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getAccredited"), + + # getAnalyst index is used in Analyses (Duplicates and Reference included) + # and Worksheets. None of the types stored in setup_catalog support Analyst + # https://github.com/senaite/senaite.core/pull/1484 + ("bika_setup_catalog", "getAnalyst"), ] METADATA_TO_REMOVE = [ From 05f5a15430b309d75a464cbff0d610cc83f07d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 20:49:58 +0100 Subject: [PATCH 33/96] getAvailableMethodUIDs -> method_available_uids --- bika/lims/browser/widgets/serviceswidget.py | 2 +- bika/lims/catalog/indexers/bikasetup.py | 16 +++++++++++ bika/lims/catalog/indexers/configure.zcml | 4 +++ bika/lims/content/analysisservice.py | 31 +++++++++++---------- bika/lims/setuphandlers.py | 4 ++- bika/lims/upgrade/v01_03_003.py | 23 +++++++++++---- bika/lims/validators.py | 2 +- 7 files changed, 60 insertions(+), 22 deletions(-) diff --git a/bika/lims/browser/widgets/serviceswidget.py b/bika/lims/browser/widgets/serviceswidget.py index c46d46a494..8a55618235 100644 --- a/bika/lims/browser/widgets/serviceswidget.py +++ b/bika/lims/browser/widgets/serviceswidget.py @@ -49,7 +49,7 @@ def __init__(self, context, request): method_uid = context.getMethodUID() if method_uid: self.contentFilter.update({ - "getAvailableMethodUIDs": method_uid + "method_available_uids": method_uid }) self.context_actions = {} diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index e9ee811f1c..fa98ce088a 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -20,6 +20,7 @@ from plone.indexer import indexer +from bika.lims.interfaces import IAnalysisService from bika.lims.interfaces import IBikaSetupCatalog from bika.lims.interfaces import ISampleTypeAwareMixin @@ -34,3 +35,18 @@ def sampletype_uids(instance): searches for `MissingValue` entries too. """ return instance.getSampleTypeUID() or (None, ) + + +@indexer(IAnalysisService, IBikaSetupCatalog) +def method_available_uids(instance): + """Returns a list of Method UIDs that are available for this instance + + If the instance (AnalysisService) has InstrumentEntryOfResults set to True, + it returns the methods available from the instruments capable to perform the + service, as well as the methods set manually to the analysis. Otherwise, it + returns the methods assigned manually only. + + If the instance has no available method assigned, it returns a tuple with + a None value. This allows searches for `MissingValue` entries too. + """ + return instance.getAvailableMethodUIDs() or (None, ) diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 55e6990556..30e6a1f666 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -31,6 +31,10 @@ Specifications and Templates when a Sample Type is selected --> + + + diff --git a/bika/lims/content/analysisservice.py b/bika/lims/content/analysisservice.py index 7d90271db9..a928a38979 100644 --- a/bika/lims/content/analysisservice.py +++ b/bika/lims/content/analysisservice.py @@ -488,18 +488,15 @@ def getAvailableMethods(self): is unset, only the methods assigned manually to that service are returned. """ - methods = self.getMethods() - muids = [m.UID() for m in methods] - if self.getInstrumentEntryOfResults(): - # Add the methods from the instruments capable to perform - # this analysis service - for ins in self.getInstruments(): - for method in ins.getMethods(): - if method and method.UID() not in muids: - methods.append(method) - muids.append(method.UID()) + if not self.getInstrumentEntryOfResults(): + # No need to go further, just return the manually assigned methods + return self.getMethods() - return methods + # Return the manually assigned methods plus those from instruments + method_uids = self.getAvailableMethodUIDs() + query = dict(portal_type="Method", UID=method_uids) + brains = api.search(query, "bika_setup_catalog") + return map(api.get_object_by_uid, brains) @security.public def getAvailableMethodUIDs(self): @@ -507,7 +504,13 @@ def getAvailableMethodUIDs(self): Returns the UIDs of the available methods. it is used as a vocabulary to fill the selection list of 'Methods' field. """ - return [m.UID() for m in self.getAvailableMethods()] + method_uids = self.getRawMethods() + if self.getInstrumentEntryOfResults(): + for instrument in self.getInstruments(): + method_uids.extend(instrument.getRawMethods()) + method_uids = filter(None, method_uids) + method_uids = list(set(method_uids)) + return method_uids @security.public def getMethods(self): @@ -530,7 +533,7 @@ def getMethodUIDs(self): :returns: List of method UIDs """ - return map(api.get_uid, self.getMethods()) + return self.getRawMethods() @security.public def getInstruments(self): @@ -550,7 +553,7 @@ def getInstrumentUIDs(self): :returns: List of instrument UIDs """ - return map(api.get_uid, self.getInstruments()) + return self.getRawInstruments() @security.public def getAvailableInstruments(self): diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 203dba8f01..e7b1d365a4 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -167,7 +167,9 @@ ("bika_setup_catalog", "UID", "", "FieldIndex"), ("bika_setup_catalog", "allowedRolesAndUsers", "", "KeywordIndex"), ("bika_setup_catalog", "created", "", "DateIndex"), - ("bika_setup_catalog", "getAvailableMethodUIDs", "", "KeywordIndex"), + # Filter services in Worksheet's Add Analyses View for when the Worksheet + # Template being used has a Method assigned + ("bika_setup_catalog", "method_available_uids", "", "KeywordIndex"), ("bika_setup_catalog", "getBlank", "", "FieldIndex"), ("bika_setup_catalog", "getCalculationTitle", "", "FieldIndex"), ("bika_setup_catalog", "getCalculationUID", "", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 2e1e3b5401..876b61f863 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -31,9 +31,15 @@ profile = "profile-{0}:default".format(product) INDEXES_TO_ADD = [ - # We changed the type of this index from FieldIndex to KeywordIndex + # Replaces getSampleTypeUIDs # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "sampletype_uids", "KeywordIndex"), + + # Replaces getAvailableMethodUIDs + # Used to filter services in Worksheet's Add Analyses View for when the + # Worksheet Template being used has a Method assigned. + # https://github.com/senaite/senaite.core/pull/1481 + ("bika_setup_catalog", "method_available_uids", "KeywordIndex"), ] INDEXES_TO_REMOVE = [ @@ -52,10 +58,6 @@ # stored in bika_catalog (Batch, BatchFolder and ReferenceSample) ("bika_catalog", "getSampleTypeUID"), - # We remove this index because we changed it's type to KeywordIndex - # https://github.com/senaite/senaite.core/pull/1481 - ("bika_setup_catalog", "getSampleTypeUID"), - # getAccredited was only used in the "hidden" view accreditation to filter # services labeled as "accredited". Since we don't expect that listing to # contain too many items, they are now filtered by waking-up the object @@ -66,6 +68,17 @@ # and Worksheets. None of the types stored in setup_catalog support Analyst # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getAnalyst"), + + + # REPLACEMENTS (indexes to be removed because of a replacement) + + # getSampleTypeUID --> sampletype_uid (FieldIndex --> KeywordIndex) + # https://github.com/senaite/senaite.core/pull/1481 + ("bika_setup_catalog", "getSampleTypeUID"), + + # getAvailableMethodUIDs --> method_available_uids + # https://github.com/senaite/senaite.core/pull/1484 + ("bika_setup_catalog", "getAvailableMethodUIDs"), ] METADATA_TO_REMOVE = [ diff --git a/bika/lims/validators.py b/bika/lims/validators.py index ff5124eb73..69d7cb8d98 100644 --- a/bika/lims/validators.py +++ b/bika/lims/validators.py @@ -1322,7 +1322,7 @@ def __call__(self, value, *args, **kwargs): bsc = getToolByName(instance, 'bika_setup_catalog') query = { 'portal_type': 'AnalysisService', - 'getAvailableMethodUIDs': method.UID() + 'method_available_uids': method.UID() } method_ans_uids = [b.UID for b in bsc(query)] rules = instance.getReflexRules() From 721e690718f159ab132ed218336406fb45fafa25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 23:01:14 +0100 Subject: [PATCH 34/96] Misspelling --- bika/lims/catalog/indexers/configure.zcml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 30e6a1f666..b3a764a586 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -31,8 +31,8 @@ Specifications and Templates when a Sample Type is selected --> - + From 570b6b7a02b15016a891481515dd5f4d908cde4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 23:12:54 +0100 Subject: [PATCH 35/96] Remove getBlank index and metadata from setup_catalog --- bika/lims/setuphandlers.py | 3 +-- bika/lims/upgrade/v01_03_003.py | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index e7b1d365a4..2e32b1e642 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -138,6 +138,7 @@ ("bika_catalog", "UID", "", "FieldIndex"), ("bika_catalog", "allowedRolesAndUsers", "", "KeywordIndex"), ("bika_catalog", "created", "", "DateIndex"), + # Filter ReferenceSamples in AddControl and AddBlank views from Worksheet ("bika_catalog", "getBlank", "", "BooleanIndex"), ("bika_catalog", "getClientBatchID", "", "FieldIndex"), ("bika_catalog", "getClientID", "", "FieldIndex"), @@ -170,7 +171,6 @@ # Filter services in Worksheet's Add Analyses View for when the Worksheet # Template being used has a Method assigned ("bika_setup_catalog", "method_available_uids", "", "KeywordIndex"), - ("bika_setup_catalog", "getBlank", "", "FieldIndex"), ("bika_setup_catalog", "getCalculationTitle", "", "FieldIndex"), ("bika_setup_catalog", "getCalculationUID", "", "FieldIndex"), ("bika_setup_catalog", "getCalibrationExpiryDate", "", "FieldIndex"), @@ -256,7 +256,6 @@ ("bika_setup_catalog", "getInstrumentType"), ("bika_setup_catalog", "getInstrumentTypeName"), ("bika_setup_catalog", "getInstrumentLocationName"), - ("bika_setup_catalog", "getBlank"), ("bika_setup_catalog", "getCalculationTitle"), ("bika_setup_catalog", "getCalculationUID"), ("bika_setup_catalog", "getCalibrationExpiryDate"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 876b61f863..e46c490fde 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -69,6 +69,10 @@ # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getAnalyst"), + # getBlank index is not used in setup_catalog, but in bika_catalog, where + # is used in AddControl and AddBlank views (Worksheet) + # https://github.com/senaite/senaite.core/pull/1484 + ("bika_setup_catalog", "getBlank"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -99,6 +103,10 @@ # Not used anywhere # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getAccredited"), + + # Not used anywhere + # https://github.com/senaite/senaite.core/pull/1484 + ("bika_setup_catalog", "getBlank"), ] From 8a84b3b1f82bf9269ff39c114b76e2a09d71c525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 23:16:19 +0100 Subject: [PATCH 36/96] Remove index and metadata: getDuplicateVariation --- bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 9 +++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 2e32b1e642..69dd359f8f 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -179,7 +179,6 @@ ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), ("bika_setup_catalog", "getDepartmentTitle", "", "FieldIndex"), ("bika_setup_catalog", "getDocumentID", "", "FieldIndex"), - ("bika_setup_catalog", "getDuplicateVariation", "", "FieldIndex"), ("bika_setup_catalog", "getFormula", "", "FieldIndex"), ("bika_setup_catalog", "getFullname", "", "FieldIndex"), ("bika_setup_catalog", "getHazardous", "", "FieldIndex"), @@ -263,7 +262,6 @@ ("bika_setup_catalog", "getCategoryUID"), ("bika_setup_catalog", "getClientUID"), ("bika_setup_catalog", "getDepartmentTitle"), - ("bika_setup_catalog", "getDuplicateVariation"), ("bika_setup_catalog", "getFormula"), ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getHazardous"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index e46c490fde..9a74902d72 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -74,6 +74,11 @@ # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getBlank"), + # Not used anywhere + # https://github.com/senaite/senaite.core/pull/1484 + ("bika_setup_catalog", "getDuplicateVariation"), + + # REPLACEMENTS (indexes to be removed because of a replacement) # getSampleTypeUID --> sampletype_uid (FieldIndex --> KeywordIndex) @@ -107,6 +112,10 @@ # Not used anywhere # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getBlank"), + + # Not used anywhere + # https://github.com/senaite/senaite.core/pull/1484 + ("bika_setup_catalog", "getDuplicateVariation"), ] From 7cf7e7cc162e68274bb9614809356246c82b0456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 23:19:47 +0100 Subject: [PATCH 37/96] Remove getFormula index and metadata from setup_catalog --- bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 5 ++--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 69dd359f8f..f7a4430b79 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -179,7 +179,6 @@ ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), ("bika_setup_catalog", "getDepartmentTitle", "", "FieldIndex"), ("bika_setup_catalog", "getDocumentID", "", "FieldIndex"), - ("bika_setup_catalog", "getFormula", "", "FieldIndex"), ("bika_setup_catalog", "getFullname", "", "FieldIndex"), ("bika_setup_catalog", "getHazardous", "", "FieldIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), @@ -262,7 +261,6 @@ ("bika_setup_catalog", "getCategoryUID"), ("bika_setup_catalog", "getClientUID"), ("bika_setup_catalog", "getDepartmentTitle"), - ("bika_setup_catalog", "getFormula"), ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getHazardous"), ("bika_setup_catalog", "getInstrumentTitle"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 9a74902d72..b5d73c69ba 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -77,6 +77,7 @@ # Not used anywhere # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getDuplicateVariation"), + ("bika_setup_catalog", "getFormula"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -112,10 +113,8 @@ # Not used anywhere # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getBlank"), - - # Not used anywhere - # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getDuplicateVariation"), + ("bika_setup_catalog", "getFormula"), ] From 3df7ca4ff8a98d06f5057e93d05ddee40743e339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 23:21:43 +0100 Subject: [PATCH 38/96] Removal of getDocumentID index and metadata from setup_catalog --- bika/lims/setuphandlers.py | 1 - bika/lims/upgrade/v01_03_003.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index f7a4430b79..6f94fa5e8a 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -178,7 +178,6 @@ ("bika_setup_catalog", "getCategoryUID", "", "FieldIndex"), ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), ("bika_setup_catalog", "getDepartmentTitle", "", "FieldIndex"), - ("bika_setup_catalog", "getDocumentID", "", "FieldIndex"), ("bika_setup_catalog", "getFullname", "", "FieldIndex"), ("bika_setup_catalog", "getHazardous", "", "FieldIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index b5d73c69ba..8d334af73d 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -76,6 +76,7 @@ # Not used anywhere # https://github.com/senaite/senaite.core/pull/1484 + ("bika_setup_catalog", "getDocumentID"), ("bika_setup_catalog", "getDuplicateVariation"), ("bika_setup_catalog", "getFormula"), From 9bd34dcd52479e3421c7eb6bf4c1c97a61208e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 23:26:12 +0100 Subject: [PATCH 39/96] Remove getInstrumentLocationName index and metadata from setup_catalog --- bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 6f94fa5e8a..d23f156c48 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -181,7 +181,6 @@ ("bika_setup_catalog", "getFullname", "", "FieldIndex"), ("bika_setup_catalog", "getHazardous", "", "FieldIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), - ("bika_setup_catalog", "getInstrumentLocationName", "", "FieldIndex"), ("bika_setup_catalog", "getInstrumentTitle", "", "FieldIndex"), ("bika_setup_catalog", "getInstrumentType", "", "FieldIndex"), ("bika_setup_catalog", "getInstrumentTypeName", "", "FieldIndex"), @@ -252,7 +251,6 @@ ("bika_setup_catalog", "review_state"), ("bika_setup_catalog", "getInstrumentType"), ("bika_setup_catalog", "getInstrumentTypeName"), - ("bika_setup_catalog", "getInstrumentLocationName"), ("bika_setup_catalog", "getCalculationTitle"), ("bika_setup_catalog", "getCalculationUID"), ("bika_setup_catalog", "getCalibrationExpiryDate"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 8d334af73d..3f82f82dd7 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -79,6 +79,7 @@ ("bika_setup_catalog", "getDocumentID"), ("bika_setup_catalog", "getDuplicateVariation"), ("bika_setup_catalog", "getFormula"), + ("bika_setup_catalog", "getInstrumentLocationName"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -116,6 +117,7 @@ ("bika_setup_catalog", "getBlank"), ("bika_setup_catalog", "getDuplicateVariation"), ("bika_setup_catalog", "getFormula"), + ("bika_setup_catalog", "getInstrumentLocationName"), ] From b7c0966e811bf21afb0906b6a9031313ccc1d7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Thu, 28 Nov 2019 23:40:25 +0100 Subject: [PATCH 40/96] Cleanup getInstrumentTitle from setup_catalog --- bika/lims/catalog/indexers/bikasetup.py | 10 ++++++++++ bika/lims/catalog/indexers/configure.zcml | 3 +++ bika/lims/content/abstractbaseanalysis.py | 8 -------- bika/lims/content/worksheet.py | 11 ----------- bika/lims/content/worksheettemplate.py | 13 +++---------- bika/lims/controlpanel/bika_worksheettemplates.py | 2 +- bika/lims/interfaces/__init__.py | 3 +++ bika/lims/setuphandlers.py | 4 ++-- bika/lims/upgrade/v01_03_003.py | 9 +++++++++ 9 files changed, 31 insertions(+), 32 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index fa98ce088a..c94ab2d113 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -20,9 +20,11 @@ from plone.indexer import indexer +from bika.lims import api from bika.lims.interfaces import IAnalysisService from bika.lims.interfaces import IBikaSetupCatalog from bika.lims.interfaces import ISampleTypeAwareMixin +from bika.lims.interfaces import IWorksheetTemplate @indexer(ISampleTypeAwareMixin, IBikaSetupCatalog) @@ -50,3 +52,11 @@ def method_available_uids(instance): a None value. This allows searches for `MissingValue` entries too. """ return instance.getAvailableMethodUIDs() or (None, ) + + +@indexer(IWorksheetTemplate, IBikaSetupCatalog) +def instrument_title(instance): + """Returns the title of the instrument assigned to the instance + """ + instrument = instance.getInstrument() + return instrument and api.get_title(instrument) or "" diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index b3a764a586..b616fc1a1c 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -35,6 +35,9 @@ Analyses View for when the Worksheet Template being has a Method assigned --> + + + diff --git a/bika/lims/content/abstractbaseanalysis.py b/bika/lims/content/abstractbaseanalysis.py index 76df20613f..ecc2d95e23 100644 --- a/bika/lims/content/abstractbaseanalysis.py +++ b/bika/lims/content/abstractbaseanalysis.py @@ -967,14 +967,6 @@ def getMethodURL(self): if method: return method.absolute_url_path() - @security.public - def getInstrumentTitle(self): - """Used to populate catalog values - """ - instrument = self.getInstrument() - if instrument: - return instrument.Title() - @security.public def getInstrument(self): """Returns the assigned instrument diff --git a/bika/lims/content/worksheet.py b/bika/lims/content/worksheet.py index 2e2da5b9e0..b606cbb83e 100644 --- a/bika/lims/content/worksheet.py +++ b/bika/lims/content/worksheet.py @@ -1116,17 +1116,6 @@ def applyWorksheetTemplate(self, wst): if method: self.setMethod(method, True) - def getInstrumentTitle(self): - """ - Returns the instrument title - :returns: instrument's title - :rtype: string - """ - instrument = self.getInstrument() - if instrument: - return instrument.Title() - return '' - def getWorksheetTemplateUID(self): """ Returns the template's UID assigned to this worksheet diff --git a/bika/lims/content/worksheettemplate.py b/bika/lims/content/worksheettemplate.py index ff1223155a..e3ba563c01 100644 --- a/bika/lims/content/worksheettemplate.py +++ b/bika/lims/content/worksheettemplate.py @@ -44,6 +44,8 @@ from bika.lims.interfaces import IDeactivable from zope.interface import implements +from bika.lims.interfaces import IWorksheetTemplate + schema = BikaSchema.copy() + Schema(( RecordsField( "Layout", @@ -159,7 +161,7 @@ class WorksheetTemplate(BaseContent): """Worksheet Templates """ - implements(IDeactivable) + implements(IWorksheetTemplate, IDeactivable) security = ClassSecurityInfo() displayContentsTab = False schema = schema @@ -169,15 +171,6 @@ def _renameAfterCreation(self, check_auto_id=False): from bika.lims.idserver import renameAfterCreation renameAfterCreation(self) - @security.public - def getInstrumentTitle(self): - """Return the instrument title - """ - instrument = self.getInstrument() - if not instrument: - return "" - return api.get_title(instrument) - @security.public def getAnalysisTypes(self): """Return Analysis type displaylist diff --git a/bika/lims/controlpanel/bika_worksheettemplates.py b/bika/lims/controlpanel/bika_worksheettemplates.py index b19b00a7a7..369ffad314 100644 --- a/bika/lims/controlpanel/bika_worksheettemplates.py +++ b/bika/lims/controlpanel/bika_worksheettemplates.py @@ -82,7 +82,7 @@ def __init__(self, context, request): "toggle": True}), ("Instrument", { "title": _("Instrument"), - "index": "getInstrumentTitle", + "index": "instrument_title", "toggle": True, }), )) diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index b74fc273d7..0cec362d76 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -539,6 +539,9 @@ class IWorksheetTemplates(Interface): """Marker interface for Worksheet Templates """ +class IWorksheetTemplate(Interface): + """Marker interface for Worksheet Template + """ class IBikaCatalog(Interface): """Marker interface for bika_catalog diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index d23f156c48..0f76584180 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -181,7 +181,8 @@ ("bika_setup_catalog", "getFullname", "", "FieldIndex"), ("bika_setup_catalog", "getHazardous", "", "FieldIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), - ("bika_setup_catalog", "getInstrumentTitle", "", "FieldIndex"), + # Sorting of listings: Worksheet Templates + ("bika_setup_catalog", "instrument_title", "", "FieldIndex"), ("bika_setup_catalog", "getInstrumentType", "", "FieldIndex"), ("bika_setup_catalog", "getInstrumentTypeName", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), @@ -260,7 +261,6 @@ ("bika_setup_catalog", "getDepartmentTitle"), ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getHazardous"), - ("bika_setup_catalog", "getInstrumentTitle"), ("bika_setup_catalog", "getKeyword"), ("bika_setup_catalog", "getManagerName"), ("bika_setup_catalog", "getManagerPhone"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 3f82f82dd7..07b988ccc6 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -40,6 +40,11 @@ # Worksheet Template being used has a Method assigned. # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "method_available_uids", "KeywordIndex"), + + # Replaces getInstrumentTitle + # Used for sorting Worksheet Templates listing by Instrument + # https://github.com/senaite/senaite.core/pull/1481 + ("bika_setup_catalog", "instrument_title", "FieldIndex") ] INDEXES_TO_REMOVE = [ @@ -91,6 +96,9 @@ # getAvailableMethodUIDs --> method_available_uids # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getAvailableMethodUIDs"), + + # getInstrumentTitle --> instrument_title + ("bika_setup_catalog", "getInstrumentTitle"), ] METADATA_TO_REMOVE = [ @@ -118,6 +126,7 @@ ("bika_setup_catalog", "getDuplicateVariation"), ("bika_setup_catalog", "getFormula"), ("bika_setup_catalog", "getInstrumentLocationName"), + ("bika_setup_catalog", "getInstrumentTitle"), ] From 4e7c0d213901cd7ed49ad6573274372786fde56f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 00:05:43 +0100 Subject: [PATCH 41/96] Cleanup getPrice index and metadata from setup_catalog --- bika/lims/catalog/indexers/bikasetup.py | 8 ++++++++ bika/lims/catalog/indexers/configure.zcml | 2 ++ bika/lims/controlpanel/bika_labproducts.py | 2 +- bika/lims/interfaces/__init__.py | 3 +++ bika/lims/setuphandlers.py | 4 ++-- bika/lims/upgrade/v01_03_003.py | 11 ++++++++++- 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index c94ab2d113..2ee5fc3e57 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -23,6 +23,7 @@ from bika.lims import api from bika.lims.interfaces import IAnalysisService from bika.lims.interfaces import IBikaSetupCatalog +from bika.lims.interfaces import ILabProduct from bika.lims.interfaces import ISampleTypeAwareMixin from bika.lims.interfaces import IWorksheetTemplate @@ -60,3 +61,10 @@ def instrument_title(instance): """ instrument = instance.getInstrument() return instrument and api.get_title(instrument) or "" + + +@indexer(ILabProduct, IBikaSetupCatalog) +def price(instance): + """Returns the price of the instance + """ + return instance.getPrice() diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index b616fc1a1c..63396209b1 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -38,6 +38,8 @@ + + diff --git a/bika/lims/controlpanel/bika_labproducts.py b/bika/lims/controlpanel/bika_labproducts.py index a5e7941a69..03145a7d8e 100644 --- a/bika/lims/controlpanel/bika_labproducts.py +++ b/bika/lims/controlpanel/bika_labproducts.py @@ -59,7 +59,7 @@ def __init__(self, context, request): 'index': 'getUnit', 'toggle': True}, 'Price': {'title': _('Price'), - 'index': 'getPrice', + 'index': 'price', 'toggle': True}, 'VATAmount': {'title': _('VAT Amount'), 'index': 'getVATAmount', diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index 0cec362d76..2dc9a7770b 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -454,6 +454,9 @@ class ILabProducts(Interface): """Marker interface for Lab Products """ +class ILabProduct(Interface): + """Marker interface for a LabProduct + """ class ISamplePoint(Interface): """Marker interface for a Sample Point diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 0f76584180..87f951d681 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -194,7 +194,8 @@ ("bika_setup_catalog", "getModel", "", "FieldIndex"), ("bika_setup_catalog", "getName", "", "FieldIndex"), ("bika_setup_catalog", "getPointOfCapture", "", "FieldIndex"), - ("bika_setup_catalog", "getPrice", "", "FieldIndex"), + # Sorting of listings: LabProducts + ("bika_setup_catalog", "price", "", "FieldIndex"), ("bika_setup_catalog", "getSamplePointTitle", "", "KeywordIndex"), ("bika_setup_catalog", "getSamplePointUID", "", "FieldIndex"), # Sorting of listings: Sample Points, Specifications @@ -269,7 +270,6 @@ ("bika_setup_catalog", "getModel"), ("bika_setup_catalog", "getName"), ("bika_setup_catalog", "getPointOfCapture"), - ("bika_setup_catalog", "getPrice"), ("bika_setup_catalog", "getSamplePointTitle"), ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getServiceUID"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 07b988ccc6..b11ccc0d11 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -44,7 +44,12 @@ # Replaces getInstrumentTitle # Used for sorting Worksheet Templates listing by Instrument # https://github.com/senaite/senaite.core/pull/1481 - ("bika_setup_catalog", "instrument_title", "FieldIndex") + ("bika_setup_catalog", "instrument_title", "FieldIndex"), + + # Replaces getPrice + # Used for sorting LabProducts listing + # https://github.com/senaite/senaite.core/pull/1481 + ("bika_setup_catalog", "price", "FieldIndex"), ] INDEXES_TO_REMOVE = [ @@ -99,6 +104,9 @@ # getInstrumentTitle --> instrument_title ("bika_setup_catalog", "getInstrumentTitle"), + + # getPrice --> price + ("bika_setup_catalog", "getPrice"), ] METADATA_TO_REMOVE = [ @@ -127,6 +135,7 @@ ("bika_setup_catalog", "getFormula"), ("bika_setup_catalog", "getInstrumentLocationName"), ("bika_setup_catalog", "getInstrumentTitle"), + ("bika_setup_catalog", "getPrice"), ] From 14b91c693719e7b2a257a685966740513fcc4958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 00:16:26 +0100 Subject: [PATCH 42/96] getTotalPrice --> price_total --- bika/lims/catalog/indexers/bikasetup.py | 7 +++++++ bika/lims/catalog/indexers/configure.zcml | 1 + bika/lims/controlpanel/bika_labproducts.py | 2 +- bika/lims/setuphandlers.py | 4 ++-- bika/lims/upgrade/v01_03_003.py | 4 ++++ 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 2ee5fc3e57..92450827b4 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -68,3 +68,10 @@ def price(instance): """Returns the price of the instance """ return instance.getPrice() + + +@indexer(ILabProduct, IBikaSetupCatalog) +def price_total(instance): + """Returns the total price of the instance + """ + return instance.getTotalPrice() diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 63396209b1..c661a13149 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -40,6 +40,7 @@ + diff --git a/bika/lims/controlpanel/bika_labproducts.py b/bika/lims/controlpanel/bika_labproducts.py index 03145a7d8e..c90aa0e451 100644 --- a/bika/lims/controlpanel/bika_labproducts.py +++ b/bika/lims/controlpanel/bika_labproducts.py @@ -65,7 +65,7 @@ def __init__(self, context, request): 'index': 'getVATAmount', 'toggle': True}, 'TotalPrice': {'title': _('Total Price'), - 'index': 'getTotalPrice', + 'index': 'price_total', 'toggle': True}, } self.review_states = [ diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 87f951d681..4f20965e4e 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -196,6 +196,8 @@ ("bika_setup_catalog", "getPointOfCapture", "", "FieldIndex"), # Sorting of listings: LabProducts ("bika_setup_catalog", "price", "", "FieldIndex"), + # Sorting of listings: LabProducts + ("bika_setup_catalog", "price_total", "", "FieldIndex"), ("bika_setup_catalog", "getSamplePointTitle", "", "KeywordIndex"), ("bika_setup_catalog", "getSamplePointUID", "", "FieldIndex"), # Sorting of listings: Sample Points, Specifications @@ -204,7 +206,6 @@ ("bika_setup_catalog", "sampletype_uids", "", "KeywordIndex"), ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), - ("bika_setup_catalog", "getTotalPrice", "", "FieldIndex"), ("bika_setup_catalog", "getUnit", "", "FieldIndex"), ("bika_setup_catalog", "getVATAmount", "getVATAmount", "FieldIndex"), ("bika_setup_catalog", "getVolume", "", "FieldIndex"), @@ -273,7 +274,6 @@ ("bika_setup_catalog", "getSamplePointTitle"), ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getServiceUID"), - ("bika_setup_catalog", "getTotalPrice"), ("bika_setup_catalog", "getUnit"), ("bika_setup_catalog", "getVATAmount"), ("bika_setup_catalog", "getVolume"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index b11ccc0d11..f031971190 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -50,6 +50,7 @@ # Used for sorting LabProducts listing # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "price", "FieldIndex"), + ("bika_setup_catalog", "price_total", "FieldIndex"), ] INDEXES_TO_REMOVE = [ @@ -107,6 +108,8 @@ # getPrice --> price ("bika_setup_catalog", "getPrice"), + # getTotalPrice --> price_total + ("bika_setup_catalog", "getTotalPrice"), ] METADATA_TO_REMOVE = [ @@ -136,6 +139,7 @@ ("bika_setup_catalog", "getInstrumentLocationName"), ("bika_setup_catalog", "getInstrumentTitle"), ("bika_setup_catalog", "getPrice"), + ("bika_setup_catalog", "getTotalPrice"), ] From 05c979561251c58bd27127ce8dc2c3e13ba945be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 00:21:05 +0100 Subject: [PATCH 43/96] getVolume --> volume --- bika/lims/catalog/indexers/bikasetup.py | 7 +++++++ bika/lims/catalog/indexers/configure.zcml | 4 +++- bika/lims/controlpanel/bika_labproducts.py | 2 +- bika/lims/setuphandlers.py | 4 ++-- bika/lims/upgrade/v01_03_003.py | 6 +++++- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 92450827b4..c479395635 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -75,3 +75,10 @@ def price_total(instance): """Returns the total price of the instance """ return instance.getTotalPrice() + + +@indexer(ILabProduct, IBikaSetupCatalog) +def volume(instance): + """Returns the total price of the instance + """ + return instance.getVolume() diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index c661a13149..b6c0e52c71 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -38,9 +38,11 @@ - + + + diff --git a/bika/lims/controlpanel/bika_labproducts.py b/bika/lims/controlpanel/bika_labproducts.py index c90aa0e451..59280da102 100644 --- a/bika/lims/controlpanel/bika_labproducts.py +++ b/bika/lims/controlpanel/bika_labproducts.py @@ -53,7 +53,7 @@ def __init__(self, context, request): 'index': 'sortable_title', 'toggle': True}, 'Volume': {'title': _('Volume'), - 'index': 'getVolume', + 'index': 'volume', 'toggle': True}, 'Unit': {'title': _('Unit'), 'index': 'getUnit', diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 4f20965e4e..3f4ac92284 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -208,7 +208,8 @@ ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), ("bika_setup_catalog", "getUnit", "", "FieldIndex"), ("bika_setup_catalog", "getVATAmount", "getVATAmount", "FieldIndex"), - ("bika_setup_catalog", "getVolume", "", "FieldIndex"), + # Sorting of listings: LabProducts + ("bika_setup_catalog", "volume", "", "FieldIndex"), ("bika_setup_catalog", "id", "getId", "FieldIndex"), ("bika_setup_catalog", "is_active", "", "BooleanIndex"), ("bika_setup_catalog", "path", "getPhysicalPath", "ExtendedPathIndex"), @@ -276,7 +277,6 @@ ("bika_setup_catalog", "getServiceUID"), ("bika_setup_catalog", "getUnit"), ("bika_setup_catalog", "getVATAmount"), - ("bika_setup_catalog", "getVolume"), ("portal_catalog", "Analyst"), ) diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index f031971190..9e74075a99 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -46,11 +46,12 @@ # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "instrument_title", "FieldIndex"), - # Replaces getPrice + # Replaces getPrice, getTotalPrice, getVolume # Used for sorting LabProducts listing # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "price", "FieldIndex"), ("bika_setup_catalog", "price_total", "FieldIndex"), + ("bika_setup_catalog", "volume", "FieldIndex"), ] INDEXES_TO_REMOVE = [ @@ -110,6 +111,8 @@ ("bika_setup_catalog", "getPrice"), # getTotalPrice --> price_total ("bika_setup_catalog", "getTotalPrice"), + # getVolume --> volume + ("bika_setup_catalog", "getVolume"), ] METADATA_TO_REMOVE = [ @@ -140,6 +143,7 @@ ("bika_setup_catalog", "getInstrumentTitle"), ("bika_setup_catalog", "getPrice"), ("bika_setup_catalog", "getTotalPrice"), + ("bika_setup_catalog", "getVolume"), ] From 11fe31e500f220357941d75393a974643ac789d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 10:22:08 +0100 Subject: [PATCH 44/96] Added IHavePrice interface --- bika/lims/catalog/indexers/bikasetup.py | 7 ++++--- bika/lims/content/labproduct.py | 15 +++++++++------ bika/lims/interfaces/__init__.py | 13 +++++++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index a06b9a4011..bbc72597c9 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -23,6 +23,7 @@ from bika.lims import api from bika.lims.interfaces import IAnalysisService from bika.lims.interfaces import IBikaSetupCatalog +from bika.lims.interfaces import IHavePrice from bika.lims.interfaces import ILabProduct from bika.lims.interfaces import ISampleTypeAwareMixin from bika.lims.interfaces import IWorksheetTemplate @@ -63,14 +64,14 @@ def instrument_title(instance): return instrument and api.get_title(instrument) or "" -@indexer(ILabProduct, IBikaSetupCatalog) +@indexer(IHavePrice, IBikaSetupCatalog) def price(instance): """Returns the price of the instance """ return instance.getPrice() -@indexer(ILabProduct, IBikaSetupCatalog) +@indexer(IHavePrice, IBikaSetupCatalog) def price_total(instance): """Returns the total price of the instance """ @@ -79,7 +80,7 @@ def price_total(instance): @indexer(ILabProduct, IBikaSetupCatalog) def volume(instance): - """Returns the total price of the instance + """Returns the volume of the instance """ return instance.getVolume() diff --git a/bika/lims/content/labproduct.py b/bika/lims/content/labproduct.py index 499aa4b650..e1b04077cc 100644 --- a/bika/lims/content/labproduct.py +++ b/bika/lims/content/labproduct.py @@ -18,16 +18,17 @@ # Copyright 2018-2019 by it's authors. # Some rights reserved, see README and LICENSE. +from decimal import Decimal + from AccessControl import ClassSecurityInfo from Products.Archetypes.public import * -from Products.CMFCore.permissions import View, ModifyPortalContent +from zope.interface import implements + +from bika.lims import bikaMessageFactory as _ from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from decimal import Decimal -from bika.lims import bikaMessageFactory as _ from bika.lims.interfaces import IDeactivable -from bika.lims.utils import t -from zope.interface import implements +from bika.lims.interfaces import IHavePrice schema = BikaSchema.copy() + Schema(( StringField('Volume', @@ -72,8 +73,9 @@ schema['description'].schemata = 'default' schema['description'].widget.visible = True + class LabProduct(BaseContent): - implements(IDeactivable) + implements(IDeactivable, IHavePrice) security = ClassSecurityInfo() displayContentsTab = False schema = schema @@ -110,4 +112,5 @@ def getVATAmount(self): vatamount = Decimal('0.00') return vatamount.quantize(Decimal('0.00')) + registerType(LabProduct, PROJECTNAME) diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index 2dc9a7770b..fe02607c4a 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -1023,3 +1023,16 @@ def getSampleTypeUID(self): def getSampleTypeTitle(self): """Returns the title or a comma separated list of sample type titles """ + + +class IHavePrice(Interface): + """Marker interface for objects that have a Price + """ + + def getPrice(self): + """Returns the price of the instance + """ + + def getTotalPrice(self): + """Returns the total price of the instance + """ From 8eb6eba356532e33a057b5b0798a97e6c6ff8c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 10:30:12 +0100 Subject: [PATCH 45/96] Cleanup getInstrumentTypeName from setup_catalog --- bika/lims/catalog/indexers/bikasetup.py | 7 +++++++ bika/lims/catalog/indexers/configure.zcml | 2 ++ bika/lims/controlpanel/bika_instruments.py | 2 +- bika/lims/setuphandlers.py | 4 ++-- bika/lims/upgrade/v01_03_003.py | 9 +++++++++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index bbc72597c9..c412270f19 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -24,6 +24,7 @@ from bika.lims.interfaces import IAnalysisService from bika.lims.interfaces import IBikaSetupCatalog from bika.lims.interfaces import IHavePrice +from bika.lims.interfaces import IInstrument from bika.lims.interfaces import ILabProduct from bika.lims.interfaces import ISampleTypeAwareMixin from bika.lims.interfaces import IWorksheetTemplate @@ -84,3 +85,9 @@ def volume(instance): """ return instance.getVolume() + +@indexer(IInstrument, IBikaSetupCatalog) +def instrumenttype_name(instance): + """Returns the name of the Instrument Type the instance is assigned to + """ + return instance.getInstrumentTypeName() diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index b6c0e52c71..76d96248db 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -43,6 +43,8 @@ + + diff --git a/bika/lims/controlpanel/bika_instruments.py b/bika/lims/controlpanel/bika_instruments.py index 25b4d3ad1e..cc7952fa39 100644 --- a/bika/lims/controlpanel/bika_instruments.py +++ b/bika/lims/controlpanel/bika_instruments.py @@ -72,7 +72,7 @@ def __init__(self, context, request): "index": "sortable_title"}), ("Type", { "title": _("Type"), - "index": "getInstrumentTypeName", + "index": "instrumenttype_name", "toggle": True, "sortable": True}), ("Brand", { diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 3f4ac92284..d8c31558b7 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -184,7 +184,8 @@ # Sorting of listings: Worksheet Templates ("bika_setup_catalog", "instrument_title", "", "FieldIndex"), ("bika_setup_catalog", "getInstrumentType", "", "FieldIndex"), - ("bika_setup_catalog", "getInstrumentTypeName", "", "FieldIndex"), + # Sorting of listings: Instruments + ("bika_setup_catalog", "instrumenttype_name", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), ("bika_setup_catalog", "getManagerEmail", "", "FieldIndex"), ("bika_setup_catalog", "getManagerName", "", "FieldIndex"), @@ -254,7 +255,6 @@ ("bika_setup_catalog", "description"), ("bika_setup_catalog", "review_state"), ("bika_setup_catalog", "getInstrumentType"), - ("bika_setup_catalog", "getInstrumentTypeName"), ("bika_setup_catalog", "getCalculationTitle"), ("bika_setup_catalog", "getCalculationUID"), ("bika_setup_catalog", "getCalibrationExpiryDate"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 9e74075a99..96ca63ad32 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -52,6 +52,9 @@ ("bika_setup_catalog", "price", "FieldIndex"), ("bika_setup_catalog", "price_total", "FieldIndex"), ("bika_setup_catalog", "volume", "FieldIndex"), + + # Replaces getInstrumentTypeName + ("bika_setup_catalog", "instrumenttype_name", "FieldIndex"), ] INDEXES_TO_REMOVE = [ @@ -109,10 +112,15 @@ # getPrice --> price ("bika_setup_catalog", "getPrice"), + # getTotalPrice --> price_total ("bika_setup_catalog", "getTotalPrice"), + # getVolume --> volume ("bika_setup_catalog", "getVolume"), + + # getInstrumentTypeName --> instrumenttype_name + ("bika_setup_catalog", "getInstrumentTypeName"), ] METADATA_TO_REMOVE = [ @@ -144,6 +152,7 @@ ("bika_setup_catalog", "getPrice"), ("bika_setup_catalog", "getTotalPrice"), ("bika_setup_catalog", "getVolume"), + ("bika_setup_catalog", "getInstrumentTypeName"), ] From 065a7ae05f2eb0fd205c2b14c1bc46ffff32c509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 10:32:12 +0100 Subject: [PATCH 46/96] Remove getInstrumentType index and metadata from setup_catalog --- bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index d8c31558b7..016a88e181 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -183,7 +183,6 @@ ("bika_setup_catalog", "getId", "", "FieldIndex"), # Sorting of listings: Worksheet Templates ("bika_setup_catalog", "instrument_title", "", "FieldIndex"), - ("bika_setup_catalog", "getInstrumentType", "", "FieldIndex"), # Sorting of listings: Instruments ("bika_setup_catalog", "instrumenttype_name", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), @@ -254,7 +253,6 @@ ("bika_setup_catalog", "sortable_title"), ("bika_setup_catalog", "description"), ("bika_setup_catalog", "review_state"), - ("bika_setup_catalog", "getInstrumentType"), ("bika_setup_catalog", "getCalculationTitle"), ("bika_setup_catalog", "getCalculationUID"), ("bika_setup_catalog", "getCalibrationExpiryDate"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 96ca63ad32..534a9ced72 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -95,6 +95,7 @@ ("bika_setup_catalog", "getDuplicateVariation"), ("bika_setup_catalog", "getFormula"), ("bika_setup_catalog", "getInstrumentLocationName"), + ("bika_setup_catalog", "getInstrumentType"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -153,6 +154,7 @@ ("bika_setup_catalog", "getTotalPrice"), ("bika_setup_catalog", "getVolume"), ("bika_setup_catalog", "getInstrumentTypeName"), + ("bika_setup_catalog", "getInstrumentType"), ] From e6bf75cfc45f2e9584ce15e3907692d5b6cd0f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 10:42:51 +0100 Subject: [PATCH 47/96] Remove getHazardous and getManagerEmail indexes+metadata --- bika/lims/controlpanel/bika_departments.py | 2 -- bika/lims/setuphandlers.py | 4 ---- bika/lims/upgrade/v01_03_003.py | 4 ++++ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/bika/lims/controlpanel/bika_departments.py b/bika/lims/controlpanel/bika_departments.py index 3e51b5378e..91e63ae260 100644 --- a/bika/lims/controlpanel/bika_departments.py +++ b/bika/lims/controlpanel/bika_departments.py @@ -83,11 +83,9 @@ def __init__(self, context, request): "toggle": True}), ("ManagerPhone", { "title": _("Manager Phone"), - "index": "getManagerPhone", "toggle": True}), ("ManagerEmail", { "title": _("Manager Email"), - "index": "getManagerEmail", "toggle": True}), )) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 016a88e181..5302ca5161 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -179,14 +179,12 @@ ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), ("bika_setup_catalog", "getDepartmentTitle", "", "FieldIndex"), ("bika_setup_catalog", "getFullname", "", "FieldIndex"), - ("bika_setup_catalog", "getHazardous", "", "FieldIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), # Sorting of listings: Worksheet Templates ("bika_setup_catalog", "instrument_title", "", "FieldIndex"), # Sorting of listings: Instruments ("bika_setup_catalog", "instrumenttype_name", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), - ("bika_setup_catalog", "getManagerEmail", "", "FieldIndex"), ("bika_setup_catalog", "getManagerName", "", "FieldIndex"), ("bika_setup_catalog", "getManagerPhone", "", "FieldIndex"), ("bika_setup_catalog", "getMaxTimeAllowed", "", "FieldIndex"), @@ -261,11 +259,9 @@ ("bika_setup_catalog", "getClientUID"), ("bika_setup_catalog", "getDepartmentTitle"), ("bika_setup_catalog", "getFullname"), - ("bika_setup_catalog", "getHazardous"), ("bika_setup_catalog", "getKeyword"), ("bika_setup_catalog", "getManagerName"), ("bika_setup_catalog", "getManagerPhone"), - ("bika_setup_catalog", "getManagerEmail"), ("bika_setup_catalog", "getMaxTimeAllowed"), ("bika_setup_catalog", "getModel"), ("bika_setup_catalog", "getName"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 534a9ced72..39978f974b 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -96,6 +96,8 @@ ("bika_setup_catalog", "getFormula"), ("bika_setup_catalog", "getInstrumentLocationName"), ("bika_setup_catalog", "getInstrumentType"), + ("bika_setup_catalog", "getHazardous"), + ("bika_setup_catalog", "getManagerEmail"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -155,6 +157,8 @@ ("bika_setup_catalog", "getVolume"), ("bika_setup_catalog", "getInstrumentTypeName"), ("bika_setup_catalog", "getInstrumentType"), + ("bika_setup_catalog", "getHazardous"), + ("bika_setup_catalog", "getManagerEmail"), ] From 7ab583f0cabaee9a63c55ec245939ed01a6c0343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 10:44:14 +0100 Subject: [PATCH 48/96] Remove getManagerPhone index and metadata from setup_catalog --- bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 5302ca5161..cd884a76ce 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -186,7 +186,6 @@ ("bika_setup_catalog", "instrumenttype_name", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), ("bika_setup_catalog", "getManagerName", "", "FieldIndex"), - ("bika_setup_catalog", "getManagerPhone", "", "FieldIndex"), ("bika_setup_catalog", "getMaxTimeAllowed", "", "FieldIndex"), ("bika_setup_catalog", "getMethodID", "", "FieldIndex"), ("bika_setup_catalog", "getModel", "", "FieldIndex"), @@ -261,7 +260,6 @@ ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getKeyword"), ("bika_setup_catalog", "getManagerName"), - ("bika_setup_catalog", "getManagerPhone"), ("bika_setup_catalog", "getMaxTimeAllowed"), ("bika_setup_catalog", "getModel"), ("bika_setup_catalog", "getName"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 39978f974b..c990fcac13 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -98,6 +98,7 @@ ("bika_setup_catalog", "getInstrumentType"), ("bika_setup_catalog", "getHazardous"), ("bika_setup_catalog", "getManagerEmail"), + ("bika_setup_catalog", "getManagerPhone"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -159,6 +160,7 @@ ("bika_setup_catalog", "getInstrumentType"), ("bika_setup_catalog", "getHazardous"), ("bika_setup_catalog", "getManagerEmail"), + ("bika_setup_catalog", "getManagerPhone"), ] From 98a5eaf3a9aa90d58332b0e71ae190da8ba04ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 10:45:26 +0100 Subject: [PATCH 49/96] Remove getManagerName index and metadata from setup_catalog --- bika/lims/controlpanel/bika_departments.py | 1 - bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bika/lims/controlpanel/bika_departments.py b/bika/lims/controlpanel/bika_departments.py index 91e63ae260..1a156bca5c 100644 --- a/bika/lims/controlpanel/bika_departments.py +++ b/bika/lims/controlpanel/bika_departments.py @@ -79,7 +79,6 @@ def __init__(self, context, request): "toggle": True}), ("Manager", { "title": _("Manager"), - "index": "getManagerName", "toggle": True}), ("ManagerPhone", { "title": _("Manager Phone"), diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index cd884a76ce..1a7357eb9e 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -185,7 +185,6 @@ # Sorting of listings: Instruments ("bika_setup_catalog", "instrumenttype_name", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), - ("bika_setup_catalog", "getManagerName", "", "FieldIndex"), ("bika_setup_catalog", "getMaxTimeAllowed", "", "FieldIndex"), ("bika_setup_catalog", "getMethodID", "", "FieldIndex"), ("bika_setup_catalog", "getModel", "", "FieldIndex"), @@ -259,7 +258,6 @@ ("bika_setup_catalog", "getDepartmentTitle"), ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getKeyword"), - ("bika_setup_catalog", "getManagerName"), ("bika_setup_catalog", "getMaxTimeAllowed"), ("bika_setup_catalog", "getModel"), ("bika_setup_catalog", "getName"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index c990fcac13..e0409e4cef 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -99,6 +99,7 @@ ("bika_setup_catalog", "getHazardous"), ("bika_setup_catalog", "getManagerEmail"), ("bika_setup_catalog", "getManagerPhone"), + ("bika_setup_catalog", "getManagerName"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -161,6 +162,7 @@ ("bika_setup_catalog", "getHazardous"), ("bika_setup_catalog", "getManagerEmail"), ("bika_setup_catalog", "getManagerPhone"), + ("bika_setup_catalog", "getManagerName"), ] From c20d385b6fb0a95383365d4173c0d594dc073b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 10:46:42 +0100 Subject: [PATCH 50/96] Remove getMethodID index from setup_catalog --- bika/lims/setuphandlers.py | 1 - bika/lims/upgrade/v01_03_003.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 1a7357eb9e..c0efd40bea 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -186,7 +186,6 @@ ("bika_setup_catalog", "instrumenttype_name", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), ("bika_setup_catalog", "getMaxTimeAllowed", "", "FieldIndex"), - ("bika_setup_catalog", "getMethodID", "", "FieldIndex"), ("bika_setup_catalog", "getModel", "", "FieldIndex"), ("bika_setup_catalog", "getName", "", "FieldIndex"), ("bika_setup_catalog", "getPointOfCapture", "", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index e0409e4cef..08a2d7072f 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -100,6 +100,7 @@ ("bika_setup_catalog", "getManagerEmail"), ("bika_setup_catalog", "getManagerPhone"), ("bika_setup_catalog", "getManagerName"), + ("bika_setup_catalog", "getMethodID"), # REPLACEMENTS (indexes to be removed because of a replacement) From b80ad34e7f46382060bc80bb22f2856f8ca7e4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 10:47:49 +0100 Subject: [PATCH 51/96] Remove getMaxTimeAllowed index and metadata from setup_catalog --- bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index c0efd40bea..3e279e2d2d 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -185,7 +185,6 @@ # Sorting of listings: Instruments ("bika_setup_catalog", "instrumenttype_name", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), - ("bika_setup_catalog", "getMaxTimeAllowed", "", "FieldIndex"), ("bika_setup_catalog", "getModel", "", "FieldIndex"), ("bika_setup_catalog", "getName", "", "FieldIndex"), ("bika_setup_catalog", "getPointOfCapture", "", "FieldIndex"), @@ -257,7 +256,6 @@ ("bika_setup_catalog", "getDepartmentTitle"), ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getKeyword"), - ("bika_setup_catalog", "getMaxTimeAllowed"), ("bika_setup_catalog", "getModel"), ("bika_setup_catalog", "getName"), ("bika_setup_catalog", "getPointOfCapture"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 08a2d7072f..f74a193691 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -101,6 +101,7 @@ ("bika_setup_catalog", "getManagerPhone"), ("bika_setup_catalog", "getManagerName"), ("bika_setup_catalog", "getMethodID"), + ("bika_setup_catalog", "getMaxTimeAllowed"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -164,6 +165,7 @@ ("bika_setup_catalog", "getManagerEmail"), ("bika_setup_catalog", "getManagerPhone"), ("bika_setup_catalog", "getManagerName"), + ("bika_setup_catalog", "getMaxTimeAllowed"), ] From 8ba0749ef21c70a9e3baab78f6bb948ca8dd17aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 10:56:03 +0100 Subject: [PATCH 52/96] Remove getModel index and metadata from setup_catalog --- bika/lims/controlpanel/bika_instruments.py | 1 - bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bika/lims/controlpanel/bika_instruments.py b/bika/lims/controlpanel/bika_instruments.py index cc7952fa39..66f2e77bdc 100644 --- a/bika/lims/controlpanel/bika_instruments.py +++ b/bika/lims/controlpanel/bika_instruments.py @@ -81,7 +81,6 @@ def __init__(self, context, request): "toggle": True}), ("Model", { "title": _("Model"), - "index": "getModel", "toggle": True}), ("ExpiryDate", { "title": _("Expiry Date"), diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 3e279e2d2d..6d72a66525 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -185,7 +185,6 @@ # Sorting of listings: Instruments ("bika_setup_catalog", "instrumenttype_name", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), - ("bika_setup_catalog", "getModel", "", "FieldIndex"), ("bika_setup_catalog", "getName", "", "FieldIndex"), ("bika_setup_catalog", "getPointOfCapture", "", "FieldIndex"), # Sorting of listings: LabProducts @@ -256,7 +255,6 @@ ("bika_setup_catalog", "getDepartmentTitle"), ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getKeyword"), - ("bika_setup_catalog", "getModel"), ("bika_setup_catalog", "getName"), ("bika_setup_catalog", "getPointOfCapture"), ("bika_setup_catalog", "getSamplePointTitle"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index f74a193691..2b9e6d63d1 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -102,6 +102,7 @@ ("bika_setup_catalog", "getManagerName"), ("bika_setup_catalog", "getMethodID"), ("bika_setup_catalog", "getMaxTimeAllowed"), + ("bika_setup_catalog", "getModel"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -166,6 +167,7 @@ ("bika_setup_catalog", "getManagerPhone"), ("bika_setup_catalog", "getManagerName"), ("bika_setup_catalog", "getMaxTimeAllowed"), + ("bika_setup_catalog", "getModel"), ] From 3e73b0438ac1a88bb9aaf5cf97e65f3574bc8939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 11:11:02 +0100 Subject: [PATCH 53/96] Remove getCalculationTitle index and metadata from setup_catalog --- bika/lims/content/abstractanalysis.py | 8 -------- bika/lims/content/analysisservice.py | 8 -------- bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/bika/lims/content/abstractanalysis.py b/bika/lims/content/abstractanalysis.py index 6edd740e1d..279c9f0452 100644 --- a/bika/lims/content/abstractanalysis.py +++ b/bika/lims/content/abstractanalysis.py @@ -1128,14 +1128,6 @@ def getAttachmentUIDs(self): uids = [att.UID() for att in attachments] return uids - @security.public - def getCalculationTitle(self): - """Used to populate catalog values - """ - calculation = self.getCalculation() - if calculation: - return calculation.Title() - @security.public def getCalculationUID(self): """Used to populate catalog values diff --git a/bika/lims/content/analysisservice.py b/bika/lims/content/analysisservice.py index a928a38979..711f958918 100644 --- a/bika/lims/content/analysisservice.py +++ b/bika/lims/content/analysisservice.py @@ -429,14 +429,6 @@ def _renameAfterCreation(self, check_auto_id=False): return renameAfterCreation(self) - @security.public - def getCalculationTitle(self): - """Used to populate catalog values - """ - calculation = self.getCalculation() - if calculation: - return calculation.Title() - @security.public def getCalculation(self): """Returns the assigned calculation diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 6d72a66525..39971207a3 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -171,7 +171,6 @@ # Filter services in Worksheet's Add Analyses View for when the Worksheet # Template being used has a Method assigned ("bika_setup_catalog", "method_available_uids", "", "KeywordIndex"), - ("bika_setup_catalog", "getCalculationTitle", "", "FieldIndex"), ("bika_setup_catalog", "getCalculationUID", "", "FieldIndex"), ("bika_setup_catalog", "getCalibrationExpiryDate", "", "FieldIndex"), ("bika_setup_catalog", "getCategoryTitle", "", "FieldIndex"), @@ -246,7 +245,6 @@ ("bika_setup_catalog", "sortable_title"), ("bika_setup_catalog", "description"), ("bika_setup_catalog", "review_state"), - ("bika_setup_catalog", "getCalculationTitle"), ("bika_setup_catalog", "getCalculationUID"), ("bika_setup_catalog", "getCalibrationExpiryDate"), ("bika_setup_catalog", "getCategoryTitle"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 2b9e6d63d1..a244e0d56c 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -103,6 +103,7 @@ ("bika_setup_catalog", "getMethodID"), ("bika_setup_catalog", "getMaxTimeAllowed"), ("bika_setup_catalog", "getModel"), + ("bika_setup_catalog", "getCalculationTitle"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -168,6 +169,7 @@ ("bika_setup_catalog", "getManagerName"), ("bika_setup_catalog", "getMaxTimeAllowed"), ("bika_setup_catalog", "getModel"), + ("bika_setup_catalog", "getCalculationTitle"), ] From 42f72b6286625181e2e70dda7de78ac9979e0e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 11:25:09 +0100 Subject: [PATCH 54/96] Remove getCalculationUID index and metadata from setup_catalog --- bika/lims/setuphandlers.py | 4 ---- bika/lims/upgrade/v01_03_003.py | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 39971207a3..e911254881 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -171,8 +171,6 @@ # Filter services in Worksheet's Add Analyses View for when the Worksheet # Template being used has a Method assigned ("bika_setup_catalog", "method_available_uids", "", "KeywordIndex"), - ("bika_setup_catalog", "getCalculationUID", "", "FieldIndex"), - ("bika_setup_catalog", "getCalibrationExpiryDate", "", "FieldIndex"), ("bika_setup_catalog", "getCategoryTitle", "", "FieldIndex"), ("bika_setup_catalog", "getCategoryUID", "", "FieldIndex"), ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), @@ -245,8 +243,6 @@ ("bika_setup_catalog", "sortable_title"), ("bika_setup_catalog", "description"), ("bika_setup_catalog", "review_state"), - ("bika_setup_catalog", "getCalculationUID"), - ("bika_setup_catalog", "getCalibrationExpiryDate"), ("bika_setup_catalog", "getCategoryTitle"), ("bika_setup_catalog", "getCategoryUID"), ("bika_setup_catalog", "getClientUID"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index a244e0d56c..f319aa6e65 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -89,6 +89,9 @@ # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getBlank"), + # Only used in analyses listing, but from analysis_catalog + ("bika_setup_catalog", "getCalculationUID"), + # Not used anywhere # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getDocumentID"), @@ -104,6 +107,7 @@ ("bika_setup_catalog", "getMaxTimeAllowed"), ("bika_setup_catalog", "getModel"), ("bika_setup_catalog", "getCalculationTitle"), + ("bika_setup_catalog", "getCalibrationExpiryDate"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -170,6 +174,8 @@ ("bika_setup_catalog", "getMaxTimeAllowed"), ("bika_setup_catalog", "getModel"), ("bika_setup_catalog", "getCalculationTitle"), + ("bika_setup_catalog", "getCalculationUID"), + ("bika_setup_catalog", "getCalibrationExpiryDate"), ] From 71a81c8e78fdebdca40241e554272e1ed98f120f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 12:12:04 +0100 Subject: [PATCH 55/96] getDepartmentTitle --> department_title index --- bika/lims/catalog/indexers/bikasetup.py | 9 +++++++++ bika/lims/catalog/indexers/configure.zcml | 3 +++ bika/lims/content/abstractbaseanalysis.py | 8 -------- bika/lims/content/analysiscategory.py | 5 ----- bika/lims/controlpanel/bika_analysiscategories.py | 3 +-- bika/lims/setuphandlers.py | 4 ++-- bika/lims/upgrade/v01_03_003.py | 7 +++++++ 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index c412270f19..957e243f1b 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -21,6 +21,7 @@ from plone.indexer import indexer from bika.lims import api +from bika.lims.interfaces import IAnalysisCategory from bika.lims.interfaces import IAnalysisService from bika.lims.interfaces import IBikaSetupCatalog from bika.lims.interfaces import IHavePrice @@ -91,3 +92,11 @@ def instrumenttype_name(instance): """Returns the name of the Instrument Type the instance is assigned to """ return instance.getInstrumentTypeName() + + +@indexer(IAnalysisCategory, IBikaSetupCatalog) +def department_title(instance): + """Returns the title of the Department the instance is assigned to + """ + department = instance.getDepartment() + return department and api.get_title(department) or "" diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 76d96248db..836431e5bf 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -46,6 +46,9 @@ + + + diff --git a/bika/lims/content/abstractbaseanalysis.py b/bika/lims/content/abstractbaseanalysis.py index ecc2d95e23..78cbd7a811 100644 --- a/bika/lims/content/abstractbaseanalysis.py +++ b/bika/lims/content/abstractbaseanalysis.py @@ -1014,14 +1014,6 @@ def getCategoryUID(self): if category: return category.UID() - @security.public - def getDepartmentTitle(self): - """Used to populate catalog values - """ - department = self.getDepartment() - if department: - return department.Title() - @security.public def getMaxTimeAllowed(self): """Returns the maximum turnaround time for this analysis. If no TAT is diff --git a/bika/lims/content/analysiscategory.py b/bika/lims/content/analysiscategory.py index 89bc4d5be9..aacd325b19 100644 --- a/bika/lims/content/analysiscategory.py +++ b/bika/lims/content/analysiscategory.py @@ -92,11 +92,6 @@ def getDepartments(self): deps.append((d.UID, d.Title)) return DisplayList(deps) - def getDepartmentTitle(self): - field = self.Schema().getField('Department') - dept = field.get(self) - return dept.Title() if dept else '' - def workflow_script_deactivate(self): # A instance cannot be deactivated if it contains services pu = getToolByName(self, 'plone_utils') diff --git a/bika/lims/controlpanel/bika_analysiscategories.py b/bika/lims/controlpanel/bika_analysiscategories.py index ef64769555..14d8237e2d 100644 --- a/bika/lims/controlpanel/bika_analysiscategories.py +++ b/bika/lims/controlpanel/bika_analysiscategories.py @@ -80,8 +80,7 @@ def __init__(self, context, request): }), ("Department", { "title": _("Department"), - "index": "getDepartmentTitle", - "attr": "getDepartmentTitle", + "index": "department_title", }), ("SortKey", { "title": _("Sort Key"), diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index e911254881..33b9f1bb26 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -174,7 +174,8 @@ ("bika_setup_catalog", "getCategoryTitle", "", "FieldIndex"), ("bika_setup_catalog", "getCategoryUID", "", "FieldIndex"), ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), - ("bika_setup_catalog", "getDepartmentTitle", "", "FieldIndex"), + # Sorting of listings: Analysis Categories + ("bika_setup_catalog", "department_title", "", "FieldIndex"), ("bika_setup_catalog", "getFullname", "", "FieldIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), # Sorting of listings: Worksheet Templates @@ -246,7 +247,6 @@ ("bika_setup_catalog", "getCategoryTitle"), ("bika_setup_catalog", "getCategoryUID"), ("bika_setup_catalog", "getClientUID"), - ("bika_setup_catalog", "getDepartmentTitle"), ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getKeyword"), ("bika_setup_catalog", "getName"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index f319aa6e65..b78a49c0f3 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -55,6 +55,9 @@ # Replaces getInstrumentTypeName ("bika_setup_catalog", "instrumenttype_name", "FieldIndex"), + + # Replaces getDepartmentTitle + ("bika_setup_catalog", "department_title", "FieldIndex"), ] INDEXES_TO_REMOVE = [ @@ -134,6 +137,9 @@ # getInstrumentTypeName --> instrumenttype_name ("bika_setup_catalog", "getInstrumentTypeName"), + + # getDepartmentTitle --> department_title + ("bika_setup_catalog", "getDepartmentTitle"), ] METADATA_TO_REMOVE = [ @@ -176,6 +182,7 @@ ("bika_setup_catalog", "getCalculationTitle"), ("bika_setup_catalog", "getCalculationUID"), ("bika_setup_catalog", "getCalibrationExpiryDate"), + ("bika_setup_catalog", "getDepartmentTitle"), ] From d90acf7d40bc951fc4741e48386bed48b0fec92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 12:28:18 +0100 Subject: [PATCH 56/96] instrumenttype_name --> instrumenttype_title --- bika/lims/catalog/indexers/bikasetup.py | 7 +++--- bika/lims/catalog/indexers/configure.zcml | 2 +- bika/lims/content/instrument.py | 27 ++++------------------ bika/lims/controlpanel/bika_instruments.py | 2 +- bika/lims/setuphandlers.py | 2 +- bika/lims/upgrade/v01_03_003.py | 4 ++-- 6 files changed, 13 insertions(+), 31 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 957e243f1b..044bdee78f 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -88,10 +88,11 @@ def volume(instance): @indexer(IInstrument, IBikaSetupCatalog) -def instrumenttype_name(instance): - """Returns the name of the Instrument Type the instance is assigned to +def instrumenttype_title(instance): + """Returns the title of the Instrument Type the instance is assigned to """ - return instance.getInstrumentTypeName() + instrument_type = instance.getInstrumentType() + return instrument_type and api.get_title(instrument_type) or "" @indexer(IAnalysisCategory, IBikaSetupCatalog) diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 836431e5bf..90d933579a 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -44,7 +44,7 @@ - + diff --git a/bika/lims/content/instrument.py b/bika/lims/content/instrument.py index f4dd568d4d..bfa8381e89 100644 --- a/bika/lims/content/instrument.py +++ b/bika/lims/content/instrument.py @@ -55,10 +55,10 @@ from Products.Archetypes.atapi import ImageWidget from Products.Archetypes.atapi import BooleanWidget from Products.Archetypes.atapi import SelectionWidget -from Products.Archetypes.atapi import ReferenceWidget from Products.Archetypes.atapi import MultiSelectionWidget from bika.lims.browser.widgets import DateTimeWidget from bika.lims.browser.widgets import RecordsWidget +from bika.lims.browser.widgets import ReferenceWidget # bika.lims imports from bika.lims import api @@ -81,10 +81,10 @@ allowed_types=('InstrumentType',), relationship='InstrumentInstrumentType', required=1, - widget=SelectionWidget( - format='select', + widget=ReferenceWidget( label=_("Instrument type"), - visible={'view': 'invisible', 'edit': 'visible'} + catalog_name='bika_setup_catalog', + base_query={"is_active": True}, ), ), @@ -263,16 +263,6 @@ ), ), - # Needed since InstrumentType is sorted by its own object, not by its name. - ComputedField( - 'InstrumentTypeName', - expression='here.getInstrumentType().Title() if here.getInstrumentType() else ""', - widget=ComputedWidget( - label=_('Instrument Type'), - visible=True, - ), - ), - ComputedField( 'InstrumentLocationName', expression='here.getInstrumentLocation().Title() if here.getInstrumentLocation() else ""', @@ -360,7 +350,6 @@ schema.moveField('AssetNumber', before='description') schema.moveField('SupplierName', before='Model') schema.moveField('ManufacturerName', before='SupplierName') -schema.moveField('InstrumentTypeName', before='ManufacturerName') schema['description'].widget.visible = True schema['description'].schemata = 'default' @@ -456,14 +445,6 @@ def _getAvailableMethods(self): items.insert(0, ('', t(_('None')))) return DisplayList(items) - def getInstrumentTypes(self): - bsc = getToolByName(self, 'bika_setup_catalog') - items = [(c.UID, c.Title) - for c in bsc(portal_type='InstrumentType', - is_active=True)] - items.sort(lambda x, y: cmp(x[1], y[1])) - return DisplayList(items) - def getInstrumentLocations(self): bsc = getToolByName(self, 'bika_setup_catalog') items = [(c.UID, c.Title) diff --git a/bika/lims/controlpanel/bika_instruments.py b/bika/lims/controlpanel/bika_instruments.py index 66f2e77bdc..28a7ac5297 100644 --- a/bika/lims/controlpanel/bika_instruments.py +++ b/bika/lims/controlpanel/bika_instruments.py @@ -72,7 +72,7 @@ def __init__(self, context, request): "index": "sortable_title"}), ("Type", { "title": _("Type"), - "index": "instrumenttype_name", + "index": "instrumenttype_title", "toggle": True, "sortable": True}), ("Brand", { diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 33b9f1bb26..6dd1a338dd 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -181,7 +181,7 @@ # Sorting of listings: Worksheet Templates ("bika_setup_catalog", "instrument_title", "", "FieldIndex"), # Sorting of listings: Instruments - ("bika_setup_catalog", "instrumenttype_name", "", "FieldIndex"), + ("bika_setup_catalog", "instrumenttype_title", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), ("bika_setup_catalog", "getName", "", "FieldIndex"), ("bika_setup_catalog", "getPointOfCapture", "", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index b78a49c0f3..6bc1f007bb 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -54,7 +54,7 @@ ("bika_setup_catalog", "volume", "FieldIndex"), # Replaces getInstrumentTypeName - ("bika_setup_catalog", "instrumenttype_name", "FieldIndex"), + ("bika_setup_catalog", "instrumenttype_title", "FieldIndex"), # Replaces getDepartmentTitle ("bika_setup_catalog", "department_title", "FieldIndex"), @@ -135,7 +135,7 @@ # getVolume --> volume ("bika_setup_catalog", "getVolume"), - # getInstrumentTypeName --> instrumenttype_name + # getInstrumentTypeName --> instrumenttype_title ("bika_setup_catalog", "getInstrumentTypeName"), # getDepartmentTitle --> department_title From 7ccd02d37151d5368a227af514bbbeb5e0403bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 12:35:34 +0100 Subject: [PATCH 57/96] Remove getVATAmount index and metadata from setup_catalog --- bika/lims/controlpanel/bika_labproducts.py | 1 - bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bika/lims/controlpanel/bika_labproducts.py b/bika/lims/controlpanel/bika_labproducts.py index 59280da102..fe1fa155df 100644 --- a/bika/lims/controlpanel/bika_labproducts.py +++ b/bika/lims/controlpanel/bika_labproducts.py @@ -62,7 +62,6 @@ def __init__(self, context, request): 'index': 'price', 'toggle': True}, 'VATAmount': {'title': _('VAT Amount'), - 'index': 'getVATAmount', 'toggle': True}, 'TotalPrice': {'title': _('Total Price'), 'index': 'price_total', diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 6dd1a338dd..758e129e16 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -198,7 +198,6 @@ ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), ("bika_setup_catalog", "getUnit", "", "FieldIndex"), - ("bika_setup_catalog", "getVATAmount", "getVATAmount", "FieldIndex"), # Sorting of listings: LabProducts ("bika_setup_catalog", "volume", "", "FieldIndex"), ("bika_setup_catalog", "id", "getId", "FieldIndex"), @@ -255,7 +254,6 @@ ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getServiceUID"), ("bika_setup_catalog", "getUnit"), - ("bika_setup_catalog", "getVATAmount"), ("portal_catalog", "Analyst"), ) diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 6bc1f007bb..db177eb932 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -111,6 +111,7 @@ ("bika_setup_catalog", "getModel"), ("bika_setup_catalog", "getCalculationTitle"), ("bika_setup_catalog", "getCalibrationExpiryDate"), + ("bika_setup_catalog", "getVATAmount"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -183,6 +184,7 @@ ("bika_setup_catalog", "getCalculationUID"), ("bika_setup_catalog", "getCalibrationExpiryDate"), ("bika_setup_catalog", "getDepartmentTitle"), + ("bika_setup_catalog", "getVATAmount"), ] From 018067d303a3188e78ed6157bbe67fe4a3fccc55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 12:46:40 +0100 Subject: [PATCH 58/96] Remove getUnit index and metadata from setup_catalog --- bika/lims/browser/widgets/analysisprofileanalyseswidget.py | 6 +++++- bika/lims/controlpanel/bika_analysisservices.py | 6 +++++- bika/lims/controlpanel/bika_labproducts.py | 1 - bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/bika/lims/browser/widgets/analysisprofileanalyseswidget.py b/bika/lims/browser/widgets/analysisprofileanalyseswidget.py index 0bb0d7208f..59cbbf1927 100644 --- a/bika/lims/browser/widgets/analysisprofileanalyseswidget.py +++ b/bika/lims/browser/widgets/analysisprofileanalyseswidget.py @@ -27,6 +27,7 @@ from bika.lims.api.security import check_permission from bika.lims.browser.bika_listing import BikaListingView from bika.lims.permissions import FieldEditProfiles +from bika.lims.utils import format_supsub from bika.lims.utils import get_image from bika.lims.utils import get_link from plone.memoize import view @@ -79,7 +80,6 @@ def __init__(self, context, request): "sortable": False}), ("Unit", { "title": _("Unit"), - "index": "getUnit", "sortable": False}), ("Price", { "title": _("Price"), @@ -238,6 +238,10 @@ def folderitem(self, obj, item, index): else: item["methods"] = "" + # Unit + unit = obj.getUnit() + item["Unit"] = format_supsub(unit) if unit else "" + # Icons after_icons = "" if obj.getAccredited(): diff --git a/bika/lims/controlpanel/bika_analysisservices.py b/bika/lims/controlpanel/bika_analysisservices.py index a1feb6cdb8..18f42764f0 100644 --- a/bika/lims/controlpanel/bika_analysisservices.py +++ b/bika/lims/controlpanel/bika_analysisservices.py @@ -34,6 +34,7 @@ from bika.lims.idserver import renameAfterCreation from bika.lims.interfaces import IAnalysisServices from bika.lims.permissions import AddAnalysisService +from bika.lims.utils import format_supsub from bika.lims.utils import get_image from bika.lims.utils import get_link from bika.lims.utils import tmpID @@ -230,7 +231,6 @@ def __init__(self, context, request): "sortable": self.can_sort}), ("Unit", { "title": _("Unit"), - "attr": "getUnit", "sortable": False}), ("Price", { "title": _("Price"), @@ -390,6 +390,10 @@ def folderitem(self, obj, item, index): item["DuplicateVariation"] = self.format_duplication_variation( dup_variation) + # Unit + unit = obj.getUnit() + item["Unit"] = format_supsub(unit) if unit else "" + # Icons after_icons = "" if obj.getAccredited(): diff --git a/bika/lims/controlpanel/bika_labproducts.py b/bika/lims/controlpanel/bika_labproducts.py index fe1fa155df..a8cbff9cfb 100644 --- a/bika/lims/controlpanel/bika_labproducts.py +++ b/bika/lims/controlpanel/bika_labproducts.py @@ -56,7 +56,6 @@ def __init__(self, context, request): 'index': 'volume', 'toggle': True}, 'Unit': {'title': _('Unit'), - 'index': 'getUnit', 'toggle': True}, 'Price': {'title': _('Price'), 'index': 'price', diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 758e129e16..92705d9ef3 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -197,7 +197,6 @@ ("bika_setup_catalog", "sampletype_uids", "", "KeywordIndex"), ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), - ("bika_setup_catalog", "getUnit", "", "FieldIndex"), # Sorting of listings: LabProducts ("bika_setup_catalog", "volume", "", "FieldIndex"), ("bika_setup_catalog", "id", "getId", "FieldIndex"), @@ -253,7 +252,6 @@ ("bika_setup_catalog", "getSamplePointTitle"), ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getServiceUID"), - ("bika_setup_catalog", "getUnit"), ("portal_catalog", "Analyst"), ) diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index db177eb932..77b9a77bb3 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -112,6 +112,7 @@ ("bika_setup_catalog", "getCalculationTitle"), ("bika_setup_catalog", "getCalibrationExpiryDate"), ("bika_setup_catalog", "getVATAmount"), + ("bika_setup_catalog", "getUnit"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -185,6 +186,7 @@ ("bika_setup_catalog", "getCalibrationExpiryDate"), ("bika_setup_catalog", "getDepartmentTitle"), ("bika_setup_catalog", "getVATAmount"), + ("bika_setup_catalog", "getUnit"), ] From cbfa361b653e00dbaf88d10ad96d994892f4e8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 12:55:13 +0100 Subject: [PATCH 59/96] getPointOfCapture --> point_of_capture --- bika/lims/browser/analysisrequest/add2.py | 2 +- bika/lims/catalog/indexers/bikasetup.py | 7 +++++++ bika/lims/catalog/indexers/configure.zcml | 4 ++++ bika/lims/setuphandlers.py | 4 ++-- bika/lims/upgrade/v01_03_003.py | 7 +++++++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index 5760dd976b..815cda9069 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -538,7 +538,7 @@ def get_services(self, poc="lab"): bsc = api.get_tool("bika_setup_catalog") query = { "portal_type": "AnalysisService", - "getPointOfCapture": poc, + "point_of_capture": poc, "is_active": True, "sort_on": "sortable_title", } diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 044bdee78f..f0f2c82377 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -101,3 +101,10 @@ def department_title(instance): """ department = instance.getDepartment() return department and api.get_title(department) or "" + + +@indexer(IAnalysisService, IBikaSetupCatalog) +def point_of_capture(instance): + """Returns the point of capture of the instance + """ + return instance.getPointOfCapture() diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 90d933579a..df37c83746 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -49,6 +49,10 @@ + + + + diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 92705d9ef3..2de9f14cb2 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -184,7 +184,8 @@ ("bika_setup_catalog", "instrumenttype_title", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), ("bika_setup_catalog", "getName", "", "FieldIndex"), - ("bika_setup_catalog", "getPointOfCapture", "", "FieldIndex"), + # Add Sample form to split services in listing + ("bika_setup_catalog", "point_of_capture", "", "FieldIndex"), # Sorting of listings: LabProducts ("bika_setup_catalog", "price", "", "FieldIndex"), # Sorting of listings: LabProducts @@ -248,7 +249,6 @@ ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getKeyword"), ("bika_setup_catalog", "getName"), - ("bika_setup_catalog", "getPointOfCapture"), ("bika_setup_catalog", "getSamplePointTitle"), ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getServiceUID"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 77b9a77bb3..32076c5494 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -58,6 +58,9 @@ # Replaces getDepartmentTitle ("bika_setup_catalog", "department_title", "FieldIndex"), + + # Replaces getPointOfCapture + ("bika_setup_catalog", "point_of_capture", "FieldIndex"), ] INDEXES_TO_REMOVE = [ @@ -142,6 +145,9 @@ # getDepartmentTitle --> department_title ("bika_setup_catalog", "getDepartmentTitle"), + + # getPointOfCapture --> point_of_capture + ("bika_setup_catalog", "getPointOfCapture"), ] METADATA_TO_REMOVE = [ @@ -187,6 +193,7 @@ ("bika_setup_catalog", "getDepartmentTitle"), ("bika_setup_catalog", "getVATAmount"), ("bika_setup_catalog", "getUnit"), + ("bika_setup_catalog", "getPointOfCapture"), ] From 6e79fee69289b0507c13720e5518bf79c7cc1cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 12:58:13 +0100 Subject: [PATCH 60/96] Remove getSamplePointTitle index from setup_catalog --- bika/lims/setuphandlers.py | 1 - bika/lims/upgrade/v01_03_003.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 2de9f14cb2..a9e1d13a3e 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -190,7 +190,6 @@ ("bika_setup_catalog", "price", "", "FieldIndex"), # Sorting of listings: LabProducts ("bika_setup_catalog", "price_total", "", "FieldIndex"), - ("bika_setup_catalog", "getSamplePointTitle", "", "KeywordIndex"), ("bika_setup_catalog", "getSamplePointUID", "", "FieldIndex"), # Sorting of listings: Sample Points, Specifications ("bika_setup_catalog", "getSampleTypeTitle", "", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 32076c5494..6b2fb39dd0 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -116,6 +116,7 @@ ("bika_setup_catalog", "getCalibrationExpiryDate"), ("bika_setup_catalog", "getVATAmount"), ("bika_setup_catalog", "getUnit"), + ("bika_setup_catalog", "getSamplePointTitle"), # REPLACEMENTS (indexes to be removed because of a replacement) From ea903935b7bd279b784502d69357dcac7638ee3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 13:06:01 +0100 Subject: [PATCH 61/96] Remove volume index from setup_catalog --- bika/lims/catalog/indexers/bikasetup.py | 7 ------- bika/lims/catalog/indexers/configure.zcml | 1 - bika/lims/controlpanel/bika_labproducts.py | 1 - bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 5 +---- 5 files changed, 1 insertion(+), 15 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index f0f2c82377..b1a7b1e98d 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -80,13 +80,6 @@ def price_total(instance): return instance.getTotalPrice() -@indexer(ILabProduct, IBikaSetupCatalog) -def volume(instance): - """Returns the volume of the instance - """ - return instance.getVolume() - - @indexer(IInstrument, IBikaSetupCatalog) def instrumenttype_title(instance): """Returns the title of the Instrument Type the instance is assigned to diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index df37c83746..4ffa310868 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -41,7 +41,6 @@ - diff --git a/bika/lims/controlpanel/bika_labproducts.py b/bika/lims/controlpanel/bika_labproducts.py index a8cbff9cfb..efae5eda75 100644 --- a/bika/lims/controlpanel/bika_labproducts.py +++ b/bika/lims/controlpanel/bika_labproducts.py @@ -53,7 +53,6 @@ def __init__(self, context, request): 'index': 'sortable_title', 'toggle': True}, 'Volume': {'title': _('Volume'), - 'index': 'volume', 'toggle': True}, 'Unit': {'title': _('Unit'), 'toggle': True}, diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index a9e1d13a3e..40f73b4e34 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -197,8 +197,6 @@ ("bika_setup_catalog", "sampletype_uids", "", "KeywordIndex"), ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), - # Sorting of listings: LabProducts - ("bika_setup_catalog", "volume", "", "FieldIndex"), ("bika_setup_catalog", "id", "getId", "FieldIndex"), ("bika_setup_catalog", "is_active", "", "BooleanIndex"), ("bika_setup_catalog", "path", "getPhysicalPath", "ExtendedPathIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 6b2fb39dd0..36adc735a6 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -51,7 +51,6 @@ # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "price", "FieldIndex"), ("bika_setup_catalog", "price_total", "FieldIndex"), - ("bika_setup_catalog", "volume", "FieldIndex"), # Replaces getInstrumentTypeName ("bika_setup_catalog", "instrumenttype_title", "FieldIndex"), @@ -117,6 +116,7 @@ ("bika_setup_catalog", "getVATAmount"), ("bika_setup_catalog", "getUnit"), ("bika_setup_catalog", "getSamplePointTitle"), + ("bika_setup_catalog", "getVolume"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -138,9 +138,6 @@ # getTotalPrice --> price_total ("bika_setup_catalog", "getTotalPrice"), - # getVolume --> volume - ("bika_setup_catalog", "getVolume"), - # getInstrumentTypeName --> instrumenttype_title ("bika_setup_catalog", "getInstrumentTypeName"), From 701d14cff1d2175d46fc8d754a4f6bd050f1cc0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 15:18:19 +0100 Subject: [PATCH 62/96] Remove getSamplePointUID index and metadata from setup_catalog --- .../reports/selection_macros/__init__.py | 31 ------------------- .../selection_macros/select_samplepoint.pt | 26 ---------------- bika/lims/catalog/indexers/bikasetup.py | 1 - bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 2 ++ 5 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 bika/lims/browser/reports/selection_macros/select_samplepoint.pt diff --git a/bika/lims/browser/reports/selection_macros/__init__.py b/bika/lims/browser/reports/selection_macros/__init__.py index d5d22e0bda..c23a2f453b 100644 --- a/bika/lims/browser/reports/selection_macros/__init__.py +++ b/bika/lims/browser/reports/selection_macros/__init__.py @@ -156,14 +156,6 @@ def _cache_key_select_reference_service(method, self, style=None): return key -def _cache_key_select_samplepoint(method, self, allow_blank=True, multiselect=False, style=None): - """ - This function returns the key used to decide if method select_samplepoint has to be recomputed - """ - key = update_timer(), allow_blank, multiselect, style - return key - - def _cache_key_select_sample_type(method, self, allow_blank=True, multiselect=False, style=None): """ This function returns the key used to decide if method select_sample_type has to be recomputed @@ -457,29 +449,6 @@ def parse_state(self, request, workflow_id, field_id, field_title): res['titles'] = state_title return res - select_samplepoint_pt = ViewPageTemplateFile("select_samplepoint.pt") - - @ram.cache(_cache_key_select_samplepoint) - def select_samplepoint(self, allow_blank=True, multiselect=False, style=None): - self.style = style - self.allow_blank = allow_blank - self.multiselect = multiselect - self.samplepoints = self.bsc(portal_type='SamplePoint', - is_active=True, - sort_on='sortable_title') - return self.select_samplepoint_pt() - - def parse_samplepoint(self, request): - val = request.form.get("SamplePointUID", "") - if val: - obj = val and self.rc.lookupObject(val) - title = obj.Title() - res = {} - res['contentFilter'] = ('getSamplePointUID', val) - res['parms'] = {'title': _("Sample Point"), 'value': title} - res['titles'] = title - return res - select_sampletype_pt = ViewPageTemplateFile("select_sampletype.pt") @ram.cache(_cache_key_select_sample_type) diff --git a/bika/lims/browser/reports/selection_macros/select_samplepoint.pt b/bika/lims/browser/reports/selection_macros/select_samplepoint.pt deleted file mode 100644 index fee1748199..0000000000 --- a/bika/lims/browser/reports/selection_macros/select_samplepoint.pt +++ /dev/null @@ -1,26 +0,0 @@ -
- - -
- - - -
diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index b1a7b1e98d..01f3d0950d 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -26,7 +26,6 @@ from bika.lims.interfaces import IBikaSetupCatalog from bika.lims.interfaces import IHavePrice from bika.lims.interfaces import IInstrument -from bika.lims.interfaces import ILabProduct from bika.lims.interfaces import ISampleTypeAwareMixin from bika.lims.interfaces import IWorksheetTemplate diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 40f73b4e34..dc684feebf 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -190,7 +190,6 @@ ("bika_setup_catalog", "price", "", "FieldIndex"), # Sorting of listings: LabProducts ("bika_setup_catalog", "price_total", "", "FieldIndex"), - ("bika_setup_catalog", "getSamplePointUID", "", "FieldIndex"), # Sorting of listings: Sample Points, Specifications ("bika_setup_catalog", "getSampleTypeTitle", "", "FieldIndex"), # Filter in Add2: Sample Points, Specifications, Templates @@ -247,7 +246,6 @@ ("bika_setup_catalog", "getKeyword"), ("bika_setup_catalog", "getName"), ("bika_setup_catalog", "getSamplePointTitle"), - ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getServiceUID"), ("portal_catalog", "Analyst"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 36adc735a6..41af19d73b 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -117,6 +117,7 @@ ("bika_setup_catalog", "getUnit"), ("bika_setup_catalog", "getSamplePointTitle"), ("bika_setup_catalog", "getVolume"), + ("bika_setup_catalog", "getSamplePointUID"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -192,6 +193,7 @@ ("bika_setup_catalog", "getVATAmount"), ("bika_setup_catalog", "getUnit"), ("bika_setup_catalog", "getPointOfCapture"), + ("bika_setup_catalog", "getSamplePointUID"), ] From 99643e20086dd5ff5d6a3069ea0e7e9797dd843d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 16:09:56 +0100 Subject: [PATCH 63/96] getSampleTypeTitle --> sampletype_title --- bika/lims/catalog/indexers/bikasetup.py | 12 ++++++++++++ bika/lims/catalog/indexers/configure.zcml | 3 +++ bika/lims/controlpanel/bika_analysisspecs.py | 2 +- bika/lims/controlpanel/bika_samplepoints.py | 2 +- bika/lims/setuphandlers.py | 2 +- bika/lims/upgrade/v01_03_003.py | 9 ++++++--- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 01f3d0950d..4f0bcf2fde 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -42,6 +42,18 @@ def sampletype_uids(instance): return instance.getSampleTypeUID() or (None, ) +@indexer(ISampleTypeAwareMixin, IBikaSetupCatalog) +def sampletype_title(instance): + """Returns a list of titles from SampleType the instance is assigned to + """ + sample_type = instance.getSampleType() + if isinstance(sample_type, (list, tuple)): + return map(api.get_title, sample_type) + elif sample_type: + return [api.get_title(sample_type)] + return [None] + + @indexer(IAnalysisService, IBikaSetupCatalog) def method_available_uids(instance): """Returns a list of Method UIDs that are available for this instance diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 4ffa310868..d48da8a8df 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -31,6 +31,9 @@ Specifications and Templates when a Sample Type is selected --> + + + diff --git a/bika/lims/controlpanel/bika_analysisspecs.py b/bika/lims/controlpanel/bika_analysisspecs.py index 77560b2f45..bd8afd3732 100644 --- a/bika/lims/controlpanel/bika_analysisspecs.py +++ b/bika/lims/controlpanel/bika_analysisspecs.py @@ -76,7 +76,7 @@ def __init__(self, context, request): "index": "sortable_title"}), ("SampleType", { "title": _("Sample Type"), - "index": "getSampleTypeTitle"}), + "index": "sampletype_title"}), )) self.review_states = [ diff --git a/bika/lims/controlpanel/bika_samplepoints.py b/bika/lims/controlpanel/bika_samplepoints.py index eb4ea60ca1..b79189ff27 100644 --- a/bika/lims/controlpanel/bika_samplepoints.py +++ b/bika/lims/controlpanel/bika_samplepoints.py @@ -89,7 +89,7 @@ def __init__(self, context, request): "toggle": False}), ("SampleTypes", { "title": _("Sample Types"), - "index": "getSampleTypeTitle", + "index": "sampletype_title", "toggle": True}), )) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index dc684feebf..a652539636 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -191,7 +191,7 @@ # Sorting of listings: LabProducts ("bika_setup_catalog", "price_total", "", "FieldIndex"), # Sorting of listings: Sample Points, Specifications - ("bika_setup_catalog", "getSampleTypeTitle", "", "FieldIndex"), + ("bika_setup_catalog", "sampletype_title", "", "KeywordIndex"), # Filter in Add2: Sample Points, Specifications, Templates ("bika_setup_catalog", "sampletype_uids", "", "KeywordIndex"), ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 41af19d73b..1a26132eb4 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -32,9 +32,11 @@ INDEXES_TO_ADD = [ # Replaces getSampleTypeUIDs - # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "sampletype_uids", "KeywordIndex"), + # Replaces getSampleTypeTitle + ("bika_setup_catalog", "sampletype_title", "KeywordIndex"), + # Replaces getAvailableMethodUIDs # Used to filter services in Worksheet's Add Analyses View for when the # Worksheet Template being used has a Method assigned. @@ -123,11 +125,12 @@ # REPLACEMENTS (indexes to be removed because of a replacement) # getSampleTypeUID --> sampletype_uid (FieldIndex --> KeywordIndex) - # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "getSampleTypeUID"), + # getSampleTypeTitle --> sampletype_title + ("bika_setup_catalog", "getSampleTypeTitle"), + # getAvailableMethodUIDs --> method_available_uids - # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getAvailableMethodUIDs"), # getInstrumentTitle --> instrument_title From 3fd867e07b47a9995edc309d8f4ce2def818ab02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 17:38:40 +0100 Subject: [PATCH 64/96] FieldIndex --> KeywordIndex --- CODE_CONVENTIONS.md | 35 ++++++++++++++++++++++--- bika/lims/catalog/indexers/bikasetup.py | 34 +++++++++++++++++------- bika/lims/setuphandlers.py | 6 ++--- bika/lims/upgrade/v01_03_003.py | 11 +++----- 4 files changed, 64 insertions(+), 22 deletions(-) diff --git a/CODE_CONVENTIONS.md b/CODE_CONVENTIONS.md index 9cac866a87..b536a23c86 100644 --- a/CODE_CONVENTIONS.md +++ b/CODE_CONVENTIONS.md @@ -10,8 +10,33 @@ any add-ons for `senaite` too. Names for catalog indexes don't follow the `CamelCase` naming convention, rather all in lowercase and words separated by `_`: -- Wrong: `getSampleTypeUID` -- Good: `sampletype_uids` +- Bad: `getSampleTypeUID` +- Good: `sampletype_uid` + +#### Plural and singular forms + +Indexes will be written in singular form. There are a few exceptions, mostly +those that come from `Plone` or `Zope` (e.g. `allowedRolesAndUsers`). Quite +frequently, the plural form is used wrongly because the name of the meta-type +index to use leads us to think about the plural form: e.g. `KeywordIndex`, that +indexes a sequence of keywords. Is better to think about how the searches +against the index work. + +For instance, for a given object, a `KeywordIndex` will store a sequence of +keywords, but if we do a search for single or multiple keywords against this +index, the search will only return those items that have at least one of the +keywords. And if there are multiple keyword matches for same item, the system +will only return the item once. Since we can query for any index (`FieldIndex`, +`KeywordIndex`, etc.) using a list, it does not make sense to use the plural +form. In fact, if you are forced to add an index in plural form because a given +index with same name, but in singular already exists, probably the index in +singular is a `FieldIndex`, that don't allow you to store multiple values. In +such case, the best approach is to change the meta-type of the existing index +from `FieldIndex` to `KeywordIndex`. + +- Bad: `sampletype_titles` +- Good: `sampletype_title` + ### Metadata fields naming @@ -22,6 +47,10 @@ convention. Since one would expect the name of the metadata field to match with the name of the function from the object, we keep same convention. This might change in future when we move to `Dexterity`. -- Wrong: `SampleTypeUID` +- Bad: `SampleTypeUID` - Good: `getSampleTypeUID` +#### Plural and singular forms + +For metadata fields, use plural forms when the field returns a list and use +singular when the field returns a single value. diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 4f0bcf2fde..f9eb7f1491 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -45,13 +45,12 @@ def sampletype_uids(instance): @indexer(ISampleTypeAwareMixin, IBikaSetupCatalog) def sampletype_title(instance): """Returns a list of titles from SampleType the instance is assigned to + + If the instance has no sample type assigned, it returns a tuple with + a None value. This allows searches for `MissingValue` entries too. """ sample_type = instance.getSampleType() - if isinstance(sample_type, (list, tuple)): - return map(api.get_title, sample_type) - elif sample_type: - return [api.get_title(sample_type)] - return [None] + return to_title_list(sample_type) @indexer(IAnalysisService, IBikaSetupCatalog) @@ -71,10 +70,13 @@ def method_available_uids(instance): @indexer(IWorksheetTemplate, IBikaSetupCatalog) def instrument_title(instance): - """Returns the title of the instrument assigned to the instance + """Returns a list of titles from SampleType the instance is assigned to + + If the instance has no instrument assigned, it returns a tuple with + a None value. This allows searches for `MissingValue` entries too. """ instrument = instance.getInstrument() - return instrument and api.get_title(instrument) or "" + return to_title_list(instrument) @indexer(IHavePrice, IBikaSetupCatalog) @@ -94,17 +96,23 @@ def price_total(instance): @indexer(IInstrument, IBikaSetupCatalog) def instrumenttype_title(instance): """Returns the title of the Instrument Type the instance is assigned to + + If the instance has no instrument type assigned, it returns a tuple with + a None value. This allows searches for `MissingValue` entries too. """ instrument_type = instance.getInstrumentType() - return instrument_type and api.get_title(instrument_type) or "" + return to_title_list(instrument_type) @indexer(IAnalysisCategory, IBikaSetupCatalog) def department_title(instance): """Returns the title of the Department the instance is assigned to + + If the instance has no instrument type assigned, it returns a tuple with + a None value. This allows searches for `MissingValue` entries too. """ department = instance.getDepartment() - return department and api.get_title(department) or "" + return to_title_list(department) @indexer(IAnalysisService, IBikaSetupCatalog) @@ -112,3 +120,11 @@ def point_of_capture(instance): """Returns the point of capture of the instance """ return instance.getPointOfCapture() + + +def to_title_list(obj): + if isinstance(obj, (list, tuple)): + return map(api.get_title, obj) + elif obj: + return [api.get_title(obj)] + return [None] diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index a652539636..38e9257edc 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -175,13 +175,13 @@ ("bika_setup_catalog", "getCategoryUID", "", "FieldIndex"), ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), # Sorting of listings: Analysis Categories - ("bika_setup_catalog", "department_title", "", "FieldIndex"), + ("bika_setup_catalog", "department_title", "", "KeywordIndex"), ("bika_setup_catalog", "getFullname", "", "FieldIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), # Sorting of listings: Worksheet Templates - ("bika_setup_catalog", "instrument_title", "", "FieldIndex"), + ("bika_setup_catalog", "instrument_title", "", "KeywordIndex"), # Sorting of listings: Instruments - ("bika_setup_catalog", "instrumenttype_title", "", "FieldIndex"), + ("bika_setup_catalog", "instrumenttype_title", "", "KeywordIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), ("bika_setup_catalog", "getName", "", "FieldIndex"), # Add Sample form to split services in listing diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 1a26132eb4..e8fc4f9f86 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -39,26 +39,23 @@ # Replaces getAvailableMethodUIDs # Used to filter services in Worksheet's Add Analyses View for when the - # Worksheet Template being used has a Method assigned. - # https://github.com/senaite/senaite.core/pull/1481 + # Worksheet Template being used has a Method assigned ("bika_setup_catalog", "method_available_uids", "KeywordIndex"), # Replaces getInstrumentTitle # Used for sorting Worksheet Templates listing by Instrument - # https://github.com/senaite/senaite.core/pull/1481 - ("bika_setup_catalog", "instrument_title", "FieldIndex"), + ("bika_setup_catalog", "instrument_title", "KeywordIndex"), # Replaces getPrice, getTotalPrice, getVolume # Used for sorting LabProducts listing - # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "price", "FieldIndex"), ("bika_setup_catalog", "price_total", "FieldIndex"), # Replaces getInstrumentTypeName - ("bika_setup_catalog", "instrumenttype_title", "FieldIndex"), + ("bika_setup_catalog", "instrumenttype_title", "KeywordIndex"), # Replaces getDepartmentTitle - ("bika_setup_catalog", "department_title", "FieldIndex"), + ("bika_setup_catalog", "department_title", "KeywordIndex"), # Replaces getPointOfCapture ("bika_setup_catalog", "point_of_capture", "FieldIndex"), From 28a63187b5e7227fcaaad7cf2b0a776e41993c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 20:21:38 +0100 Subject: [PATCH 65/96] Indexes renaming: *_uids --> *_uid --- bika/lims/browser/analysisrequest/add2.py | 6 +++--- bika/lims/browser/widgets/serviceswidget.py | 2 +- bika/lims/catalog/indexers/bikasetup.py | 4 ++-- bika/lims/catalog/indexers/configure.zcml | 8 ++++---- bika/lims/setuphandlers.py | 4 ++-- bika/lims/upgrade/v01_03_003.py | 7 ++++--- bika/lims/validators.py | 2 +- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index 815cda9069..00ab0d637c 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -1018,18 +1018,18 @@ def get_sampletype_info(self, obj): # Display Sample Points that have this sample type assigned plus # those that do not have a sample type assigned "SamplePoint": { - "sampletype_uids": [sample_type_uid, None], + "sampletype_uid": [sample_type_uid, None], "getClientUID": [client_uid, ""], }, # Display Specifications that have this sample type assigned only "Specification": { - "sampletype_uids": sample_type_uid, + "sampletype_uid": sample_type_uid, "getClientUID": [client_uid, ""], }, # Display AR Templates that have this sample type assigned plus # those that do not have a sample type assigned "Template": { - "sampletype_uids": [sample_type_uid, None], + "sampletype_uid": [sample_type_uid, None], "getClientUID": [client_uid, ""], } } diff --git a/bika/lims/browser/widgets/serviceswidget.py b/bika/lims/browser/widgets/serviceswidget.py index 8a55618235..b3c8e5e43a 100644 --- a/bika/lims/browser/widgets/serviceswidget.py +++ b/bika/lims/browser/widgets/serviceswidget.py @@ -49,7 +49,7 @@ def __init__(self, context, request): method_uid = context.getMethodUID() if method_uid: self.contentFilter.update({ - "method_available_uids": method_uid + "method_available_uid": method_uid }) self.context_actions = {} diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index f9eb7f1491..53b5c3bbb3 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -31,7 +31,7 @@ @indexer(ISampleTypeAwareMixin, IBikaSetupCatalog) -def sampletype_uids(instance): +def sampletype_uid(instance): """Returns the list of SampleType UIDs the instance is assigned to This is a KeywordIndex, so it will be indexed as a list, even if only one @@ -54,7 +54,7 @@ def sampletype_title(instance): @indexer(IAnalysisService, IBikaSetupCatalog) -def method_available_uids(instance): +def method_available_uid(instance): """Returns a list of Method UIDs that are available for this instance If the instance (AnalysisService) has InstrumentEntryOfResults set to True, diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index d48da8a8df..254009bf7d 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -27,16 +27,16 @@ - - + - - + diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 38e9257edc..614b68fc54 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -170,7 +170,7 @@ ("bika_setup_catalog", "created", "", "DateIndex"), # Filter services in Worksheet's Add Analyses View for when the Worksheet # Template being used has a Method assigned - ("bika_setup_catalog", "method_available_uids", "", "KeywordIndex"), + ("bika_setup_catalog", "method_available_uid", "", "KeywordIndex"), ("bika_setup_catalog", "getCategoryTitle", "", "FieldIndex"), ("bika_setup_catalog", "getCategoryUID", "", "FieldIndex"), ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), @@ -193,7 +193,7 @@ # Sorting of listings: Sample Points, Specifications ("bika_setup_catalog", "sampletype_title", "", "KeywordIndex"), # Filter in Add2: Sample Points, Specifications, Templates - ("bika_setup_catalog", "sampletype_uids", "", "KeywordIndex"), + ("bika_setup_catalog", "sampletype_uid", "", "KeywordIndex"), ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), ("bika_setup_catalog", "id", "getId", "FieldIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index e8fc4f9f86..2d580493ae 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -32,7 +32,7 @@ INDEXES_TO_ADD = [ # Replaces getSampleTypeUIDs - ("bika_setup_catalog", "sampletype_uids", "KeywordIndex"), + ("bika_setup_catalog", "sampletype_uid", "KeywordIndex"), # Replaces getSampleTypeTitle ("bika_setup_catalog", "sampletype_title", "KeywordIndex"), @@ -40,7 +40,7 @@ # Replaces getAvailableMethodUIDs # Used to filter services in Worksheet's Add Analyses View for when the # Worksheet Template being used has a Method assigned - ("bika_setup_catalog", "method_available_uids", "KeywordIndex"), + ("bika_setup_catalog", "method_available_uid", "KeywordIndex"), # Replaces getInstrumentTitle # Used for sorting Worksheet Templates listing by Instrument @@ -123,11 +123,12 @@ # getSampleTypeUID --> sampletype_uid (FieldIndex --> KeywordIndex) ("bika_setup_catalog", "getSampleTypeUID"), + ("bika_setup_catalog", "sampletype_uids"), # getSampleTypeTitle --> sampletype_title ("bika_setup_catalog", "getSampleTypeTitle"), - # getAvailableMethodUIDs --> method_available_uids + # getAvailableMethodUIDs --> method_available_uid ("bika_setup_catalog", "getAvailableMethodUIDs"), # getInstrumentTitle --> instrument_title diff --git a/bika/lims/validators.py b/bika/lims/validators.py index 69d7cb8d98..9f22d02920 100644 --- a/bika/lims/validators.py +++ b/bika/lims/validators.py @@ -1322,7 +1322,7 @@ def __call__(self, value, *args, **kwargs): bsc = getToolByName(instance, 'bika_setup_catalog') query = { 'portal_type': 'AnalysisService', - 'method_available_uids': method.UID() + 'method_available_uid': method.UID() } method_ans_uids = [b.UID for b in bsc(query)] rules = instance.getReflexRules() From 9fead8e06ac3c7c9dbe2998ed84c1848c1c802d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 29 Nov 2019 20:51:31 +0100 Subject: [PATCH 66/96] Remove index: getCategoryTitle --- bika/lims/browser/referencesample.py | 3 +-- .../browser/widgets/referenceresultswidget.py | 3 +-- bika/lims/setuphandlers.py | 1 - bika/lims/subscribers/objectmodified.py | 15 +++++++++------ bika/lims/upgrade/v01_03_003.py | 3 +++ 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/bika/lims/browser/referencesample.py b/bika/lims/browser/referencesample.py index e217b3df74..053475ceed 100644 --- a/bika/lims/browser/referencesample.py +++ b/bika/lims/browser/referencesample.py @@ -266,11 +266,10 @@ def __init__(self, context, request): self.show_search = False # Categories + self.categories = [] if self.show_categories_enabled(): - self.categories = [] self.show_categories = True self.expand_all_categories = True - self.category_index = "getCategoryTitle" self.columns = collections.OrderedDict(( ("Title", { diff --git a/bika/lims/browser/widgets/referenceresultswidget.py b/bika/lims/browser/widgets/referenceresultswidget.py index 9ba7161345..e5d28994bb 100644 --- a/bika/lims/browser/widgets/referenceresultswidget.py +++ b/bika/lims/browser/widgets/referenceresultswidget.py @@ -55,11 +55,10 @@ def __init__(self, context, request, fieldvalue=[], allow_edit=True): self.omit_form = True # Categories + self.categories = [] if self.show_categories_enabled(): - self.categories = [] self.show_categories = True self.expand_all_categories = False - self.category_index = "getCategoryTitle" self.columns = collections.OrderedDict(( ("Title", { diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 614b68fc54..280470c51a 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -171,7 +171,6 @@ # Filter services in Worksheet's Add Analyses View for when the Worksheet # Template being used has a Method assigned ("bika_setup_catalog", "method_available_uid", "", "KeywordIndex"), - ("bika_setup_catalog", "getCategoryTitle", "", "FieldIndex"), ("bika_setup_catalog", "getCategoryUID", "", "FieldIndex"), ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), # Sorting of listings: Analysis Categories diff --git a/bika/lims/subscribers/objectmodified.py b/bika/lims/subscribers/objectmodified.py index 1802458ca8..5b09123961 100644 --- a/bika/lims/subscribers/objectmodified.py +++ b/bika/lims/subscribers/objectmodified.py @@ -20,6 +20,9 @@ from Products.CMFCore.utils import getToolByName +from bika.lims import api +from bika.lims.catalog import CATALOG_ANALYSIS_LISTING + def ObjectModifiedEventHandler(obj, event): """ Various types need automation on edit. @@ -59,9 +62,9 @@ def ObjectModifiedEventHandler(obj, event): elif obj.portal_type == 'AnalysisCategory': # If the analysis category's Title is modified, we must # re-index all services and analyses that refer to this title. - for i in [['Analysis', 'bika_analysis_catalog'], - ['AnalysisService', 'bika_setup_catalog']]: - cat = getToolByName(obj, i[1]) - brains = cat(portal_type=i[0], getCategoryUID=obj.UID()) - for brain in brains: - brain.getObject().reindexObject(idxs=['getCategoryTitle']) + query = dict(getCategoryUID=obj.UID()) + brains = api.search(query, CATALOG_ANALYSIS_LISTING) + for brain in brains: + obj = api.get_object(brain) + obj.reindexObject(idxs=['getCategoryTitle']) + diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 2d580493ae..6b1399155d 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -59,6 +59,7 @@ # Replaces getPointOfCapture ("bika_setup_catalog", "point_of_capture", "FieldIndex"), + ] INDEXES_TO_REMOVE = [ @@ -117,6 +118,7 @@ ("bika_setup_catalog", "getSamplePointTitle"), ("bika_setup_catalog", "getVolume"), ("bika_setup_catalog", "getSamplePointUID"), + ("bika_setup_catalog", "getCategoryTitle"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -148,6 +150,7 @@ # getPointOfCapture --> point_of_capture ("bika_setup_catalog", "getPointOfCapture"), + ] METADATA_TO_REMOVE = [ From 69b0ccfda03d12ffbfc382cfd07fa94995d59f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Sat, 30 Nov 2019 00:09:58 +0100 Subject: [PATCH 67/96] Code revisit and refactoring --- bika/lims/browser/accreditation.py | 12 +- .../widgets/analysisprofileanalyseswidget.py | 2 +- bika/lims/catalog/bikasetup_catalog.py | 5 +- bika/lims/catalog/indexers/bikasetup.py | 43 ++++--- bika/lims/catalog/indexers/configure.zcml | 1 + bika/lims/content/abstractbaseanalysis.py | 66 +++++----- bika/lims/content/analysiscategory.py | 119 ++++++++++-------- bika/lims/content/analysisspec.py | 40 ++---- bika/lims/content/department.py | 81 ++++++------ bika/lims/content/instrument.py | 6 +- bika/lims/content/labcontact.py | 11 +- .../controlpanel/bika_analysisservices.py | 2 +- bika/lims/controlpanel/bika_departments.py | 41 ++---- bika/lims/interfaces/__init__.py | 18 +++ bika/lims/setuphandlers.py | 1 + bika/lims/upgrade/v01_03_003.py | 5 + 16 files changed, 229 insertions(+), 224 deletions(-) diff --git a/bika/lims/browser/accreditation.py b/bika/lims/browser/accreditation.py index 07a4e28211..b3f0239290 100644 --- a/bika/lims/browser/accreditation.py +++ b/bika/lims/browser/accreditation.py @@ -108,12 +108,12 @@ def search(self, searchterm="", ignorecase=True): # Boil out those that are not accredited # There is no need to keep a `getAccredited` index in the catalog only # for this view. Since we don't expect a lot of items from this content - # type (AnalysisService), so is fine to wake-up them + # type (AnalysisService), is fine to wake-up them brains = super(AccreditationView, self).search(searchterm, ignorecase) - out_brains = [] - for brain in brains: + + def is_accredited(brain): obj = api.get_object(brain) - if obj.getAccredited(): - out_brains.append(brain) - return out_brains + return obj.getAccredited() + + return filter(is_accredited, brains) diff --git a/bika/lims/browser/widgets/analysisprofileanalyseswidget.py b/bika/lims/browser/widgets/analysisprofileanalyseswidget.py index 59cbbf1927..c7cd1ea270 100644 --- a/bika/lims/browser/widgets/analysisprofileanalyseswidget.py +++ b/bika/lims/browser/widgets/analysisprofileanalyseswidget.py @@ -240,7 +240,7 @@ def folderitem(self, obj, item, index): # Unit unit = obj.getUnit() - item["Unit"] = format_supsub(unit) if unit else "" + item["Unit"] = unit and format_supsub(unit) or "" # Icons after_icons = "" diff --git a/bika/lims/catalog/bikasetup_catalog.py b/bika/lims/catalog/bikasetup_catalog.py index b985ea882c..9d31a326f4 100644 --- a/bika/lims/catalog/bikasetup_catalog.py +++ b/bika/lims/catalog/bikasetup_catalog.py @@ -24,6 +24,9 @@ from bika.lims.interfaces import IBikaSetupCatalog +SETUP_CATALOG = "bika_setup_catalog" + + class BikaSetupCatalog(BikaCatalogTool): """ Catalog for all bika_setup objects @@ -31,7 +34,7 @@ class BikaSetupCatalog(BikaCatalogTool): implements(IBikaSetupCatalog) def __init__(self): - BikaCatalogTool.__init__(self, 'bika_setup_catalog', + BikaCatalogTool.__init__(self, SETUP_CATALOG, 'Bika Setup Catalog', 'BikaSetupCatalog') diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 53b5c3bbb3..cea67b8b0d 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -21,13 +21,13 @@ from plone.indexer import indexer from bika.lims import api -from bika.lims.interfaces import IAnalysisCategory from bika.lims.interfaces import IAnalysisService from bika.lims.interfaces import IBikaSetupCatalog +from bika.lims.interfaces import IHaveDepartment +from bika.lims.interfaces import IHaveInstrument from bika.lims.interfaces import IHavePrice from bika.lims.interfaces import IInstrument from bika.lims.interfaces import ISampleTypeAwareMixin -from bika.lims.interfaces import IWorksheetTemplate @indexer(ISampleTypeAwareMixin, IBikaSetupCatalog) @@ -39,7 +39,8 @@ def sampletype_uid(instance): SampleType assigned, it returns a tuple with a None value. This allows searches for `MissingValue` entries too. """ - return instance.getSampleTypeUID() or (None, ) + sample_type = instance.getSampleType() + return to_keywords_list(sample_type, api.get_uid) @indexer(ISampleTypeAwareMixin, IBikaSetupCatalog) @@ -50,7 +51,7 @@ def sampletype_title(instance): a None value. This allows searches for `MissingValue` entries too. """ sample_type = instance.getSampleType() - return to_title_list(sample_type) + return to_keywords_list(sample_type, api.get_title) @indexer(IAnalysisService, IBikaSetupCatalog) @@ -68,15 +69,15 @@ def method_available_uid(instance): return instance.getAvailableMethodUIDs() or (None, ) -@indexer(IWorksheetTemplate, IBikaSetupCatalog) +@indexer(IHaveInstrument, IBikaSetupCatalog) def instrument_title(instance): - """Returns a list of titles from SampleType the instance is assigned to + """Returns a list of titles from Instrument the instance is assigned to If the instance has no instrument assigned, it returns a tuple with a None value. This allows searches for `MissingValue` entries too. """ instrument = instance.getInstrument() - return to_title_list(instrument) + return to_keywords_list(instrument, api.get_title) @indexer(IHavePrice, IBikaSetupCatalog) @@ -95,24 +96,26 @@ def price_total(instance): @indexer(IInstrument, IBikaSetupCatalog) def instrumenttype_title(instance): - """Returns the title of the Instrument Type the instance is assigned to - - If the instance has no instrument type assigned, it returns a tuple with - a None value. This allows searches for `MissingValue` entries too. + """Returns a list of Instrument Type titles the instance is assigned to """ instrument_type = instance.getInstrumentType() - return to_title_list(instrument_type) + return to_keywords_list(instrument_type, api.get_title) + + +@indexer(IHaveDepartment, IBikaSetupCatalog) +def department_uid(instance): + """Returns a list of Department UIDs the instance is assigned to + """ + department = instance.getDepartment() + return to_keywords_list(department, api.get_uid) -@indexer(IAnalysisCategory, IBikaSetupCatalog) +@indexer(IHaveDepartment, IBikaSetupCatalog) def department_title(instance): """Returns the title of the Department the instance is assigned to - - If the instance has no instrument type assigned, it returns a tuple with - a None value. This allows searches for `MissingValue` entries too. """ department = instance.getDepartment() - return to_title_list(department) + return to_keywords_list(department, api.get_title) @indexer(IAnalysisService, IBikaSetupCatalog) @@ -122,9 +125,9 @@ def point_of_capture(instance): return instance.getPointOfCapture() -def to_title_list(obj): +def to_keywords_list(obj, func): if isinstance(obj, (list, tuple)): - return map(api.get_title, obj) + return map(func, obj) elif obj: - return [api.get_title(obj)] + return [func(obj)] return [None] diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 254009bf7d..53481a12c0 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -54,6 +54,7 @@ + diff --git a/bika/lims/content/abstractbaseanalysis.py b/bika/lims/content/abstractbaseanalysis.py index 78cbd7a811..b56f88617e 100644 --- a/bika/lims/content/abstractbaseanalysis.py +++ b/bika/lims/content/abstractbaseanalysis.py @@ -19,21 +19,7 @@ # Some rights reserved, see README and LICENSE. from AccessControl import ClassSecurityInfo -from bika.lims import api -from bika.lims import bikaMessageFactory as _ -from bika.lims.browser.fields import DurationField -from bika.lims.browser.fields import UIDReferenceField -from bika.lims.browser.widgets.durationwidget import DurationWidget -from bika.lims.browser.widgets.recordswidget import RecordsWidget -from bika.lims.browser.widgets.referencewidget import ReferenceWidget -from bika.lims.config import ATTACHMENT_OPTIONS -from bika.lims.config import SERVICE_POINT_OF_CAPTURE -from bika.lims.content.bikaschema import BikaSchema -from bika.lims.interfaces import IBaseAnalysis, ISubmitted -from bika.lims.permissions import FieldEditAnalysisHidden -from bika.lims.permissions import FieldEditAnalysisRemarks -from bika.lims.permissions import FieldEditAnalysisResult -from bika.lims.utils import to_utf8 as _c +from Products.ATExtensions.ateapi import RecordsField from Products.Archetypes.BaseContent import BaseContent from Products.Archetypes.Field import BooleanField from Products.Archetypes.Field import FixedPointField @@ -42,18 +28,35 @@ from Products.Archetypes.Field import StringField from Products.Archetypes.Field import TextField from Products.Archetypes.Schema import Schema -from Products.Archetypes.utils import DisplayList -from Products.Archetypes.utils import IntDisplayList from Products.Archetypes.Widget import BooleanWidget from Products.Archetypes.Widget import DecimalWidget from Products.Archetypes.Widget import IntegerWidget from Products.Archetypes.Widget import SelectionWidget from Products.Archetypes.Widget import StringWidget -from Products.ATExtensions.ateapi import RecordsField +from Products.Archetypes.utils import DisplayList +from Products.Archetypes.utils import IntDisplayList from Products.CMFCore.permissions import View from Products.CMFCore.utils import getToolByName from zope.interface import implements +from bika.lims import api +from bika.lims import bikaMessageFactory as _ +from bika.lims.browser.fields import DurationField +from bika.lims.browser.fields import UIDReferenceField +from bika.lims.browser.widgets.durationwidget import DurationWidget +from bika.lims.browser.widgets.recordswidget import RecordsWidget +from bika.lims.browser.widgets.referencewidget import ReferenceWidget +from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG +from bika.lims.config import ATTACHMENT_OPTIONS +from bika.lims.config import SERVICE_POINT_OF_CAPTURE +from bika.lims.content.bikaschema import BikaSchema +from bika.lims.interfaces import IBaseAnalysis +from bika.lims.interfaces import IHaveDepartment +from bika.lims.permissions import FieldEditAnalysisHidden +from bika.lims.permissions import FieldEditAnalysisRemarks +from bika.lims.permissions import FieldEditAnalysisResult +from bika.lims.utils import to_utf8 as _c + # Anywhere that there just isn't space for unpredictably long names, # this value will be used instead. It's set on the AnalysisService, # but accessed on all analysis objects. @@ -477,13 +480,16 @@ schemata="Description", required=0, allowed_types=('Department',), - vocabulary='getDepartments', widget=ReferenceWidget( - checkbox_bound=0, label=_("Department"), description=_("The laboratory department"), - catalog_name='bika_setup_catalog', - base_query={'is_active': True}, + showOn=True, + catalog_name=SETUP_CATALOG, + base_query=dict( + is_active=True, + sort_on="sortable_title", + sort_order="ascending", + ), ) ) @@ -744,7 +750,7 @@ class AbstractBaseAnalysis(BaseContent): # TODO BaseContent? is really needed? - implements(IBaseAnalysis) + implements(IBaseAnalysis, IHaveDepartment) security = ClassSecurityInfo() schema = schema displayContentsTab = False @@ -848,20 +854,6 @@ def getAnalysisCategories(self): items.sort(lambda x, y: cmp(x[1], y[1])) return DisplayList(list(items)) - @security.public - def getDepartments(self): - """A vocabulary listing available (and activated) departments. - """ - bsc = getToolByName(self, 'bika_setup_catalog') - items = [('', '')] + [(o.UID, o.Title) for o in - bsc(portal_type='Department', - is_active=True)] - o = self.getDepartment() - if o and o.UID() not in [i[0] for i in items]: - items.append((o.UID(), o.Title())) - items.sort(lambda x, y: cmp(x[1], y[1])) - return DisplayList(list(items)) - @security.public def getLowerDetectionLimit(self): """Returns the Lower Detection Limit for this service as a floatable diff --git a/bika/lims/content/analysiscategory.py b/bika/lims/content/analysiscategory.py index aacd325b19..455f1071d2 100644 --- a/bika/lims/content/analysiscategory.py +++ b/bika/lims/content/analysiscategory.py @@ -18,62 +18,83 @@ # Copyright 2018-2019 by it's authors. # Some rights reserved, see README and LICENSE. -"""Analysis Category - the category of the analysis service -""" - import transaction from AccessControl import ClassSecurityInfo -from Products.Archetypes.public import * +from Products.Archetypes.Field import FloatField +from Products.Archetypes.Field import ReferenceField +from Products.Archetypes.Field import TextField +from Products.Archetypes.Schema import Schema +from Products.Archetypes.Widget import DecimalWidget +from Products.Archetypes.Widget import TextAreaWidget +from Products.Archetypes.public import BaseContent +from Products.Archetypes.public import registerType from Products.Archetypes.references import HoldingReference from Products.CMFCore.WorkflowCore import WorkflowException -from Products.CMFCore.utils import getToolByName +from zope.interface import implements + +from bika.lims import api from bika.lims import bikaMessageFactory as _ +from bika.lims.browser.widgets import ReferenceWidget +from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from bika.lims.interfaces import IAnalysisCategory, IDeactivable -from zope.interface import implements +from bika.lims.interfaces import IAnalysisCategory +from bika.lims.interfaces import IDeactivable +from bika.lims.interfaces import IHaveDepartment -schema = BikaSchema.copy() + Schema(( - TextField( - 'Comments', - default_output_type='text/plain', - allowable_content_types=('text/plain',), - widget=TextAreaWidget( - description=_( - "To be displayed below each Analysis Category section on " - "results reports."), - label=_("Comments")), - ), - ReferenceField( - 'Department', - required=1, - vocabulary='getDepartments', - allowed_types=('Department',), - relationship='AnalysisCategoryDepartment', - referenceClass=HoldingReference, - widget=ReferenceWidget( - checkbox_bound=0, - label=_("Department"), - description=_("The laboratory department"), - ), - ), - FloatField( - 'SortKey', - validators=('SortKeyValidator',), - widget=DecimalWidget( - label=_("Sort Key"), - description=_( - "Float value from 0.0 - 1000.0 indicating the sort " - "order. Duplicate values are ordered alphabetically."), - ), +Comments = TextField( + "Comments", + default_output_type="text/plain", + allowable_content_types=("text/plain",), + widget=TextAreaWidget( + description=_( + "To be displayed below each Analysis Category section on results " + "reports."), + label=_("Comments")), +) + +Department = ReferenceField( + "Department", + required=1, + allowed_types=("Department",), + relationship="AnalysisCategoryDepartment", + referenceClass=HoldingReference, + widget=ReferenceWidget( + label=_("Department"), + description=_("The laboratory department"), + showOn=True, + catalog_name=SETUP_CATALOG, + base_query={ + "is_active": True, + "sort_on": "sortable_title", + "sort_order": "ascending" + }, + ) +) + +SortKey = FloatField( + "SortKey", + validators=("SortKeyValidator",), + widget=DecimalWidget( + label=_("Sort Key"), + description=_( + "Float value from 0.0 - 1000.0 indicating the sort order. " + "Duplicate values are ordered alphabetically."), ), +) + +schema = BikaSchema.copy() + Schema(( + Comments, + Department, + SortKey, )) + schema['description'].widget.visible = True schema['description'].schemata = 'default' class AnalysisCategory(BaseContent): - implements(IAnalysisCategory, IDeactivable) + implements(IAnalysisCategory, IHaveDepartment, IDeactivable) security = ClassSecurityInfo() displayContentsTab = False schema = schema @@ -84,20 +105,12 @@ def _renameAfterCreation(self, check_auto_id=False): from bika.lims.idserver import renameAfterCreation renameAfterCreation(self) - def getDepartments(self): - bsc = getToolByName(self, 'bika_setup_catalog') - deps = [] - for d in bsc(portal_type='Department', - is_active=True): - deps.append((d.UID, d.Title)) - return DisplayList(deps) - def workflow_script_deactivate(self): # A instance cannot be deactivated if it contains services - pu = getToolByName(self, 'plone_utils') - bsc = getToolByName(self, 'bika_setup_catalog') - ars = bsc(portal_type='AnalysisService', getCategoryUID=self.UID()) - if ars: + query = dict(portal_type="AnalysisService", getCategoryUID=self.UID()) + brains = api.search(query) + if brains: + pu = api.get_tool("plone_utils") message = _("Category cannot be deactivated because it contains " "Analysis Services") pu.addPortalMessage(message, 'error') diff --git a/bika/lims/content/analysisspec.py b/bika/lims/content/analysisspec.py index 4a3fccc4f1..e7c2894e0b 100644 --- a/bika/lims/content/analysisspec.py +++ b/bika/lims/content/analysisspec.py @@ -23,17 +23,16 @@ from Products.ATExtensions.field.records import RecordsField from Products.Archetypes import atapi from Products.Archetypes.public import BaseFolder -from Products.Archetypes.public import ReferenceWidget from Products.Archetypes.public import Schema -from Products.Archetypes.utils import DisplayList from Products.CMFPlone.utils import safe_unicode from zope.i18n import translate from zope.interface import implements -from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims.browser.fields import UIDReferenceField from bika.lims.browser.widgets import AnalysisSpecificationWidget +from bika.lims.browser.widgets import ReferenceWidget +from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.content.clientawaremixin import ClientAwareMixin @@ -45,11 +44,17 @@ UIDReferenceField( 'SampleType', - vocabulary="getSampleTypes", allowed_types=('SampleType',), + required=1, widget=ReferenceWidget( - checkbox_bound=0, label=_("Sample Type"), + showOn=True, + catalog_name=SETUP_CATALOG, + base_query=dict( + is_active=True, + sort_on="sortable_title", + sort_order="ascending" + ), ), ), @@ -127,7 +132,6 @@ def Title(self): """ Return the title if possible, else return the Sample type. Fall back on the instance's ID if there's no sample type or title. """ - title = '' if self.title: title = self.title else: @@ -141,8 +145,7 @@ def contextual_title(self): else: return self.title + " (" + translate(_("Client")) + ")" - security.declarePublic('getResultsRangeDict') - + @security.public def getResultsRangeDict(self): """Return a dictionary with the specification fields for each service. The keys of the dictionary are the keywords of each @@ -163,27 +166,6 @@ def getResultsRangeDict(self): specs[keyword][key] = spec.get(key, '') return specs - security.declarePublic('getRemainingSampleTypes') - - def getSampleTypes(self, active_only=True): - """Return all sampletypes - """ - catalog = api.get_tool("bika_setup_catalog") - query = { - "portal_type": "SampleType", - # N.B. The `sortable_title` index sorts case sensitive. Since there - # is no sort key for sample types, it makes more sense to sort - # them alphabetically in the selection - "sort_on": "title", - "sort_order": "ascending" - } - results = catalog(query) - if active_only: - results = filter(api.is_active, results) - sampletypes = map( - lambda brain: (brain.UID, brain.Title), results) - return DisplayList(sampletypes) - atapi.registerType(AnalysisSpec, PROJECTNAME) diff --git a/bika/lims/content/department.py b/bika/lims/content/department.py index 39a42ef0f5..9bfd6e6d61 100644 --- a/bika/lims/content/department.py +++ b/bika/lims/content/department.py @@ -18,58 +18,53 @@ # Copyright 2018-2019 by it's authors. # Some rights reserved, see README and LICENSE. -"""Department - the department in the laboratory. -""" -from Products.Archetypes.public import * +from AccessControl import ClassSecurityInfo +from Products.Archetypes.public import BaseContent +from Products.Archetypes.public import ReferenceField +from Products.Archetypes.public import Schema +from Products.Archetypes.public import registerType from Products.Archetypes.references import HoldingReference -from Products.CMFCore.utils import getToolByName +from zope.interface import implements + +from bika.lims import bikaMessageFactory as _ +from bika.lims.browser.widgets import ReferenceWidget +from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema -from AccessControl import ClassSecurityInfo -import sys -from bika.lims import bikaMessageFactory as _ -from bika.lims.utils import t -from zope.interface import implements -from bika.lims.interfaces import IDepartment, IDeactivable +from bika.lims.interfaces import IDeactivable +from bika.lims.interfaces import IDepartment -schema = BikaSchema.copy() + Schema(( - ReferenceField('Manager', - vocabulary = 'getContacts', - vocabulary_display_path_bound = sys.maxint, - allowed_types = ('LabContact',), - referenceClass = HoldingReference, - relationship = 'DepartmentLabContact', - widget = ReferenceWidget( - checkbox_bound = 0, - label=_("Manager"), - description = _( - "Select a manager from the available personnel configured under the " - "'lab contacts' setup item. Departmental managers are referenced on " - "analysis results reports containing analyses by their department."), - ), - ), - ComputedField('ManagerName', - expression = "context.getManager() and context.getManager().getFullname() or ''", - widget = ComputedWidget( - visible = False, - ), - ), - ComputedField('ManagerPhone', - expression = "context.getManager() and context.getManager().getBusinessPhone() or ''", - widget = ComputedWidget( - visible = False, - ), - ), - ComputedField('ManagerEmail', - expression = "context.getManager() and context.getManager().getEmailAddress() or ''", - widget = ComputedWidget( - visible = False, +Manager = ReferenceField( + 'Manager', + required=1, + allowed_types=('LabContact',), + referenceClass=HoldingReference, + relationship="DepartmentLabContact", + widget=ReferenceWidget( + label=_("Manager"), + description=_( + "Select a manager from the available personnel configured under " + "the 'lab contacts' setup item. Departmental managers are " + "referenced on analysis results reports containing analyses by " + "their department."), + showOn=True, + catalog_name=SETUP_CATALOG, + base_query=dict( + is_active=True, + sort_on="sortable_title", + sort_order="ascending", ), ), +) + +schema = BikaSchema.copy() + Schema(( + Manager, )) + schema['description'].widget.visible = True schema['description'].schemata = 'default' + class Department(BaseContent): implements(IDepartment, IDeactivable) security = ClassSecurityInfo() @@ -77,8 +72,10 @@ class Department(BaseContent): schema = schema _at_rename_after_creation = True + def _renameAfterCreation(self, check_auto_id=False): from bika.lims.idserver import renameAfterCreation renameAfterCreation(self) + registerType(Department, PROJECTNAME) diff --git a/bika/lims/content/instrument.py b/bika/lims/content/instrument.py index bfa8381e89..7a871ac224 100644 --- a/bika/lims/content/instrument.py +++ b/bika/lims/content/instrument.py @@ -84,7 +84,11 @@ widget=ReferenceWidget( label=_("Instrument type"), catalog_name='bika_setup_catalog', - base_query={"is_active": True}, + base_query={ + "is_active": True, + "sort_on": "sortable_title", + "sort_order": "ascending", + }, ), ), diff --git a/bika/lims/content/labcontact.py b/bika/lims/content/labcontact.py index 04d7265c76..034c6e6443 100644 --- a/bika/lims/content/labcontact.py +++ b/bika/lims/content/labcontact.py @@ -28,6 +28,7 @@ from bika.lims.content.contact import Contact from bika.lims.content.person import Person from bika.lims.interfaces import IDeactivable +from bika.lims.interfaces import IHaveDepartment from bika.lims.interfaces import ILabContact from Products.Archetypes import atapi from Products.Archetypes.Field import ImageField @@ -96,7 +97,7 @@ class LabContact(Contact): """A Lab Contact, which can be linked to a System User """ - implements(ILabContact, IDeactivable) + implements(ILabContact, IHaveDepartment, IDeactivable) schema = schema displayContentsTab = False @@ -112,6 +113,14 @@ def Title(self): """ return safe_unicode(self.getFullname()).encode("utf-8") + @security.public + def getDepartment(self): + """Required by IHaveDepartment. Returns the list of departments this + laboratory contact is assigned to plus the default department + """ + departments = self.getDepartments() + [self.getDefaultDepartment()] + return filter(None, list(set(departments))) + @security.public def getDefaultDepartment(self): """Returns the assigned default department diff --git a/bika/lims/controlpanel/bika_analysisservices.py b/bika/lims/controlpanel/bika_analysisservices.py index 18f42764f0..c9334701ae 100644 --- a/bika/lims/controlpanel/bika_analysisservices.py +++ b/bika/lims/controlpanel/bika_analysisservices.py @@ -392,7 +392,7 @@ def folderitem(self, obj, item, index): # Unit unit = obj.getUnit() - item["Unit"] = format_supsub(unit) if unit else "" + item["Unit"] = unit and format_supsub(unit) or "" # Icons after_icons = "" diff --git a/bika/lims/controlpanel/bika_departments.py b/bika/lims/controlpanel/bika_departments.py index 1a156bca5c..4ba7697ecb 100644 --- a/bika/lims/controlpanel/bika_departments.py +++ b/bika/lims/controlpanel/bika_departments.py @@ -130,26 +130,22 @@ def folderitem(self, obj, item, index): item["replace"]["Title"] = get_link(url, value=title) item["Description"] = description + item["Manager"] = "" + item["ManagerPhone"] = "" + item["ManagerEmail"] = "" manager = obj.getManager() - manager_name = obj.getManagerName() - manager_phone = obj.getManagerPhone() - manager_email = obj.getManagerEmail() - if manager: + manager_name = manager.getFullname() item["Manager"] = manager_name - item["replace"]["Manager"] = get_link( - manager.absolute_url(), manager_name) - else: - item["Manager"] = "" - if manager_email: - item["ManagerEmail"] = manager_email + manager_url = manager.absolute_url() + item["replace"]["Manager"] = get_link(manager_url, manager_name) + + manager_email = manager.getEmailAddress() item["replace"]["ManagerEmail"] = get_email_link( manager_email, value=manager_email) - else: - item["ManagerEmail"] = "" - item["ManagerPhone"] = manager_phone + item["ManagerPhone"] = manager.getBusinessPhone() return item @@ -162,25 +158,6 @@ class Departments(ATFolder): displayContentsTab = False schema = schema - def getContacts(self, active_only=True): - catalog = api.get_tool("bika_setup_catalog") - query = { - "portal_type": "LabContact", - "sort_on": "sortable_title", - "sort_order": "ascending" - } - results = catalog(query) - - # XXX Better directly filter in the catalog query as soon as we have - # the active/inactive state in the primary workflow - if active_only: - results = filter(api.is_active, results) - - pairs = map( - lambda brain: (brain.UID, brain.Title), results) - - return DisplayList(pairs) - schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False) atapi.registerType(Departments, PROJECTNAME) diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index fe02607c4a..9b4d748bd7 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -1036,3 +1036,21 @@ def getPrice(self): def getTotalPrice(self): """Returns the total price of the instance """ + + +class IHaveInstrument(Interface): + """Marker interface for objects that have Instrument(s) assigned + """ + + def getInstrument(self): + """Returns the instrument or instruments the instance is assigned to + """ + + +class IHaveDepartment(Interface): + """Marker interface for objects that have Department(s) assigned + """ + + def getDepartment(self): + """Returns the department or departments the instance is assigned to + """ diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 280470c51a..c40cabffee 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -202,6 +202,7 @@ ("bika_setup_catalog", "review_state", "", "FieldIndex"), ("bika_setup_catalog", "sortable_title", "", "FieldIndex"), ("bika_setup_catalog", "title", "", "FieldIndex"), + ("bika_setup_catalog", "department_uid", "", "KeywordIndex"), ("portal_catalog", "Analyst", "", "FieldIndex"), ) diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 6b1399155d..eab1d5e307 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -60,6 +60,8 @@ # Replaces getPointOfCapture ("bika_setup_catalog", "point_of_capture", "FieldIndex"), + # Replaces getDepartmentUID + ("bika_setup_catalog", "department_uid", "KeywordIndex"), ] INDEXES_TO_REMOVE = [ @@ -151,6 +153,9 @@ # getPointOfCapture --> point_of_capture ("bika_setup_catalog", "getPointOfCapture"), + # getDepartmentUID --> department_uid + ("bika_setup_catalog", "getDepartmentUID"), + ] METADATA_TO_REMOVE = [ From 8c2dbbb992bc60bfab458464221b44699ea3a3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 12:20:43 +0100 Subject: [PATCH 68/96] Remove getFullname index and metadata from setup_catalog --- bika/lims/browser/department/labcontacts.py | 2 +- bika/lims/catalog/indexers/configure.zcml | 4 +++ bika/lims/catalog/indexers/contact.py | 28 ++++++++++++++++ bika/lims/content/person.py | 36 --------------------- bika/lims/controlpanel/bika_labcontacts.py | 3 +- bika/lims/setuphandlers.py | 4 +-- bika/lims/upgrade/v01_03_003.py | 17 ++++++++++ 7 files changed, 52 insertions(+), 42 deletions(-) create mode 100644 bika/lims/catalog/indexers/contact.py diff --git a/bika/lims/browser/department/labcontacts.py b/bika/lims/browser/department/labcontacts.py index b482da7795..17bc38e644 100644 --- a/bika/lims/browser/department/labcontacts.py +++ b/bika/lims/browser/department/labcontacts.py @@ -46,7 +46,7 @@ def __init__(self, context, request): } self.columns = { 'Fullname': {'title': _('Name'), - 'index': 'getFullname'}, + 'index': 'fullname'}, 'Department': {'title': _('Department')}, 'BusinessPhone': {'title': _('Phone')}, 'MobilePhone': {'title': _('Mobile Phone')}, diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 53481a12c0..2ad1422134 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -15,6 +15,9 @@ + + + @@ -56,6 +59,7 @@ + diff --git a/bika/lims/catalog/indexers/contact.py b/bika/lims/catalog/indexers/contact.py new file mode 100644 index 0000000000..3cfff8962f --- /dev/null +++ b/bika/lims/catalog/indexers/contact.py @@ -0,0 +1,28 @@ +# -*- 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-2019 by it's authors. +# Some rights reserved, see README and LICENSE. + +from plone.indexer import indexer + +from bika.lims.interfaces import IContact + + +@indexer(IContact) +def sortable_title(instance): + return instance.getFullname().lower() diff --git a/bika/lims/content/person.py b/bika/lims/content/person.py index d03b6f37cf..a23816b6d3 100644 --- a/bika/lims/content/person.py +++ b/bika/lims/content/person.py @@ -253,42 +253,6 @@ def getFullname(self): fullname = '%s %s' % (self.getFirstname(), self.getSurname()) return fullname.strip() - def getListingname(self): - """Person's Fullname as Surname, Firstname - """ - fn = self.getFirstname() - mi = self.getMiddleinitial() - md = self.getMiddlename() - sn = self.getSurname() - fullname = "" - if fn and sn: - fullname = "%s, %s" % ( - self.getSurname(), - self.getFirstname()) - elif fn or sn: - fullname = "%s %s" % ( - self.getSurname(), - self.getFirstname()) - else: - fullname = "" - - if fullname != "": - if mi and md: - fullname = "%s %s %s" % ( - fullname, - self.getMiddleinitial(), - self.getMiddlename()) - elif mi: - fullname = "%s %s" % ( - fullname, - self.getMiddleinitial()) - elif md: - fullname = "%s %s" % ( - fullname, - self.getMiddlename()) - - return fullname.strip() - Title = getFullname @security.protected(CMFCorePermissions.ManagePortal) diff --git a/bika/lims/controlpanel/bika_labcontacts.py b/bika/lims/controlpanel/bika_labcontacts.py index a456b6716b..9d22b1c71f 100644 --- a/bika/lims/controlpanel/bika_labcontacts.py +++ b/bika/lims/controlpanel/bika_labcontacts.py @@ -67,10 +67,9 @@ def __init__(self, context, request): self.pagesize = 25 self.columns = collections.OrderedDict(( - # TODO: Better sort by last name (index required!) ("Fullname", { "title": _("Name"), - "index": "getFullname"}), + "index": "sortable_title"}), ("DefaultDepartment", { "title": _("Default Department"), "toggle": False}), diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index c40cabffee..230e099cdf 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -108,7 +108,7 @@ ("Instrument", ["bika_setup_catalog", "portal_catalog"]), ("InstrumentLocation", ["bika_setup_catalog", "portal_catalog"]), ("InstrumentType", ["bika_setup_catalog", "portal_catalog"]), - ("LabContact", ["bika_setup_catalog", "portal_catalog"]), + ("LabContact", ["bika_setup_catalog"]), ("LabProduct", ["bika_setup_catalog", "portal_catalog"]), ("Manufacturer", ["bika_setup_catalog", "portal_catalog"]), ("Method", ["bika_setup_catalog", "portal_catalog"]), @@ -175,7 +175,6 @@ ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), # Sorting of listings: Analysis Categories ("bika_setup_catalog", "department_title", "", "KeywordIndex"), - ("bika_setup_catalog", "getFullname", "", "FieldIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), # Sorting of listings: Worksheet Templates ("bika_setup_catalog", "instrument_title", "", "KeywordIndex"), @@ -242,7 +241,6 @@ ("bika_setup_catalog", "getCategoryTitle"), ("bika_setup_catalog", "getCategoryUID"), ("bika_setup_catalog", "getClientUID"), - ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "getKeyword"), ("bika_setup_catalog", "getName"), ("bika_setup_catalog", "getSamplePointTitle"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index eab1d5e307..05263ff840 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -22,6 +22,7 @@ from bika.lims import api from bika.lims import logger +from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG from bika.lims.config import PROJECTNAME as product from bika.lims.setuphandlers import setup_form_controller_actions from bika.lims.upgrade import upgradestep @@ -99,6 +100,9 @@ # Only used in analyses listing, but from analysis_catalog ("bika_setup_catalog", "getCalculationUID"), + # Only used for sorting in LabContacts listing. Replaced by sortable_title + ("bika_setup_catalog", "getFullname"), + # Not used anywhere # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getDocumentID"), @@ -203,6 +207,7 @@ ("bika_setup_catalog", "getUnit"), ("bika_setup_catalog", "getPointOfCapture"), ("bika_setup_catalog", "getSamplePointUID"), + ("bika_setup_catalog", "getFullname"), ] @@ -238,6 +243,9 @@ def upgrade(tool): # https://github.com/senaite/senaite.core/pull/1477 reindex_client_fields(portal) + # Some indexes in setup_catalog changed + reindex_labcontact_sortable_title(portal) + # Redirect to worksheets folder when a Worksheet is removed # https://github.com/senaite/senaite.core/pull/1480 setup_form_controller_actions(portal) @@ -278,6 +286,15 @@ def reindex_client_fields(portal): logger.info("Reindexing client fields ... [DONE]") +def reindex_labcontact_sortable_title(portal): + logger.info("Reindexing sortable_title for LabContacts ...") + query = dict(portal_type="LabContact") + for brain in api.search(query, SETUP_CATALOG): + obj = api.get_object(brain) + obj.reindexObject(idxs=["sortable_title"]) + logger.info("Reindexing sortable_title for LabContacts ... [DONE]") + + def remove_stale_indexes(portal): logger.info("Removing stale indexes ...") for catalog, index in INDEXES_TO_REMOVE: From a6a8f91d7a5fe1e143289c7553e5cdb6d3fcc9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 12:44:32 +0100 Subject: [PATCH 69/96] Remove cancellation_sate index/metadata from setup_catalog --- bika/lims/upgrade/v01_03_003.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 05263ff840..297d30a5f2 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -125,6 +125,7 @@ ("bika_setup_catalog", "getVolume"), ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getCategoryTitle"), + ("bika_setup_catalog", "cancellation_state"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -208,6 +209,7 @@ ("bika_setup_catalog", "getPointOfCapture"), ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getFullname"), + ("bika_setup_catalog", "cancellation_state"), ] From ad56a8328a5aad5c774783bd8d20fbb9c4198e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 13:27:52 +0100 Subject: [PATCH 70/96] Remove getName index and metadata from setup_catalog --- bika/lims/content/instrument.py | 21 +++++++++------------ bika/lims/content/organisation.py | 6 ++++++ bika/lims/controlpanel/bika_suppliers.py | 2 +- bika/lims/setuphandlers.py | 2 -- bika/lims/upgrade/v01_03_003.py | 12 ++++++++++++ 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/bika/lims/content/instrument.py b/bika/lims/content/instrument.py index 7a871ac224..43a677426f 100644 --- a/bika/lims/content/instrument.py +++ b/bika/lims/content/instrument.py @@ -83,6 +83,7 @@ required=1, widget=ReferenceWidget( label=_("Instrument type"), + showOn=True, catalog_name='bika_setup_catalog', base_query={ "is_active": True, @@ -107,14 +108,18 @@ ReferenceField( 'Supplier', - vocabulary='getSuppliers', allowed_types=('Supplier',), relationship='InstrumentSupplier', required=1, - widget=SelectionWidget( - format='select', + widget=ReferenceWidget( label=_("Supplier"), - visible={'view': 'invisible', 'edit': 'visible'} + showOn=True, + catalog_name='bika_setup_catalog', + base_query={ + "is_active": True, + "sort_on": "sortable_title", + "sort_order": "ascending", + }, ), ), @@ -428,14 +433,6 @@ def getMethodUIDs(self): uids = [m.UID() for m in self.getMethods()] return uids - def getSuppliers(self): - bsc = getToolByName(self, 'bika_setup_catalog') - items = [(c.UID, c.getName) - for c in bsc(portal_type='Supplier', - is_active=True)] - items.sort(lambda x, y: cmp(x[1], y[1])) - return DisplayList(items) - def _getAvailableMethods(self): """ Returns the available (active) methods. One method can be done by multiple instruments, but one diff --git a/bika/lims/content/organisation.py b/bika/lims/content/organisation.py index 5d61b33443..62a1b122ef 100644 --- a/bika/lims/content/organisation.py +++ b/bika/lims/content/organisation.py @@ -171,6 +171,12 @@ class Organisation(ATFolder): displayContentsTab = False schema = schema + @property + def title(self): + """Return the name of the Organisation + """ + return self.Title() + def Title(self): """Return the name of the Organisation """ diff --git a/bika/lims/controlpanel/bika_suppliers.py b/bika/lims/controlpanel/bika_suppliers.py index 5d4aafa61e..6821639f83 100644 --- a/bika/lims/controlpanel/bika_suppliers.py +++ b/bika/lims/controlpanel/bika_suppliers.py @@ -71,7 +71,7 @@ def __init__(self, context, request): self.columns = collections.OrderedDict(( ("Name", { "title": _("Name"), - "index": "getName"}), + "index": "sortable_title"}), ("Email", { "title": _("Email"), "toggle": True}), diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 230e099cdf..4be7da6969 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -181,7 +181,6 @@ # Sorting of listings: Instruments ("bika_setup_catalog", "instrumenttype_title", "", "KeywordIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), - ("bika_setup_catalog", "getName", "", "FieldIndex"), # Add Sample form to split services in listing ("bika_setup_catalog", "point_of_capture", "", "FieldIndex"), # Sorting of listings: LabProducts @@ -242,7 +241,6 @@ ("bika_setup_catalog", "getCategoryUID"), ("bika_setup_catalog", "getClientUID"), ("bika_setup_catalog", "getKeyword"), - ("bika_setup_catalog", "getName"), ("bika_setup_catalog", "getSamplePointTitle"), ("bika_setup_catalog", "getServiceUID"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 297d30a5f2..50960ddf65 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -126,6 +126,7 @@ ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getCategoryTitle"), ("bika_setup_catalog", "cancellation_state"), + ("bika_setup_catalog", "getName"), # REPLACEMENTS (indexes to be removed because of a replacement) @@ -210,6 +211,7 @@ ("bika_setup_catalog", "getSamplePointUID"), ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "cancellation_state"), + ("bika_setup_catalog", "getName"), ] @@ -247,6 +249,7 @@ def upgrade(tool): # Some indexes in setup_catalog changed reindex_labcontact_sortable_title(portal) + reindex_supplier_titles(portal) # Redirect to worksheets folder when a Worksheet is removed # https://github.com/senaite/senaite.core/pull/1480 @@ -297,6 +300,15 @@ def reindex_labcontact_sortable_title(portal): logger.info("Reindexing sortable_title for LabContacts ... [DONE]") +def reindex_supplier_titles(portal): + logger.info("Reindexing title indexes for Suppliers ...") + query = dict(portal_type="Supplier") + for brain in api.search(query, SETUP_CATALOG): + obj = api.get_object(brain) + obj.reindexObject(idxs=["title", "sortable_title"]) + logger.info("Reindexing title indexes for Suppliers ... [DONE]") + + def remove_stale_indexes(portal): logger.info("Removing stale indexes ...") for catalog, index in INDEXES_TO_REMOVE: From df06c8063b69363c9f0d71ab055d6d8ead49cf1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 13:35:23 +0100 Subject: [PATCH 71/96] Use ReferenceWidget for Manufacturer and Location in INstrument --- bika/lims/content/instrument.py | 43 ++++++++++++--------------------- bika/lims/upgrade/v01_03_003.py | 8 +++--- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/bika/lims/content/instrument.py b/bika/lims/content/instrument.py index 43a677426f..d19047a9ec 100644 --- a/bika/lims/content/instrument.py +++ b/bika/lims/content/instrument.py @@ -95,14 +95,18 @@ ReferenceField( 'Manufacturer', - vocabulary='getManufacturers', allowed_types=('Manufacturer',), relationship='InstrumentManufacturer', required=1, - widget=SelectionWidget( - format='select', + widget=ReferenceWidget( label=_("Manufacturer"), - visible={'view': 'invisible', 'edit': 'visible'} + showOn=True, + catalog_name='bika_setup_catalog', + base_query={ + "is_active": True, + "sort_on": "sortable_title", + "sort_order": "ascending", + }, ), ), @@ -313,17 +317,19 @@ ReferenceField( 'InstrumentLocation', schemata='Additional info.', - vocabulary='getInstrumentLocations', allowed_types=('InstrumentLocation', ), relationship='InstrumentInstrumentLocation', required=0, - widget=SelectionWidget( - format='select', + widget=ReferenceWidget( label=_("Instrument Location"), - label_msgid="instrument_location", description=_("The room and location where the instrument is installed"), - description_msgid="help_instrument_location", - visible={'view': 'invisible', 'edit': 'visible'} + showOn=True, + catalog_name='bika_setup_catalog', + base_query={ + "is_active": True, + "sort_on": "sortable_title", + "sort_order": "ascending", + }, ) ), @@ -419,14 +425,6 @@ def getMaintenanceTypesList(self): def getCalibrationAgentsList(self): return getCalibrationAgents(self) - def getManufacturers(self): - bsc = getToolByName(self, 'bika_setup_catalog') - items = [(c.UID, c.Title) - for c in bsc(portal_type='Manufacturer', - is_active=True)] - items.sort(lambda x, y: cmp(x[1], y[1])) - return DisplayList(items) - def getMethodUIDs(self): uids = [] if self.getMethods(): @@ -446,15 +444,6 @@ def _getAvailableMethods(self): items.insert(0, ('', t(_('None')))) return DisplayList(items) - def getInstrumentLocations(self): - bsc = getToolByName(self, 'bika_setup_catalog') - items = [(c.UID, c.Title) - for c in bsc(portal_type='InstrumentLocation', - is_active=True)] - items.sort(lambda x, y: cmp(x[1], y[1])) - items.insert(0, ('', t(_('None')))) - return DisplayList(items) - def getMaintenanceTasks(self): return self.objectValues('InstrumentMaintenanceTask') diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 50960ddf65..1c64b62568 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -249,7 +249,7 @@ def upgrade(tool): # Some indexes in setup_catalog changed reindex_labcontact_sortable_title(portal) - reindex_supplier_titles(portal) + reindex_supplier_manufacturers_titles(portal) # Redirect to worksheets folder when a Worksheet is removed # https://github.com/senaite/senaite.core/pull/1480 @@ -300,13 +300,13 @@ def reindex_labcontact_sortable_title(portal): logger.info("Reindexing sortable_title for LabContacts ... [DONE]") -def reindex_supplier_titles(portal): - logger.info("Reindexing title indexes for Suppliers ...") +def reindex_supplier_manufacturers_titles(portal): + logger.info("Reindexing title indexes for Suppliers and Manufacturers ...") query = dict(portal_type="Supplier") for brain in api.search(query, SETUP_CATALOG): obj = api.get_object(brain) obj.reindexObject(idxs=["title", "sortable_title"]) - logger.info("Reindexing title indexes for Suppliers ... [DONE]") + logger.info("Reindexing title indexes for Suppliers and Manufacturers ... [DONE]") def remove_stale_indexes(portal): From 6b878613decbe0a2f23c0e6fc73127a7b3887f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 18:55:38 +0100 Subject: [PATCH 72/96] Remove getServiceUIDs index from setup_catalog --- bika/lims/setuphandlers.py | 1 - bika/lims/upgrade/v01_03_003.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 4be7da6969..6025f1fa54 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -192,7 +192,6 @@ # Filter in Add2: Sample Points, Specifications, Templates ("bika_setup_catalog", "sampletype_uid", "", "KeywordIndex"), ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), - ("bika_setup_catalog", "getServiceUIDs", "", "KeywordIndex"), ("bika_setup_catalog", "id", "getId", "FieldIndex"), ("bika_setup_catalog", "is_active", "", "BooleanIndex"), ("bika_setup_catalog", "path", "getPhysicalPath", "ExtendedPathIndex"), diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index 1c64b62568..f01334bb2d 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -127,6 +127,7 @@ ("bika_setup_catalog", "getCategoryTitle"), ("bika_setup_catalog", "cancellation_state"), ("bika_setup_catalog", "getName"), + ("bika_setup_catalog", "getServiceUIDs"), # REPLACEMENTS (indexes to be removed because of a replacement) From ad6586e5e3314415e063da12a4b151808f4c9623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 19:06:09 +0100 Subject: [PATCH 73/96] Remove getServiceUID index and metadata from setup_catalog --- bika/lims/upgrade/v01_03_003.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index f01334bb2d..d4c3d12d81 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -103,6 +103,9 @@ # Only used for sorting in LabContacts listing. Replaced by sortable_title ("bika_setup_catalog", "getFullname"), + # Used in analysis_catalog, but not in setup_catalog + ("bika_setup_catalog", "getServiceUID"), + # Not used anywhere # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getDocumentID"), @@ -213,6 +216,7 @@ ("bika_setup_catalog", "getFullname"), ("bika_setup_catalog", "cancellation_state"), ("bika_setup_catalog", "getName"), + ("bika_setup_catalog", "getServiceUID"), ] From f954c140309f337617729d7a0f30e9096c6e3cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 19:09:27 +0100 Subject: [PATCH 74/96] Forgot to remove getServiceUID from setuphandlers --- bika/lims/setuphandlers.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 6025f1fa54..858362aae3 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -191,7 +191,6 @@ ("bika_setup_catalog", "sampletype_title", "", "KeywordIndex"), # Filter in Add2: Sample Points, Specifications, Templates ("bika_setup_catalog", "sampletype_uid", "", "KeywordIndex"), - ("bika_setup_catalog", "getServiceUID", "", "FieldIndex"), ("bika_setup_catalog", "id", "getId", "FieldIndex"), ("bika_setup_catalog", "is_active", "", "BooleanIndex"), ("bika_setup_catalog", "path", "getPhysicalPath", "ExtendedPathIndex"), @@ -241,7 +240,6 @@ ("bika_setup_catalog", "getClientUID"), ("bika_setup_catalog", "getKeyword"), ("bika_setup_catalog", "getSamplePointTitle"), - ("bika_setup_catalog", "getServiceUID"), ("portal_catalog", "Analyst"), ) From 31d4f893994f73c9a1cea4574816b91ffa2eab93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 19:27:00 +0100 Subject: [PATCH 75/96] Added generic listing_searchable_text for setup_catalog --- bika/lims/catalog/indexers/__init__.py | 33 ++++++++++++++--------- bika/lims/catalog/indexers/bikasetup.py | 13 ++++++++- bika/lims/catalog/indexers/configure.zcml | 4 +++ bika/lims/setuphandlers.py | 1 + bika/lims/upgrade/v01_03_003.py | 4 +++ 5 files changed, 41 insertions(+), 14 deletions(-) diff --git a/bika/lims/catalog/indexers/__init__.py b/bika/lims/catalog/indexers/__init__.py index 8f094b0543..3d8efdff19 100644 --- a/bika/lims/catalog/indexers/__init__.py +++ b/bika/lims/catalog/indexers/__init__.py @@ -66,19 +66,7 @@ def listing_searchable_text(instance): wildcard searches :return: all metadata values joined in a string """ - entries = set() - catalog = api.get_tool(BIKA_CATALOG) - metadata = get_metadata_for(instance, catalog) - for key, brain_value in metadata.items(): - instance_value = api.safe_getattr(instance, key, None) - parsed = api.to_searchable_text_metadata(brain_value or instance_value) - entries.add(parsed) - - # Remove empties - entries = filter(None, entries) - - # Concatenate all strings to one text blob - return " ".join(entries) + return generic_listing_searchable_text(instance, BIKA_CATALOG) def get_metadata_for(instance, catalog): @@ -91,3 +79,22 @@ def get_metadata_for(instance, catalog): logger.warn("Cannot get metadata from {}. Path not found: {}" .format(catalog.id, path)) return {} + + +def generic_listing_searchable_text(instance, catalog_name): + """Retrieves all the values of metadata columns in the catalog for + wildcard searches + """ + entries = set() + catalog = api.get_tool(catalog_name) + metadata = get_metadata_for(instance, catalog) + for key, brain_value in metadata.items(): + instance_value = api.safe_getattr(instance, key, None) + parsed = api.to_searchable_text_metadata(brain_value or instance_value) + entries.add(parsed) + + # Remove empties + entries = filter(None, entries) + + # Concatenate all strings to one text blob + return " ".join(entries) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index cea67b8b0d..b112eda688 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -17,10 +17,12 @@ # # Copyright 2018-2019 by it's authors. # Some rights reserved, see README and LICENSE. - +from Products.Archetypes.interfaces import IBaseObject from plone.indexer import indexer from bika.lims import api +from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG +from bika.lims.catalog.indexers import generic_listing_searchable_text from bika.lims.interfaces import IAnalysisService from bika.lims.interfaces import IBikaSetupCatalog from bika.lims.interfaces import IHaveDepartment @@ -125,6 +127,15 @@ def point_of_capture(instance): return instance.getPointOfCapture() +@indexer(IBaseObject, IBikaSetupCatalog) +def listing_searchable_text(instance): + """ Retrieves all the values of metadata columns in the catalog for + wildcard searches + :return: all metadata values joined in a string + """ + return generic_listing_searchable_text(instance, SETUP_CATALOG) + + def to_keywords_list(obj, func): if isinstance(obj, (list, tuple)): return map(func, obj) diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 2ad1422134..a0cd41b2f8 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -59,6 +59,10 @@ + + + + diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 858362aae3..7d3940971e 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -199,6 +199,7 @@ ("bika_setup_catalog", "sortable_title", "", "FieldIndex"), ("bika_setup_catalog", "title", "", "FieldIndex"), ("bika_setup_catalog", "department_uid", "", "KeywordIndex"), + ("bika_setup_catalog", "listing_searchable_text", "", "TextIndexNG3"), ("portal_catalog", "Analyst", "", "FieldIndex"), ) diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index d4c3d12d81..a9549ea66a 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -63,6 +63,9 @@ # Replaces getDepartmentUID ("bika_setup_catalog", "department_uid", "KeywordIndex"), + + # Default listing_searchable_text index adapter for setup_catalog + ("bika_setup_catalog", "listing_searchable_text", "TextIndexNG3"), ] INDEXES_TO_REMOVE = [ @@ -131,6 +134,7 @@ ("bika_setup_catalog", "cancellation_state"), ("bika_setup_catalog", "getName"), ("bika_setup_catalog", "getServiceUIDs"), + ("bika_setup_catalog", "SearchableText"), # REPLACEMENTS (indexes to be removed because of a replacement) From da2a64aaff7c8467a191c138cb1fffcf81f04768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 20:05:29 +0100 Subject: [PATCH 76/96] Comments cleanup (creation of indexers/README.md) --- bika/lims/catalog/indexers/README.md | 55 +++++++++++++++ bika/lims/catalog/indexers/configure.zcml | 84 ++++++++--------------- bika/lims/setuphandlers.py | 31 +++------ 3 files changed, 94 insertions(+), 76 deletions(-) create mode 100644 bika/lims/catalog/indexers/README.md diff --git a/bika/lims/catalog/indexers/README.md b/bika/lims/catalog/indexers/README.md new file mode 100644 index 0000000000..cfa64c65be --- /dev/null +++ b/bika/lims/catalog/indexers/README.md @@ -0,0 +1,55 @@ +# Indexes + +## Generic indexes + +- **`is_active`**: Whether the object is neither cancelled nor invalid +- **`listing_searchable_text`**: Wildcard searches in listings +- **`sortable_title`**: Default case-insensitive sorting + +## Catalog-specific + +### bika_setup_catalog + +- **`department_title`**: Sorting of Analyses Categories listing +- **`instrument_title`**: Sorting of Worksheet Templates listing by Instrument +- **`instrumenttype_title`**: Sorting of Instruments listing +- **`method_available_uid`**: Filtering of services in Worksheet's Add Analyses +View for when the Worksheet Template being used has a Method assigned +- **`point_of_capture`**: To split analyses services listing in Add Sample Form +- **`price`**: Sorting of Lab Products listing +- **`price_total`**: Sorting of Lab Products listing +- **`sampletype_title`**: Used for sorting of listings (Sample Points, +Specifications and Templates) +- **`sample_type_uid`**: Used in Add Sample form to filter Sample Points, +Specifications and Templates when a Sample Type is selected. + +## Content-specific + +### AnalysisCategory + +- **`sortable_title`**: Case-insensitive + sortkey for default sorting + +### AnalysisRequest + +- **`assigned_state`**: Whether all analyses have been assigned or not +- **`getAncestorsUIDs`**: Partitions' analyses masking in searches +- **`is_received`**: Whether the Analysis Request has been received +- **`listing_searchable_text`**: Wildcard searches, including partitions + +### BaseAnalysis + +- **`sortable_title`**: Case-insensitive + sortkey for default sorting + +### IContact (LabContact, Contact) + +- **`sortable_title`**: Case-insenstive contact's fullname for default sorting + + + + + + + + + + diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index a0cd41b2f8..65879e6640 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -2,67 +2,27 @@ xmlns="http://namespaces.zope.org/zope" i18n_domain="senaite.core"> - - - - - - - - - - - - - - - + - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - + + - - + + + + + + @@ -73,5 +33,19 @@ + + + + + + + + + + + + + + diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 7d3940971e..5a66cb8e3f 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -138,7 +138,6 @@ ("bika_catalog", "UID", "", "FieldIndex"), ("bika_catalog", "allowedRolesAndUsers", "", "KeywordIndex"), ("bika_catalog", "created", "", "DateIndex"), - # Filter ReferenceSamples in AddControl and AddBlank views from Worksheet ("bika_catalog", "getBlank", "", "BooleanIndex"), ("bika_catalog", "getClientBatchID", "", "FieldIndex"), ("bika_catalog", "getClientID", "", "FieldIndex"), @@ -168,38 +167,28 @@ ("bika_setup_catalog", "UID", "", "FieldIndex"), ("bika_setup_catalog", "allowedRolesAndUsers", "", "KeywordIndex"), ("bika_setup_catalog", "created", "", "DateIndex"), - # Filter services in Worksheet's Add Analyses View for when the Worksheet - # Template being used has a Method assigned - ("bika_setup_catalog", "method_available_uid", "", "KeywordIndex"), + ("bika_setup_catalog", "department_title", "", "KeywordIndex"), + ("bika_setup_catalog", "department_uid", "", "KeywordIndex"), ("bika_setup_catalog", "getCategoryUID", "", "FieldIndex"), ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), - # Sorting of listings: Analysis Categories - ("bika_setup_catalog", "department_title", "", "KeywordIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), - # Sorting of listings: Worksheet Templates + ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), + ("bika_setup_catalog", "id", "getId", "FieldIndex"), ("bika_setup_catalog", "instrument_title", "", "KeywordIndex"), - # Sorting of listings: Instruments ("bika_setup_catalog", "instrumenttype_title", "", "KeywordIndex"), - ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), - # Add Sample form to split services in listing + ("bika_setup_catalog", "is_active", "", "BooleanIndex"), + ("bika_setup_catalog", "listing_searchable_text", "", "TextIndexNG3"), + ("bika_setup_catalog", "method_available_uid", "", "KeywordIndex"), + ("bika_setup_catalog", "path", "getPhysicalPath", "ExtendedPathIndex"), ("bika_setup_catalog", "point_of_capture", "", "FieldIndex"), - # Sorting of listings: LabProducts + ("bika_setup_catalog", "portal_type", "", "FieldIndex"), ("bika_setup_catalog", "price", "", "FieldIndex"), - # Sorting of listings: LabProducts ("bika_setup_catalog", "price_total", "", "FieldIndex"), - # Sorting of listings: Sample Points, Specifications + ("bika_setup_catalog", "review_state", "", "FieldIndex"), ("bika_setup_catalog", "sampletype_title", "", "KeywordIndex"), - # Filter in Add2: Sample Points, Specifications, Templates ("bika_setup_catalog", "sampletype_uid", "", "KeywordIndex"), - ("bika_setup_catalog", "id", "getId", "FieldIndex"), - ("bika_setup_catalog", "is_active", "", "BooleanIndex"), - ("bika_setup_catalog", "path", "getPhysicalPath", "ExtendedPathIndex"), - ("bika_setup_catalog", "portal_type", "", "FieldIndex"), - ("bika_setup_catalog", "review_state", "", "FieldIndex"), ("bika_setup_catalog", "sortable_title", "", "FieldIndex"), ("bika_setup_catalog", "title", "", "FieldIndex"), - ("bika_setup_catalog", "department_uid", "", "KeywordIndex"), - ("bika_setup_catalog", "listing_searchable_text", "", "TextIndexNG3"), ("portal_catalog", "Analyst", "", "FieldIndex"), ) From bac11cb67681e6bf841f898e885afb4acb6a7a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 20:06:32 +0100 Subject: [PATCH 77/96] Missed to remove getSamplePointTitle from setup_handlers --- bika/lims/setuphandlers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 5a66cb8e3f..a80c5d90d8 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -229,7 +229,6 @@ ("bika_setup_catalog", "getCategoryUID"), ("bika_setup_catalog", "getClientUID"), ("bika_setup_catalog", "getKeyword"), - ("bika_setup_catalog", "getSamplePointTitle"), ("portal_catalog", "Analyst"), ) From a219af61e910bfa62a1143ebecd5b99d089913ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 20:07:52 +0100 Subject: [PATCH 78/96] Remove boldies --- bika/lims/catalog/indexers/README.md | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/bika/lims/catalog/indexers/README.md b/bika/lims/catalog/indexers/README.md index cfa64c65be..7eca401f3f 100644 --- a/bika/lims/catalog/indexers/README.md +++ b/bika/lims/catalog/indexers/README.md @@ -2,47 +2,47 @@ ## Generic indexes -- **`is_active`**: Whether the object is neither cancelled nor invalid -- **`listing_searchable_text`**: Wildcard searches in listings -- **`sortable_title`**: Default case-insensitive sorting +- `is_active`: Whether the object is neither cancelled nor invalid +- `listing_searchable_text`: Wildcard searches in listings +- `sortable_title`: Default case-insensitive sorting ## Catalog-specific ### bika_setup_catalog -- **`department_title`**: Sorting of Analyses Categories listing -- **`instrument_title`**: Sorting of Worksheet Templates listing by Instrument -- **`instrumenttype_title`**: Sorting of Instruments listing -- **`method_available_uid`**: Filtering of services in Worksheet's Add Analyses +- `department_title`: Sorting of Analyses Categories listing +- `instrument_title`: Sorting of Worksheet Templates listing by Instrument +- `instrumenttype_title`: Sorting of Instruments listing +- `method_available_uid`: Filtering of services in Worksheet's Add Analyses View for when the Worksheet Template being used has a Method assigned -- **`point_of_capture`**: To split analyses services listing in Add Sample Form -- **`price`**: Sorting of Lab Products listing -- **`price_total`**: Sorting of Lab Products listing -- **`sampletype_title`**: Used for sorting of listings (Sample Points, +- `point_of_capture`: To split analyses services listing in Add Sample Form +- `price`: Sorting of Lab Products listing +- `price_total`: Sorting of Lab Products listing +- `sampletype_title`: Used for sorting of listings (Sample Points, Specifications and Templates) -- **`sample_type_uid`**: Used in Add Sample form to filter Sample Points, +- `sample_type_uid`: Used in Add Sample form to filter Sample Points, Specifications and Templates when a Sample Type is selected. ## Content-specific ### AnalysisCategory -- **`sortable_title`**: Case-insensitive + sortkey for default sorting +- `sortable_title`: Case-insensitive + sortkey for default sorting ### AnalysisRequest -- **`assigned_state`**: Whether all analyses have been assigned or not -- **`getAncestorsUIDs`**: Partitions' analyses masking in searches -- **`is_received`**: Whether the Analysis Request has been received -- **`listing_searchable_text`**: Wildcard searches, including partitions +- `assigned_state`: Whether all analyses have been assigned or not +- `getAncestorsUIDs`: Partitions' analyses masking in searches +- `is_received`: Whether the Analysis Request has been received +- `listing_searchable_text`: Wildcard searches, including partitions ### BaseAnalysis -- **`sortable_title`**: Case-insensitive + sortkey for default sorting +- `sortable_title`: Case-insensitive + sortkey for default sorting ### IContact (LabContact, Contact) -- **`sortable_title`**: Case-insenstive contact's fullname for default sorting +- `sortable_title`: Case-insenstive contact's fullname for default sorting From 717a910c329e3c21671915ebb82b2473aec4b5db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 21:16:21 +0100 Subject: [PATCH 79/96] Fix problem with title index for Organisation-like objects --- bika/lims/catalog/indexers/README.md | 13 ++++----- bika/lims/catalog/indexers/__init__.py | 3 +- bika/lims/catalog/indexers/configure.zcml | 3 ++ bika/lims/catalog/indexers/organisation.py | 32 ++++++++++++++++++++++ bika/lims/content/organisation.py | 23 +++++++--------- bika/lims/interfaces/__init__.py | 5 ++++ 6 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 bika/lims/catalog/indexers/organisation.py diff --git a/bika/lims/catalog/indexers/README.md b/bika/lims/catalog/indexers/README.md index 7eca401f3f..ba136682d9 100644 --- a/bika/lims/catalog/indexers/README.md +++ b/bika/lims/catalog/indexers/README.md @@ -44,12 +44,9 @@ Specifications and Templates when a Sample Type is selected. - `sortable_title`: Case-insenstive contact's fullname for default sorting +### IOrganisation (Supplier, Manufacturer, Client, etc.) - - - - - - - - +- `title`: Organisation-like objects don't use the default attribute `title` +provided by AT. Rather, they keep this attribute empty and the schema field +`Name` is used (`Title` acts as a shortcut to `getName`). We need to handle this +behavior to simulate default behavior of `title` index diff --git a/bika/lims/catalog/indexers/__init__.py b/bika/lims/catalog/indexers/__init__.py index 3d8efdff19..7c14acb14f 100644 --- a/bika/lims/catalog/indexers/__init__.py +++ b/bika/lims/catalog/indexers/__init__.py @@ -23,7 +23,8 @@ from Products.CMFPlone.utils import safe_callable from plone.indexer import indexer -from bika.lims import api, logger +from bika.lims import api +from bika.lims import logger from bika.lims.catalog.bika_catalog import BIKA_CATALOG from bika.lims.interfaces import IBikaCatalog diff --git a/bika/lims/catalog/indexers/configure.zcml b/bika/lims/catalog/indexers/configure.zcml index 65879e6640..4da1722286 100644 --- a/bika/lims/catalog/indexers/configure.zcml +++ b/bika/lims/catalog/indexers/configure.zcml @@ -48,4 +48,7 @@ + + + diff --git a/bika/lims/catalog/indexers/organisation.py b/bika/lims/catalog/indexers/organisation.py new file mode 100644 index 0000000000..6a24197e65 --- /dev/null +++ b/bika/lims/catalog/indexers/organisation.py @@ -0,0 +1,32 @@ +# -*- 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-2019 by it's authors. +# Some rights reserved, see README and LICENSE. + +from plone.indexer import indexer + +from bika.lims.interfaces import IOrganisation + + +@indexer(IOrganisation) +def title(instance): + """Organisation objects does not use the built-in title, rather it uses + Name schema field. We need this type-specific index to simulate the default + behavior for index `title` + """ + return instance.Title() diff --git a/bika/lims/content/organisation.py b/bika/lims/content/organisation.py index 62a1b122ef..7214da55bc 100644 --- a/bika/lims/content/organisation.py +++ b/bika/lims/content/organisation.py @@ -19,19 +19,21 @@ # Some rights reserved, see README and LICENSE. from AccessControl import ClassSecurityInfo -from bika.lims import bikaMessageFactory as _ -from bika.lims.browser.fields import AddressField -from bika.lims.browser.widgets import AddressWidget -from bika.lims.config import PROJECTNAME -from bika.lims.content.bikaschema import BikaFolderSchema -from bika.lims.content.bikaschema import BikaSchema -from plone.app.folder.folder import ATFolder from Products.Archetypes.public import ManagedSchema from Products.Archetypes.public import StringField from Products.Archetypes.public import StringWidget from Products.Archetypes.public import registerType from Products.CMFPlone.utils import safe_unicode +from plone.app.folder.folder import ATFolder +from zope.interface import implements +from bika.lims import bikaMessageFactory as _ +from bika.lims.browser.fields import AddressField +from bika.lims.browser.widgets import AddressWidget +from bika.lims.config import PROJECTNAME +from bika.lims.content.bikaschema import BikaFolderSchema +from bika.lims.content.bikaschema import BikaSchema +from bika.lims.interfaces import IOrganisation schema = BikaFolderSchema.copy() + BikaSchema.copy() + ManagedSchema(( @@ -166,17 +168,12 @@ class Organisation(ATFolder): """Base class for Clients, Suppliers and for the Laboratory """ + implements(IOrganisation) security = ClassSecurityInfo() displayContentsTab = False schema = schema - @property - def title(self): - """Return the name of the Organisation - """ - return self.Title() - def Title(self): """Return the name of the Organisation """ diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index 9b4d748bd7..187541280d 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -1054,3 +1054,8 @@ class IHaveDepartment(Interface): def getDepartment(self): """Returns the department or departments the instance is assigned to """ + + +class IOrganisation(Interface): + """Marker interface for IOrganisation object + """ From ffe2deb4d3dd99459b2ea5e2eecab75010b0689e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 21:27:35 +0100 Subject: [PATCH 80/96] Keep labcontact in portal_catalog --- bika/lims/setuphandlers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index a80c5d90d8..23565ab4fc 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -108,7 +108,7 @@ ("Instrument", ["bika_setup_catalog", "portal_catalog"]), ("InstrumentLocation", ["bika_setup_catalog", "portal_catalog"]), ("InstrumentType", ["bika_setup_catalog", "portal_catalog"]), - ("LabContact", ["bika_setup_catalog"]), + ("LabContact", ["bika_setup_catalog", "portal_catalog"]), ("LabProduct", ["bika_setup_catalog", "portal_catalog"]), ("Manufacturer", ["bika_setup_catalog", "portal_catalog"]), ("Method", ["bika_setup_catalog", "portal_catalog"]), From 5ae70b2bb1c582e71e9700121d1c31b91167ceae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 22:10:54 +0100 Subject: [PATCH 81/96] Fix Client's Title() not safe_unicode --- bika/lims/content/client.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bika/lims/content/client.py b/bika/lims/content/client.py index 31a1b6ec54..33a200c665 100644 --- a/bika/lims/content/client.py +++ b/bika/lims/content/client.py @@ -166,11 +166,6 @@ def _renameAfterCreation(self, check_auto_id=False): from bika.lims.idserver import renameAfterCreation renameAfterCreation(self) - def Title(self): - """Return the Organisation's Name as its title - """ - return self.getName() - security.declarePublic("getContactFromUsername") def getContactFromUsername(self, username): From 39b96166fddaa7cbe4b8559c9472b7fc45d7d1d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 22:20:06 +0100 Subject: [PATCH 82/96] Remove unnecessary code from Laboratory content type --- bika/lims/content/laboratory.py | 65 +++++++++------------------------ 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/bika/lims/content/laboratory.py b/bika/lims/content/laboratory.py index b93ac0bfa8..91cefa6cd5 100644 --- a/bika/lims/content/laboratory.py +++ b/bika/lims/content/laboratory.py @@ -19,13 +19,6 @@ # Some rights reserved, see README and LICENSE. from AccessControl import ClassSecurityInfo -from bika.lims import api -from bika.lims import bikaMessageFactory as _ -from bika.lims.browser.fields import UIDReferenceField -from bika.lims.config import PROJECTNAME -from bika.lims.config import ManageBika -from bika.lims.content.organisation import Organisation -from bika.lims.interfaces import ILaboratory from Products.Archetypes.public import BooleanField from Products.Archetypes.public import BooleanWidget from Products.Archetypes.public import ImageField @@ -33,17 +26,24 @@ from Products.Archetypes.public import IntegerField from Products.Archetypes.public import IntegerWidget from Products.Archetypes.public import Schema -from Products.Archetypes.public import SelectionWidget from Products.Archetypes.public import StringField from Products.Archetypes.public import StringWidget from Products.Archetypes.public import TextAreaWidget from Products.Archetypes.public import TextField from Products.Archetypes.public import registerType -from Products.Archetypes.utils import DisplayList from Products.CMFCore.utils import UniqueObject from Products.CMFPlone.utils import safe_unicode from zope.interface import implements +from bika.lims import bikaMessageFactory as _ +from bika.lims.browser.fields import UIDReferenceField +from bika.lims.browser.widgets import ReferenceWidget +from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG +from bika.lims.config import ManageBika +from bika.lims.config import PROJECTNAME +from bika.lims.content.organisation import Organisation +from bika.lims.interfaces import ILaboratory + DEFAULT_ACCREDITATION_PAGE_HEADER = """${lab_name} has been accredited as ${accreditation_standard} conformant by ${accreditation_body_abbr}, ${accreditation_body_name}

${accreditation_body_abbr} is the single @@ -70,13 +70,17 @@ "Supervisor", required=0, allowed_types=("LabContact",), - vocabulary="_getLabContacts", write_permission=ManageBika, - accessor="getSupervisorUID", - widget=SelectionWidget( - format="select", + widget=ReferenceWidget( label=_("Supervisor"), - description=_("Supervisor of the Lab") + description=_("Supervisor of the Lab"), + showOn=True, + catalog_name=SETUP_CATALOG, + base_query=dict( + is_active=True, + sort_on="sortable_title", + sort_order="ascending", + ), ) ), @@ -194,38 +198,5 @@ def Title(self): title = self.getName() and self.getName() or _("Laboratory") return safe_unicode(title).encode("utf-8") - def _getLabContacts(self): - bsc = api.get_tool("bika_setup_catalog") - # fallback - all Lab Contacts - pairs = [["", ""]] - for contact in bsc(portal_type="LabContact", - is_active=True, - sort_on="sortable_title"): - pairs.append((contact.UID, contact.Title)) - return DisplayList(pairs) - - @security.public - def getSupervisor(self): - """Returns the assigned supervisor - - :returns: Supervisor object - """ - return self.getField("Supervisor").get(self) - - @security.public - def getSupervisorUID(self): - """Returns the UID of the assigned Supervisor - - NOTE: This is the default accessor of the `Supervisor` schema field - and needed for the selection widget to render the selected value - properly in _view_ mode. - - :returns: Supervisor UID - """ - supervisor = self.getSupervisor() - if not supervisor: - return None - return api.get_uid(supervisor) - registerType(Laboratory, PROJECTNAME) From f506b79aa358f9742f14810eb2b577a95a081f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Mon, 2 Dec 2019 22:29:26 +0100 Subject: [PATCH 83/96] Remove getAnalysisCategories vocabulary from Client --- bika/lims/content/client.py | 45 +++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/bika/lims/content/client.py b/bika/lims/content/client.py index 33a200c665..79f9c650d5 100644 --- a/bika/lims/content/client.py +++ b/bika/lims/content/client.py @@ -18,33 +18,33 @@ # Copyright 2018-2019 by it's authors. # Some rights reserved, see README and LICENSE. -import sys - from AccessControl import ClassSecurityInfo from AccessControl import Unauthorized from Products.ATContentTypes.content import schemata from Products.Archetypes.public import BooleanField from Products.Archetypes.public import BooleanWidget from Products.Archetypes.public import ReferenceField -from Products.Archetypes.public import ReferenceWidget from Products.Archetypes.public import Schema from Products.Archetypes.public import SelectionWidget from Products.Archetypes.public import StringField from Products.Archetypes.public import StringWidget from Products.Archetypes.public import registerType -from Products.Archetypes.utils import DisplayList from Products.CMFCore import permissions from Products.CMFCore.PortalFolder import PortalFolderBase as PortalFolder from Products.CMFCore.utils import _checkPermission +from zope.interface import implements + from bika.lims import _ from bika.lims import api +from bika.lims.browser.widgets import ReferenceWidget +from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG from bika.lims.config import ARIMPORT_OPTIONS from bika.lims.config import DECIMAL_MARKS from bika.lims.config import PROJECTNAME from bika.lims.content.attachment import Attachment from bika.lims.content.organisation import Organisation -from bika.lims.interfaces import IClient, IDeactivable -from zope.interface import implements +from bika.lims.interfaces import IClient +from bika.lims.interfaces import IDeactivable schema = Organisation.schema.copy() + Schema(( StringField( @@ -93,15 +93,19 @@ schemata="Preferences", required=0, multiValued=1, - vocabulary="getAnalysisCategories", - vocabulary_display_path_bound=sys.maxint, allowed_types=("AnalysisCategory",), relationship="ClientDefaultCategories", widget=ReferenceWidget( - checkbox_bound=0, label=_("Default categories"), description=_( "Always expand the selected categories in client views"), + showOn=True, + catalog_name=SETUP_CATALOG, + base_query=dict( + is_active=True, + sort_on="sortable_title", + sort_order="ascending", + ), ), ), @@ -110,15 +114,19 @@ schemata="Preferences", required=0, multiValued=1, - vocabulary="getAnalysisCategories", validators=("restrictedcategoriesvalidator",), - vocabulary_display_path_bound=sys.maxint, allowed_types=("AnalysisCategory",), relationship="ClientRestrictedCategories", widget=ReferenceWidget( - checkbox_bound=0, label=_("Restrict categories"), description=_("Show only selected categories in client views"), + showOn=True, + catalog_name=SETUP_CATALOG, + base_query=dict( + is_active=True, + sort_on="sortable_title", + sort_order="ascending", + ), ), ), @@ -193,19 +201,6 @@ def getContactUIDForUser(self): def getARImportOptions(self): return ARIMPORT_OPTIONS - security.declarePublic("getAnalysisCategories") - - def getAnalysisCategories(self): - """Return all available analysis categories - """ - bsc = api.get_tool("bika_setup_catalog") - cats = [] - for st in bsc(portal_type="AnalysisCategory", - is_active=True, - sort_on="sortable_title"): - cats.append((st.UID, st.Title)) - return DisplayList(cats) - def getContacts(self, only_active=True): """Return an array containing the contacts from this Client """ From d5dba6129e073fe135b4900e55db4521f6bd2ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 00:03:27 +0100 Subject: [PATCH 84/96] Fix DataLayer tests --- bika/lims/catalog/indexers/organisation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bika/lims/catalog/indexers/organisation.py b/bika/lims/catalog/indexers/organisation.py index 6a24197e65..b2b42be3f2 100644 --- a/bika/lims/catalog/indexers/organisation.py +++ b/bika/lims/catalog/indexers/organisation.py @@ -29,4 +29,5 @@ def title(instance): Name schema field. We need this type-specific index to simulate the default behavior for index `title` """ - return instance.Title() + name = getattr(instance, "Name", None) + return name and name or "" From d92128c6d1daec61bec509e17ae75639e1c895a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 00:42:24 +0100 Subject: [PATCH 85/96] Changelog --- CHANGES.rst | 1 + bika/lims/upgrade/v01_03_003.py | 36 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index b9c38fac62..eb32a383bf 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -14,6 +14,7 @@ Changelog **Changed** +- #1486 Clean-up of indexes and metadata from `setup_catalog` **Removed** diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index a9549ea66a..fc367562db 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -71,7 +71,6 @@ INDEXES_TO_REMOVE = [ # Only used in add2 to filter Sample Points by Sample Type when a Sample # Type was selected. Now, getSampleTypeUID is used instead because of - # https://github.com/senaite/senaite.core/pull/1481 ("bika_setup_catalog", "getSampleTypeTitles"), # Only used for when Sample and SamplePartition objects @@ -87,17 +86,14 @@ # getAccredited was only used in the "hidden" view accreditation to filter # services labeled as "accredited". Since we don't expect that listing to # contain too many items, they are now filtered by waking-up the object - # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getAccredited"), # getAnalyst index is used in Analyses (Duplicates and Reference included) # and Worksheets. None of the types stored in setup_catalog support Analyst - # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getAnalyst"), # getBlank index is not used in setup_catalog, but in bika_catalog, where # is used in AddControl and AddBlank views (Worksheet) - # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getBlank"), # Only used in analyses listing, but from analysis_catalog @@ -110,7 +106,6 @@ ("bika_setup_catalog", "getServiceUID"), # Not used anywhere - # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getDocumentID"), ("bika_setup_catalog", "getDuplicateVariation"), ("bika_setup_catalog", "getFormula"), @@ -188,11 +183,9 @@ ("bika_catalog", "getSampleTypeTitle"), # Not used anywhere - # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getAccredited"), # Not used anywhere - # https://github.com/senaite/senaite.core/pull/1484 ("bika_setup_catalog", "getBlank"), ("bika_setup_catalog", "getDuplicateVariation"), ("bika_setup_catalog", "getFormula"), @@ -240,26 +233,19 @@ def upgrade(tool): # -------- ADD YOUR STUFF BELOW -------- + # Fix Site Properties Generic Setup Export Step # https://github.com/senaite/senaite.core/pull/1469 setup.runImportStepFromProfile(profile, "propertiestool") - # Remove stale indexes and metadata - # https://github.com/senaite/senaite.core/pull/1481 - remove_stale_indexes(portal) - remove_stale_metadata(portal) - - # Add new indexes - # https://github.com/senaite/senaite.core/pull/1481 - add_new_indexes(portal) + # Remove, rename and add indexes/metadata + # https://github.com/senaite/senaite.core/pull/1486 + cleanup_indexes_and_metadata(portal) + # Sample edit form (some selection widgets empty) # Reindex client's related fields (getClientUID, getClientTitle, etc.) # https://github.com/senaite/senaite.core/pull/1477 reindex_client_fields(portal) - # Some indexes in setup_catalog changed - reindex_labcontact_sortable_title(portal) - reindex_supplier_manufacturers_titles(portal) - # Redirect to worksheets folder when a Worksheet is removed # https://github.com/senaite/senaite.core/pull/1480 setup_form_controller_actions(portal) @@ -299,6 +285,18 @@ def reindex_client_fields(portal): logger.info("Reindexing client fields ... [DONE]") +def cleanup_indexes_and_metadata(portal): + # Remove stale indexes and metadata + remove_stale_indexes(portal) + remove_stale_metadata(portal) + + # Add new indexes + add_new_indexes(portal) + + # Some indexes in setup_catalog changed + reindex_labcontact_sortable_title(portal) + reindex_supplier_manufacturers_titles(portal) + def reindex_labcontact_sortable_title(portal): logger.info("Reindexing sortable_title for LabContacts ...") From 4aada684420d4d4867b83fc231048d04e298fddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 00:53:51 +0100 Subject: [PATCH 86/96] Added getName signature for IOrganisation --- bika/lims/interfaces/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index 187541280d..a427b3deeb 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -1059,3 +1059,7 @@ def getDepartment(self): class IOrganisation(Interface): """Marker interface for IOrganisation object """ + + def getName(self): + """Returns the name of the organisation. Masks Title() + """ From bc81e8defd33ee3c1b33ca2b5cc7f3f4428e1a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 09:25:32 +0100 Subject: [PATCH 87/96] LabContacts view sorted by sortable_title --- bika/lims/browser/department/labcontacts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bika/lims/browser/department/labcontacts.py b/bika/lims/browser/department/labcontacts.py index 17bc38e644..da4f975e21 100644 --- a/bika/lims/browser/department/labcontacts.py +++ b/bika/lims/browser/department/labcontacts.py @@ -41,12 +41,12 @@ def __init__(self, context, request): self.context_actions = {} self.contentFilter = { 'portal_type': 'LabContact', - 'sort_on': 'getFirstname', + 'sort_on': 'sortable_title', 'sort_order': 'ascending' } self.columns = { 'Fullname': {'title': _('Name'), - 'index': 'fullname'}, + 'index': 'sortable_title'}, 'Department': {'title': _('Department')}, 'BusinessPhone': {'title': _('Phone')}, 'MobilePhone': {'title': _('Mobile Phone')}, From 5ce7cf2633b0a46d49d6c60254068885e558a0d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 10:06:20 +0100 Subject: [PATCH 88/96] Better searches for items from setup_catalog --- bika/lims/api/__init__.py | 2 ++ bika/lims/catalog/indexers/__init__.py | 27 ++++++++++++++++++++++++- bika/lims/catalog/indexers/bikasetup.py | 14 ++++++++++++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/bika/lims/api/__init__.py b/bika/lims/api/__init__.py index aa4d63a2d9..3bab9c4882 100644 --- a/bika/lims/api/__init__.py +++ b/bika/lims/api/__init__.py @@ -1327,6 +1327,8 @@ def to_searchable_text_metadata(value): return to_searchable_text_metadata(v) if is_date(value): return value.strftime("%Y-%m-%d") + if is_at_content(value): + return to_searchable_text_metadata(get_title(value)) if not isinstance(value, basestring): value = str(value) return safe_unicode(value) diff --git a/bika/lims/catalog/indexers/__init__.py b/bika/lims/catalog/indexers/__init__.py index 7c14acb14f..2a07f91aef 100644 --- a/bika/lims/catalog/indexers/__init__.py +++ b/bika/lims/catalog/indexers/__init__.py @@ -25,6 +25,7 @@ from bika.lims import api from bika.lims import logger +from bika.lims.api import safe_getattr from bika.lims.catalog.bika_catalog import BIKA_CATALOG from bika.lims.interfaces import IBikaCatalog @@ -82,18 +83,42 @@ def get_metadata_for(instance, catalog): return {} -def generic_listing_searchable_text(instance, catalog_name): +def generic_listing_searchable_text(instance, catalog_name, + exclude_field_names=None, + include_field_names=None): """Retrieves all the values of metadata columns in the catalog for wildcard searches + :param instance: the object to retrieve metadata/values from + :param catalog_name: the catalog to retrieve metadata from + :param exclude_field_names: field names to exclude from the metadata + :param include_field_names: field names to include, even if no metadata """ entries = set() + + # Fields to include/exclude + include = include_field_names or [] + exclude = exclude_field_names or [] + + # Get the metadata fields from this instance and catalog catalog = api.get_tool(catalog_name) metadata = get_metadata_for(instance, catalog) for key, brain_value in metadata.items(): + if key in exclude: + continue + elif key in include: + # A metadata field already + include.remove(key) + instance_value = api.safe_getattr(instance, key, None) parsed = api.to_searchable_text_metadata(brain_value or instance_value) entries.add(parsed) + # Include values from additional fields + for field_name in include: + field_value = api.safe_getattr(instance, field_name, None) + field_value = api.to_searchable_text_metadata(field_value) + entries.add(field_value) + # Remove empties entries = filter(None, entries) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index b112eda688..a935f53a3e 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -133,7 +133,19 @@ def listing_searchable_text(instance): wildcard searches :return: all metadata values joined in a string """ - return generic_listing_searchable_text(instance, SETUP_CATALOG) + exclude = ["getObjPositionInParent", ] + + # Additional fields to include values from + include = ["getCalculation" + "getDepartment", + "getInstrument", + "getInstrumentType", + "getInstruments", + "getSampleTypeTitle", ] + + return generic_listing_searchable_text(instance, SETUP_CATALOG, + exclude_field_names=exclude, + include_field_names=include) def to_keywords_list(obj, func): From f1280ae34dacd7f5e5c2329cd7650cfadcece782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 10:22:23 +0100 Subject: [PATCH 89/96] Remove unused Schema fields from Instrument --- bika/lims/catalog/indexers/organisation.py | 2 +- bika/lims/content/instrument.py | 34 ---------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/bika/lims/catalog/indexers/organisation.py b/bika/lims/catalog/indexers/organisation.py index b2b42be3f2..c1f1249741 100644 --- a/bika/lims/catalog/indexers/organisation.py +++ b/bika/lims/catalog/indexers/organisation.py @@ -30,4 +30,4 @@ def title(instance): behavior for index `title` """ name = getattr(instance, "Name", None) - return name and name or "" + return name or "" diff --git a/bika/lims/content/instrument.py b/bika/lims/content/instrument.py index d19047a9ec..4bbe16be2a 100644 --- a/bika/lims/content/instrument.py +++ b/bika/lims/content/instrument.py @@ -28,7 +28,6 @@ from Products.Archetypes.atapi import registerType from bika.lims.api.analysis import is_out_of_range from bika.lims.catalog.analysis_catalog import CATALOG_ANALYSIS_LISTING -from zope.component._api import getAdapters from zope.interface import implements from plone.app.folder.folder import ATFolder @@ -68,7 +67,6 @@ from bika.lims.config import PROJECTNAME from bika.lims.exportimport import instruments from bika.lims.interfaces import IInstrument, IDeactivable -from bika.lims.config import QCANALYSIS_TYPES from bika.lims.content.bikaschema import BikaSchema from bika.lims.content.bikaschema import BikaFolderSchema from bika.lims import bikaMessageFactory as _ @@ -276,36 +274,6 @@ ), ), - ComputedField( - 'InstrumentLocationName', - expression='here.getInstrumentLocation().Title() if here.getInstrumentLocation() else ""', - widget=ComputedWidget( - label=_("Instrument Location"), - label_msgid="instrument_location", - description=_("The room and location where the instrument is installed"), - description_msgid="help_instrument_location", - visible=True, - ), - ), - - ComputedField( - 'ManufacturerName', - expression='here.getManufacturer().Title() if here.getManufacturer() else ""', - widget=ComputedWidget( - label=_('Manufacturer'), - visible=True, - ), - ), - - ComputedField( - 'SupplierName', - expression='here.getSupplier().Title() if here.getSupplier() else ""', - widget=ComputedWidget( - label=_('Supplier'), - visible=True, - ), - ), - StringField( 'AssetNumber', widget=StringWidget( @@ -363,8 +331,6 @@ )) schema.moveField('AssetNumber', before='description') -schema.moveField('SupplierName', before='Model') -schema.moveField('ManufacturerName', before='SupplierName') schema['description'].widget.visible = True schema['description'].schemata = 'default' From c8c218bbf041eaed02ef756a3bcb5ee40eba56b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 10:29:20 +0100 Subject: [PATCH 90/96] Additional fields for listing_searchable_text --- bika/lims/catalog/indexers/bikasetup.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index a935f53a3e..4c9cdec62c 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -139,9 +139,12 @@ def listing_searchable_text(instance): include = ["getCalculation" "getDepartment", "getInstrument", - "getInstrumentType", "getInstruments", - "getSampleTypeTitle", ] + "getInstrumentType", + "getSamplePoint" + "getSampleType", + "getSupplier", + "getManufacturer", ] return generic_listing_searchable_text(instance, SETUP_CATALOG, exclude_field_names=exclude, From 76da915a0e7ad60293ba8e9ac85a231460c92fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 11:45:43 +0100 Subject: [PATCH 91/96] Make WorksheetTemplate and Method to implement IHaveInstrument --- bika/lims/catalog/indexers/bikasetup.py | 1 - bika/lims/content/abstractbaseanalysis.py | 3 ++- bika/lims/content/method.py | 9 ++++++++- bika/lims/content/worksheettemplate.py | 3 ++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 4c9cdec62c..989a0bbe87 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -139,7 +139,6 @@ def listing_searchable_text(instance): include = ["getCalculation" "getDepartment", "getInstrument", - "getInstruments", "getInstrumentType", "getSamplePoint" "getSampleType", diff --git a/bika/lims/content/abstractbaseanalysis.py b/bika/lims/content/abstractbaseanalysis.py index b56f88617e..4a5d1e9fc1 100644 --- a/bika/lims/content/abstractbaseanalysis.py +++ b/bika/lims/content/abstractbaseanalysis.py @@ -52,6 +52,7 @@ from bika.lims.content.bikaschema import BikaSchema from bika.lims.interfaces import IBaseAnalysis from bika.lims.interfaces import IHaveDepartment +from bika.lims.interfaces import IHaveInstrument from bika.lims.permissions import FieldEditAnalysisHidden from bika.lims.permissions import FieldEditAnalysisRemarks from bika.lims.permissions import FieldEditAnalysisResult @@ -750,7 +751,7 @@ class AbstractBaseAnalysis(BaseContent): # TODO BaseContent? is really needed? - implements(IBaseAnalysis, IHaveDepartment) + implements(IBaseAnalysis, IHaveDepartment, IHaveInstrument) security = ClassSecurityInfo() schema = schema displayContentsTab = False diff --git a/bika/lims/content/method.py b/bika/lims/content/method.py index ebc2d794af..66111ab00d 100644 --- a/bika/lims/content/method.py +++ b/bika/lims/content/method.py @@ -25,6 +25,7 @@ from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.interfaces import IDeactivable +from bika.lims.interfaces import IHaveInstrument from bika.lims.interfaces import IMethod from bika.lims.utils import t from plone.app.blob.field import FileField as BlobFileField @@ -176,7 +177,7 @@ class Method(BaseFolder): """Method content """ - implements(IMethod, IDeactivable) + implements(IMethod, IDeactivable, IHaveInstrument) security = ClassSecurityInfo() displayContentsTab = False @@ -231,6 +232,12 @@ def _getCalculations(self): items.insert(0, ("", t(_("None")))) return DisplayList(items) + def getInstrument(self): + """Instruments capable to perform this method. + Required by IHaveInstrument + """ + return self.getInstruments() + def getInstruments(self): """Instruments capable to perform this method """ diff --git a/bika/lims/content/worksheettemplate.py b/bika/lims/content/worksheettemplate.py index e3ba563c01..cd166fe6fc 100644 --- a/bika/lims/content/worksheettemplate.py +++ b/bika/lims/content/worksheettemplate.py @@ -44,6 +44,7 @@ from bika.lims.interfaces import IDeactivable from zope.interface import implements +from bika.lims.interfaces import IHaveInstrument from bika.lims.interfaces import IWorksheetTemplate schema = BikaSchema.copy() + Schema(( @@ -161,7 +162,7 @@ class WorksheetTemplate(BaseContent): """Worksheet Templates """ - implements(IWorksheetTemplate, IDeactivable) + implements(IWorksheetTemplate, IHaveInstrument, IDeactivable) security = ClassSecurityInfo() displayContentsTab = False schema = schema From b7b7e5070cb6e1d4e7a40374adf60fa840e3ff77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 11:55:30 +0100 Subject: [PATCH 92/96] Better handling of lists in listing_searchable_text --- bika/lims/api/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bika/lims/api/__init__.py b/bika/lims/api/__init__.py index 3bab9c4882..773df71713 100644 --- a/bika/lims/api/__init__.py +++ b/bika/lims/api/__init__.py @@ -1320,11 +1320,15 @@ def to_searchable_text_metadata(value): if isinstance(value, (bool)): return u"" if isinstance(value, (list, tuple)): - for v in value: - return to_searchable_text_metadata(v) + values = map(to_searchable_text_metadata, value) + values = filter(None, values) + return " ".join(values) if isinstance(value, (dict)): + values = set() for k, v in value.items(): - return to_searchable_text_metadata(v) + values.add(to_searchable_text_metadata(v)) + values = filter(None, values) + return " ".join(values) if is_date(value): return value.strftime("%Y-%m-%d") if is_at_content(value): From 7e18767e842d2f34bc3c85966cb3cef94c063a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 12:07:46 +0100 Subject: [PATCH 93/96] Remove ajaxGetClients the ajax call was only used when ClientID schema field was rendered. Client is the only content type that provides this field... and since this field is required, supposed to be unique and displayed on adding/editing a Client, it does not make sense to load a reference widget there for search+selection --- bika/lims/browser/clientfolder.py | 73 +--- bika/lims/browser/clientfolder.zcml | 8 - bika/lims/browser/js/bika.lims.site.js | 405 ++++++++---------- .../browser/js/coffee/bika.lims.site.coffee | 31 -- 4 files changed, 185 insertions(+), 332 deletions(-) diff --git a/bika/lims/browser/clientfolder.py b/bika/lims/browser/clientfolder.py index 43a0acf4ee..7d4b58b5b4 100644 --- a/bika/lims/browser/clientfolder.py +++ b/bika/lims/browser/clientfolder.py @@ -19,20 +19,19 @@ # Some rights reserved, see README and LICENSE. import collections -import json from Products.CMFCore.permissions import ModifyPortalContent -from bika.lims import api, logger +from plone.app.content.browser.interfaces import IFolderContentsView +from zope.interface import implements + from bika.lims import bikaMessageFactory as _ -from bika.lims.browser import BrowserView from bika.lims.browser.bika_listing import BikaListingView from bika.lims.permissions import AddClient from bika.lims.permissions import ManageAnalysisRequests -from bika.lims.utils import (check_permission, get_email_link, get_link, - get_registry_value) -from plone import protect -from plone.app.content.browser.interfaces import IFolderContentsView -from zope.interface import implements +from bika.lims.utils import check_permission +from bika.lims.utils import get_email_link +from bika.lims.utils import get_link +from bika.lims.utils import get_registry_value class ClientFolderContentsView(BikaListingView): @@ -199,61 +198,3 @@ def client_match(client, search_term): if search_term in client.Description().lower(): return True return False - - -class ajaxGetClients(BrowserView): - """Vocabulary source for jquery combo dropdown box - """ - - def __call__(self): - protect.CheckAuthenticator(self.request) - searchTerm = self.request.get("searchTerm", "").lower() - page = self.request.get("page", 1) - nr_rows = self.request.get("rows", 20) - sort_order = self.request.get("sord") or "ascending" - sort_index = self.request.get("sidx") or "sortable_title" - - if sort_order == "desc": - sort_order = "descending" - - # Use the catalog to speed things up and also limit the results - catalog = api.get_tool("portal_catalog") - catalog_query = { - "portal_type": "Client", - "review_state": "active", - "sort_on": sort_index, - "sort_order": sort_order, - "sort_limit": 500 - } - # Inject the searchTerm to narrow the results further - if searchTerm: - catalog_query["SearchableText"] = searchTerm - logger.debug("ajaxGetClients::catalog_query=%s" % catalog_query) - brains = catalog(catalog_query) - rows = [] - - for brain in brains: - client = brain.getObject() - # skip clients where the search term does not match - if searchTerm and not client_match(client, searchTerm): - continue - rows.append( - { - "ClientID": client.getClientID(), - "Title": client.Title(), - "ClientUID": client.UID(), - } - ) - - pages = len(rows) / int(nr_rows) - pages += divmod(len(rows), int(nr_rows))[1] and 1 or 0 - ret = { - "page": page, - "total": pages, - "records": len(rows), - "rows": rows[ - (int(page) - 1) * int(nr_rows): int(page) * int(nr_rows) - ] - } - - return json.dumps(ret) diff --git a/bika/lims/browser/clientfolder.zcml b/bika/lims/browser/clientfolder.zcml index 1c2d7f09ac..97766b57c7 100644 --- a/bika/lims/browser/clientfolder.zcml +++ b/bika/lims/browser/clientfolder.zcml @@ -12,12 +12,4 @@ layer="bika.lims.interfaces.IBikaLIMS" /> - - diff --git a/bika/lims/browser/js/bika.lims.site.js b/bika/lims/browser/js/bika.lims.site.js index ea565da7a0..de056db9d3 100644 --- a/bika/lims/browser/js/bika.lims.site.js +++ b/bika/lims/browser/js/bika.lims.site.js @@ -1,85 +1,63 @@ -(function() { - /* Please use this command to compile this file into the parent `js` directory: - coffee --no-header -w -o ../ -c bika.lims.site.coffee - */ - window.SiteView = class SiteView { - constructor() { - this.load = this.load.bind(this); - /* INITIALIZERS */ - this.bind_eventhandler = this.bind_eventhandler.bind(this); - this.init_client_add_overlay = this.init_client_add_overlay.bind(this); - // here is where we'd populate the form controls, if we cared to. - this.init_spinner = this.init_spinner.bind(this); - this.init_client_combogrid = this.init_client_combogrid.bind(this); - this.init_datepickers = this.init_datepickers.bind(this); - this.init_referencedefinition = this.init_referencedefinition.bind(this); - /* METHODS */ - this.get_portal_url = this.get_portal_url.bind(this); - this.get_authenticator = this.get_authenticator.bind(this); - this.portalAlert = this.portalAlert.bind(this); - this.portal_alert = this.portal_alert.bind(this); - this.log = this.log.bind(this); - this.readCookie = this.readCookie.bind(this); - this.read_cookie = this.read_cookie.bind(this); - this.setCookie = this.setCookie.bind(this); - this.set_cookie = this.set_cookie.bind(this); - this.notificationPanel = this.notificationPanel.bind(this); - this.notify_in_panel = this.notify_in_panel.bind(this); - this.start_spinner = this.start_spinner.bind(this); - this.stop_spinner = this.stop_spinner.bind(this); - /* EVENT HANDLER */ - this.on_date_range_start_change = this.on_date_range_start_change.bind(this); - this.on_date_range_end_change = this.on_date_range_end_change.bind(this); - this.on_autocomplete_keydown = this.on_autocomplete_keydown.bind(this); - this.on_at_integer_field_keyup = this.on_at_integer_field_keyup.bind(this); - this.on_at_float_field_keyup = this.on_at_float_field_keyup.bind(this); - this.on_numeric_field_paste = this.on_numeric_field_paste.bind(this); - this.on_numeric_field_keypress = this.on_numeric_field_keypress.bind(this); - this.on_reference_definition_list_change = this.on_reference_definition_list_change.bind(this); - this.on_service_info_click = this.on_service_info_click.bind(this); - this.on_ajax_start = this.on_ajax_start.bind(this); - this.on_ajax_end = this.on_ajax_end.bind(this); - this.on_ajax_error = this.on_ajax_error.bind(this); - } - load() { +/* Please use this command to compile this file into the parent `js` directory: + coffee --no-header -w -o ../ -c bika.lims.site.coffee + */ + +(function() { + var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + window.SiteView = (function() { + function SiteView() { + this.on_ajax_error = bind(this.on_ajax_error, this); + this.on_ajax_end = bind(this.on_ajax_end, this); + this.on_ajax_start = bind(this.on_ajax_start, this); + this.on_service_info_click = bind(this.on_service_info_click, this); + this.on_reference_definition_list_change = bind(this.on_reference_definition_list_change, this); + this.on_numeric_field_keypress = bind(this.on_numeric_field_keypress, this); + this.on_numeric_field_paste = bind(this.on_numeric_field_paste, this); + this.on_at_float_field_keyup = bind(this.on_at_float_field_keyup, this); + this.on_at_integer_field_keyup = bind(this.on_at_integer_field_keyup, this); + this.on_autocomplete_keydown = bind(this.on_autocomplete_keydown, this); + this.on_date_range_end_change = bind(this.on_date_range_end_change, this); + this.on_date_range_start_change = bind(this.on_date_range_start_change, this); + this.stop_spinner = bind(this.stop_spinner, this); + this.start_spinner = bind(this.start_spinner, this); + this.notify_in_panel = bind(this.notify_in_panel, this); + this.notificationPanel = bind(this.notificationPanel, this); + this.set_cookie = bind(this.set_cookie, this); + this.setCookie = bind(this.setCookie, this); + this.read_cookie = bind(this.read_cookie, this); + this.readCookie = bind(this.readCookie, this); + this.log = bind(this.log, this); + this.portal_alert = bind(this.portal_alert, this); + this.portalAlert = bind(this.portalAlert, this); + this.get_authenticator = bind(this.get_authenticator, this); + this.get_portal_url = bind(this.get_portal_url, this); + this.init_referencedefinition = bind(this.init_referencedefinition, this); + this.init_datepickers = bind(this.init_datepickers, this); + this.init_spinner = bind(this.init_spinner, this); + this.init_client_add_overlay = bind(this.init_client_add_overlay, this); + this.bind_eventhandler = bind(this.bind_eventhandler, this); + this.load = bind(this.load, this); + } + + SiteView.prototype.load = function() { console.debug("SiteView::load"); - // load translations jarn.i18n.loadCatalog('senaite.core'); this._ = window.jarn.i18n.MessageFactory("senaite.core"); - // initialze the loading spinner this.init_spinner(); - // initialze the client add overlay this.init_client_add_overlay(); - // initialze the client combogrid - this.init_client_combogrid(); - // initialze datepickers this.init_datepickers(); - // initialze reference definition selection this.init_referencedefinition(); - // bind the event handler to the elements this.bind_eventhandler(); - // allowed keys for numeric fields - return this.allowed_keys = [ - 8, // backspace - 9, // tab - 13, // enter - 35, // end - 36, // home - 37, // left arrow - 39, // right arrow - 46, // delete - We don't support the del key in Opera because del == . == 46. - 44, // , - 60, // < - 62, // > - 45, // - - 69, // E - 101, // e, - 61 // = - ]; - } + return this.allowed_keys = [8, 9, 13, 35, 36, 37, 39, 46, 44, 60, 62, 45, 69, 101, 61]; + }; + + + /* INITIALIZERS */ + + SiteView.prototype.bind_eventhandler = function() { - bind_eventhandler() { /* * Binds callbacks on elements * @@ -87,28 +65,22 @@ * delegate the event: https://learn.jquery.com/events/event-delegation/ */ console.debug("SiteView::bind_eventhandler"); - // ReferenceSample selection changed $("body").on("change", "#ReferenceDefinition\\:list", this.on_reference_definition_list_change); - // Numeric field events $("body").on("keypress", ".numeric", this.on_numeric_field_keypress); $("body").on("paste", ".numeric", this.on_numeric_field_paste); - // AT field events $("body").on("keyup", "input[name*='\\:int\'], .ArchetypesIntegerWidget input", this.on_at_integer_field_keyup); $("body").on("keyup", "input[name*='\\:float\'], .ArchetypesDecimalWidget input", this.on_at_float_field_keyup); - // Autocomplete events - // XXX Where is this used? $("body").on("keydown", "input.autocomplete", this.on_autocomplete_keydown); - // Date Range Filtering $("body").on("change", ".date_range_start", this.on_date_range_start_change); $("body").on("change", ".date_range_end", this.on_date_range_end_change); $("body").on("click", "a.service_info", this.on_service_info_click); - // handle Ajax events $(document).on("ajaxStart", this.on_ajax_start); $(document).on("ajaxStop", this.on_ajax_end); return $(document).on("ajaxError", this.on_ajax_error); - } + }; + + SiteView.prototype.init_client_add_overlay = function() { - init_client_add_overlay() { /* * Initialize Client Overlay */ @@ -123,70 +95,35 @@ config: { closeOnEsc: false, onLoad: function() { - // manually remove remarks this.getOverlay().find('.ArchetypesRemarksWidget').remove(); }, onClose: function() {} } }); - } + }; + + SiteView.prototype.init_spinner = function() { - init_spinner() { /* * Initialize Spinner Overlay */ console.debug("SiteView::init_spinner"); - // unbind default Plone loader $(document).unbind('ajaxStart'); $(document).unbind('ajaxStop'); $('#ajax-spinner').remove(); - // counter of active spinners this.counter = 0; - // crate a spinner and append it to the body - this.spinner = $(`
`); + this.spinner = $("
"); return this.spinner.appendTo('body').hide(); - } + }; - init_client_combogrid() { - /* - * Initialize client combogrid, e.g. on the Client Add View - */ - console.debug("SiteView::init_client_combogrid"); - return $("input[id*='ClientID']").combogrid({ - colModel: [ - { - 'columnName': 'ClientUID', - 'hidden': true - }, - { - 'columnName': 'ClientID', - 'width': '20', - 'label': _('Client ID') - }, - { - 'columnName': 'Title', - 'width': '80', - 'label': _('Title') - } - ], - showOn: true, - width: '450px', - url: `${this.get_portal_url()}/getClients?_authenticator=${this.get_authenticator()}`, - select: function(event, ui) { - $(this).val(ui.item.ClientID); - $(this).change(); - return false; - } - }); - } + SiteView.prototype.init_datepickers = function() { - init_datepickers() { - var curDate, dateFormat, limitString, y; /* * Initialize date pickers * * XXX Where are these event handlers used? */ + var curDate, dateFormat, limitString, y; console.debug("SiteView::init_datepickers"); curDate = new Date; y = curDate.getFullYear(); @@ -196,11 +133,12 @@ dateFormat = 'yy-mm-dd'; } $('input.datepicker_range').datepicker({ + /** This function defines a datepicker for a date range. Both input elements should be siblings and have the class 'date_range_start' and 'date_range_end'. - */ + */ showOn: 'focus', showAnim: '', changeMonth: true, @@ -270,9 +208,10 @@ $(this).attr('value', ''); }).focus(); }); - } + }; + + SiteView.prototype.init_referencedefinition = function() { - init_referencedefinition() { /* * Initialize reference definition selection * XXX: When is this used? @@ -282,68 +221,77 @@ console.warn("SiteView::init_referencedefinition: Refactor this method!"); return $('#ReferenceDefinition:list').change(); } - } + }; + + + /* METHODS */ + + SiteView.prototype.get_portal_url = function() { - get_portal_url() { /* * Return the portal url */ return window.portal_url; - } + }; + + SiteView.prototype.get_authenticator = function() { - get_authenticator() { /* * Get the authenticator value */ return $("input[name='_authenticator']").val(); - } + }; + + SiteView.prototype.portalAlert = function(html) { - portalAlert(html) { /* * BBB: Use portal_alert */ console.warn("SiteView::portalAlert: Please use portal_alert method instead."); return this.portal_alert(html); - } + }; + + SiteView.prototype.portal_alert = function(html) { - portal_alert(html) { - var alerts; /* * Display a portal alert box */ + var alerts; console.debug("SiteView::portal_alert"); alerts = $('#portal-alert'); if (alerts.length === 0) { - $('#portal-header').append(``); + $('#portal-header').append(""); } else { - alerts.append(`
${html}
`); + alerts.append("
" + html + "
"); } alerts.fadeIn(); - } + }; + + SiteView.prototype.log = function(message) { - log(message) { /* * Log message via bika.lims.log */ - console.debug(`SiteView::log: message=${message}`); - // XXX: This should actually log via XHR to the server, but seem to not work. + console.debug("SiteView::log: message=" + message); return window.bika.lims.log(message); - } + }; + + SiteView.prototype.readCookie = function(cname) { - readCookie(cname) { /* * BBB: Use read_cookie */ console.warn("SiteView::readCookie: Please use read_cookie method instead."); return this.read_cookie(cname); - } + }; + + SiteView.prototype.read_cookie = function(cname) { - read_cookie(cname) { - var c, ca, i, name; /* * Read cookie value */ - console.debug(`SiteView::read_cookie:${cname}`); + var c, ca, i, name; + console.debug("SiteView::read_cookie:" + cname); name = cname + '='; ca = document.cookie.split(';'); i = 0; @@ -358,72 +306,78 @@ i++; } return null; - } + }; + + SiteView.prototype.setCookie = function(cname, cvalue) { - setCookie(cname, cvalue) { /* * BBB: Use set_cookie */ console.warn("SiteView::setCookie: Please use set_cookie method instead."); return this.set_cookie(cname, cvalue); - } + }; + + SiteView.prototype.set_cookie = function(cname, cvalue) { - set_cookie(cname, cvalue) { - var d, expires; /* * Read cookie value */ - console.debug(`SiteView::set_cookie:cname=${cname}, cvalue=${cvalue}`); + var d, expires; + console.debug("SiteView::set_cookie:cname=" + cname + ", cvalue=" + cvalue); d = new Date; d.setTime(d.getTime() + 1 * 24 * 60 * 60 * 1000); expires = 'expires=' + d.toUTCString(); document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/'; - } + }; + + SiteView.prototype.notificationPanel = function(data, mode) { - notificationPanel(data, mode) { /* * BBB: Use notify_in_panel */ console.warn("SiteView::notificationPanel: Please use notfiy_in_panel method instead."); return this.notify_in_panel(data, mode); - } + }; + + SiteView.prototype.notify_in_panel = function(data, mode) { - notify_in_panel(data, mode) { - var html; /* * Render an alert inside the content panel, e.g.in autosave of ARView */ - console.debug(`SiteView::notify_in_panel:data=${data}, mode=${mode}`); + var html; + console.debug("SiteView::notify_in_panel:data=" + data + ", mode=" + mode); $('#panel-notification').remove(); - html = ``; + html = ""; $('div#viewlet-above-content-title').append(html); $('#panel-notification').fadeIn('slow', 'linear', function() { setTimeout((function() { $('#panel-notification').fadeOut('slow', 'linear'); }), 3000); }); - } + }; + + SiteView.prototype.start_spinner = function() { - start_spinner() { /* * Start Spinner Overlay */ console.debug("SiteView::start_spinner"); - // increase the counter this.counter++; - this.timer = setTimeout((() => { - if (this.counter > 0) { - this.spinner.show('fast'); - } - }), 500); - } + this.timer = setTimeout(((function(_this) { + return function() { + if (_this.counter > 0) { + _this.spinner.show('fast'); + } + }; + })(this)), 500); + }; + + SiteView.prototype.stop_spinner = function() { - stop_spinner() { /* * Stop Spinner Overlay */ console.debug("SiteView::stop_spinner"); - // decrease the counter this.counter--; if (this.counter < 0) { this.counter = 0; @@ -433,49 +387,53 @@ this.spinner.stop(); this.spinner.hide(); } - } + }; + + + /* EVENT HANDLER */ + + SiteView.prototype.on_date_range_start_change = function(event) { - on_date_range_start_change(event) { - var $el, brother, date_element, el; /* * Eventhandler for Date Range Filtering * * 1. Go to Setup and enable advanced filter bar * 2. Set the start date of adv. filter bar, e.g. in AR listing */ + var $el, brother, date_element, el; console.debug("°°° SiteView::on_date_range_start_change °°°"); el = event.currentTarget; $el = $(el); - // Set the min selectable end date to the start date date_element = $el.datepicker('getDate'); brother = $el.siblings('.date_range_end'); return $(brother).datepicker('option', 'minDate', date_element); - } + }; + + SiteView.prototype.on_date_range_end_change = function(event) { - on_date_range_end_change(event) { - var $el, brother, date_element, el; /* * Eventhandler for Date Range Filtering * * 1. Go to Setup and enable advanced filter bar * 2. Set the start date of adv. filter bar, e.g. in AR listing */ + var $el, brother, date_element, el; console.debug("°°° SiteView::on_date_range_end_change °°°"); el = event.currentTarget; $el = $(el); - // Set the max selectable start date to the end date date_element = $el.datepicker('getDate'); brother = $el.siblings('.date_range_start'); return $(brother).datepicker('option', 'maxDate', date_element); - } + }; + + SiteView.prototype.on_autocomplete_keydown = function(event) { - on_autocomplete_keydown(event) { - var $el, availableTags, el, extractLast, split; /* * Eventhandler for Autocomplete fields * * XXX: Refactor if it is clear where this code is used! */ + var $el, availableTags, el, extractLast, split; console.debug("°°° SiteView::on_autocomplete_keydown °°°"); el = event.currentTarget; $el = $(el); @@ -493,81 +451,77 @@ return $el.autocomplete({ minLength: 0, source: function(request, response) { - // delegate back to autocomplete, but extract the last term response($.ui.autocomplete.filter(availableTags, extractLast(request.term))); }, focus: function() { - // prevent value inserted on focus return false; }, select: function(event, ui) { var terms; terms = split($el.val()); - // remove the current input terms.pop(); - // add the selected item terms.push(ui.item.value); - // add placeholder to get the comma-and-space at the end terms.push(''); this.el.val(terms.join(', ')); return false; } }); - } + }; + + SiteView.prototype.on_at_integer_field_keyup = function(event) { - on_at_integer_field_keyup(event) { - var $el, el; /* * Eventhandler for AT integer fields */ + var $el, el; console.debug("°°° SiteView::on_at_integer_field_keyup °°°"); el = event.currentTarget; $el = $(el); if (/\D/g.test($el.val())) { $el.val($el.val().replace(/\D/g, '')); } - } + }; + + SiteView.prototype.on_at_float_field_keyup = function(event) { - on_at_float_field_keyup(event) { - var $el, el; /* * Eventhandler for AT float fields */ + var $el, el; console.debug("°°° SiteView::on_at_float_field_keyup °°°"); el = event.currentTarget; $el = $(el); if (/[^-.\d]/g.test($el.val())) { $el.val($el.val().replace(/[^.\d]/g, '')); } - } + }; + + SiteView.prototype.on_numeric_field_paste = function(event) { - on_numeric_field_paste(event) { - var $el, el; /* * Eventhandler when the user pasted a value inside a numeric field. */ + var $el, el; console.debug("°°° SiteView::on_numeric_field_paste °°°"); el = event.currentTarget; $el = $(el); - // Wait (next cycle) for value popluation and replace commas. window.setTimeout((function() { $el.val($el.val().replace(',', '.')); }), 0); - } + }; + + SiteView.prototype.on_numeric_field_keypress = function(event) { - on_numeric_field_keypress(event) { - var $el, el, isAllowedKey, key; /* * Eventhandler when the user pressed a key inside a numeric field. */ + var $el, el, isAllowedKey, key; console.debug("°°° SiteView::on_numeric_field_keypress °°°"); el = event.currentTarget; $el = $(el); key = event.which; isAllowedKey = this.allowed_keys.join(',').match(new RegExp(key)); if (!key || 48 <= key && key <= 57 || isAllowedKey) { - // Opera assigns values for control keys. - // Wait (next cycle) for value popluation and replace commas. window.setTimeout((function() { $el.val($el.val().replace(',', '.')); }), 0); @@ -575,10 +529,10 @@ } else { event.preventDefault(); } - } + }; + + SiteView.prototype.on_reference_definition_list_change = function(event) { - on_reference_definition_list_change(event) { - var $el, authenticator, el, option, uid; /* * Eventhandler when the user clicked on the reference defintion dropdown. * @@ -588,6 +542,7 @@ * * The dropdown with the id="ReferenceDefinition:list" is rendered there. */ + var $el, authenticator, el, option, uid; console.debug("°°° SiteView::on_reference_definition_list_change °°°"); el = event.currentTarget; $el = $(el); @@ -595,8 +550,6 @@ uid = $el.val(); option = $el.children(':selected').html(); if (uid === '') { - // No reference definition selected; - // render empty widget. $('#Blank').prop('checked', false); $('#Hazardous').prop('checked', false); $('.bika-listing-table').load('referenceresults', { @@ -618,18 +571,17 @@ '_authenticator': authenticator, 'uid': uid }); - } + }; + + SiteView.prototype.on_service_info_click = function(event) { - on_service_info_click(event) { - var el; /* * Eventhandler when the service info icon was clicked */ + var el; console.debug("°°° SiteView::on_service_info_click °°°"); event.preventDefault(); el = event.currentTarget; - // https://jquerytools.github.io/documentation/overlay - // https://github.com/plone/plone.app.jquerytools/blob/master/plone/app/jquerytools/browser/overlayhelpers.js $(el).prepOverlay({ subtype: "ajax", width: '70%', @@ -643,45 +595,44 @@ return overlay.draggable(); }, onLoad: function(event) { - // manually dispatch the DOMContentLoaded event, so that the ReactJS - // component loads event = new Event("DOMContentLoaded", {}); return window.document.dispatchEvent(event); } } }); - // workaround un-understandable overlay api return $(el).click(); - } + }; + + SiteView.prototype.on_ajax_start = function(event) { - on_ajax_start(event) { /* * Eventhandler if an global Ajax Request started */ console.debug("°°° SiteView::on_ajax_start °°°"); - // start the loading spinner return this.start_spinner(); - } + }; + + SiteView.prototype.on_ajax_end = function(event) { - on_ajax_end(event) { /* * Eventhandler if an global Ajax Request ended */ console.debug("°°° SiteView::on_ajax_end °°°"); - // stop the loading spinner return this.stop_spinner(); - } + }; + + SiteView.prototype.on_ajax_error = function(event, jqxhr, settings, thrownError) { - on_ajax_error(event, jqxhr, settings, thrownError) { /* * Eventhandler if an global Ajax Request error */ console.debug("°°° SiteView::on_ajax_error °°°"); - // stop the loading spinner this.stop_spinner(); - return this.log(`Error at ${settings.url}: ${thrownError}`); - } + return this.log("Error at " + settings.url + ": " + thrownError); + }; + + return SiteView; - }; + })(); }).call(this); diff --git a/bika/lims/browser/js/coffee/bika.lims.site.coffee b/bika/lims/browser/js/coffee/bika.lims.site.coffee index c49feb096c..fea2bfbc1d 100644 --- a/bika/lims/browser/js/coffee/bika.lims.site.coffee +++ b/bika/lims/browser/js/coffee/bika.lims.site.coffee @@ -18,9 +18,6 @@ class window.SiteView # initialze the client add overlay @init_client_add_overlay() - # initialze the client combogrid - @init_client_combogrid() - # initialze datepickers @init_datepickers() @@ -130,34 +127,6 @@ class window.SiteView @spinner.appendTo('body').hide() - init_client_combogrid: => - ### - * Initialize client combogrid, e.g. on the Client Add View - ### - console.debug "SiteView::init_client_combogrid" - - $("input[id*='ClientID']").combogrid - colModel: [ - 'columnName': 'ClientUID' - 'hidden': true - , - 'columnName': 'ClientID' - 'width': '20' - 'label': _('Client ID') - , - 'columnName': 'Title' - 'width': '80' - 'label': _('Title') - ] - showOn: true - width: '450px' - url: "#{@get_portal_url()}/getClients?_authenticator=#{@get_authenticator()}" - select: (event, ui) -> - $(this).val ui.item.ClientID - $(this).change() - false - - init_datepickers: => ### * Initialize date pickers From 520e020922c052eef3f8d057fcdae3ce957f109b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 12:13:32 +0100 Subject: [PATCH 94/96] Better comment --- bika/lims/catalog/indexers/bikasetup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/catalog/indexers/bikasetup.py b/bika/lims/catalog/indexers/bikasetup.py index 989a0bbe87..4ab183c7bb 100644 --- a/bika/lims/catalog/indexers/bikasetup.py +++ b/bika/lims/catalog/indexers/bikasetup.py @@ -135,7 +135,7 @@ def listing_searchable_text(instance): """ exclude = ["getObjPositionInParent", ] - # Additional fields to include values from + # Additional non-metadata fields to include in the index include = ["getCalculation" "getDepartment", "getInstrument", From eca310bf6a0ba6d925fdbeab01fe0afd5f742cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 13:14:41 +0100 Subject: [PATCH 95/96] getCategoryUID index --> category_uid --- bika/lims/browser/js/bika.lims.loader.js | 3 - bika/lims/browser/js/bika.lims.worksheet.js | 210 ------------------ .../js/coffee/bika.lims.worksheet.coffee | 189 ---------------- .../productivity_analysesperservice.py | 2 +- bika/lims/browser/worksheet/ajax.py | 35 +-- bika/lims/browser/worksheet/configure.zcml | 8 - bika/lims/catalog/indexers/README.md | 3 +- bika/lims/catalog/indexers/bikasetup.py | 9 + bika/lims/catalog/indexers/configure.zcml | 1 + bika/lims/content/abstractbaseanalysis.py | 3 +- bika/lims/content/analysiscategory.py | 4 +- bika/lims/interfaces/__init__.py | 17 ++ bika/lims/setuphandlers.py | 2 +- bika/lims/skins/bika/ploneCustom.css.dtml | 5 - bika/lims/upgrade/v01_03_003.py | 6 + bika/lims/validators.py | 3 +- 16 files changed, 45 insertions(+), 455 deletions(-) diff --git a/bika/lims/browser/js/bika.lims.loader.js b/bika/lims/browser/js/bika.lims.loader.js index 1837f1ce3d..e650b05f31 100644 --- a/bika/lims/browser/js/bika.lims.loader.js +++ b/bika/lims/browser/js/bika.lims.loader.js @@ -131,9 +131,6 @@ window.bika.lims.controllers = { ".portaltype-worksheetfolder": ['WorksheetFolderView'], - ".portaltype-worksheet.template-add_analyses": - ['WorksheetAddAnalysesView'], - ".portaltype-worksheet.template-add_blank": ['WorksheetAddQCAnalysesView'], diff --git a/bika/lims/browser/js/bika.lims.worksheet.js b/bika/lims/browser/js/bika.lims.worksheet.js index 575d770274..fb4764eb66 100644 --- a/bika/lims/browser/js/bika.lims.worksheet.js +++ b/bika/lims/browser/js/bika.lims.worksheet.js @@ -109,216 +109,6 @@ })(); - window.WorksheetAddAnalysesView = (function() { - function WorksheetAddAnalysesView() { - this.on_search_click = bind(this.on_search_click, this); - this.on_category_change = bind(this.on_category_change, this); - this.filter_service_selector_by_category_uid = bind(this.filter_service_selector_by_category_uid, this); - this.get_listing_form = bind(this.get_listing_form, this); - this.get_listing_form_id = bind(this.get_listing_form_id, this); - this.get_authenticator = bind(this.get_authenticator, this); - this.get_base_url = bind(this.get_base_url, this); - this.ajax_submit = bind(this.ajax_submit, this); - this.bind_eventhandler = bind(this.bind_eventhandler, this); - this.load = bind(this.load, this); - } - - - /* - * Controller class for Worksheet's add analyses view - */ - - WorksheetAddAnalysesView.prototype.load = function() { - console.debug("WorksheetAddanalysesview::load"); - return this.bind_eventhandler(); - }; - - - /* INITIALIZERS */ - - WorksheetAddAnalysesView.prototype.bind_eventhandler = function() { - - /* - * Binds callbacks on elements - * - * N.B. We attach all the events to the form and refine the selector to - * delegate the event: https://learn.jquery.com/events/event-delegation/ - * - */ - console.debug("WorksheetAddanalysesview::bind_eventhandler"); - $("body").on("change", "[name='list_FilterByCategory']", this.on_category_change); - return $("body").on("click", ".ws-analyses-search-button", this.on_search_click); - }; - - - /* METHODS */ - - WorksheetAddAnalysesView.prototype.ajax_submit = function(options) { - var done; - if (options == null) { - options = {}; - } - - /* - * Ajax Submit with automatic event triggering and some sane defaults - */ - console.debug("°°° ajax_submit °°°"); - if (options.type == null) { - options.type = "POST"; - } - if (options.url == null) { - options.url = this.get_base_url(); - } - if (options.context == null) { - options.context = this; - } - console.debug(">>> ajax_submit::options=", options); - $(this).trigger("ajax:submit:start"); - done = (function(_this) { - return function() { - return $(_this).trigger("ajax:submit:end"); - }; - })(this); - return $.ajax(options).done(done); - }; - - WorksheetAddAnalysesView.prototype.get_base_url = function() { - - /* - * Return the current base url - */ - var url; - url = window.location.href; - return url.split('?')[0]; - }; - - WorksheetAddAnalysesView.prototype.get_authenticator = function() { - - /* - * Get the authenticator value - */ - return $("input[name='_authenticator']").val(); - }; - - WorksheetAddAnalysesView.prototype.get_listing_form_id = function() { - - /* - * Returns the CSS ID of the analyses listing - */ - return "list"; - }; - - WorksheetAddAnalysesView.prototype.get_listing_form = function() { - - /* - * Returns the analyses listing form element - */ - var form_id; - form_id = this.get_listing_form_id(); - return $("form[id='" + form_id + "']"); - }; - - WorksheetAddAnalysesView.prototype.filter_service_selector_by_category_uid = function(category_uid) { - - /* - * Filters the service selector by category - */ - var $select, base_url, data, form_id, select_name, url; - console.debug("WorksheetAddanalysesview::filter_service_selector_by_category_uid:" + category_uid); - form_id = this.get_listing_form_id(); - select_name = form_id + "_FilterByService"; - $select = $("[name='" + select_name + "']"); - base_url = this.get_base_url(); - url = base_url.replace("/add_analyses", "/getServices"); - data = { - _authenticator: this.get_authenticator() - }; - if (category_uid !== "any") { - data["getCategoryUID"] = category_uid; - } - return this.ajax_submit({ - url: url, - data: data, - dataType: "json" - }).done(function(data) { - var any_option; - $select.empty(); - any_option = ""; - $select.append(any_option); - return $.each(data, function(index, item) { - var name, option, uid; - uid = item[0]; - name = item[1]; - option = ""; - return $select.append(option); - }); - }); - }; - - - /* EVENT HANDLER */ - - WorksheetAddAnalysesView.prototype.on_category_change = function(event) { - - /* - * Eventhandler for category change - */ - var $el, category_uid; - console.debug("°°° WorksheetAddanalysesview::on_category_change °°°"); - $el = $(event.currentTarget); - category_uid = $el.val(); - return this.filter_service_selector_by_category_uid(category_uid); - }; - - WorksheetAddAnalysesView.prototype.on_search_click = function(event) { - - /* - * Eventhandler for the search button - */ - var filter_indexes, form, form_data, form_id; - console.debug("°°° WorksheetAddanalysesview::on_search_click °°°"); - event.preventDefault(); - form = this.get_listing_form(); - form_id = this.get_listing_form_id(); - filter_indexes = ["FilterByCategory", "FilterByService", "FilterByClient"]; - $.each(filter_indexes, function(index, filter) { - var $el, input, name, value; - name = form_id + "_" + filter; - $el = $("select[name='" + name + "']"); - value = $el.val(); - input = $("input[name='" + name + "']", form); - if (input.length === 0) { - form.append(""); - input = $("input[name='" + name + "']", form); - } - input.val(value); - if (value === "any") { - return input.remove(); - } - }); - form_data = new FormData(form[0]); - form_data.set("table_only", form_id); - return this.ajax_submit({ - data: form_data, - processData: false, - contentType: false - }).done(function(data) { - var $container, $data; - $container = $("div.bika-listing-table-container", form); - $data = $(data); - if ($data.find("tbody").length === 0) { - return $container.html("
0 " + (_('Results')) + "
"); - } else { - $container.html(data); - return window.bika.lims.BikaListingTableView.load_transitions(); - } - }); - }; - - return WorksheetAddAnalysesView; - - })(); - window.WorksheetAddQCAnalysesView = (function() { function WorksheetAddQCAnalysesView() { this.on_referencesample_row_click = bind(this.on_referencesample_row_click, this); diff --git a/bika/lims/browser/js/coffee/bika.lims.worksheet.coffee b/bika/lims/browser/js/coffee/bika.lims.worksheet.coffee index 3dfcefdb8b..41890ed40e 100644 --- a/bika/lims/browser/js/coffee/bika.lims.worksheet.coffee +++ b/bika/lims/browser/js/coffee/bika.lims.worksheet.coffee @@ -100,195 +100,6 @@ class window.WorksheetFolderView bika.lims.SiteView.notify_in_panel message, "error" - -class window.WorksheetAddAnalysesView - ### - * Controller class for Worksheet's add analyses view - ### - - load: => - console.debug "WorksheetAddanalysesview::load" - - # bind the event handler to the elements - @bind_eventhandler() - - - ### INITIALIZERS ### - - bind_eventhandler: => - ### - * Binds callbacks on elements - * - * N.B. We attach all the events to the form and refine the selector to - * delegate the event: https://learn.jquery.com/events/event-delegation/ - * - ### - console.debug "WorksheetAddanalysesview::bind_eventhandler" - - # Category filter changed - $("body").on "change", "[name='list_FilterByCategory']", @on_category_change - - # Search button clicked - $("body").on "click", ".ws-analyses-search-button", @on_search_click - - - ### METHODS ### - - ajax_submit: (options={}) => - ### - * Ajax Submit with automatic event triggering and some sane defaults - ### - console.debug "°°° ajax_submit °°°" - - # some sane option defaults - options.type ?= "POST" - options.url ?= @get_base_url() - options.context ?= this - - console.debug ">>> ajax_submit::options=", options - - $(this).trigger "ajax:submit:start" - done = => - $(this).trigger "ajax:submit:end" - return $.ajax(options).done done - - - get_base_url: => - ### - * Return the current base url - ### - url = window.location.href - return url.split('?')[0] - - - get_authenticator: => - ### - * Get the authenticator value - ### - return $("input[name='_authenticator']").val() - - - get_listing_form_id: () => - ### - * Returns the CSS ID of the analyses listing - ### - return "list" - - - get_listing_form: () => - ### - * Returns the analyses listing form element - ### - form_id = @get_listing_form_id() - return $("form[id='#{form_id}']") - - - filter_service_selector_by_category_uid: (category_uid) => - ### - * Filters the service selector by category - ### - console.debug "WorksheetAddanalysesview::filter_service_selector_by_category_uid:#{category_uid}" - - form_id = @get_listing_form_id() - select_name = "#{form_id}_FilterByService" - $select = $("[name='#{select_name}']") - - base_url = @get_base_url() - url = base_url.replace "/add_analyses", "/getServices" - - data = - _authenticator: @get_authenticator() - - if category_uid isnt "any" - data["getCategoryUID"] = category_uid - - @ajax_submit - url: url - data: data - dataType: "json" - .done (data) -> - $select.empty() - any_option = "" - $select.append any_option - $.each data, (index, item) -> - uid = item[0] - name = item[1] - option = "" - $select.append option - - - ### EVENT HANDLER ### - - on_category_change: (event) => - ### - * Eventhandler for category change - ### - console.debug "°°° WorksheetAddanalysesview::on_category_change °°°" - - # The select element for WS Template - $el = $(event.currentTarget) - - # extract the category UID and filter the services box - category_uid = $el.val() - @filter_service_selector_by_category_uid category_uid - - - on_search_click: (event) => - ### - * Eventhandler for the search button - ### - console.debug "°°° WorksheetAddanalysesview::on_search_click °°°" - - # Prevent form submit - event.preventDefault() - - form = @get_listing_form() - form_id = @get_listing_form_id() - - filter_indexes = [ - "FilterByCategory" - "FilterByService" - "FilterByClient" - ] - - # The filter elements (Category/Service/Client) belong to another form. - # Therefore, we need to inject these values into the listing form as hidden - # input fields. - $.each filter_indexes, (index, filter) -> - name = "#{form_id}_#{filter}" - $el = $("select[name='#{name}']") - value = $el.val() - - # get the corresponding input element of the listing form - input = $("input[name='#{name}']", form) - if input.length == 0 - form.append "" - input = $("input[name='#{name}']", form) - input.val value - - # omit the field if the value is set to any - if value == "any" - input.remove() - - # extract the data of the listing form and post it to the AddAnalysesView - form_data = new FormData form[0] - form_data.set "table_only", form_id - - @ajax_submit - data: form_data - processData: no # do not transform to a query string - contentType: no # do not set any content type header - .done (data) -> - $container = $("div.bika-listing-table-container", form) - $data = $(data) - if $data.find("tbody").length == 0 - $container.html "
0 #{_('Results')}
" - else - $container.html data - window.bika.lims.BikaListingTableView.load_transitions() - - - class window.WorksheetAddQCAnalysesView ### * Controller class for Worksheet's add blank/control views diff --git a/bika/lims/browser/reports/productivity_analysesperservice.py b/bika/lims/browser/reports/productivity_analysesperservice.py index 6933cc5149..18e4f06266 100644 --- a/bika/lims/browser/reports/productivity_analysesperservice.py +++ b/bika/lims/browser/reports/productivity_analysesperservice.py @@ -103,7 +103,7 @@ def __call__(self): 'colspan': 2}, ] datalines.append(dataline) for service in sc(portal_type="AnalysisService", - getCategoryUID=cat.UID, + category_uid=cat.UID, sort_on='sortable_title'): query['getServiceUID'] = service.UID analyses = bc(query) diff --git a/bika/lims/browser/worksheet/ajax.py b/bika/lims/browser/worksheet/ajax.py index ad2592af5c..618eb0aa0b 100644 --- a/bika/lims/browser/worksheet/ajax.py +++ b/bika/lims/browser/worksheet/ajax.py @@ -18,46 +18,17 @@ # Copyright 2018-2019 by it's authors. # Some rights reserved, see README and LICENSE. -from bika.lims import logger -from bika.lims.utils import t +import json from operator import itemgetter -from Products.Archetypes.config import REFERENCE_CATALOG -from Products.CMFCore.utils import getToolByName import plone import plone.protect -import json +from Products.Archetypes.config import REFERENCE_CATALOG +from Products.CMFCore.utils import getToolByName from bika.lims.workflow import getCurrentState -class GetServices(): - """ When a Category is selected in the add_analyses search screen, this - function returns a list of services from the selected category. - """ - def __init__(self, context, request): - self.context = context - self.request = request - - def __call__(self): - plone.protect.CheckAuthenticator(self.request) - bsc = getToolByName(self.context, 'bika_setup_catalog') - - query = { - "portal_type": 'AnalysisService', - "is_active": True, - "sort_on": 'sortable_title', - } - - getCategoryUID = self.request.get('getCategoryUID', '') - if getCategoryUID: - query["getCategoryUID"] = getCategoryUID - - brains = bsc(query) - voc = [[brain.UID, brain.Title] for brain in brains] - return json.dumps(voc) - - class AttachAnalyses(): """ In attachment add form, the analyses dropdown combo uses this as source. diff --git a/bika/lims/browser/worksheet/configure.zcml b/bika/lims/browser/worksheet/configure.zcml index 2f7187f6d8..cd4ddb6956 100644 --- a/bika/lims/browser/worksheet/configure.zcml +++ b/bika/lims/browser/worksheet/configure.zcml @@ -106,14 +106,6 @@ - - + diff --git a/bika/lims/content/abstractbaseanalysis.py b/bika/lims/content/abstractbaseanalysis.py index 4a5d1e9fc1..f0bdc2aac6 100644 --- a/bika/lims/content/abstractbaseanalysis.py +++ b/bika/lims/content/abstractbaseanalysis.py @@ -51,6 +51,7 @@ from bika.lims.config import SERVICE_POINT_OF_CAPTURE from bika.lims.content.bikaschema import BikaSchema from bika.lims.interfaces import IBaseAnalysis +from bika.lims.interfaces import IHaveAnalysisCategory from bika.lims.interfaces import IHaveDepartment from bika.lims.interfaces import IHaveInstrument from bika.lims.permissions import FieldEditAnalysisHidden @@ -751,7 +752,7 @@ class AbstractBaseAnalysis(BaseContent): # TODO BaseContent? is really needed? - implements(IBaseAnalysis, IHaveDepartment, IHaveInstrument) + implements(IBaseAnalysis, IHaveAnalysisCategory, IHaveDepartment, IHaveInstrument) security = ClassSecurityInfo() schema = schema displayContentsTab = False diff --git a/bika/lims/content/analysiscategory.py b/bika/lims/content/analysiscategory.py index 455f1071d2..b22b6e2a5f 100644 --- a/bika/lims/content/analysiscategory.py +++ b/bika/lims/content/analysiscategory.py @@ -107,8 +107,8 @@ def _renameAfterCreation(self, check_auto_id=False): def workflow_script_deactivate(self): # A instance cannot be deactivated if it contains services - query = dict(portal_type="AnalysisService", getCategoryUID=self.UID()) - brains = api.search(query) + query = dict(portal_type="AnalysisService", category_uid=self.UID()) + brains = api.search(query, SETUP_CATALOG) if brains: pu = api.get_tool("plone_utils") message = _("Category cannot be deactivated because it contains " diff --git a/bika/lims/interfaces/__init__.py b/bika/lims/interfaces/__init__.py index a427b3deeb..a05fc7b3b5 100644 --- a/bika/lims/interfaces/__init__.py +++ b/bika/lims/interfaces/__init__.py @@ -1063,3 +1063,20 @@ class IOrganisation(Interface): def getName(self): """Returns the name of the organisation. Masks Title() """ + + +class IHaveAnalysisCategory(Interface): + """Marker interface for objects that have AnalysisCategory(ies) assigned + """ + + def getCategory(self): + """Returns the category(ies) assigned to this instance + """ + + def getCategoryUID(self): + """Returns the UID of the category(ies) assigned to this instance + """ + + def getCategoryTitle(self): + """Returns the title of the category(ies) assigned to this instance + """ diff --git a/bika/lims/setuphandlers.py b/bika/lims/setuphandlers.py index 23565ab4fc..fd1256aaee 100644 --- a/bika/lims/setuphandlers.py +++ b/bika/lims/setuphandlers.py @@ -166,10 +166,10 @@ ("bika_setup_catalog", "Type", "", "FieldIndex"), ("bika_setup_catalog", "UID", "", "FieldIndex"), ("bika_setup_catalog", "allowedRolesAndUsers", "", "KeywordIndex"), + ("bika_setup_catalog", "category_uid", "", "KeywordIndex"), ("bika_setup_catalog", "created", "", "DateIndex"), ("bika_setup_catalog", "department_title", "", "KeywordIndex"), ("bika_setup_catalog", "department_uid", "", "KeywordIndex"), - ("bika_setup_catalog", "getCategoryUID", "", "FieldIndex"), ("bika_setup_catalog", "getClientUID", "", "FieldIndex"), ("bika_setup_catalog", "getId", "", "FieldIndex"), ("bika_setup_catalog", "getKeyword", "", "FieldIndex"), diff --git a/bika/lims/skins/bika/ploneCustom.css.dtml b/bika/lims/skins/bika/ploneCustom.css.dtml index b020c7d4ed..09fad1c8fa 100644 --- a/bika/lims/skins/bika/ploneCustom.css.dtml +++ b/bika/lims/skins/bika/ploneCustom.css.dtml @@ -1394,9 +1394,4 @@ div.bika-listing-table-top-hooks div.listing-hook-top-wide { margin-bottom: 0; } -.ws-analyses-search-button { - clear: left; - float: left; -} - diff --git a/bika/lims/upgrade/v01_03_003.py b/bika/lims/upgrade/v01_03_003.py index fc367562db..2d861f4926 100644 --- a/bika/lims/upgrade/v01_03_003.py +++ b/bika/lims/upgrade/v01_03_003.py @@ -66,6 +66,9 @@ # Default listing_searchable_text index adapter for setup_catalog ("bika_setup_catalog", "listing_searchable_text", "TextIndexNG3"), + + # Default listing_searchable_text index adapter for setup_catalog + ("bika_setup_catalog", "category_uid", "KeywordIndex"), ] INDEXES_TO_REMOVE = [ @@ -165,6 +168,9 @@ # getDepartmentUID --> department_uid ("bika_setup_catalog", "getDepartmentUID"), + # getCategoryUID --> category_uid + ("bika_setup_catalog", "getCategoryUID"), + ] METADATA_TO_REMOVE = [ diff --git a/bika/lims/validators.py b/bika/lims/validators.py index 9f22d02920..2dc5088302 100644 --- a/bika/lims/validators.py +++ b/bika/lims/validators.py @@ -658,8 +658,7 @@ def __call__(self, value, *args, **kwargs): for category in value: if not category: continue - services = bsc( - portal_type="AnalysisService", getCategoryUID=category) + services = bsc(portal_type="AnalysisService", category_uid=category) for service in services: service = service.getObject() calc = service.getCalculation() From 481de70ddb6ee87336d6ab75ba42e97d44a8fad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Tue, 3 Dec 2019 17:01:21 +0100 Subject: [PATCH 96/96] Simplify to_searchable_metadata function --- bika/lims/api/__init__.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bika/lims/api/__init__.py b/bika/lims/api/__init__.py index 773df71713..5e248920c1 100644 --- a/bika/lims/api/__init__.py +++ b/bika/lims/api/__init__.py @@ -1323,12 +1323,8 @@ def to_searchable_text_metadata(value): values = map(to_searchable_text_metadata, value) values = filter(None, values) return " ".join(values) - if isinstance(value, (dict)): - values = set() - for k, v in value.items(): - values.add(to_searchable_text_metadata(v)) - values = filter(None, values) - return " ".join(values) + if isinstance(value, dict): + return to_searchable_text_metadata(value.values()) if is_date(value): return value.strftime("%Y-%m-%d") if is_at_content(value):