Commit 05cf036d authored by Tomáš Peterka's avatar Tomáš Peterka

[renderjs_ui] Add Mass Workflow transition Action

parent c8c23c98
<?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>category</string> </key>
<value> <string>object_jio_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Modify Workflow State of multiple Documents </string> </value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>mass_workflow</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>100.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Change State</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}/Folder_modifyDocumentListStatusDialog</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>python: object.getPortalType() in portal.getPortalModuleTypeList()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -255,12 +255,6 @@ if True:
if deferred_portal_skin:
# has to be either ODS or ODT because only those contain `form_list`
request.set('deferred_portal_skin', deferred_portal_skin)
# and to cleanup formulator's special key in request
# XXX unless we are in Folder_modifyWorkflowStatus which validates again !
if dialog_method != 'Folder_modifyWorkflowStatus':
for key in list(request.keys()):
if str(key).startswith('field') or str(key).startswith('subfield'):
request.form.pop(key, None)
# now get dialog_method after skin re-selection and dialog_method mingling
dialog_form = getattr(context, dialog_method)
......
......@@ -5,7 +5,7 @@ from Products.ERP5Type.Message import translateString
from Products.ERP5Type.Log import log, WARNING
portal = context.getPortalObject()
request = kw.get("REQUEST", None) or context.REQUEST
request = REQUEST or context.REQUEST
form = getattr(context, dialog_id)
......@@ -90,7 +90,6 @@ else:
message = request.get('portal_status_message')
if message is None:
message = translateString('Status changed.')
kw.clear() # useful ?
# Allow to redirect to another document
redirect_document_path = request.get('redirect_document_path', None)
......@@ -101,4 +100,4 @@ else:
redirect_document = context
return redirect_document.Base_redirect(form_id,
keep_items={'portal_status_message': message}, **kw)
keep_items={'portal_status_message': message})
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>form_id, dialog_id, **kw</string> </value>
<value> <string>form_id, dialog_id, REQUEST=None, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
portal_actions | clone_document
portal_actions | create_a_document
portal_actions | delete_document
portal_actions | delete_document_list
portal_actions | mass_workflow_jio
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<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_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testMassWorkflowTransition</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test RenderJS UI Module Action Change State</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><th rowspan="1" colspan="3">Test RenderJS UI Module Action Change State</th></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Clean Up -->
<tr><td>open</td>
<td>${base_url}/foo_module/ListBoxZuite_reset</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Reset Successfully.</td><td></td></tr>
<!-- Shortcut for full renderjs url -->
<tr><td>store</td>
<td>${base_url}/web_site_module/renderjs_runner</td>
<td>renderjs_url</td></tr>
<tr><th colspan="3">Create Foo objects with distinguishible titles (Title 1%, Title 2%)</th></tr>
<tr><td>open</td>
<td>${base_url}/foo_module/FooModule_createObjects?start:int=10&amp;num:int=2</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Created Successfully.</td><td></td></tr>
<tr><td>open</td>
<td>${base_url}/foo_module/FooModule_createObjects?start:int=20&amp;num:int=2</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Created Successfully.</td><td></td></tr>
<tr><td>open</td>
<td>${base_url}/foo_module/FooModule_createObjects?start:int=30&amp;num:int=2</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Created Successfully.</td><td></td></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/wait_for_activities" />
<tr><td>open</td>
<td>${base_url}/FooModule_viewFooList/listbox/ListBox_setPropertyList?field_columns=id%7CID%0Atitle%7CTitle%0Asimulation_state%7CState&field_lines=3</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Set Successfully.</td><td></td></tr>
<tr><td>open</td>
<td>${renderjs_url}/#/foo_module</td><td></td></tr>
<tr><td>waitForElementPresent</td>
<td>//div[@data-role="header"]//a[@data-i18n="Actions"]</td><td></td></tr>
<tr><td>click</td>
<td>//div[@data-role="header"]//a[@data-i18n="Actions"]</td><td></td></tr>
<tr><td>waitForElementPresent</td>
<td>//ul[@data-role="listview"]//a[@data-i18n="Change State"]</td><td></td></tr>
<tr><td>click</td>
<td>//ul[@data-role="listview"]//a[@data-i18n="Change State"]</td><td></td></tr>
<tal:block tal:define="pagination_configuration python: {'header': '(1 - 3 / 6)', 'footer': 'Records 1 - 3 / 6'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_listbox_pagination_text" />
</tal:block>
<tr><th colspan="3">Check that sort and pagination work</th></tr>
<tr><td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/thead/tr/th//a[@data-i18n="ID"]</td><td></td></tr>
<tr><td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/thead/tr/th//a[@data-i18n="ID"]</td><td></td></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="pagination_configuration python: {'header': '(1 - 3 / 6)', 'footer': 'Records 1 - 3 / 6'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_listbox_pagination_text" />
</tal:block>
<tr><td>waitForText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[1]/td[1]//p</td>
<td>31</td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[1]/td[1]//p</td>
<td>31</td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[1]/td[3]//a</td>
<td>draft</td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[2]/td[1]//p</td>
<td>30</td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[3]/td[1]//p</td>
<td>21</td></tr>
<tr><td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//nav/a[@data-i18n="Next"]</td><td></td></tr>
<tr><td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//nav/a[@data-i18n="Next"]</td><td></td></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="pagination_configuration python: {'header': '(4 - 6 / 6)', 'footer': 'Records 4 - 6 / 6'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_listbox_pagination_text" />
</tal:block>
<tr><td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[3]/</td><td></td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[1]/td[1]//p</td>
<td>20</td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[1]/td[3]//a</td>
<td>draft</td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[2]/td[1]//p</td>
<td>11</td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[3]/td[1]//p</td>
<td>10</td></tr>
<tr><th colspan="3">Search <em>( title: "Title 1%" OR title: "Title 3%" )</em> so we work on subset</th></tr>
<tr><td>click</td>
<td>//div[@data-role="header"]//h1//a</td><td></td></tr>
<tal:block tal:define='search_query string:( title: "Title 1%" OR title: "Title 3%" )'>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/search_in_form_list" />
</tal:block>
<tr><td>waitForElementPresent</td>
<td>//div[@data-role="header"]//a[@data-i18n="Actions"]</td><td></td></tr>
<tr><td>click</td>
<td>//div[@data-role="header"]//a[@data-i18n="Actions"]</td><td></td></tr>
<tr><td>waitForElementPresent</td>
<td>//ul[@data-role="listview"]//a[@data-i18n="Change State"]</td><td></td></tr>
<tr><td>click</td>
<td>//ul[@data-role="listview"]//a[@data-i18n="Change State"]</td><td></td></tr>
<tal:block tal:define="pagination_configuration python: {'header': '(1 - 3 / 4)', 'footer': 'Records 1 - 3 / 4'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_listbox_pagination_text" />
</tal:block>
<tr><td>waitForElementPresent</td>
<td>//select[@name="field_workflow_action"]</td><td></td></tr>
<tr><td>select</td>
<td>//select[@name="field_workflow_action"]</td>
<td>value=validate_action</td></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'error', 'text': 'Form updated.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tr><td>waitForElementPresent</td>
<td>//textarea[@name="field_workflow_dialog_your_comment"]</td><td></td></tr>
<tr><td>type</td>
<td>//textarea[@name="field_workflow_dialog_your_comment"]</td>
<td>Crème brulée</td></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success', 'text': 'Workflow modification in progress.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/clear_query" />
<tr><td>open</td>
<td>${base_url}/Zuite_waitForActivities</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Done.</td><td></td></tr>
<tr><td>open</td>
<td>${renderjs_url}/#/foo_module</td><td></td></tr>
<tr><th colspan="3">Check statuses </th></tr>
<tr><td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/thead/tr/th//a[@data-i18n="ID"]</td><td></td></tr>
<tr><td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/thead/tr/th//a[@data-i18n="ID"]</td><td></td></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="pagination_configuration python: {'header': '(1 - 3 / 6)', 'footer': 'Records 1 - 3 / 6'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_listbox_pagination_text" />
</tal:block>
<tr><td>waitForText</td>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[1]/td[3]//a</td>
<td>validated</td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[2]/td[3]//a</td>
<td>validated</td></tr>
<tr><td>assertText</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tbody/tr[3]/td[3]//a</td>
<td>draft</td></tr>
<!-- clear_query -->
</tbody></table>
</body>
</html>
\ No newline at end of file
"""Base_getFormIdForWorkflowAction returns form_id of a form (dialog) used by `workflow_action`
This is not an UI script - it should be used in TALES expressions or called internally.
Developer Notes:
Format of Action returned by getFilteredActions['workflow'] = [{
'available': True,
'visible': True,
'allowed': True,
'link_target': None,
'id': 'invalidate_action',
'category': 'workflow',
'name': 'Invalidate Action',
'title': 'Invalidate Action',
'url': 'https://softinst81338.host.vifib.net/erp5/web_site_module/renderjs_runner/foo_module/27/Base_viewWorkflowActionDialog?workflow_action=invalidate_action',
'transition': <TransitionDefinition at /erp5/portal_workflow/foo_workflow/id_form_dict/invalidate_action>,
'icon': ''}, ... ]
"""
action_tool = context.getPortalObject().portal_actions
id_form_dict = dict()
context.log("called with form_id {}, query {}, workflow_action {}".format(form_id, query, workflow_action))
for result in context.Base_searchUsingFormIdAndQuery(form_id, query):
for action in action_tool.listFilteredActionsFor(result.getObject()).get('workflow', []):
id_form_dict[action['id']] = action['url'].rsplit('/', 1)[1].split('?')[0]
if not workflow_action and len(id_form_dict) == 1:
# if we have only one possible workflow transition we suppose it is the default one
return id_form_dict.items()[0][1]
if workflow_action in id_form_dict:
# if the workflow_action is done and we found it then return related form dialog
return id_form_dict[workflow_action]
# if we have no idea what workflow form we should use - just use ~~the default one~~ nothing
return ""
<?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>form_id, query, workflow_action=\'\'</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getFormIdForWorkflowAction</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -15,6 +15,4 @@ if 1: # keep indentation
if getattr(message, 'msg', None) and same_type(message.msg, []):
message = '. '.join('%s' % x for x in message.msg)
if not batch :
context.REQUEST.RESPONSE.redirect(
"%s/view?portal_status_message=%s" %
(context.absolute_url(), message))
return context.Base_redirect(keep_items={'portal_status_message': str(message)})
"""Return a list of Documents specified by `uid` which provide `workflow_id` transition."""
portal_catalog = context.getPortalObject().portal_catalog
action_tool = context.getPortalObject().portal_actions
if not uid:
return []
document_list = [result.getObject() for result in portal_catalog.searchResults(uid=uid, sort_on=sort_on, limit=limit)]
if not workflow_action:
# if we have no filter (=workflow action) we return back all documents
return document_list
filtered_list = []
for document in document_list:
for action in action_tool.listFilteredActionsFor(document).get('workflow', []):
if action['id'] == workflow_action:
filtered_list.append(document)
break
return filtered_list
<?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>uid, workflow_action=\'\', sort_on=(), limit=None, **kwargs</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Folder_filterDocumentByWorkflow</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"""Return items (ready to be used in listbox of listfield) of common workflows on documents defined by `form_id` and `query`.
:param form_id: {str} Form.ID of a form containing listbox to execute the query
:param query: {str} fulltext query
:param add_empty: {bool} First choice is empty
Developer Notes:
Format of Action returned by getFilteredActions['workflow'] = [{
'available': True,
'visible': True,
'allowed': True,
'link_target': None,
'id': 'invalidate_action',
'category': 'workflow',
'name': 'Invalidate Action',
'title': 'Invalidate Action',
'url': 'https://softinst81338.host.vifib.net/erp5/web_site_module/renderjs_runner/foo_module/27/Base_viewWorkflowActionDialog?workflow_action=invalidate_action',
'transition': <TransitionDefinition at /erp5/portal_workflow/foo_workflow/transition_dict/invalidate_action>,
'icon': ''}, ... ]
"""
def formatDict(d, padding=0):
if not isinstance(d, dict):
return " " * padding + str(d)
return "\n".join(" " * padding + key + ":" + formatDict(d[key], padding+4) for key in d)
action_tool = context.getPortalObject().portal_actions
translate = context.getPortalObject().Base_translateString
workflow_list = []
if add_empty:
workflow_list.append((translate('Choose desired action.'), ''))
transition_dict = {}
for result in context.Base_searchUsingFormIdAndQuery(form_id, query):
for action in action_tool.listFilteredActionsFor(result.getObject()).get('workflow', []):
transition_dict[action['id']] = action['title']
if not transition_dict:
workflow_list.append((translate("No state change possible"), ""))
if len(transition_dict) == 1:
workflow_list = [] # if there is only one workflow possible - do not bother with an empty option
# transition_dict.items() is in form (id, title) but ERP5 requires (title, id) so we reverse
if transition_dict:
workflow_list.extend((title, id) for id, title in sorted(transition_dict.items(), key=lambda x: x[1]))
return workflow_list
<?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>_Cacheable__manager_id</string> </key>
<value>
<none/>
</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>form_id, query, add_empty=False</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Folder_listWorkflow</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"""Script to execute `workflow_action`on selected documents by `uids` with optional `comment`.
This script is intended as a dialog target.
:param form_id, dialog_id: mandatory parameters of dialog form target script
:param uids: {list[int]} marks that this script takes objects from previous listbox as its input
:param workflow_action: {str} the ID of (worflow) action to execute on each object
:param comment: {str} optional comment
"""
from Products.CMFCore.WorkflowCore import WorkflowException
portal = context.getPortalObject()
request = kwargs.get("REQUEST", None) or context.REQUEST
translate = portal.Base_translateString
# Ensure the selected action is doable on received objects
document_list = [result.getObject() for result in portal.portal_catalog.searchResults(uid=uids)]
workflowable_list = []
if not workflow_action:
return context.Base_redirect(form_id,
keep_items={
"portal_status_message": translate("No state change possible on selected documents."),
"portal_status_level": "error"})
# workflow_action_rendered is a control field to remember which workflow_action was rendered
# and we diallow submit if different action is selected and different dialog embedded
request.form['workflow_action_rendered'] = workflow_action
if is_updating or workflow_action_rendered != workflow_action:
return context.Base_renderForm(dialog_id,
message=translate("Form updated."),
level="warning",
REQUEST=request)
for document in document_list:
try:
# Kato: Why does it throw an axception instead of just returning False?
portal.portal_workflow.canDoActionFor(document, workflow_action)
except WorkflowException as exception:
pass
else:
workflowable_list.append(document)
# generate a random tag for activity grouping
tag = 'folder_workflow_action_{:d}'.format(random.randint(0, 1000)) # Kato: how come that random is accessible?
# We want change state activities to have a lower priority that erp5_deferred_style reports
# not to prevent everybody from running report while a users change state of many documents.
priority = 3
batch_size = 100
for i in xrange(0, len(workflowable_list), batch_size):
context.activate(activity='SQLQueue', priority=priority, tag=tag).callMethodOnObjectList(
[doc.getRelativeUrl() for doc in workflowable_list[i:i+batch_size]],
'Base_workflowStatusModify',
batch_mode=True, workflow_action=workflow_action, comment=comment)
# activate something on the module after everything, so that user can know that
# something is happening in the background
context.activate(after_tag=tag).getTitle()
return context.Base_redirect(form_id,
keep_items=dict(portal_status_message=translate("Workflow modification in progress.")))
<?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>form_id, dialog_id, uids, workflow_action, workflow_action_rendered, comment=\'\', is_updating=False, **kwargs</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Folder_modifyDocumentListStatus</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5 Form" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Folder_modifyDocumentListStatus</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Change Workflow state on multiple documents at once</string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list>
<string>listbox</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list>
<string>workflow_action</string>
<string>workflow_dialog</string>
<string>workflow_dialog_my_workflow_action</string>
<string>workflow_dialog_your_workflow_action</string>
<string>workflow_action_rendered</string>
</list>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Folder_modifyDocumentListStatusDialog</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Folder_modifyDocumentListStatusDialog</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_dialog</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Change State of Multiple Documents</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string>Folder_modifyDocumentListStatus</string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?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>list_method</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>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>form_id</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>listbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>FooModule_viewFooList</string> </value>
</item>
<item>
<key> <string>list_method</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</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: here.Form_getListbox(form_id=request.get(\'form_id\')).getId()</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>request/form_id</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="Method" module="Products.Formulator.MethodField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>method_name</string> </key>
<value> <string>Folder_filterDocumentByWorkflow</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="FormBox" module="Products.ERP5Form.FormBox"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>workflow_dialog</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>
<item>
<key> <string>form_invalidated</string> </key>
<value> <string>Form invalidated.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>context_method_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>formbox_target_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>context_method_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>formbox_target_id</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>hidden</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>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>context_method_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string>invisible</string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>formbox_target_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>workflow_dialog</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: here.Base_getFormIdForWorkflowAction(request.get("form_id"), request.get("query"), request.get("workflow_action", ""))</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -4,7 +4,7 @@ from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.ERP5Type.Message import translateString
from Products.ERP5Type.Log import log
portal = context.getPortalObject()
request = kw.get("REQUEST", None) or context.REQUEST
request = REQUEST or context.REQUEST
form = getattr(context, dialog_id)
......@@ -84,14 +84,13 @@ except ValidationFailed, error_message:
except WorkflowException as error_message:
if str(error_message) == "No workflow provides the '${action_id}' action.":
message = translateString("Workflow state may have been updated by other user. Please try again.")
return context.Base_redirect(form_id, keep_items={'portal_status_message': message}, **kw)
return context.Base_redirect(form_id, keep_items={'portal_status_message': message})
else:
raise
else:
message = request.get('portal_status_message')
if message is None:
message = translateString('Status changed.')
kw.clear() # useful ?
# Allow to redirect to another document
redirect_document_path = request.get('redirect_document_path', None)
......@@ -102,4 +101,4 @@ else:
redirect_document = context
return redirect_document.Base_redirect(form_id,
keep_items={'portal_status_message': message}, **kw)
keep_items={'portal_status_message': message})
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>form_id, dialog_id, **kw</string> </value>
<value> <string>form_id, dialog_id, REQUEST=None, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
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