[MIG] mail_tracking: Migration to 15.0
This commit is contained in:
parent
021689d073
commit
680eee8074
@ -7,7 +7,7 @@
|
||||
{
|
||||
"name": "Email tracking",
|
||||
"summary": "Email tracking system for all mails sent",
|
||||
"version": "14.0.2.0.2",
|
||||
"version": "15.0.1.0.0",
|
||||
"category": "Social Network",
|
||||
"website": "https://github.com/OCA/social",
|
||||
"author": ("Tecnativa, " "Odoo Community Association (OCA)"),
|
||||
@ -19,18 +19,30 @@
|
||||
"data/tracking_data.xml",
|
||||
"security/mail_tracking_email_security.xml",
|
||||
"security/ir.model.access.csv",
|
||||
"views/assets.xml",
|
||||
"views/mail_tracking_email_view.xml",
|
||||
"views/mail_tracking_event_view.xml",
|
||||
"views/mail_message_view.xml",
|
||||
"views/res_partner_view.xml",
|
||||
],
|
||||
"qweb": [
|
||||
"static/src/xml/mail_tracking.xml",
|
||||
"static/src/xml/failed_message/common.xml",
|
||||
"static/src/xml/failed_message/thread.xml",
|
||||
"static/src/xml/failed_message/discuss.xml",
|
||||
],
|
||||
"assets": {
|
||||
"web.assets_backend": [
|
||||
"mail_tracking/static/src/css/mail_tracking.scss",
|
||||
"mail_tracking/static/src/css/failed_message.scss",
|
||||
"mail_tracking/static/src/js/mail_tracking.esm.js",
|
||||
"mail_tracking/static/src/js/message.esm.js",
|
||||
"mail_tracking/static/src/js/failed_message/mail_failed_box.esm.js",
|
||||
"mail_tracking/static/src/js/failed_message/thread.esm.js",
|
||||
"mail_tracking/static/src/js/models/thread.esm.js",
|
||||
"mail_tracking/static/src/js/chatter.esm.js",
|
||||
"mail_tracking/static/src/js/discuss/discuss.esm.js",
|
||||
],
|
||||
"web.assets_qweb": [
|
||||
"mail_tracking/static/src/xml/mail_tracking.xml",
|
||||
"mail_tracking/static/src/xml/failed_message/common.xml",
|
||||
"mail_tracking/static/src/xml/failed_message/thread.xml",
|
||||
"mail_tracking/static/src/xml/failed_message/discuss.xml",
|
||||
],
|
||||
},
|
||||
"demo": ["demo/demo.xml"],
|
||||
"pre_init_hook": "pre_init_hook",
|
||||
}
|
||||
|
@ -10,7 +10,8 @@ import werkzeug
|
||||
import odoo
|
||||
from odoo import SUPERUSER_ID, api, http
|
||||
|
||||
from odoo.addons.mail.controllers.main import MailController
|
||||
from odoo.addons.mail.controllers.discuss import DiscussController
|
||||
from odoo.addons.mail.controllers.mail import MailController
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@ -26,11 +27,10 @@ def db_env(dbname):
|
||||
cr = http.request.cr
|
||||
if not cr:
|
||||
cr = odoo.sql_db.db_connect(dbname).cursor()
|
||||
with api.Environment.manage():
|
||||
yield api.Environment(cr, SUPERUSER_ID, {})
|
||||
yield api.Environment(cr, SUPERUSER_ID, {})
|
||||
|
||||
|
||||
class MailTrackingController(MailController):
|
||||
class MailTrackingController(MailController, DiscussController):
|
||||
def _request_metadata(self):
|
||||
"""Prepare remote info metadata"""
|
||||
request = http.request.httprequest
|
||||
@ -59,8 +59,8 @@ class MailTrackingController(MailController):
|
||||
res = env["mail.tracking.email"].event_process(
|
||||
http.request, kw, metadata, event_type=event_type
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
_logger.warning(e)
|
||||
if not res or res == "NOT FOUND":
|
||||
return werkzeug.exceptions.NotAcceptable()
|
||||
return res
|
||||
@ -89,8 +89,8 @@ class MailTrackingController(MailController):
|
||||
)
|
||||
elif tracking_email.state in ("sent", "delivered"):
|
||||
tracking_email.event_create("open", metadata)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
_logger.warning(e)
|
||||
|
||||
# Always return GIF blank image
|
||||
response = werkzeug.wrappers.Response()
|
||||
@ -106,3 +106,12 @@ class MailTrackingController(MailController):
|
||||
{"failed_counter": http.request.env["mail.message"].get_failed_count()}
|
||||
)
|
||||
return values
|
||||
|
||||
@http.route("/mail/failed/messages", methods=["POST"], type="json", auth="user")
|
||||
def discuss_failed_messages(self, max_id=None, min_id=None, limit=30, **kwargs):
|
||||
return http.request.env["mail.message"]._message_fetch(
|
||||
domain=[("is_failed_message", "=", True)],
|
||||
max_id=max_id,
|
||||
min_id=min_id,
|
||||
limit=limit,
|
||||
)
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<!-- Message with CC -->
|
||||
<record id="mail_message_cc" model="mail.message">
|
||||
<field name="model">res.partner</field>
|
||||
@ -9,17 +7,17 @@
|
||||
<field name="message_type">comment</field>
|
||||
<field name="subtype_id" ref="mail.mt_comment" />
|
||||
<field
|
||||
name="email_cc"
|
||||
>acc@testmail.com,wood.corner26@example.com,toni.rhodes11@example.com</field>
|
||||
name="email_cc"
|
||||
>acc@testmail.com,wood.corner26@example.com,toni.rhodes11@example.com</field>
|
||||
<field name="mail_tracking_needs_action">1</field>
|
||||
<field name="body"><![CDATA[<p>This is a message with CC</p>]]></field>
|
||||
<field name="email_from">wood.corner26@example.com</field>
|
||||
<field name="author_id" ref="base.res_partner_1" />
|
||||
<field name="partner_ids" eval="[(6, 0, [ref('base.partner_demo')])]" />
|
||||
<field
|
||||
name="notification_ids"
|
||||
eval="[(0, 0, {'res_partner_id': ref('base.partner_demo')})]"
|
||||
/>
|
||||
name="notification_ids"
|
||||
eval="[(0, 0, {'res_partner_id': ref('base.partner_demo')})]"
|
||||
/>
|
||||
<field name="subject">Message with CC</field>
|
||||
</record>
|
||||
|
||||
@ -45,9 +43,9 @@
|
||||
<field name="author_id" ref="base.res_partner_1" />
|
||||
<field name="partner_ids" eval="[(6, 0, [ref('base.partner_demo')])]" />
|
||||
<field
|
||||
name="notification_ids"
|
||||
eval="[(0, 0, {'res_partner_id': ref('base.partner_demo')})]"
|
||||
/>
|
||||
name="notification_ids"
|
||||
eval="[(0, 0, {'res_partner_id': ref('base.partner_demo')})]"
|
||||
/>
|
||||
<field name="subject">Failed Message</field>
|
||||
</record>
|
||||
|
||||
@ -73,9 +71,9 @@
|
||||
<field name="author_id" ref="base.res_partner_10" />
|
||||
<field name="partner_ids" eval="[(6, 0, [ref('base.partner_demo')])]" />
|
||||
<field
|
||||
name="notification_ids"
|
||||
eval="[(0, 0, {'res_partner_id': ref('base.partner_demo')})]"
|
||||
/>
|
||||
name="notification_ids"
|
||||
eval="[(0, 0, {'res_partner_id': ref('base.partner_demo')})]"
|
||||
/>
|
||||
<field name="subject">Failed Message</field>
|
||||
</record>
|
||||
|
||||
@ -101,9 +99,9 @@
|
||||
<field name="author_id" ref="base.partner_admin" />
|
||||
<field name="partner_ids" eval="[(6, 0, [ref('base.partner_demo')])]" />
|
||||
<field
|
||||
name="notification_ids"
|
||||
eval="[(0, 0, {'res_partner_id': ref('base.partner_demo')})]"
|
||||
/>
|
||||
name="notification_ids"
|
||||
eval="[(0, 0, {'res_partner_id': ref('base.partner_demo')})]"
|
||||
/>
|
||||
<field name="subject">Failed Message</field>
|
||||
</record>
|
||||
|
||||
@ -116,6 +114,4 @@
|
||||
<field name="state">error</field>
|
||||
<field name="time" eval="DateTime.today().strftime('%Y-%m-%d %H:%M')" />
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
@ -224,9 +224,9 @@ class MailMessage(models.Model):
|
||||
|
||||
return list(filter(_filter_alias, mail_list))
|
||||
|
||||
def message_format(self):
|
||||
def message_format(self, format_reply=True):
|
||||
"""Preare values to be used by the chatter widget"""
|
||||
res = super().message_format()
|
||||
res = super().message_format(format_reply)
|
||||
mail_message_ids = {m.get("id") for m in res if m.get("id")}
|
||||
mail_messages = self.browse(mail_message_ids)
|
||||
tracking_statuses = mail_messages.tracking_status()
|
||||
@ -273,13 +273,8 @@ class MailMessage(models.Model):
|
||||
"""
|
||||
self.check_access_rule("read")
|
||||
self.write({"mail_tracking_needs_action": False})
|
||||
notification = {
|
||||
"type": "toggle_tracking_status",
|
||||
"message_ids": self.ids,
|
||||
"needs_actions": False,
|
||||
}
|
||||
self.env["bus.bus"].sendone(
|
||||
(self._cr.dbname, "res.partner", self.env.user.partner_id.id), notification
|
||||
self.env["bus.bus"]._sendone(
|
||||
self.env.user.partner_id, "toggle_tracking_status", self.ids
|
||||
)
|
||||
|
||||
@api.model
|
||||
|
@ -49,13 +49,9 @@ class MailResendMessage(models.TransientModel):
|
||||
tracking_ids.sudo().write({"state": False})
|
||||
# Send bus notifications to update Discuss and
|
||||
# mail_failed_messages widget
|
||||
notification = {
|
||||
"type": "toggle_tracking_status",
|
||||
"message_ids": [self.mail_message_id.id],
|
||||
"needs_actions": False,
|
||||
}
|
||||
self.env["bus.bus"].sendone(
|
||||
(self._cr.dbname, "res.partner", self.env.user.partner_id.id),
|
||||
notification,
|
||||
self.env["bus.bus"]._sendone(
|
||||
self.env.user.partner_id.id,
|
||||
"toggle_tracking_status",
|
||||
self.mail_message_id.id,
|
||||
)
|
||||
super().resend_mail_action()
|
||||
return super().resend_mail_action()
|
||||
|
@ -30,7 +30,6 @@ class MailTrackingEmail(models.Model):
|
||||
# - state: Search and group_by in tree view
|
||||
name = fields.Char(string="Subject", readonly=True, index=True)
|
||||
display_name = fields.Char(
|
||||
string="Display name",
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute="_compute_tracking_display_name",
|
||||
@ -38,10 +37,8 @@ class MailTrackingEmail(models.Model):
|
||||
timestamp = fields.Float(
|
||||
string="UTC timestamp", readonly=True, digits="MailTracking Timestamp"
|
||||
)
|
||||
time = fields.Datetime(string="Time", readonly=True, index=True)
|
||||
date = fields.Date(
|
||||
string="Date", readonly=True, compute="_compute_date", store=True
|
||||
)
|
||||
time = fields.Datetime(readonly=True, index=True)
|
||||
date = fields.Date(readonly=True, compute="_compute_date", store=True)
|
||||
mail_message_id = fields.Many2one(
|
||||
string="Message", comodel_name="mail.message", readonly=True, index=True
|
||||
)
|
||||
@ -71,7 +68,6 @@ class MailTrackingEmail(models.Model):
|
||||
("bounced", "Bounced"),
|
||||
("soft-bounced", "Soft bounced"),
|
||||
],
|
||||
string="State",
|
||||
index=True,
|
||||
readonly=True,
|
||||
default=False,
|
||||
@ -97,10 +93,10 @@ class MailTrackingEmail(models.Model):
|
||||
"bounced by recipient Mail Exchange (MX) server.\n",
|
||||
)
|
||||
error_smtp_server = fields.Char(string="Error SMTP server", readonly=True)
|
||||
error_type = fields.Char(string="Error type", readonly=True)
|
||||
error_description = fields.Char(string="Error description", readonly=True)
|
||||
bounce_type = fields.Char(string="Bounce type", readonly=True)
|
||||
bounce_description = fields.Char(string="Bounce description", readonly=True)
|
||||
error_type = fields.Char(readonly=True)
|
||||
error_description = fields.Char(readonly=True)
|
||||
bounce_type = fields.Char(readonly=True)
|
||||
bounce_description = fields.Char(readonly=True)
|
||||
tracking_event_ids = fields.One2many(
|
||||
string="Tracking events",
|
||||
comodel_name="mail.tracking.event",
|
||||
@ -126,10 +122,11 @@ class MailTrackingEmail(models.Model):
|
||||
return records
|
||||
|
||||
def write(self, vals):
|
||||
super().write(vals)
|
||||
res = super().write(vals)
|
||||
state = vals.get("state")
|
||||
if state and state in self.env["mail.message"].get_failed_states():
|
||||
self.mapped("mail_message_id").write({"mail_tracking_needs_action": True})
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def email_is_bounced(self, email):
|
||||
|
@ -14,7 +14,7 @@ class MailTrackingEvent(models.Model):
|
||||
_rec_name = "event_type"
|
||||
_description = "MailTracking event"
|
||||
|
||||
recipient = fields.Char(string="Recipient", readonly=True)
|
||||
recipient = fields.Char(readonly=True)
|
||||
recipient_address = fields.Char(
|
||||
string="Recipient email address",
|
||||
readonly=True,
|
||||
@ -25,10 +25,8 @@ class MailTrackingEvent(models.Model):
|
||||
timestamp = fields.Float(
|
||||
string="UTC timestamp", readonly=True, digits="MailTracking Timestamp"
|
||||
)
|
||||
time = fields.Datetime(string="Time", readonly=True)
|
||||
date = fields.Date(
|
||||
string="Date", readonly=True, compute="_compute_date", store=True
|
||||
)
|
||||
time = fields.Datetime(readonly=True)
|
||||
date = fields.Date(readonly=True, compute="_compute_date", store=True)
|
||||
tracking_email_id = fields.Many2one(
|
||||
string="Message",
|
||||
readonly=True,
|
||||
@ -38,7 +36,6 @@ class MailTrackingEvent(models.Model):
|
||||
index=True,
|
||||
)
|
||||
event_type = fields.Selection(
|
||||
string="Event type",
|
||||
selection=[
|
||||
("sent", "Sent"),
|
||||
("delivered", "Delivered"),
|
||||
@ -56,7 +53,7 @@ class MailTrackingEvent(models.Model):
|
||||
smtp_server = fields.Char(string="SMTP server", readonly=True)
|
||||
url = fields.Char(string="Clicked URL", readonly=True)
|
||||
ip = fields.Char(string="User IP", readonly=True)
|
||||
user_agent = fields.Char(string="User agent", readonly=True)
|
||||
user_agent = fields.Char(readonly=True)
|
||||
mobile = fields.Boolean(string="Is mobile?", readonly=True)
|
||||
os_family = fields.Char(string="Operating system family", readonly=True)
|
||||
ua_family = fields.Char(string="User agent family", readonly=True)
|
||||
@ -64,9 +61,9 @@ class MailTrackingEvent(models.Model):
|
||||
user_country_id = fields.Many2one(
|
||||
string="User country", readonly=True, comodel_name="res.country"
|
||||
)
|
||||
error_type = fields.Char(string="Error type", readonly=True)
|
||||
error_description = fields.Char(string="Error description", readonly=True)
|
||||
error_details = fields.Text(string="Error details", readonly=True)
|
||||
error_type = fields.Char(readonly=True)
|
||||
error_description = fields.Char(readonly=True)
|
||||
error_details = fields.Text(readonly=True)
|
||||
|
||||
@api.depends("recipient")
|
||||
def _compute_recipient_address(self):
|
||||
|
32
mail_tracking/static/src/js/chatter.esm.js
Normal file
32
mail_tracking/static/src/js/chatter.esm.js
Normal file
@ -0,0 +1,32 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {attr} from "@mail/model/model_field";
|
||||
import {
|
||||
registerFieldPatchModel,
|
||||
registerInstancePatchModel,
|
||||
} from "@mail/model/model_core";
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.chatter",
|
||||
"mail/static/src/models/chatter/chatter.js",
|
||||
{
|
||||
async refresh() {
|
||||
this._super(...arguments);
|
||||
this.thread.refreshMessagefailed();
|
||||
},
|
||||
toggleMessageFailedBoxVisibility() {
|
||||
this.update({
|
||||
isMessageFailedBoxVisible: !this.isMessageFailedBoxVisible,
|
||||
});
|
||||
},
|
||||
_onThreadIdOrThreadModelChanged() {
|
||||
this._super(...arguments);
|
||||
this.thread.refreshMessagefailed();
|
||||
},
|
||||
}
|
||||
);
|
||||
registerFieldPatchModel("mail.chatter", "mail/static/src/models/chatter/chatter.js", {
|
||||
isMessageFailedBoxVisible: attr({
|
||||
default: true,
|
||||
}),
|
||||
});
|
@ -1,38 +0,0 @@
|
||||
odoo.define("mail_tracking/static/src/js/chatter.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
const {attr} = require("mail/static/src/model/model_field.js");
|
||||
const {
|
||||
registerInstancePatchModel,
|
||||
registerFieldPatchModel,
|
||||
} = require("mail/static/src/model/model_core.js");
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.chatter",
|
||||
"mail/static/src/models/chatter/chatter.js",
|
||||
{
|
||||
async refresh() {
|
||||
this._super(...arguments);
|
||||
this.thread.refreshMessagefailed();
|
||||
},
|
||||
toggleMessageFailedBoxVisibility() {
|
||||
this.update({
|
||||
isMessageFailedBoxVisible: !this.isMessageFailedBoxVisible,
|
||||
});
|
||||
},
|
||||
_onThreadIdOrThreadModelChanged() {
|
||||
this._super(...arguments);
|
||||
this.thread.refreshMessagefailed();
|
||||
},
|
||||
}
|
||||
);
|
||||
registerFieldPatchModel(
|
||||
"mail.chatter",
|
||||
"mail/static/src/models/chatter/chatter.js",
|
||||
{
|
||||
isMessageFailedBoxVisible: attr({
|
||||
default: true,
|
||||
}),
|
||||
}
|
||||
);
|
||||
});
|
156
mail_tracking/static/src/js/discuss/discuss.esm.js
Normal file
156
mail_tracking/static/src/js/discuss/discuss.esm.js
Normal file
@ -0,0 +1,156 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {attr, many2one, one2one} from "@mail/model/model_field";
|
||||
import {insertAndReplace, replace} from "@mail/model/model_field_command";
|
||||
import {
|
||||
registerClassPatchModel,
|
||||
registerFieldPatchModel,
|
||||
registerInstancePatchModel,
|
||||
} from "@mail/model/model_core";
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.messaging_initializer",
|
||||
"mail/static/src/models/messaging_initializer/messaging_initializer.js",
|
||||
{
|
||||
async start() {
|
||||
this.messaging.update({
|
||||
failedmsg: insertAndReplace({
|
||||
id: "failedmsg",
|
||||
isServerPinned: true,
|
||||
model: "mail.box",
|
||||
name: this.env._t("Failed"),
|
||||
}),
|
||||
});
|
||||
return this._super(...arguments);
|
||||
},
|
||||
async _init({
|
||||
channels,
|
||||
companyName,
|
||||
current_partner,
|
||||
currentGuest,
|
||||
current_user_id,
|
||||
current_user_settings,
|
||||
mail_failures = [],
|
||||
menu_id,
|
||||
needaction_inbox_counter = 0,
|
||||
partner_root,
|
||||
public_partners,
|
||||
shortcodes = [],
|
||||
starred_counter = 0,
|
||||
failed_counter = 0,
|
||||
}) {
|
||||
const discuss = this.messaging.discuss;
|
||||
// Partners first because the rest of the code relies on them
|
||||
this._initPartners({
|
||||
currentGuest,
|
||||
current_partner,
|
||||
current_user_id,
|
||||
partner_root,
|
||||
public_partners,
|
||||
});
|
||||
// Mailboxes after partners and before other initializers that might
|
||||
// manipulate threads or messages
|
||||
this._initMailboxes({
|
||||
needaction_inbox_counter,
|
||||
starred_counter,
|
||||
failed_counter,
|
||||
});
|
||||
// Init mail user settings
|
||||
if (current_user_settings) {
|
||||
this._initResUsersSettings(current_user_settings);
|
||||
} else {
|
||||
this.messaging.update({
|
||||
userSetting: insertAndReplace({
|
||||
id: -1, // Fake id for guest
|
||||
}),
|
||||
});
|
||||
}
|
||||
// Various suggestions in no particular order
|
||||
this._initCannedResponses(shortcodes);
|
||||
// FIXME: guests should have (at least some) commands available
|
||||
if (!this.messaging.isCurrentUserGuest) {
|
||||
this._initCommands();
|
||||
}
|
||||
// Channels when the rest of messaging is ready
|
||||
await this.async(() => this._initChannels(channels));
|
||||
// Failures after channels
|
||||
this._initMailFailures(mail_failures);
|
||||
discuss.update({menu_id});
|
||||
// Company related data
|
||||
this.messaging.update({companyName});
|
||||
},
|
||||
|
||||
_initMailboxes({needaction_inbox_counter, starred_counter, failed_counter}) {
|
||||
this.messaging.inbox.update({counter: needaction_inbox_counter});
|
||||
this.messaging.starred.update({counter: starred_counter});
|
||||
this.messaging.failedmsg.update({counter: failed_counter});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
registerFieldPatchModel(
|
||||
"mail.messaging",
|
||||
"mail/static/src/models/messaging/messaging.js",
|
||||
{
|
||||
failedmsg: one2one("mail.thread"),
|
||||
}
|
||||
);
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.thread_cache",
|
||||
"mail/static/src/models/thread_cache/thread_cache.js",
|
||||
{
|
||||
_extendMessageDomain(domain) {
|
||||
const thread = this.thread;
|
||||
if (thread === this.env.messaging.failedmsg) {
|
||||
return domain.concat([["is_failed_message", "=", true]]);
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
registerFieldPatchModel("mail.message", "mail/static/src/models/message/message.js", {
|
||||
messagingFailedmsg: many2one("mail.thread", {
|
||||
related: "messaging.failedmsg",
|
||||
}),
|
||||
isFailed: attr({
|
||||
default: false,
|
||||
}),
|
||||
});
|
||||
|
||||
registerClassPatchModel("mail.message", "mail/static/src/models/message/message.js", {
|
||||
convertData(data) {
|
||||
const data2 = this._super(data);
|
||||
if ("is_failed_message" in data) {
|
||||
data2.isFailed = data.is_failed_message;
|
||||
}
|
||||
return data2;
|
||||
},
|
||||
});
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.message",
|
||||
"mail/static/src/models/message/message.js",
|
||||
{
|
||||
_computeThreads() {
|
||||
const threads = [];
|
||||
if (this.isHistory && this.messaging.history) {
|
||||
threads.push(this.messaging.history);
|
||||
}
|
||||
if (this.isNeedaction && this.messaging.inbox) {
|
||||
threads.push(this.messaging.inbox);
|
||||
}
|
||||
if (this.isStarred && this.messaging.starred) {
|
||||
threads.push(this.messaging.starred);
|
||||
}
|
||||
if (this.isFailed && this.messaging.failedmsg) {
|
||||
threads.push(this.messaging.failedmsg);
|
||||
}
|
||||
if (this.originThread) {
|
||||
threads.push(this.originThread);
|
||||
}
|
||||
return replace(threads);
|
||||
},
|
||||
}
|
||||
);
|
@ -1,148 +0,0 @@
|
||||
odoo.define("mail_tracking/static/src/js/discuss/discuss.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
const {attr} = require("mail/static/src/model/model_field.js");
|
||||
const {
|
||||
registerInstancePatchModel,
|
||||
registerFieldPatchModel,
|
||||
registerClassPatchModel,
|
||||
} = require("mail/static/src/model/model_core.js");
|
||||
const {one2one, many2one} = require("mail/static/src/model/model_field.js");
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.messaging_initializer",
|
||||
"mail/static/src/models/messaging_initializer/messaging_initializer.js",
|
||||
{
|
||||
async start() {
|
||||
this.messaging.update({
|
||||
failedmsg: [
|
||||
[
|
||||
"create",
|
||||
{
|
||||
id: "failedmsg",
|
||||
isServerPinned: true,
|
||||
model: "mail.box",
|
||||
name: this.env._t("Failed"),
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
return this._super(...arguments);
|
||||
},
|
||||
async _init({
|
||||
channel_slots,
|
||||
commands = [],
|
||||
current_partner,
|
||||
current_user_id,
|
||||
mail_failures = {},
|
||||
mention_partner_suggestions = [],
|
||||
menu_id,
|
||||
moderation_channel_ids = [],
|
||||
moderation_counter = 0,
|
||||
needaction_inbox_counter = 0,
|
||||
partner_root,
|
||||
public_partner,
|
||||
public_partners,
|
||||
shortcodes = [],
|
||||
starred_counter = 0,
|
||||
failed_counter = 0,
|
||||
}) {
|
||||
const discuss = this.messaging.discuss;
|
||||
// Partners first because the rest of the code relies on them
|
||||
this._initPartners({
|
||||
current_partner,
|
||||
current_user_id,
|
||||
moderation_channel_ids,
|
||||
partner_root,
|
||||
public_partner,
|
||||
public_partners,
|
||||
});
|
||||
// Mailboxes after partners and before other initializers that might
|
||||
// manipulate threads or messages
|
||||
this._initMailboxes({
|
||||
moderation_channel_ids,
|
||||
moderation_counter,
|
||||
needaction_inbox_counter,
|
||||
starred_counter,
|
||||
failed_counter,
|
||||
});
|
||||
// Various suggestions in no particular order
|
||||
this._initCannedResponses(shortcodes);
|
||||
this._initCommands(commands);
|
||||
this._initMentionPartnerSuggestions(mention_partner_suggestions);
|
||||
// Channels when the rest of messaging is ready
|
||||
await this.async(() => this._initChannels(channel_slots));
|
||||
// Failures after channels
|
||||
this._initMailFailures(mail_failures);
|
||||
discuss.update({menu_id});
|
||||
},
|
||||
|
||||
_initMailboxes({
|
||||
moderation_channel_ids,
|
||||
moderation_counter,
|
||||
needaction_inbox_counter,
|
||||
starred_counter,
|
||||
failed_counter,
|
||||
}) {
|
||||
this.env.messaging.inbox.update({counter: needaction_inbox_counter});
|
||||
this.env.messaging.starred.update({counter: starred_counter});
|
||||
this.env.messaging.failedmsg.update({counter: failed_counter});
|
||||
if (moderation_channel_ids.length > 0) {
|
||||
this.messaging.moderation.update({
|
||||
counter: moderation_counter,
|
||||
isServerPinned: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
registerFieldPatchModel(
|
||||
"mail.messaging",
|
||||
"mail/static/src/models/messaging/messaging.js",
|
||||
{
|
||||
failedmsg: one2one("mail.thread"),
|
||||
}
|
||||
);
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.thread_cache",
|
||||
"mail/static/src/models/thread_cache/thread_cache.js",
|
||||
{
|
||||
_extendMessageDomain(domain) {
|
||||
const thread = this.thread;
|
||||
if (thread === this.env.messaging.failedmsg) {
|
||||
return domain.concat([["is_failed_message", "=", true]]);
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
registerFieldPatchModel(
|
||||
"mail.message",
|
||||
"mail/static/src/models/message/message.js",
|
||||
{
|
||||
messagingFailedmsg: many2one("mail.thread", {
|
||||
related: "messaging.failedmsg",
|
||||
}),
|
||||
isFailed: attr({
|
||||
default: false,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
registerClassPatchModel(
|
||||
"mail.message",
|
||||
"mail/static/src/models/message/message.js",
|
||||
{
|
||||
convertData(data) {
|
||||
const data2 = this._super(data);
|
||||
if ("is_failed_message" in data) {
|
||||
data2.isFailed = data.is_failed_message;
|
||||
}
|
||||
return data2;
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
@ -0,0 +1,62 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
// const chatter = require("mail/static/src/models/chatter/chatter.js");
|
||||
// const useStore = require("mail/static/src/component_hooks/use_store/use_store.js");
|
||||
import {registerMessagingComponent} from "@mail/utils/messaging_component";
|
||||
const {Component} = owl;
|
||||
|
||||
export class MessageFailedBox extends Component {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
}
|
||||
|
||||
// Get chatter() {
|
||||
// return this.env.models["mail.chatter"].get(this.props.chatterLocalId);
|
||||
// }
|
||||
|
||||
_onClickTitle() {
|
||||
this.chatter.toggleMessageFailedBoxVisibility();
|
||||
}
|
||||
_markFailedMessageReviewed(id) {
|
||||
return this.env.services.rpc({
|
||||
model: "mail.message",
|
||||
method: "set_need_action_done",
|
||||
args: [[id]],
|
||||
});
|
||||
}
|
||||
_onRetryFailedMessage(event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
const thread = this.chatter.thread;
|
||||
var self = this;
|
||||
this.env.bus.trigger("do-action", {
|
||||
action: "mail.mail_resend_message_action",
|
||||
options: {
|
||||
additional_context: {
|
||||
mail_message_to_resend: messageID,
|
||||
},
|
||||
on_close: () => {
|
||||
self.trigger("reload", {keepChanges: true});
|
||||
thread.refresh();
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
_onMarkFailedMessageReviewed(event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
this._markFailedMessageReviewed(messageID);
|
||||
this.trigger("reload", {keepChanges: true});
|
||||
this.chatter.thread.refreshMessagefailed();
|
||||
this.chatter.thread.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(MessageFailedBox, {
|
||||
props: {
|
||||
chatterLocalId: String,
|
||||
},
|
||||
template: "mail_tracking.MessageFailedBox",
|
||||
});
|
||||
|
||||
registerMessagingComponent(MessageFailedBox);
|
@ -1,76 +0,0 @@
|
||||
odoo.define(
|
||||
"mail_tracking/static/src/js/failed_message/mail_failed_box.js",
|
||||
function (require) {
|
||||
"use strict";
|
||||
|
||||
const chatter = require("mail/static/src/components/chatter/chatter.js");
|
||||
const useStore = require("mail/static/src/component_hooks/use_store/use_store.js");
|
||||
|
||||
const {Component} = owl;
|
||||
|
||||
class MessageFailedBox extends Component {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
useStore((props) => {
|
||||
const chatter = this.env.models["mail.chatter"].get(
|
||||
props.chatterLocalId
|
||||
);
|
||||
const thread = chatter && chatter.thread;
|
||||
return {
|
||||
chatter: chatter ? chatter.__state : undefined,
|
||||
thread: thread && thread.__state,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
get chatter() {
|
||||
return this.env.models["mail.chatter"].get(this.props.chatterLocalId);
|
||||
}
|
||||
|
||||
_onClickTitle() {
|
||||
this.chatter.toggleMessageFailedBoxVisibility();
|
||||
}
|
||||
_markFailedMessageReviewed(id) {
|
||||
return this.env.services.rpc({
|
||||
model: "mail.message",
|
||||
method: "set_need_action_done",
|
||||
args: [[id]],
|
||||
});
|
||||
}
|
||||
_onRetryFailedMessage(event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
const thread = this.chatter.thread;
|
||||
var self = this;
|
||||
this.env.bus.trigger("do-action", {
|
||||
action: "mail.mail_resend_message_action",
|
||||
options: {
|
||||
additional_context: {
|
||||
mail_message_to_resend: messageID,
|
||||
},
|
||||
on_close: () => {
|
||||
self.trigger("reload", {keepChanges: true});
|
||||
thread.refresh();
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
_onMarkFailedMessageReviewed(event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
this._markFailedMessageReviewed(messageID);
|
||||
this.trigger("reload", {keepChanges: true});
|
||||
this.chatter.thread.refreshMessagefailed();
|
||||
this.chatter.thread.refresh();
|
||||
}
|
||||
}
|
||||
MessageFailedBox.template = "mail_tracking.MessageFailedBox";
|
||||
MessageFailedBox.props = {
|
||||
chatterLocalId: String,
|
||||
};
|
||||
chatter.components = Object.assign({}, chatter.components, {
|
||||
MessageFailedBox,
|
||||
});
|
||||
return MessageFailedBox;
|
||||
}
|
||||
);
|
58
mail_tracking/static/src/js/failed_message/thread.esm.js
Normal file
58
mail_tracking/static/src/js/failed_message/thread.esm.js
Normal file
@ -0,0 +1,58 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
registerFieldPatchModel,
|
||||
registerInstancePatchModel,
|
||||
} from "@mail/model/model_core";
|
||||
import {one2many} from "@mail/model/model_field";
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.thread",
|
||||
"mail_tracking/static/src/js/failed_message/thread.js",
|
||||
{
|
||||
async refreshMessagefailed() {
|
||||
var id = this.__values.id;
|
||||
var model = this.__values.model;
|
||||
const messagefailedData = await this.async(() =>
|
||||
this.env.services.rpc(
|
||||
{
|
||||
model: "mail.message",
|
||||
method: "get_failed_messsage_info",
|
||||
args: [id, model],
|
||||
},
|
||||
{
|
||||
shadow: true,
|
||||
}
|
||||
)
|
||||
);
|
||||
const messagefailed = this.messaging.models["mail.message.failed"].insert(
|
||||
messagefailedData.map((messageData) =>
|
||||
this.messaging.models["mail.message.failed"].convertData(
|
||||
messageData
|
||||
)
|
||||
)
|
||||
);
|
||||
this.update({
|
||||
messagefailed: [["replace", messagefailed]],
|
||||
});
|
||||
},
|
||||
|
||||
_computeFetchMessagesUrl() {
|
||||
switch (this) {
|
||||
case this.messaging.failedmsg:
|
||||
return "/mail/failed/messages";
|
||||
}
|
||||
return this._super();
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
registerFieldPatchModel(
|
||||
"mail.thread",
|
||||
"mail_tracking/static/src/js/failed_message/thread.js",
|
||||
{
|
||||
messagefailed: one2many("mail.message.failed", {
|
||||
inverse: "thread",
|
||||
}),
|
||||
}
|
||||
);
|
@ -1,50 +0,0 @@
|
||||
odoo.define("mail_tracking/static/src/js/failed_message/thread.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
registerInstancePatchModel,
|
||||
registerFieldPatchModel,
|
||||
} = require("mail/static/src/model/model_core.js");
|
||||
const {one2many} = require("mail/static/src/model/model_field.js");
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.thread",
|
||||
"mail_tracking/static/src/js/failed_message/thread.js",
|
||||
{
|
||||
async refreshMessagefailed() {
|
||||
var id = this.__values.id;
|
||||
var model = this.__values.model;
|
||||
const messagefailedData = await this.async(() =>
|
||||
this.env.services.rpc(
|
||||
{
|
||||
model: "mail.message",
|
||||
method: "get_failed_messsage_info",
|
||||
args: [id, model],
|
||||
},
|
||||
{
|
||||
shadow: true,
|
||||
}
|
||||
)
|
||||
);
|
||||
const messagefailed = this.env.models["mail.message.failed"].insert(
|
||||
messagefailedData.map((messageData) =>
|
||||
this.env.models["mail.message.failed"].convertData(messageData)
|
||||
)
|
||||
);
|
||||
this.update({
|
||||
messagefailed: [["replace", messagefailed]],
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
registerFieldPatchModel(
|
||||
"mail.thread",
|
||||
"mail_tracking/static/src/js/failed_message/thread.js",
|
||||
{
|
||||
messagefailed: one2many("mail.message.failed", {
|
||||
inverse: "thread",
|
||||
}),
|
||||
}
|
||||
);
|
||||
});
|
51
mail_tracking/static/src/js/mail_tracking.esm.js
Normal file
51
mail_tracking/static/src/js/mail_tracking.esm.js
Normal file
@ -0,0 +1,51 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
registerClassPatchModel,
|
||||
registerFieldPatchModel,
|
||||
registerInstancePatchModel,
|
||||
} from "@mail/model/model_core";
|
||||
import {attr} from "@mail/model/model_field";
|
||||
|
||||
registerClassPatchModel(
|
||||
"mail.message",
|
||||
"mail_tracking/static/src/js/mail_tracking.js",
|
||||
{
|
||||
convertData(data) {
|
||||
const data2 = this._super(data);
|
||||
if ("partner_trackings" in data) {
|
||||
data2.partner_trackings = data.partner_trackings;
|
||||
}
|
||||
return data2;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
registerFieldPatchModel(
|
||||
"mail.message",
|
||||
"mail_tracking/static/src/js/mail_tracking.js",
|
||||
{
|
||||
partner_trackings: attr(),
|
||||
}
|
||||
);
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.model",
|
||||
"mail_tracking/static/src/js/mail_tracking.js",
|
||||
{
|
||||
hasPartnerTrackings() {
|
||||
return _.some(this.__values.partner_trackings);
|
||||
},
|
||||
|
||||
hasEmailCc() {
|
||||
return _.some(this._emailCc);
|
||||
},
|
||||
|
||||
getPartnerTrackings: function () {
|
||||
if (!this.hasPartnerTrackings()) {
|
||||
return [];
|
||||
}
|
||||
return this.__values.partner_trackings;
|
||||
},
|
||||
}
|
||||
);
|
@ -1,53 +0,0 @@
|
||||
odoo.define("mail_tracking/static/src/js/mail_tracking.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
registerClassPatchModel,
|
||||
registerFieldPatchModel,
|
||||
registerInstancePatchModel,
|
||||
} = require("mail/static/src/model/model_core.js");
|
||||
const {attr} = require("mail/static/src/model/model_field.js");
|
||||
|
||||
registerClassPatchModel(
|
||||
"mail.message",
|
||||
"mail_tracking/static/src/js/mail_tracking.js",
|
||||
{
|
||||
convertData(data) {
|
||||
const data2 = this._super(data);
|
||||
if ("partner_trackings" in data) {
|
||||
data2.partner_trackings = data.partner_trackings;
|
||||
}
|
||||
return data2;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
registerFieldPatchModel(
|
||||
"mail.message",
|
||||
"mail_tracking/static/src/js/mail_tracking.js",
|
||||
{
|
||||
partner_trackings: attr(),
|
||||
}
|
||||
);
|
||||
|
||||
registerInstancePatchModel(
|
||||
"mail.model",
|
||||
"mail_tracking/static/src/js/mail_tracking.js",
|
||||
{
|
||||
hasPartnerTrackings() {
|
||||
return _.some(this.__values.partner_trackings);
|
||||
},
|
||||
|
||||
hasEmailCc() {
|
||||
return _.some(this._emailCc);
|
||||
},
|
||||
|
||||
getPartnerTrackings: function () {
|
||||
if (!this.hasPartnerTrackings()) {
|
||||
return [];
|
||||
}
|
||||
return this.__values.partner_trackings;
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
55
mail_tracking/static/src/js/message.esm.js
Normal file
55
mail_tracking/static/src/js/message.esm.js
Normal file
@ -0,0 +1,55 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {Message} from "@mail/components/message/message";
|
||||
import {patch} from "web.utils";
|
||||
|
||||
patch(Message.prototype, "mail_tracking/static/src/js/message.js", {
|
||||
constructor() {
|
||||
this._super(...arguments);
|
||||
},
|
||||
_onTrackingStatusClick(event) {
|
||||
var tracking_email_id = $(event.currentTarget).data("tracking");
|
||||
event.preventDefault();
|
||||
return this.env.bus.trigger("do-action", {
|
||||
action: {
|
||||
type: "ir.actions.act_window",
|
||||
view_type: "form",
|
||||
view_mode: "form",
|
||||
res_model: "mail.tracking.email",
|
||||
views: [[false, "form"]],
|
||||
target: "new",
|
||||
res_id: tracking_email_id,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// For discuss
|
||||
_onMarkFailedMessageReviewed(event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
this._markFailedMessageReviewed(messageID);
|
||||
window.location.reload();
|
||||
},
|
||||
_onRetryFailedMessage(event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
this.env.bus.trigger("do-action", {
|
||||
action: "mail.mail_resend_message_action",
|
||||
options: {
|
||||
additional_context: {
|
||||
mail_message_to_resend: messageID,
|
||||
},
|
||||
on_close: () => {
|
||||
window.location.reload();
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
_markFailedMessageReviewed(id) {
|
||||
return this.env.services.rpc({
|
||||
model: "mail.message",
|
||||
method: "set_need_action_done",
|
||||
args: [[id]],
|
||||
});
|
||||
},
|
||||
});
|
@ -1,58 +0,0 @@
|
||||
odoo.define("mail_tracking/static/src/js/message.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
const Message = require("mail/static/src/components/message/message.js");
|
||||
const MessageList = require("mail/static/src/components/message_list/message_list.js");
|
||||
|
||||
class MessageTracking extends Message {
|
||||
constructor(parent, props) {
|
||||
super(parent, props);
|
||||
}
|
||||
_onTrackingStatusClick(event) {
|
||||
var tracking_email_id = $(event.currentTarget).data("tracking");
|
||||
event.preventDefault();
|
||||
return this.env.bus.trigger("do-action", {
|
||||
action: {
|
||||
type: "ir.actions.act_window",
|
||||
view_type: "form",
|
||||
view_mode: "form",
|
||||
res_model: "mail.tracking.email",
|
||||
views: [[false, "form"]],
|
||||
target: "new",
|
||||
res_id: tracking_email_id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// For discuss
|
||||
_onMarkFailedMessageReviewed(event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
this._markFailedMessageReviewed(messageID);
|
||||
window.location.reload();
|
||||
}
|
||||
_onRetryFailedMessage(event) {
|
||||
event.preventDefault();
|
||||
var messageID = $(event.currentTarget).data("message-id");
|
||||
this.env.bus.trigger("do-action", {
|
||||
action: "mail.mail_resend_message_action",
|
||||
options: {
|
||||
additional_context: {
|
||||
mail_message_to_resend: messageID,
|
||||
},
|
||||
on_close: () => {
|
||||
window.location.reload();
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
_markFailedMessageReviewed(id) {
|
||||
return this.env.services.rpc({
|
||||
model: "mail.message",
|
||||
method: "set_need_action_done",
|
||||
args: [[id]],
|
||||
});
|
||||
}
|
||||
}
|
||||
MessageList.components.Message = MessageTracking;
|
||||
});
|
53
mail_tracking/static/src/js/models/thread.esm.js
Normal file
53
mail_tracking/static/src/js/models/thread.esm.js
Normal file
@ -0,0 +1,53 @@
|
||||
/** @odoo-module **/
|
||||
import {registerNewModel} from "@mail/model/model_core";
|
||||
import {attr, many2one} from "@mail/model/model_field";
|
||||
|
||||
function factory(dependencies) {
|
||||
class MessageFailed extends dependencies["mail.model"] {
|
||||
static convertData(data) {
|
||||
const data2 = {};
|
||||
if ("author" in data) {
|
||||
if (!data.author) {
|
||||
data2.author = [["unlink-all"]];
|
||||
} else {
|
||||
data2.author = data.author[1];
|
||||
data2.author_id = data.author[0];
|
||||
}
|
||||
}
|
||||
if ("body" in data) {
|
||||
data2.body = data.body;
|
||||
}
|
||||
if ("date" in data) {
|
||||
data2.date = data.date;
|
||||
}
|
||||
if ("failed_recipients" in data) {
|
||||
data2.failed_recipients = data.failed_recipients;
|
||||
}
|
||||
if ("id" in data) {
|
||||
data2.id = data.id;
|
||||
}
|
||||
return data2;
|
||||
}
|
||||
}
|
||||
|
||||
MessageFailed.fields = {
|
||||
thread: many2one("mail.thread", {
|
||||
inverse: "messagefailed",
|
||||
}),
|
||||
body: attr(),
|
||||
author: attr(),
|
||||
author_id: attr(),
|
||||
date: attr(),
|
||||
failed_recipients: attr(),
|
||||
id: attr({
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
||||
MessageFailed.modelName = "mail.message.failed";
|
||||
MessageFailed.identifyingFields = ["id"];
|
||||
return MessageFailed;
|
||||
}
|
||||
|
||||
registerNewModel("mail.message.failed", factory);
|
@ -1,53 +0,0 @@
|
||||
odoo.define("mail_tracking/static/src/js/models/thread.js", function (require) {
|
||||
"use strict";
|
||||
|
||||
const {registerNewModel} = require("mail/static/src/model/model_core.js");
|
||||
const {attr, many2one} = require("mail/static/src/model/model_field.js");
|
||||
|
||||
function factory(dependencies) {
|
||||
class MessageFailed extends dependencies["mail.model"] {
|
||||
static convertData(data) {
|
||||
const data2 = {};
|
||||
if ("author" in data) {
|
||||
if (!data.author) {
|
||||
data2.author = [["unlink-all"]];
|
||||
} else {
|
||||
data2.author = data.author[1];
|
||||
data2.author_id = data.author[0];
|
||||
}
|
||||
}
|
||||
if ("body" in data) {
|
||||
data2.body = data.body;
|
||||
}
|
||||
if ("date" in data) {
|
||||
data2.date = data.date;
|
||||
}
|
||||
if ("failed_recipients" in data) {
|
||||
data2.failed_recipients = data.failed_recipients;
|
||||
}
|
||||
if ("id" in data) {
|
||||
data2.id = data.id;
|
||||
}
|
||||
return data2;
|
||||
}
|
||||
}
|
||||
|
||||
MessageFailed.fields = {
|
||||
thread: many2one("mail.thread", {
|
||||
inverse: "messagefailed",
|
||||
}),
|
||||
body: attr(),
|
||||
author: attr(),
|
||||
author_id: attr(),
|
||||
date: attr(),
|
||||
failed_recipients: attr(),
|
||||
id: attr(),
|
||||
};
|
||||
|
||||
MessageFailed.modelName = "mail.message.failed";
|
||||
|
||||
return MessageFailed;
|
||||
}
|
||||
|
||||
registerNewModel("mail.message.failed", factory);
|
||||
});
|
@ -1,24 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<t t-inherit="mail.ThreadIcon" t-inherit-mode="extension">
|
||||
<xpath
|
||||
expr="//t[@t-elif='thread === env.messaging.moderation']"
|
||||
position="after"
|
||||
>
|
||||
<t t-elif="thread === env.messaging.failedmsg">
|
||||
<xpath expr="//t[@t-elif='thread === messaging.history']" position="after">
|
||||
<t t-elif="thread === messaging.failedmsg">
|
||||
<div class="o_ThreadIcon_mailboxModeration fa fa-exclamation" />
|
||||
</t>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
<t t-inherit="mail.DiscussSidebar" t-inherit-mode="extension">
|
||||
<xpath
|
||||
expr="//div[hasclass('o_DiscussSidebar_categoryMailbox')]"
|
||||
position="inside"
|
||||
>
|
||||
<DiscussSidebarMailbox threadLocalId="messaging.failedmsg.localId" />
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
<t t-inherit="mail.MessageList" t-inherit-mode="extension">
|
||||
<t t-elif="threadView.thread === messaging.history" position="after">
|
||||
<t t-elif="threadView.thread === messaging.failedmsg">
|
||||
<div class="o_MessageList_emptyTitle o-neutral-face-icon">
|
||||
No failed messages
|
||||
</div>
|
||||
Failed messages will be appeared here.
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-inherit="mail.Message" t-inherit-mode="extension">
|
||||
<xpath expr="//div[hasclass('o_Message_originThread')]" position="inside">
|
||||
<t t-if="message.isFailed">
|
||||
<t t-if="messageView.message.isFailed">
|
||||
<span t-attf-class="o_thread_icons">
|
||||
<a
|
||||
href="#"
|
||||
class="btn btn-link btn-success o_thread_icon text-muted btn-sm o_failed_message_reviewed o_activity_link"
|
||||
t-on-click="_onMarkFailedMessageReviewed"
|
||||
t-att-data-message-id="message.id"
|
||||
t-att-data-message-id="messageView.message.id"
|
||||
>
|
||||
<i class="fa fa-check" />
|
||||
Set as Reviewed
|
||||
@ -27,7 +45,7 @@
|
||||
href="#"
|
||||
class="btn btn-link btn-success o_thread_icon text-muted btn-sm o_failed_message_retry o_activity_link"
|
||||
t-on-click="_onRetryFailedMessage"
|
||||
t-att-data-message-id="message.id"
|
||||
t-att-data-message-id="messageView.message.id"
|
||||
>
|
||||
<i class="fa fa-retweet" />
|
||||
Retry
|
||||
|
@ -54,12 +54,17 @@
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-inherit="mail.Message" t-inherit-mode="extension">
|
||||
<t t-name="mail.MessageTracking" t-inherit="mail.Message" t-inherit-mode="extension">
|
||||
<xpath expr="//div[hasclass('o_Message_header')]" position="after">
|
||||
<t t-if="message.hasPartnerTrackings() || message.hasEmailCc()">
|
||||
<t
|
||||
t-if="messageView.message.hasPartnerTrackings() || messageView.message.hasEmailCc()"
|
||||
>
|
||||
<p class="o_mail_tracking">
|
||||
<strong>To:</strong>
|
||||
<t t-foreach="message.getPartnerTrackings()" t-as="tracking">
|
||||
<t
|
||||
t-foreach="messageView.message.getPartnerTrackings()"
|
||||
t-as="tracking"
|
||||
>
|
||||
<t t-if="!tracking_first">
|
||||
-
|
||||
</t>
|
||||
@ -91,6 +96,7 @@
|
||||
class="mail_tracking o_mail_action_tracking_status"
|
||||
t-att-data-tracking="tracking['tracking_id']"
|
||||
t-att-title="title_status"
|
||||
type="button"
|
||||
t-on-click="_onTrackingStatusClick"
|
||||
>
|
||||
<t t-call="mail.tracking.status" />
|
||||
|
@ -88,7 +88,8 @@ class TestMailTracking(TransactionCase):
|
||||
"body": "<p>This is a test message</p>",
|
||||
}
|
||||
)
|
||||
message._moderate_accept()
|
||||
if message.is_thread_message():
|
||||
self.env[message.model].browse(message.res_id)._notify_thread(message)
|
||||
# Search tracking created
|
||||
tracking_email = self.env["mail.tracking.email"].search(
|
||||
[
|
||||
@ -138,7 +139,10 @@ class TestMailTracking(TransactionCase):
|
||||
"body": "<p>This is a test message</p>",
|
||||
}
|
||||
)
|
||||
message.with_context(do_not_send_copy=True)._moderate_accept()
|
||||
if message.is_thread_message():
|
||||
self.env[message.model].browse(message.res_id).with_context(
|
||||
do_not_send_copy=True
|
||||
)._notify_thread(message)
|
||||
# Search tracking created
|
||||
tracking_email = self.env["mail.tracking.email"].search(
|
||||
[
|
||||
@ -203,7 +207,8 @@ class TestMailTracking(TransactionCase):
|
||||
"body": "<p>This is another test message</p>",
|
||||
}
|
||||
)
|
||||
message._moderate_accept()
|
||||
if message.is_thread_message():
|
||||
self.env[message.model].browse(message.res_id)._notify_thread(message)
|
||||
recipients = self.recipient._message_get_suggested_recipients()
|
||||
self.assertEqual(len(recipients[self.recipient.id]), 3)
|
||||
self._check_partner_trackings_cc(message)
|
||||
@ -257,7 +262,8 @@ class TestMailTracking(TransactionCase):
|
||||
"body": "<p>This is another test message</p>",
|
||||
}
|
||||
)
|
||||
message._moderate_accept()
|
||||
if message.is_thread_message():
|
||||
self.env[message.model].browse(message.res_id)._notify_thread(message)
|
||||
recipients = self.recipient._message_get_suggested_recipients()
|
||||
self.assertEqual(len(recipients[self.recipient.id]), 4)
|
||||
self._check_partner_trackings_to(message)
|
||||
@ -316,7 +322,8 @@ class TestMailTracking(TransactionCase):
|
||||
"body": "<p>This is a test message</p>",
|
||||
}
|
||||
)
|
||||
message._moderate_accept()
|
||||
if message.is_thread_message():
|
||||
self.env[message.model].browse(message.res_id)._notify_thread(message)
|
||||
# Search tracking created
|
||||
tracking_email = self.env["mail.tracking.email"].search(
|
||||
[
|
||||
@ -330,7 +337,7 @@ class TestMailTracking(TransactionCase):
|
||||
wizard = (
|
||||
self.env["mail.resend.message"]
|
||||
.sudo()
|
||||
.with_context({"mail_message_to_resend": message.id})
|
||||
.with_context(mail_message_to_resend=message.id)
|
||||
.create({})
|
||||
)
|
||||
# Check failed recipient)s
|
||||
|
@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
|
||||
<odoo>
|
||||
<template
|
||||
id="assets_backend"
|
||||
name="mail_tracking assets"
|
||||
inherit_id="web.assets_backend"
|
||||
>
|
||||
<xpath expr="." position="inside">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/mail_tracking/static/src/css/mail_tracking.scss"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/mail_tracking/static/src/css/failed_message.scss"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_tracking/static/src/js/mail_tracking.js"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_tracking/static/src/js/message.js"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_tracking/static/src/js/failed_message/mail_failed_box.js"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_tracking/static/src/js/failed_message/thread.js"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_tracking/static/src/js/models/thread.js"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_tracking/static/src/js/chatter.js"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/mail_tracking/static/src/js/discuss/discuss.js"
|
||||
/>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
@ -3,74 +3,78 @@
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
|
||||
<odoo>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_tracking_email_form">
|
||||
<field name="name">mail.tracking.email.form</field>
|
||||
<field name="model">mail.tracking.email</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="MailTracking event" create="false" edit="false" delete="false">
|
||||
<header>
|
||||
<field name="state" widget="statusbar" />
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" />
|
||||
</group>
|
||||
<group>
|
||||
<record model="ir.ui.view" id="view_mail_tracking_email_form">
|
||||
<field name="name">mail.tracking.email.form</field>
|
||||
<field name="model">mail.tracking.email</field>
|
||||
<field name="arch" type="xml">
|
||||
<form
|
||||
string="MailTracking event"
|
||||
create="false"
|
||||
edit="false"
|
||||
delete="false"
|
||||
>
|
||||
<header>
|
||||
<field name="state" widget="statusbar" />
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="mail_message_id" />
|
||||
<field name="mail_id" />
|
||||
<field name="partner_id" />
|
||||
<field name="recipient" />
|
||||
<field name="sender" />
|
||||
<field name="name" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="timestamp" />
|
||||
<field name="time" />
|
||||
<field name="date" />
|
||||
<group>
|
||||
<field name="mail_message_id" />
|
||||
<field name="mail_id" />
|
||||
<field name="partner_id" />
|
||||
<field name="recipient" />
|
||||
<field name="sender" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="timestamp" />
|
||||
<field name="time" />
|
||||
<field name="date" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('bounce_type', '=', False)]}">
|
||||
<field name="bounce_type" />
|
||||
<field name="bounce_description" />
|
||||
</group>
|
||||
<group attrs="{'invisible': [('error_type', '=', False)]}">
|
||||
<field
|
||||
<group attrs="{'invisible': [('bounce_type', '=', False)]}">
|
||||
<field name="bounce_type" />
|
||||
<field name="bounce_description" />
|
||||
</group>
|
||||
<group attrs="{'invisible': [('error_type', '=', False)]}">
|
||||
<field
|
||||
name="error_smtp_server"
|
||||
attrs="{'invisible': [('error_smtp_server', '=', False)]}"
|
||||
/>
|
||||
<field name="error_type" />
|
||||
<field name="error_description" />
|
||||
</group>
|
||||
<label for="tracking_event_ids" />
|
||||
<div>
|
||||
<field name="tracking_event_ids">
|
||||
<tree
|
||||
string="Tracking events"
|
||||
<field name="error_type" />
|
||||
<field name="error_description" />
|
||||
</group>
|
||||
<label for="tracking_event_ids" />
|
||||
<div>
|
||||
<field name="tracking_event_ids">
|
||||
<tree
|
||||
decoration-muted="event_type == 'deferral'"
|
||||
decoration-danger="event_type in ('hard_bounce', 'soft_bounce', 'spam', 'reject')"
|
||||
decoration-info="event_type in ('unsub', 'click', 'open')"
|
||||
>
|
||||
<field name="time" />
|
||||
<field name="event_type" />
|
||||
<field name="ip" />
|
||||
<field name="url" />
|
||||
<field name="user_country_id" string="Country" />
|
||||
<field name="os_family" string="OS" />
|
||||
<field name="ua_family" string="User agent" />
|
||||
</tree>
|
||||
</field>
|
||||
</div>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<field name="time" />
|
||||
<field name="event_type" />
|
||||
<field name="ip" />
|
||||
<field name="url" />
|
||||
<field name="user_country_id" string="Country" />
|
||||
<field name="os_family" string="OS" />
|
||||
<field name="ua_family" string="User agent" />
|
||||
</tree>
|
||||
</field>
|
||||
</div>
|
||||
</sheet>
|
||||
<footer />
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_tracking_email_tree">
|
||||
<field name="name">mail.tracking.email.tree</field>
|
||||
<field name="model">mail.tracking.email</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree
|
||||
string="MailTracking emails"
|
||||
<record model="ir.ui.view" id="view_mail_tracking_email_tree">
|
||||
<field name="name">mail.tracking.email.tree</field>
|
||||
<field name="model">mail.tracking.email</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree
|
||||
create="false"
|
||||
edit="false"
|
||||
delete="false"
|
||||
@ -79,101 +83,105 @@
|
||||
decoration-danger="state in ('rejected', 'spam', 'bounced', 'soft-bounced', 'error')"
|
||||
decoration-info="state == 'unsub'"
|
||||
>
|
||||
<field name="time" />
|
||||
<field name="date" invisible="1" />
|
||||
<field name="name" />
|
||||
<field name="sender" string="Sender" />
|
||||
<field name="recipient" string="Recipient" />
|
||||
<field name="state" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<field name="time" />
|
||||
<field name="date" invisible="1" />
|
||||
<field name="name" />
|
||||
<field name="sender" string="Sender" />
|
||||
<field name="recipient" string="Recipient" />
|
||||
<field name="state" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_tracking_email_search">
|
||||
<field name="name">mail.tracking.email.search</field>
|
||||
<field name="model">mail.tracking.email</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="MailTracking email search">
|
||||
<field
|
||||
<record model="ir.ui.view" id="view_mail_tracking_email_search">
|
||||
<field name="name">mail.tracking.email.search</field>
|
||||
<field name="model">mail.tracking.email</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="MailTracking email search">
|
||||
<field
|
||||
name="display_name"
|
||||
string="Email"
|
||||
filter_domain="['|', ('sender', 'ilike', self), ('recipient', 'ilike', self)]"
|
||||
/>
|
||||
<field
|
||||
<field
|
||||
name="sender"
|
||||
string="Sender"
|
||||
filter_domain="[('sender', 'ilike', self)]"
|
||||
/>
|
||||
<field
|
||||
<field
|
||||
name="recipient_address"
|
||||
string="Recipient Address"
|
||||
filter_domain="[('recipient_address', '=', self)]"
|
||||
/>
|
||||
<field name="name" string="Subject" />
|
||||
<field name="time" string="Time" />
|
||||
<field name="date" string="Date" />
|
||||
<filter name="sent" string="Sent" domain="[('state', 'in', ('sent',))]" />
|
||||
<filter
|
||||
<field name="name" string="Subject" />
|
||||
<field name="time" string="Time" />
|
||||
<field name="date" string="Date" />
|
||||
<filter
|
||||
name="sent"
|
||||
string="Sent"
|
||||
domain="[('state', 'in', ('sent',))]"
|
||||
/>
|
||||
<filter
|
||||
name="deferred"
|
||||
string="Deferred"
|
||||
domain="[('state', '=', 'deferred')]"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
name="delivered"
|
||||
string="Delivered"
|
||||
domain="[('state', 'in', ('delivered', 'opened'))]"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
name="unsub"
|
||||
string="Unsubscribed"
|
||||
domain="[('state', '=', 'unsub')]"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
name="exception"
|
||||
string="Failed"
|
||||
domain="[('state', 'in', ('error', 'rejected', 'spam', 'bounced', 'soft-bounced'))]"
|
||||
/>
|
||||
<separator />
|
||||
<group expand="0" string="Group By">
|
||||
<filter
|
||||
<separator />
|
||||
<group expand="0" string="Group By">
|
||||
<filter
|
||||
string="State"
|
||||
name="group_by_state"
|
||||
domain="[]"
|
||||
context="{'group_by': 'state'}"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
string="Subject"
|
||||
name="group_by_subject"
|
||||
domain="[]"
|
||||
context="{'group_by': 'name'}"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
string="Sender"
|
||||
name="group_by_sender"
|
||||
domain="[]"
|
||||
context="{'group_by': 'sender'}"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
string="Month"
|
||||
name="group_by_month"
|
||||
domain="[]"
|
||||
context="{'group_by': 'date'}"
|
||||
/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_view_mail_tracking_email" model="ir.actions.act_window">
|
||||
<field name="name">MailTracking emails</field>
|
||||
<field name="res_model">mail.tracking.email</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_mail_tracking_email_search" />
|
||||
</record>
|
||||
<record id="action_view_mail_tracking_email" model="ir.actions.act_window">
|
||||
<field name="name">MailTracking emails</field>
|
||||
<field name="res_model">mail.tracking.email</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_mail_tracking_email_search" />
|
||||
</record>
|
||||
|
||||
<!-- Add menu entry in Settings/Email -->
|
||||
<menuitem
|
||||
<!-- Add menu entry in Settings/Email -->
|
||||
<menuitem
|
||||
name="Tracking emails"
|
||||
id="menu_mail_tracking_email"
|
||||
parent="base.menu_email"
|
||||
|
@ -3,66 +3,70 @@
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
|
||||
<odoo>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_tracking_event_form">
|
||||
<field name="name">mail.tracking.event.form</field>
|
||||
<field name="model">mail.tracking.event</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="MailTracking event" create="false" edit="false" delete="false">
|
||||
<sheet>
|
||||
<group>
|
||||
<record model="ir.ui.view" id="view_mail_tracking_event_form">
|
||||
<field name="name">mail.tracking.event.form</field>
|
||||
<field name="model">mail.tracking.event</field>
|
||||
<field name="arch" type="xml">
|
||||
<form
|
||||
string="MailTracking event"
|
||||
create="false"
|
||||
edit="false"
|
||||
delete="false"
|
||||
>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="tracking_email_id" />
|
||||
<field name="recipient" />
|
||||
<field name="event_type" />
|
||||
<group>
|
||||
<field name="tracking_email_id" />
|
||||
<field name="recipient" />
|
||||
<field name="event_type" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="timestamp" />
|
||||
<field name="time" />
|
||||
<field name="date" />
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="timestamp" />
|
||||
<field name="time" />
|
||||
<field name="date" />
|
||||
<group attrs="{'invisible': [('event_type', 'not in', ('sent',))]}">
|
||||
<field name="smtp_server" />
|
||||
</group>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('event_type', 'not in', ('sent',))]}">
|
||||
<field name="smtp_server" />
|
||||
</group>
|
||||
<group
|
||||
<group
|
||||
attrs="{'invisible': [('event_type', 'not in', ('open', 'click'))]}"
|
||||
>
|
||||
<field name="url" />
|
||||
</group>
|
||||
<group
|
||||
<field name="url" />
|
||||
</group>
|
||||
<group
|
||||
attrs="{'invisible': [('event_type', 'not in', ('open', 'click'))]}"
|
||||
>
|
||||
<group>
|
||||
<field name="mobile" />
|
||||
<field name="ip" />
|
||||
<field name="user_country_id" />
|
||||
<group>
|
||||
<field name="mobile" />
|
||||
<field name="ip" />
|
||||
<field name="user_country_id" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="user_agent" />
|
||||
<field name="ua_family" />
|
||||
<field name="ua_type" />
|
||||
<field name="os_family" />
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="user_agent" />
|
||||
<field name="ua_family" />
|
||||
<field name="ua_type" />
|
||||
<field name="os_family" />
|
||||
</group>
|
||||
</group>
|
||||
<group
|
||||
<group
|
||||
string="Error"
|
||||
attrs="{'invisible': [('error_type', '=', False)]}"
|
||||
>
|
||||
<field name="error_type" />
|
||||
<field name="error_description" />
|
||||
<field name="error_details" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<field name="error_type" />
|
||||
<field name="error_description" />
|
||||
<field name="error_details" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_tracking_event_tree">
|
||||
<field name="name">mail.tracking.event.tree</field>
|
||||
<field name="model">mail.tracking.event</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree
|
||||
string="MailTracking events"
|
||||
<record model="ir.ui.view" id="view_mail_tracking_event_tree">
|
||||
<field name="name">mail.tracking.event.tree</field>
|
||||
<field name="model">mail.tracking.event</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree
|
||||
create="false"
|
||||
edit="false"
|
||||
delete="false"
|
||||
@ -70,125 +74,133 @@
|
||||
decoration-danger="event_type in ('hard_bounce', 'soft_bounce', 'spam', 'reject')"
|
||||
decoration-info="event_type in ('unsub', 'click', 'open')"
|
||||
>
|
||||
<field name="time" />
|
||||
<field name="tracking_email_id" />
|
||||
<field name="recipient" />
|
||||
<field name="event_type" />
|
||||
<field
|
||||
<field name="time" />
|
||||
<field name="tracking_email_id" />
|
||||
<field name="recipient" />
|
||||
<field name="event_type" />
|
||||
<field
|
||||
name="error_details"
|
||||
invisible="not context.get('event_error_filter', False)"
|
||||
/>
|
||||
<field name="date" invisible="1" />
|
||||
<field name="ip" />
|
||||
<field name="url" />
|
||||
<field name="user_country_id" string="Country" />
|
||||
<field name="os_family" string="OS" />
|
||||
<field name="ua_family" string="User agent" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<field name="date" invisible="1" />
|
||||
<field name="ip" />
|
||||
<field name="url" />
|
||||
<field name="user_country_id" string="Country" />
|
||||
<field name="os_family" string="OS" />
|
||||
<field name="ua_family" string="User agent" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_tracking_event_search">
|
||||
<field name="name">mail.tracking.event.search</field>
|
||||
<field name="model">mail.tracking.event</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="MailTracking event search">
|
||||
<field
|
||||
<record model="ir.ui.view" id="view_mail_tracking_event_search">
|
||||
<field name="name">mail.tracking.event.search</field>
|
||||
<field name="model">mail.tracking.event</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="MailTracking event search">
|
||||
<field
|
||||
name="tracking_email_id"
|
||||
string="Message"
|
||||
filter_domain="[('tracking_email_id', 'ilike', self)]"
|
||||
/>
|
||||
<field name="recipient" string="Recipient" />
|
||||
<field name="time" string="Time" />
|
||||
<field name="date" string="Date" />
|
||||
<field name="ip" string="IP" />
|
||||
<field name="url" string="URL" />
|
||||
<filter name="sent" string="Sent" domain="[('event_type', '=', 'sent')]" />
|
||||
<filter
|
||||
<field name="recipient" string="Recipient" />
|
||||
<field name="time" string="Time" />
|
||||
<field name="date" string="Date" />
|
||||
<field name="ip" string="IP" />
|
||||
<field name="url" string="URL" />
|
||||
<filter
|
||||
name="sent"
|
||||
string="Sent"
|
||||
domain="[('event_type', '=', 'sent')]"
|
||||
/>
|
||||
<filter
|
||||
name="delivered"
|
||||
string="Delivered"
|
||||
domain="[('event_type', '=', 'delivered')]"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
name="click"
|
||||
string="Click"
|
||||
domain="[('event_type', '=', 'click')]"
|
||||
/>
|
||||
<filter name="open" string="Open" domain="[('event_type', '=', 'open')]" />
|
||||
<filter
|
||||
<filter
|
||||
name="open"
|
||||
string="Open"
|
||||
domain="[('event_type', '=', 'open')]"
|
||||
/>
|
||||
<filter
|
||||
name="unsub"
|
||||
string="Unsubscribe"
|
||||
domain="[('event_type', '=', 'unsub')]"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
name="bounce"
|
||||
string="Bounce"
|
||||
domain="[('event_type', 'in', ('hard_bounce', 'soft_bounce'))]"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
name="exception"
|
||||
string="Failed"
|
||||
domain="[('event_type', 'in', ('reject', 'spam'))]"
|
||||
context="{'event_error_filter': True}"
|
||||
/>
|
||||
<separator />
|
||||
<group expand="0" string="Group By">
|
||||
<filter
|
||||
<separator />
|
||||
<group expand="0" string="Group By">
|
||||
<filter
|
||||
string="Type"
|
||||
name="group_by_type"
|
||||
domain="[]"
|
||||
context="{'group_by': 'event_type'}"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
string="Message"
|
||||
name="group_by_message"
|
||||
domain="[]"
|
||||
context="{'group_by': 'tracking_email_id'}"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
string="OS"
|
||||
name="group_by_os"
|
||||
domain="[('os_family', '!=', False)]"
|
||||
context="{'group_by': 'os_family'}"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
string="User agent"
|
||||
name="group_by_user_agent"
|
||||
domain="[('ua_family', '!=', False)]"
|
||||
context="{'group_by': 'ua_family'}"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
string="User agent type"
|
||||
name="group_by_user_agent_type"
|
||||
domain="[('ua_type', '!=', False)]"
|
||||
context="{'group_by': 'ua_type'}"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
string="Country"
|
||||
name="group_by_country"
|
||||
domain="[('user_country_id', '!=', False)]"
|
||||
context="{'group_by': 'user_country_id'}"
|
||||
/>
|
||||
<filter
|
||||
<filter
|
||||
string="Month"
|
||||
name="group_by_date"
|
||||
domain="[]"
|
||||
context="{'group_by': 'date'}"
|
||||
/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_mail_tracking_event" model="ir.actions.act_window">
|
||||
<field name="name">MailTracking events</field>
|
||||
<field name="res_model">mail.tracking.event</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_mail_tracking_event_search" />
|
||||
</record>
|
||||
<record id="action_view_mail_tracking_event" model="ir.actions.act_window">
|
||||
<field name="name">MailTracking events</field>
|
||||
<field name="res_model">mail.tracking.event</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_mail_tracking_event_search" />
|
||||
</record>
|
||||
|
||||
<!-- Add menu entry in Settings/Email -->
|
||||
<menuitem
|
||||
<!-- Add menu entry in Settings/Email -->
|
||||
<menuitem
|
||||
name="Tracking events"
|
||||
id="menu_mail_tracking_event"
|
||||
parent="base.menu_email"
|
||||
|
Loading…
Reference in New Issue
Block a user