Commit 8f4c2891 authored by Arnaud Fontaine's avatar Arnaud Fontaine

RFC: ERP5Workflow: DC Workflows are now ERP5 objects.

Work done by Wenjie Zheng, Isabelle Vallet, Sebastien Robin and myself.
parent e051c03e
......@@ -35,7 +35,7 @@ from Products.CMFCore.utils import _checkPermission
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.utils import reindex
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from AccessControl.SecurityManagement import newSecurityManager
from Products.ERP5Type.tests.Sequence import SequenceList
from Products.ERP5Form.PreferenceTool import Priority
......
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.Message import translateString
closing_period = state_change['object']
......
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.Message import translateString
period = state_change['object']
......
......@@ -2,7 +2,7 @@
XXX why proxy role ???
"""
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.Message import translateString
transaction = state_change['object']
......
......@@ -3,7 +3,7 @@
XXX why proxy role ???
"""
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.Message import translateString
transaction = state_change['object']
......@@ -13,7 +13,8 @@ section_portal_type_list = ['Person', 'Organisation']
invalid_state_list = ['invalidated', 'deleted']
# first of all, validate the transaction itself
container.validateTransaction(state_change)
script_id = container.getScriptIdByReference('validateTransaction')
container.getScriptValueById(script_id)(state_change)
# Check that all lines uses open accounts, and doesn't use invalid third
......
return sci.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](sci)
return sci.getPortal().portal_workflow.accounting_workflow.getScriptValueById(script.getId())(sci)
return sci.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](sci)
return sci.getPortal().portal_workflow.accounting_workflow.getScriptValueById(script.getId())(sci)
return state_change.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](state_change)
return state_change.getPortal().portal_workflow.accounting_workflow.getScriptValueById(script.getId())(state_change)
return state_change.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](state_change)
return state_change.getPortal().portal_workflow.accounting_workflow.getScriptValueById(script.getId())(state_change)
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.Message import translateString
internal_invoice = state_change['object']
......@@ -7,4 +7,5 @@ if old_state.getId() == 'draft':
if internal_invoice.InternalInvoiceTransaction_getAuthenticatedUserSection() == internal_invoice.getDestinationSection():
raise ValidationFailed(translateString("Your entity should not be destination."))
return state_change.getPortal().portal_workflow.accounting_workflow.scripts[script.getId()](state_change)
script = state_change.getPortal().portal_workflow.accounting_workflow.getScriptValueById(script.getId())
return script(state_change)
from Products.ERP5Type.Message import Message
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
inventory = state_change['object']
......
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.Message import Message
# Check new catalog or catalog is the same as previous archive
......
......@@ -32,7 +32,7 @@ import unittest
from DateTime import DateTime
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5ReportTestCase
from erp5.component.test.testAccounting import AccountingTestCase
......
......@@ -35,7 +35,7 @@ from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from erp5.component.mixin.EncryptedPasswordMixin import EncryptedPasswordMixin
from erp5.component.mixin.LoginAccountProviderMixin import LoginAccountProviderMixin
from erp5.component.mixin.ERP5UserMixin import ERP5UserMixin
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.CMFCore.utils import _checkPermission
from Products.CMFCore.exceptions import AccessControl_Unauthorized
......
......@@ -5,7 +5,7 @@
# In this case we want to be sure that open assignments share the same site category.
# XXX
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
# Get the assignment object and its parent
assignment_object = state_change['object']
......
# XXX: Duplicates Base_checkConsistency so proxy role is really effective.
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
message_list = [x.getTranslatedMessage() for x in state_change['object'].checkConsistency()]
if message_list:
raise ValidationFailed(message_list)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>launch_configuration</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>10.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Launch Configuration</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Workflow_launchConfiguration</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -246,6 +246,8 @@ class BusinessConfiguration(Item):
## go one step back
current_state = self.getCurrentStateValue()
current_state.undoTransition(self)
if not wh['transition']:
raise ValueError("Empty URL for transition in workflow history.")
transition = self.unrestrictedTraverse(wh['transition'])
conf_save = self.unrestrictedTraverse(wh['configuration_save_url'])
## check if this transition can be shown to user ...
......
......@@ -45,6 +45,9 @@
<item>Standard BT5 Configurator Item</item>
<item>System Preference Configurator Item</item>
</portal_type>
<portal_type id="Configuration Workflow">
<item>Embedded File</item>
</portal_type>
<portal_type id="Organisation Configurator Item">
<item>Address</item>
<item>Email</item>
......@@ -59,7 +62,4 @@
<portal_type id="Portal Type Roles Spreadsheet Configurator Item">
<item>Embedded File</item>
</portal_type>
<portal_type id="Workflow">
<item>Embedded File</item>
</portal_type>
</allowed_content_type_list>
\ No newline at end of file
......@@ -4,6 +4,9 @@
<item>File</item>
<item>Link</item>
</portal_type>
<portal_type id="Configuration Workflow">
<item>Embedded File</item>
</portal_type>
<portal_type id="Organisation Configurator Item">
<item>Address</item>
<item>Email</item>
......@@ -15,7 +18,4 @@
<item>Email</item>
<item>Telephone</item>
</portal_type>
<portal_type id="Workflow">
<item>Embedded File</item>
</portal_type>
</hidden_content_type_list>
\ No newline at end of file
<property_sheet_list>
<portal_type id="Workflow">
<portal_type id="Configuration Workflow">
<item>DefaultImage</item>
<item>WorkflowConfigurator</item>
</portal_type>
......
......@@ -9,7 +9,9 @@
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
<list>
<string>columns</string>
</list>
</value>
</item>
<item>
......@@ -69,6 +71,37 @@
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>id</string>
<string>Reference</string>
</tuple>
<tuple>
<string>title</string>
<string>Title</string>
</tuple>
<tuple>
<string>resource_title</string>
<string>Resource</string>
</tuple>
<tuple>
<string>creation_date</string>
<string>Creation Date</string>
</tuple>
<tuple>
<string>translated_validation_state_title</string>
<string>State</string>
</tuple>
<tuple>
<string>translated_simulation_state_title</string>
<string>Installation State</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_list_mode_listbox_business_configuration</string> </value>
......
......@@ -104,8 +104,8 @@
<value>
<list>
<tuple>
<string>Workflow</string>
<string>Workflow</string>
<string>Configuration Workflow</string>
<string>Configuration Workflow</string>
</tuple>
</list>
</value>
......
......@@ -8,6 +8,8 @@ Catalog Keyword Key Configurator Item | view
Categories Spreadsheet Configurator Item | view
Category Configurator Item | view
Configuration Save | view
Configuration Workflow | configurator_settings
Configuration Workflow | launch_configuration
Configurator Tool | view
Currency Configurator Item | view
Customer BT5 Configurator Item | view
......@@ -27,6 +29,4 @@ Site Property Configurator Item | view
Solver Configurator Item | view
Standard BT5 Configurator Item | view
System Preference Configurator Item | view
Workflow | configurator_settings
Workflow | launch_configuration
portal_actions | use_configurator
\ No newline at end of file
......@@ -34,6 +34,7 @@ Configuration Save | Site Property Configurator Item
Configuration Save | Solver Configurator Item
Configuration Save | Standard BT5 Configurator Item
Configuration Save | System Preference Configurator Item
Configuration Workflow | Embedded File
Organisation Configurator Item | Address
Organisation Configurator Item | Email
Organisation Configurator Item | Telephone
......@@ -41,5 +42,4 @@ Person Configurator Item | Address
Person Configurator Item | Career
Person Configurator Item | Email
Person Configurator Item | Telephone
Portal Type Roles Spreadsheet Configurator Item | Embedded File
Workflow | Embedded File
\ No newline at end of file
Portal Type Roles Spreadsheet Configurator Item | Embedded File
\ No newline at end of file
Business Configuration | Configuration Save
Business Configuration | File
Business Configuration | Link
Configuration Workflow | Embedded File
Organisation Configurator Item | Address
Organisation Configurator Item | Email
Organisation Configurator Item | Telephone
Person Configurator Item | Address
Person Configurator Item | Career
Person Configurator Item | Email
Person Configurator Item | Telephone
Workflow | Embedded File
\ No newline at end of file
Person Configurator Item | Telephone
\ No newline at end of file
Workflow | DefaultImage
Workflow | WorkflowConfigurator
\ No newline at end of file
Configuration Workflow | DefaultImage
Configuration Workflow | WorkflowConfigurator
\ No newline at end of file
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
class TestWorkflowMixin(ERP5TypeTestCase):
def getWorklistDocumentCountFromActionName(self, action_name):
# action_name look like: "Documents to validate (3)"
self.assertEqual(action_name[-1], ')')
left_parenthesis_offset = action_name.rfind('(')
self.assertNotEquals(left_parenthesis_offset, -1)
return int(action_name[left_parenthesis_offset + 1:-1])
def checkWorklist(self, action_list, name, count,
url_parameter_dict=None, workflow_id=None):
entry_list = [
x for x in action_list if x['name'].startswith(name)
and (
workflow_id is None
or 'workflow_id' in x
and x['workflow_id'] == workflow_id
)
]
# ensure there is a single entry in action list
self.assertEqual(len(entry_list), count and 1)
if count:
self.assertEqual(count,
self.getWorklistDocumentCountFromActionName(entry_list[0]['name']))
if entry_list and url_parameter_dict:
url = entry_list[0].get('url')
self.assertTrue(url, 'Can not check url parameters without url')
url = '%s%s' % (self.portal.getId(), url[len(self.portal.absolute_url()):])
# Touch URL to save worklist parameters in listbox selection
self.assertEqual(200, self.publish(url, user='manager').getStatus())
self.commit()
if getattr(self, 'module_selection_name') is not None:
selection_parameter_dict = self.portal.portal_selections.getSelectionParamsFor(selection_name)
for parameter, value in url_parameter_dict.iteritems():
self.assertIn(parameter, selection_parameter_dict)
self.assertEqual(value, selection_parameter_dict[parameter])
def clearCache(self):
self.portal.portal_caches.clearAllCache()
\ No newline at end of file
......@@ -2,7 +2,7 @@
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Extension Component" module="erp5.portal_type"/>
<global name="Mixin Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
......@@ -14,7 +14,7 @@
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>ERP5UpgraderUtils</string> </value>
<value> <string>TestWorkflowMixin</string> </value>
</item>
<item>
<key> <string>description</string> </key>
......@@ -24,11 +24,11 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>extension.erp5.ERP5UpgraderUtils</string> </value>
<value> <string>mixin.erp5.TestWorkflowMixin</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Extension Component</string> </value>
<value> <string>Mixin Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
......@@ -100,28 +100,24 @@
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
<module>
<id>organisation_module</id>
<permission_list>
<permission type='tuple'>
<name>Access contents information</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Add portal content</name>
<role>Assignor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Add portal folders</name>
<role>Assignor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Change local roles</name>
<role>Assignor</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Copy or Move</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Delete objects</name>
<role>Assignor</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>List folder contents</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>Modify portal content</name>
<role>Assignor</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>View</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Manager</role>
</permission>
<permission type='tuple'>
<name>View History</name>
<role>Assignee</role>
<role>Assignor</role>
<role>Associate</role>
<role>Auditor</role>
<role>Author</role>
<role>Manager</role>
</permission>
</permission_list>
<portal_type>Organisation Module</portal_type>
<title>Organisations</title>
</module>
\ No newline at end of file
......@@ -118,23 +118,24 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
"""
Remove workflow related to the portal type
"""
self.getWorkflowTool().setChainForPortalTypes(
['Organisation'], ())
self.getPortalObject().portal_types.Organisation.setTypeWorkflowList([])
def stepAssociateWorkflows(self, sequence=None, sequence_list=None, **kw):
"""
Associate workflow to the portal type
"""
self.getWorkflowTool().setChainForPortalTypes(
['Organisation'], ('validation_workflow', 'edit_workflow'))
self.getPortalObject().portal_types.Organisation.setTypeWorkflowList([
'validation_workflow', 'edit_workflow'
])
def stepAssociateWorkflowsExcludingEdit(self, sequence=None,
sequence_list=None, **kw):
"""
Associate workflow to the portal type
"""
self.getWorkflowTool().setChainForPortalTypes(
['Organisation'], ('validation_workflow',))
self.getPortalObject().portal_types.Organisation.setTypeWorkflowList([
'validation_workflow'
])
def stepCreateObject(self, sequence=None, sequence_list=None, **kw):
"""
......@@ -928,19 +929,16 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
# Add a non-existent workflow.
pw = self.getWorkflowTool()
dummy_worlflow_id = 'never_existent_workflow'
addWorkflowByType(pw, 'erp5_workflow', dummy_worlflow_id)
dummy_workflow_id = 'never_existent_workflow'
addWorkflowByType(pw, 'erp5_workflow', dummy_workflow_id)
self.commit()
cbt = pw._chains_by_type
props = {}
for id_, wf_ids in cbt.iteritems():
if id_ == portal_type:
wf_ids = list(wf_ids) + [dummy_worlflow_id]
props['chain_%s' % id_] = ','.join(wf_ids)
pw.manage_changeWorkflows('', props = props)
pw.manage_delObjects([dummy_worlflow_id])
organisation_type = portal.portal_types.getTypeInfo(portal_type)
organisation_initial_workflow_list = organisation_type.getTypeWorkflowList()
organisation_type.setTypeWorkflowList(
organisation_initial_workflow_list + [dummy_workflow_id])
pw.manage_delObjects([dummy_workflow_id])
self.commit()
......@@ -949,15 +947,7 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
'thisMethodShouldNotBePresent')
finally:
# Make sure that the artificial workflow is not referred to any longer.
cbt = pw._chains_by_type
props = {}
for id, wf_ids in cbt.iteritems():
if id == portal_type:
# Remove the non-existent workflow.
wf_ids = [wf_id for wf_id in wf_ids \
if wf_id != dummy_worlflow_id]
props['chain_%s' % id] = ','.join(wf_ids)
pw.manage_changeWorkflows('', props = props)
organisation_type.setTypeWorkflowList(organisation_initial_workflow_list)
self.commit()
......@@ -984,13 +974,10 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
dummy_simulation_worlflow = pw[dummy_simulation_worlflow_id]
dummy_validation_worlflow = pw[dummy_validation_worlflow_id]
dummy_validation_worlflow.variables.setStateVar('validation_state')
cbt = pw._chains_by_type
props = {}
for id_, wf_ids in cbt.iteritems():
if id_ == portal_type:
old_wf_ids = wf_ids
props['chain_%s' % id_] = ','.join([dummy_validation_worlflow_id, dummy_simulation_worlflow_id])
pw.manage_changeWorkflows('', props=props)
organisation_type = portal.portal_types.getTypeInfo(portal_type)
organisation_initial_workflow_list = organisation_type.getTypeWorkflowList()
organisation_type.setTypeWorkflowList([dummy_validation_worlflow_id,
dummy_simulation_worlflow_id])
permission_list = list(dummy_simulation_worlflow.permissions)
manager_has_permission = {}
for permission in permission_list:
......@@ -1032,14 +1019,7 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
self.assertTrue(user.has_permission(permission, obj))
finally:
# Make sure that the artificial workflow is not referred to any longer.
cbt = pw._chains_by_type
props = {}
for id, wf_ids in cbt.iteritems():
if id == portal_type:
# Remove the non-existent workflow.
wf_ids = old_wf_ids
props['chain_%s' % id] = ','.join(wf_ids)
pw.manage_changeWorkflows('', props=props)
organisation_type.setTypeWorkflowList(organisation_initial_workflow_list)
pw.manage_delObjects([dummy_simulation_worlflow_id, dummy_validation_worlflow_id])
def test_getViewPermissionOwnerDefault(self):
......
......@@ -102,7 +102,7 @@ class PropertySheetTestCase(ERP5TypeTestCase):
self.assertTrue('portal_type' in kw, "You need to specify the portal_type"
" you want to use to create that new property")
suffix = ps.newContent(temp_object=1, **kw).getIdAsReferenceSuffix()
suffix = ps.newContent(temp_object=1, **kw).getIdAsReferenceAffix()
property_id_as_reference = property_id + suffix
property_ = getattr(ps, property_id_as_reference, None)
if property_ is not None:
......@@ -130,11 +130,12 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor):
self.login()
# all those tests does strange things with Person type, so we won't
# filter content types to add inside Person.
self.getTypesTool().getTypeInfo('Person').filter_content_types = 0
person_type_object = self.getTypesTool().getTypeInfo('Person')
person_type_object.filter_content_types = 0
self.commit()
# save workflow chain for Person type
self.person_chain = self.getWorkflowTool().getChainFor('Person')
self.person_workflow_list = person_type_object.getTypeWorkflowList()
def beforeTearDown(self):
self.abort()
......@@ -145,13 +146,13 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor):
self.getCategoryTool().region ]:
module.manage_delObjects(list(module.objectIds()))
person_type_object = self.getTypesTool().getTypeInfo('Person')
# set Person.acquire_local_roles back.
if getattr(self, 'person_acquire_local_roles', None) is not None:
self.getTypesTool().getTypeInfo('Person').setTypeAcquireLocalRole(self.person_acquire_local_roles)
person_type_object.setTypeAcquireLocalRole(self.person_acquire_local_roles)
# restore workflows for other tests
self.getWorkflowTool().setChainForPortalTypes(
['Person'], self.person_chain)
person_type_object.setTypeWorkflowList(self.person_workflow_list)
super(TestERP5Type, self).beforeTearDown()
......@@ -988,24 +989,23 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor):
person = self.getPersonModule().newContent(id='1', portal_type='Person')
wf = self.getWorkflowTool().validation_workflow
# those are assumptions for this test.
self.assertTrue(wf.getId() in
self.getWorkflowTool().getChainFor('Person'))
self.assertEqual('validation_state', wf.variables.getStateVar())
initial_state = wf.states[wf.initial_state]
other_state = wf.states['validated']
self.assertTrue(wf in self.getWorkflowTool().getWorkflowValueListFor('Person'))
self.assertEqual('validation_state', wf.getStateVariable())
initial_state = wf.getSourceValue()
other_state = wf.getStateValueById('validated')
self.assertTrue(hasattr(person, 'getValidationState'))
self.assertTrue(hasattr(person, 'getValidationStateTitle'))
self.assertTrue(hasattr(person, 'getTranslatedValidationStateTitle'))
self.assertEqual(initial_state.getId(), person.getValidationState())
self.assertEqual(initial_state.getReference(), person.getValidationState())
self.assertEqual(initial_state.title,
person.getValidationStateTitle())
self.assertEqual(initial_state.title,
person.getTranslatedValidationStateTitle())
self.assertTrue([initial_state.title], message_catalog._translated)
self.assertEqual(initial_state.getId(),
self.assertEqual(initial_state.getReference(),
person.getProperty('validation_state'))
self.assertEqual(initial_state.title,
person.getProperty('validation_state_title'))
......@@ -1015,7 +1015,7 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor):
self.assertTrue([initial_state.title], message_catalog._translated)
# default parameter is accepted by getProperty for compatibility
self.assertEqual(initial_state.getId(),
self.assertEqual(initial_state.getReference(),
person.getProperty('validation_state', 'default'))
self.assertEqual(initial_state.title,
person.getProperty('validation_state_title', 'default'))
......@@ -1027,12 +1027,12 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor):
# pass a transition and check accessors again.
person.validate()
self.assertEqual(other_state.getId(), person.getValidationState())
self.assertEqual(other_state.getReference(), person.getValidationState())
self.assertEqual(other_state.title,
person.getValidationStateTitle())
self.assertEqual(other_state.title,
person.getTranslatedValidationStateTitle())
self.assertEqual(other_state.getId(),
self.assertEqual(other_state.getReference(),
person.getProperty('validation_state'))
self.assertEqual(other_state.title,
person.getProperty('validation_state_title'))
......
......@@ -91,8 +91,8 @@ class TestInteractionWorkflow(ERP5TypeTestCase):
if getattr(wf.interactions, 'edit_interaction', None) is None:
wf.interactions.addInteraction(id='edit_interaction')
self.interaction = wf.interactions['edit_interaction']
self.getWorkflowTool().setChainForPortalTypes(
[self.portal_type],'test_workflow, validation_workflow')
type_object = self.portal.portal_types.getTypeInfo(self.portal_type)
type_object.setTypeWorkflowList(['test_workflow', 'validation_workflow'])
_aq_reset() # XXX Fails XXX _setLastId not found when doing newContent
def createInteractionWorkflowWithTwoInteractions(self):
......@@ -110,8 +110,8 @@ class TestInteractionWorkflow(ERP5TypeTestCase):
self.scriptB = wf.scripts['afterEditB']
wf.interactions.addInteraction(id='editB')
self.interactionB = wf.interactions['editB']
self.getWorkflowTool().setChainForPortalTypes(
[self.portal_type],'test_workflow, validation_workflow')
type_object = self.portal.portal_types.getTypeInfo(self.portal_type)
type_object.setTypeWorkflowList(['test_workflow', 'validation_workflow'])
_aq_reset() # XXX Fails XXX _setLastId not found when doing newContent
def test_no_interactions(self):
......@@ -679,8 +679,8 @@ context.setTitle('Bar')
def test_portal_type_filter(self):
self.createInteractionWorkflow()
self.getWorkflowTool().setChainForPortalTypes(
['Bank Account'],'test_workflow, validation_workflow')
type_object = self.portal.portal_types.getTypeInfo('Bank Account')
type_object.setTypeWorkflowList(['test_workflow', 'validation_workflow'])
self.interaction.setProperties(
'default',
# only for bank accounts
......@@ -704,8 +704,8 @@ context.setTitle('Bar')
def test_portal_type_group_filter(self):
self.createInteractionWorkflow()
self.getWorkflowTool().setChainForPortalTypes(
['Bank Account'],'test_workflow, validation_workflow')
type_object = self.portal.portal_types.getTypeInfo('Bank Account')
type_object.setTypeWorkflowList(['test_workflow', 'validation_workflow'])
self.interaction.setProperties(
'default',
# only for payment nodes portal type group (ie. bank account)
......
......@@ -27,10 +27,11 @@
#
##############################################################################
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Testing.ZopeTestCase.PortalTestCase import PortalTestCase
import re
class TestWorklist(ERP5TypeTestCase):
from erp5.component.mixin.TestWorkflowMixin import TestWorkflowMixin
class TestWorklist(TestWorkflowMixin):
run_all_test = 1
quiet = 1
......@@ -142,32 +143,99 @@ class TestWorklist(ERP5TypeTestCase):
assert result.getValidationState() == self.checked_validation_state
return result
def getWorklistDocumentCountFromActionName(self, action_name):
self.assertEqual(action_name[-1], ')')
left_parenthesis_offset = action_name.rfind('(')
self.assertNotEquals(left_parenthesis_offset, -1)
return int(action_name[left_parenthesis_offset + 1:-1])
def associatePropertySheet(self):
self._addPropertySheet(self.checked_portal_type, 'SortIndex')
def addWorkflowCataloguedVariable(self, workflow_id, variable_id):
variables = self.getWorkflowTool()[workflow_id].variables
variables.addVariable(variable_id)
assert variables[variable_id].for_catalog == 1
# add new workflow compatibility
workflow_value = self.getWorkflowTool()[workflow_id]
if workflow_value.__class__.__name__ == 'Workflow':
# Will add dynamic variable in worklist.
pass
else:
variables = workflow_value.variables
variables.addVariable(variable_id)
variable_value = variables[variable_id]
assert variable_value.for_catalog == 1
def createWorklist(self, workflow_id, worklist_id, actbox_name,
actbox_url=None, **kw):
worklists = self.getWorkflowTool()[workflow_id].worklists
worklists.addWorklist(worklist_id)
worklists._getOb(worklist_id).setProperties('',
# add new workflow compatibility
tales_re = re.compile(r'(\w+:)?(.*)')
workflow_value = self.getWorkflowTool()[workflow_id]
if workflow_value.__class__.__name__ == 'Workflow':
worklist_value = workflow_value.newContent(portal_type='Worklist')
worklist_value.setReference(worklist_id)
# Configure new workflow:
actbox_name='%s (%%(count)s)' % actbox_name
worklist_value.setActionName(str(actbox_name))
worklist_value.setAction(str(actbox_url))
worklist_value.setActionType('global')
props={k if k.startswith('guard_') else 'variable_' + k: v
for k, v in kw.iteritems()}
if 'variable_portal_type' in props:
v = props.get('variable_portal_type', None)
if v:
worklist_value.setMatchedPortalTypeList(v)
if 'variable_validation_state' in props:
v = props.get('variable_validation_state', None)
if v:
worklist_value.setMatchedValidationState(v)
if 'variable_' + self.int_catalogued_variable_id in props:
variable_ref = self.int_catalogued_variable_id
v = props.get('variable_'+self.int_catalogued_variable_id, None)
if v:
# Add a local worklist variable:
variable_value = worklist_value._getOb('variable_' + self.int_catalogued_variable_id, None)
if variable_value is None:
variable_value = worklist_value.newContent(portal_type='Worklist Variable')
variable_value.setReference(variable_ref)
variable_value.setVariableDefaultValue(str(v))
# test04 related key
if 'variable_region_uid' in props:
v = props.get('variable_region_uid', None)
if v:
variable_value = worklist_value._getOb('variable_region_uid', None)
if variable_value is None:
variable_value = worklist_value.newContent(portal_type='Worklist Variable')
variable_value.setReference('region_uid')
variable_value.setVariableDefaultValue(v)
if 'variable_base_category_id' in props:
variable_value = worklist_value._getOb('variable_base_category_id', None)
v = props.get('variable_base_category_id', None)
if variable_value is None:
variable_value = worklist_value.newContent(portal_type='Worklist Variable')
variable_value.setReference('base_category_id')
variable_value.setVariableDefaultValue(v)
# Update guard configuration for view and guard value.
if 'guard_roles' in props:
v = props.get('guard_roles', '')
if v:
worklist_value.setGuardRoleList([ var.strip() for var in v.split(';') ])
if 'guard_expr' in props:
v = props.get('guard_expr', '')
if v:
worklist_value.setGuardExpression(v)
else:
worklists = workflow_value.worklists
worklists.addWorklist(worklist_id)
worklist_value = worklists._getOb(worklist_id)
worklist_value.setProperties('',
actbox_name='%s (%%(count)s)' % actbox_name, actbox_url=actbox_url,
props={k if k.startswith('guard_') else 'var_match_' + k: v
for k, v in kw.iteritems()})
def removeWorklist(self, workflow_id, worklist_id_list):
worklists = self.getWorkflowTool()[workflow_id].worklists
worklists.deleteWorklists(worklist_id_list)
# add new workflow compatibility
workflow_value = self.getWorkflowTool()[workflow_id]
if workflow_value.__class__.__name__ == 'Workflow':
for worklist_id in worklist_id_list:
workflow_value._delObject('worklist_'+worklist_id)
else:
worklists = self.getWorkflowTool()[workflow_id].worklists
worklists.deleteWorklists(worklist_id_list)
def createWorklists(self):
for worklist_id, actbox_name, role, expr, state, int_variable in [
......@@ -200,30 +268,6 @@ class TestWorklist(ERP5TypeTestCase):
self.worklist_int_variable_id,
])
def clearCache(self):
self.portal.portal_caches.clearAllCache()
def checkWorklist(self, result, name, count, url_parameter_dict=None):
entry_list = [x for x in result if x['name'].startswith(name)]
self.assertEqual(len(entry_list), count and 1)
if count:
self.assertEqual(count,
self.getWorklistDocumentCountFromActionName(entry_list[0]['name']))
if not entry_list:
return
url = entry_list[0].get('url')
if url_parameter_dict:
self.assertTrue(url, 'Can not check url parameters without url')
url = '%s%s' % (self.portal.getId(), url[len(self.portal.absolute_url()):])
# Touch URL to save worklist parameters in listbox selection
# XXX which user ?
self.assertEqual(200, self.publish(url, user='manager').getStatus())
selection_parameter_dict = self.portal.portal_selections.getSelectionParamsFor(
self.module_selection_name)
for parameter, value in url_parameter_dict.iteritems():
self.assertTrue(parameter in selection_parameter_dict)
self.assertEqual(value, selection_parameter_dict[parameter])
def test_01_permission(self, quiet=0, run=run_all_test):
"""
Test the permission of the building module.
......
mixin.erp5.TestWorkflowMixin
\ No newline at end of file
organisation_module
\ No newline at end of file
......@@ -46,6 +46,7 @@ test.erp5.testQueryModule
test.erp5.testRestrictedPythonSecurity
test.erp5.testSelectionTool
test.erp5.testSessionTool
test.erp5.testSQLCachedWorklist
test.erp5.testTimeout
test.erp5.testTimerService
test.erp5.testTransactionalVariable
......
......@@ -3,7 +3,7 @@ from Products.ERP5Type.Utils import UpperCase
portal = context.getPortalObject()
workflow_tool = portal.portal_workflow
for workflow in workflow_tool.getWorkflowsFor(context):
for workflow in workflow_tool.getWorkflowValueListFor(context):
# Exclude interaction workflows and edit_workflow
if workflow.state_var != 'state':
return getattr(context, 'getTranslated%sTitle' % UpperCase(workflow.state_var))()
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.Message import translateString
container.Event_checkConsistency(sci)
......
......@@ -2543,7 +2543,11 @@ return 1
document.reject()
document.share()
logged_in_user = self.portal.portal_membership.getAuthenticatedMember().getId()
event_list = document.Base_getWorkflowEventInfoList()
# on the new document, during initialization, some workflow set the event's
# action to None, but they are not interesting in this test, just filter
# them
event_list = [event for event in document.Base_getWorkflowEventInfoList()
if event.action is not None]
event_list.reverse()
# all actions by logged in user
for event in event_list:
......
......@@ -65,7 +65,7 @@ def findMessageListFromPythonInProduct(function_name_list):
erp5_product_list = ('CMFActivity', 'CMFCategory',
'ERP5', 'ERP5Catalog',
'ERP5Form', 'ERP5OOo', 'ERP5Security',
'ERP5Type', 'ERP5Wizard', 'ERP5Workflow',
'ERP5Type', 'ERP5Wizard',
'HBTreeFolder2', 'MailTemplates', 'TimerService',
'ZMySQLDA', 'ZSQLCatalog',
)
......
......@@ -25,12 +25,12 @@ def get_obj_and_reference_list(business_field):
wf = getattr(portal_workflow, wf_id)
if getattr(wf, "interactions", marker) is marker: # only way to make sure it is not an interaction workflow ?
result.append((wf, wf_id, 'workflow'))
for state_id, state in wf.states.items():
result.append((state, state_id, 'state'))
for trans_id, trans in wf.transitions.items():
result.append((trans, trans_id, 'transition'))
if trans.trigger_type == 1 and trans.actbox_name: # 1 == TRIGGER_USER_ACTION
result.append((trans, "%s_actbox_name" % trans_id, 'action'))
for state in wf.getStateValueList():
result.append((state, state.getReference(), 'state'))
for transition in wf.getTransitionValueList():
result.append((transition, transaction.getReference(), 'transition'))
if transition.getTriggerType() == 1 and transaction.getActionName(): # 1 == TRIGGER_USER_ACTION
result.append((transition, "%s_actbox_name" % transaction.getReference(), 'action'))
return result
business_field_list = [i for i in business_field_list if i]
......
from Products.ERP5Type.Document import newTempBase
marker = []
prefix = 'erp5_'
language = 'en'
term_dict = {}
result = []
for bt_id in template_list:
# XXX this might be too simple: some business template include more than one skin folder
bt = context.portal_templates.getInstalledBusinessTemplate(bt_id)
if bt is None: continue
if bt_id.startswith(prefix):
bt_id = bt_id[len(prefix):]
portal_catalog = context.portal_catalog
portal_workflow = context.portal_workflow
portal_templates = context.portal_templates
def get_term_list(business_field, reference):
reference = reference.rsplit('_action', 1)[0]
term_list = portal_catalog(portal_type='Glossary Term',
validation_state='validated',
language_id='en',
business_field_title=('core', business_field),
reference=reference)
return [i.getObject() for i in term_list]
def get_obj_and_reference_list(business_field):
business_field = business_field.split('/')[0]
result = []
# XXX this might be too simple: some business template include more than one skin folder
bt = portal_templates.getInstalledBusinessTemplate("erp5_%s" % business_field)
if bt is None: return result
for wf_id in bt.getTemplateWorkflowIdList():
wf = getattr(context.portal_workflow, wf_id)
wf = getattr(portal_workflow, wf_id)
if getattr(wf, "interactions", marker) is marker: # only way to make sure it is not an interaction workflow ?
term_dict[(wf_id, bt_id, wf.title, wf.description)] = wf_id
for state_id, state in wf.states.items():
term_dict[(state_id, bt_id, state.title, state.description)] = wf_id
for trans_id, trans in wf.transitions.items():
term_dict[(trans_id, bt_id, trans.title, trans.description)] = wf_id
if trans.trigger_type == 1 and trans.actbox_name: # 1 == TRIGGER_USER_ACTION
term_dict[('%s_actbox_name' % trans_id, bt_id, trans.actbox_name, '')] = wf_id
for (reference, business_field, title, description), workflow_id in term_dict.items():
result.append({'reference': reference,
'language': language,
'business_field': business_field,
'title': title,
'description': description,
'workflow_id':workflow_id})
return result
result.append((wf, wf_id, 'workflow'))
for state in wf.getStateValueList():
result.append((state, state.getReference(), 'state'))
for transition in wf.getTransitionValueList():
result.append((transition, transition.getReference(), 'transition'))
if transition.getTriggerType() == 1 and transition.getActionName(): # 1 == TRIGGER_USER_ACTION
result.append((transition, "%s_actbox_name" % transition.getReference(), 'action'))
return result
business_field_list = [i for i in business_field_list if i]
line_list = []
c = 0
item_dict = {}
for business_field in business_field_list:
for wf_item, reference, type in get_obj_and_reference_list(business_field):
term_list = get_term_list(business_field, reference)
#if not term_list:
# continue
if item_dict.has_key(wf_item):
continue
item_dict[wf_item] = True
c += 1
if type == 'workflow':
wf_item_path = wf_item.getId()
wf_item_title = wf_item.getTitle()
elif type == 'state':
wf_item_path = '%s/states/%s' % (wf_item.aq_parent.aq_parent.getId(), wf_item.getId())
wf_item_title = wf_item.getTitle()
elif type == 'transition':
wf_item_path = '%s/transitions/%s' % (wf_item.aq_parent.aq_parent.getId(), wf_item.getId())
wf_item_title = wf_item.getTitle()
else: # type == 'action'
wf_item_path = '%s/transitions/%s_actbox_name' % (wf_item.aq_parent.aq_parent.getId(), wf_item.getId())
wf_item_title = wf_item.getActionName()
wf_item_description = wf_item.getDescription()
if type == 'transition' and wf_item_path.endswith('_action'):
if len(term_list) == 1 and \
term_list[0].getTitle() + ' Action' == wf_item_title and \
term_list[0].getDescription() == wf_item_description:
continue
else:
if len(term_list) == 1 and \
term_list[0].getTitle() == wf_item_title and \
term_list[0].getDescription() == wf_item_description:
continue
line = newTempBase(context, 'tmp_glossary_wf_item_%s' % c)
line.edit(wf_item_path=wf_item_path,
wf_item_type=type,
wf_item_title=wf_item_title,
wf_item_edit_url = "%s/manage_properties" % wf_item.absolute_url(),
wf_item_description = wf_item_description,
reference=reference,
term_list=term_list
)
line.setUid(wf_item_path)
line_list.append(line)
line_list.sort(key=lambda x:x.wf_item_path)
return line_list
......@@ -23,7 +23,7 @@ for i in kw.keys():
wf_item.setProperties(term.getTitle(), description=term.getDescription(), manager_bypass=wf_item.manager_bypass)
elif wf_item.meta_type == "Workflow State":
wf_item.setProperties(term.getTitle(), description=term.getDescription(),
transitions=wf_item.transitions, type_list=wf_item.type_list)
transitions=wf_item.getDestinationReferenceList(), type_list=wf_item.type_list)
else: # wf_item.meta_type == "Workflow Transition"
guard = getattr(wf_item, 'guard', None)
if not is_action:
......
......@@ -40,7 +40,7 @@ iterate(context.portal_skins)
# Collect python script from workflow objects.
for workflow in context.portal_workflow.objectValues():
for i in workflow.scripts.objectValues():
for i in workflow.getScriptValueDict().values():
if i.meta_type=='Script (Python)':
python_script_list.append(i)
......@@ -107,34 +107,35 @@ for i in page_template_list:
for i in context.portal_workflow.objectValues():
add_message(i.title_or_id(), portal_url.getRelativeContentURL(i))
if not i.states:
state_value_list = i.getStateValueList()
if not state_value_list:
continue
for s in i.states.values():
s_title = s.title
if s_title:
for s in state_value_list:
if s.getTitle():
# adding a context in msg_id for more precise translation
msg_id = getMessageIdWithContext(s_title,'state',i.id)
msg_id = getMessageIdWithContext(s.getTitle(),'state',i.getId())
add_message(msg_id, portal_url.getRelativeContentURL(s))
# also use state title as msg_id for compatibility
add_message(s_title, portal_url.getRelativeContentURL(s))
add_message(s.getTitle(), portal_url.getRelativeContentURL(s))
if not i.transitions:
transition_value_list = i.getTransitionValueList()
if not transition_value_list:
continue
for t in i.transitions.values():
if t.actbox_name:
for t in transition_value_list:
if t.getActionName():
#adding a context in msg_id for more precise translation
msg_id = getMessageIdWithContext(t.actbox_name,'transition',i.id)
msg_id = getMessageIdWithContext(t.getActionName(),'transition',i.getId())
add_message(msg_id, portal_url.getRelativeContentURL(t))
# also use action box name as msg_id for compatibility
add_message(t.actbox_name, portal_url.getRelativeContentURL(t))
if t.title:
add_message(t.getActionName(), portal_url.getRelativeContentURL(t))
if t.getTitle():
#adding a context in msg_id for more precise translation
msg_id = getMessageIdWithContext(t.title,'transition',i.id)
msg_id = getMessageIdWithContext(t.getTitle(),'transition',i.getId())
add_message(msg_id, portal_url.getRelativeContentURL(t))
# also use transition title as msg_id for compatibility
add_message(t.title, portal_url.getRelativeContentURL(t))
for worklist in i.worklists.objectValues():
add_message(worklist.actbox_name, portal_url.getRelativeContentURL(worklist))
add_message(t.getTitle(), portal_url.getRelativeContentURL(t))
for worklist in i.getWorklistValueList():
add_message(worklist.getActionName(), portal_url.getRelativeContentURL(worklist))
#
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>reset_graph</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>Modify portal content</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>8.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Reset graph positions</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Workflow_resetGraph</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>6.0</float> </value>
<value> <float>8.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
......
from Products.ERP5Type.Message import translateString
import json
portal = context.getPortalObject()
# if a graph has been saved, we use this info for node coordinates.
position_graph = context.getProperty('jsplumb_graph')
if position_graph:
position_graph = json.loads(position_graph)['graph']
# TODO:
# select after script in edge properties
# checked box for validation ? or at least select before script
def getWorkflowGraph(workflow):
graph = {'node': {}, 'edge': {}}
for state in workflow.getStateValueList():
is_initial_state = state.getId() == workflow.getSourceId()
transition_list = []
graph['node'][state.getId()] = {
'_class':'workflow.state',
'name': state.getTitleOrId(),
'is_initial_state': is_initial_state,
'path': state.getPath()
}
for transition in state.getDestinationValueList():
transition_id = transition.getReference()
if transition_id in workflow.getTransitionIdList():
if transition.getDestinationId():
graph['edge']["%s_%s" % (state.getId(), transition.getId())] = ({
'_class': 'workflow.transition',
'source': state.getId(),
'destination': transition.getDestinationId(),
'name': transition.getActionName() or transition.getTitleOrId(),
'description': transition.getDescription(),
'actbox_url': transition.getAction(),
'transition_id': transition.getId(), # used for edition.
'path': transition.getPath()
})
else:
# user action
transition_list.append(transition)
if transition_list != []:
graph['edge']['transition_to_%s' % (state.getId())] = {
'_class':'workflow.transition',
'source':state.getId(),
'destination': state.getId(),
'name_path_dict': {transition.getTitleOrId(): transition.getPath() for transition in transition_list}
}
if position_graph:
for state_id in graph['node'].keys():
if state_id in position_graph['node']:
graph['node'][state_id]['coordinate'] = position_graph['node'][state_id]['coordinate']
return graph
return json.dumps(dict(graph=getWorkflowGraph(context), class_definition={}), indent=2)
......@@ -54,7 +54,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Variable_getNonEvaluatedInitialValue</string> </value>
<value> <string>Workflow_getGraph</string> </value>
</item>
</dictionary>
</pickle>
......
# after calling this script, positions of the states will be chosen by jsplumb
# and manually changed positions which were saved by a user will be erased
context.setProperty('jsplumb_graph', None)
context.Base_redirect(form_id='Workflow_viewGraph')
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Workflow_resetGraph</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -18,6 +18,7 @@
<script src="../lib/jquery-ui.js" type="text/javascript"></script>
<script src="../lib/jquery.jsplumb.js" type="text/javascript"></script>
<script src="../lib/handlebars.min.js" type="text/javascript"></script>
<script src="seedrandom.js" type="text/javascript"></script>
<script src="../lib/springy.js" type="text/javascript"></script>
<script src="../dream/mixin_promise.js" type="text/javascript"></script>
......@@ -27,7 +28,7 @@
<div class="window {{class}}"
id="{{element_id}}"
title="{{title}}">
{{name}}
<a href="{{name_href}}">{{name}}</a>
<div class="ep"></div>
</div>
</script>
......
......@@ -4,13 +4,17 @@
border: 1px solid #999;
min-width: 400px;
min-height: 400px;
min-height: 1200px;
overflow: hidden;
background-color: #eaedef;
text-align: center;
}
.selected {
color: #bd0b0b!important
}
.window,
.label {
background-color: #fff;
......@@ -109,4 +113,4 @@ path,
}
path {
cursor: pointer
}
\ No newline at end of file
}
......@@ -353,11 +353,25 @@
function addEdge(gadget, edge_id, edge_data) {
var overlays = [];
var connection;
var label = '';
if (edge_data.name) {
label = edge_data.name;
if (edge_data.path) {
label = label.link(edge_data.path);
}
}
if (edge_data.name_path_dict) {
var linked_name_list = [];
for (var name in edge_data.name_path_dict) {
linked_name_list.push(name.link(edge_data.name_path_dict[name]));
}
label = linked_name_list.join(', ');
}
if (label) {
overlays = [
["Label", {
cssClass: "l1 component label",
label: edge_data.name
label: label
}]
];
}
......@@ -477,78 +491,6 @@
return clone(expanded_class_definition);
}
function openEdgeEditionDialog(gadget, connection) {
var edge_id = connection.id;
var edge_data = gadget.props.data.graph.edge[edge_id];
var edit_popup = $(gadget.props.element).find("#popup-edit-template");
var schema;
var fieldset_element;
var delete_promise;
schema = expandSchema(gadget.props.data.class_definition[edge_data._class], gadget.props.data);
// We do not edit source & destination on edge this way.
delete schema.properties.source;
delete schema.properties.destination;
gadget.props.element.insertAdjacentHTML("beforeend", popup_edit_template);
edit_popup = $(gadget.props.element).find("#edit-popup");
edit_popup.find(".node_class").text(connection.name || connection._class);
fieldset_element = edit_popup.find("fieldset")[0];
edit_popup.dialog();
edit_popup.show();
function save_promise(fieldset_gadget) {
return new RSVP.Queue().push(function () {
return promiseEventListener(edit_popup.find(".graph_editor_validate_button")[0], "click", false);
}).push(function (evt) {
var data = {
id: $(evt.target[1]).val(),
data: {}
};
return fieldset_gadget.getContent().then(function (r) {
$.extend(data.data, gadget.props.data.graph.edge[connection.id]);
$.extend(data.data, r);
// to redraw, we remove the edge and add again.
// but we want to disable events on connection, since event
// handling promise are executed asynchronously in undefined order,
// we cannot just remove and /then/ add, because the new edge is
// added before the old is removed.
connection.ignoreEvent = true;
gadget.props.jsplumb_instance.detach(connection);
addEdge(gadget, r.id, data.data);
});
});
}
delete_promise = new RSVP.Queue().push(function () {
return promiseEventListener(edit_popup.find(".graph_editor_delete_button")[0], "click", false);
}).push(function () {
// connectionDetached event will remove the edge from data
gadget.props.jsplumb_instance.detach(connection);
});
return gadget.declareGadget("../fieldset/index.html", {
element: fieldset_element,
scope: "fieldset"
}).push(function (fieldset_gadget) {
return RSVP.all([fieldset_gadget, fieldset_gadget.render({
value: edge_data,
property_definition: schema
}, edge_id)]);
}).push(function (fieldset_gadget) {
edit_popup.dialog("open");
return fieldset_gadget[0];
}).push(function (fieldset_gadget) {
fieldset_gadget.startService(); // XXX
return fieldset_gadget;
}).push(function (fieldset_gadget) {
// Expose the dialog handling promise so that we can wait for it in
// test.
gadget.props.dialog_promise = RSVP.any([save_promise(fieldset_gadget, edge_id), delete_promise]);
return gadget.props.dialog_promise;
}).push(function () {
edit_popup.dialog("close");
edit_popup.remove();
delete gadget.props.dialog_promise;
});
}
function openNodeEditionDialog(gadget, element) {
var node_id = getNodeId(gadget, element.id);
var node_data = gadget.props.data.graph.node[node_id];
......@@ -646,12 +588,6 @@
});
}
function waitForConnectionClick(gadget) {
return loopJsplumbBind(gadget, "click", function (connection) {
return openEdgeEditionDialog(gadget, connection);
});
}
function addNode(gadget, node_id, node_data) {
var render_element = $(gadget.props.main);
var class_definition = gadget.props.data.class_definition[node_data._class];
......@@ -676,7 +612,8 @@
"class": node_data._class.replace(".", "-"),
element_id: dom_element_id,
title: node_data.name || node_data.id,
name: node_data.name || node_data.id
name: node_data.name || node_data.id,
name_href: node_data.path
}), "text/html").querySelector(".window");
render_element.append(domElement);
box = $(gadget.props.element).find("#" + dom_element_id);
......@@ -686,6 +623,10 @@
}
box.css("top", absolute_position[1]);
box.css("left", absolute_position[0]);
if (node_data.is_initial_state) {
box.css("border", "double #000000");
box.css("font-weight", "bold");
}
updateNodeStyle(gadget, dom_element_id);
draggable(gadget);
// XXX make only this element draggable.
......@@ -862,8 +803,7 @@
return RSVP.all([
waitForDrop(gadget),
waitForConnection(gadget),
waitForConnectionDetached(gadget),
waitForConnectionClick(gadget)
waitForConnectionDetached(gadget)
]);
});
......
......@@ -2,21 +2,25 @@
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ExternalMethod" module="Products.ExternalMethod.ExternalMethod"/>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_function</string> </key>
<value> <string>ERP5Site_dumpWorkflowChainByPortalType</string> </value>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value>
</item>
<item>
<key> <string>_module</string> </key>
<value> <string>ERP5UpgraderUtils</string> </value>
<key> <string>__name__</string> </key>
<value> <string>seedrandom.js</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ERP5Site_dumpWorkflowChainByPortalType</string> </value>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
......
......@@ -24,6 +24,13 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
// Nexedi patch: use seedrandom instead of Math.random to always get the same
// graph representation this will in order to be able to use seed and thus
// get the same set of random number, used to set the place of the graph nodes
var seeded_random = new Math.seedrandom('Using seedrandom for getting same set'
+ 'of pseudorandom numbers.');
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
......@@ -577,7 +584,7 @@
};
Vector.random = function() {
return new Vector(10.0 * (Math.random() - 0.5), 10.0 * (Math.random() - 0.5));
return new Vector(10.0 * (seeded_random() - 0.5), 10.0 * (seeded_random() - 0.5));
};
Vector.prototype.add = function(v2) {
......
Business Process | view_graph_editor
\ No newline at end of file
Business Process | view_graph_editor
Workflow | reset_graph
Workflow | view_graph
\ No newline at end of file
from Products.CMFCore.WorkflowCore import WorkflowException
from Products.Formulator.Errors import FormValidationError
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.Message import translateString
from erp5.component.module.Log import WARNING
......
......@@ -27,7 +27,7 @@
#
##############################################################################
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Acquisition import aq_parent
......
......@@ -5,6 +5,6 @@
portal_workflow = context.getPortalObject().portal_workflow
workflow = getattr(portal_workflow, workflow_id)
worklist = getattr(workflow.worklists, worklist_id)
roles = worklist.getGuard().getRolesText().split(';')
return roles
worklist = workflow.getWorklistValueById(worklist_id)
role_list = worklist.getGuardRoleList()
return role_list
......@@ -14,7 +14,7 @@ except AttributeError:
return {}
# If this is a worklist action, read the worklist definition
worklist = getattr(workflow.worklists, action['worklist_id'])
worklist = workflow.getWorklistValueById(action['worklist_id'])
for varkey in worklist.getVarMatchKeys():
kw[varkey] = worklist.getVarMatch(varkey)
......
......@@ -133,7 +133,7 @@ XXX: Folder_filter accesses selection directly
</tal:block>
<tal:block tal:condition="portal/portal_workflow/Base_getSourceVisibility">
<option value="1" disabled="disabled" i18n:translate="" i18n:domain="ui">-- Workflows --</option>
<tal:block tal:repeat="workflow python: portal.portal_workflow.getWorkflowsFor(here)">
<tal:block tal:repeat="workflow python: portal.portal_workflow.getWorkflowValueListFor(here)">
<option tal:attributes="value python: '%s/manage_properties' % (workflow.absolute_url(), )" tal:content="workflow/title" />
</tal:block>
</tal:block>
......
......@@ -62,7 +62,7 @@ portal.support_request_module.newContent(
).validate()
# create a campaign that should not appear in this worklist
if portal.portal_workflow.ticket_workflow.worklists.get('0A_draft_campaign_list', None) is None:
if portal.portal_workflow.ticket_workflow.getWorklistValueById('0A_draft_campaign_list') is None:
raise ValueError('Without this worklist, tests have to be updated.')
portal.campaign_module.newContent(
portal_type='Campaign',
......
......@@ -9,7 +9,7 @@ import datetime
import os
import time
import requests
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
present = False
tz = None
......
......@@ -29,7 +29,7 @@ from test import pystone
from time import time
pystone.clock = time
from erp5.component.test.testPerformance import TestPerformanceMixin
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Testing import ZopeTestCase
class TestWorkflowPerformance(TestPerformanceMixin):
......
......@@ -32,7 +32,7 @@ import unittest
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from AccessControl.SecurityManagement import newSecurityManager
from DateTime import DateTime
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.tests.Sequence import SequenceList, Sequence
class TestTaskMixin:
......
......@@ -48,7 +48,7 @@ class TestRealTimeInventoryAccountingMixin:
sequence.edit(current_production_packing_list=sequence['production_packing_list_1'])
def _transitAndCheck(self, document, workflow_method_id, expected_state):
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
try:
if workflow_method_id.endswith('_action'):
self.portal.portal_workflow.doActionFor(document, workflow_method_id)
......
......@@ -45,6 +45,7 @@ class SolverMixin(object):
# Declarative interfaces
zope.interface.implements(ISolver,)
workflow_list = ()
def _solve(self, activate_kw=None):
raise NotImplementedError
......
......@@ -103,6 +103,7 @@
<string>my_type_property_sheet_list</string>
<string>my_type_base_category_list</string>
<string>my_type_icon</string>
<string>my_type_workflow_list</string>
</list>
</value>
</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>items</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_type_workflow_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_parallel_list_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Workflow</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: [(x.getId(), x.getId()) for x in here.getPortalObject().portal_workflow.objectValues()]</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
delivery = state_change['object']
divergence_list = delivery.getDivergenceList()
......
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
import json
from time import sleep
......
......@@ -2706,8 +2706,8 @@ class TestInventory(TestOrderMixin, ERP5TypeTestCase):
Make sure that changing workflow state after delivered changes
records in stock table.
"""
delivered_state = self.portal.portal_workflow.inventory_workflow.states['delivered']
delivered_state.transitions = delivered_state.transitions + ('cancel',)
delivered_state = self.portal.portal_workflow.inventory_workflow.getStateValueById('delivered')
delivered_state.addPossibleTransition('cancel')
self.commit()
......
......@@ -536,7 +536,7 @@ class TestOrderBuilder(TestOrderBuilderMixin, ERP5TypeTestCase):
"""
# changing type_list here is somehow dirty, decision would need to be taken if this is acceptable
# for everyone to have auto_planned as part of future inventory
self.portal.portal_workflow.order_workflow.states['auto_planned'].type_list = ('planned_order', 'future_inventory')
self.portal.portal_workflow.order_workflow.getStateValueById('auto_planned').setStateTypeList(('planned_order', 'future_inventory'))
self.portal.portal_caches.clearAllCache()
self.assertTrue('auto_planned' in self.portal.getPortalFutureInventoryStateList())
# end of patch
......
......@@ -31,7 +31,6 @@ import unittest
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5.Document.BusinessTemplate import getChainByType
from zLOG import LOG
from Products.ERP5Type.tests.Sequence import SequenceList
from erp5.component.test.testOrder import TestOrderMixin
......@@ -2270,10 +2269,8 @@ class TestSolvingPackingList(TestPackingListMixin, ERP5TypeTestCase):
solver_process_type_info.getTypeAllowedContentTypeList() +
[solver_id]
)
(default_chain, chain_dict) = getChainByType(self.portal)
chain_dict['chain_%s' % solver_id] = 'solver_workflow'
self.portal.portal_workflow.manage_changeWorkflows(default_chain,
props=chain_dict)
type_object = self.portal.portal_types.getTypeInfo(solver_id)
type_object.setTypeWorkflowList(['solver_workflow'])
self.portal.portal_caches.clearAllCache()
self.added_target_solver_list.append(solver_id)
......
......@@ -39,7 +39,7 @@ transaction.newContent(
quantity=(-float(context.getTotalPrice())),
)
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from zExceptions import Redirect
try:
transaction.Base_checkConsistency()
......
"""Just raise a Validation failed exception.
"""
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Core.Workflow import ValidationFailed
from Products.ERP5Type.Message import Message
raise ValidationFailed(Message('erp5_ui', 'Workflow script raised'))
......@@ -3,6 +3,5 @@
<item>TemplateToolBusinessTemplateInstallationConstraint</item>
<item>TemplateToolCategoryNameConstraint</item>
<item>TemplateToolTableConsistencyConstraint</item>
<item>TemplateToolWorkflowChainConsistencyConstraint</item>
</portal_type>
</property_sheet_list>
\ No newline at end of file
......@@ -38,20 +38,12 @@ for _, bt5_id in resolved_list:
workflow_id_list.append(workflow_id)
error_list = []
workflow_chain_by_portal_type_dict = context.ERP5Site_dumpWorkflowChainByPortalType()
new_workflow_chain_dict = {'chain_%s' % portal_type : ','.join(chain) \
for portal_type, chain in workflow_chain_by_portal_type_dict.iteritems()}
for portal_type, workflow_chain in portal_type_dict.iteritems():
workflow_chain_list = list(workflow_chain_by_portal_type_dict.get(portal_type, []))
workflow_chain_list = context.portal_types.getTypeInfo(portal_type).getTypeWorkflowList()
expected_workflow_chain = sorted(workflow_chain)
if sorted(workflow_chain_list) != expected_workflow_chain:
error_list.append("%s - Expected: %s <> Found: %s" % (portal_type, ', '.join(workflow_chain), ', '.join(workflow_chain_list)))
error_list.append("%r - Expected: %s <> Found: %r" % (portal_type, workflow_chain, workflow_chain_list))
if fixit:
new_workflow_chain_dict["chain_%s" % portal_type] = ','.join(expected_workflow_chain)
if fixit and new_workflow_chain_dict:
portal_workflow = context.getPortalObject().portal_workflow
portal_workflow.manage_changeWorkflows(default_chain="", props=new_workflow_chain_dict)
portal_type_document.setTypeWorkflowList(expected_workflow_chain)
return error_list
......@@ -228,14 +228,6 @@ class TestUpgrader(ERP5TypeTestCase):
def stepCheckPostUpgradeEmptyConstraintList(self, sequence=None):
self._checkEmptyConstraintList('upgrader_check_post_upgrade')
def stepCheckPosUpgradeWorkflowChainConsistency(self, sequence=None):
alarm = getattr(self.portal.portal_alarms, 'upgrader_check_post_upgrade')
active_process = alarm.getLastActiveProcess()
detail_list = active_process.getResultList()[0].detail
message = 'Preference - Expected: edit_workflow, preference_interaction_workflow, preference_workflow <> Found: (Default)'
self.assertIn(message, detail_list)
self.assertTrue(detail_list.count(message), 1)
def stepSetConstraintInPersonModulePortalType(self, sequence=None):
types_tool = self.portal.portal_types
portal_type = types_tool['Person Module']
......@@ -254,14 +246,6 @@ class TestUpgrader(ERP5TypeTestCase):
portal_type.setTypePropertySheetList(
portal_type.getTypePropertySheetList() + ['TemplateToolPostUpgradeConstraint',])
def stepSetDefaultWorkflowChainToPreference(self, sequence=None):
workflow_chain_per_type_dict = {}
for portal_type, workflow_chain_list in self.portal.ERP5Site_dumpWorkflowChainByPortalType().iteritems():
workflow_chain_per_type_dict['chain_%s' % portal_type] = ",".join(workflow_chain_list)
workflow_chain_per_type_dict['chain_Preference'] = '(Default)'
self.portal.portal_workflow.manage_changeWorkflows(default_chain="",
props=workflow_chain_per_type_dict)
def _stepSolveAlarm(self, alarm_id):
getattr(self.portal.portal_alarms, alarm_id).solve()
......@@ -520,34 +504,6 @@ class TestUpgrader(ERP5TypeTestCase):
self.assertTrue(message in detail_list, detail_list)
self.assertTrue(detail_list.count(message), 1)
def test_workflow_chain_constraint(self):
""" Check if Workflow chains is broken, it can be detected and fixed after
upgrade"""
sequence_list = SequenceList()
sequence_string = """
stepActiveSensePreUpgradeAlarm
stepTic
stepRunUpgrader
stepTic
stepCheckUpgradeNotRequired
stepTic
stepSetConstraintInTemplateToolPortalType
stepActiveSensePostUpgradeAlarm
stepTic
stepCheckPostUpgradeEmptyConstraintList
stepSetDefaultWorkflowChainToPreference
stepActiveSensePostUpgradeAlarm
stepTic
stepCheckPosUpgradeWorkflowChainConsistency
stepRunPostUpgrade
stepTic
stepActiveSensePostUpgradeAlarm
stepTic
stepCheckPostUpgradeEmptyConstraintList
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
def test_not_post_many_active_result_when_upgrade(self):
""" Check that is possible fix consistency before the upgrade"""
sequence_list = SequenceList()
......
extension.erp5.ERP5UpgraderUtils
\ No newline at end of file
Template Tool | TemplateToolBusinessTemplateInstallationConstraint
Template Tool | TemplateToolCategoryNameConstraint
Template Tool | TemplateToolTableConsistencyConstraint
Template Tool | TemplateToolWorkflowChainConsistencyConstraint
\ No newline at end of file
TemplateToolBusinessTemplateInstallationConstraint
TemplateToolCategoryNameConstraint
TemplateToolTableConsistencyConstraint
TemplateToolWorkflowChainConsistencyConstraint
\ No newline at end of file
erp5_full_text_mroonga_catalog
erp5_base
erp5_upgrader_test
\ No newline at end of file
erp5_upgrader_test
erp5_workflow
......@@ -86,8 +86,8 @@ class TestOOoChartMixin(ERP5TypeTestCase, ZopeTestCase.Functional):
preference = self.getPortal().portal_preferences.default_site_preference
preference.setPriority(1)
if preference.getPreferenceState() == 'disabled':
self.getWorkflowTool().doActionFor(ob=preference,
action='enable_action',
self.getWorkflowTool().doActionFor(preference,
'enable_action',
wf_id='preference_workflow')
self.validator = Validator()
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>View</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/ConfigurationState_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>View</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/ConfigurationTransition_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>launch_configuration</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>10.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Launch Configuration</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Workflow_launchConfiguration</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -71,7 +71,7 @@
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Workflow_viewStateList</string> </value>
<value> <string>string:${object_url}/ConfigurationWorkflow_viewStateList</string> </value>
</item>
</dictionary>
</pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>transition_view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>3.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Transitions</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/ConfigurationWorkflow_viewTransitionList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>4.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Variables</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/ConfigurationWorkflow_viewVariableList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>View</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/ConfigurationWorkflow_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<allowed_content_type_list>
<portal_type id="Transition">
<portal_type id="Configuration Transition">
<item>Transition Variable</item>
</portal_type>
<portal_type id="Workflow">
<item>State</item>
<item>Transition</item>
<item>Variable</item>
<portal_type id="Configuration Workflow">
<item>Configuration State</item>
<item>Configuration Transition</item>
<item>Embedded File</item>
<item>Workflow Variable</item>
<item>Worklist</item>
</portal_type>
<portal_type id="Workflow Module">
<item>Workflow</item>
<item>Configuration Workflow</item>
</portal_type>
</allowed_content_type_list>
\ No newline at end of file
<hidden_content_type_list>
<portal_type id="Configuration Workflow">
<item>Embedded File</item>
</portal_type>
</hidden_content_type_list>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>content_icon</string> </key>
<value> <string>document.gif</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A busniess configuration state.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Configuration State</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Base Type</string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>ConfigurationState</string> </value>
</item>
<item>
<key> <string>type_interface</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>acquire_local_roles</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>content_icon</string> </key>
<value> <string>document.gif</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A business configuration transition.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Configuration Transition</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Base Type</string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>ConfigurationTransition</string> </value>
</item>
<item>
<key> <string>type_interface</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>content_icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A business configuration workflow.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Configuration Workflow</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Base Type</string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>ConfigurationWorkflow</string> </value>
</item>
<item>
<key> <string>type_interface</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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