[MERGE]merge mail-cleaning-fp and change in mail message

bzr revid: sgo@tinyerp.com-20120831050230-opnug0owd3o1ucaf
This commit is contained in:
Sanjay Gohel (Open ERP) 2012-08-31 10:32:30 +05:30
commit 18d606a794
37 changed files with 604 additions and 462 deletions

View File

@ -21,13 +21,14 @@
</record>
<!-- Notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>With OpenERP's accounting, you can get an instant access to all your financial data, setup your analytic accounting, forecast your taxes, control your budgets, easily create and send invoices, record bank statements, etc.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Accounting and Finance application installed!</field>
<field name="body">With OpenERP's accounting, you get instant access to your financial data, and can setup analytic accounting, forecast taxes, control budgets, easily create and send invoices, record bank statements, etc.
The accounting features are fully integrated with others OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.</value>
<value>Module Accounting and Finance has been installed.</value>
</function>
The accounting features are fully integrated with other OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.</field>
</record>
</data>
</openerp>

View File

@ -2,15 +2,16 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>OpenERP's electronic invoicing allows to ease and fasten the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">eInvoicing &amp; Payments application installed!</field>
<field name="body">OpenERP's electronic invoicing accelerates the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.
You can track customer payments easily and automate the reminders. You get an overview of the discussion with your customers on each invoice to ensure a full traceability.
You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability.
If you want to use advanced accounting features, you should install the "Accounting and Finance" module.</value>
<value>Module eInvoicing &amp; Payments has been installed.</value>
</function>
For advanced accounting features, you should install the "Accounting and Finance" module.</field>
</record>
</data>
</openerp>

View File

@ -55,21 +55,20 @@
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>From the top menu Sales, you can: trace leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">CRM application installed!</field>
<field name="body">From the top Sales menu you can track leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects.
To manage quotations and sale orders, install the "Sales Management" application.</field>
</record>
To manage quotations and sale orders, install the module "Sales Management".</value>
<value>Module CRM has been installed</value>
</function>
<record model="mail.alias" id="default_sales_alias">
<field name="alias_name">sales</field>
<field name="alias_model_id" ref="model_crm_lead"/>
<field name="alias_user_id" ref="base.user_root"/>
<field name="alias_defaults">{'type':'lead'}</field>
</record>
</data>
</openerp>

View File

@ -28,6 +28,8 @@ from osv import osv
from osv import fields
import tools
from tools.translate import _
from tools.html_sanitize import html_sanitize
from tools import html2plaintext
from urllib import quote as quote
_logger = logging.getLogger(__name__)
@ -134,7 +136,7 @@ class email_template(osv.osv):
"This is useful for CRM leads for example"),
# Overridden mail.message.common fields for technical reasons:
'model': fields.related('model_id','model', type='char', string='Related Document Model',
'model': fields.related('model_id', 'model', type='char', string='Related Document Model',
size=128, select=True, store=True, readonly=True),
# we need a separate m2m table to avoid ID collisions with the original mail.message entries
#'attachment_ids': fields.many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id',
@ -143,7 +145,7 @@ class email_template(osv.osv):
# "emails created from this template"),
# Overridden mail.message.common fields to make tooltips more appropriate:
#'subject':fields.char('Subject', size=512, translate=True, help="Subject (placeholders may be used here)",),
'subject': fields.char('Subject', translate=True, help="Subject (placeholders may be used here)",),
'email_from': fields.char('From', size=128, help="Sender address (placeholders may be used here)"),
'email_to': fields.char('To', size=256, help="Comma-separated recipient addresses (placeholders may be used here)"),
'email_cc': fields.char('Cc', size=256, help="Carbon copy recipients (placeholders may be used here)"),
@ -151,13 +153,7 @@ class email_template(osv.osv):
'mail_server_id': fields.many2one('ir.mail_server', 'Outgoing Mail Server', readonly=False,
help="Optional preferred server for outgoing mails. If not set, the highest "
"priority one will be used."),
#'body': fields.text('Text Contents', translate=True, help="Plaintext version of the message (placeholders may be used here)"),
'body_html': fields.text('Rich-text Contents', translate=True, help="Rich-text/HTML version of the message (placeholders may be used here)"),
#'message_id': fields.char('Message-Id', size=256, help="Message-ID SMTP header to use in outgoing messages based on this template. "
# "Please note that this overrides the 'Resource Tracking' option, "
# "so if you simply need to track replies to outgoing emails, enable "
# "that option instead.\n"
# "Placeholders must be used here, as this value always needs to be unique!"),
# Fake fields used to implement the placeholder assistant
'model_object_field': fields.many2one('ir.model.fields', string="Field",
@ -300,7 +296,6 @@ class email_template(osv.osv):
context = {}
values = {
'subject': False,
'body': False,
'body_html': False,
'email_from': False,
'email_to': False,
@ -314,7 +309,6 @@ class email_template(osv.osv):
'attachment_ids': False,
'message_id': False,
'state': 'outgoing',
'content_subtype': 'plain',
}
if not template_id:
return values
@ -322,15 +316,15 @@ class email_template(osv.osv):
report_xml_pool = self.pool.get('ir.actions.report.xml')
template = self.get_email_template(cr, uid, template_id, res_id, context)
for field in ['subject', 'body', 'body_html', 'email_from',
'email_to', 'email_cc', 'reply_to',
'message_id']:
for field in ['subject', 'body_html', 'email_from',
'email_to', 'email_cc', 'reply_to']:
values[field] = self.render_template(cr, uid, getattr(template, field),
template.model, res_id, context=context) \
or False
if values['body_html']:
values.update(content_subtype='html')
values['body'] = html_sanitize(values['body_html'])
values['body_text'] = html2plaintext(values['body_html'])
if template.user_signature:
signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature

View File

@ -22,10 +22,7 @@
<field name="reply_to"/>
<field name="subject" required="1"/>
<notebook colspan="4">
<page string="Body (Text)">
<field name="body" colspan="4" width="250" height="250" nolabel="1"/>
</page>
<page string="Body (Rich/HTML)">
<page string="Body (HTML)">
<field name="body_html" colspan="4" width="250" height="250" nolabel="1"/>
<label string="Note: This is Raw HTML." colspan="4"/>
</page>

View File

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import test_mail
checks = [
test_mail,
]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.tests import common
import tools
class test_message_compose(common.TransactionCase):
def _mock_smtp_gateway(self, *args, **kwargs):
return True
def _mock_build_email(self, *args, **kwargs):
self._build_email_args = args
self._build_email_kwargs = kwargs
return self.build_email_real(*args, **kwargs)
def setUp(self):
super(test_message_compose, self).setUp()
self.mail_group = self.registry('mail.group')
self.mail_mail = self.registry('mail.mail')
self.mail_message = self.registry('mail.message')
self.res_users = self.registry('res.users')
self.res_partner = self.registry('res.partner')
# Install mock SMTP gateway
self.build_email_real = self.registry('ir.mail_server').build_email
self.registry('ir.mail_server').build_email = self._mock_build_email
self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
# create a 'pigs' group that will be used through the various tests
self.group_pigs_id = self.mail_group.create(self.cr, self.uid,
{'name': 'Pigs', 'description': 'Fans of Pigs, unite !'})
def test_00_message_compose_wizard(self):
""" Tests designed for the mail.compose.message wizard updated by email_template. """
cr, uid = self.cr, self.uid
mail_compose = self.registry('mail.compose.message')
self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'})
user_admin = self.res_users.browse(cr, uid, uid)
group_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'mail.group')])[0]
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
# Create template on mail.group
email_template = self.registry('email.template')
email_template_id = email_template.create(cr, uid, {'model_id': group_model_id,
'name': 'Pigs Template', 'subject': '${record.name}',
'body_html': '${object.description}', 'user_signature': True,
'email_to': 'b@b c@c', 'email_cc': 'd@d'})
# import pdb
# pdb.set_trace()
# Mail data
_subject = 'Pigs'
_body_text = 'Pigs rules'
# 3 - Create in mass_mail composition mode that should work with or without email_template installed
compose_id = mail_compose.create(cr, uid,
{'subject': _subject, 'body': _body_text},
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group',
'default_res_id': -1, 'default_use_template': True,
'active_ids': [self.group_pigs_id], 'default_template_id': email_template_id})
compose = mail_compose.browse(cr, uid, compose_id)
# print compose.subject
# Try the 'onchange_template_id'
values = mail_compose.onchange_template_id(cr, uid, [], compose.use_template, compose.template_id, compose.composition_mode, compose.res_id)
# print values
values = mail_compose.onchange_use_template(cr, uid, [], not compose.use_template, compose.template_id, compose.composition_mode, compose.res_id)
# print values
compose.refresh()
# # Post the comment, get created message
# mail_compose.send_mail(cr, uid, [compose_id], {'default_res_id': -1, 'active_ids': [self.group_pigs_id]})
# group_pigs.refresh()
# msg = group_pigs.message_ids[0]
# # Test: last message on Pigs = last created message
# test_msg = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [], limit=1))[0]
# self.assertEqual(msg.id, test_msg.id, 'Pigs did not receive its mass mailing message')
# # Test: mail.message: subject, body
# self.assertEqual(msg.subject, _subject, 'mail.message subject is incorrect')
# self.assertEqual(msg.body, group_pigs.description, 'mail.message body is incorrect')

View File

@ -20,62 +20,62 @@
##############################################################################
import base64
import tools
from osv import osv
from osv import fields
from tools.translate import _
import tools
class mail_compose_message(osv.osv_memory):
""" Inherit mail_compose_message to add email template feature in the
message composer. """
_inherit = 'mail.compose.message'
def _get_templates(self, cr, uid, context=None):
"""
Return Email Template of particular Model.
"""
""" Return Email Template of particular Model. """
if context is None:
context = {}
record_ids = []
email_template= self.pool.get('email.template')
model = False
if context.get('message_id'):
mail_message = self.pool.get('mail.message')
message_data = mail_message.browse(cr, uid, int(context.get('message_id')), context)
model = message_data.model
elif context.get('mail.compose.target.model') or context.get('active_model'):
model = context.get('mail.compose.target.model', context.get('active_model'))
email_template_obj= self.pool.get('email.template')
if context.get('default_composition_mode') == 'reply' and context.get('active_id'):
message_data = self.pool.get('mail.message').browse(cr, uid, int(context.get('active_id')), context)
if message_data:
model = message_data.model
else:
model = context.get('default_model', context.get('active_model'))
if model:
record_ids = email_template.search(cr, uid, [('model', '=', model)])
return email_template.name_get(cr, uid, record_ids, context) + [(False,'')]
record_ids = email_template_obj.search(cr, uid, [('model', '=', model)], context=context)
return email_template_obj.name_get(cr, uid, record_ids, context) + [(False, '')]
return []
def default_get(self, cr, uid, fields, context=None):
""" Override to handle templates. """
if context is None:
context = {}
result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
result['template_id'] = context.get('default_template_id', context.get('mail.compose.template_id', False))
return result
_columns = {
'use_template': fields.boolean('Use Template'),
'template_id': fields.selection(_get_templates, 'Template',
size=-1 # means we want an int db column
),
}
_defaults = {
'template_id' : lambda self, cr, uid, context={} : context.get('mail.compose.template_id', False)
# incredible hack of the day: size=-1 means we want an int db column instead of an str one
'template_id': fields.selection(_get_templates, 'Template', size=-1),
}
def on_change_template(self, cr, uid, ids, use_template, template_id, email_from=None, email_to=None, context=None):
if context is None:
context = {}
values = {}
if template_id:
res_id = context.get('active_id', False)
if context.get('mail.compose.message.mode') == 'mass_mail':
# use the original template values - to be rendered when actually sent
# by super.send_mail()
values = self.pool.get('email.template').read(cr, uid, template_id, self.fields_get_keys(cr, uid), context)
def onchange_template_id(self, cr, uid, ids, use_template, template_id, composition_mode, res_id, context=None):
""" onchange_template_id: read or render the template if set, get back
to default values if not. """
fields = ['body', 'body_html', 'subject', 'partner_ids', 'email_to', 'email_cc']
if use_template and template_id:
# use the original template values, to be rendered when actually sent
if composition_mode == 'mass_mail':
values = self.pool.get('email.template').read(cr, uid, template_id, fields, context)
# render the mail as one-shot
else:
# render the mail as one-shot
values = self.pool.get('email.template').generate_email(cr, uid, template_id, res_id, context=context)
# get partner_ids back
values['dest_partner_ids'] = values['partner_ids']
# retrofit generated attachments in the expected field format
if values['attachments']:
attachment = values.pop('attachments')
@ -92,65 +92,61 @@ class mail_compose_message(osv.osv_memory):
}
att_ids.append(attachment_obj.create(cr, uid, data_attach))
values['attachment_ids'] = att_ids
else:
# restore defaults
values = self.default_get(cr, uid, self.fields_get_keys(cr, uid), context)
values.update(use_template=use_template, template_id=template_id)
else: # restore defaults
values = self.default_get(cr, uid, fields, context=context)
if values.get('body_html') and not values.get('body'):
values['body'] = values.get('body_html')
values.update(use_template=use_template, template_id=template_id)
print 'returning ', values
return {'value': values}
def template_toggle(self, cr, uid, ids, context=None):
def toggle_template(self, cr, uid, ids, context=None):
""" hit toggle template mode button: calls onchange_use_template to
emulate an on_change, then writes the value to update the form. """
for record in self.browse(cr, uid, ids, context=context):
values = {}
use_template = record.use_template
# simulate an on_change on use_template
values.update(self.onchange_use_template(cr, uid, ids, not use_template, context=context)['value'])
record.write(values)
return False
onchange_res = self.onchange_use_template(cr, uid, ids, not record.use_template,
record.template_id, record.composition_mode, record.res_id, context=context)['value']
record.write(onchange_res)
return True
def onchange_use_template(self, cr, uid, ids, use_template, context=None):
values = {'use_template': use_template}
for record in self.browse(cr, uid, ids, context=context):
if not use_template:
# equivalent to choosing an empty template
onchange_template_values = self.on_change_template(cr, uid, record.id, use_template,
False, email_from=record.email_from, email_to=record.email_to, context=context)
values.update(onchange_template_values['value'])
return {'value': values}
def onchange_use_template(self, cr, uid, ids, use_template, template_id, composition_mode, res_id, context=None):
""" onchange_use_template (values: True or False). If use_template is
False, we do like an onchange with template_id False for values """
onchange_template_values = self.onchange_template_id(cr, uid, ids, use_template,
template_id, composition_mode, res_id, context=context)
return onchange_template_values
def save_as_template(self, cr, uid, ids, context=None):
if context is None:
context = {}
""" hit save as template button: current form value will be a new
template attached to the current document. """
email_template = self.pool.get('email.template')
model_pool = self.pool.get('ir.model')
ir_model_pool = self.pool.get('ir.model')
for record in self.browse(cr, uid, ids, context=context):
model = record.model or context.get('active_model')
model_ids = model_pool.search(cr, uid, [('model', '=', model)])
model = record.model
model_ids = ir_model_pool.search(cr, uid, [('model', '=', model)])
model_id = model_ids and model_ids[0] or False
model_name = ''
if model_id:
model_name = model_pool.browse(cr, uid, model_id, context=context).name
model_name = ir_model_pool.browse(cr, uid, model_id, context=context).name
template_name = "%s: %s" % (model_name, tools.ustr(record.subject))
values = {
'name': template_name,
'email_from': record.email_from or False,
'subject': record.subject or False,
'body': record.body or False,
'email_to': record.email_to or False,
'email_cc': record.email_cc or False,
'reply_to': record.reply_to or False,
'model_id': model_id or False,
'attachment_ids': [(6, 0, [att.id for att in record.attachment_ids])]
}
template_id = email_template.create(cr, uid, values, context=context)
record.write({'template_id': template_id,
'use_template': True})
record.write({'template_id': template_id, 'use_template': True})
return True
# _reopen same wizard screen with new template preselected
return False
# override the basic implementation
def render_template(self, cr, uid, template, model, res_id, context=None):
""" Override of mail.compose.message behavior: use the power of
templates ! """
return self.pool.get('email.template').render_template(cr, uid, template, model, res_id, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -10,15 +10,16 @@
<data>
<xpath expr="//form/footer/button" position="before">
<field name="use_template" invisible="1"/>
<button icon="gtk-paste" type="object" name="template_toggle"
<button icon="gtk-paste" type="object" name="toggle_template"
string="" help="Use a message template" />
<button icon="gtk-save" type="object" name="save_as_template"
string="" help="Save as a new template"/>
</xpath>
<xpath expr="//form/notebook" position="after">
<group attrs="{'invisible':[('use_template','=',False)]}" colspan="4" col="4">
<field name="use_template" invisible="1"/>
<field name="template_id" colspan="3"
on_change="on_change_template(use_template, template_id, email_from, email_to, context)"/>
on_change="onchange_template_id(use_template, template_id, composition_mode, res_id, context)"/>
</group>
</xpath>
</data>
@ -33,14 +34,14 @@
<data>
<xpath expr="//field[@name='partner_ids']" position="after">
<field name="use_template" colspan="2" nolabel="1" invisible="1"
on_change="onchange_use_template(use_template, context)"/>
on_change="onchange_use_template(use_template, template_id, composition_mode, res_id, context)"/>
<field name="template_id" colspan="2" nolabel="1"
attrs="{'invisible':[('use_template','=',False)]}"
on_change="on_change_template(use_template, template_id, False, False, context)"/>
on_change="onchange_template_id(use_template, template_id, composition_mode, res_id, context)"/>
</xpath>
<xpath expr="//button[@class='oe_mail_compose_message_attachment']" position="before">
<button icon="/email_template/static/src/img/email_template.png"
type="object" name="template_toggle" string=""
type="object" name="toggle_template" string=""
help="Use a message template"/>
<button icon="/email_template/static/src/img/email_template_save.png"
type="object" name="save_as_template" string=""

View File

@ -14,11 +14,13 @@
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>From the top menu Events, you can organize events, manage registrations, automate communication around your event and sell events through your quotations.</value>
<value>Module Events Organisation has been installed</value>
</function>
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Events Organisation application installed!</field>
<field name="body">From the top Events menu, you can organize events, manage registrations, automate communication around your event and sell events through your quotations.</field>
</record>
</data>
</openerp>

View File

@ -2,14 +2,16 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Manage your human resources in OpenERP: employees and hierarchy, HR departments and jobs.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Employee Directory application installed!</field>
<field name="body">Manage your human resources with OpenERP: employees and their hierarchy, HR departments and job positions.
More HR features are available from the following modules: Recruitment Process (manage job positions and recruitment), Timesheets Validation (record timesheets and attendance), Leaves Management (keep track of employee leaves), Expenses Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager.)</value>
<value>Module Employee Directory has been installed</value>
</function>
More HR features are available via extra applications: Recruitment Process (manage job positions and recruitment), Timesheet Validation (record timesheets and attendance),
Leave Management (keep track of employee leaves), Expense Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager).</field>
</record>
<record id="employee" model="hr.employee">
<field name="name">Administrator</field>

View File

@ -14,12 +14,14 @@
<field name="sequence">100</field>
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Create evaluations for your subordinates or manager. You can define a plan with several surveys, where you organize evaluation surveys related to the hierarchy levels. Evaluations filled by employees can exported as pdf files.</value>
<value>Module Employee Appraisals has been installed</value>
</function>
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Employee Appraisals application installed!</field>
<field name="body">Manage employee reviews: you can define an appraisal campaign with several steps, with specific evaluation surveys according to hierarchy levels.
Evaluations filled by employees may be exported as pdf files.</field>
</record>
<record id="survey_2" model="survey">
<field name="title">Self Appraisal</field>

View File

@ -21,14 +21,14 @@
{
'name': 'Expenses Management',
'name': 'Expense Management',
'version': '1.0',
'category': 'Human Resources',
'sequence': 30,
'summary': 'Expenses Validation, Invoicing',
'description': """
This module aims to manage employee's expenses.
===============================================
This module aims to manage employee expenses.
=============================================
The whole workflow is implemented:
----------------------------------

View File

@ -2,20 +2,20 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Manage your employee's expenses, with validations by employee manager and accountant, creation and payment of invoices.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Expense Management application installed!</field>
<field name="body">Manage your employees' expenses, after due validation by their manager and the accountant, then generate and pay the corresponding invoices.
This module also uses the analytic accounting and is compatible with the invoice on timesheet module so that you will be able to automatically re-invoice your customer's expenses if your work by project.</value>
<value>Module Expenses Management has been installed</value>
</function>
This feature is also linked to analytic accounting and compatible with timesheet invoices, so you will be able to automatically re-invoice project-related expenses to your customers.</field>
</record>
<!-- Resource: product.uom.categ -->
<record id="cat_expense" model="product.category">
<field name="parent_id" ref="product.product_category_all"/>
<field name="name">Expenses</field>
</record>
</data>
</openerp>

View File

@ -21,7 +21,7 @@
{
'name': 'Leaves Management',
'name': 'Leave Management',
'version': '1.5',
'author': 'OpenERP SA',
'category': 'Human Resources',
@ -29,8 +29,8 @@
'summary': 'Holidays, Allocation and Leave Requests',
'website': 'http://www.openerp.com',
'description': """
This module allows you to manage leaves and leave's requests.
=============================================================
This module allows you to manage leaves and leave requests.
===========================================================
Implements a dashboard for human resource management that includes:
-------------------------------------------------------------------

View File

@ -13,12 +13,15 @@
<field name="sequence">100</field>
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR people. Once validated, they are visible in the employee's calendar. HR people can define leave types and allocate off-days for employees.</value>
<value>Module Leaves Management has been installed</value>
</function>
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Leave Management application installed!</field>
<field name="body">Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR officers.
Once validated, they are visible in the employee's calendar. HR officers can define leave types and allocate leaves to employees and employee categories.</field>
</record>
<!-- Casual leave -->
<record model="hr.holidays.status" id="holiday_status_cl">

View File

@ -2,14 +2,15 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Manage job positions and the recruitment process in your company. This module is integrated with the module Survey to help you to define interviews for different jobs.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Recruitment Process application installed!</field>
<field name="body">Manage job positions and your company's recruitment process. This application is integrated with the Survey application to help you define interviews for different jobs.
You can automatically create application records from an email gateway, that you can configure in the Human Resources Settings.</value>
<value>Module Recruitment Process has been installed</value>
</function>
You can automatically receive job application though an email gateway, see the Human Resources settings.</field>
</record>
<!-- Meeting Types (for interview meetings) -->
<record model="crm.meeting.type" id="categ_meet_interview">

View File

@ -27,8 +27,8 @@
'sequence': 16,
'summary': 'Timesheets, Attendances, Activities',
'description': """
This module helps you to easily encode and validate timesheet and attendances within the same view.
===================================================================================================
This module helps you to easily record and validate timesheets and attendances within the same view.
====================================================================================================
* It will maintain attendances and track (sign in/sign out) events.
* Track the timesheet lines.

View File

@ -1,23 +1,23 @@
<?xml version="1.0" ?>
<openerp>
<data noupdate="1">
<!-- Notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>From the top menu "Human Resources", encode and validate timesheets and attendances.</value>
<value>Module Timesheets Validation has been installed</value>
</function>
<!-- notify all employees of module installation -->
<record model="mail.message" id="hr_timesheet_module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Timesheet Validation application installed!</field>
<field name="body">From the top menu "Human Resources", enter and validate timesheets and attendances.</field>
</record>
<record id="ir_actions_server_timsheet_sheet" model="ir.actions.server">
<field eval="5" name="sequence"/>
<field eval="&quot;&quot;&quot;code&quot;&quot;&quot;" name="state"/>
<field eval="&quot;&quot;&quot;ir.actions.server&quot;&quot;&quot;" name="type"/>
<field name="sequence" eval="5"/>
<field name="state">code</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_hr_timesheet_current_open"/>
<field eval="[(6,0,[])]" name="child_ids"/>
<field eval="&quot;&quot;&quot;action = pool.get('hr.timesheet.current.open').open_timesheet(cr, uid, None, context)&quot;&quot;&quot;" name="code"/>
<field eval="&quot;&quot;&quot;True&quot;&quot;&quot;" name="condition"/>
<field eval="&quot;&quot;&quot;My Timesheet&quot;&quot;&quot;" name="name"/>
<field name="code">action = pool.get('hr.timesheet.current.open').open_timesheet(cr, uid, None, context)</field>
<field name="condition">True</field>
<field name="name">My Timesheet</field>
</record>
<menuitem name="My Current Timesheet" id="menu_act_hr_timesheet_sheet_form_my_current" parent="hr_attendance.menu_hr_time_tracking" action="ir_actions_server_timsheet_sheet" sequence="1"/>

View File

@ -4,9 +4,9 @@
<record id="message_blogpost0" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="body"><![CDATA[Your monthly meal vouchers arrived. You can get them at Christine's office.
This month you also have 250 EUR of eco-checks for all employees that worked with us since 1 year minimum.]]></field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="body">Your monthly meal vouchers arrived. You can get them at Christine's office.
This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</field>
<field name="type">comment</field>
</record>
@ -21,7 +21,7 @@ This month you also have 250 EUR of eco-checks for all employees that worked wit
<record id="message_blogpost0_comment1" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="body"><![CDATA[Yes, that's a good news.]]></field>
<field name="body">Thanks, but where is Christine's office, if I may ask? (I'm new here)</field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
</record>
@ -29,16 +29,19 @@ This month you also have 250 EUR of eco-checks for all employees that worked wit
<record id="message_blogpost0_comment2" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="body"><![CDATA[Sure: Curabitur tempor bibendum diam, et euismod ante rutrum vel.
In quis purus neque. Integer sodales dolor eu elit fringilla blandit. Maecenas lacus nisi, facilisis sit amet viverra eu, tristique vel augue.
Donec viverra congue dui eu blandit. In lacinia molestie nulla, ut sagittis risus feugiat eu.
Check the file in attachment for more information ! (third comment)]]></field>
<field name="body">Great news, I need to buy a new fridge, I think I can pay it with the eco-vouchers!</field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
</record>
<record id="message_blogpost0_comment1_2" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="body">Building B3, second floor on the right :-)</field>
<field name="parent_id" ref="message_blogpost0_comment1"/>
<field name="type">comment</field>
</record>
<record model="ir.config_parameter" id="user_mail_alias">
<field name="key">mail.catchall.domain</field>
<field name="value">demo.openerp.com</field>

View File

@ -13,16 +13,16 @@
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- thread_id, body='', subject=False, msg_type='notification', parent_id=False -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Your homepage is a summary of messages you received and key information about documents you follow.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Welcome to OpenERP!</field>
<field name="body">Your homepage is a summary of messages you received and key information about documents you follow.
The top menu bar contains all applications you installed. You can use this &lt;i&gt;Settings&lt;/i&gt; menu to install more applications, activate others features or give access to new users.
To setup your preferences (name, email signature, avatar), click on the top right corner.</value>
<value>Welcome to OpenERP!</value>
</function>
To setup your preferences (name, email signature, avatar), click on the top right corner.</field>
</record>
</data>
</openerp>

View File

@ -83,19 +83,19 @@ class mail_notification(osv.Model):
if context.get('mail_noemail') or not partner_ids:
return True
mail_mail_obj = self.pool.get('mail.mail')
msg_obj = self.pool.get('mail.message')
msg = msg_obj.browse(cr, uid, msg_id, context=context)
mail_mail = self.pool.get('mail.mail')
msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context)
# add signature
body_html = msg.body
signature = msg.author_id and msg.author_id.user_ids[0].signature or ''
insertion_point = body_html.find('</html>')
if insertion_point > -1:
if signature:
signature_block = u'\n<pre>%s</pre>\n' % signature
insertion_point = body_html.find('</html>')
body_html = body_html[:insertion_point] + '<div>%s</div>' % tools.ustr(signature) + body_html[insertion_point:]
else:
body_html = body_html + '<div>%s</div>' % tools.ustr(signature)
if insertion_point > -1:
body_html = body_html[:insertion_point] + signature_block + body_html[insertion_point:]
else:
body_html += signature_block
towrite = {
'mail_message_id': msg.id,
@ -122,8 +122,8 @@ class mail_notification(osv.Model):
continue
if partner.email not in towrite['email_to']:
towrite['email_to'].append(partner.email)
towrite['email_to'] = ', '.join(towrite['email_to'])
email_notif_id = mail_mail_obj.create(cr, uid, towrite, context=context)
mail_mail_obj.send(cr, uid, [email_notif_id], context=context)
if towrite['email_to']:
towrite['email_to'] = ', '.join(towrite['email_to'])
email_notif_id = mail_mail.create(cr, uid, towrite, context=context)
mail_mail.send(cr, uid, [email_notif_id], context=context)
return True

View File

@ -54,10 +54,10 @@ class mail_mail(osv.Model):
'auto_delete': fields.boolean('Auto Delete',
help="Permanently delete this email after sending it, to save space"),
'references': fields.text('References', help='Message references, such as identifiers of previous messages', readonly=1),
'email_from': fields.char('From', size=128, help='Message sender, taken from user preferences.'),
'email_from': fields.char('From', help='Message sender, taken from user preferences.'),
'email_to': fields.text('To', help='Message recipients'),
'email_cc': fields.char('Cc', size=256, help='Carbon copy message recipients'),
'reply_to':fields.char('Reply-To', size=256, help='Preferred response address for the message'),
'email_cc': fields.char('Cc', help='Carbon copy message recipients'),
'reply_to':fields.char('Reply-To', help='Preferred response address for the message'),
'body_html': fields.text('Rich-text Contents', help="Rich-text/HTML message"),
}

View File

@ -340,21 +340,21 @@ class mail_message(osv.Model):
if subtype_id:
if subtype_id in [subtype.id for subtype in subscription.subtype_ids]:
is_subtype = True
partners_to_notify = []
partners_to_notify = set([])
# add all partner_ids of the message
if message.partner_ids:
for partner in message.partner_ids:
if partner.id not in partners_to_notify:
if(is_subtype):
partners_to_notify.append(partner.id)
# add all followers and set them as partner_ids
if(is_subtype):
partners_to_notify |= set(partner.id for partner in message.partner_ids)
# add all followers and set add them in partner_ids
if message.model and message.res_id:
modobj = self.pool.get(message.model)
for follower in modobj.browse(cr, uid, message.res_id, context=context).message_follower_ids:
if(is_subtype):
partners_to_notify.append(follower.id)
self.write(cr, uid, [newid], {'partner_ids': [(4, follower.id)]}, context=context)
self.pool.get('mail.notification').notify(cr, uid, partners_to_notify, newid, context=context)
record = self.pool.get(message.model).browse(cr, uid, message.res_id, context=context)
extra_notified = set(partner.id for partner in record.message_follower_ids)
missing_notified = extra_notified - partners_to_notify
if missing_notified:
message.write({'partner_ids': [(4, p_id) for p_id in missing_notified]})
if(is_subtype):
partners_to_notify |= extra_notified
self.pool.get('mail.notification').notify(cr, uid, list(partners_to_notify), newid, context=context)
def read(self, cr, uid, ids, fields_to_read=None, context=None, load='_classic_read'):
self.check(cr, uid, ids, 'read', context=context)

View File

@ -475,16 +475,25 @@ class mail_thread(osv.Model):
# plain text is wrapped in <pre/> to preserve formatting
text = u'<pre>%s</pre>' % tools.ustr(part.get_payload(decode=True),
encoding, errors='replace')
body = body[:insertion_point] + text + body[:insertion_point]
if insertion_point != -1:
body = body[:insertion_point] + text + body[insertion_point:]
else:
body += text
# 3) text/html -> raw
elif part.get_content_type() == 'text/html':
html = tools.ustr(part.get_payload(decode=True), encoding, errors='replace')
if alternative:
body = html
# force </html> tag to lowercase, for easier matching
body = re.sub(r'(?i)</html>', r'</html>', body)
else:
html = re.sub('(?i)</?html>', '', html)
# strip enclosing html/body tags and append to existing body
html = re.sub(r'(?i)(</?html>|</?body>)', '', html)
insertion_point = body.find('</html>')
body = body[:insertion_point] + text + body[:insertion_point]
if insertion_point != -1:
body = body[:insertion_point] + html + body[insertion_point:]
else:
body += html
# 4) Anything else -> attachment
else:
attachments.append((filename or 'attachment', part.get_payload(decode=True)))

View File

@ -97,7 +97,8 @@ class test_mail(common.TransactionCase):
'alias_model_id': self.mail_group_model_id})
# create a 'pigs' group that will be used through the various tests
self.group_pigs_id = self.mail_group.create(self.cr, self.uid, {'name': 'pigs'})
self.group_pigs_id = self.mail_group.create(self.cr, self.uid,
{'name': 'Pigs', 'description': 'Fans of Pigs, unite !'})
def test_00_message_process(self):
cr, uid = self.cr, self.uid
@ -150,69 +151,47 @@ class test_mail(common.TransactionCase):
{'res_model': 'mail.group', 'res_id': group_dummy_id, 'partner_id': partner_bert_id})
# Pigs just created: should be only Admin as follower
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
self.assertTrue(len(follower_ids) == 1,
'Newly created group should have only 1 follower')
self.assertTrue(user_admin.partner_id.id in follower_ids,
'Admin should be the only Pigs group follower')
follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan')
# Subscribe Bert through a '4' command
group_pigs.write({'message_follower_ids': [(4, partner_bert_id)]})
group_pigs.refresh()
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
self.assertTrue(len(follower_ids) == 2,
'Pigs group should have 2 followers after linking Bert')
self.assertTrue(all(id in follower_ids for id in [partner_bert_id, user_admin.partner_id.id]),
'Bert and Admin should be the 2 Pigs group followers')
follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
self.assertEqual(follower_ids, set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the only Pigs fans')
# Unsubscribe Bert through a '3' command
group_pigs.write({'message_follower_ids': [(3, partner_bert_id)]})
group_pigs.refresh()
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
self.assertTrue(len(follower_ids) == 1,
'Pigs group should have 1 follower after unlinking Bert')
self.assertTrue(all(id in follower_ids for id in [user_admin.partner_id.id]),
'Admin should be the only Pigs group follower')
follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan')
# Set followers through a '6' command
group_pigs.write({'message_follower_ids': [(6, 0, [partner_bert_id])]})
group_pigs.refresh()
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
self.assertTrue(len(follower_ids) == 1,
'Pigs group should have 1 follower after replacing followers')
self.assertTrue(follower_ids == [partner_bert_id],
'Bert should be the only Pigs group follower')
follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the only Pigs fan')
# Add a follower created on the fly through a '0' command
group_pigs.write({'message_follower_ids': [(0, 0, {'name': 'Patrick Fiori'})]})
partner_patrick_id = self.res_partner.search(cr, uid, [('name', '=', 'Patrick Fiori')])[0]
group_pigs.refresh()
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
self.assertTrue(len(follower_ids) == 2,
'Pigs group should have 2 followers after linking to new partner')
self.assertTrue(all(id in follower_ids for id in [partner_bert_id, partner_patrick_id]),
'Bert and Patrick should be Pigs group followers')
follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
self.assertEqual(follower_ids, set([partner_bert_id, partner_patrick_id]), 'Bert and Patrick should be the only Pigs fans')
# Finally, unlink through a '5' command
group_pigs.write({'message_follower_ids': [(5, 0)]})
group_pigs.refresh()
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
self.assertTrue(len(follower_ids) == 0,
'Pigs group should not have followers anymore')
follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
self.assertFalse(follower_ids, 'Pigs group should not have fans anymore')
# Test dummy data has not been altered
fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.thread'), ('res_id', '=', self.group_pigs_id)])
follower_ids = [follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)]
self.assertTrue(len(follower_ids) == 1,
'mail.thread dummy data should have 1 follower')
self.assertTrue(follower_ids[0] == partner_bert_id,
'Bert should be the follower of dummy mail.thread data')
follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)])
self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the follower of dummy mail.thread data')
fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', group_dummy_id)])
follower_ids = [follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)]
self.assertTrue(len(follower_ids) == 2,
'mail.group dummy data should have 2 followers')
self.assertTrue(all(id in follower_ids for id in [partner_bert_id, user_admin.partner_id.id]),
'Bert and Admin should be the followers of dummy mail.group data')
follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)])
self.assertEqual(follower_ids,set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the followers of dummy mail.group data')
def test_11_message_followers(self):
""" Tests designed for the subscriber API. """
@ -227,21 +206,14 @@ class test_mail(common.TransactionCase):
# Subscribe Raoul twice (niak niak) through message_subscribe_users
group_pigs.message_subscribe_users([user_raoul_id, user_raoul_id])
group_pigs.refresh()
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
self.assertTrue(len(follower_ids) == 2,
'Pigs group should have 2 followers after having subscribed Raoul. Subscribing twice '\
'the same user should create only one follower.')
self.assertTrue(all(id in follower_ids for id in [user_raoul.partner_id.id, user_admin.partner_id.id]),
'Admin and Raoul should be the 2 Pigs group followers')
follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
self.assertEqual(follower_ids, set([user_raoul.partner_id.id, user_admin.partner_id.id]), 'Admin and Raoul should be the only 2 Pigs group followers')
# Unsubscribe Raoul twice through message_unsubscribe_users
group_pigs.message_unsubscribe_users([user_raoul_id, user_raoul_id])
group_pigs.refresh()
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
self.assertTrue(len(follower_ids) == 1,
'Pigs group should have 1 follower after unsubscribing Raoul')
self.assertTrue(all(id in follower_ids for id in [user_admin.partner_id.id]),
'Admin the only Pigs group followers')
follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin must be the only Pigs fan')
def test_20_message_post(self):
""" Tests designed for message_post. """
@ -266,97 +238,72 @@ class test_mail(common.TransactionCase):
_subject = 'Pigs'
_mail_subject = '%s posted on %s' % (user_admin.name, group_pigs.name)
_body1 = 'Pigs rules'
_mail_body1 = 'Pigs rules<div>Admin</div>'
_mail_body1 = 'Pigs rules\n<pre>Admin</pre>\n'
_mail_bodyalt1 = 'Pigs rules\nAdmin'
_body2 = '<html>Pigs rules</html>'
_mail_body2 = '<html>Pigs rules<div>Admin</div></html>'
_mail_bodyalt2 = 'Pigs rules\nAdmin'
_mail_body2 = '<html>Pigs rules\n<pre>Admin</pre>\n</html>'
_mail_bodyalt2 = 'Pigs rules\nAdmin\n'
# Post comment with body and subject, comment preference
msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body1, subject=_subject, msg_type='comment')
# Fetch: created mail_message, mail_mail, send_email
# Fetch: created mail_message, mail_mail, sent_email
message = self.mail_message.browse(cr, uid, msg_id)
mail_ids = self.mail_mail.search(cr, uid, [], limit=1)
mail = self.mail_mail.browse(cr, uid, mail_ids[0])
send_email = self._build_email_kwargs
sent_email = self._build_email_kwargs
# Test: mail_message: subject is _subject, body is _body1 (no formatting done)
self.assertEqual(message.subject, _subject,
'mail.message subject is %s; should be %s' % (message.subject, _subject))
self.assertEqual(message.body, _body1,
'mail.message body is %s; should be %s' % (message.body, _body1))
self.assertEqual(message.subject, _subject, 'mail.message subject incorrect')
self.assertEqual(message.body, _body1, 'mail.message body incorrect')
# Test: mail_mail: subject is _subject, body_html is _mail_body1 (signature appended)
self.assertEqual(mail.subject, _subject,
'mail.mail subject is %s; should be %s' % (mail.subject, _subject))
self.assertEqual(mail.body_html, _mail_body1,
'mail.mail body_html is %s; should be %s' % (mail.body_html, _mail_body1))
self.assertTrue(mail.mail_message_id and mail.mail_message_id.id == msg_id,
'mail_mail.mail_message_id is not the id of its related mail_message; got %s, should be %s' % (mail.mail_message_id.id, msg_id))
# Test: send_email: email send by server: correct subject and body
self.assertEqual(send_email['subject'], _subject,
'send_email subject is %s; should be %s' % (send_email['subject'], _subject))
self.assertEqual(send_email['body'], _mail_body1,
'send_email body is %s; should be %s' % (send_email['body'], _mail_body1))
self.assertEqual(send_email['body_alternative'], _mail_bodyalt1,
'send_email body_alternative is %s; should be %s' % (send_email['body_alternative'], _mail_bodyalt1))
self.assertEqual(mail.subject, _subject, 'mail.mail subject incorrect')
self.assertEqual(mail.body_html, _mail_body1, 'mail.mail body_html incorrect')
self.assertEqual(mail.mail_message_id.id, msg_id, 'mail_mail.mail_message_id is not the id of its related mail_message)')
# Test: sent_email: email send by server: correct subject and body
self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
self.assertEqual(sent_email['body'], _mail_body1, 'sent_email body incorrect')
self.assertEqual(sent_email['body_alternative'], _mail_bodyalt1, 'sent_email body_alternative is incorrect')
# Test: mail_message: partner_ids = group followers
message_pids = [partner.id for partner in message.partner_ids]
test_pids = [p_a_id, p_b_id, p_c_id]
self.assertTrue(all(pid in message_pids for pid in test_pids) and len(message_pids) == len(test_pids),
'mail.message partners are %s; should be %s' % (message_pids, test_pids))
message_pids = set([partner.id for partner in message.partner_ids])
test_pids = set([p_a_id, p_b_id, p_c_id])
self.assertEqual(test_pids, message_pids, 'mail.message partners incorrect')
# Test: notification linked to this message = group followers = partner_ids
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
notif_pids = [notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)]
self.assertTrue(all(pid in notif_pids for pid in test_pids) and len(notif_pids) == len(test_pids),
'mail.message notification partners are %s; should be %s' % (notif_pids, test_pids))
# Test: send_email: email_to should contain b@b, not c@c (pref email), not a@a (writer)
test_emails = ['b@b']
self.assertTrue(all(email in send_email['email_to'] for email in test_emails) and len(send_email['email_to']) == len(test_emails),
'send_email email_to is %s; should be %s' % (send_email['email_to'], test_emails))
notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)])
self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect')
# Test: sent_email: email_to should contain b@b, not c@c (pref email), not a@a (writer)
self.assertEqual(sent_email['email_to'], ['b@b'], 'sent_email email_to is incorrect')
# New post: test automatic subject, signature in html, add a partner, email preference, parent_id previous message
msg_id2 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body2, msg_type='email', partner_ids=[(6, 0, [p_d_id])], parent_id=msg_id)
# Fetch: created mail_message, mail_mail, send_email
# Fetch: created mail_message, mail_mail, sent_email
message = self.mail_message.browse(cr, uid, msg_id2)
mail_ids = self.mail_mail.search(cr, uid, [], limit=1)
mail = self.mail_mail.browse(cr, uid, mail_ids[0])
send_email = self._build_email_kwargs
sent_email = self._build_email_kwargs
# Test: mail_message: subject is False, body is _body1 (no formatting done), parent_id is msg_id
self.assertEqual(message.subject, False,
'mail.message subject is %s; should be %s' % (message.subject, False))
self.assertEqual(message.body, _body2,
'mail.message body is %s; should be %s' % (message.body, _body2))
self.assertEqual(message.parent_id.id, msg_id,
'mail.message parent_id is %s; should be %s' % (message.parent_id.id, msg_id))
self.assertEqual(message.subject, False, 'mail.message subject incorrect')
self.assertEqual(message.body, _body2, 'mail.message body incorrect')
self.assertEqual(message.parent_id.id, msg_id, 'mail.message parent_id incorrect')
# Test: mail_mail: subject is False, body_html is _mail_body1 (signature appended)
self.assertEqual(mail.subject, False,
'mail.mail subject is %s; should be %s' % (mail.subject, False))
self.assertEqual(mail.body_html, _mail_body2,
'mail.mail body_html is %s; should be %s' % (mail.body_html, _mail_body2))
self.assertTrue(mail.mail_message_id and mail.mail_message_id.id == msg_id2,
'mail_mail.mail_message_id is not the id of its related mail_message; got %s, should be %s' % (mail.mail_message_id.id, msg_id2))
# Test: send_email: email send by server: correct subject and body
self.assertEqual(send_email['subject'], _mail_subject,
'send_email subject is %s; should be %s' % (send_email['subject'], _mail_subject))
self.assertEqual(send_email['body'], _mail_body2,
'send_email body is %s; should be %s' % (send_email['body'], _mail_body2))
self.assertEqual(send_email['body_alternative'], _mail_bodyalt2,
'send_email body_alternative is %s; should be %s' % (send_email['body_alternative'], _mail_bodyalt2))
self.assertEqual(mail.subject, False, 'mail.mail subject is incorrect')
self.assertEqual(mail.body_html, _mail_body2, 'mail.mail body_html incorrect')
self.assertEqual(mail.mail_message_id.id, msg_id2, 'mail_mail.mail_message_id incorrect')
# Test: sent_email: email send by server: correct subject and body
self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect')
self.assertEqual(sent_email['body'], _mail_body2, 'sent_email body incorrect')
self.assertEqual(sent_email['body_alternative'], _mail_bodyalt2, 'sent_email body_alternative incorrect')
# Test: mail_message: partner_ids = group followers
message_pids = [partner.id for partner in message.partner_ids]
test_pids = [p_a_id, p_b_id, p_c_id, p_d_id]
self.assertTrue(all(pid in message_pids for pid in test_pids) and len(message_pids) == len(test_pids),
'mail.message partners are %s; should be %s' % (message_pids, test_pids))
message_pids = set([partner.id for partner in message.partner_ids])
test_pids = set([p_a_id, p_b_id, p_c_id, p_d_id])
self.assertEqual(message_pids, test_pids, 'mail.message partners incorrect')
# Test: notification linked to this message = group followers = partner_ids
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
notif_pids = [notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)]
self.assertTrue(all(pid in notif_pids for pid in test_pids) and len(notif_pids) == len(test_pids),
'mail.message notification partners are %s; should be %s' % (notif_pids, test_pids))
# Test: send_email: email_to should contain b@b, c@c, not a@a (writer)
test_emails = ['b@b', 'c@c']
self.assertTrue(all(email in send_email['email_to'] for email in test_emails) and len(send_email['email_to']) == len(test_emails),
'send_email email_to is %s; should be %s' % (send_email['email_to'], test_emails))
notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)])
self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect')
# Test: sent_email: email_to should contain b@b, c@c, not a@a (writer)
self.assertEqual(set(sent_email['email_to']), set(['b@b', 'c@c']), 'sent_email email_to incorrect')
def test_21_message_post_attachments(self):
""" Tests designed for attachments. """
@ -429,6 +376,26 @@ class test_mail(common.TransactionCase):
self.assertEqual(compose.parent_id.id, msg.id,
'Wizard parent_id is %d; should be %d' % (compose.parent_id.id, msg.id))
# 3 - Create in mass_mail composition mode that should work with or without email_template installed
compose_id = mail_compose.create(cr, uid,
{'subject': _subject, 'body': '${object.description}'},
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group', 'default_res_id': -1,
'active_ids': [self.group_pigs_id]})
compose = mail_compose.browse(cr, uid, compose_id)
# Post the comment, get created message
mail_compose.send_mail(cr, uid, [compose_id], {'default_res_id': -1, 'active_ids': [self.group_pigs_id]})
group_pigs.refresh()
msg = group_pigs.message_ids[0]
# Test: last message on Pigs = last created message
test_msg = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [], limit=1))[0]
self.assertEqual(msg.id, test_msg.id, 'Pigs did not receive its mass mailing message')
# Test: mail.message: subject, body
self.assertEqual(msg.subject, _subject, 'mail.message subject is incorrect')
self.assertEqual(msg.body, group_pigs.description, 'mail.message body is incorrect')
def test_30_message_read(self):
""" Tests designed for message_read. """
def _simplify_struct(read_dict):

View File

@ -68,17 +68,19 @@ class mail_compose_message(osv.TransientModel):
result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
# get some important values from context
composition_mode = context.get('mail.compose.message.mode')
composition_mode = context.get('default_composition_mode', context.get('mail.compose.message.mode'))
model = context.get('default_model', context.get('active_model'))
res_id = context.get('default_res_id', context.get('active_id'))
active_id = context.get('active_id')
active_ids = context.get('active_ids')
# get default values according to the composition mode
if composition_mode in ['reply']:
if composition_mode == 'reply':
vals = self.get_message_data(cr, uid, active_id, context=context)
elif composition_mode in ['comment', 'mass_mail'] and model and res_id:
elif composition_mode == 'comment' and model and res_id:
vals = self.get_record_data(cr, uid, model, res_id, context=context)
elif composition_mode == 'mass_mail' and model and active_ids:
vals = {'model': model, 'res_id': res_id, 'content_subtype': 'html'}
else:
vals = {'model': model, 'res_id': res_id}
if composition_mode:
@ -189,91 +191,107 @@ class mail_compose_message(osv.TransientModel):
""" onchange_content_subtype (values: 'plain' or 'html'). This onchange
on the subtype allows to have some specific behavior when switching
between text or html mode.
Basically, subject is reset when going out of html mode.
This method can be overridden for models that want to have their
specific behavior.
"""
specific behavior. """
return {'value': {'content_subtype': value}}
def _verify_partner_email(self, cr, uid, partner_ids, context=None):
""" Verify that selected partner_ids have an email_address defined.
Otherwise throw a warning. """
partner_wo_email_lst = []
for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context):
if not partner.email:
partner_wo_email_lst.append(partner)
if not partner_wo_email_lst:
return {}
warning_msg = _('The following partners chosen as recipients for the email have no email address linked :')
for partner in partner_wo_email_lst:
warning_msg += '\n- %s' % (partner.name)
return {'warning': {
'title': _('Partners email addresses not found'),
'message': warning_msg }
}
def onchange_partner_ids(self, cr, uid, ids, value, context=None):
""" onchange_partner_ids (value format: [[6, False, [3, 4]]]). The
basic purpose of this method is to check that destination partners
effectively have email addresses. Otherwise a warning is thrown.
"""
partner_ids = value[0][2]
partner_wo_email_lst = []
for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context):
if not partner.email:
partner_wo_email_lst.append(partner)
if not partner_wo_email_lst:
return {'value': {}}
warning_msg = _('The following partners chosen as recipients for the email have no email address linked :')
for partner in partner_wo_email_lst:
warning_msg += '\n- %s' % (partner.name)
warning = {
'title': _('Partners email addresses not found'),
'message': warning_msg,
}
return {'warning': warning, 'value': {}}
res = {'value': {}}
if not value or not value[0] or not value[0][0] == 6:
return
res.update(self._verify_partner_email(cr, uid, value[0][2], context=context))
return res
def send_mail(self, cr, uid, ids, context=None):
""" Process the wizard content and proceed with sending the related
email(s), rendering any template patterns on the fly if needed. """
if context is None:
context = {}
active_ids = context.get('active_ids')
for wizard in self.browse(cr, uid, ids, context=context):
mass_mail_mode = wizard.composition_mode == 'mass_mail'
attachment = {}
for attach in wizard.attachment_ids:
attachment[attach.datas_fname] = attach.datas and attach.datas or False
# default values, according to the wizard options
subject = wizard.subject if wizard.content_subtype == 'html' else False
partner_ids = [(4, partner.id) for partner in wizard.partner_ids]
body = wizard.body if wizard.content_subtype == 'html' else '<pre>%s</pre>' % tools.ustr(wizard.body_text)
active_model_pool = self.pool.get(wizard.model if wizard.model else 'mail.thread')
#TODO: TDE: WIP: have to check for mass mail and templates - no time anymore today
if context.get('mail.compose.message.mode') == 'mass_mail' and context.get('default_model', False) and context.get('default_res_id', False):
active_model = context.get('default_model', False)
active_model_pool = self.pool.get(active_model)
subject = self.render_template(cr, uid, subject, active_model, active_id)
body = self.render_template(cr, uid, wizard.body, active_model, active_id)
# TODO TDE: find partner_ids
# if email_to: find or create a partner
if values['email_to']:
partner_id = self.pool.get('mail.thread').message_partner_by_email(cr, uid, values['email_to'], context=context)['partner_id']
if not partner_id:
partner_id = self.pool.get('res.partner').name_create(cr, uid, values['email_to'], context=context)
values['partner_ids'] = [partner_id]
# determine the ids we are commenting
if mass_mail_mode:
res_ids = context.get('active_ids', [])
else:
res_ids = [wizard.res_id]
active_model_pool.message_post(cr, uid, res_ids, body=body, subject=subject, msg_type='comment',
attachments=attachment, context=context, partner_ids=partner_ids)
# wizard works in batch mode: [res_id] or active_ids
res_ids = active_ids if mass_mail_mode and wizard.model and active_ids else [wizard.res_id]
for res_id in res_ids:
# default values, according to the wizard options
post_values = {
'subject': wizard.subject if wizard.content_subtype == 'html' else False,
'body': wizard.body if wizard.content_subtype == 'html' else '<pre>%s</pre>' % tools.ustr(wizard.body_text),
'partner_ids': [(4, partner.id) for partner in wizard.partner_ids],
'attachments': [(attach.datas_fname, attach.datas) for attach in wizard.attachment_ids],
}
# mass mailing: render and override default values
if mass_mail_mode and wizard.model:
email_dict = self.render_message(cr, uid, wizard, wizard.model, res_id, context=context)
post_values['subject'] = email_dict.get('subject', False)
post_values['body'] = email_dict.get('body', '')
if email_dict.get('partner_ids'):
post_values['partner_ids'] += [(4, id) for id in email_dict.get('partner_ids')]
if email_dict.get('attachments'):
post_values['attachments'] += [(attach.datas_fname, attach.datas) for attach in email_dict.get('attachments')]
# post the message
active_model_pool.message_post(cr, uid, res_ids, msg_type='comment', context=context, **post_values)
return {'type': 'ir.actions.act_window_close'}
def render_message(self, cr, uid, wizard, model, res_id, context=None):
""" Generate an email from the template for given (model, res_id) pair.
This method is meant to be inherited by email_template that will
produce a more complete dictionary, with email_to, ...
"""
# TDE: TODO: to move into mail.compose.message in email template
# mails = tools.email_split(email_dict.get('email_to', '')) + tools.email_split(email_dict.get('email_cc', ''))
# for mail in mails:
# partner_search_ids = self.pool.get('res.partner').search(cr, uid, [('email', 'ilike', email)], context=context)
# if partner_search_ids:
# partner_ids.append((4, 0, partner_search_ids[0]))
# else:
# partner_id = self.pool.get('res.partner').name_create(cr, uid, values['email_to'], context=context)
# partner_ids.append((4, 0, partner_id))
return {
'subject': self.render_template(cr, uid, wizard.subject, model, res_id, context),
'body': self.render_template(cr, uid, wizard.body, model, res_id, context),
'partner_ids': [],
'attachment_ids': [],
}
def render_template(self, cr, uid, template, model, res_id, context=None):
"""Render the given template text, replace mako-like expressions ``${expr}``
with the result of evaluating these expressions with an evaluation context
containing:
""" Render the given template text, replace mako-like expressions ``${expr}``
with the result of evaluating these expressions with an evaluation context
containing:
* ``user``: browse_record of the current user
* ``object``: browse_record of the document record this mail is
related to
* ``context``: the context passed to the mail composition wizard
:param str template: the template text to render
:param str model: model name of the document record this mail is related to.
:param int res_id: id of the document record this mail is related to.
:param str template: the template text to render
:param str model: model name of the document record this mail is related to.
:param int res_id: id of the document record this mail is related to.
"""
if context is None:
context = {}

View File

@ -7,6 +7,7 @@
<field name="arch" type="xml">
<form string="Compose Email" version="7.0">
<group>
<field name="composition_mode" invisible="1"/>
<field name="model" invisible="1"/>
<field name="res_id" invisible="1"/>
<field name="author_id"/>
@ -38,11 +39,11 @@
<field name="arch" type="xml">
<form string="Compose Email" version="7.0" >
<group>
<!-- truly invisible fields for control and options -->
<field name="composition_mode" colspan="2" nolabel="1" invisible="1"/>
<field name="model" colspan="2" nolabel="1" invisible="1"/>
<field name="res_id" colspan="2" nolabel="1" invisible="1"/>
<field name="parent_id" colspan="2" nolabel="1" invisible="1"/>
<!-- truly invisible fields for control and options -->
<field name="content_subtype" colspan="2" nolabel="1" invisible="1"/>
<!-- visible wizard -->
<field name="subject" colspan="2" nolabel="1" placeholder="Subject..."
@ -63,14 +64,15 @@
class="oe_mail_compose_message_attachment_ids"/>
<!-- void div to display attachments, Chatter-controlled -->
<div colspan="2" class="oe_mail_compose_message_attachments"/>
<!-- buttons, mostly Chatter-controlled -->
<!-- buttons, with as few Chatter logic as possible -->
<div>
<button name="send_mail" string="Post" type="object"
class="oe_mail_compose_message_button_send"/>
</div>
<div class='oe_mail_compose_message_icons'>
<button icon="/mail/static/src/img/attachment.png" name="dummy"
<button icon="/mail/static/src/img/attachment.png"
class="oe_mail_compose_message_attachment" string=""
name="dummy"
help="Add an attachment"/>
<button icon="/mail/static/src/img/formatting.png"
class="oe_mail_compose_message_formatting" string=""
@ -100,6 +102,6 @@
target="new"
key2="client_action_multi"
id="base.action_partner_mass_mail"
context="{'mail.compose.message.mode':'mass_mail'}"/>
context="{'default_composition_mode': 'mass_mail'}"/>
</data>
</openerp>

View File

@ -2,14 +2,16 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Manage your manufacturing process in OpenERP by defining bill of materials (BoM), routings and work centers. This module supports complete integration and planification of stockable goods, consumable, and services.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">MRP application installed!</field>
<field name="body">Manage your manufacturing process with OpenERP by defining your bills of materials (BoM), routings and work centers.
This application supports complete integration and production scheduling for stockable goods, consumables, and services.
From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time.</value>
<value>Module MRP has been installed</value>
</function>
From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time.</field>
</record>
<record id="sequence_mrp_prod_type" model="ir.sequence.type">
<field name="name">Production order</field>

View File

@ -24,14 +24,15 @@
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Encode sale orders, register payments, compute money to return, create invoices, and manage refunds of former sales through a specific, web-based, touch-screen user interface.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Point of Sale application installed!</field>
<field name="body">Record sale orders, register payments, compute change to return, create invoices, and manage refunds through a specific web touch-screen interface.
If you install the PoS proxy, you will be able to interface OpenERP with retail materials; barcode scanners, printers, cash registers, weighing machine, credit card payments.</value>
<value>Module Point of Sale has been installed</value>
</function>
If you install the PoS proxy you will be able to interface OpenERP with retail hardware: barcode scanners, printers, cash registers, weighing machines, credit card payment terminals.</field>
</record>
<record id="unreferenced_product" model="product.product">
<field name="list_price">1.00</field>

View File

@ -124,13 +124,15 @@
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Manage multi-level projects and tasks. You can delegate tasks, track the work done on tasks, and review your planning based on the entered data.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Project Management application installed!</field>
<field name="body">Manage multi-level projects and tasks. You can delegate tasks, track task work, and review your planning.
You can manage todo lists on tasks by installing the module "Todo Lists", which supports the methodology Getting Things Done (GTD). You can also manage issues/bugs in projects by installing the module "Issues Tracker."</value>
<value>Module Project Management has been installed</value>
</function>
You can manage todo lists on tasks by installing the "Todo Lists" application, supporting the Getting Things Done (GTD) methodology.
You can also manage issues/bugs in projects by installing the "Issue Tracker" application.</field>
</record>
</data>
</openerp>

View File

@ -26,11 +26,14 @@
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Add todo items on project tasks, to help you organize your work. This module supports the methodology Getting Things Done (GTD), created by David Allen, and described in the book of the same name.</value>
<value>Module Todo Lists has been installed</value>
</function>
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Todo Lists application installed!</field>
<field name="body">Add todo items on project tasks, to help you organize your work.
This application supports the Getting Things Done (GTD) methodology, based on David Allen's book.</field>
</record>
</data>
</openerp>

View File

@ -21,11 +21,11 @@
##############################################################################
{
'name': 'Issues Tracker',
'name': 'Issue Tracker',
'version': '1.0',
'category': 'Project Management',
'sequence': 22,
'summary': 'Support, Bug Traker, Helpdesk',
'summary': 'Support, Bug Tracker, Helpdesk',
'description': """
This module provides Issues/Bugs Management in Project.
=======================================================

View File

@ -32,13 +32,15 @@
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Manage the issues you might face in a project, like bugs in a system, client complaints or material breakdowns. You can record issues, assign them to some responsible person, and keep track of their status as they evolve over time.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Issue Tracker application installed!</field>
<field name="body">Manage the issues you might face in a project, such as bugs in a system, client complaints or material breakdowns.
You can record issues, assign them to a responsible person, and keep track of their status as they evolve over time.
Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view.</field>
</record>
You can access issues from the top menu Project, and access the issues of a specific project from the projects gallery view.</value>
<value>Module Issues Tracker has been installed.</value>
</function>
</data>
</openerp>

View File

@ -3,14 +3,15 @@
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>From the top menu Purchases, create purchase orders to buy products from your suppliers, encode supplier invoices and manage your payments.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Purchase Management application installed!</field>
<field name="body">From the top menu Purchases, create purchase orders to buy products from your suppliers, enter supplier invoices and manage payments.
You can also manage purchase requisitions, see the Purchase Settings.</value>
<value>Module Purchase Management has been installed.</value>
</function>
You can also manage purchase requisitions, see also the Purchase Settings.</field>
</record>
<record id="req_link_purchase_order" model="res.request.link">
<field name="name">Purchase Order</field>

View File

@ -41,13 +41,14 @@
<function eval="('default',False,'shop_id', [('sale.order', False)], sale_shop_1, True, False, False, False, True)" id="sale_default_set" model="ir.values" name="set"/>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>This modules allows you to create and send easily quotations and process your sales orders; from the delivery to the invoicing.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Sales Management application installed!</field>
<field name="body">This application lets you create and send quotations and process your sales orders; from delivery to invoicing.
If you need to manage your sales pipeline (leads, opportunities, phonecalls), you can install the module &lt;i&gt;CRM&lt;/i&gt; from the top menu Settings.</value>
<value>The Sales Management application has been installed.</value>
</function>
If you need to manage your sales pipeline (leads, opportunities, phonecalls), the &lt;i&gt;CRM&lt;/i&gt; application may be useful. Use the Settings menu to install it.</field>
</record>
</data>
</openerp>

View File

@ -2,12 +2,14 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_post">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Manage your product inventoy and stock locations. You can control your stock moves history and planning, perform stock valuation, and trace product lots upstream and downstream (based on serial numbers.)</value>
<value>Module Warehouse Management has been installed</value>
</function>
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Warehouse Management application installed!</field>
<field name="body">Manage your product inventoy and stock locations: you can control stock moves history and planning,
watch your stock valuation, and track production lots upstream and downstream (based on serial numbers).</field>
</record>
<record id="stock_journal_sequence" model="ir.sequence">
<field name="name">Stock Journal Sequence</field>