[MERGE] Sync with turnk
This commit is contained in:
commit
46235aa78c
|
@ -542,18 +542,17 @@ class account_analytic_account(osv.osv):
|
||||||
'nodestroy': True,
|
'nodestroy': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
def on_change_template(self, cr, uid, ids, template_id, date_start=False, fix_price_invoices=False, invoice_on_timesheets=False, recurring_invoices=False, context=None):
|
def on_change_template(self, cr, uid, ids, template_id, date_start=False, context=None):
|
||||||
if not template_id:
|
if not template_id:
|
||||||
return {}
|
return {}
|
||||||
obj_analytic_line = self.pool.get('account.analytic.invoice.line')
|
|
||||||
res = super(account_analytic_account, self).on_change_template(cr, uid, ids, template_id, date_start=date_start, context=context)
|
res = super(account_analytic_account, self).on_change_template(cr, uid, ids, template_id, date_start=date_start, context=context)
|
||||||
|
|
||||||
template = self.browse(cr, uid, template_id, context=context)
|
template = self.browse(cr, uid, template_id, context=context)
|
||||||
|
|
||||||
if not fix_price_invoices:
|
if not ids:
|
||||||
res['value']['fix_price_invoices'] = template.fix_price_invoices
|
res['value']['fix_price_invoices'] = template.fix_price_invoices
|
||||||
res['value']['amount_max'] = template.amount_max
|
res['value']['amount_max'] = template.amount_max
|
||||||
if not invoice_on_timesheets:
|
if not ids:
|
||||||
res['value']['invoice_on_timesheets'] = template.invoice_on_timesheets
|
res['value']['invoice_on_timesheets'] = template.invoice_on_timesheets
|
||||||
res['value']['hours_qtt_est'] = template.hours_qtt_est
|
res['value']['hours_qtt_est'] = template.hours_qtt_est
|
||||||
|
|
||||||
|
@ -561,7 +560,7 @@ class account_analytic_account(osv.osv):
|
||||||
res['value']['to_invoice'] = template.to_invoice.id
|
res['value']['to_invoice'] = template.to_invoice.id
|
||||||
if template.pricelist_id.id:
|
if template.pricelist_id.id:
|
||||||
res['value']['pricelist_id'] = template.pricelist_id.id
|
res['value']['pricelist_id'] = template.pricelist_id.id
|
||||||
if not recurring_invoices:
|
if not ids:
|
||||||
invoice_line_ids = []
|
invoice_line_ids = []
|
||||||
for x in template.recurring_invoice_line_ids:
|
for x in template.recurring_invoice_line_ids:
|
||||||
invoice_line_ids.append((0, 0, {
|
invoice_line_ids.append((0, 0, {
|
||||||
|
|
|
@ -38,9 +38,6 @@
|
||||||
<field name="partner_id" position="attributes">
|
<field name="partner_id" position="attributes">
|
||||||
<attribute name="attrs">{'required': [('type','=','contract'),'|','|',('fix_price_invoices','=',True), ('invoice_on_timesheets', '=', True), ('recurring_invoices', '=', True)]}</attribute>
|
<attribute name="attrs">{'required': [('type','=','contract'),'|','|',('fix_price_invoices','=',True), ('invoice_on_timesheets', '=', True), ('recurring_invoices', '=', True)]}</attribute>
|
||||||
</field>
|
</field>
|
||||||
<field name="template_id" position="attributes">
|
|
||||||
<attribute name="on_change">on_change_template(template_id, date_start, fix_price_invoices, invoice_on_timesheets, recurring_invoices)</attribute>
|
|
||||||
</field>
|
|
||||||
<xpath expr='//group[@name="invoice_on_timesheets"]' position="replace">
|
<xpath expr='//group[@name="invoice_on_timesheets"]' position="replace">
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr='//separator[@name="description"]' position='before'>
|
<xpath expr='//separator[@name="description"]' position='before'>
|
||||||
|
|
|
@ -363,7 +363,10 @@ openerp.base_import = function (instance) {
|
||||||
var fields = this.$('.oe_import_fields input.oe_import_match_field').map(function (index, el) {
|
var fields = this.$('.oe_import_fields input.oe_import_match_field').map(function (index, el) {
|
||||||
return $(el).select2('val') || false;
|
return $(el).select2('val') || false;
|
||||||
}).get();
|
}).get();
|
||||||
kwargs.context = this.parent_context;
|
kwargs.context = _.extend(
|
||||||
|
{}, this.parent_context,
|
||||||
|
{tracking_disable: !this.$('#oe_import_tracking').prop('checked')}
|
||||||
|
);
|
||||||
return this.Import.call('do', [this.id, fields, this.import_options()], kwargs)
|
return this.Import.call('do', [this.id, fields, this.import_options()], kwargs)
|
||||||
.then(undefined, function (error, event) {
|
.then(undefined, function (error, event) {
|
||||||
// In case of unexpected exception, convert
|
// In case of unexpected exception, convert
|
||||||
|
|
|
@ -53,6 +53,15 @@
|
||||||
|
|
||||||
<div class="oe_import_with_file oe_padding">
|
<div class="oe_import_with_file oe_padding">
|
||||||
<h2>Map your data to OpenERP</h2>
|
<h2>Map your data to OpenERP</h2>
|
||||||
|
<div title="If the model uses openchatter, history tracking
|
||||||
|
will set up subscriptions and send notifications
|
||||||
|
during the import, but lead to a slower import.">
|
||||||
|
<input type="checkbox" id="oe_import_tracking"
|
||||||
|
checked="checked"/>
|
||||||
|
<label for="oe_import_tracking">
|
||||||
|
Track history during import
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<input type="checkbox" class="oe_import_has_header"
|
<input type="checkbox" class="oe_import_has_header"
|
||||||
id="oe_import_has_header" checked="checked"/>
|
id="oe_import_has_header" checked="checked"/>
|
||||||
<label for="oe_import_has_header">The first row of the
|
<label for="oe_import_has_header">The first row of the
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<field name="subject">Your registration at ${object.event_id.name}</field>
|
<field name="subject">Your registration at ${object.event_id.name}</field>
|
||||||
<field name="body_html"><![CDATA[
|
<field name="body_html"><![CDATA[
|
||||||
<p>Hello ${object.name},</p>
|
<p>Hello ${object.name},</p>
|
||||||
<p>The event ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin} to ${object.event_id.date_end}.
|
<p>The event ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin_located.strftime('%Y-%m-%d %H:%M:%S (%Z)')} to ${object.event_id.date_end_located.strftime('%Y-%m-%d %H:%M:%S (%Z)')}.
|
||||||
For any further information please contact our event department.</p>
|
For any further information please contact our event department.</p>
|
||||||
<p>Thank you for your participation!</p>
|
<p>Thank you for your participation!</p>
|
||||||
<p>Best regards</p>]]></field>
|
<p>Best regards</p>]]></field>
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
import pytz
|
||||||
|
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
@ -156,6 +157,22 @@ class event_event(osv.osv):
|
||||||
for event in self.browse(cr, uid, ids, context=context)
|
for event in self.browse(cr, uid, ids, context=context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _compute_date_tz(self, cr, uid, ids, fld, arg, context=None):
|
||||||
|
if context is None:
|
||||||
|
context = {}
|
||||||
|
res = {}
|
||||||
|
for event in self.browse(cr, uid, ids, context=context):
|
||||||
|
ctx = dict(context, tz=(event.date_tz or 'UTC'))
|
||||||
|
if fld == 'date_begin_located':
|
||||||
|
date_to_convert = event.date_begin
|
||||||
|
elif fld == 'date_end_located':
|
||||||
|
date_to_convert = event.date_end
|
||||||
|
res[event.id] = fields.datetime.context_timestamp(cr, uid, datetime.strptime(date_to_convert, DEFAULT_SERVER_DATETIME_FORMAT), context=ctx)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def _tz_get(self, cr, uid, context=None):
|
||||||
|
return [(x, x) for x in pytz.all_timezones]
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Event Name', size=64, required=True, translate=True, readonly=False, states={'done': [('readonly', True)]}),
|
'name': fields.char('Event Name', size=64, required=True, translate=True, readonly=False, states={'done': [('readonly', True)]}),
|
||||||
'user_id': fields.many2one('res.users', 'Responsible User', readonly=False, states={'done': [('readonly', True)]}),
|
'user_id': fields.many2one('res.users', 'Responsible User', readonly=False, states={'done': [('readonly', True)]}),
|
||||||
|
@ -175,8 +192,11 @@ class event_event(osv.osv):
|
||||||
store={'event.registration': (_get_events_from_registrations, ['state'], 10),
|
store={'event.registration': (_get_events_from_registrations, ['state'], 10),
|
||||||
'event.event': (lambda self, cr, uid, ids, c = {}: ids, ['seats_max', 'registration_ids'], 20)}),
|
'event.event': (lambda self, cr, uid, ids, c = {}: ids, ['seats_max', 'registration_ids'], 20)}),
|
||||||
'registration_ids': fields.one2many('event.registration', 'event_id', 'Registrations', readonly=False, states={'done': [('readonly', True)]}),
|
'registration_ids': fields.one2many('event.registration', 'event_id', 'Registrations', readonly=False, states={'done': [('readonly', True)]}),
|
||||||
|
'date_tz': fields.selection(_tz_get, string='Timezone'),
|
||||||
'date_begin': fields.datetime('Start Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
'date_begin': fields.datetime('Start Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
||||||
'date_end': fields.datetime('End Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
'date_end': fields.datetime('End Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
||||||
|
'date_begin_located': fields.function(_compute_date_tz, string='Start Date Located', type="datetime"),
|
||||||
|
'date_end_located': fields.function(_compute_date_tz, string='End Date Located', type="datetime"),
|
||||||
'state': fields.selection([
|
'state': fields.selection([
|
||||||
('draft', 'Unconfirmed'),
|
('draft', 'Unconfirmed'),
|
||||||
('cancel', 'Cancelled'),
|
('cancel', 'Cancelled'),
|
||||||
|
@ -204,7 +224,8 @@ class event_event(osv.osv):
|
||||||
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'event.event', context=c),
|
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'event.event', context=c),
|
||||||
'user_id': lambda obj, cr, uid, context: uid,
|
'user_id': lambda obj, cr, uid, context: uid,
|
||||||
'organizer_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id,
|
'organizer_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id,
|
||||||
'address_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id
|
'address_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id,
|
||||||
|
'date_tz': lambda self, cr, uid, ctx: ctx.get('tz', "UTC"),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _check_seats_limit(self, cr, uid, ids, context=None):
|
def _check_seats_limit(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
<field name="type" on_change="onchange_event_type(type,context)" />
|
<field name="type" on_change="onchange_event_type(type,context)" />
|
||||||
<field name="date_begin" on_change="onchange_start_date(date_begin,date_end)"/>
|
<field name="date_begin" on_change="onchange_start_date(date_begin,date_end)"/>
|
||||||
<field name="date_end"/>
|
<field name="date_end"/>
|
||||||
|
<field name="date_tz" />
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
|
|
|
@ -155,7 +155,7 @@ class gamification_badge(osv.Model):
|
||||||
string='Authorized Users',
|
string='Authorized Users',
|
||||||
help="Only these people can give this badge"),
|
help="Only these people can give this badge"),
|
||||||
'rule_auth_badge_ids': fields.many2many('gamification.badge',
|
'rule_auth_badge_ids': fields.many2many('gamification.badge',
|
||||||
'rel_badge_badge', 'badge1_id', 'badge2_id',
|
'gamification_badge_rule_badge_rel', 'badge1_id', 'badge2_id',
|
||||||
string='Required Badges',
|
string='Required Badges',
|
||||||
help="Only the people having these badges can give this badge"),
|
help="Only the people having these badges can give this badge"),
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ class gamification_challenge(osv.Model):
|
||||||
'manager_id': fields.many2one('res.users',
|
'manager_id': fields.many2one('res.users',
|
||||||
string='Responsible', help="The user responsible for the challenge."),
|
string='Responsible', help="The user responsible for the challenge."),
|
||||||
|
|
||||||
'user_ids': fields.many2many('res.users', 'user_ids',
|
'user_ids': fields.many2many('res.users', 'gamification_challenge_users_rel',
|
||||||
string='Users',
|
string='Users',
|
||||||
help="List of users participating to the challenge"),
|
help="List of users participating to the challenge"),
|
||||||
'user_domain': fields.char('User domain', help="Alternative to a list of users"),
|
'user_domain': fields.char('User domain', help="Alternative to a list of users"),
|
||||||
|
@ -149,7 +149,7 @@ class gamification_challenge(osv.Model):
|
||||||
'end_date': fields.date('End Date',
|
'end_date': fields.date('End Date',
|
||||||
help="The day a new challenge will be automatically closed. If no periodicity is set, will use this date as the goal end date."),
|
help="The day a new challenge will be automatically closed. If no periodicity is set, will use this date as the goal end date."),
|
||||||
|
|
||||||
'invited_user_ids': fields.many2many('res.users', 'invited_user_ids',
|
'invited_user_ids': fields.many2many('res.users', 'gamification_invited_user_ids_rel',
|
||||||
string="Suggest to users"),
|
string="Suggest to users"),
|
||||||
|
|
||||||
'line_ids': fields.one2many('gamification.challenge.line', 'challenge_id',
|
'line_ids': fields.one2many('gamification.challenge.line', 'challenge_id',
|
||||||
|
|
|
@ -5,11 +5,12 @@ How to use OpenChatter in my addon
|
||||||
Running example
|
Running example
|
||||||
++++++++++++++++
|
++++++++++++++++
|
||||||
|
|
||||||
A small my_task model will be used as example to explain how to use the OpenChatter feature. Being simple, it has only the following fields :
|
A small my_task model will be used as example to explain how to use the
|
||||||
|
OpenChatter feature. Being simple, it has only the following fields:
|
||||||
|
|
||||||
- a name
|
- a name
|
||||||
- a task responsible
|
- a task responsible
|
||||||
- a related project
|
- a related project
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
@ -28,9 +29,7 @@ A small my_task model will be used as example to explain how to use the OpenChat
|
||||||
Two-lines feature integration
|
Two-lines feature integration
|
||||||
++++++++++++++++++++++++++++++
|
++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
Make your module inheriting from the ``mail.thread`` class.
|
Make your object inherit from :class:`mail.thread`::
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
class my_task(osv.osv):
|
class my_task(osv.osv):
|
||||||
_name = "my.task"
|
_name = "my.task"
|
||||||
|
@ -38,9 +37,8 @@ Make your module inheriting from the ``mail.thread`` class.
|
||||||
# inherit from mail.thread allows the use of OpenChatter
|
# inherit from mail.thread allows the use of OpenChatter
|
||||||
_inherit = ['mail.thread']
|
_inherit = ['mail.thread']
|
||||||
|
|
||||||
Use the thread viewer widget inside your form view by using the mail_thread widget on the message_ids field inherited from mail.thread.
|
Use the thread viewer widget inside your form view by using the mail_thread
|
||||||
|
widget on the message_ids field inherited from :class:`mail.thread`::
|
||||||
::
|
|
||||||
|
|
||||||
<record model="ir.ui.view" id="my_task_form_view">
|
<record model="ir.ui.view" id="my_task_form_view">
|
||||||
<field name="name">My Task</field>
|
<field name="name">My Task</field>
|
||||||
|
@ -57,98 +55,58 @@ Use the thread viewer widget inside your form view by using the mail_thread widg
|
||||||
Send notifications
|
Send notifications
|
||||||
+++++++++++++++++++
|
+++++++++++++++++++
|
||||||
|
|
||||||
When sending a notification is required in your workflow or business logic, use the ``message_post`` method. This method is a shortcut to the ``message_append`` method that takes all ``mail.message`` fields as arguments. This latter method calls ``message_create`` that
|
When sending a notification is required in your workflow or business logic,
|
||||||
|
use :meth:`mail.thread.message_post`. It will automatically take care of
|
||||||
|
subscriptions and notifications.
|
||||||
|
|
||||||
- creates the message
|
Here is a small example of sending a notification when the ``do_something``
|
||||||
- parses the body to find users you want to push the message to (finding and parsing ``@login`` in the message body)
|
method is called::
|
||||||
- pushes a notification to users following the document and requested users of the latetr step
|
|
||||||
|
|
||||||
You should therefore not worry about subscriptions or anything else than sending the notification. Here is a small example of sending a notification when the ``do_something`` method is called :
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
def do_something(self, cr, uid, ids, context=None):
|
def do_something(self, cr, uid, ids, context=None):
|
||||||
[...]
|
self.do_something_send_note(cr, uid, ids, context=context)
|
||||||
self.do_something_send_note(cr, uid, ids, context=context)
|
return res
|
||||||
[...]
|
|
||||||
return res
|
|
||||||
|
|
||||||
def do_something_send_note(self, cr, uid, ids, context=None):
|
def do_something_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, _('My subject'),
|
self.message_post(
|
||||||
_("has received a <b>notification</b> and is happy for it."), context=context)
|
cr, uid, ids, _('My subject'),
|
||||||
|
_("has received a <b>notification</b> and is happy for it."),
|
||||||
|
context=context)
|
||||||
|
|
||||||
Notifications guidelines
|
Notifications guidelines
|
||||||
+++++++++++++++++++++++++
|
+++++++++++++++++++++++++
|
||||||
|
|
||||||
Here are a few guidelines that you should keep in mind during the addition of system notifications :
|
- avoid unnecessary content, swamping users with irrelevant messages will lead
|
||||||
|
to them ignoring all messages
|
||||||
- avoid unnecessary content; if a message has no interest, do not implement it
|
- use short sentences
|
||||||
- use short sentences
|
- do not include the document name, this is done by the thread widget
|
||||||
- do not include the document name, as it is managed by the thread widget
|
- use a simple and clean style
|
||||||
- use a simple and clean style
|
|
||||||
|
|
||||||
- html tags are supported: use <b> or <em> mainly
|
- html tags are supported: use <b> or <em> mainly
|
||||||
- put main word(s) in bold
|
- put key word(s) in bold
|
||||||
- avoid fancy styles that will break the OpenERP look and feel
|
- avoid fancy styles that will break the OpenERP look and feel
|
||||||
- create a separate method for sending your notification
|
- create a separate method for sending your notification, use clear method
|
||||||
|
names allowing quickly spotting notification code e.g. name notification
|
||||||
- use a method name like ``original_method_name_send_note``, that allow to easily spot notification methods in the code
|
methods by using the original method name postfixed by ``_send_note``
|
||||||
|
(``do_something`` -> ``do_something_send_note``)
|
||||||
|
|
||||||
Subscription management
|
Subscription management
|
||||||
++++++++++++++++++++++++
|
++++++++++++++++++++++++
|
||||||
|
|
||||||
There are a few default subscription tricks that you should know before playing with subscription:
|
The default subscription behavior is the following:
|
||||||
|
|
||||||
- users that click on 'follow' follow the document. An entry in ``mail.subscription`` is created.
|
* Subscriptions are set up by creating a :class:`mail.followers`` entry
|
||||||
- users that click on 'unfollow' are no longer followers to the document. The related entry in ``mail.subscription`` is created.
|
* If a user creates or updates a document, they automatically follow it. The
|
||||||
- users that create or update a document automatically follow it. An entry in ``mail.subscription`` is created.
|
corresponding :class:`mail.followers` entry is created
|
||||||
|
* If a user explicitly cliks on the document's :guilabel:`Follow` button,
|
||||||
|
they follow the document. The corresponding :class:`mail.followers` entry
|
||||||
|
is created
|
||||||
|
* If a user explicitly clicks on the document's :guilabel:`Unfollow` button,
|
||||||
|
they stop following the document. The corresponding :class:`mail.followers`
|
||||||
|
entry is deleted
|
||||||
|
|
||||||
If you want to override this default behavior, you should avoid doing it manualle. You should instead override the ``message_get_subscribers`` method from mail.thread. The default implementation looks in the ``mail.suscription`` table for entries matching ``user_id=uid, res_model=self._name, res_id=current_record_id``. You can add subscribers by overriding the ``message_get_subscribers`` and adding user ids to the returned list. This means that they will be considered as followers even if they do not have an entry in the mail.subscription table.
|
You should not directly manipulate :class:`mail.followers` entry, if you need
|
||||||
|
to override the default subscription behavior you should override the relevant
|
||||||
|
:class:`mail.thread` methods.
|
||||||
|
|
||||||
As an exemple, let us say that you want to automatically add the my_task responsible along with the project manager to the list of followers. The method could look like:
|
.. TODO: wtf are the relevant mail.thread methds? message_get_subscribers
|
||||||
|
has disappeared and nothing looks like a replacement
|
||||||
::
|
|
||||||
|
|
||||||
def message_get_subscribers(self, cr, uid, ids, context=None):
|
|
||||||
# get the followers from the mail.subscription table
|
|
||||||
sub_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context);
|
|
||||||
# add the employee and its manager if specified to the subscribed users
|
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
|
||||||
if obj.user_id:
|
|
||||||
sub_ids.append(obj.user_id)
|
|
||||||
if obj.project_id and obj.project_id.user_id:
|
|
||||||
sub_ids.append(obj.project_id.user_id)
|
|
||||||
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context)
|
|
||||||
|
|
||||||
This method has the advantage of being able to implement a particular behavior with as few code addition as possible. Moreover, when changing the task responsible of the project manager, the subscribers are always correct. This allows to avoid to implement complex corner cases that could obfuscate the code.
|
|
||||||
|
|
||||||
The drawback of this method is that it is no longer possible to those subscribers to unfollow a document. Indeed, as user ids are added directly in a list in ``message_get_subscribers``, it is not possible to unsubscribe to a document. However, this drawback is mitigated by
|
|
||||||
|
|
||||||
- only important users shoudl be added using this method. Important users should not unsubscribe from their documents.
|
|
||||||
- users can hide the notifications on their Wall
|
|
||||||
|
|
||||||
Messages display management
|
|
||||||
++++++++++++++++++++++++++++
|
|
||||||
|
|
||||||
By default, the mail_thread widget shows all messages related to the current document beside the document, in the History and comments section. However, you may want to display other messages in the widget. For example, the OpenChatter on res.users model shows
|
|
||||||
|
|
||||||
- messages related to the user, as usual (messages with ``model = res.users, res_id = current_document_id``)
|
|
||||||
- messages directly pushed to this user (containing @login)
|
|
||||||
|
|
||||||
The best way to direct the messages that will be displayed in the OpenChatter widget is to override the ``message_load`` method. For example, the following method fetches messages as usual, but also fetches messages linked to the task project that contain the task name. Please refer to the API for more details about the arguments.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
def message_load(self, cr, uid, ids, limit=100, offset=0, domain=[], ascent=False, root_ids=[False], context=None):
|
|
||||||
msg_obj = self.pool.get('mail.message')
|
|
||||||
for my_task in self.browse(cr, uid, ids, context=context):
|
|
||||||
# search as usual messages related to the current document
|
|
||||||
msg_ids += msg_obj.search(cr, uid, ['|', '&', ('res_id', '=', my_task.id), ('model', '=', self._name),
|
|
||||||
# add: search in the current task project messages
|
|
||||||
'&', '&', ('res_id', '=', my_task.project_id.id), ('model', '=', 'project.project'),
|
|
||||||
# ... containing the task name
|
|
||||||
'|', ('body', 'like', '%s' % (my_task.name)), ('body_html', 'like', '%s' % (my_task.name))
|
|
||||||
] + domain, limit=limit, offset=offset, context=context)
|
|
||||||
# if asked: add ancestor ids to have complete threads
|
|
||||||
if (ascent): msg_ids = self._message_add_ancestor_ids(cr, uid, ids, msg_ids, root_ids, context=context)
|
|
||||||
return msg_obj.read(cr, uid, msg_ids, context=context)
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
.. _mail_thread:
|
.. _mail_thread:
|
||||||
|
|
||||||
|
===========================
|
||||||
mail.thread and OpenChatter
|
mail.thread and OpenChatter
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
API
|
API
|
||||||
+++
|
===
|
||||||
|
|
||||||
Writing messages and notifications
|
Writing messages and notifications
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
|
@ -359,6 +359,10 @@ class mail_thread(osv.AbstractModel):
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
|
if context.get('tracking_disable'):
|
||||||
|
return super(mail_thread, self).create(
|
||||||
|
cr, uid, values, context=context)
|
||||||
|
|
||||||
# subscribe uid unless asked not to
|
# subscribe uid unless asked not to
|
||||||
if not context.get('mail_create_nosubscribe'):
|
if not context.get('mail_create_nosubscribe'):
|
||||||
pid = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid).partner_id.id
|
pid = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid).partner_id.id
|
||||||
|
@ -394,6 +398,9 @@ class mail_thread(osv.AbstractModel):
|
||||||
context = {}
|
context = {}
|
||||||
if isinstance(ids, (int, long)):
|
if isinstance(ids, (int, long)):
|
||||||
ids = [ids]
|
ids = [ids]
|
||||||
|
if context.get('tracking_disable'):
|
||||||
|
return super(mail_thread, self).write(
|
||||||
|
cr, uid, ids, values, context=context)
|
||||||
# Track initial values of tracked fields
|
# Track initial values of tracked fields
|
||||||
track_ctx = dict(context)
|
track_ctx = dict(context)
|
||||||
if 'lang' not in track_ctx:
|
if 'lang' not in track_ctx:
|
||||||
|
|
|
@ -48,6 +48,8 @@ professional emails and reuse templates in a few clicks.
|
||||||
'views/res_config.xml',
|
'views/res_config.xml',
|
||||||
'views/res_partner.xml',
|
'views/res_partner.xml',
|
||||||
'views/email_template.xml',
|
'views/email_template.xml',
|
||||||
|
'views/website_mass_mailing.xml',
|
||||||
|
'views/snippets.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'views/mass_mailing.xml',
|
'views/mass_mailing.xml',
|
||||||
],
|
],
|
||||||
|
|
|
@ -40,3 +40,34 @@ class MassMailController(http.Controller):
|
||||||
if 'opt_out' in request.registry[mailing.mailing_model]._all_columns:
|
if 'opt_out' in request.registry[mailing.mailing_model]._all_columns:
|
||||||
request.registry[mailing.mailing_model].write(cr, SUPERUSER_ID, record_ids, {'opt_out': True}, context=context)
|
request.registry[mailing.mailing_model].write(cr, SUPERUSER_ID, record_ids, {'opt_out': True}, context=context)
|
||||||
return 'OK'
|
return 'OK'
|
||||||
|
|
||||||
|
@http.route(['/website_mass_mailing/is_subscriber'], type='json', auth="public", website=True)
|
||||||
|
def is_subscriber(self, list_id, **post):
|
||||||
|
cr, uid, context = request.cr, request.uid, request.context
|
||||||
|
Contacts = request.registry['mail.mass_mailing.contact']
|
||||||
|
Users = request.registry['res.users']
|
||||||
|
|
||||||
|
is_subscriber = False
|
||||||
|
email = None
|
||||||
|
if uid != request.website.user_id.id:
|
||||||
|
email = Users.browse(cr, SUPERUSER_ID, uid, context).email
|
||||||
|
elif request.session.get('mass_mailing_email'):
|
||||||
|
email = request.session['mass_mailing_email']
|
||||||
|
|
||||||
|
if email:
|
||||||
|
contact_ids = Contacts.search(cr, SUPERUSER_ID, [('list_id', '=', int(list_id)), ('email', '=', email)], context=context)
|
||||||
|
is_subscriber = len(contact_ids) > 0
|
||||||
|
|
||||||
|
return {'is_subscriber': is_subscriber, 'email': email}
|
||||||
|
|
||||||
|
@http.route(['/website_mass_mailing/subscribe'], type='json', auth="public", website=True)
|
||||||
|
def subscribe(self, list_id, email, **post):
|
||||||
|
cr, uid, context = request.cr, request.uid, request.context
|
||||||
|
Contacts = request.registry['mail.mass_mailing.contact']
|
||||||
|
|
||||||
|
contact_ids = Contacts.search(cr, SUPERUSER_ID, [('list_id', '=', int(list_id)), ('email', '=', email)], context=context)
|
||||||
|
if not contact_ids:
|
||||||
|
Contacts.name_create(cr, SUPERUSER_ID, email, context=context)
|
||||||
|
# add email to session
|
||||||
|
request.session['mass_mailing_email'] = email
|
||||||
|
return True
|
||||||
|
|
|
@ -33,5 +33,10 @@
|
||||||
<field name="sequence">30</field>
|
<field name="sequence">30</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- Create mailing lists -->
|
||||||
|
<record id="mass_mail_list_1" model="mail.mass_mailing.list">
|
||||||
|
<field name="name">Newsletter</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
|
@ -9,7 +9,7 @@
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Create mailing lists -->
|
<!-- Create mailing lists -->
|
||||||
<record id="mass_mail_list_1" model="mail.mass_mailing.list">
|
<record id="mass_mail_list_2" model="mail.mass_mailing.list">
|
||||||
<field name="name">Imported Contacts</field>
|
<field name="name">Imported Contacts</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
@ -17,17 +17,17 @@
|
||||||
<record id="mass_mail_contact_1" model="mail.mass_mailing.contact">
|
<record id="mass_mail_contact_1" model="mail.mass_mailing.contact">
|
||||||
<field name="name">Aristide Antario</field>
|
<field name="name">Aristide Antario</field>
|
||||||
<field name="email">aa@example.com</field>
|
<field name="email">aa@example.com</field>
|
||||||
<field name="list_id" ref="mass_mailing.mass_mail_list_1"/>
|
<field name="list_id" ref="mass_mailing.mass_mail_list_2"/>
|
||||||
</record>
|
</record>
|
||||||
<record id="mass_mail_contact_2" model="mail.mass_mailing.contact">
|
<record id="mass_mail_contact_2" model="mail.mass_mailing.contact">
|
||||||
<field name="name">Beverly Bridge</field>
|
<field name="name">Beverly Bridge</field>
|
||||||
<field name="email">bb@example.com</field>
|
<field name="email">bb@example.com</field>
|
||||||
<field name="list_id" ref="mass_mailing.mass_mail_list_1"/>
|
<field name="list_id" ref="mass_mailing.mass_mail_list_2"/>
|
||||||
</record>
|
</record>
|
||||||
<record id="mass_mail_contact_3" model="mail.mass_mailing.contact">
|
<record id="mass_mail_contact_3" model="mail.mass_mailing.contact">
|
||||||
<field name="name">Carol Cartridge</field>
|
<field name="name">Carol Cartridge</field>
|
||||||
<field name="email">cc@example.com</field>
|
<field name="email">cc@example.com</field>
|
||||||
<field name="list_id" ref="mass_mailing.mass_mail_list_1"/>
|
<field name="list_id" ref="mass_mailing.mass_mail_list_2"/>
|
||||||
<field name="opt_out" eval="True"/>
|
<field name="opt_out" eval="True"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
|
@ -0,0 +1,40 @@
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var website = openerp.website;
|
||||||
|
var _t = openerp._t;
|
||||||
|
|
||||||
|
website.snippet.options.mailing_list_subscribe = website.snippet.Option.extend({
|
||||||
|
on_prompt: function () {
|
||||||
|
var self = this;
|
||||||
|
return website.prompt({
|
||||||
|
id: "editor_new_mailing_list_subscribe_button",
|
||||||
|
window_title: _t("Add a Newsletter Subscribe Button"),
|
||||||
|
select: _t("Newsletter"),
|
||||||
|
init: function (field) {
|
||||||
|
return website.session.model('mail.mass_mailing.list')
|
||||||
|
.call('name_search', ['', []], { context: website.get_context() });
|
||||||
|
},
|
||||||
|
}).then(function (mailing_list_id) {
|
||||||
|
self.$target.attr("data-list-id", mailing_list_id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
drop_and_build_snippet: function() {
|
||||||
|
var self = this;
|
||||||
|
this._super();
|
||||||
|
this.on_prompt().fail(function () {
|
||||||
|
self.editor.on_remove();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
start : function () {
|
||||||
|
var self = this;
|
||||||
|
this.$el.find(".js_mailing_list").on("click", _.bind(this.on_prompt, this));
|
||||||
|
this._super();
|
||||||
|
},
|
||||||
|
clean_for_save: function () {
|
||||||
|
this.$target.addClass("hidden");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var website = openerp.website;
|
||||||
|
|
||||||
|
website.snippet.animationRegistry.subscribe = website.snippet.Animation.extend({
|
||||||
|
selector: ".js_subscribe",
|
||||||
|
start: function (editable_mode) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// set value and display button
|
||||||
|
self.$target.find("input").removeClass("hidden");
|
||||||
|
openerp.jsonRpc('/website_mass_mailing/is_subscriber', 'call', {
|
||||||
|
list_id: this.$target.data('list-id'),
|
||||||
|
}).always(function (data) {
|
||||||
|
self.$target.find('input.js_subscribe_email')
|
||||||
|
.val(data.email ? data.email : "")
|
||||||
|
.attr("disabled", data.is_subscriber && data.email.length ? "disabled" : false);
|
||||||
|
self.$target.attr("data-subscribe", data.is_subscriber ? 'on' : 'off');
|
||||||
|
self.$target.find('a.js_subscribe_btn')
|
||||||
|
.val(data.email ? data.email : "")
|
||||||
|
.attr("disabled", data.is_subscriber && data.email.length ? "disabled" : false);
|
||||||
|
self.$target.removeClass("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
// not if editable mode to allow designer to edit alert field
|
||||||
|
if (!editable_mode) {
|
||||||
|
$('.js_subscribe > .alert').addClass("hidden");
|
||||||
|
$('.js_subscribe > .input-group-btn.hidden').removeClass("hidden");
|
||||||
|
this.$target.find('.js_subscribe_btn').on('click', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
self.on_click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
on_click: function () {
|
||||||
|
var self = this;
|
||||||
|
var $email = this.$target.find(".js_subscribe_email:visible");
|
||||||
|
|
||||||
|
if ($email.length && !$email.val().match(/.+@.+/)) {
|
||||||
|
this.$target.addClass('has-error');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.$target.removeClass('has-error');
|
||||||
|
|
||||||
|
openerp.jsonRpc('/website_mass_mailing/subscribe', 'call', {
|
||||||
|
'list_id': this.$target.data('list-id'),
|
||||||
|
'email': $email.length ? $email.val() : false,
|
||||||
|
}).then(function (subscribe) {
|
||||||
|
self.$target.find(".js_subscribe_email, .input-group-btn").addClass("hidden");
|
||||||
|
self.$target.find(".alert").removeClass("hidden");
|
||||||
|
self.$target.find('input.js_subscribe_email').attr("disabled", subscribe ? "disabled" : false);
|
||||||
|
self.$target.attr("data-subscribe", subscribe ? 'on' : 'off');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})();
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<template id="mailing_list_subscribe" inherit_id="website.snippets" name="Subscribe to Newsletter">
|
||||||
|
|
||||||
|
<xpath expr="//div[@id='snippet_content']" position="inside">
|
||||||
|
<div>
|
||||||
|
<div class="oe_snippet_thumbnail">
|
||||||
|
<img class="oe_snippet_thumbnail_img" src="/mass_mailing/static/src/img/blocks/button_newsletter.png"/>
|
||||||
|
<span class="oe_snippet_thumbnail_title">Newsletter</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="oe_snippet_body input-group js_subscribe"
|
||||||
|
data-list-id="0">
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
class="js_subscribe_email form-control"
|
||||||
|
placeholder="your email..."/>
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<a href="#" class="btn btn-primary js_subscribe_btn">Subscribe</a>
|
||||||
|
</span>
|
||||||
|
<div class="alert alert-success hidden">Thanks for your subscription!</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//div[@id='snippet_options']" position="inside">
|
||||||
|
<div data-snippet-option-id='mailing_list_subscribe'
|
||||||
|
data-selector=".js_subscribe"
|
||||||
|
data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
<a href="#" class="button js_mailing_list">Change Newsletter</a>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<template id="head" inherit_id="website.layout" name="Mail customization">
|
||||||
|
<xpath expr="//head" position="inside">
|
||||||
|
<script type="text/javascript" src="/mass_mailing/static/src/js/website_mass_mailing.editor.js" groups="base.group_website_publisher"></script>
|
||||||
|
<script type="text/javascript" src="/mass_mailing/static/src/js/website_mass_mailing.js"></script>
|
||||||
|
<link rel='stylesheet' href='/website_mail/static/src/css/website_mail.css'/>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -29,7 +29,7 @@ class sale_report(osv.osv):
|
||||||
_rec_name = 'date'
|
_rec_name = 'date'
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'date': fields.date('Date Order', readonly=True),
|
'date': fields.datetime('Date Order', readonly=True),
|
||||||
'date_confirm': fields.date('Date Confirm', readonly=True),
|
'date_confirm': fields.date('Date Confirm', readonly=True),
|
||||||
'product_id': fields.many2one('product.product', 'Product', readonly=True),
|
'product_id': fields.many2one('product.product', 'Product', readonly=True),
|
||||||
'product_uom': fields.many2one('product.uom', 'Unit of Measure', readonly=True),
|
'product_uom': fields.many2one('product.uom', 'Unit of Measure', readonly=True),
|
||||||
|
|
|
@ -45,7 +45,7 @@ class WebsiteSurvey(http.Controller):
|
||||||
return werkzeug.utils.redirect("/survey/")
|
return werkzeug.utils.redirect("/survey/")
|
||||||
|
|
||||||
# In case of auth required, block public user
|
# In case of auth required, block public user
|
||||||
if survey.auth_required and uid == request.registry['website'].get_public_user(cr, uid, context):
|
if survey.auth_required and uid == request.website.user_id.id:
|
||||||
return request.website.render("website.403")
|
return request.website.render("website.403")
|
||||||
|
|
||||||
# In case of non open surveys
|
# In case of non open surveys
|
||||||
|
|
|
@ -6,6 +6,7 @@ import werkzeug
|
||||||
|
|
||||||
from lxml import etree, html
|
from lxml import etree, html
|
||||||
|
|
||||||
|
from openerp import SUPERUSER_ID
|
||||||
from openerp.addons.website.models import website
|
from openerp.addons.website.models import website
|
||||||
from openerp.http import request
|
from openerp.http import request
|
||||||
from openerp.osv import osv, fields
|
from openerp.osv import osv, fields
|
||||||
|
@ -197,3 +198,7 @@ class view(osv.osv):
|
||||||
self.write(cr, uid, res_id, {
|
self.write(cr, uid, res_id, {
|
||||||
'arch': self._pretty_arch(arch)
|
'arch': self._pretty_arch(arch)
|
||||||
}, context=context)
|
}, context=context)
|
||||||
|
|
||||||
|
view = self.browse(cr, SUPERUSER_ID, res_id, context=context)
|
||||||
|
if view.model_data_id:
|
||||||
|
view.model_data_id.write({'noupdate': True})
|
||||||
|
|
|
@ -80,6 +80,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</group>
|
</group>
|
||||||
|
<group string="Menu">
|
||||||
|
<button type="action"
|
||||||
|
name="%(website.action_website_menu)d"
|
||||||
|
string="Configure website menus" class="oe_link"/>
|
||||||
|
</group>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
|
|
|
@ -73,5 +73,27 @@
|
||||||
</group>
|
</group>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="action_website_menu" model="ir.actions.act_window">
|
||||||
|
<field name="name">Website Menu</field>
|
||||||
|
<field name="res_model">website.menu</field>
|
||||||
|
<field name="view_mode">list</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="menu_tree" model="ir.ui.view">
|
||||||
|
<field name="name">website.menu.tree</field>
|
||||||
|
<field name="model">website.menu</field>
|
||||||
|
<field name="field_parent">child_id</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree string="Website menu" editable="bottom">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="url"/>
|
||||||
|
<field name="new_window"/>
|
||||||
|
<field name="parent_id"/>
|
||||||
|
<field name="sequence"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -244,10 +244,8 @@ class WebsiteBlog(http.Controller):
|
||||||
blog_post = request.registry['blog.post']
|
blog_post = request.registry['blog.post']
|
||||||
partner_obj = request.registry['res.partner']
|
partner_obj = request.registry['res.partner']
|
||||||
thread_obj = request.registry['mail.thread']
|
thread_obj = request.registry['mail.thread']
|
||||||
website = request.registry['website']
|
|
||||||
|
|
||||||
public_id = website.get_public_user(cr, uid, context)
|
if uid != request.website.user_id.id:
|
||||||
if uid != public_id:
|
|
||||||
partner_ids = [user.partner_id.id]
|
partner_ids = [user.partner_id.id]
|
||||||
else:
|
else:
|
||||||
partner_ids = blog_post._find_partner_from_emails(
|
partner_ids = blog_post._find_partner_from_emails(
|
||||||
|
|
|
@ -34,8 +34,8 @@ class WebsiteForum(http.Controller):
|
||||||
def _prepare_forum_values(self, forum=None, **kwargs):
|
def _prepare_forum_values(self, forum=None, **kwargs):
|
||||||
Forum = request.registry['forum.forum']
|
Forum = request.registry['forum.forum']
|
||||||
user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, context=request.context)
|
user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, context=request.context)
|
||||||
public_uid = request.registry['website'].get_public_user(request.cr, request.uid, request.context)
|
values = {'user': user,
|
||||||
values = {'user': user, 'is_public_user': user.id == public_uid,
|
'is_public_user': user.id == request.website.user_id.id,
|
||||||
'notifications': self._get_notifications(),
|
'notifications': self._get_notifications(),
|
||||||
'header': kwargs.get('header', dict()),
|
'header': kwargs.get('header', dict()),
|
||||||
'searches': kwargs.get('searches', dict()),
|
'searches': kwargs.get('searches', dict()),
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
<field name="domain" eval="[('model', '=', 'forum.post'), ('subtype_id', 'in', [ref('website_forum.mt_answer_edit'), ref('website_forum.mt_question_edit')])]"/>
|
<field name="domain" eval="[('model', '=', 'forum.post'), ('subtype_id', 'in', [ref('website_forum.mt_answer_edit'), ref('website_forum.mt_question_edit')])]"/>
|
||||||
<field name="batch_mode">True</field>
|
<field name="batch_mode">True</field>
|
||||||
<field name="batch_distinctive_field" eval="ref('mail.field_mail_message_author_id')" />
|
<field name="batch_distinctive_field" eval="ref('mail.field_mail_message_author_id')" />
|
||||||
<field name="batch_user_expression">user.id</field>
|
<field name="batch_user_expression">user.partner_id.id</field>
|
||||||
</record>
|
</record>
|
||||||
<record model="gamification.challenge" id="challenge_editor">
|
<record model="gamification.challenge" id="challenge_editor">
|
||||||
<field name="name">Editor</field>
|
<field name="name">Editor</field>
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
<data noupdate="1">
|
<data noupdate="1">
|
||||||
|
|
||||||
<record model="mail.group" id="group_all_employees">
|
<record model="mail.group" id="group_all_employees">
|
||||||
<field name="name">Newsletter</field>
|
<field name="name">Discussion Group</field>
|
||||||
<field name="public">public</field>
|
<field name="public">public</field>
|
||||||
<field name="description">Public Newsletter.</field>
|
<field name="description">Public Discussion Group</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
|
@ -10,7 +10,7 @@
|
||||||
return website.prompt({
|
return website.prompt({
|
||||||
id: "editor_new_subscribe_button",
|
id: "editor_new_subscribe_button",
|
||||||
window_title: _t("Add a Subscribe Button"),
|
window_title: _t("Add a Subscribe Button"),
|
||||||
select: _t("Mailing List"),
|
select: _t("Discussion List"),
|
||||||
init: function (field) {
|
init: function (field) {
|
||||||
return website.session.model('mail.group')
|
return website.session.model('mail.group')
|
||||||
.call('name_search', ['', [['public','=','public']]], { context: website.get_context() });
|
.call('name_search', ['', [['public','=','public']]], { context: website.get_context() });
|
||||||
|
|
|
@ -499,8 +499,8 @@
|
||||||
<xpath expr="//div[@id='snippet_content']" position="inside">
|
<xpath expr="//div[@id='snippet_content']" position="inside">
|
||||||
<div>
|
<div>
|
||||||
<div class="oe_snippet_thumbnail">
|
<div class="oe_snippet_thumbnail">
|
||||||
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_button.png"/>
|
<img class="oe_snippet_thumbnail_img" src="/website_mail/static/src/img/blocks/button_group_subscribe.png"/>
|
||||||
<span class="oe_snippet_thumbnail_title">Subscribe Button</span>
|
<span class="oe_snippet_thumbnail_title">Discussion Group</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="oe_snippet_body input-group js_follow"
|
<div class="oe_snippet_body input-group js_follow"
|
||||||
|
@ -516,7 +516,7 @@
|
||||||
<a href="#" class="btn btn-default js_unfollow_btn">Unsubscribe</a>
|
<a href="#" class="btn btn-default js_unfollow_btn">Unsubscribe</a>
|
||||||
<a href="#" class="btn btn-primary js_follow_btn">Subscribe</a>
|
<a href="#" class="btn btn-primary js_follow_btn">Subscribe</a>
|
||||||
</span>
|
</span>
|
||||||
<div class="alert alert-success hidden">thanks for your subscription!</div>
|
<div class="alert alert-success hidden">Thanks for your subscription!</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -529,7 +529,7 @@
|
||||||
data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel"
|
data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel"
|
||||||
>
|
>
|
||||||
<li>
|
<li>
|
||||||
<a href="#" class="button js_mailing_list">Change mailing list</a>
|
<a href="#" class="button js_mailing_list">Change Discussion List</a>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
Loading…
Reference in New Issue