Commit 9e6db4ee authored by Jérome Perrin's avatar Jérome Perrin

deferred_style: alarm to automate reports production

See merge request nexedi/erp5!1357
parents 2e60dde5 3b600793
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Alarm" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>active_sense_method_id</string> </key>
<value> <string>Alarm_generateReportDocumentList</string> </value>
</item>
<item>
<key> <string>automatic_solve</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>configuration_form_id</string> </key>
<value> <string>Alarm_viewGenerateReportDocumentConfiguration</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>template_report_alarm</string> </value>
</item>
<item>
<key> <string>periodicity_day_frequency</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>periodicity_hour</string> </key>
<value>
<tuple>
<int>0</int>
</tuple>
</value>
</item>
<item>
<key> <string>periodicity_minute</string> </key>
<value>
<tuple>
<int>0</int>
</tuple>
</value>
</item>
<item>
<key> <string>periodicity_month</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_month_day</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_start_date</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1609459200.0</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>periodicity_week</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Alarm</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Report Alarm</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# type: (str, list[dict], str, str, str, str, str, DateTime.DateTime, Any)
portal = context.getPortalObject()
for attachment in attachment_list:
document = portal.portal_contributions.newContent(
data=attachment['content'],
filename=attachment['name'],
title=title,
reference=reference,
version=version,
publication_section=publication_section,
language=language,
effective_date=effective_date,
)
document.share()
<?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>subject, attachment_list, title, reference, version=\'\', publication_section=\'\', language=None, effective_date=None, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_contributeAndShareReportDocument</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# coding: utf-8
"""
Alarm must define a script that returns a list of dictionnaries with the following keys:
- form_id str: id of an ERP5 Form or ERP5 Report. Required.
- context erp5.portal_type.Base: the context to render the report. Required.
- parameters dict: request parameters to render the report. Required.
Must be serializable for CMFActivity
- skin_name str: skin selection to use for this report ('ODS' | 'ODT'). Required.
- format Optional[str]: convert the document to this format. Note that in scenarios like
storing the result report in document module, it's better to keep the default format (None)
and convert on demand the stored document.
- language str: Localizer language to use. Required.
- callback_script_id str: id of a script to call at the end of report generation. Required
The script will be called on the context of the alarm, with the following arguments:
- subject str: the name of the report
- attachment_list dict: files produced by the report, dicts with following keys:
- name str: file name
- mime str: file mime type
- content bytes: file body
- **callback_script_kwargs
- callback_script_kwargs dict: of arguemnts that will be passed to callback script id.
- setup Callable[[dict], dict]: a function to call at setup before rendering the report.
This function receive this dict as argument and must return a dict of the same type.
"""
priority = 3
portal = context.getPortalObject()
report_configuration_script_id = context.getProperty('report_configuration_script_id')
assert report_configuration_script_id
for report_data in getattr(context, report_configuration_script_id)():
if report_data.get('setup'):
report_data = report_data['setup'](report_data)
notify_report_complete_kwargs = {
'alarm_relative_url': context.getRelativeUrl(),
'callback_script_id': report_data['callback_script_id'],
'callback_script_kwargs': report_data.get('callback_script_kwargs', {}),
}
report_context = report_data.get('context', context)
report_active_context = report_context.activate(
activity='SQLQueue',
node=portal.portal_preferences.getPreferredDeferredReportActivityFamily(),
tag=tag,
priority=priority,
)
if getattr(getattr(report_context, report_data['form_id']), 'pt', 'form_list') == 'report_view':
# erp5 report
report_active_context.Base_computeReportSection(
form=report_data['form_id'],
request_other=report_data['parameters'],
user_name=None,
tag=tag,
skin_name=report_data['skin_name'],
format=report_data.get('format', None),
priority=priority,
localizer_language=report_data['language'],
notify_report_complete_script_id='ERP5Site_finalizeAlarmReportDocumentGeneration',
notify_report_complete_kwargs=notify_report_complete_kwargs,
)
else:
# simple view
params = {}
if 'format' in report_data:
params['format'] = report_data['format']
report_active_context.Base_renderSimpleView(
localizer_language=report_data['language'],
skin_name=report_data['skin_name'],
request_form=report_data['parameters'],
deferred_style_dialog_method=report_data['form_id'],
user_name=None,
params=params,
notify_report_complete_script_id='ERP5Site_finalizeAlarmReportDocumentGeneration',
notify_report_complete_kwargs=notify_report_complete_kwargs,
)
<?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>tag, fixit=False, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_generateReportDocumentList</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>Base_edit</string> </value>
</item>
<item>
<key> <string>action_title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></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/>
</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>my_report_configuration_script_id</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>Alarm_viewGenerateReportDocumentConfiguration</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Alarm_viewGenerateReportDocumenConfiguration</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>ERP5 Form</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_view</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>Configuration</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></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>description</string>
<string>display_width</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_report_configuration_script_id</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> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string>ID of a script returning the report configuration. See Alarm_generateReportDocumentList for the exact API</string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>20</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Report Configuration Script ID</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# pylint: disable=redefined-builtin # pylint: disable=redefined-builtin
portal = context.getPortalObject() portal = context.getPortalObject()
if notify_report_complete_kwargs is None:
notify_report_complete_kwargs = {}
form = context.restrictedTraverse(form) form = context.restrictedTraverse(form)
request = container.REQUEST request = container.REQUEST
...@@ -58,5 +60,7 @@ activity_context.activate( ...@@ -58,5 +60,7 @@ activity_context.activate(
form_path=form.getPhysicalPath(), form_path=form.getPhysicalPath(),
user_name=user_name, user_name=user_name,
format=format, format=format,
report_section_count=len(report_section_list) report_section_count=len(report_section_list),
) notify_report_complete_script_id=notify_report_complete_script_id,
notify_report_complete_kwargs=notify_report_complete_kwargs,
)
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>form, request_other, user_name, tag, skin_name, format, priority, localizer_language, **kw</string> </value> <value> <string>form, request_other, user_name, tag, skin_name, format, priority, localizer_language, notify_report_complete_script_id=\'ERP5Site_notifyReportComplete\', notify_report_complete_kwargs=None, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>_proxy_roles</string> </key> <key> <string>_proxy_roles</string> </key>
......
# Render a "normal" form or an OOo template in an activity and send it by email # Render a "normal" form or an OOo template in an activity and send it by email
from Products.ERP5Type.Message import translateString from Products.ERP5Type.Message import translateString
portal = context.getPortalObject() portal = context.getPortalObject()
if notify_report_complete_kwargs is None:
notify_report_complete_kwargs = {}
request = portal.REQUEST request = portal.REQUEST
report_format = request_form.get('format', '') report_format = request_form.get('format', '')
if portal.portal_preferences.getPreferredDeferredReportStoredAsDocument(): if portal.portal_preferences.getPreferredDeferredReportStoredAsDocument():
...@@ -31,9 +33,11 @@ with portal.Localizer.translationContext(localizer_language): ...@@ -31,9 +33,11 @@ with portal.Localizer.translationContext(localizer_language):
'content': '%s' % report_data, 'content': '%s' % report_data,
'name': attachment_name},) 'name': attachment_name},)
portal.ERP5Site_notifyReportComplete( getattr(portal, notify_report_complete_script_id)(
user_name=user_name, user_name=user_name,
subject=str(translateString(attachment_name.rsplit('.', 1)[0])), subject=str(translateString(attachment_name.rsplit('.', 1)[0])),
message='', message='',
attachment_list=attachment_list, attachment_list=attachment_list,
format=report_format) format=report_format,
**notify_report_complete_kwargs
)
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>localizer_language, skin_name, request_form, deferred_style_dialog_method, user_name, params</string> </value> <value> <string>localizer_language, skin_name, request_form, deferred_style_dialog_method, user_name, params, notify_report_complete_script_id=\'ERP5Site_notifyReportComplete\', notify_report_complete_kwargs=None</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -51,9 +51,11 @@ with portal.Localizer.translationContext(localizer_language): ...@@ -51,9 +51,11 @@ with portal.Localizer.translationContext(localizer_language):
'content': '%s' % report_data, 'content': '%s' % report_data,
'name': attachment_name},) 'name': attachment_name},)
portal.ERP5Site_notifyReportComplete( getattr(portal, notify_report_complete_script_id)(
user_name=user_name, user_name=user_name,
subject=title, subject=title,
message='', message='',
attachment_list=attachment_list, attachment_list=attachment_list,
format=format) format=format,
**notify_report_complete_kwargs
)
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>active_process_url, skin_name, localizer_language, title, request_other, form_path, user_name, format, report_section_count</string> </value> <value> <string>active_process_url, skin_name, localizer_language, title, request_other, form_path, user_name, format, report_section_count, notify_report_complete_script_id, notify_report_complete_kwargs</string> </value>
</item> </item>
<item> <item>
<key> <string>_proxy_roles</string> </key> <key> <string>_proxy_roles</string> </key>
......
# pylint:disable=redefined-builtin
portal = context.getPortalObject()
assert alarm_relative_url
alarm = portal.restrictedTraverse(alarm_relative_url)
assert callback_script_id
callback = getattr(alarm, callback_script_id)
callback(
subject=subject,
attachment_list=attachment_list,
**callback_script_kwargs
)
<?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>user_name, subject, message, attachment_list, format, alarm_relative_url, callback_script_id, callback_script_kwargs</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ERP5Site_finalizeAlarmReportDocumentGeneration</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
2021-02-04 Jérome
* Alarm to automate report creation
2009-09-12 Jérome 2009-09-12 Jérome
* Allow rendering of any form / printout in deferred mode * Allow rendering of any form / printout in deferred mode
\ No newline at end of file
portal_alarms/template_report_alarm
\ No newline at end of file
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
############################################################################## ##############################################################################
import unittest import unittest
import textwrap
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.utils import createZODBPythonScript from Products.ERP5Type.tests.utils import createZODBPythonScript
from Testing import ZopeTestCase from Testing import ZopeTestCase
...@@ -36,8 +37,7 @@ from lxml import html ...@@ -36,8 +37,7 @@ from lxml import html
import email, urlparse, httplib import email, urlparse, httplib
class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): class DeferredStyleTestCase(ERP5TypeTestCase, ZopeTestCase.Functional):
"""Tests deferred styles for ERP5."""
skin = content_type = None skin = content_type = None
recipient_email_address = 'invalid@example.com' recipient_email_address = 'invalid@example.com'
attachment_file_extension = '' attachment_file_extension = ''
...@@ -50,9 +50,6 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -50,9 +50,6 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
publication_section = "reporting" publication_section = "reporting"
classification = "collaborative" classification = "collaborative"
def getTitle(self):
return 'Test Deferred Style'
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return ('erp5_core_proxy_field_legacy', return ('erp5_core_proxy_field_legacy',
'erp5_base', 'erp5_base',
...@@ -67,14 +64,10 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -67,14 +64,10 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
def afterSetUp(self): def afterSetUp(self):
self.login() self.login()
if not self.skin:
raise NotImplementedError('Subclasses must define skin')
self.portal.MailHost.reset() self.portal.MailHost.reset()
person_module = self.portal.person_module person_module = self.portal.person_module
if person_module._getOb('pers', None) is None: if person_module._getOb('pers', None) is None:
person = person_module.newContent(id='pers', portal_type='Person', person = person_module.newContent(id='pers', portal_type='Person',
reference=self.username,
first_name=self.first_name, first_name=self.first_name,
default_email_text=self.recipient_email_address) default_email_text=self.recipient_email_address)
assignment = person.newContent(portal_type='Assignment') assignment = person.newContent(portal_type='Assignment')
...@@ -107,23 +100,29 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -107,23 +100,29 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
self.tic() self.tic()
def loginAsUser(self, username): def loginAsUser(self, username):
"""Login as a user and assign Manager role to this user.
"""
uf = self.portal.acl_users uf = self.portal.acl_users
user = uf.getUser(username).__of__(uf) user = uf.getUser(username).__of__(uf)
uf.zodb_roles.assignRoleToPrincipal('Manager', user.getId()) uf.zodb_roles.assignRoleToPrincipal('Manager', user.getId())
newSecurityManager(None, user) newSecurityManager(None, user)
class TestDeferredStyleBase(DeferredStyleTestCase):
"""Tests deferred styles for ERP5."""
def test_skin_selection(self): def test_skin_selection(self):
self.assertTrue('Deferred' in self.portal.portal_skins.getSkinSelections()) self.assertTrue('Deferred' in self.portal.portal_skins.getSkinSelections())
def test_report_view(self): def test_report_view(self):
self.loginAsUser('bob') self.loginAsUser(self.username)
self.portal.changeSkin('Deferred') self.portal.changeSkin('Deferred')
response = self.publish( response = self.publish(
'/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s' '/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s'
% (self.portal.getId(), self.skin), '%s:%s' % (self.username, self.password)) % (self.portal.getId(), self.skin), '%s:%s' % (self.username, self.password))
self.tic() self.tic()
last_message = self.portal.MailHost._last_message last_message = self.portal.MailHost._last_message
self.assertNotEquals((), last_message) self.assertNotEqual(last_message, ())
mfrom, mto, message_text = last_message mfrom, mto, message_text = last_message
self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0]) self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0])
mail_message = email.message_from_string(message_text) mail_message = email.message_from_string(message_text)
...@@ -158,7 +157,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -158,7 +157,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
def _checkDocument(self): def _checkDocument(self):
document_list = self.portal.document_module.objectValues() document_list = self.portal.document_module.objectValues()
self.assertEquals(len(document_list), 1) self.assertEqual(len(document_list), 1)
document = document_list[0].getObject() document = document_list[0].getObject()
expected_file_name = 'History%s' % self.attachment_file_extension expected_file_name = 'History%s' % self.attachment_file_extension
self.assertEqual(expected_file_name, document.getFilename()) self.assertEqual(expected_file_name, document.getFilename())
...@@ -179,7 +178,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -179,7 +178,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
def test_report_stored_as_document(self): def test_report_stored_as_document(self):
self._defineSystemPreference() self._defineSystemPreference()
self.loginAsUser('bob') self.loginAsUser(self.username)
self.portal.changeSkin('Deferred') self.portal.changeSkin('Deferred')
response = self.publish( response = self.publish(
'/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s' '/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s'
...@@ -188,7 +187,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -188,7 +187,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
self._checkDocument() self._checkDocument()
last_message = self.portal.MailHost._last_message last_message = self.portal.MailHost._last_message
self.assertNotEquals((), last_message) self.assertNotEqual(last_message, ())
mfrom, mto, message_text = last_message mfrom, mto, message_text = last_message
self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0]) self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0])
mail_message = email.message_from_string(message_text) mail_message = email.message_from_string(message_text)
...@@ -217,7 +216,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -217,7 +216,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
notification_message.validate() notification_message.validate()
self.tic() self.tic()
self._defineSystemPreference("notification-deferred.report") self._defineSystemPreference("notification-deferred.report")
self.loginAsUser('bob') self.loginAsUser(self.username)
self.portal.changeSkin('Deferred') self.portal.changeSkin('Deferred')
response = self.publish( response = self.publish(
'/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s' '/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s'
...@@ -226,7 +225,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -226,7 +225,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
self._checkDocument() self._checkDocument()
last_message = self.portal.MailHost._last_message last_message = self.portal.MailHost._last_message
self.assertNotEquals((), last_message) self.assertNotEqual(last_message, ())
mfrom, mto, message_text = last_message mfrom, mto, message_text = last_message
self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0]) self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0])
mail_message = email.message_from_string(message_text) mail_message = email.message_from_string(message_text)
...@@ -240,7 +239,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -240,7 +239,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
def test_pdf_report_stored_as_document(self): def test_pdf_report_stored_as_document(self):
self._defineSystemPreference() self._defineSystemPreference()
self.loginAsUser('bob') self.loginAsUser(self.username)
self.portal.changeSkin('Deferred') self.portal.changeSkin('Deferred')
response = self.publish( response = self.publish(
'/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s&format=pdf' '/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s&format=pdf'
...@@ -250,7 +249,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -250,7 +249,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
self._checkDocument() self._checkDocument()
last_message = self.portal.MailHost._last_message last_message = self.portal.MailHost._last_message
self.assertNotEquals((), last_message) self.assertNotEqual(last_message, ())
mfrom, mto, message_text = last_message mfrom, mto, message_text = last_message
self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0]) self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0])
mail_message = email.message_from_string(message_text) mail_message = email.message_from_string(message_text)
...@@ -263,7 +262,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -263,7 +262,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
self.fail('Link not found in email\n%s' % message_text) self.fail('Link not found in email\n%s' % message_text)
def test_normal_form(self): def test_normal_form(self):
self.loginAsUser('bob') self.loginAsUser(self.username)
# simulate a big request, for which Base_callDialogMethod will not issue a # simulate a big request, for which Base_callDialogMethod will not issue a
# redirect # redirect
response = self.publish( response = self.publish(
...@@ -275,7 +274,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -275,7 +274,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
'%s:%s' % (self.username, self.password)) '%s:%s' % (self.username, self.password))
self.tic() self.tic()
last_message = self.portal.MailHost._last_message last_message = self.portal.MailHost._last_message
self.assertNotEquals((), last_message) self.assertNotEqual(last_message, ())
mfrom, mto, message_text = last_message mfrom, mto, message_text = last_message
self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0]) self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0])
mail_message = email.message_from_string(message_text) mail_message = email.message_from_string(message_text)
...@@ -298,7 +297,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -298,7 +297,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
def test_lang_negociation(self): def test_lang_negociation(self):
# User's Accept-Language header is honored in reports. # User's Accept-Language header is honored in reports.
self.loginAsUser('bob') self.loginAsUser(self.username)
self.portal.changeSkin('Deferred') self.portal.changeSkin('Deferred')
response = self.publish( response = self.publish(
'/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s' '/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s'
...@@ -323,7 +322,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -323,7 +322,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
def test_lang_negociation_cookie(self): def test_lang_negociation_cookie(self):
# User's LOCALIZER_LANGUAGE cookie is honored in reports and have priority over Accept-Language # User's LOCALIZER_LANGUAGE cookie is honored in reports and have priority over Accept-Language
self.loginAsUser('bob') self.loginAsUser(self.username)
self.portal.changeSkin('Deferred') self.portal.changeSkin('Deferred')
response = self.publish( response = self.publish(
'/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s' '/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s'
...@@ -354,8 +353,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -354,8 +353,7 @@ class TestDeferredStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
self.tic() self.tic()
class TestODSDeferredStyle(TestDeferredStyleBase):
class TestODSDeferredStyle(TestDeferredStyle):
skin = 'ODS' skin = 'ODS'
content_type = 'application/vnd.oasis.opendocument.spreadsheet' content_type = 'application/vnd.oasis.opendocument.spreadsheet'
attachment_file_extension = '.ods' attachment_file_extension = '.ods'
...@@ -364,14 +362,14 @@ class TestODSDeferredStyle(TestDeferredStyle): ...@@ -364,14 +362,14 @@ class TestODSDeferredStyle(TestDeferredStyle):
def test_report_view_sheet_per_report_section(self): def test_report_view_sheet_per_report_section(self):
"""Test the sheet_per_report_section feature of erp5_ods_style. """Test the sheet_per_report_section feature of erp5_ods_style.
""" """
self.loginAsUser('bob') self.loginAsUser(self.username)
self.portal.changeSkin('Deferred') self.portal.changeSkin('Deferred')
response = self.publish( response = self.publish(
'/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s&sheet_per_report_section:int=1' '/%s/person_module/pers/Base_viewHistory?deferred_portal_skin=%s&sheet_per_report_section:int=1'
% (self.portal.getId(), self.skin), '%s:%s' % (self.username, self.password)) % (self.portal.getId(), self.skin), '%s:%s' % (self.username, self.password))
self.tic() self.tic()
last_message = self.portal.MailHost._last_message last_message = self.portal.MailHost._last_message
self.assertNotEquals((), last_message) self.assertNotEqual(last_message, ())
mfrom, mto, message_text = last_message mfrom, mto, message_text = last_message
self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0]) self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0])
mail_message = email.message_from_string(message_text) mail_message = email.message_from_string(message_text)
...@@ -394,14 +392,148 @@ class TestODSDeferredStyle(TestDeferredStyle): ...@@ -394,14 +392,148 @@ class TestODSDeferredStyle(TestDeferredStyle):
self.fail('Attachment not found in email\n%s' % message_text) self.fail('Attachment not found in email\n%s' % message_text)
class TestODTDeferredStyle(TestDeferredStyle): class TestODTDeferredStyle(TestDeferredStyleBase):
skin = 'ODT' skin = 'ODT'
content_type = 'application/vnd.oasis.opendocument.text' content_type = 'application/vnd.oasis.opendocument.text'
attachment_file_extension = '.odt' attachment_file_extension = '.odt'
portal_type = "Text" portal_type = "Text"
class TestDeferredReportAlarm(DeferredStyleTestCase):
def getBusinessTemplateList(self):
return super(TestDeferredReportAlarm, self).getBusinessTemplateList() + (
'erp5_pdm',
'erp5_simulation',
'erp5_trade',
'erp5_accounting',
'erp5_knowledge_pad',
'erp5_web',
'erp5_ingestion',
'erp5_ingestion_mysql_innodb_catalog',
'erp5_dms',
)
def test_alarm(self):
# create some data for reports
self.portal.person_module.newContent(portal_type='Person', first_name="not_included")
self.portal.person_module.newContent(portal_type='Person', first_name="yes_included").validate()
# make a script to configure the reports
report_configuration_script_id = 'Alarm_getTestReportList{}'.format(self.id())
report_after_generation_script_id = 'Alarm_afterReportGenerated{}'.format(self.id())
createZODBPythonScript(
self.portal.portal_skins.custom,
report_configuration_script_id,
'',
textwrap.dedent(
'''\
# coding: utf-8
portal = context.getPortalObject()
report_data_list = [
# For the first two reports, we us included script:
# Alarm_contributeAndShareReportDocument
# which creates a document in document module.
# First with person module view
{
'form_id': 'PersonModule_viewPersonList',
'context': portal.person_module,
'parameters': {
'validation_state': 'validated',
},
'skin_name': 'ODS',
'language': 'fr',
'format': 'txt',
'callback_script_id': 'Alarm_contributeAndShareReportDocument',
'callback_script_kwargs': {
'title': 'Persons {}'.format(DateTime()),
'reference': 'TEST-Persons.Report',
'language': 'fr',
},
},
# Then with an accounting report (which uses report_view and a different
# approach to generate report).
{
'form_id': 'AccountModule_viewTrialBalanceReport',
'context': portal.accounting_module,
'parameters': {
'from_date': DateTime(2021, 1, 1),
'at_date': DateTime(2021, 12, 31),
'section_category': 'group',
'section_category_strict': False,
'simulation_state': ['delivered'],
'show_empty_accounts': True,
'expand_accounts': False,
'per_account_class_summary': False,
'show_detailed_balance_columns': False,
},
'skin_name': 'ODS',
'language': 'fr',
'callback_script_id': 'Alarm_contributeAndShareReportDocument',
'callback_script_kwargs': {
'title': 'Trial Balance {}'.format(DateTime()),
'reference': 'TEST-Trial.Balance.Report',
'language': 'fr',
},
},
# then another report to verify the callback script protocol.
{
'form_id': 'Person_view',
'context': portal.person_module.contentValues()[0],
'skin_name': 'ODS',
'language': portal.Localizer.get_default_language(),
'parameters': {},
'callback_script_id': '%s',
'callback_script_kwargs': {
'foo': 'bar'
},
},
]
return report_data_list
''' % report_after_generation_script_id))
createZODBPythonScript(
self.portal.portal_skins.custom,
report_after_generation_script_id,
'subject, attachment_list, foo',
textwrap.dedent(
'''\
context.setTitle('after script called with foo=' + foo)
'''
))
alarm = self.portal.portal_alarms.template_report_alarm.Base_createCloneDocument(
batch_mode=True)
alarm.edit(
report_configuration_script_id=report_configuration_script_id
)
alarm.activeSense()
self.tic()
# the first two reports are created
person_report, = self.portal.portal_catalog.getDocumentValueList(
reference='TEST-Persons.Report',
language='fr',
)
self.assertIn('yes_included', person_report.getTextContent())
self.assertNotIn('not_included', person_report.getTextContent())
trial_balance_report, = self.portal.portal_catalog.getDocumentValueList(
reference='TEST-Trial.Balance.Report',
language='fr',
)
self.assertEqual(trial_balance_report.getPortalType(), 'Spreadsheet')
# the third report, used to check the callback script protocol, modified the alarm title
self.assertEqual(alarm.getTitle(), 'after script called with foo=bar')
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestODSDeferredStyle)) suite.addTest(unittest.makeSuite(TestODSDeferredStyle))
suite.addTest(unittest.makeSuite(TestODTDeferredStyle)) suite.addTest(unittest.makeSuite(TestODTDeferredStyle))
suite.addTest(unittest.makeSuite(TestDeferredReportAlarm))
return suite return suite
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