From 375a6935a08ce45cbc2c52470e03720a595625d7 Mon Sep 17 00:00:00 2001 From: Campbell Date: Wed, 4 Oct 2017 15:22:03 +0200 Subject: [PATCH 01/15] LIMS-2696: Factor worksheet folderitem into separate method for each column. This is done in bika_listing so that self.column_* will always be called after the rest of folderitem(s) has been run --- bika/lims/browser/bika_listing.py | 18 ++ bika/lims/browser/worksheet/views/folder.py | 245 ++++++++++---------- docs/CHANGELOG.txt | 1 + 3 files changed, 143 insertions(+), 121 deletions(-) diff --git a/bika/lims/browser/bika_listing.py b/bika/lims/browser/bika_listing.py index e6487ea76e..f02a7621e8 100644 --- a/bika/lims/browser/bika_listing.py +++ b/bika/lims/browser/bika_listing.py @@ -1099,6 +1099,8 @@ def folderitems(self, full_objects=False): item = self.folderitem(obj, results_dict, idx) if item: results.append(item) + # Populate column values using self.column_* methods + self._call_column_getters(item, obj) idx += 1 # Need manual_sort? @@ -1110,6 +1112,22 @@ def folderitems(self, full_objects=False): return results + def _call_column_getters(self, item, obj): + """Populate column values using self.column_* methods. These methods + are called if the column is displayed. + """ + # columns to display combines defaults and cookie value + cookie_cols = self.get_toggle_cols() + for col_title, col in self.columns.items(): + if not (col_title in cookie_cols or col['toggle']): + continue + if not hasattr(self, "column_%s" % col_title): + continue + fun = getattr(self, "column_%s" % col_title) + # call each column_* function + if callable(fun): + fun(item, obj) + def contents_table(self, table_only=False): """ If you set table_only to true, then nothing outside of the tag will be printed (form tags, authenticator, etc). diff --git a/bika/lims/browser/worksheet/views/folder.py b/bika/lims/browser/worksheet/views/folder.py index 9a2e23b879..2ef93fa7f2 100644 --- a/bika/lims/browser/worksheet/views/folder.py +++ b/bika/lims/browser/worksheet/views/folder.py @@ -5,31 +5,24 @@ # Copyright 2011-2017 by it's authors. # Some rights reserved. See LICENSE.txt, AUTHORS.txt. -from DateTime import DateTime -from DocumentTemplate import sequence +import json +import logging + from Products.Archetypes.config import REFERENCE_CATALOG from Products.Archetypes.public import DisplayList from Products.CMFCore.utils import getToolByName -from Products.CMFPlone.utils import _createObjectByType from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile -from plone.app.content.browser.interfaces import IFolderContentsView -from plone.app.layout.globals.interfaces import IViewView -from zope.interface import implements - +from bika.lims import PMF from bika.lims import bikaMessageFactory as _ -from bika.lims import PMF, logger -from bika.lims.browser import BrowserView from bika.lims.browser.bika_listing import BikaListingView -from bika.lims.browser.bika_listing import WorkflowAction from bika.lims.permissions import EditWorksheet from bika.lims.permissions import ManageWorksheets -from bika.lims.utils import getUsers, tmpID, t +from bika.lims.utils import getUsers from bika.lims.utils import to_utf8 as _c +from plone.app.content.browser.interfaces import IFolderContentsView +from plone.app.layout.globals.interfaces import IViewView +from zope.interface import implements -import logging -import plone -import json -import zope class FolderView(BikaListingView): @@ -228,9 +221,6 @@ def __init__(self, context, request): 'CreationDate', 'state_title']}, ] - self.display_columns = [ - 'state_title', 'Title', 'Template', - 'CreationDate', 'Analyst', 'Priority'] def __call__(self): self.wf = getToolByName(self, 'portal_workflow') @@ -322,105 +312,9 @@ def folderitem(self, obj, item, index): if not item: return None - item['CreationDate'] = self.ulocalized_time(obj.creation_date) - item['Analyst'] = obj.getAnalyst().strip() - item['Priority'] = '' - item['getPriority'] = '' - - instrument = obj.getInstrument() - item['Instrument'] = instrument.Title() if instrument else '' - - wst = obj.getWorksheetTemplate() - item['Template'] = wst.Title() if wst else '' - if wst: - item['replace']['Template'] = "%s" % \ - (wst.absolute_url(), wst.Title()) - if len(obj.getAnalyses()) == 0: item['table_row_class'] = 'state-empty-worksheet' - layout = obj.getLayout() - item['Title'] = obj.Title() - turl = "manage_results" if len(layout) > 0 else "add_analyses" - item['replace']['Title'] = "%s" % \ - (item['url'], turl, item['Title']) - - if 'Services' in self.display_columns: - # Set services - ws_services = {} - for slot in [s for s in layout if s['type'] == 'a']: - analysis = self.rc.lookupObject(slot['analysis_uid']) - if not analysis: - error = "Analysis with uid '%s' NOT FOUND in Reference Catalog.\n Worksheet: '%s'. Layout: '%s'" % \ - (slot['analysis_uid'], obj, layout) - logging.info(error) - continue - service = analysis.getService() - title = service.Title() - if title not in ws_services: - ws_services[title] = "%s" % \ - (service.absolute_url(), title) - keys = list(ws_services.keys()) - keys.sort() - services = [ws_services[k] for k in keys] - item['Services'] = "" - item['replace']['Services'] = ", ".join(services) - - pos_parent = {} - for slot in layout: - # compensate for bad data caused by a stupid bug. - if type(slot['position']) in (list, tuple): - slot['position'] = slot['position'][0] - if slot['position'] == 'new': - continue - if slot['position'] in pos_parent: - continue - pos_parent[slot['position']] = self.rc.lookupObject(slot['container_uid']) - - if 'SampleTypes' in self.display_columns or \ - 'QC' in self.display_columns: - # Set Sample Types and QC Samples - sampletypes = [] - qcsamples = [] - for container in pos_parent.values(): - if container.portal_type == 'AnalysisRequest': - sampletype = "%s" % \ - (container.getSample().getSampleType().absolute_url(), - container.getSample().getSampleType().Title()) - sampletypes.append(sampletype) - if container.portal_type == 'ReferenceSample': - qcsample = "%s" % \ - (container.absolute_url(), - container.Title()) - qcsamples.append(qcsample) - - sampletypes = list(set(sampletypes)) - sampletypes.sort() - item['SampleTypes'] = "" - item['replace']['SampleTypes'] = ", ".join(sampletypes) - qcsamples = list(set(qcsamples)) - qcsamples.sort() - item['QC'] = "" - item['replace']['QC'] = ", ".join(qcsamples) - item['QCTotals'] = '' - - if 'QCTotals' in self.display_columns or \ - 'RoutineTotals' in self.display_columns: - # Total QC Samples (Total Routine Analyses) - analyses = obj.getAnalyses() - totalQCAnalyses = [a for a in analyses - if a.portal_type == 'ReferenceAnalysis' - or a.portal_type == 'DuplicateAnalysis'] - totalQCSamples = [a.getSample().UID() for a in totalQCAnalyses] - totalQCSamples = list(set(totalQCSamples)) - item['QCTotals'] = str(len(totalQCSamples)) + ' (' + str(len(totalQCAnalyses)) + ')' - - # Total Routine Samples (Total Routine Analyses) - totalRoutineAnalyses = [a for a in analyses if a not in totalQCAnalyses] - totalRoutineSamples = [a.getSample().UID() for a in totalRoutineAnalyses] - totalRoutineSamples = list(set(totalRoutineSamples)) - item['RoutineTotals'] = str(len(totalRoutineSamples)) + ' (' + str(len(totalRoutineAnalyses)) + ')' - if item['review_state'] == 'open' \ and self.allow_edit \ and self.restrict_results == False \ @@ -432,14 +326,123 @@ def folderitem(self, obj, item, index): return item - def folderitems(self): - toggle_cols = self.request.cookies.get('toggle_cols') - display_columns = None - if toggle_cols: - display_columns = json.loads(toggle_cols) - if 'WorksheetFolderlist' in display_columns.keys(): - self.display_columns = display_columns['WorksheetFolderlist'] + def column_RoutineTotals(self, item, obj): + analyses = obj.getAnalyses() + totalRoutineAnalyses = [a for a in analyses + if a.portal_type != 'ReferenceAnalysis' + or a.portal_type != 'DuplicateAnalysis'] + totalRoutineSamples = [a.getSample().UID() for a in + totalRoutineAnalyses] + totalRoutineSamples = list(set(totalRoutineSamples)) + item['RoutineTotals'] = str(len(totalRoutineSamples)) + ' (' + str( + len(totalRoutineAnalyses)) + ')' + + def column_QCTotals(self, item, obj): + analyses = obj.getAnalyses() + totalQCAnalyses = [a for a in analyses + if a.portal_type == 'ReferenceAnalysis' + or a.portal_type == 'DuplicateAnalysis'] + totalQCSamples = [a.getSample().UID() for a in totalQCAnalyses] + totalQCSamples = list(set(totalQCSamples)) + item['QCTotals'] = str(len(totalQCSamples)) + ' (' + str( + len(totalQCAnalyses)) + ')' + + def column_SampleTypes(self, item, obj): + layout = obj.getLayout() + pos_parent = {} + for slot in layout: + if slot['position'] == 'new': + continue + if slot['position'] in pos_parent: + continue + pos_parent[slot['position']] = self.rc.lookupObject( + slot['container_uid']) + sampletypes = [] + for container in pos_parent.values(): + if container.portal_type == 'AnalysisRequest': + sampletype = \ + "%s" % \ + (container.getSample().getSampleType().absolute_url(), + container.getSample().getSampleType().Title()) + sampletypes.append(sampletype) + sampletypes = list(set(sampletypes)) + sampletypes.sort() + item['SampleTypes'] = "" + item['replace']['SampleTypes'] = ", ".join(sampletypes) + + def column_QC(self, item, obj): + layout = obj.getLayout() + pos_parent = {} + for slot in layout: + if slot['position'] == 'new': + continue + if slot['position'] in pos_parent: + continue + pos_parent[slot['position']] = self.rc.lookupObject( + slot['container_uid']) + qcsamples = [] + for container in pos_parent.values(): + if container.portal_type == 'ReferenceSample': + qcsample = "%s" % (container.absolute_url(), + container.Title()) + qcsamples.append(qcsample) + qcsamples = list(set(qcsamples)) + qcsamples.sort() + item['QC'] = "" + item['replace']['QC'] = ", ".join(qcsamples) + item['QCTotals'] = '' + + def column_Priority(self, item, obj): + item['Priority'] = '' + + def column_Analyst(self, item, obj): + item['Analyst'] = obj.getAnalyst().strip() + def column_CreationDate(self, item, obj): + item['CreationDate'] = self.ulocalized_time(obj.creation_date) + + def column_Title(self, item, obj): + layout = obj.getLayout() + item['Title'] = obj.Title() + turl = "manage_results" if len(layout) > 0 else "add_analyses" + item['replace']['Title'] = "%s" % \ + (item['url'], turl, item['Title']) + + def column_Template(self, item, obj): + wst = obj.getWorksheetTemplate() + item['Template'] = wst.Title() if wst else '' + if wst: + item['replace']['Template'] = "%s" % \ + (wst.absolute_url(), wst.Title()) + + def column_Services(self, item, obj): + # Set services + layout = obj.getLayout() + ws_services = {} + for slot in [s for s in layout if s['type'] == 'a']: + analysis = self.rc.lookupObject(slot['analysis_uid']) + if not analysis: + error = "Analysis with uid '%s' NOT FOUND in Reference " \ + "Catalog.\n Worksheet: '%s'. Layout: '%s'" % \ + (slot['analysis_uid'], obj, layout) + logging.info(error) + continue + service = analysis.getService() + title = service.Title() + if title not in ws_services: + ws_services[title] = "%s" % \ + (service.absolute_url(), title) + keys = list(ws_services.keys()) + keys.sort() + services = [ws_services[k] for k in keys] + item['Services'] = "" + item['replace']['Services'] = ", ".join(services) + + def column_Instrument(self, item, obj): + instrument = obj.getInstrument() + item['Instrument'] = instrument.Title() if instrument else '' + + def folderitems(self): items = BikaListingView.folderitems(self) # can_reassigned value is assigned in folderitem(obj,item,index) function diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index fb23dd9874..497fbdd2d7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -1,6 +1,7 @@ 3.4.0 (unreleased) ------------------ +- LIMS-2696: bika_listing performance: refactor folderitem to use column_* methods - BC-147: Default empty WS view should list on due date - Issue-2103: WS Templates not offered for selection - Instrument selection for creating WSs does not work From baee8e1391b6856f62e522dc2447b2f689802a5c Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Wed, 4 Oct 2017 18:09:53 +0200 Subject: [PATCH 02/15] BC-177: Performance on AR Listing --- .../analysisrequest/analysisrequests.py | 166 ++++++++++++++---- 1 file changed, 130 insertions(+), 36 deletions(-) diff --git a/bika/lims/browser/analysisrequest/analysisrequests.py b/bika/lims/browser/analysisrequest/analysisrequests.py index 18815e847d..336b4d0787 100644 --- a/bika/lims/browser/analysisrequest/analysisrequests.py +++ b/bika/lims/browser/analysisrequest/analysisrequests.py @@ -711,15 +711,7 @@ def isItemAllowed(self, obj): result = len(matches) > 0 return result - def folderitem(self, obj, item, index): - # Additional info from AnalysisRequest to be added in the item generated - # by default by bikalisting. - - # Call the folderitem method from the base class - item = BikaListingView.folderitem(self, obj, item, index) - if not item: - return None - + def column_Client(self, item, obj): member = self.mtool.getAuthenticatedMember() roles = member.getRoles() hideclientlink = 'RegulatoryInspector' in roles \ @@ -736,23 +728,29 @@ def folderitem(self, obj, item, index): if (hideclientlink == False): item['replace']['Client'] = "%s" % \ (obj.aq_parent.absolute_url(), obj.aq_parent.Title()) - item['Creator'] = self.user_fullname(obj.Creator()) + + def column_RequestedID(self, item, obj): item['getRequestID'] = obj.getRequestID() item['replace']['getRequestID'] = "%s" % \ (url, item['getRequestID']) + + def column_Creator(self, item, obj): + item['Creator'] = self.user_fullname(obj.Creator()) + + def column_getSample(self, item, obj): + sample = obj.getSample() item['getSample'] = sample item['replace']['getSample'] = \ "%s" % (sample.absolute_url(), sample.Title()) - item['replace']['getProfilesTitle'] = ", ".join( - [p.Title() for p in obj.getProfiles()]) - + def column_getAnalysesNum(self, item, obj): analysesnum = obj.getAnalysesNum() if analysesnum: item['getAnalysesNum'] = str(analysesnum[0]) + '/' + str(analysesnum[1]) else: item['getAnalysesNum'] = '' + def column_BatchID(self, item, obj): batch = obj.getBatch() if batch: item['BatchID'] = batch.getBatchID() @@ -761,52 +759,45 @@ def folderitem(self, obj, item, index): else: item['BatchID'] = '' + def column_SubGroup(self, item, obj): val = obj.Schema().getField('SubGroup').get(obj) item['SubGroup'] = val.Title() if val else '' + def column_getAnalysesNum(self, item, obj): sd = obj.getSample().getSamplingDate() item['SamplingDate'] = \ self.ulocalized_time(sd, long_format=1) if sd else '' + + def column_getDateReceived(self, item, obj): item['getDateReceived'] = \ self.ulocalized_time(obj.getDateReceived()) + + def column_getDatePublished(self, item, obj): item['getDatePublished'] = \ self.ulocalized_time(getTransitionDate(obj, 'publish')) + + def column_getDateVerified(self, item, obj): item['getDateVerified'] = \ self.ulocalized_time(getTransitionDate(obj, 'verify')) + def column_SamplingDeviation(self, item, obj): deviation = sample.getSamplingDeviation() item['SamplingDeviation'] = deviation and deviation.Title() or '' + + def column_Priority(self, item, obj): priority = obj.getPriority() item['Priority'] = '' # priority.Title() + def column_getStorageLocation(self, item, obj): item['getStorageLocation'] = sample.getStorageLocation() and sample.getStorageLocation().Title() or '' - item['AdHoc'] = sample.getAdHoc() and True or '' - after_icons = "" - state = self.workflow.getInfoFor(obj, 'worksheetanalysis_review_state') - if state == 'assigned': - after_icons += "" % \ - (self.portal_url, t(_("All analyses assigned"))) - if self.workflow.getInfoFor(obj, 'review_state') == 'invalid': - after_icons += "" % \ - (self.portal_url, t(_("Results have been withdrawn"))) - if obj.getLate(): - after_icons += "" % \ - (self.portal_url, t(_("Late Analyses"))) - if sd and sd > DateTime(): - after_icons += "" % \ - (self.portal_url, t(_("Future dated sample"))) - if obj.getInvoiceExclude(): - after_icons += "" % \ - (self.portal_url, t(_("Exclude from invoice"))) - if sample.getSampleType().getHazardous(): - after_icons += "" % \ - (self.portal_url, t(_("Hazardous"))) - if after_icons: - item['after']['getRequestID'] = after_icons + def column_Adhoc(self, item, obj): + item['AdHoc'] = sample.getAdHoc() and True or '' + def column_Created(self, item, obj): item['Created'] = self.ulocalized_time(obj.created()) + def column_ClientContact(self, item, obj): contact = obj.getContact() if contact: item['ClientContact'] = contact.Title() @@ -815,6 +806,7 @@ def folderitem(self, obj, item, index): else: item['ClientContact'] = "" + def column_getDateSampled(self, item, obj): SamplingWorkflowEnabled = sample.getSamplingWorkflowEnabled() if SamplingWorkflowEnabled and (not sd or not sd > DateTime()): datesampled = self.ulocalized_time( @@ -852,6 +844,69 @@ def folderitem(self, obj, item, index): (username in samplers.keys() and username) or '' item['getSampler'] = Sampler + def column_Sampler(self, item, obj): + SamplingWorkflowEnabled = sample.getSamplingWorkflowEnabled() + if SamplingWorkflowEnabled and (not sd or not sd > DateTime()): + datesampled = self.ulocalized_time( + sample.getDateSampled(), long_format=True) + if not datesampled: + datesampled = self.ulocalized_time( + DateTime(), long_format=True) + item['class']['getDateSampled'] = 'provisional' + sampler = sample.getSampler().strip() + if sampler: + item['replace']['getSampler'] = self.user_fullname(sampler) + if 'Sampler' in member.getRoles() and not sampler: + sampler = member.id + item['class']['getSampler'] = 'provisional' + else: + datesampled = '' + sampler = '' + item['getDateSampled'] = datesampled + item['getSampler'] = sampler + + # sampling workflow - inline edits for Sampler and Date Sampled + checkPermission = self.context.portal_membership.checkPermission + state = self.workflow.getInfoFor(obj, 'review_state') + if state == 'to_be_sampled' \ + and checkPermission(SampleSample, obj) \ + and (not sd or not sd > DateTime()): + item['required'] = ['getSampler', 'getDateSampled'] + item['allow_edit'] = ['getSampler', 'getDateSampled'] + samplers = getUsers(sample, ['Sampler', 'LabManager', 'Manager']) + username = member.getUserName() + users = [({'ResultValue': u, 'ResultText': samplers.getValue(u)}) + for u in samplers] + item['choices'] = {'getSampler': users} + Sampler = sampler and sampler or \ + (username in samplers.keys() and username) or '' + item['getSampler'] = Sampler + + def column_getDatePreserved(self, item, obj): + # These don't exist on ARs + # XXX This should be a list of preservers... + item['getPreserver'] = '' + item['getDatePreserved'] = '' + + # inline edits for Preserver and Date Preserved + checkPermission = self.context.portal_membership.checkPermission + if checkPermission(PreserveSample, obj): + item['required'] = ['getPreserver', 'getDatePreserved'] + item['allow_edit'] = ['getPreserver', 'getDatePreserved'] + preservers = getUsers(obj, ['Preserver', 'LabManager', 'Manager']) + username = member.getUserName() + users = [({'ResultValue': u, 'ResultText': preservers.getValue(u)}) + for u in preservers] + item['choices'] = {'getPreserver': users} + preserver = username in preservers.keys() and username or '' + item['getPreserver'] = preserver + item['getDatePreserved'] = self.ulocalized_time( + DateTime(), + long_format=1) + item['class']['getPreserver'] = 'provisional' + item['class']['getDatePreserved'] = 'provisional' + + def column_getDatePreserved(self, item, obj): # These don't exist on ARs # XXX This should be a list of preservers... item['getPreserver'] = '' @@ -875,6 +930,45 @@ def folderitem(self, obj, item, index): item['class']['getPreserver'] = 'provisional' item['class']['getDatePreserved'] = 'provisional' + + def folderitem(self, obj, item, index): + # Additional info from AnalysisRequest to be added in the item generated + # by default by bikalisting. + + # Call the folderitem method from the base class + item = BikaListingView.folderitem(self, obj, item, index) + if not item: + return None + + member = self.mtool.getAuthenticatedMember() + item['replace']['getProfilesTitle'] = ", ".join( + [p.Title() for p in obj.getProfiles()]) + + sd = obj.getSample().getSamplingDate() + + after_icons = "" + state = self.workflow.getInfoFor(obj, 'worksheetanalysis_review_state') + if state == 'assigned': + after_icons += "" % \ + (self.portal_url, t(_("All analyses assigned"))) + if self.workflow.getInfoFor(obj, 'review_state') == 'invalid': + after_icons += "" % \ + (self.portal_url, t(_("Results have been withdrawn"))) + if obj.getLate(): + after_icons += "" % \ + (self.portal_url, t(_("Late Analyses"))) + if sd and sd > DateTime(): + after_icons += "" % \ + (self.portal_url, t(_("Future dated sample"))) + if obj.getInvoiceExclude(): + after_icons += "" % \ + (self.portal_url, t(_("Exclude from invoice"))) + if sample.getSampleType().getHazardous(): + after_icons += "" % \ + (self.portal_url, t(_("Hazardous"))) + if after_icons: + item['after']['getRequestID'] = after_icons + # Submitting user may not verify results if item['review_state'] == 'to_be_verified': username = member.getUserName() From f5cd2a89d32da1ab32355afa7a6b2554a334f3a1 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Wed, 4 Oct 2017 18:44:22 +0200 Subject: [PATCH 03/15] BC-177: Performance on Clients Listing --- bika/lims/browser/clientfolder.py | 58 ++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/bika/lims/browser/clientfolder.py b/bika/lims/browser/clientfolder.py index b3964b1cd9..95b0445f6a 100644 --- a/bika/lims/browser/clientfolder.py +++ b/bika/lims/browser/clientfolder.py @@ -160,31 +160,57 @@ def getClientList(self, contentFilter): return clients - def folderitems(self): - self.contentsMethod = self.getClientList - items = BikaListingView.folderitems(self) + def column_EmailAddress(self, item, obj): + if "obj" in item: + obj = item['obj'] + item['EmailAddress'] = obj.getEmailAddress() + item['replace']['EmailAddress'] = "%s" % \ + ('mailto:%s' % obj.getEmailAddress(), obj.getEmailAddress()) + + def column_Phone(self, item, obj): + if "obj" in item: + obj = item['obj'] + item['Phone'] = obj.getPhone() + + def column_ClientID(self, item, obj): + if "obj" in item: + obj = item['obj'] + item['ClientID'] = obj.getClientID() + + def column_Fax(self, item, obj): + if "obj" in item: + obj = item['obj'] + item['Fax'] = obj.getFax() + + def column_BulkDiscount(self, item, obj): + if "obj" in item: + obj = item['obj'] + item['BulkDiscount'] = obj.getBulkDiscount() and 'Y' or 'N' + + def column_title(self, item, obj): registry = getUtility(IRegistry) if 'bika.lims.client.default_landing_page' in registry: landing_page = registry['bika.lims.client.default_landing_page'] else: landing_page = 'analysisrequests' - for item in items: - if "obj" not in item: - continue + item['replace']['title'] = "%s" % \ + (item['url'], landing_page.encode('ascii'), item['title']) + + def column_MemberDiscountApplies(self, item, obj): + if "obj" in item: obj = item['obj'] + item['MemberDiscountApplies'] = obj.getMemberDiscountApplies() and 'Y' or 'N' - item['replace']['title'] = "%s" % \ - (item['url'], landing_page.encode('ascii'), item['title']) - item['EmailAddress'] = obj.getEmailAddress() - item['replace']['EmailAddress'] = "%s" % \ - ('mailto:%s' % obj.getEmailAddress(), obj.getEmailAddress()) - item['Phone'] = obj.getPhone() - item['Fax'] = obj.getFax() - item['ClientID'] = obj.getClientID() - item['BulkDiscount'] = obj.getBulkDiscount() and 'Y' or 'N' - item['MemberDiscountApplies'] = obj.getMemberDiscountApplies() and 'Y' or 'N' + def folderitems(self): + self.contentsMethod = self.getClientList + items = BikaListingView.folderitems(self) + registry = getUtility(IRegistry) + if 'bika.lims.client.default_landing_page' in registry: + landing_page = registry['bika.lims.client.default_landing_page'] + else: + landing_page = 'analysisrequests' return items From 39c0c49a32d4ed20efe1336e3774826475652004 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Wed, 4 Oct 2017 19:06:45 +0200 Subject: [PATCH 04/15] -177: Performance on Reference Samples and AR Listings --- .../analysisrequest/analysisrequests.py | 12 +++++++- bika/lims/browser/referencesample.py | 29 +++++++++++++++---- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/bika/lims/browser/analysisrequest/analysisrequests.py b/bika/lims/browser/analysisrequest/analysisrequests.py index 336b4d0787..e7d2172533 100644 --- a/bika/lims/browser/analysisrequest/analysisrequests.py +++ b/bika/lims/browser/analysisrequest/analysisrequests.py @@ -719,7 +719,6 @@ def column_Client(self, item, obj): and 'LabManager' not in roles \ and 'LabClerk' not in roles - sample = obj.getSample() url = obj.absolute_url() if getSecurityManager().checkPermission(EditResults, obj): url += "/manage_results" @@ -781,6 +780,7 @@ def column_getDateVerified(self, item, obj): self.ulocalized_time(getTransitionDate(obj, 'verify')) def column_SamplingDeviation(self, item, obj): + sample = obj.getSample() deviation = sample.getSamplingDeviation() item['SamplingDeviation'] = deviation and deviation.Title() or '' @@ -789,9 +789,11 @@ def column_Priority(self, item, obj): item['Priority'] = '' # priority.Title() def column_getStorageLocation(self, item, obj): + sample = obj.getSample() item['getStorageLocation'] = sample.getStorageLocation() and sample.getStorageLocation().Title() or '' def column_Adhoc(self, item, obj): + sample = obj.getSample() item['AdHoc'] = sample.getAdHoc() and True or '' def column_Created(self, item, obj): @@ -807,6 +809,9 @@ def column_ClientContact(self, item, obj): item['ClientContact'] = "" def column_getDateSampled(self, item, obj): + sd = obj.getSample().getSamplingDate() + sample = obj.getSample() + member = self.mtool.getAuthenticatedMember() SamplingWorkflowEnabled = sample.getSamplingWorkflowEnabled() if SamplingWorkflowEnabled and (not sd or not sd > DateTime()): datesampled = self.ulocalized_time( @@ -845,6 +850,8 @@ def column_getDateSampled(self, item, obj): item['getSampler'] = Sampler def column_Sampler(self, item, obj): + sd = obj.getSample().getSamplingDate() + sample = obj.getSample() SamplingWorkflowEnabled = sample.getSamplingWorkflowEnabled() if SamplingWorkflowEnabled and (not sd or not sd > DateTime()): datesampled = self.ulocalized_time( @@ -883,6 +890,7 @@ def column_Sampler(self, item, obj): item['getSampler'] = Sampler def column_getDatePreserved(self, item, obj): + member = self.mtool.getAuthenticatedMember() # These don't exist on ARs # XXX This should be a list of preservers... item['getPreserver'] = '' @@ -907,6 +915,7 @@ def column_getDatePreserved(self, item, obj): item['class']['getDatePreserved'] = 'provisional' def column_getDatePreserved(self, item, obj): + member = self.mtool.getAuthenticatedMember() # These don't exist on ARs # XXX This should be a list of preservers... item['getPreserver'] = '' @@ -945,6 +954,7 @@ def folderitem(self, obj, item, index): [p.Title() for p in obj.getProfiles()]) sd = obj.getSample().getSamplingDate() + sample = obj.getSample() after_icons = "" state = self.workflow.getInfoFor(obj, 'worksheetanalysis_review_state') diff --git a/bika/lims/browser/referencesample.py b/bika/lims/browser/referencesample.py index d47b51126a..16708acb3d 100644 --- a/bika/lims/browser/referencesample.py +++ b/bika/lims/browser/referencesample.py @@ -152,21 +152,38 @@ def isItemAllowed(self, obj): allowed = super(ReferenceAnalysesView, self).isItemAllowed(obj) return allowed if not allowed else obj.getResult() != '' - def folderitem(self, obj, item, index): - item = super(ReferenceAnalysesView, self).folderitem(obj, item, index) - if not item: - return None + def column_Category(self, item, obj): service = obj.getService() item['Category'] = service.getCategoryTitle() + + def column_Service(self, item, obj): + service = obj.getService() item['Service'] = service.Title() + + def column_Captured(self, item, obj): + service = obj.getService() item['Captured'] = self.ulocalized_time(obj.getResultCaptureDate()) + + def column_Worksheet(self, item, obj): brefs = obj.getBackReferences("WorksheetAnalysis") item['Worksheet'] = brefs and brefs[0].Title() or '' + + def column_Keyword(self, item, obj): + service = obj.getService() + item['Keyword'] = service.getKeyword() + + def column_Unit(self, item, obj): + service = obj.getService() + item['Unit'] = service.getUnit() + + def folderitem(self, obj, item, index): + item = super(ReferenceAnalysesView, self).folderitem(obj, item, index) + if not item: + return None + service = obj.getService() # The following item keywords are required for the # JSON return value below, which is used to render graphs. # they are not actually used in the table rendering. - item['Keyword'] = service.getKeyword() - item['Unit'] = service.getUnit() self.addToJSON(obj, service, item) return item From 21ab3ec8593141411c5fff5cf18ac64953b3d81c Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Wed, 4 Oct 2017 19:27:17 +0200 Subject: [PATCH 05/15] -177: Performance on Batch Listing --- bika/lims/browser/batchfolder.py | 43 +++++++++++++++++++------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/bika/lims/browser/batchfolder.py b/bika/lims/browser/batchfolder.py index bdce25b8f4..b4de69eca7 100644 --- a/bika/lims/browser/batchfolder.py +++ b/bika/lims/browser/batchfolder.py @@ -132,34 +132,41 @@ def isItemAllowed(self, obj): return True return False - def folderitems(self): - self.filter_indexes = None - - items = BikaListingView.folderitems(self) - for x in range(len(items)): - if 'obj' not in items[x]: - continue - obj = items[x]['obj'] - + def column_BatchID(self, item, obj): + if 'obj' in item: + obj = item['obj'] bid = obj.getBatchID() - items[x]['BatchID'] = bid - items[x]['replace']['BatchID'] = "%s" % (items[x]['url'], 'analysisrequests', bid) + item['BatchID'] = bid + item['replace']['BatchID'] = "%s" % (item['url'], 'analysisrequests', bid) + def column_Title(self, item, obj): + if 'obj' in item: + obj = item['obj'] title = obj.Title() - items[x]['Title'] = title - items[x]['replace']['Title'] = "%s" % (items[x]['url'], 'analysisrequests', title) + item['Title'] = title + item['replace']['Title'] = "%s" % (item['url'], 'analysisrequests', title) + def column_Client(self, item, obj): + if 'obj' in item: + obj = item['obj'] if obj.getClient(): - items[x]['Client'] = obj.getClient().Title() - items[x]['replace']['Client'] = "%s" % ( obj.getClient().absolute_url(), obj.getClient().Title()) + item['Client'] = obj.getClient().Title() + item['replace']['Client'] = "%s" % ( obj.getClient().absolute_url(), obj.getClient().Title()) else: - items[x]['Client'] = '' + item['Client'] = '' + def column_Client(self, item, obj): + if 'obj' in item: + obj = item['obj'] date = obj.Schema().getField('BatchDate').get(obj) if callable(date): date = date() - items[x]['BatchDate'] = date - items[x]['replace']['BatchDate'] = self.ulocalized_time(date) + item['BatchDate'] = date + item['replace']['BatchDate'] = self.ulocalized_time(date) + + def folderitems(self): + self.filter_indexes = None + items = BikaListingView.folderitems(self) return items From f17134d07b85e8342a3429f6a39510c17367fe57 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Wed, 4 Oct 2017 20:40:02 +0200 Subject: [PATCH 06/15] Performance on ARImport Listing --- bika/lims/browser/arimports.py | 62 +++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/bika/lims/browser/arimports.py b/bika/lims/browser/arimports.py index f1a01c0fd2..70c90a077c 100644 --- a/bika/lims/browser/arimports.py +++ b/bika/lims/browser/arimports.py @@ -142,31 +142,55 @@ def __init__(self, context, request): 'state_title']}, ] - def folderitems(self, **kwargs): - items = super(ARImportsView, self).folderitems() - for x in range(len(items)): - if 'obj' not in items[x]: - continue - obj = items[x]['obj'] - items[x]['Title'] = obj.title_or_id() - if items[x]['review_state'] == 'invalid': - items[x]['replace']['Title'] = "%s" % ( - obj.absolute_url(), items[x]['Title']) + def column_Title(self, item, obj): + if 'obj' in item: + obj = item['obj'] + item['Title'] = obj.title_or_id() + if item['review_state'] == 'invalid': + item['replace']['Title'] = "%s" % ( + obj.absolute_url(), item['Title']) else: - items[x]['replace']['Title'] = "%s" % ( - obj.absolute_url(), items[x]['Title']) - items[x]['Creator'] = obj.Creator() - items[x]['Filename'] = obj.getFilename() + item['replace']['Title'] = "%s" % ( + obj.absolute_url(), item['Title']) + + def column_Creator(self, item, obj): + if 'obj' in item: + obj = item['obj'] + item['Creator'] = obj.Creator() + + def column_Filename(self, item, obj): + if 'obj' in item: + obj = item['obj'] + item['Filename'] = obj.getFilename() + + def column_Client(self, item, obj): + if 'obj' in item: + obj = item['obj'] parent = obj.aq_parent - items[x]['Client'] = parent if IClient.providedBy(parent) else '' - items[x]['replace']['Client'] = "%s/arimports" % ( + item['Client'] = parent if IClient.providedBy(parent) else '' + item['replace']['Client'] = "%s/arimports" % ( parent.absolute_url(), parent.Title()) - items[x]['DateCreated'] = ulocalized_time( + + def column_DateCreated(self, item, obj): + if 'obj' in item: + obj = item['obj'] + item['DateCreated'] = ulocalized_time( obj.created(), long_format=True, time_only=False, context=obj) + + def column_DateValidated(self, item, obj): + if 'obj' in item: + obj = item['obj'] date = getTransitionDate(obj, 'validate') - items[x]['DateValidated'] = date if date else '' + item['DateValidated'] = date if date else '' + + def column_DateImported(self, item, obj): + if 'obj' in item: + obj = item['obj'] date = getTransitionDate(obj, 'import') - items[x]['DateImported'] = date if date else '' + item['DateImported'] = date if date else '' + + def folderitems(self, **kwargs): + items = super(ARImportsView, self).folderitems() return items From 2ad65a96a450673491dd0978286f9d096a575bc9 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Wed, 4 Oct 2017 20:45:18 +0200 Subject: [PATCH 07/15] Changelog --- docs/CHANGELOG.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 497fbdd2d7..0a6347e2d5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -1,6 +1,7 @@ 3.4.0 (unreleased) ------------------ +- LIMS-2696: bika_listing performance: Used refactor on other(mostly used) Listings - LIMS-2696: bika_listing performance: refactor folderitem to use column_* methods - BC-147: Default empty WS view should list on due date - Issue-2103: WS Templates not offered for selection From 8418c1a300b7154fc4936fb9c9468b6fa7a7c889 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Thu, 5 Oct 2017 11:49:20 +0200 Subject: [PATCH 08/15] typo and bug on column_getRequestID --- bika/lims/browser/analysisrequest/analysisrequests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bika/lims/browser/analysisrequest/analysisrequests.py b/bika/lims/browser/analysisrequest/analysisrequests.py index e7d2172533..13b8eeaafb 100644 --- a/bika/lims/browser/analysisrequest/analysisrequests.py +++ b/bika/lims/browser/analysisrequest/analysisrequests.py @@ -728,7 +728,8 @@ def column_Client(self, item, obj): item['replace']['Client'] = "%s" % \ (obj.aq_parent.absolute_url(), obj.aq_parent.Title()) - def column_RequestedID(self, item, obj): + def column_getRequestID(self, item, obj): + url = obj.absolute_url() item['getRequestID'] = obj.getRequestID() item['replace']['getRequestID'] = "%s" % \ (url, item['getRequestID']) From 03ef6447bcb0864a27de7ddcadb394a89450f856 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Thu, 5 Oct 2017 12:55:58 +0200 Subject: [PATCH 09/15] Fixed KeyError toggle by doing a get --- bika/lims/browser/bika_listing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/browser/bika_listing.py b/bika/lims/browser/bika_listing.py index f02a7621e8..775ac4fc13 100644 --- a/bika/lims/browser/bika_listing.py +++ b/bika/lims/browser/bika_listing.py @@ -1119,7 +1119,7 @@ def _call_column_getters(self, item, obj): # columns to display combines defaults and cookie value cookie_cols = self.get_toggle_cols() for col_title, col in self.columns.items(): - if not (col_title in cookie_cols or col['toggle']): + if not (col_title in cookie_cols or col.get('toggle',[]): continue if not hasattr(self, "column_%s" % col_title): continue From 1390acc0eea86f9f8dddec66e411b81b8ebd51e4 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Thu, 5 Oct 2017 13:02:50 +0200 Subject: [PATCH 10/15] Syntax error --- bika/lims/browser/bika_listing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/browser/bika_listing.py b/bika/lims/browser/bika_listing.py index 775ac4fc13..93f1f9d738 100644 --- a/bika/lims/browser/bika_listing.py +++ b/bika/lims/browser/bika_listing.py @@ -1119,7 +1119,7 @@ def _call_column_getters(self, item, obj): # columns to display combines defaults and cookie value cookie_cols = self.get_toggle_cols() for col_title, col in self.columns.items(): - if not (col_title in cookie_cols or col.get('toggle',[]): + if not (col_title in cookie_cols or col.get('toggle',[])): continue if not hasattr(self, "column_%s" % col_title): continue From 18d01bfe59e167f0cd434fd1e42faf554e4bd2f6 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Thu, 5 Oct 2017 23:30:08 +0200 Subject: [PATCH 11/15] Colored review states on top of the tables: --- bika/lims/browser/templates/bika_listing_table.pt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bika/lims/browser/templates/bika_listing_table.pt b/bika/lims/browser/templates/bika_listing_table.pt index 9c96c29ee1..0a4c95543e 100644 --- a/bika/lims/browser/templates/bika_listing_table.pt +++ b/bika/lims/browser/templates/bika_listing_table.pt @@ -142,8 +142,7 @@ href python:view.bika_listing.GET_url(review_state=state['id']); value state_id; id state/id; - class python:request.get(form_id + '_review_state', 'default') == state_id - and 'selected' or ''" + class python:request.get(form_id + '_review_state', 'default') == state_id and 'state-'+state_id+' selected' or 'state-'+state_id" tal:content="structure state/title"/> From f2ea48a8df20b4f84a3529098d78bb0f3eb4c0dc Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Thu, 5 Oct 2017 23:36:15 +0200 Subject: [PATCH 12/15] On the AR View Default to None and hide None --- .../analysisrequest/analysisrequests.py | 60 ++++++++++++++++--- .../browser/client/views/analysisrequests.py | 5 +- bika/lims/skins/bika/bika_listing.css.dtml | 1 + 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/bika/lims/browser/analysisrequest/analysisrequests.py b/bika/lims/browser/analysisrequest/analysisrequests.py index 13b8eeaafb..ecdedff2ce 100644 --- a/bika/lims/browser/analysisrequest/analysisrequests.py +++ b/bika/lims/browser/analysisrequest/analysisrequests.py @@ -151,6 +151,38 @@ def __init__(self, context, request): } self.review_states = [ {'id': 'default', + 'title': _('None'), + 'contentFilter': {'review_state': 'impossible'}, + 'custom_actions': [], + 'columns': ['getRequestID', + 'getSample', + 'BatchID', + 'SubGroup', + 'Client', + 'Creator', + 'Created', + 'getClientOrderNumber', + 'getClientReference', + 'ClientContact', + 'getClientSampleID', + 'getProfilesTitle', + 'getTemplateTitle', + 'getSampleTypeTitle', + 'getSamplePointTitle', + 'getStorageLocation', + 'SamplingDeviation', + 'Priority', + 'AdHoc', + 'SamplingDate', + 'getDateSampled', + 'getSampler', + 'getDatePreserved', + 'getPreserver', + 'getDateReceived', + 'getAnalysesNum', + 'getDateVerified', + 'state_title']}, + {'id': 'active', 'title': _('Active'), 'contentFilter': {'sort_on': 'created', 'sort_order': 'reverse'}, @@ -1018,15 +1050,25 @@ def __call__(self): review_states.append(review_state) self.review_states = review_states - if True: - review_states = [] - for review_state in self.review_states: - review_state.get('custom_actions', []).extend( - [{'id': 'print_stickers', - 'title': _('Print Stickers'), - 'url': 'workflow_action?action=print_stickers'}, ]) - review_states.append(review_state) - self.review_states = review_states + # Don't know where else to hook this in + review_states = [] + import pdb; pdb.set_trace() + for review_state in self.review_states: + review_state.get('custom_actions', []).extend( + [{'id': 'print_coc', + 'title': _('Print COC'), + 'url': 'workflow_action?action=copy_to_new'}, ]) + review_states.append(review_state) + self.review_states = review_states + + review_states = [] + for review_state in self.review_states: + review_state.get('custom_actions', []).extend( + [{'id': 'print_stickers', + 'title': _('Print Stickers'), + 'url': 'workflow_action?action=print_stickers'}, ]) + review_states.append(review_state) + self.review_states = review_states # Hide Preservation/Sampling workflow actions if the edit columns # are not displayed. diff --git a/bika/lims/browser/client/views/analysisrequests.py b/bika/lims/browser/client/views/analysisrequests.py index a15faa0f11..5ad5df5226 100644 --- a/bika/lims/browser/client/views/analysisrequests.py +++ b/bika/lims/browser/client/views/analysisrequests.py @@ -23,8 +23,9 @@ def __init__(self, context, request): "level": 0} review_states = [] for review_state in self.review_states: - review_state['columns'].remove('Client') - review_states.append(review_state) + if review_state['columns']: + review_state['columns'].remove('Client') + review_states.append(review_state) self.review_states = review_states def __call__(self): diff --git a/bika/lims/skins/bika/bika_listing.css.dtml b/bika/lims/skins/bika/bika_listing.css.dtml index ffc6bcf833..e3fed78944 100644 --- a/bika/lims/skins/bika/bika_listing.css.dtml +++ b/bika/lims/skins/bika/bika_listing.css.dtml @@ -201,6 +201,7 @@ table.bika-listing-table { background: #fff; padding:5px 3px 5px 3px !important; } +.state-default{display:none} table.bika-listing-table thead tr td.listing-filter-row { background-attachment: scroll !important; From 34fc4bcba8ae40fde0fd89b5d9d61be22f3ffc88 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Thu, 5 Oct 2017 23:39:00 +0200 Subject: [PATCH 13/15] Missing code --- .../analysisrequest/analysisrequests.py | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/bika/lims/browser/analysisrequest/analysisrequests.py b/bika/lims/browser/analysisrequest/analysisrequests.py index ecdedff2ce..1da84a9ea1 100644 --- a/bika/lims/browser/analysisrequest/analysisrequests.py +++ b/bika/lims/browser/analysisrequest/analysisrequests.py @@ -1050,25 +1050,15 @@ def __call__(self): review_states.append(review_state) self.review_states = review_states - # Don't know where else to hook this in - review_states = [] - import pdb; pdb.set_trace() - for review_state in self.review_states: - review_state.get('custom_actions', []).extend( - [{'id': 'print_coc', - 'title': _('Print COC'), - 'url': 'workflow_action?action=copy_to_new'}, ]) - review_states.append(review_state) - self.review_states = review_states - - review_states = [] - for review_state in self.review_states: - review_state.get('custom_actions', []).extend( - [{'id': 'print_stickers', - 'title': _('Print Stickers'), - 'url': 'workflow_action?action=print_stickers'}, ]) - review_states.append(review_state) - self.review_states = review_states + if True: + review_states = [] + for review_state in self.review_states: + review_state.get('custom_actions', []).extend( + [{'id': 'print_stickers', + 'title': _('Print Stickers'), + 'url': 'workflow_action?action=print_stickers'}, ]) + review_states.append(review_state) + self.review_states = review_states # Hide Preservation/Sampling workflow actions if the edit columns # are not displayed. From ee3707882ad5fc6910282214aa07f3758cea857e Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Wed, 11 Oct 2017 14:16:15 +0200 Subject: [PATCH 14/15] Fixed test --- .../tests/test_LIMS-2062-cancelled-ars-visible-in-lists.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bika/lims/tests/test_LIMS-2062-cancelled-ars-visible-in-lists.py b/bika/lims/tests/test_LIMS-2062-cancelled-ars-visible-in-lists.py index 9269d2948b..03809a56de 100644 --- a/bika/lims/tests/test_LIMS-2062-cancelled-ars-visible-in-lists.py +++ b/bika/lims/tests/test_LIMS-2062-cancelled-ars-visible-in-lists.py @@ -60,7 +60,9 @@ def tearDown(self): super(Test_ShowPrices, self).tearDown() def test_default_view_does_not_show_cancelled_items(self): - url = self.portal.analysisrequests.absolute_url() + ars_url = self.portal.analysisrequests.absolute_url() + active_ars = '/base_view?analysisrequests_review_state=active' + url = '{}{}'.format(ars_url, active_ars) browser = self.getBrowser() browser.open(url) if "H2O-0001-R01" in browser.contents: From 97a25baa4937abdca2e7f178bdfea7caec809241 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Fri, 13 Oct 2017 13:32:36 +0200 Subject: [PATCH 15/15] BC-192 Reference Sample Analyses tab. addToJSON KeyError: 'Keyword' --- bika/lims/browser/referencesample.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/bika/lims/browser/referencesample.py b/bika/lims/browser/referencesample.py index 16708acb3d..ab097df979 100644 --- a/bika/lims/browser/referencesample.py +++ b/bika/lims/browser/referencesample.py @@ -168,14 +168,6 @@ def column_Worksheet(self, item, obj): brefs = obj.getBackReferences("WorksheetAnalysis") item['Worksheet'] = brefs and brefs[0].Title() or '' - def column_Keyword(self, item, obj): - service = obj.getService() - item['Keyword'] = service.getKeyword() - - def column_Unit(self, item, obj): - service = obj.getService() - item['Unit'] = service.getUnit() - def folderitem(self, obj, item, index): item = super(ReferenceAnalysesView, self).folderitem(obj, item, index) if not item: @@ -184,6 +176,8 @@ def folderitem(self, obj, item, index): # The following item keywords are required for the # JSON return value below, which is used to render graphs. # they are not actually used in the table rendering. + item['Keyword'] = service.getKeyword() + item['Unit'] = service.getUnit() self.addToJSON(obj, service, item) return item