========================================================== Organizations: Persons, Institutions, Addresses, Work, ... ========================================================== ($Id$) >>> from zope import component Basic Work Item Lifecycle ========================= 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 WorkItem, 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=WorkItem) >>> workItems = IWorkItems(tracks) The work management only deals with the IDs or names of tasks and persons, so we do not have to set up real objects. >>> wi01 = workItems.add('001', 'john') >>> wi01 Properties that have not been set explicitly have a default of None; properties not specified in the IWorkItem interface will lead to an AttributeError. >>> wi01.description is None True >>> wi01.something Traceback (most recent call last): ... AttributeError: something Properties may be set as long as the work item is in status "new". >>> wi01.setData(start=1229955772, party='annie') >>> wi01 The duration value is calculated automatically when start and end are set; the effort is taken from the duration if not set explicitly. >>> (wi01.end, wi01.duration, wi01.effort) (None, None, None) >>> wi01.setData(end=1229956372) >>> (wi01.end, wi01.duration, wi01.effort) (1229956372, 600, 600) >>> wi01.setData(duration=700) >>> wi01.effort 700 >>> w = wi01.doAction('plan', 'john', party='jim') >>> wi01.userName 'jim' Change work item state ---------------------- Now Jim accepts the work item, i.e. he wants to work on it. The previous record keeps its state but it is marked by a "_x" suffix so that it may be excluded from queries. >>> wi02 = wi01.doAction('accept', 'jim') >>> wi01.state 'planned_x' >>> wi02 It is not possible to change a value of a work item that is not in state "new". >>> wi01.setData(party='annie') Traceback (most recent call last): ... ValueError: Attributes may only be changed in state 'new'. Jim now really starts to work. The start time is usually set automatically but may also be specified explicitly. >>> wi03 = wi02.doAction('start', 'jim', start=1229958000) >>> wi03 Stopping and finishing work --------------------------- After five minutes of work Jim decides to stop working; but he will continue work later, so he executes a ``stop`` action. The work item marked as "running" will be replaced by a new one. >>> wi04 = wi03.doAction('work', 'jim', end=1229958300) >>> wi03 >>> wi04 After another hour Jim works again on the task; he now finishes it within ten minutes and records this in one step. >>> wi05 = wi04.doAction('finish', 'jim', start=1229961600, end=1229962200) >>> wi05 >>> wi05.duration, wi05.effort (600, 600) Closing work ------------ As the work is now finished, the work item may be closed; the corresponding "run" (a sequence of work items belonging together) will be finished. >>> wi06 = wi05.doAction('close', 'john') >>> wi06 Let's now check how many work items have been generated. >>> len(list(workItems)) 6 Delegation of Work Items ======================== A user may delegate a newly created work item to another party. This will create a new work item even if the initial one is still in state "new". The new work item is now in "planned" state, its predecessor is market as delegated so that it may be selected by queries. >>> wi07 = workItems.add('001', 'john', start=1229970800) >>> wi08 = wi07.doAction('delegate', 'john', party='annie') >>> wi07 >>> wi08 >>> len(list(workItems)) 8 Modification of Work Items ========================== Existing work items may never be modified except when still in "new" state. To allow for correcting errors that may be detected later there is a "modify" action that will in fact create a new work item. This makes sure that all changes will be tracked correctly. Note that nevertheless only the last work item of a run may be modified. >>> wi09 = wi08.doAction('modify', 'annie', duration=3600) >>> wi08 >>> wi09 Moving Work Items to Other Tasks ================================ >>> wi10 = wi07.doAction('move', 'john') >>> wi10 Queries ======= Runs ---- >>> list(tracks.runs) [2, 3, 4] >>> list(tracks.finishedRuns) [1] Some Special Cases ================== Close a run with some delegated items. >>> wi07a = workItems.query(run=2)[-2] >>> wi07b = workItems.query(run=2)[-1] >>> wi07b >>> wi07c = wi07b.doAction('close', 'john') >>> wi07a.state 'delegated_x' >>> wi07b.state 'moved_x' >>> list(tracks.finishedRuns) [1, 2]