work in progress: reporting, example 'work statement' report

This commit is contained in:
Helmut Merz 2011-11-26 14:54:24 +01:00
parent eb73015265
commit 120156cd04
6 changed files with 105 additions and 23 deletions

View file

@ -85,7 +85,7 @@ class ResultsView(NodeView):
def reportInstance(self): def reportInstance(self):
instance = component.getAdapter(self.report, IReportInstance, instance = component.getAdapter(self.report, IReportInstance,
name=self.report.reportType) name=self.report.reportType)
instance.request = self.request instance.view = self
return instance return instance
#@Lazy #@Lazy

View file

@ -22,9 +22,9 @@
provides="loops.expert.report.IReport" trusted="True" /> provides="loops.expert.report.IReport" trusted="True" />
<class class="loops.expert.report.Report"> <class class="loops.expert.report.Report">
<require permission="zope.View" <require permission="zope.View"
interface="loops.expert.report.IReportSchema" /> interface="loops.expert.report.IReport" />
<require permission="zope.ManageContent" <require permission="zope.ManageContent"
set_schema="loops.expert.report.IReportSchema" /> set_schema="loops.expert.report.IReport" />
</class> </class>
<adapter factory="loops.expert.report.DefaultConceptReportInstance" <adapter factory="loops.expert.report.DefaultConceptReportInstance"

View file

@ -29,6 +29,7 @@ from zope.security.proxy import removeSecurityProxy
from cybertools.composer.report.base import Report as BaseReport from cybertools.composer.report.base import Report as BaseReport
from cybertools.composer.report.base import LeafQueryCriteria, CompoundQueryCriteria from cybertools.composer.report.base import LeafQueryCriteria, CompoundQueryCriteria
from cybertools.composer.report.interfaces import IReport as IBaseReport from cybertools.composer.report.interfaces import IReport as IBaseReport
from cybertools.composer.report.interfaces import IReportParams
from cybertools.composer.report.result import ResultSet, Row from cybertools.composer.report.result import ResultSet, Row
from cybertools.util.jeep import Jeep from cybertools.util.jeep import Jeep
from loops.common import AdapterBase from loops.common import AdapterBase
@ -40,7 +41,7 @@ from loops.util import _
# interfaces # interfaces
class IReport(ILoopsAdapter): class IReport(ILoopsAdapter, IReportParams):
""" The report adapter for the persistent object (concept) that stores """ The report adapter for the persistent object (concept) that stores
the report in the concept map. the report in the concept map.
""" """
@ -53,19 +54,11 @@ class IReport(ILoopsAdapter):
required=True) required=True)
class IReportSchema(IBaseReport, IReport): class IReportInstance(IBaseReport):
""" All report attributes - use for security declarations.
"""
class IReportInstance(Interface):
""" The report-type-specific object (an adapter on the report) that """ The report-type-specific object (an adapter on the report) that
does the real report execution stuff. does the real report execution stuff.
""" """
label = Attribute('The user-friendly label of the report type specified '
'by this instance class.')
# report concept adapter and instances # report concept adapter and instances
@ -85,12 +78,18 @@ class ReportInstance(BaseReport):
rowFactory = Row rowFactory = Row
view = None # set upon creation
def __init__(self, context): def __init__(self, context):
self.context = context self.context = context
def getResultsRenderer(self, name, macros): def getResultsRenderer(self, name, macros):
return macros[name] return macros[name]
@property
def queryCriteria(self):
return self.context.queryCriteria
def getResults(self, dynaParams=None): def getResults(self, dynaParams=None):
crit = self.queryCriteria crit = self.queryCriteria
if crit is None: if crit is None:
@ -105,8 +104,21 @@ class ReportInstance(BaseReport):
sortCriteria=self.getSortCriteria(), queryCriteria=qc) sortCriteria=self.getSortCriteria(), queryCriteria=qc)
def selectObjects(self, parts): def selectObjects(self, parts):
# to be implemented by subclass
return [] return []
@Lazy
def conceptManager(self):
return self.view.conceptManager
@Lazy
def recordManager(self):
return self.view.loopsRoot.getRecordManager()
@Lazy
def hasReportPredicate(self):
return self.conceptManager['hasreport']
class ReportTypeSourceList(object): class ReportTypeSourceList(object):

View file

@ -183,12 +183,47 @@ So we use the PersonWorkItems view, assigning john to the query.
Work Reports Work Reports
============ ============
First we have to make sure that there is a report concept type available.
In addition we need a predicate that connects one or more tasks with a report.
>>> from loops.expert.report import IReport, Report
>>> component.provideAdapter(Report)
>>> tReport = addAndConfigureObject(concepts, Concept, 'report',
... title=u'Report', conceptType=concepts.getTypeConcept(),
... typeInterface=IReport)
>>> hasReport = addAndConfigureObject(concepts, Concept, 'hasreport',
... title=u'has Report', conceptType=concepts.getPredicateType())
Now we can create a report and register it as the report for the task
used above.
>>> workStatement = addAndConfigureObject(concepts, Concept, 'work_statement',
... title=u'Work Statement', conceptType=tReport,
... reportType='work_report')
>>> workStatement.assignChild(task01, hasReport)
The executable report is a report instance that is an adapter to the
(adapted) report instance.
>>> from loops.organize.work.report import WorkReportInstance >>> from loops.organize.work.report import WorkReportInstance
>>> from loops.expert.report import IReportInstance >>> from loops.expert.report import IReportInstance
>>> component.provideAdapter(WorkReportInstance, >>> component.provideAdapter(WorkReportInstance,
... provides=IReportInstance, ... provides=IReportInstance,
... name='work_report') ... name='work_report')
The user interface to the report is a report view, the results are presented
in a results view.
>>> from loops.view import Node
>>> reportNode = addAndConfigureObject(home, Node, 'report',
... title=u'Report', target=workStatement)
>>> from loops.expert.browser.report import ReportView, ResultsView
>>> resultsView = ResultsView(reportNode, TestRequest())
>>> results = resultsView.results()
>>> len(results.data)
2
Fin de partie Fin de partie
============= =============

View file

@ -28,14 +28,17 @@ from cybertools.composer.report.base import Report
from cybertools.composer.report.base import LeafQueryCriteria, CompoundQueryCriteria from cybertools.composer.report.base import LeafQueryCriteria, CompoundQueryCriteria
from cybertools.composer.report.field import Field from cybertools.composer.report.field import Field
from cybertools.composer.report.result import ResultSet, Row as BaseRow from cybertools.composer.report.result import ResultSet, Row as BaseRow
from cybertools.organize.interfaces import IWorkItems
from cybertools.util.jeep import Jeep from cybertools.util.jeep import Jeep
from loops.common import adapted, baseObject
from loops.expert.report import ReportInstance from loops.expert.report import ReportInstance
from loops import util
results_template = ViewPageTemplateFile('results.pt') results_template = ViewPageTemplateFile('results.pt')
task = Field('task', u'Task', tasks = Field('tasks', u'Tasks',
description=u'The task to which work items belong.', description=u'The tasks to which work items belong.',
executionSteps=['query', 'output', 'sort']) executionSteps=['query', 'output', 'sort'])
work = Field('work', u'Work', work = Field('work', u'Work',
description=u'The short description of the work.', description=u'The short description of the work.',
@ -65,12 +68,20 @@ class WorkReportInstance(ReportInstance):
label = u'Work Report' label = u'Work Report'
rowFactory = WorkRow rowFactory = WorkRow
fields = Jeep((day, dayFrom, dayTo, task, work, workDescription)) fields = Jeep((day, dayFrom, dayTo, tasks, work, workDescription))
defaultOutputFields = fields defaultOutputFields = fields
@Lazy @property
def queryCriteria(self): def queryCriteria(self):
# TODO: take from persistent report where appropriate crit = self.context.queryCriteria
if crit is None:
f = self.fields['tasks']
tasks = baseObject(self.context).getChildren([self.hasReportPredicate])
crit = [LeafQueryCriteria(f.name, f.operator, tasks, f)]
return CompoundQueryCriteria(crit)
@property
def xx_queryCriteria(self):
crit = [LeafQueryCriteria(f.name, f.operator, None, f) crit = [LeafQueryCriteria(f.name, f.operator, None, f)
for f in self.getAllQueryFields()] for f in self.getAllQueryFields()]
return CompoundQueryCriteria(crit) return CompoundQueryCriteria(crit)
@ -79,8 +90,31 @@ class WorkReportInstance(ReportInstance):
return results_template.macros[name] return results_template.macros[name]
def selectObjects(self, parts): def selectObjects(self, parts):
task = parts.get('task') result = []
if not task: tasks = parts.pop('tasks').comparisonValue
return [] for t in list(tasks):
return [] tasks.extend(self.getAllSubtasks(t))
for t in tasks:
result.extend(self.selectWorkItems(t, parts))
# TODO: remove parts already used for selection from parts list
return result
def selectWorkItems(self, task, parts):
wi = self.workItems
return wi.query(task=util.getUidForObject(task))
def getAllSubtasks(self, concept):
result = []
for c in concept.getChildren():
if c.conceptType == self.taskType:
result.append(c)
result.extend(self.getAllSubtasks(c))
return result
@Lazy
def taskType(self):
return self.conceptManager['task']
@Lazy
def workItems(self):
return IWorkItems(self.recordManager['work'])

View file

@ -11,7 +11,8 @@
</tr> </tr>
<tr tal:repeat="row view/results"> <tr tal:repeat="row view/results">
<tal:column repeat="col view/displayedColumns"> <tal:column repeat="col view/displayedColumns">
<metal:column use-macro="python: view.getColumnRenderer(col.renderer)" /> <p tal:content="col/renderer" />
<xmetal:column use-macro="python:view.getColumnRenderer(col.renderer)" />
</tal:column> </tal:column>
</tr> </tr>
</table> </table>