work in progress: work item (task) management

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@3079 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2008-12-22 12:41:20 +00:00
parent 0356cdf85c
commit ee49d66e0d
5 changed files with 112 additions and 9 deletions

View file

@ -4,6 +4,9 @@ Organizations: Persons, Institutions, Addresses...
($Id$)
>>> from zope import component
Persons and Addresses
=====================
@ -48,6 +51,12 @@ Let's create an address and assign it to a person:
u'Broadway 1'
Tasks
=====
>>> from cybertools.organize.task import Task
Service Management
==================
@ -59,5 +68,28 @@ Service Management
Work
====
>>> from cybertools.organize.work import WorkItem
Work items are stored in a tracking storage; in order to conveniently access
the work items we have to provide an adapter to the tracking storage.
>>> from cybertools.tracking.btree import TrackingStorage
>>> from cybertools.organize.interfaces import IWorkItems
>>> from cybertools.organize.work import WorkItemTrack, WorkItems
>>> component.provideAdapter(WorkItems)
The individual work item (a track) is carrying a state attribute that is
governed by a special states definition. We have to register this states
definition as a utility.
>>> from cybertools.organize.work import workItemStates
>>> component.provideUtility(workItemStates(), name='organize.workItemStates')
We are now ready to set up the tracking storage.
>>> tracks = TrackingStorage(trackFactory=WorkItemTrack)
>>> workItems = component.getAdapter(tracks, IWorkItems)
The work management only deals with the IDs or names of tasks and persons,
so we do not have to set up real objects.
>>> workItems.add('001', 'john')
<WorkItem ['001', 1, 'john', '2008-12-22 12:07', 'created']: {}>

View file

@ -3,8 +3,16 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:i18n="http://namespaces.zope.org/i18n"
i18n_domain="zope">
i18n_domain="cybertools.organize">
<i18n:registerTranslations directory="locales" />
<!-- work -->
<adapter factory="cybertools.organize.work.WorkItems" />
<utility component="cybertools.organize.work.workItemStates"
provides="cybertools.stateful.interfaces.IStatesDefinition"
name="organize.workItemStates" />
</configure>

View file

@ -425,19 +425,24 @@ class IWorkItem(Interface):
done by exactly one party (usually a person).
"""
task = Attribute('The task this work item belongs to.')
runId = Attribute('Used for recurring tasks: identifies the run '
task = Attribute('The task this work item belongs to, identified by '
'its name or ID.')
run = Attribute('Used for recurring tasks: identifies the run '
'(execution instance) of the task the work item belongs to.')
party = Attribute('Whoever does the work, usually a person.')
party = Attribute('Whoever does the work, usually a person, identified '
'by its name or ID.')
state = Attribute('The current state the work item is in.')
description = Attribute('A note about what has to be done, and why...')
comment = Attribute('A note about what has been done, and why...')
# optional plan fields; duration (and effort) may be derived from start and end
# all date/time fields are timeStamp values, all duration and effort
# fields are in seconds
planStart = Attribute('When the work should start.')
planEnd = Attribute('When the work should be finished.')
planDuration = Attribute('How long it may take to finish the work.')
planEffort = Attribute('How much effort (time units) it might take '
'to finish the work.')
# real stuff; duration (and effort) may be derived from start and end
# real stuff
start = Attribute('When the work was started.')
end = Attribute('When the work was finished.')
duration = Attribute('How long it took to finish the work.')
@ -450,3 +455,12 @@ class IWorkItem(Interface):
newTask = Attribute('Optional: a new task that has been created based '
'on this work item.')
class IWorkItems(Interface):
""" A collection (manager, container) of work items.
"""
def add(task, party, run=0, **kw):
""" Create and register a work item; return it. Additional properties
may be specified via keyword arguments.
"""

View file

@ -22,14 +22,17 @@ Planning and recording activities (work items).
$Id$
"""
from zope import component
from zope.component import adapts
from zope.interface import implementer, implements
from cybertools.organize.interfaces import IWorkItem
from cybertools.organize.interfaces import IWorkItem, IWorkItems
from cybertools.stateful.base import Stateful
from cybertools.stateful.definition import StatesDefinition
from cybertools.stateful.definition import State, Transition
from cybertools.stateful.interfaces import IStatesDefinition
from cybertools.tracking.btree import Track
from cybertools.tracking.interfaces import ITrackingStorage
@implementer(IStatesDefinition)
@ -56,3 +59,50 @@ class WorkItem(Stateful):
statesDefinition = 'organize.workItemStates'
def getStatesDefinition(self):
return component.getUtility(IStatesDefinition, name=self.statesDefinition)
# work item attributes (except state that is provided by stateful
class WorkItemTrack(WorkItem, Track):
""" A work item that may be stored as a track in a tracking storage.
"""
metadata_attributes = Track.metadata_attributes + ('state',)
index_attributes = metadata_attributes
typeName = 'WorkItem'
initAttributes = set(['description', 'predecessor',
'planStart', 'planEnd', 'planDuration', 'planEffort'])
def __init__(self, taskId, runId, userName, data={}):
for k in data:
if k not in initAttributes:
raise ValueError("Illegal initial attribute: '%s'." % k)
super(WorkItemTrack, self).__init__(taskId, runId, userName, data)
self.state = self.getState() # make initial state persistent
def __getattr__(self, attr):
value = self.data.get(attr, _not_found)
if value is _not_found:
raise AttributeError(attr)
return value
class WorkItems(object):
""" A tracking storage adapter managing work items.
"""
implements(IWorkItems)
adapts(ITrackingStorage)
def __init__(self, context):
self.context = context
def __getitem__(self, key):
return self.context[key]
def add(self, task, party, run=0, **kw):
trackId = self.context.saveUserTrack(task, run, party, kw)
return self[trackId]

View file

@ -92,14 +92,13 @@ class TrackingStorage(BTreeContainer):
implements(ITrackingStorage)
trackFactory = Track
indexAttributes = trackFactory.index_attributes
trackNum = runId = 0
runs = None # currently active runs
finishedRuns = None # finished runs
currentRuns = None # the currently active run for each task
indexAttributes = Track.index_attributes
def __init__(self, *args, **kw):
trackFactory = kw.pop('trackFactory', None)
if trackFactory is not None: