Commit 663025de authored by Arnaud Fontaine's avatar Arnaud Fontaine

WIP: ERP5Workflow: DC Workflows are now ERP5 object and migrated to ERP5Workflow.

Work done by Wenjie Zheng, Isabelle Vallet and Sebastien Robin.
parent 226a4204
......@@ -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)
......@@ -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)
......@@ -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>
<?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
......@@ -42,4 +43,3 @@ Person Configurator Item | Career
Person Configurator Item | Email
Person Configurator Item | Telephone
Portal Type Roles Spreadsheet Configurator Item | Embedded File
\ No newline at end of file
Workflow | 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
......@@ -8,4 +9,3 @@ Person Configurator Item | Address
Person Configurator Item | Career
Person Configurator Item | Email
Person Configurator Item | Telephone
\ No newline at end of file
Workflow | Embedded File
\ 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
<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):
"""
......@@ -189,7 +190,7 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
def stepSetSameTitleValueWithEdit(self, sequence=None, sequence_list=None,
**kw):
"""
Set a different title value
Set the same title value
"""
object_instance = sequence.get('object_instance')
object_instance.edit(title=object_instance.getTitle())
......@@ -907,8 +908,8 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
'workflow_history', property_value)
def test_12_editTempObject(self, quiet=quiet, run=run_all_test):
"""Simple t
est to edit a temp object.
"""
Simple test to edit a temp object.
"""
portal = self.getPortal()
tmp_object = portal.newContent(temp_object=True, portal_type='Organisation',
......@@ -933,14 +934,11 @@ class TestBase(ERP5TypeTestCase, ZopeTestCase.Functional):
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 + [non_existent_worlflow_id])
pw.manage_delObjects([non_existent_worlflow_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):
......
......@@ -129,11 +129,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()
......@@ -144,13 +145,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.acquire_local_roles = 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()
......@@ -987,24 +988,24 @@ 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'))
......@@ -1014,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'))
......@@ -1026,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,9 @@ 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')
portal = self.getPortalObject()
type_object = 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 +111,9 @@ 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')
portal = self.getPortalObject()
type_object = 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 +681,9 @@ context.setTitle('Bar')
def test_portal_type_filter(self):
self.createInteractionWorkflow()
self.getWorkflowTool().setChainForPortalTypes(
['Bank Account'],'test_workflow, validation_workflow')
portal = self.getPortalObject()
type_object = portal.portal_types.getTypeInfo('Bank Account')
type_object.setTypeWorkflowList(['test_workflow', 'validation_workflow'])
self.interaction.setProperties(
'default',
# only for bank accounts
......@@ -704,8 +707,9 @@ context.setTitle('Bar')
def test_portal_type_group_filter(self):
self.createInteractionWorkflow()
self.getWorkflowTool().setChainForPortalTypes(
['Bank Account'],'test_workflow, validation_workflow')
portal = self.getPortalObject()
type_object = 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)
......
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
class testWorkflowMixin(ERP5TypeTestCase):
def countFromActionName(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,
selection_name=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.countFromActionName(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
publish_response = self.publish(url, 'manager:') # XXX: troubles running live test, returns HTTP error 500
self.assertEqual(publish_response.status, 200)
self.commit()
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
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Test Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testWorkflowMixin</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testWorkflowMixin</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Test Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<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>
......@@ -152,20 +152,94 @@ class TestWorklist(ERP5TypeTestCase):
self._addPropertySheet(self.checked_portal_type, 'SortIndex')
def addWorkflowCataloguedVariable(self, workflow_id, variable_id):
variables = self.getWorkflowTool()[workflow_id].variables
# 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)
assert variables[variable_id].for_catalog == 1
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
# 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.setActboxName(str(actbox_name))
worklist_value.setActboxUrl(str(actbox_url))
worklist_value.setActboxCategory(str('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('state_'+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.setInitialValue(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.setDefaultExpr(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.setInitialValue(v)
# Update guard configuration for view and guard value.
if 'guard_roles' in props:
v = props.get('guard_roles', '')
if v:
worklist_value.setRoleList([ var.strip() for var in v.split(';') ])
if 'guard_expr' in props:
v = props.get('guard_expr', '')
if v:
worklist_value.setExpression(v)
worklist_value.getGuard()
else:
worklists = workflow_value.worklists
worklists.addWorklist(worklist_id)
worklists._getOb(worklist_id).setProperties('',
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):
# 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)
......
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
......
......@@ -22,10 +22,6 @@
<key> <string>actbox_url</string> </key>
<value> <string>%(content_url)s/Event_viewCreateTicketWorkflowActionDialog?workflow_action=create_ticket_action</string> </value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>create_ticket</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Disabled action.</string> </value>
......
......@@ -2470,7 +2470,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:
......
......@@ -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.trigger_type == 1 and transaction.actbox_name: # 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.trigger_type == 1 and transition.actbox_name: # 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.id
wf_item_title = wf_item.title
elif type == 'state':
wf_item_path = '%s/states/%s' % (wf_item.aq_parent.aq_parent.id, wf_item.id)
wf_item_title = wf_item.title
elif type == 'transition':
wf_item_path = '%s/transitions/%s' % (wf_item.aq_parent.aq_parent.id, wf_item.id)
wf_item_title = wf_item.title
else: # type == 'action'
wf_item_path = '%s/transitions/%s_actbox_name' % (wf_item.aq_parent.aq_parent.id, wf_item.id)
wf_item_title = wf_item.actbox_name
wf_item_description = wf_item.description
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,20 +107,21 @@ 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.title:
# adding a context in msg_id for more precise translation
msg_id = getMessageIdWithContext(s_title,'state',i.id)
msg_id = getMessageIdWithContext(s.title,'state',i.id)
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.title, 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():
for t in transition_value_list:
if t.actbox_name:
#adding a context in msg_id for more precise translation
msg_id = getMessageIdWithContext(t.actbox_name,'transition',i.id)
......@@ -133,7 +134,7 @@ for i in context.portal_workflow.objectValues():
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():
for worklist in i.getWorklistValueList():
add_message(worklist.actbox_name, 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;
......
......@@ -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)
]);
});
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>seedrandom.js</string> </value>
</item>
<item>
<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>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -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
Workflow | reset_graph
Workflow | view_graph
\ No newline at end of file
......@@ -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)
......
......@@ -45,6 +45,7 @@ class SolverMixin(object):
# Declarative interfaces
zope.interface.implements(ISolver,)
workflow_list = ()
def _solve(self, activate_kw=None):
raise NotImplementedError
......
......@@ -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()
......
......@@ -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)
......
......@@ -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
import re
template_tool = context
portal = context.getPortalObject()
bt5_per_title_dict = {}
bt5_list = [i.getTitle() for i in \
......@@ -39,19 +40,15 @@ for _, bt5_id in resolved_list:
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, []))
portal_type_document = portal.portal_types.getTypeInfo(portal_type)
workflow_chain_list = portal_type_document.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()
......
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
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>
......@@ -104,7 +104,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>State_view</string> </value>
<value> <string>ConfigurationState_view</string> </value>
</item>
<item>
<key> <string>method</string> </key>
......
......@@ -9,7 +9,9 @@
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
......@@ -81,7 +83,11 @@
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>BaseWorkflow_FieldLibrary</string> </value>
<value> <string>Workflow_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Comment</string> </value>
</item>
</dictionary>
</value>
......
......@@ -81,7 +81,7 @@
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>BaseWorkflow_FieldLibrary</string> </value>
<value> <string>Workflow_viewFieldLibrary</string> </value>
</item>
</dictionary>
</value>
......
......@@ -95,8 +95,8 @@
<value>
<list>
<tuple>
<string>Transition</string>
<string>Transition</string>
<string>Configuration Transition</string>
<string>Configuration Transition</string>
</tuple>
</list>
</value>
......
......@@ -81,7 +81,7 @@
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>BaseWorkflow_FieldLibrary</string> </value>
<value> <string>Workflow_viewFieldLibrary</string> </value>
</item>
</dictionary>
</value>
......
......@@ -99,8 +99,8 @@
<value>
<list>
<string>my_transition_form_id</string>
<string>my_before_script_id</string>
<string>my_after_script_id</string>
<string>my_before_script_list</string>
<string>my_after_script_list</string>
</list>
</value>
</item>
......@@ -109,7 +109,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Transition_view</string> </value>
<value> <string>ConfigurationTransition_view</string> </value>
</item>
<item>
<key> <string>method</string> </key>
......@@ -117,7 +117,7 @@
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Transition_view</string> </value>
<value> <string>ConfigurationTransition_view</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
......
<?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>columns</string>
<string>portal_types</string>
<string>selection_name</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox</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>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>id</string>
<string>ID</string>
</tuple>
<tuple>
<string>causality_title</string>
<string>Causality</string>
</tuple>
<tuple>
<string>Variable_getNonEvaluatedVariableValue</string>
<string>Value</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>portal_types</string> </key>
<value>
<list>
<tuple>
<string>Transition Variable</string>
<string>Transition Variable</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>selection_name</string> </key>
<value> <string>configuration_transition_variable_selection</string> </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>Transition Variables</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -90,8 +90,8 @@
<value>
<list>
<tuple>
<string>State</string>
<string>State</string>
<string>Configuration State</string>
<string>Configuration State</string>
</tuple>
</list>
</value>
......
......@@ -81,7 +81,7 @@
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>BaseWorkflow_FieldLibrary</string> </value>
<value> <string>Workflow_viewFieldLibrary</string> </value>
</item>
</dictionary>
</value>
......
......@@ -85,6 +85,7 @@
<key> <string>left</string> </key>
<value>
<list>
<string>my_id</string>
<string>my_title</string>
</list>
</value>
......@@ -102,7 +103,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Workflow_view</string> </value>
<value> <string>ConfigurationWorkflow_view</string> </value>
</item>
<item>
<key> <string>method</string> </key>
......
......@@ -9,7 +9,9 @@
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
......@@ -81,7 +83,11 @@
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>BaseWorkflow_FieldLibrary</string> </value>
<value> <string>Workflow_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Comment</string> </value>
</item>
</dictionary>
</value>
......
......@@ -81,7 +81,7 @@
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>BaseWorkflow_FieldLibrary</string> </value>
<value> <string>Workflow_viewFieldLibrary</string> </value>
</item>
</dictionary>
</value>
......
......@@ -81,7 +81,7 @@
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>BaseWorkflow_FieldLibrary</string> </value>
<value> <string>Workflow_viewFieldLibrary</string> </value>
</item>
</dictionary>
</value>
......
......@@ -105,7 +105,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Workflow_viewStateList</string> </value>
<value> <string>ConfigurationWorkflow_viewStateList</string> </value>
</item>
<item>
<key> <string>method</string> </key>
......@@ -113,7 +113,7 @@
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Workflow_viewStateList</string> </value>
<value> <string>ConfigurationWorkflow_viewStateList</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
......
......@@ -139,15 +139,15 @@
<value>
<list>
<tuple>
<string>State</string>
<string>State</string>
<string>Configuration State</string>
<string>Configuration State</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>selection_name</string> </key>
<value> <string>workflow_state_selection</string> </value>
<value> <string>configuration_state_selection</string> </value>
</item>
<item>
<key> <string>sort</string> </key>
......
<?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>base_category</string>
<string>catalog_index</string>
<string>parameter_list</string>
<string>portal_type</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_source_title</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>parameter_list</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>base_category</string> </key>
<value> <string>source</string> </value>
</item>
<item>
<key> <string>catalog_index</string> </key>
<value> <string>title</string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_relation_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>parameter_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value>
<list>
<tuple>
<string>Configuration State</string>
<string>Configuration State</string>
</tuple>
</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>Initial State</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: [(\'parent_uid\', here.getUid())]</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -87,7 +87,7 @@
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>BaseWorkflow_FieldLibrary</string> </value>
<value> <string>Workflow_viewFieldLibrary</string> </value>
</item>
</dictionary>
</value>
......
......@@ -111,7 +111,7 @@
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Workflow_viewTransitionList</string> </value>
<value> <string>ConfigurationWorkflow_viewTransitionList</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
......
......@@ -97,6 +97,14 @@
<string>destination_title</string>
<string>Destination State</string>
</tuple>
<tuple>
<string>before_script_id</string>
<string>Before Script</string>
</tuple>
<tuple>
<string>after_script_id</string>
<string>After Script</string>
</tuple>
</list>
</value>
</item>
......@@ -128,15 +136,15 @@
<value>
<list>
<tuple>
<string>Transition</string>
<string>Transition</string>
<string>Configuration Transition</string>
<string>Configuration Transition</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>selection_name</string> </key>
<value> <string>workflow_transition_selection</string> </value>
<value> <string>configuration_transition_selection</string> </value>
</item>
<item>
<key> <string>sort</string> </key>
......
......@@ -64,15 +64,15 @@
<item>
<key> <string>bottom</string> </key>
<value>
<list/>
<list>
<string>listbox</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list>
<string>my_comment</string>
</list>
<list/>
</value>
</item>
<item>
......@@ -86,7 +86,7 @@
<value>
<list>
<string>my_title</string>
<string>my_description</string>
<string>my_state_base_category</string>
</list>
</value>
</item>
......@@ -101,7 +101,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Worklist_view</string> </value>
<value> <string>ConfigurationWorkflow_viewVariableList</string> </value>
</item>
<item>
<key> <string>method</string> </key>
......@@ -109,7 +109,7 @@
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Worklist_view</string> </value>
<value> <string>Workflow_viewVariableList</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
......@@ -125,7 +125,7 @@
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Worklist</string> </value>
<value> <string>Variables</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
......
<?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>columns</string>
<string>default_params</string>
<string>editable_columns</string>
<string>portal_types</string>
<string>selection_name</string>
<string>sort</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox</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>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>reference</string>
<string>Reference</string>
</tuple>
<tuple>
<string>title</string>
<string>Title</string>
</tuple>
<tuple>
<string>Variable_getNonEvaluatedVariableValue</string>
<string>Initial Value</string>
</tuple>
<tuple>
<string>automatic_update</string>
<string>Update on every Transition</string>
</tuple>
<tuple>
<string>for_catalog</string>
<string>Available for Catalog</string>
</tuple>
<tuple>
<string>variable_expression</string>
<string>Expression</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>default_params</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>editable_columns</string> </key>
<value>
<list>
<tuple>
<string>title</string>
<string>Title</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>portal_types</string> </key>
<value>
<list>
<tuple>
<string>Workflow Variable</string>
<string>Workflow Variable</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>selection_name</string> </key>
<value> <string>configuration_workflow_variable_selection</string> </value>
</item>
<item>
<key> <string>sort</string> </key>
<value>
<list>
<tuple>
<string>reference</string>
<string>Reference</string>
</tuple>
</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>Variables</string> </value>
</item>
</dictionary>
</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.
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