[PEP8] pre-commit

This commit is contained in:
houssine 2021-11-08 12:48:44 +01:00 committed by Jasmin Solanki
parent aba9ad7561
commit 53cc2ff96f
13 changed files with 386 additions and 388 deletions

View File

@ -7,7 +7,7 @@
{ {
"name": "Email tracking", "name": "Email tracking",
"summary": "Email tracking system for all mails sent", "summary": "Email tracking system for all mails sent",
"version": "14.0.1.1.1", "version": "14.0.1.1.2",
"category": "Social Network", "category": "Social Network",
"website": "https://github.com/OCA/social", "website": "https://github.com/OCA/social",
"author": ("Tecnativa, " "Odoo Community Association (OCA)"), "author": ("Tecnativa, " "Odoo Community Association (OCA)"),

View File

@ -310,6 +310,10 @@ class MailMessage(models.Model):
@api.model @api.model
def get_failed_messsage_info(self, ids, model): def get_failed_messsage_info(self, ids, model):
msg_ids = self.search([('res_id', '=', ids), ('model', '=', model)]) msg_ids = self.search([("res_id", "=", ids), ("model", "=", model)])
res = [msg._prepare_dict_failed_message() for msg in msg_ids.sorted("date", reverse=True) if msg._prepare_dict_failed_message()] res = [
msg._prepare_dict_failed_message()
for msg in msg_ids.sorted("date", reverse=True)
if msg._prepare_dict_failed_message()
]
return res return res

View File

@ -6,3 +6,6 @@
* Ernesto Tejeda * Ernesto Tejeda
* Rafael Blasco * Rafael Blasco
* Alexandre Díaz * Alexandre Díaz
* `Eezee-IT <https://www.eezee-it.com>`_:
* Asma Elferkhsi

View File

@ -1,30 +1,38 @@
odoo.define('mail_tracking/static/src/js/chatter.js', function (require) { odoo.define("mail_tracking/static/src/js/chatter.js", function (require) {
'use strict'; "use strict";
const ChatterContainer = require('mail/static/src/components/chatter_container/chatter_container.js'); const {attr} = require("mail/static/src/model/model_field.js");
const { attr } = require('mail/static/src/model/model_field.js'); const {
const { registerInstancePatchModel,registerFieldPatchModel, registerClassPatchModel, registerInstancePatchModel,
} = require('mail/static/src/model/model_core.js'); 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()
}
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,
}),
}
);
}); });
registerFieldPatchModel('mail.chatter', 'mail/static/src/models/chatter/chatter.js', {
isMessageFailedBoxVisible: attr({
default: true,
}),
});
});

View File

@ -1,139 +1,148 @@
odoo.define('mail_tracking/static/src/js/discuss/discuss.js', function(require) { odoo.define("mail_tracking/static/src/js/discuss/discuss.js", function (require) {
'use strict'; "use strict";
const { const {attr} = require("mail/static/src/model/model_field.js");
attr
} = require('mail/static/src/model/model_field.js');
const { const {
registerInstancePatchModel, registerInstancePatchModel,
registerFieldPatchModel, registerFieldPatchModel,
registerClassPatchModel registerClassPatchModel,
} = require('mail/static/src/model/model_core.js'); } = require("mail/static/src/model/model_core.js");
const { const {one2one, many2one} = require("mail/static/src/model/model_field.js");
one2one,
many2one
} = require('mail/static/src/model/model_field.js');
registerInstancePatchModel('mail.messaging_initializer', 'mail/static/src/models/messaging_initializer/messaging_initializer.js', { registerInstancePatchModel(
async start() { "mail.messaging_initializer",
this._super(...arguments); "mail/static/src/models/messaging_initializer/messaging_initializer.js",
this.messaging.update({ {
failedmsg: [ async start() {
['create', { this._super(...arguments);
id: 'failedmsg', this.messaging.update({
isServerPinned: true, failedmsg: [
model: 'mail.box', [
name: this.env._t("Failed"), "create",
}] {
], id: "failedmsg",
}); isServerPinned: true,
model: "mail.box",
}, name: this.env._t("Failed"),
async _init({ },
channel_slots, ],
commands = [], ],
current_partner, });
current_user_id, },
mail_failures = {}, async _init({
mention_partner_suggestions = [], channel_slots,
menu_id, commands = [],
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_partner,
current_user_id, current_user_id,
moderation_channel_ids, mail_failures = {},
mention_partner_suggestions = [],
menu_id,
moderation_channel_ids = [],
moderation_counter = 0,
needaction_inbox_counter = 0,
partner_root, partner_root,
public_partner, public_partner,
public_partners, public_partners,
}); shortcodes = [],
// mailboxes after partners and before other initializers that might starred_counter = 0,
// manipulate threads or messages failed_counter = 0,
this._initMailboxes({ }) {
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_channel_ids,
moderation_counter, moderation_counter,
needaction_inbox_counter, needaction_inbox_counter,
starred_counter, starred_counter,
failed_counter, failed_counter,
}); }) {
// various suggestions in no particular order this.env.messaging.inbox.update({counter: needaction_inbox_counter});
this._initCannedResponses(shortcodes); this.env.messaging.starred.update({counter: starred_counter});
this._initCommands(commands); this.env.messaging.failedmsg.update({counter: failed_counter});
this._initMentionPartnerSuggestions(mention_partner_suggestions); if (moderation_channel_ids.length > 0) {
// channels when the rest of messaging is ready this.messaging.moderation.update({
await this.async(() => this._initChannels(channel_slots)); counter: moderation_counter,
// failures after channels isServerPinned: true,
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"),
}
);
registerFieldPatchModel('mail.messaging', 'mail/static/src/models/messaging/messaging.js', { registerInstancePatchModel(
failedmsg: one2one('mail.thread'), "mail.thread_cache",
"mail/static/src/models/thread_cache/thread_cache.js",
}); {
_extendMessageDomain(domain) {
registerInstancePatchModel('mail.thread_cache', 'mail/static/src/models/thread_cache/thread_cache.js', { const thread = this.thread;
_extendMessageDomain(domain) { if (thread === this.env.messaging.failedmsg) {
const thread = this.thread; return domain.concat([["is_failed_message", "=", true]]);
if (thread === this.env.messaging.failedmsg) { }
return domain.concat([
['is_failed_message', '=', true]
]);
} else {
return this._super(...arguments); 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,
}),
}
);
registerFieldPatchModel('mail.message', 'mail/static/src/models/message/message.js', { registerClassPatchModel(
messagingFailedmsg: many2one('mail.thread', { "mail.message",
related: 'messaging.failedmsg', "mail/static/src/models/message/message.js",
}), {
isFailed: attr({ convertData(data) {
default: false, const data2 = this._super(data);
}), if ("is_failed_message" in data) {
data2.isFailed = data.is_failed_message;
}); }
return data2;
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;
},
});
});

View File

@ -1,40 +1,30 @@
odoo.define('mail_tracking/static/src/js/failed_message/mail_failed_box.js', function(require) { odoo.define("mail_tracking/static/src/js/failed_message/mail_failed_box.js", function (
'use strict'; require
) {
"use strict";
const components = { const chatter = require("mail/static/src/components/chatter/chatter.js");
Message: require('mail/static/src/components/message/message.js'), const useStore = require("mail/static/src/component_hooks/use_store/use_store.js");
};
const useShouldUpdateBasedOnProps = require('mail/static/src/component_hooks/use_should_update_based_on_props/use_should_update_based_on_props.js');
const useStore = require('mail/static/src/component_hooks/use_store/use_store.js');
const chatter = require('mail/static/src/components/chatter/chatter.js');
const {
Component,
useState
} = owl;
const {Component} = owl;
class MessageFailedBox extends Component { class MessageFailedBox extends Component {
constructor(...args) { constructor(...args) {
super(...args); super(...args);
useStore(props => { useStore((props) => {
const chatter = this.env.models['mail.chatter'].get(props.chatterLocalId); const chatter = this.env.models["mail.chatter"].get(
props.chatterLocalId
);
const thread = chatter && chatter.thread; const thread = chatter && chatter.thread;
return { return {
chatter: chatter ? chatter.__state : undefined, chatter: chatter ? chatter.__state : undefined,
thread: thread && thread.__state, thread: thread && thread.__state,
}; };
}); });
} }
get chatter() { get chatter() {
return this.env.models['mail.chatter'].get(this.props.chatterLocalId); return this.env.models["mail.chatter"].get(this.props.chatterLocalId);
} }
_onClickTitle() { _onClickTitle() {
@ -44,9 +34,7 @@ odoo.define('mail_tracking/static/src/js/failed_message/mail_failed_box.js', fun
return this.env.services.rpc({ return this.env.services.rpc({
model: "mail.message", model: "mail.message",
method: "set_need_action_done", method: "set_need_action_done",
args: [ args: [[id]],
[id]
],
}); });
} }
_onRetryFailedMessage(event) { _onRetryFailedMessage(event) {
@ -54,14 +42,14 @@ odoo.define('mail_tracking/static/src/js/failed_message/mail_failed_box.js', fun
var messageID = $(event.currentTarget).data("message-id"); var messageID = $(event.currentTarget).data("message-id");
const thread = this.chatter.thread; const thread = this.chatter.thread;
var self = this; var self = this;
this.env.bus.trigger('do-action', { this.env.bus.trigger("do-action", {
action: 'mail.mail_resend_message_action', action: "mail.mail_resend_message_action",
options: { options: {
additional_context: { additional_context: {
mail_message_to_resend: messageID, mail_message_to_resend: messageID,
}, },
on_close: () => { on_close: () => {
self.trigger('reload', { keepChanges: true }); self.trigger("reload", {keepChanges: true});
thread.refresh(); thread.refresh();
}, },
}, },
@ -70,26 +58,18 @@ odoo.define('mail_tracking/static/src/js/failed_message/mail_failed_box.js', fun
_onMarkFailedMessageReviewed(event) { _onMarkFailedMessageReviewed(event) {
event.preventDefault(); event.preventDefault();
var messageID = $(event.currentTarget).data("message-id"); var messageID = $(event.currentTarget).data("message-id");
this._markFailedMessageReviewed(messageID) this._markFailedMessageReviewed(messageID);
this.trigger('reload', { keepChanges: true }); this.trigger("reload", {keepChanges: true});
this.chatter.thread.refreshMessagefailed(); this.chatter.thread.refreshMessagefailed();
this.chatter.thread.refresh(); this.chatter.thread.refresh();
} }
} }
MessageFailedBox.template = "mail_tracking.MessageFailedBox"; MessageFailedBox.template = "mail_tracking.MessageFailedBox";
MessageFailedBox.props = { MessageFailedBox.props = {
chatterLocalId: String, chatterLocalId: String,
}; };
chatter.components = Object.assign({}, chatter.components, { chatter.components = Object.assign({}, chatter.components, {
MessageFailedBox MessageFailedBox,
}); });
return MessageFailedBox; return MessageFailedBox;
});
});

View File

@ -1,60 +1,50 @@
odoo.define('mail_tracking/static/src/js/failed_message/thread.js', function(require) { odoo.define("mail_tracking/static/src/js/failed_message/thread.js", function (require) {
'use strict'; "use strict";
const components = {
Message: require('mail/static/src/components/message/message.js'),
};
const useShouldUpdateBasedOnProps = require('mail/static/src/component_hooks/use_should_update_based_on_props/use_should_update_based_on_props.js');
const useStore = require('mail/static/src/component_hooks/use_store/use_store.js');
const chatter = require('mail/static/src/components/chatter/chatter.js');
const {
Component,
useState
} = owl;
const { const {
registerInstancePatchModel, registerInstancePatchModel,
registerFieldPatchModel, registerFieldPatchModel,
} = require('mail/static/src/model/model_core.js'); } = require("mail/static/src/model/model_core.js");
const { const {one2many} = require("mail/static/src/model/model_field.js");
one2many
} = require('mail/static/src/model/model_field.js');
registerInstancePatchModel(
"mail.thread",
"mail_tracking/static/src/js/failed_message/thread.js",
registerInstancePatchModel('mail.thread', 'mail_tracking/static/src/js/failed_message/thread.js', { {
async refreshMessagefailed() {
async refreshMessagefailed() { var id = this.__values.id;
var id = this.__values.id var model = this.__values.model;
var model = this.__values.model const messagefailedData = await this.async(() =>
const messagefailedData = await this.async(() => this.env.services.rpc({ this.env.services.rpc(
model: 'mail.message', {
method: 'get_failed_messsage_info', model: "mail.message",
args: [id, model], method: "get_failed_messsage_info",
}, { args: [id, model],
shadow: true },
})); {
const messagefailed = this.env.models['mail.message.failed'].insert(messagefailedData.map( shadow: true,
messageData => this.env.models['mail.message.failed'].convertData(messageData) }
)); )
this.update({ );
messagefailed: [ const messagefailed = this.env.models["mail.message.failed"].insert(
['replace', messagefailed] messagefailedData.map((messageData) =>
] this.env.models["mail.message.failed"].convertData(messageData)
}); )
);
this.update({
messagefailed: [["replace", messagefailed]],
});
},
} }
);
}); registerFieldPatchModel(
"mail.thread",
registerFieldPatchModel('mail.thread', 'mail_tracking/static/src/js/failed_message/thread.js', { "mail_tracking/static/src/js/failed_message/thread.js",
messagefailed: one2many('mail.message.failed', { {
inverse: 'thread', messagefailed: one2many("mail.message.failed", {
}), inverse: "thread",
}),
}); }
);
}); });

View File

@ -1,48 +1,53 @@
odoo.define('mail_tracking/static/src/js/mail_tracking.js', function(require) { odoo.define("mail_tracking/static/src/js/mail_tracking.js", function (require) {
'use strict'; "use strict";
const { const {
registerClassPatchModel, registerClassPatchModel,
registerFieldPatchModel, registerFieldPatchModel,
registerInstancePatchModel, registerInstancePatchModel,
} = require('mail/static/src/model/model_core.js'); } = require("mail/static/src/model/model_core.js");
const { const {attr} = require("mail/static/src/model/model_field.js");
attr
} = require('mail/static/src/model/model_field.js');
registerClassPatchModel('mail.message', 'mail_tracking/static/src/js/mail_tracking.js', { registerClassPatchModel(
convertData(data) { "mail.message",
const data2 = this._super(data); "mail_tracking/static/src/js/mail_tracking.js",
if ('partner_trackings' in data) { {
data2.partner_trackings = data.partner_trackings; convertData(data) {
} const data2 = this._super(data);
return data2; if ("partner_trackings" in data) {
}, data2.partner_trackings = data.partner_trackings;
}); }
return data2;
},
}
);
registerFieldPatchModel('mail.message', 'mail_tracking/static/src/js/mail_tracking.js', { registerFieldPatchModel(
partner_trackings: attr(), "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);
},
registerInstancePatchModel('mail.model', 'mail_tracking/static/src/js/mail_tracking.js', { hasEmailCc() {
return _.some(this._emailCc);
},
getPartnerTrackings: function () {
hasPartnerTrackings() { if (!this.hasPartnerTrackings()) {
return _.some(this.__values.partner_trackings); return [];
}, }
return this.__values.partner_trackings;
hasEmailCc() { },
return _.some(this._emailCc); }
}, );
});
getPartnerTrackings: function() {
if (!this.hasPartnerTrackings()) {
return [];
}
return this.__values.partner_trackings;
},
})
});

View File

@ -1,11 +1,8 @@
odoo.define('mail_tracking/static/src/js/message.js', function(require) { odoo.define("mail_tracking/static/src/js/message.js", function (require) {
'use strict'; "use strict";
const Message = require('mail/static/src/components/message/message.js');
const MessageList = require('mail/static/src/components/message_list/message_list.js');
var core = require('web.core');
var _t = core._t;
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 { class MessageTracking extends Message {
constructor(parent, props) { constructor(parent, props) {
@ -14,39 +11,37 @@ odoo.define('mail_tracking/static/src/js/message.js', function(require) {
_onTrackingStatusClick(event) { _onTrackingStatusClick(event) {
var tracking_email_id = $(event.currentTarget).data("tracking"); var tracking_email_id = $(event.currentTarget).data("tracking");
event.preventDefault(); event.preventDefault();
return this.env.bus.trigger('do-action', { return this.env.bus.trigger("do-action", {
action: { action: {
type: "ir.actions.act_window", type: "ir.actions.act_window",
view_type: "form", view_type: "form",
view_mode: "form", view_mode: "form",
res_model: "mail.tracking.email", res_model: "mail.tracking.email",
views: [ views: [[false, "form"]],
[false, "form"]
],
target: "new", target: "new",
res_id: tracking_email_id, res_id: tracking_email_id,
} },
}); });
} }
// for discuss // For discuss
_onMarkFailedMessageReviewed(event) { _onMarkFailedMessageReviewed(event) {
event.preventDefault(); event.preventDefault();
var messageID = $(event.currentTarget).data("message-id"); var messageID = $(event.currentTarget).data("message-id");
this._markFailedMessageReviewed(messageID) this._markFailedMessageReviewed(messageID);
window.location.reload(); window.location.reload();
} }
_onRetryFailedMessage(event) { _onRetryFailedMessage(event) {
event.preventDefault(); event.preventDefault();
var messageID = $(event.currentTarget).data("message-id"); var messageID = $(event.currentTarget).data("message-id");
this.env.bus.trigger('do-action', { this.env.bus.trigger("do-action", {
action: 'mail.mail_resend_message_action', action: "mail.mail_resend_message_action",
options: { options: {
additional_context: { additional_context: {
mail_message_to_resend: messageID, mail_message_to_resend: messageID,
}, },
on_close: () => { on_close: () => {
window.location.reload(); window.location.reload();
}, },
}, },
}); });
@ -55,13 +50,9 @@ odoo.define('mail_tracking/static/src/js/message.js', function(require) {
return this.env.services.rpc({ return this.env.services.rpc({
model: "mail.message", model: "mail.message",
method: "set_need_action_done", method: "set_need_action_done",
args: [ args: [[id]],
[id]
],
}); });
} }
}
};
MessageList.components.Message = MessageTracking; MessageList.components.Message = MessageTracking;
});
});

View File

@ -1,53 +1,40 @@
odoo.define('mail_tracking/static/src/js/models/thread.js', function(require) { odoo.define("mail_tracking/static/src/js/models/thread.js", function (require) {
'use strict'; "use strict";
const { const {registerNewModel} = require("mail/static/src/model/model_core.js");
registerNewModel const {attr, many2one} = require("mail/static/src/model/model_field.js");
} = require('mail/static/src/model/model_core.js');
const {
attr,
many2many,
many2one
} = require('mail/static/src/model/model_field.js');
const {
clear
} = require('mail/static/src/model/model_field_command.js');
function factory(dependencies) { function factory(dependencies) {
class MessageFailed extends dependencies["mail.model"] {
class MessageFailed extends dependencies['mail.model'] {
static convertData(data) { static convertData(data) {
const data2 = {}; const data2 = {};
if ('author' in data) { if ("author" in data) {
if (!data.author) { if (!data.author) {
data2.author = [ data2.author = [["unlink-all"]];
['unlink-all']
];
} else { } else {
data2.author = data.author[1]; data2.author = data.author[1];
data2.author_id = data.author[0]; data2.author_id = data.author[0];
} }
} }
if ('body' in data) { if ("body" in data) {
data2.body = data.body; data2.body = data.body;
} }
if ('date' in data) { if ("date" in data) {
data2.date = data.date; data2.date = data.date;
} }
if ('failed_recipients' in data) { if ("failed_recipients" in data) {
data2.failed_recipients = data.failed_recipients; data2.failed_recipients = data.failed_recipients;
} }
if ('id' in data) { if ("id" in data) {
data2.id = data.id; data2.id = data.id;
} }
return data2; return data2;
} }
} }
MessageFailed.fields = { MessageFailed.fields = {
thread: many2one('mail.thread', { thread: many2one("mail.thread", {
inverse: 'messagefailed', inverse: "messagefailed",
}), }),
body: attr(), body: attr(),
author: attr(), author: attr(),
@ -57,11 +44,10 @@ odoo.define('mail_tracking/static/src/js/models/thread.js', function(require) {
id: attr(), id: attr(),
}; };
MessageFailed.modelName = 'mail.message.failed'; MessageFailed.modelName = "mail.message.failed";
return MessageFailed; return MessageFailed;
} }
registerNewModel('mail.message.failed', factory); registerNewModel("mail.message.failed", factory);
});
});

View File

@ -1,38 +1,39 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<templates> <templates>
<t t-inherit="mail.ThreadIcon" t-inherit-mode="extension"> <t t-inherit="mail.ThreadIcon" t-inherit-mode="extension">
<xpath expr="//t[@t-elif='thread === env.messaging.moderation']" <xpath
position="after"> expr="//t[@t-elif='thread === env.messaging.moderation']"
position="after"
>
<t t-elif="thread === env.messaging.failedmsg"> <t t-elif="thread === env.messaging.failedmsg">
<div class="o_ThreadIcon_mailboxModeration fa fa-exclamation"/> <div class="o_ThreadIcon_mailboxModeration fa fa-exclamation" />
</t> </t>
</xpath> </xpath>
</t> </t>
<t t-inherit="mail.Message" t-inherit-mode="extension"> <t t-inherit="mail.Message" t-inherit-mode="extension">
<xpath expr="//div[hasclass('o_Message_originThread')]" <xpath expr="//div[hasclass('o_Message_originThread')]" position="inside">
position="inside">
<t t-if="message.isFailed"> <t t-if="message.isFailed">
<span t-attf-class="o_thread_icons"> <span t-attf-class="o_thread_icons">
<a <a
href="#" href="#"
class="btn btn-link btn-success o_thread_icon text-muted btn-sm o_failed_message_reviewed o_activity_link" 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-on-click="_onMarkFailedMessageReviewed"
t-att-data-message-id="message.id" t-att-data-message-id="message.id"
> >
<i class="fa fa-check"/> <i class="fa fa-check" />
Set as Reviewed Set as Reviewed
</a> </a>
<a <a
href="#" href="#"
class="btn btn-link btn-success o_thread_icon text-muted btn-sm o_failed_message_retry o_activity_link" 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-on-click="_onRetryFailedMessage"
t-att-data-message-id="message.id" t-att-data-message-id="message.id"
> >
<i class="fa fa-retweet"/> <i class="fa fa-retweet" />
Retry Retry
</a> </a>
</span> </span>
</t> </t>
</xpath> </xpath>
</t> </t>
</templates> </templates>

View File

@ -2,88 +2,105 @@
<templates xml:space="preserve"> <templates xml:space="preserve">
<t t-name="mail_tracking.MessageFailedBox" owl="1"> <t t-name="mail_tracking.MessageFailedBox" owl="1">
<div class="o_ActivityBox"> <div class="o_ActivityBox">
<t t-if="chatter and chatter.thread and chatter.thread.messagefailed.length > 0"> <t
t-if="chatter and chatter.thread and chatter.thread.messagefailed.length > 0"
>
<a role="button" class="o_ActivityBox_title btn" t-on-click="_onClickTitle"> <a role="button" class="o_ActivityBox_title btn" t-on-click="_onClickTitle">
<hr class="o_ActivityBox_titleLine"/> <hr class="o_ActivityBox_titleLine" />
<span class="o_ActivityBox_titleText"> <span class="o_ActivityBox_titleText">
<i class="fa fa-fw" t-att-class="chatter.isMessageFailedBoxVisible ? 'fa-caret-down' : 'fa-caret-right'"/> <i
class="fa fa-fw"
t-att-class="chatter.isMessageFailedBoxVisible ? 'fa-caret-down' : 'fa-caret-right'"
/>
Failed messages Failed messages
</span> </span>
<t t-if="!chatter.isMessageFailedBoxVisible"> <t t-if="!chatter.isMessageFailedBoxVisible">
<span class="o_ActivityBox_titleBadges"> <span class="o_ActivityBox_titleBadges">
<t t-if="chatter.thread.messagefailed.length > 0"> <t t-if="chatter.thread.messagefailed.length > 0">
<span class="o_ActivityBox_titleBadge badge rounded-circle badge-danger"> <span
<t t-esc="chatter.thread.messagefailed.length"/> class="o_ActivityBox_titleBadge badge rounded-circle badge-danger"
>
<t t-esc="chatter.thread.messagefailed.length" />
</span> </span>
</t> </t>
</span> </span>
</t> </t>
<hr class="o_ActivityBox_titleLine"/> <hr class="o_ActivityBox_titleLine" />
</a> </a>
<t t-if="chatter.isMessageFailedBoxVisible and chatter.thread.messagefailed"> <t
t-if="chatter.isMessageFailedBoxVisible and chatter.thread.messagefailed"
>
<div class="o_ActivityList"> <div class="o_ActivityList">
<t t-foreach="chatter.thread.messagefailed" t-as="messagefailed" t-key="messagefailed.localId"> <t
t-foreach="chatter.thread.messagefailed"
t-as="messagefailed"
t-key="messagefailed.localId"
>
<div class="o_Activity"> <div class="o_Activity">
<t t-if="messagefailed"> <t t-if="messagefailed">
<div class="o_Activity_sidebar"> <div class="o_Activity_sidebar">
<div class="o_Activity_user"> <div class="o_Activity_user">
<t t-if="messagefailed.author"> <t t-if="messagefailed.author">
<img class="o_Activity_userAvatar" <img
t-attf-src="/web/image/res.users/{{ messagefailed.author_id }}/image_128" class="o_Activity_userAvatar"
t-att-alt="messagefailed.author"/> t-attf-src="/web/image/res.users/{{ messagefailed.author_id }}/image_128"
t-att-alt="messagefailed.author"
/>
</t> </t>
<div class="o_Activity_iconContainer bg-danger-full" <div class="o_Activity_iconContainer bg-danger-full">
> <i class="o_Activity_icon fa fa-exclamation" />
<i class="o_Activity_icon fa fa-exclamation"/>
</div> </div>
</div> </div>
</div> </div>
<div class="o_Activity_core"> <div class="o_Activity_core">
<div class="o_Activity_info"> <div class="o_Activity_info">
<div class="o_Activity_dueDateText" <div class="o_Activity_dueDateText" t-att-class="{}">
t-att-class="{}" <t t-esc="messagefailed.author" />
>
<t t-esc="messagefailed.author"/>
</div> </div>
<t t-if="messagefailed.date"> <t t-if="messagefailed.date">
<div class="o_Activity_summary text-muted"> <div class="o_Activity_summary text-muted">
<t t-esc="messagefailed.date"/> <t t-esc="messagefailed.date" />
</div> </div>
</t> </t>
<span t-attf-class="o_thread_icons"> <span t-attf-class="o_thread_icons">
<a <a
href="#" 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" class="btn btn-link btn-success o_thread_icon text-muted btn-sm o_failed_message_reviewed o_activity_link"
t-att-data-message-id="messagefailed.id" t-on-click="_onMarkFailedMessageReviewed"
> t-att-data-message-id="messagefailed.id"
>
<i class="fa fa-check" /> Set as Reviewed <i class="fa fa-check" /> Set as Reviewed
</a> </a>
<a <a
href="#" 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" class="btn btn-link btn-success o_thread_icon text-muted btn-sm o_failed_message_retry o_activity_link"
t-att-data-message-id="messagefailed.id" t-on-click="_onRetryFailedMessage"
> t-att-data-message-id="messagefailed.id"
>
<i class="fa fa-retweet" /> Retry <i class="fa fa-retweet" /> Retry
</a> </a>
</span> </span>
</div> </div>
<div class="o_Activity_info"> <div class="o_Activity_info">
<strong class="text-danger">Failed Recipients:</strong> <strong class="text-danger">Failed Recipients:</strong>
<t t-foreach="messagefailed.failed_recipients" t-as="recipient"> <t
t-foreach="messagefailed.failed_recipients"
t-as="recipient"
>
<t t-if="!recipient_first"> <t t-if="!recipient_first">
- -
</t> </t>
<a <a
class="o_mail_action_tracking_partner" class="o_mail_action_tracking_partner"
t-att-data-partner="recipient[1]" t-att-data-partner="recipient[1]"
t-attf-href="#model=res.partner&amp;id={{recipient[0]}}" t-attf-href="#model=res.partner&amp;id={{recipient[0]}}"
> >
<t t-esc="recipient[1]"/> <t t-esc="recipient[1]" />
</a> </a>
</t> </t>
</div> </div>
<div class="o_thread_message_note small"> <div class="o_thread_message_note small">
<t t-raw="messagefailed.body"/> <t t-raw="messagefailed.body" />
</div> </div>
</div> </div>
</t> </t>
@ -95,13 +112,16 @@
</div> </div>
</t> </t>
<t t-inherit="mail.Chatter" t-inherit-mode="extension"> <t t-inherit="mail.Chatter" t-inherit-mode="extension">
<xpath expr="//div[hasclass('o_Chatter_scrollPanel')]/t[@t-if='chatter.isAttachmentBoxVisible']" position="before"> <xpath
expr="//div[hasclass('o_Chatter_scrollPanel')]/t[@t-if='chatter.isAttachmentBoxVisible']"
position="before"
>
<t t-if="chatter.thread"> <t t-if="chatter.thread">
<MessageFailedBox <MessageFailedBox
class="o_Chatter_activityBox" class="o_Chatter_activityBox"
chatterLocalId="chatter.localId" chatterLocalId="chatter.localId"
/> />
</t> </t>
</xpath> </xpath>
</t> </t>
</templates> </templates>

View File

@ -299,7 +299,8 @@ class TestMailTracking(TransactionCase):
# No author_id # No author_id
tracking.mail_message_id.author_id = False tracking.mail_message_id.author_id = False
values = tracking.mail_message_id.get_failed_messages()[0] values = tracking.mail_message_id.get_failed_messages()[0]
self.assertEqual(values["author"][0], -1) if values and values.get("author"):
self.assertEqual(values["author"][0], -1)
def test_resend_failed_message(self): def test_resend_failed_message(self):
# This message will generate a notification for recipient # This message will generate a notification for recipient