Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter Templates field when Sample Type is selected in Sample Add form #1481

Merged
merged 33 commits into from
Nov 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
97524e7
Cleanup getClientUID fields (added IClientBindable and ClientBindable)
xispa Nov 22, 2019
a33ee84
Cleanup getClientUID search criteria for Add form
xispa Nov 22, 2019
49a07b6
No fixme anymore
xispa Nov 22, 2019
7fe9b8e
Sanitize AnalysisRequest content type regarding Client fields
xispa Nov 22, 2019
44532fc
BatchReferenceWidgetVocabulary -> ClientBindableReferenceWidgetVocabu…
xispa Nov 22, 2019
c798735
Upgrade step for client fields reindexing
xispa Nov 22, 2019
2631317
Remove stale js that applies field filters in Sample view
xispa Nov 22, 2019
77ec02a
ajaxGetClientInfo is no longer needed
xispa Nov 22, 2019
b390684
Remove unnecessary stuff (client.ajax.ReferenceWidgetVocabulary)
xispa Nov 22, 2019
17d5a60
Make ARReport ClientBindable
xispa Nov 22, 2019
ae47c20
Omit search filter for non-bindable portal_types
xispa Nov 22, 2019
779254b
Sample edit form - some selection widgets empty (CHANGES)
xispa Nov 22, 2019
28674ee
Typo
xispa Nov 22, 2019
4283628
Fix test
xispa Nov 22, 2019
f78ac4c
Removal of unnecessary functions (provided by ClientBindable)
xispa Nov 22, 2019
1f8369d
Cleanup of code that is no longer necessary
xispa Nov 22, 2019
0472ab0
ClientBindable -> ClientAwareMixin
xispa Nov 25, 2019
71e4039
Better way of returning a Client from acquisition chain
xispa Nov 25, 2019
a423dd4
Replace clientbindable namespace
xispa Nov 25, 2019
a03c694
Use six for isinstance
xispa Nov 25, 2019
29f5d9d
Merge branch 'master' into i1476
xispa Nov 25, 2019
dbd7eda
Filter Templates field when Sample Type is selected in Sample Add form
xispa Nov 26, 2019
48ee2bb
Merge branch 'master' of github.com:senaite/senaite.core into i968
xispa Nov 27, 2019
ba94730
getSampleTypeUID index refactoring
xispa Nov 27, 2019
64b2486
Remove SampleTypeVocabulary (no longer used)
xispa Nov 28, 2019
fa962b7
Index: getSampleTypeUID --> sampletype_uids
xispa Nov 28, 2019
c0838ab
Added code header
xispa Nov 28, 2019
244dc31
Added some comments
xispa Nov 28, 2019
49cbaa5
security.public and titles separated with ", "
xispa Nov 28, 2019
0006e31
Organize imports
xispa Nov 28, 2019
bdfe66a
Add getSampleTypesTitle in ISampleTypeAwareMixin interface
xispa Nov 28, 2019
da45ff6
Remove stupid conditional
xispa Nov 28, 2019
9f006ae
Merge branch 'master' into i968
ramonski Nov 28, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Changelog

**Added**

- #1481 Filter Templates field when Sample Type is selected in Sample Add form
- #1483 Added Accredited symbol in Analyses listings
- #1466 Support for "readonly" and "hidden" visibility modes in ReferenceWidget

Expand Down
19 changes: 14 additions & 5 deletions bika/lims/browser/analysisrequest/add2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,16 +1013,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(), ''],
"sampletype_uids": [sample_type_uid, None],
"getClientUID": [client_uid, ""],
"sort_order": "descending",
},
# Display Specifications that have this sample type assigned only
"Specification": {
"getSampleTypeTitle": obj.Title(),
"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": {
"sampletype_uids": [sample_type_uid, None],
"getClientUID": [client_uid, ""],
"sort_order": "descending",
}
}
info["filter_queries"] = filter_queries
Expand Down Expand Up @@ -1152,7 +1160,8 @@ def ajax_get_flush_settings(self):
],
"SampleType": [
"SamplePoint",
"Specification"
"Specification",
"Template",
],
"PrimarySample": [
"Batch"
Expand Down
36 changes: 36 additions & 0 deletions bika/lims/catalog/indexers/bikasetup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -*- 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 bika.lims.interfaces import ISampleTypeAwareMixin


@indexer(ISampleTypeAwareMixin, IBikaSetupCatalog)
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
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, )
8 changes: 8 additions & 0 deletions bika/lims/catalog/indexers/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@
<!-- Whether the object is neither cancelled nor invalid -->
<adapter name="is_active" factory=".is_active"/>


<!-- BikaSetup Catalog Index adapters -->

<!-- sampletype_uids: used in Add Sample form to filter Sample Points,
Specifications and Templates when a Sample Type is selected -->
<adapter name="sampletype_uids" factory=".bikasetup.sampletype_uids"/>


<!-- Auditlog Catalog Index Adapters -->
<adapter name="action" factory=".auditlog.action"/>
<adapter name="actor" factory=".auditlog.actor"/>
Expand Down
2 changes: 1 addition & 1 deletion bika/lims/content/analysisrequest.py
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@
'width': '30',
'label': _('Title'),
'align': 'left'},
{'columnName': 'SampleTypeTitle',
{'columnName': 'getSampleTypeTitle',
'width': '70',
'label': _('SampleType'),
'align': 'left'},
Expand Down
56 changes: 15 additions & 41 deletions bika/lims/content/analysisspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +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.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 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
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((

Expand All @@ -55,21 +53,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(
Expand Down Expand Up @@ -119,21 +102,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)
Expand All @@ -155,9 +131,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):
Expand Down
36 changes: 16 additions & 20 deletions bika/lims/content/artemplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +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.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
Expand All @@ -42,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",
Expand Down Expand Up @@ -96,13 +99,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,
Expand Down Expand Up @@ -300,7 +296,7 @@
schema["title"]._validationLayer()


class ARTemplate(BaseContent, ClientAwareMixin):
class ARTemplate(BaseContent, ClientAwareMixin, SampleTypeAwareMixin):
security = ClassSecurityInfo()
schema = schema
displayContentsTab = False
Expand Down
68 changes: 11 additions & 57 deletions bika/lims/content/samplepoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -34,8 +33,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 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
Expand All @@ -45,9 +46,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(
Expand Down Expand Up @@ -91,13 +91,17 @@
required=0,
multiValued=1,
allowed_types=('SampleType',),
vocabulary='SampleTypesVocabulary',
relationship='SamplePointSampleType',
widget=BikaReferenceWidget(
label=_("Sample Types"),
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,
),
),

Expand Down Expand Up @@ -126,7 +130,8 @@
schema['description'].schemata = 'default'


class SamplePoint(BaseContent, HistoryAwareMixin, ClientAwareMixin):
class SamplePoint(BaseContent, HistoryAwareMixin, ClientAwareMixin,
SampleTypeAwareMixin):
implements(IDeactivable)
security = ClassSecurityInfo()
displayContentsTab = False
Expand All @@ -141,31 +146,6 @@ 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
"""
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())

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.
Expand Down Expand Up @@ -200,31 +180,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)
Loading