Commit 66403bf8 authored by wenjie.zheng's avatar wenjie.zheng Committed by Sebastien Robin

ERP5Workflow: add configuration workflowfiles.

parent 81d68346
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from zLOG import LOG, ERROR, DEBUG, WARNING
class StateError(Exception):
"""
Must call only an available transition
"""
pass
class ConfigurationState(XMLObject):
"""
A Busniess Configuration State.
"""
meta_type = 'ERP5 State'
portal_type = 'Configuration State'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = (
PropertySheet.Base,
PropertySheet.XMLObject,
PropertySheet.CategoryCore,
PropertySheet.DublinCore,
PropertySheet.State,)
def getAvailableTransitionList(self, document):
"""
Return available transitions only if they are accessible for document.
"""
transition_list = self.getDestinationValueList(portal_type = 'Transition')
result_list = []
for transition in transition_list:
value = transition._checkPermission(document)
if value:
result_list.append(transition)
return result_list
def executeTransition(self, transition, document, form_kw=None):
"""
Execute transition on the object.
"""
if transition not in self.getAvailableTransitionList(document):
raise StateError
else:
transition.execute(document, form_kw=form_kw)
def undoTransition(self, document):
"""
Reverse previous transition
"""
wh = self.getWorkflowHistory(document, remove_undo=1)
status_dict = wh[-2]
# Update workflow state
state_bc_id = self.getParentValue().getStateBaseCategory()
document.setCategoryMembership(state_bc_id, status_dict[state_bc_id])
# Update workflow history
status_dict['undo'] = 1
self.getParentValue()._updateWorkflowHistory(document, status_dict)
# XXX
LOG("State, undo", ERROR, "Variable (like DateTime) need to be updated!")
def getWorkflowHistory(self, document, remove_undo=0, remove_not_displayed=0):
"""
Return history tuple
"""
wh = document.workflow_history[self.getParentValue()._generateHistoryKey()]
result = []
# Remove undo
if not remove_undo:
result = [x.copy() for x in wh]
else:
result = []
for x in wh:
if x.has_key('undo') and x['undo'] == 1:
result.pop()
else:
result.append(x.copy())
return result
def getVariableValue(self, document, variable_name):
"""
Get current value of the variable from the object
"""
status_dict = self.getParentValue().getCurrentStatusDict(document)
return status_dict[variable_name]
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.Accessor.Base import _evaluateTales
class ConfigurationTransition(XMLObject):
"""
A Business Configuration Transition.
"""
meta_type = 'ERP5 Transition'
portal_type = 'Configuration Transition'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = (
PropertySheet.Base,
PropertySheet.XMLObject,
PropertySheet.CategoryCore,
PropertySheet.DublinCore,
PropertySheet.Transition,
)
def execute(self, document, form_kw=None):
"""
Execute transition.
"""
workflow = self.getParentValue()
# Call the before script
self._executeBeforeScript(document)
# Modify the state
self._changeState(document)
# Get variable values
status_dict = workflow.getCurrentStatusDict(document)
status_dict['undo'] = 0
# Modify workflow history
state_bc_id = workflow.getStateBaseCategory()
status_dict[state_bc_id] = document.getCategoryMembershipList(state_bc_id)[0]
state_object = document.unrestrictedTraverse(status_dict[state_bc_id])
object = workflow.getStateChangeInformation(document, state_object, transition=self)
# Update all variables
for variable in workflow.contentValues(portal_type='Variable'):
if variable.getAutomaticUpdate():
# if we have it in form get it from there
# otherwise use default
variable_title = variable.getTitle()
if variable_title in form_kw:
status_dict[variable_title] = form_kw[variable_title]
else:
status_dict[variable_title] = variable.getInitialValue(object=object)
# Update all transition variables
if form_kw is not None:
object.REQUEST.other.update(form_kw)
for variable in self.contentValues(portal_type='Transition Variable'):
status_dict[variable.getCausalityTitle()] = variable.getInitialValue(object=object)
workflow._updateWorkflowHistory(document, status_dict)
# Call the after script
self._executeAfterScript(document, form_kw=form_kw)
def _changeState(self, document):
"""
Change the state of the object.
"""
state = self.getDestination()
if state is not None:
# Some transitions don't update the state
state_bc_id = self.getParentValue().getStateBaseCategory()
document.setCategoryMembership(state_bc_id, state)
def _executeAfterScript(self, document, form_kw=None):
"""
Execute post transition script.
"""
if form_kw is None:
form_kw = {}
script_id = self.getAfterScriptId()
if script_id is not None:
script = getattr(document, script_id)
script(**form_kw)
def _executeBeforeScript(self, document, form_kw=None):
"""
Execute pre transition script.
"""
if form_kw is None:
form_kw = {}
script_id = self.getBeforeScriptId()
if script_id is not None:
script = getattr(document, script_id)
script(**form_kw)
def _checkPermission(self, document):
"""
Check if transition is allowed.
"""
expr_value = self.getGuardExpression(evaluate=0)
if expr_value is not None:
# do not use 'getGuardExpression' to calculate tales because
# it caches value which is bad. Instead do it manually
value = _evaluateTales(document, expr_value)
else:
value = True
#print "CALC", expr_value, '-->', value
return value
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.Globals import PersistentMapping
from tempfile import mktemp
import os
from Products.DCWorkflowGraph.config import DOT_EXE
from Products.DCWorkflowGraph.DCWorkflowGraph import bin_search, getGraph
from Acquisition import aq_base
from DateTime import DateTime
class ConfigurationWorkflow(XMLObject):
"""
A Business Configuration Workflow.
"""
meta_type = 'ERP5 Workflow'
portal_type = 'Configuration Workflow'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = (
PropertySheet.Base,
PropertySheet.XMLObject,
PropertySheet.CategoryCore,
PropertySheet.DublinCore,
PropertySheet.Workflow,
)
def initializeDocument(self, document):
"""
Set initial state on the Document
"""
state_bc_id = self.getStateBaseCategory()
document.setCategoryMembership(state_bc_id, self.getSource())
object = self.getStateChangeInformation(document, self.getSourceValue())
# Initialize workflow history
status_dict = {state_bc_id: self.getSource()}
variable_list = self.contentValues(portal_type='Variable')
for variable in variable_list:
status_dict[variable.getTitle()] = variable.getInitialValue(object=object)
self._updateWorkflowHistory(document, status_dict)
def _generateHistoryKey(self):
"""
Generate a key used in the workflow history.
"""
return self.getRelativeUrl()
def _updateWorkflowHistory(self, document, status_dict):
"""
Change the state of the object.
"""
# Create history attributes if needed
if getattr(aq_base(document), 'workflow_history', None) is None:
document.workflow_history = PersistentMapping()
# XXX this _p_changed is apparently not necessary
document._p_changed = 1
# Add an entry for the workflow in the history
workflow_key = self._generateHistoryKey()
if not document.workflow_history.has_key(workflow_key):
document.workflow_history[workflow_key] = ()
# Update history
document.workflow_history[workflow_key] += (status_dict, )
# XXX this _p_changed marks the document modified, but the
# only the PersistentMapping is modified
document._p_changed = 1
# XXX this _p_changed is apparently not necessary
document.workflow_history._p_changed = 1
def getCurrentStatusDict(self, document):
"""
Get the current status dict.
"""
workflow_key = self._generateHistoryKey()
# Copy is requested
result = document.workflow_history[workflow_key][-1].copy()
return result
def getDateTime(self):
"""
Return current date time.
"""
return DateTime()
def getStateChangeInformation(self, document, state, transition=None):
"""
Return an object used for variable tales expression.
"""
if transition is None:
transition_url = None
else:
transition_url = transition.getRelativeUrl()
return self.asContext(document=document,
transition=transition,
transition_url=transition_url,
state=state)
###########
## Graph ##
############
getGraph = getGraph
def getPOT(self, *args, **kwargs):
"""
get the pot, copy from:
"dcworkfow2dot.py":http://awkly.org/Members/sidnei/weblog_storage/blog_27014
and Sidnei da Silva owns the copyright of the this function
"""
out = []
transition_dict = {}
out.append('digraph "%s" {' % self.getTitle())
transition_with_init_state_list = []
for state in self.contentValues(portal_type='State'):
out.append('%s [shape=box,label="%s",' \
'style="filled",fillcolor="#ffcc99"];' % \
(state.getId(), state.getTitle()))
# XXX Use API instead of getDestinationValueList
for available_transition in state.getDestinationValueList():
transition_with_init_state_list.append(available_transition.getId())
destination_state = available_transition.getDestinationValue()
if destination_state is None:
# take care of 'remain in state' transitions
destination_state = state
#
key = (state.getId(), destination_state.getId())
value = transition_dict.get(key, [])
value.append(available_transition.getTitle())
transition_dict[key] = value
# iterate also on transitions, and add transitions with no initial state
for transition in self.contentValues(portal_type='Transition'):
trans_id = transition.getId()
if trans_id not in transition_with_init_state_list:
destination_state = transition.getDestinationValue()
if destination_state is None:
dest_state_id = None
else:
dest_state_id = destination_state.getId()
key = (None, dest_state_id)
value = transition_dict.get(key, [])
value.append(transition.getTitle())
transition_dict[key] = value
for k, v in transition_dict.items():
out.append('%s -> %s [label="%s"];' % (k[0], k[1],
',\\n'.join(v)))
out.append('}')
return '\n'.join(out)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment