diff --git a/organize/interfaces.py b/organize/interfaces.py index 5c2b718..bfd2b3b 100644 --- a/organize/interfaces.py +++ b/organize/interfaces.py @@ -527,16 +527,21 @@ class IWorkItem(ITrack): 'by its name or ID.') state = Attribute('The current state the work item is in.') # standard attributes + workItemType = Attribute('The type of the work item ' + '(work, event, deadline).') title = Attribute('A short text characterizing the work item.') description = Attribute('A note about what has to be done, and why...') + deadline = Attribute('When the work has to be finished.') start = Attribute('When the work was started.') end = Attribute('When the work was finished.') duration = Attribute('How long it took to finish the work.') - effort = Attribute('How much effort (time units) it took to finish the work.') + effort = Attribute('How much effort (time units) it took ' + 'to finish the work.') comment = Attribute('A note about what has been done, and why...') # work item handling creator = Attribute('The party that has set up the work item.') - created = Attribute('The timeStamp of the initial creation of the work item.') + created = Attribute('The timeStamp of the initial creation ' + 'of the work item.') newTask = Attribute('Optional: a new task that has been created based ' 'on this work item.') diff --git a/organize/work.py b/organize/work.py index 7168006..9e1e3f7 100644 --- a/organize/work.py +++ b/organize/work.py @@ -32,6 +32,7 @@ from cybertools.stateful.definition import State, Transition from cybertools.stateful.interfaces import IStatesDefinition from cybertools.tracking.btree import Track, getTimeStamp from cybertools.tracking.interfaces import ITrackingStorage +from cybertools.util.jeep import Jeep _not_found = object() @@ -63,11 +64,11 @@ def workItemStates(): State('cancelled', 'cancelled', ('plan', 'accept', 'start', 'work', 'move', 'modify', 'close'), color='grey'), - State('closed', 'closed', (), color='lightblue'), + State('closed', 'closed', ('reopen',), color='lightblue'), # not directly reachable states: State('delegated', 'delegated', - ('plan', 'accept', 'start', 'work', 'finish', 'close', - 'delegate', 'move', 'cancel', 'modify'), + ('plan', 'accept', #'start', 'work', 'finish', + 'close', 'delegate', 'move', 'cancel', 'modify'), color='purple'), State('delegated_x', 'delegated', (), color='purple'), State('moved', 'moved', @@ -82,7 +83,7 @@ def workItemStates(): # transitions: Transition('plan', 'plan', 'planned'), Transition('accept', 'accept', 'accepted'), - Transition('start', 'start working', 'running'), + Transition('start', 'start working', 'running'), # obsolete? Transition('work', 'work', 'done'), Transition('finish', 'finish', 'finished'), Transition('cancel', 'cancel', 'cancelled'), @@ -90,10 +91,12 @@ def workItemStates(): Transition('delegate', 'delegate', 'planned'), Transition('move', 'move', 'planned'), Transition('close', 'close', 'closed'), + Transition('reopen', 're-open', 'planned'), initialState='new') -fieldNames = ['title', 'description', 'start', 'end', 'duration', 'effort', +fieldNames = ['title', 'description', 'deadline', 'start', 'end', + 'duration', 'effort', 'comment', 'party'] # for use in editingRules # meaning: - not editable, value=default @@ -102,22 +105,55 @@ fieldNames = ['title', 'description', 'start', 'end', 'duration', 'effort', # . default (may be empty) editingRules = dict( - plan = {'*': '++.....+'}, - accept = {'*': '++.....-', - 'planned': '++++++.-', - 'accepted': '++++++.-'}, - start = {'*': '++./...-'}, - work = {'*': '++.....-', - 'running': '+++....-'}, - finish = {'*': '++.....-', - 'running': '+++....-'}, - cancel = {'*': '++////./'}, - modify = {'*': '++++++++'}, - delegate= {'*': '++......'}, - close = {'*': '++////./'}, + plan = {'*': '+++.....+'}, + accept = {'*': '+++.....-', + 'planned': '+++++++.-', + 'accepted': '+++++++.-'}, + start = {'*': '+++./...-'}, + work = {'*': '+++.....-', + 'running': '++++....-'}, + finish = {'*': '+++.....-', + 'running': '++++....-'}, + cancel = {'*': '+++////./'}, + modify = {'*': '+++++++++'}, + delegate= {'*': '+++++++.+'}, + move = {'*': '+++++++.-'}, + close = {'*': '+++////./'}, + reopen = {'*': '+++////./'}, ) +class WorkItemType(object): + """ Specify the type of a work item. + + The work item type controls which actions (transitions) + and fields are available for a certain work item. + """ + + def __init__(self, name, title, description=u'', + actions=None, fields=None, color=None): + self.name = name + self.title = title + self.description = description + self.actions = actions or list(editingRules) + self.fields = fields or ('deadline', 'start-end', 'duration-effort') + self.color = color + +workItemTypes = Jeep(( + WorkItemType('work', u'Unit of Work'), + WorkItemType('scheduled', u'Scheduled Event', + actions=('plan', 'accept', 'finish', 'cancel', + 'modify', 'delegate', 'close', 'reopen'), + fields =('start-end', 'duration-effort',), + color ='#aaaaff'), + WorkItemType('deadline', u'Deadline', + actions=('plan', 'accept', 'finish', 'cancel', + 'modify', 'delegate', 'close', 'reopen'), + fields =('deadline',), + color ='#ffffaa') +)) + + class WorkItem(Stateful, Track): """ A work item that may be stored as a track in a tracking storage. """ @@ -130,7 +166,8 @@ class WorkItem(Stateful, Track): typeInterface = IWorkItem statesDefinition = 'organize.workItemStates' - initAttributes = set(['party', 'title', 'description', 'start', 'end', + initAttributes = set(['workItemType', 'party', 'title', 'description', + 'deadline', 'start', 'end', 'duration', 'effort']) def __init__(self, taskId, runId, userName, data): @@ -274,7 +311,7 @@ class WorkItem(Stateful, Track): if party is not None: self.userName = party self.reindex('userName') - start = kw.get('start') + start = kw.get('start') or kw.get('deadline') # TODO: check OK? if start is not None: self.timeStamp = start self.reindex('timeStamp')