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

Display the Unit in Profile Analyses Listing #659

Merged
merged 10 commits into from
Feb 15, 2018
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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 @@ -10,6 +10,7 @@ Changelog

**Changed**

- #659 Display the Unit in Profile Analyses Listing
- #655 Updated German Translations
- #647 Refactored bika.lims.bikalisting.js + several functional fixtures
- #637 Deassociate Analysis Request portal type from `worksheetanalysis_workflow`
Expand Down
255 changes: 131 additions & 124 deletions bika/lims/browser/widgets/analysisprofileanalyseswidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,27 @@
# Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst.

from AccessControl import ClassSecurityInfo
from Products.Archetypes.Registry import registerWidget, registerPropertyType
from Products.Archetypes.Widget import TypesWidget
from Products.CMFCore.utils import getToolByName
from bika.lims.browser import BrowserView
from bika.lims import bikaMessageFactory as _
from bika.lims.utils import t
from bika.lims.browser.bika_listing import BikaListingView
from Products.Archetypes.Registry import registerWidget
from Products.Archetypes.Widget import TypesWidget
from Products.CMFCore.utils import getToolByName
from zope.i18n.locales import locales
from operator import itemgetter
import json


class AnalysisProfileAnalysesView(BikaListingView):
""" bika listing to display Analyses table for an Analysis Profile.
"""View to display Analyses table for an Analysis Profile.
"""

def __init__(self, context, request, fieldvalue=[], allow_edit=False):
super(AnalysisProfileAnalysesView, self).__init__(context, request)

self.catalog = "bika_setup_catalog"
self.contentFilter = {'portal_type': 'AnalysisService',
'sort_on': 'sortable_title',
'inactive_state': 'active',}
self.contentFilter = {
"portal_type": "AnalysisService",
"sort_on": "sortable_title",
"inactive_state": "active",
}
self.context_actions = {}
self.base_url = self.context.absolute_url()
self.view_url = self.base_url
Expand All @@ -48,118 +48,117 @@ def __init__(self, context, request, fieldvalue=[], allow_edit=False):
self.expand_all_categories = False
self.ajax_categories = True
self.ajax_categories_url = self.context.absolute_url() + \
"/analysisprofile_analysesview"
self.category_index = 'getCategoryTitle'
"/analysisprofile_analysesview"
self.category_index = "getCategoryTitle"

self.columns = {
'Title': {'title': _('Service'),
'index': 'sortable_title',
'sortable': False,},
'Price': {'title': _('Price'),
'sortable': False,},
"Title": {
"title": _("Service"),
"index": "sortable_title",
"sortable": False,
},
"Unit": {
"title": _("Unit"),
"index": "getUnit",
"sortable": False,
},
"Price": {
"title": _("Price"),
"sortable": False,
},
}

self.review_states = [
{'id':'default',
'title': _('All'),
'contentFilter':{},
'columns': ['Title',
'Price',
],
'transitions': [{'id':'empty'}, ], # none
},
{
"id": "default",
"title": _("All"),
"contentFilter": {},
"columns": [
"Title",
"Unit",
"Price",
],
"transitions": [
{"id": "empty"},
],
},
]


if not self.context.bika_setup.getShowPrices():
self.review_states[0]['columns'].remove('Price')
self.review_states[0]["columns"].remove("Price")

self.fieldvalue = fieldvalue
self.selected = [x.UID() for x in fieldvalue]

if self.aq_parent.portal_type == 'AnalysisProfile':
if self.aq_parent.portal_type == "AnalysisProfile":
# Custom settings for the Analysis Services assigned to
# the Analysis Profile
# https://jira.bikalabs.com/browse/LIMS-1324
self.profile = self.aq_parent
self.columns['Hidden'] = {'title': _('Hidden'),
'sortable': False,
'type': 'boolean'}
self.review_states[0]['columns'].insert(1, 'Hidden')


def folderitems(self):
self.categories = []

bsc = getToolByName(self.context, 'bika_setup_catalog')
wf = getToolByName(self.context, 'portal_workflow')
mtool = getToolByName(self.context, 'portal_membership')
self.columns["Hidden"] = {
"title": _("Hidden"),
"sortable": False,
"type": "boolean",
}
self.review_states[0]["columns"].insert(1, "Hidden")

def before_render(self):
mtool = getToolByName(self.context, "portal_membership")
member = mtool.getAuthenticatedMember()
roles = member.getRoles()
self.allow_edit = 'LabManager' in roles or 'Manager' in roles

items = BikaListingView.folderitems(self)

for x in range(len(items)):
if not items[x].has_key('obj'): continue
obj = items[x]['obj']

cat = obj.getCategoryTitle()
# Category (upper C) is for display column value
items[x]['Category'] = cat
if self.do_cats:
# category is for bika_listing to groups entries
items[x]['category'] = cat
if cat not in self.categories:
self.categories.append(cat)

analyses = [a.UID() for a in self.fieldvalue]

items[x]['selected'] = items[x]['uid'] in analyses

items[x]['class']['Title'] = 'service_title'

calculation = obj.getCalculation()
items[x]['Calculation'] = calculation and calculation.Title()

locale = locales.getLocale('en')
currency = self.context.bika_setup.getCurrency()
symbol = locale.numbers.currencies[currency].symbol
items[x]['Price'] = "%s %s" % (symbol, obj.getPrice())
items[x]['class']['Price'] = 'nowrap'

after_icons = ''
if obj.getAccredited():
after_icons += "<img\
src='%s/++resource++bika.lims.images/accredited.png'\
title='%s'>"%(self.context.absolute_url(),
_("Accredited"))
if obj.getReportDryMatter():
after_icons += "<img\
src='%s/++resource++bika.lims.images/dry.png'\
title='%s'>"%(self.context.absolute_url(),
_("Can be reported as dry matter"))
if obj.getAttachmentOption() == 'r':
after_icons += "<img\
src='%s/++resource++bika.lims.images/attach_reqd.png'\
title='%s'>"%(self.context.absolute_url(),
_("Attachment required"))
if obj.getAttachmentOption() == 'n':
after_icons += "<img\
src='%s/++resource++bika.lims.images/attach_no.png'\
title='%s'>"%(self.context.absolute_url(),
_('Attachment not permitted'))
if after_icons:
items[x]['after']['Title'] = after_icons

if self.profile:
# Display analyses for this Analysis Service in results?
ser = self.profile.getAnalysisServiceSettings(obj.UID())
items[x]['allow_edit'] = ['Hidden', ]
items[x]['Hidden'] = ser.get('hidden', obj.getHidden())

self.allow_edit = "LabManager" in roles or "Manager" in roles
self.categories.sort()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this self.categories.sort() does nothing here in before_render. Since we don't have an after_render function (that would be nice), the best option would be to add the folderitems function, call super and sort the categories thereafter. Is not elegant, I know, but at least the Analysis Categories will appear sorted alphabetically when "Categorize Analysis Services" is enabled. With this code, the categories will appear in the order the analyses are retrieved (by sortable_title) which is not bad, but is not consistent with the rest.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, thanks, I'll change that

return items

def folderitem(self, obj, item, index):
"""Processed per Analysis
"""
cat = obj.getCategoryTitle()
# Category (upper C) is for display column value
item["Category"] = cat
if self.do_cats:
# category is for bika_listing to groups entries
item["category"] = cat
if cat not in self.categories:
self.categories.append(cat)

analyses = [a.UID() for a in self.fieldvalue]

item["selected"] = item["uid"] in analyses
item["class"]["Title"] = "service_title"

calculation = obj.getCalculation()
item["Calculation"] = calculation and calculation.Title()

locale = locales.getLocale("en")
currency = self.context.bika_setup.getCurrency()
symbol = locale.numbers.currencies[currency].symbol
item["Price"] = u"{} {}".format(symbol, obj.getPrice())
item["class"]["Price"] = "nowrap"

after_icons = ""
if obj.getAccredited():
after_icons += u"<img src='{}/++resource++bika.lims.images/accredited.png' title='{}'>".format(
self.context.absolute_url(), _("Accredited"))
if obj.getReportDryMatter():
after_icons += u"<img src='{}/++resource++bika.lims.images/dry.png' title='{}'>".format(
self.context.absolute_url(), _("Can be reported as dry matter"))
if obj.getAttachmentOption() == "r":
after_icons += u"<img src='{}/++resource++bika.lims.images/attach_reqd.png' title='{}'>".format(
self.context.absolute_url(), _("Attachment required"))
if obj.getAttachmentOption() == "n":
after_icons += u"<img src='%s/++resource++bika.lims.images/attach_no.png' title='%s'>".format(
self.context.absolute_url(), _('Attachment not permitted'))
if after_icons:
item["after"]["Title"] = after_icons

if self.profile:
# Display analyses for this Analysis Service in results?
ser = self.profile.getAnalysisServiceSettings(obj.UID())
item["allow_edit"] = ["Hidden", ]
item["Hidden"] = ser.get("hidden", obj.getHidden())

return item


class AnalysisProfileAnalysesWidget(TypesWidget):
_properties = TypesWidget._properties.copy()
Expand All @@ -172,40 +171,48 @@ class AnalysisProfileAnalysesWidget(TypesWidget):
security = ClassSecurityInfo()

security.declarePublic('process_form')
def process_form(self, instance, field, form, empty_marker = None,
emptyReturnsMarker = False):

def process_form(self, instance, field, form, empty_marker=None,
emptyReturnsMarker=False):
""" Return a list of dictionaries fit for AnalysisProfile/Analyses field
consumption.
"""
bsc = getToolByName(instance, 'bika_setup_catalog')
value = []
service_uids = form.get('uids', None)
service_uids = form.get("uids", None)

# remember the context, because we need to pass that later to the
# listing view (see method `Analyses` below)
self.instance = instance

if instance.portal_type == 'AnalysisProfile':
if instance.portal_type == "AnalysisProfile":
# Hidden analyses?
outs = []
hiddenans = form.get('Hidden', {})
hiddenans = form.get("Hidden", {})
if service_uids:
for uid in service_uids:
hidden = hiddenans.get(uid, '')
hidden = True if hidden == 'on' else False
outs.append({'uid':uid, 'hidden':hidden})
hidden = hiddenans.get(uid, "")
hidden = True if hidden == "on" else False
outs.append({"uid": uid, "hidden": hidden})
instance.setAnalysisServicesSettings(outs)

return service_uids, {}

security.declarePublic('Analyses')
def Analyses(self, field, allow_edit = False):
security.declarePublic("Analyses")

def Analyses(self, field, allow_edit=False):
""" Print analyses table
"""
fieldvalue = getattr(field, field.accessor)()
view = AnalysisProfileAnalysesView(self,
self.REQUEST,
fieldvalue = fieldvalue,
allow_edit = allow_edit)
return view.contents_table(table_only = True)

# N.B. we do not want to pass the field as the context to
# AnalysisProfileAnalysesView, but rather the holding instance
instance = getattr(self, "instance", field.aq_parent)
view = AnalysisProfileAnalysesView(instance,
self.REQUEST,
fieldvalue=fieldvalue,
allow_edit=allow_edit)
return view.contents_table(table_only=True)


registerWidget(AnalysisProfileAnalysesWidget,
title = 'Analysis Profile Analyses selector',
description = ('Analysis Profile Analyses selector'),
)
title='Analysis Profile Analyses selector',
description=('Analysis Profile Analyses selector'),)