Commit e19743d7 authored by Jérome Perrin's avatar Jérome Perrin

Update ticket modification date when a new event is posted

Some tickets (for example Support Request or Bugs) are focus on one small thing being discussed where usually a small number of events are posted.

Unlike for example  a campaign where there is a large number of events sent to a large number of recipients, in the case of these "small, self contained" tickets, it makes a lot of sense to see that the ticket was modified when a new event is posted on this ticket.

This is what we sometimes customize in some support request fast input. It was the case in Support Request App, but this was removed in 74fc68a7 , this time it's done at a lower level and such customisations are no longer needed.

/reviewed-on !807
parents 26d8e3b3 2583ffda
"""Add a note to increase modification date of support request.
This script has proxy roles, so that even users who cannot modify
the support request can still increase the modification date this way.
"""
from Products.ERP5Type.Message import translateString
context.getPortalObject().portal_workflow.doActionFor(
context,
'edit_action',
comment=translateString(
"New event ${event_reference}",
mapping={
'event_reference': event.getReference()}))
<?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>event</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SupportRequest_afterNewEvent</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>activate_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>before_commit_script_name</string> </key>
<value>
<list>
<string>updateTicket</string>
</list>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Update ticket when a new event is posted</string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>updateTicket</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>start</string>
<string>stop</string>
<string>deliver</string>
</list>
</value>
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type_group_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"""Update modification date of the ticket when posting a new event, on tickets where this makes sense.
Typically, we do this on "small tickets focusing on one thing", such as support requests or bugs, but
not, for example, on campaigns.
"""
event = sci['object']
ticket = event.getFollowUpValue()
if ticket is not None:
afterNewEvent = ticket.getTypeBasedMethod('afterNewEvent')
if afterNewEvent:
afterNewEvent(event)
<?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>sci</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>updateTicket</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
</chain> </chain>
<chain> <chain>
<type>Bug Line</type> <type>Bug Line</type>
<workflow>bug_event_workflow, edit_workflow</workflow> <workflow>bug_event_workflow, edit_workflow, event_interaction_workflow</workflow>
</chain> </chain>
<chain> <chain>
<type>Glossary Term</type> <type>Glossary Term</type>
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
portal = context.getPortalObject() portal = context.getPortalObject()
edit_kw = {'content_type': portal.portal_preferences.getPreferredTextFormat(), edit_kw = {'content_type': portal.portal_preferences.getPreferredTextFormat(),
'start_date': DateTime(), 'start_date': DateTime(),
'destination_value_list': context.BugLine_getRecipientValueList()} 'destination_value_list': context.BugLine_getRecipientValueList(),
'follow_up_value': context.getParentValue()}
# Define a Reporter as Source Trade # Define a Reporter as Source Trade
person = context.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue() person = context.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue()
......
"""Add a note to increase modification date of bug.
This script has proxy roles, so that even users who cannot modify
the bug can still increase the modification date this way.
"""
from Products.ERP5Type.Message import translateString
context.getPortalObject().portal_workflow.doActionFor(
context,
'edit_action',
comment=translateString("New comment"))
<?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>event</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Bug_afterNewEvent</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
erp5_view_style erp5_view_style
erp5_base erp5_base
\ No newline at end of file erp5_crm
\ No newline at end of file
Bug Line | bug_event_workflow Bug Line | bug_event_workflow
Bug Line | edit_workflow Bug Line | edit_workflow
Bug Line | event_interaction_workflow
Bug | bug_workflow Bug | bug_workflow
Bug | edit_workflow Bug | edit_workflow
Glossary Term | edit_workflow Glossary Term | edit_workflow
......
...@@ -62,8 +62,8 @@ class TestBug(ERP5TypeTestCase): ...@@ -62,8 +62,8 @@ class TestBug(ERP5TypeTestCase):
Return the list of required business templates. Return the list of required business templates.
""" """
return ( 'erp5_base' return ( 'erp5_base'
, 'erp5_crm'
, 'erp5_forge' , 'erp5_forge'
, 'erp5_base'
, 'erp5_pdm' , 'erp5_pdm'
, 'erp5_trade' , 'erp5_trade'
, 'erp5_project' , 'erp5_project'
...@@ -604,6 +604,17 @@ class TestBug(ERP5TypeTestCase): ...@@ -604,6 +604,17 @@ class TestBug(ERP5TypeTestCase):
self.workflow_tool.doActionFor(bug, 'stop_action', send_event=1) self.workflow_tool.doActionFor(bug, 'stop_action', send_event=1)
self.assertEqual(bug.getSimulationState(), 'stopped') self.assertEqual(bug.getSimulationState(), 'stopped')
def test_posting_bug_line_updates_bug_modification_date(self):
bug = self.portal.bug_module.newContent(portal_type='Bug')
bug_modification_date = bug.getModificationDate()
bug_line = bug.newContent(portal_type='Bug Line')
self.assertEqual(bug.getModificationDate(), bug_modification_date)
bug_line.start()
self.commit()
self.assertGreater(bug.getModificationDate(), bug_modification_date)
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestBug)) suite.addTest(unittest.makeSuite(TestBug))
......
...@@ -431,6 +431,20 @@ class TestCRM(BaseTestCRM): ...@@ -431,6 +431,20 @@ class TestCRM(BaseTestCRM):
self.assertNotEquals(support_request.getReference(), self.assertNotEquals(support_request.getReference(),
new_support_request.getReference()) new_support_request.getReference())
def test_posting_event_updates_support_request_modification_date(self):
"""Posting an event following up a support request updates the support request date.
"""
sr = self.portal.support_request_module.newContent(portal_type='Support Request')
sr_modification_date = sr.getModificationDate()
event = self.portal.event_module.newContent(
portal_type='Web Message',
follow_up_value=sr
)
self.assertEqual(sr.getModificationDate(), sr_modification_date)
event.start()
self.commit()
self.assertGreater(sr.getModificationDate(), sr_modification_date)
def test_Event_getResourceItemList(self): def test_Event_getResourceItemList(self):
"""Event_getResourceItemList returns """Event_getResourceItemList returns
......
...@@ -45,6 +45,7 @@ class TestFieldLibraryGuideline(ERP5TypeTestCase): ...@@ -45,6 +45,7 @@ class TestFieldLibraryGuideline(ERP5TypeTestCase):
""" """ """ """
return ( return (
'erp5_base', 'erp5_base',
'erp5_crm',
'erp5_forge', 'erp5_forge',
) )
......
...@@ -179,25 +179,26 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -179,25 +179,26 @@ class TestTemplateTool(ERP5TypeTestCase):
self.assertEqual(not_installed_bt5.getRevision(), new_bt.getRevision()) self.assertEqual(not_installed_bt5.getRevision(), new_bt.getRevision())
def test_updateBusinessTemplateFromUrl_keep_list(self): def test_updateBusinessTemplateFromUrl_keep_list(self):
"""
Test updateBusinessTemplateFromUrl method
"""
self._svn_setup_ssl() self._svn_setup_ssl()
template_tool = self.portal.portal_templates template_tool = self.portal.portal_templates
url = 'https://svn.erp5.org/repos/public/erp5/trunk/bt5/test_core' url = 'https://svn.erp5.org/repos/public/erp5/trunk/bt5/test_core'
# make sure this `test_core` bt is not installed
template_tool.updateBusinessTemplateFromUrl(url)
bt = template_tool.getInstalledBusinessTemplate('test_core')
bt.uninstall()
self.tic()
# don't install test_file # don't install test_file
keep_original_list = ('portal_skins/erp5_test/test_file', ) keep_original_list = ('portal_skins/erp5_test/test_file', )
template_tool.updateBusinessTemplateFromUrl(url, template_tool.updateBusinessTemplateFromUrl(url,
keep_original_list=keep_original_list) keep_original_list=keep_original_list)
bt = template_tool.getInstalledBusinessTemplate('test_core') bt = template_tool.getInstalledBusinessTemplate('test_core')
self.assertNotEquals(None, bt) self.assertNotEqual(None, bt)
erp5_test = self.portal.portal_skins['erp5_test'] erp5_test = self.portal.portal_skins['erp5_test']
self.assertFalse(erp5_test.hasObject('test_file')) self.assertFalse(erp5_test.hasObject('test_file'))
def test_updateBusinessTemplateFromUrl_after_before_script(self): def test_updateBusinessTemplateFromUrl_after_before_script(self):
"""
Test updateBusinessTemplateFromUrl method
"""
from Products.ERP5Type.tests.utils import createZODBPythonScript from Products.ERP5Type.tests.utils import createZODBPythonScript
portal = self.getPortal() portal = self.getPortal()
self._svn_setup_ssl() self._svn_setup_ssl()
...@@ -686,7 +687,14 @@ class TestTemplateTool(ERP5TypeTestCase): ...@@ -686,7 +687,14 @@ class TestTemplateTool(ERP5TypeTestCase):
template_tool = self.portal.portal_templates template_tool = self.portal.portal_templates
before = {bt.getTitle(): bt.getId() before = {bt.getTitle(): bt.getId()
for bt in template_tool.getInstalledBusinessTemplateList()} for bt in template_tool.getInstalledBusinessTemplateList()}
bt_title = 'erp5_forge'
bt_title = 'test_core'
# This test will install `bt_title` from repository and check that nothing
# else was installed.
# Test assume that `bt_title` is not installed at this point and that it
# does not depend on anything that's not already installed.
self.assertNotIn(bt_title, before)
template_tool.installBusinessTemplateListFromRepository([bt_title], template_tool.installBusinessTemplateListFromRepository([bt_title],
install_dependency=True) install_dependency=True)
self.tic() self.tic()
......
...@@ -42,7 +42,7 @@ class TestAnonymousSelection(TestZeleniumCore): ...@@ -42,7 +42,7 @@ class TestAnonymousSelection(TestZeleniumCore):
Return the list of business templates. Return the list of business templates.
""" """
return ('erp5_core_proxy_field_legacy', 'erp5_full_text_mroonga_catalog', return ('erp5_core_proxy_field_legacy', 'erp5_full_text_mroonga_catalog',
'erp5_base', 'erp5_ui_test_core', 'erp5_ui_test', 'erp5_forge', 'erp5_base', 'erp5_ui_test_core', 'erp5_ui_test', 'erp5_crm', 'erp5_forge',
'erp5_l10n_fa', 'erp5_l10n_fa',
) )
......
...@@ -40,7 +40,7 @@ class TestZeleniumCore(ERP5TypeFunctionalTestCase): ...@@ -40,7 +40,7 @@ class TestZeleniumCore(ERP5TypeFunctionalTestCase):
Return the list of business templates. Return the list of business templates.
""" """
return ('erp5_core_proxy_field_legacy', 'erp5_full_text_mroonga_catalog', return ('erp5_core_proxy_field_legacy', 'erp5_full_text_mroonga_catalog',
'erp5_base', 'erp5_ui_test_core', 'erp5_ui_test', 'erp5_forge', 'erp5_base', 'erp5_ui_test_core', 'erp5_ui_test',
'erp5_dhtml_style', 'erp5_dhtml_ui_test', 'erp5_dhtml_style', 'erp5_dhtml_ui_test',
'erp5_jquery', 'erp5_jquery_ui', 'erp5_jquery', 'erp5_jquery_ui',
'erp5_knowledge_pad', 'erp5_knowledge_pad',
...@@ -62,7 +62,9 @@ class TestZeleniumCore(ERP5TypeFunctionalTestCase): ...@@ -62,7 +62,9 @@ class TestZeleniumCore(ERP5TypeFunctionalTestCase):
'erp5_ingestion_mysql_innodb_catalog', 'erp5_ingestion', 'erp5_ingestion_mysql_innodb_catalog', 'erp5_ingestion',
'erp5_web', 'erp5_dms', 'erp5_dms_ui_test', 'erp5_web', 'erp5_dms', 'erp5_dms_ui_test',
'erp5_knowledge_pad_ui_test', 'erp5_knowledge_pad_ui_test',
'erp5_crm', 'erp5_credential', 'erp5_crm',
'erp5_forge',
'erp5_credential',
'erp5_rss_style', 'erp5_discussion', 'erp5_rss_style', 'erp5_discussion',
'erp5_l10n_fr', 'erp5_l10n_fr',
'erp5_l10n_fa', 'erp5_l10n_fa',
......
...@@ -44,7 +44,7 @@ class TestZeleniumKM(ERP5TypeFunctionalTestCase): ...@@ -44,7 +44,7 @@ class TestZeleniumKM(ERP5TypeFunctionalTestCase):
# XXX This is a rough list, we should drop as much as we can, and # XXX This is a rough list, we should drop as much as we can, and
# keep only minimal # keep only minimal
return ('erp5_core_proxy_field_legacy', 'erp5_full_text_mroonga_catalog', return ('erp5_core_proxy_field_legacy', 'erp5_full_text_mroonga_catalog',
'erp5_base', 'erp5_ui_test_core', 'erp5_ui_test', 'erp5_forge', 'erp5_base', 'erp5_ui_test_core', 'erp5_ui_test',
'erp5_dhtml_style', 'erp5_dhtml_ui_test', 'erp5_dhtml_style', 'erp5_dhtml_ui_test',
'erp5_jquery', 'erp5_jquery_ui', 'erp5_jquery', 'erp5_jquery_ui',
'erp5_knowledge_pad', 'erp5_pdm', 'erp5_knowledge_pad', 'erp5_pdm',
...@@ -57,7 +57,9 @@ class TestZeleniumKM(ERP5TypeFunctionalTestCase): ...@@ -57,7 +57,9 @@ class TestZeleniumKM(ERP5TypeFunctionalTestCase):
'erp5_knowledge_pad_ui_test', 'erp5_knowledge_pad_ui_test',
'erp5_credential', 'erp5_rss_style', 'erp5_discussion', 'erp5_credential', 'erp5_rss_style', 'erp5_discussion',
'erp5_km', 'erp5_km_ui_test_data', 'erp5_km_ui_test', 'erp5_km', 'erp5_km_ui_test_data', 'erp5_km_ui_test',
'erp5_l10n_fr', 'erp5_crm', 'erp5_web_renderjs_ui', 'erp5_l10n_fr', 'erp5_crm',
'erp5_forge',
'erp5_web_renderjs_ui',
'erp5_web_renderjs_ui_test', 'erp5_web_renderjs_ui_test',
) )
......
...@@ -49,7 +49,7 @@ class TestZeleniumStandaloneUserTutorial(ERP5TypeFunctionalTestCase): ...@@ -49,7 +49,7 @@ class TestZeleniumStandaloneUserTutorial(ERP5TypeFunctionalTestCase):
Return the list of business templates. Return the list of business templates.
""" """
return ('erp5_core_proxy_field_legacy', 'erp5_full_text_mroonga_catalog', return ('erp5_core_proxy_field_legacy', 'erp5_full_text_mroonga_catalog',
'erp5_base', 'erp5_ui_test_core', 'erp5_forge', 'erp5_base', 'erp5_ui_test_core',
'erp5_dhtml_style', 'erp5_dhtml_style',
'erp5_jquery', 'erp5_jquery_ui', 'erp5_jquery', 'erp5_jquery_ui',
'erp5_knowledge_pad', 'erp5_pdm', 'erp5_knowledge_pad', 'erp5_pdm',
...@@ -65,7 +65,7 @@ class TestZeleniumStandaloneUserTutorial(ERP5TypeFunctionalTestCase): ...@@ -65,7 +65,7 @@ class TestZeleniumStandaloneUserTutorial(ERP5TypeFunctionalTestCase):
'erp5_ingestion', 'erp5_ingestion_mysql_innodb_catalog', 'erp5_ingestion', 'erp5_ingestion_mysql_innodb_catalog',
'erp5_web', 'erp5_dms', 'erp5_credential', 'erp5_web', 'erp5_dms', 'erp5_credential',
'erp5_rss_style', 'erp5_discussion', 'erp5_rss_style', 'erp5_discussion',
'erp5_l10n_fr', 'erp5_crm', 'erp5_l10n_fr', 'erp5_crm', 'erp5_forge',
'erp5_run_my_doc', 'erp5_run_my_doc',
'erp5_user_tutorial_ui_test', 'erp5_user_tutorial_ui_test',
'erp5_user_tutorial', 'erp5_user_tutorial',
......
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