state handling for service registrations

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2123 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-10-20 16:01:20 +00:00
parent c701a05d9e
commit 89510875c9
5 changed files with 107 additions and 36 deletions

View file

@ -59,11 +59,13 @@ class Field(Component):
def name(self): def name(self):
return self.__name__ return self.__name__
@property def getDefaultValue(self):
def defaultValue(self):
if callable(self.default): if callable(self.default):
return self.default() return self.default()
return self.default return self.default
def setDefaultValue(self, value):
self.default = value
defaultValue = property(getDefaultValue, setDefaultValue)
@property @property
def fieldRenderer(self): def fieldRenderer(self):

View file

@ -32,6 +32,7 @@ from cybertools.organize.interfaces import serviceCategories
from cybertools.composer.interfaces import IInstance from cybertools.composer.interfaces import IInstance
from cybertools.composer.schema.browser.common import BaseView as SchemaBaseView from cybertools.composer.schema.browser.common import BaseView as SchemaBaseView
from cybertools.composer.schema.interfaces import IClientFactory from cybertools.composer.schema.interfaces import IClientFactory
from cybertools.stateful.interfaces import IStateful
from cybertools.util.format import formatDate from cybertools.util.format import formatDate
@ -97,6 +98,7 @@ class ServiceManagerView(BaseView):
first = tpl first = tpl
return first return first
#@Lazy - Zope 2.9 compatibility
def registrationUrl(self): def registrationUrl(self):
tpl = self.getRegistrationTemplate() tpl = self.getRegistrationTemplate()
return self.getUrlForObject(tpl) return self.getUrlForObject(tpl)
@ -170,7 +172,8 @@ class CheckoutView(ServiceManagerView):
return True # TODO: error, redirect to overview return True # TODO: error, redirect to overview
regs = IClientRegistrations(client).getRegistrations() regs = IClientRegistrations(client).getRegistrations()
for reg in regs: for reg in regs:
pass # set state to submitted, stateful = IStateful(reg)
stateful.doTransition(('submit', 'change'))
# send mail # send mail
# find thank you message and redirect to it # find thank you message and redirect to it
params = '?message=thankyou&id=' + self.clientName params = '?message=thankyou&id=' + self.clientName
@ -190,6 +193,7 @@ class ServiceView(BaseView):
man = context.getManager() man = context.getManager()
return ServiceManagerView(man, self.request).getRegistrationTemplate() return ServiceManagerView(man, self.request).getRegistrationTemplate()
#@Lazy - Zope 2.9 compatibility
def registrationUrl(self): def registrationUrl(self):
tpl = self.getRegistrationTemplate() tpl = self.getRegistrationTemplate()
return self.getUrlForObject(tpl) return self.getUrlForObject(tpl)
@ -213,6 +217,12 @@ class ServiceView(BaseView):
instance = IInstance(client) instance = IInstance(client)
return instance.applyTemplate() return instance.applyTemplate()
def getRegistrationInfo(self, reg):
registration = self.getRegistrations()[reg]
state = IStateful(registration).getStateObject()
return dict(number=registration.number,
state=state.name, stateTitle=state.title)
def update(self): def update(self):
newClient = False newClient = False
nextUrl = None nextUrl = None

View file

@ -33,6 +33,7 @@ from zope.interface import implements, Interface
from cybertools.composer.interfaces import IInstance from cybertools.composer.interfaces import IInstance
from cybertools.composer.rule.base import RuleManager, EventType from cybertools.composer.rule.base import RuleManager, EventType
from cybertools.composer.schema.interfaces import IClientManager, IClient from cybertools.composer.schema.interfaces import IClientManager, IClient
from cybertools.stateful.base import StatefulAdapter
from cybertools.stateful.definition import registerStatesDefinition from cybertools.stateful.definition import registerStatesDefinition
from cybertools.stateful.definition import StatesDefinition from cybertools.stateful.definition import StatesDefinition
from cybertools.stateful.definition import State, Transition from cybertools.stateful.definition import State, Transition
@ -97,11 +98,30 @@ class ServiceManager(RuleManager):
return self.rules return self.rules
class Registration(object):
implements(IRegistration)
number = 1
def __init__(self, client, service, number=1):
self.client = client
self.service = service
self.timeStamp = int(time())
self.number = number
class PersistentRegistration(Registration, Persistent):
pass
class Service(object): class Service(object):
implements(IService) implements(IService)
registrationsFactory = OOBTree registrationsFactory = OOBTree
registrationFactory = PersistentRegistration
manager = None manager = None
category = None category = None
@ -150,9 +170,9 @@ class Service(object):
reg = self.registrations[clientName] reg = self.registrations[clientName]
if number != reg.number: if number != reg.number:
reg.number = number reg.number = number
self.registrations[clientName] = reg # persistence hack #self.registrations[clientName] = reg # persistence hack
return reg return reg
reg = Registration(client, self, number) reg = self.registrationFactory(client, self, number)
self.registrations[clientName] = reg self.registrations[clientName] = reg
return reg return reg
#if self.availableCapacity: #if self.availableCapacity:
@ -184,20 +204,7 @@ class ScheduledService(Service):
return getattr(self.getManager(), 'end', None) return getattr(self.getManager(), 'end', None)
# registration # registration stuff
class Registration(object):
implements(IRegistration)
number = 1
def __init__(self, client, service, number=1):
self.client = client
self.service = service
self.timeStamp = int(time())
self.number = number
class RegistrationTemplate(object): class RegistrationTemplate(object):
@ -253,7 +260,6 @@ class ClientRegistrations(object):
service.unregister(self.context) service.unregister(self.context)
def getRegistrations(self): def getRegistrations(self):
# TODO: restrict to services on this template
regs = getattr(self.context, self.registrationsAttributeName, []) regs = getattr(self.context, self.registrationsAttributeName, [])
if self.template is not None: if self.template is not None:
svcs = self.template.getServices().values() svcs = self.template.getServices().values()
@ -261,19 +267,26 @@ class ClientRegistrations(object):
return regs return regs
# registration states definition # registration states
registrationStates = 'organize.service.registration'
registerStatesDefinition( registerStatesDefinition(
StatesDefinition('organize.service.registration', StatesDefinition(registrationStates,
State('temporary', 'temporary', ('submit', 'cancel',)), State('temporary', 'temporary', ('submit', 'cancel',)),
State('submitted', 'submitted', ('retract', 'setwaiting', 'confirm', 'reject',)), State('submitted', 'submitted',
('change', 'retract', 'setwaiting', 'confirm', 'reject',)),
State('cancelled', 'cancelled', ('submit',)), State('cancelled', 'cancelled', ('submit',)),
State('retracted', 'retracted', ('submit',)), State('retracted', 'retracted', ('submit',)),
State('waiting', 'waiting', ('retract', 'confirm', 'reject',)), State('waiting', 'waiting',
State('confirmed', 'confirmed', ('retract', 'reject',)), ('change', 'retract', 'confirm', 'reject',)),
State('rejected', 'rejected', ('retract', 'setwaiting', 'confirm',)), State('confirmed', 'confirmed',
('change', 'retract', 'reject',)),
State('rejected', 'rejected',
('change', 'retract', 'setwaiting', 'confirm',)),
Transition('cancel', 'Cancel registration', 'cancelled'), Transition('cancel', 'Cancel registration', 'cancelled'),
Transition('submit', 'Submit registration', 'submitted'), Transition('submit', 'Submit registration', 'submitted'),
Transition('change', 'Change registration', 'submitted'),
Transition('retract', 'Retract registration', 'retracted'), Transition('retract', 'Retract registration', 'retracted'),
Transition('setwaiting', 'Set on waiting list', 'waiting'), Transition('setwaiting', 'Set on waiting list', 'waiting'),
Transition('confirm', 'Confirm registration', 'confirmed'), Transition('confirm', 'Confirm registration', 'confirmed'),
@ -282,7 +295,14 @@ registerStatesDefinition(
)) ))
# event types class StatefulRegistration(StatefulAdapter):
component.adapts(IRegistration)
statesDefinition = registrationStates
# event types for rule-based processing
eventTypes = Jeep(( eventTypes = Jeep((
EventType('service.checkout'), EventType('service.checkout'),
@ -297,3 +317,11 @@ def clientRemoved(obj, event):
regs = IClientRegistrations(obj) regs = IClientRegistrations(obj)
for r in regs.getRegistrations(): for r in regs.getRegistrations():
r.service.unregister(obj) r.service.unregister(obj)
def serviceRemoved(obj, event):
""" Handle removal of a service.
"""
for r in obj.registrations.values():
regs = IClientRegistrations(r.client)
regs.unregister([obj])

View file

@ -47,11 +47,18 @@ class Stateful(object):
state = self.getState() state = self.getState()
return self.getStatesDefinition().states[state] return self.getStatesDefinition().states[state]
def doTransition(self, transition): def doTransition(self, transition, historyInfo=None):
""" execute transition.
"""
sd = self.getStatesDefinition() sd = self.getStatesDefinition()
if isinstance(transition, basestring):
sd.doTransitionFor(self, transition) sd.doTransitionFor(self, transition)
return
available = [t.name for t in sd.getAvailableTransitionsFor(self)]
for tr in transition:
if tr in available:
sd.doTransitionFor(self, tr)
return
raise ValueError("None of the transitions '%s' is available for state '%s'."
% (repr(transition), self.getState()))
def getAvailableTransitions(self): def getAvailableTransitions(self):
sd = self.getStatesDefinition() sd = self.getStatesDefinition()

View file

@ -50,18 +50,42 @@ class IStateful(Interface):
""" """
def getStateObject(): def getStateObject():
""" Return the state (an IState implementation) of the object. """ Return the state (an IState implementation) of the context object.
""" """
def doTransition(transition): def doTransition(transition, historyInfo=None):
""" Execute a transition; the transition is specified by its name. """ Execute a transition; the transition is specified by its name.
The ``transition`` argument may be an iterable; in this case
its elements will be checked against the available transitions
and the first one that's available will be executed.
The ``historyInfo`` argument is an arbitrary object that will be
used for recording the transition execution in the history
(only if the context object is adaptable to IHistorizable).
""" """
def getAvailableTransitions(): def getAvailableTransitions():
""" Return the transitions for this object that are available in """ Return the transitions for this object that are available in
the current state. The implementation of the returned transition the current state. The returned transition objects should
objects is not specified, they may be action dictionaries or provide the ITransition interface.
special Transition objects. """
class IHistorizable(Interface):
""" An object that may record history information, e.g. when
performing a state transition.
"""
def record(info):
""" Record the information given (typically a mapping) with the
object.
"""
def recordTransition(stateFrom, stateTo, transition, historyInfo=None):
""" Record the state transition characterized by the arguments
(names of the states and the transition), optionally
supplemented by the additional history information given.
""" """