PURPOSE This commit removes the mass_mailing.campaign model. Instead of having a fully fledged model, we will simply inherit utm.campaign. We will also add relevant statistics on utm campaign model in order to use it in various applications. SPECIFICATIONS This commit removes the mass_mailing.campaign model. Instead of having a fully fledged model, we will simply inherit utm.campaign. This change implies that mass_mailing.tag and mass_mailing.stage have to move to the utm model along their associated views/data. These changes were made so that campaigns could be used in the future by social, mass_mailing and mass_sms and available in the same view This commit also removes the source_id and the medium_id fields on the campaign. This commit also moves the unique_ab_testing field from the mass_mailing_campaign to the mass_mailing model Task ID: 2002029 PR: #34015
118 lines
5.5 KiB
Python
118 lines
5.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, fields, models
|
|
|
|
|
|
class MailingTrace(models.Model):
|
|
""" MailingTrace models the statistics collected about emails. Those statistics
|
|
are stored in a separated model and table to avoid bloating the mail_mail table
|
|
with statistics values. This also allows to delete emails send with mass mailing
|
|
without loosing the statistics about them. """
|
|
_name = 'mailing.trace'
|
|
_description = 'Mailing Statistics'
|
|
_rec_name = 'message_id'
|
|
_order = 'message_id'
|
|
|
|
# mail data
|
|
mail_mail_id = fields.Many2one('mail.mail', string='Mail', index=True)
|
|
mail_mail_id_int = fields.Integer(
|
|
string='Mail ID (tech)',
|
|
help='ID of the related mail_mail. This field is an integer field because '
|
|
'the related mail_mail can be deleted separately from its statistics. '
|
|
'However the ID is needed for several action and controllers.',
|
|
index=True,
|
|
)
|
|
email = fields.Char(string="Recipient email address")
|
|
message_id = fields.Char(string='Message-ID')
|
|
# document
|
|
model = fields.Char(string='Document model')
|
|
res_id = fields.Integer(string='Document ID')
|
|
# campaign / wave data
|
|
mass_mailing_id = fields.Many2one('mailing.mailing', string='Mass Mailing', index=True)
|
|
campaign_id = fields.Many2one(
|
|
related='mass_mailing_id.campaign_id',
|
|
string='Mass Mailing Campaign',
|
|
store=True, readonly=True, index=True)
|
|
# Bounce and tracking
|
|
ignored = fields.Datetime(help='Date when the email has been invalidated. '
|
|
'Invalid emails are blacklisted, opted-out or invalid email format')
|
|
scheduled = fields.Datetime(help='Date when the email has been created', default=fields.Datetime.now)
|
|
sent = fields.Datetime(help='Date when the email has been sent')
|
|
exception = fields.Datetime(help='Date of technical error leading to the email not being sent')
|
|
opened = fields.Datetime(help='Date when the email has been opened the first time')
|
|
replied = fields.Datetime(help='Date when this email has been replied for the first time.')
|
|
bounced = fields.Datetime(help='Date when this email has bounced.')
|
|
# Link tracking
|
|
links_click_ids = fields.One2many('link.tracker.click', 'mailing_trace_id', string='Links click')
|
|
clicked = fields.Datetime(help='Date when customer clicked on at least one tracked link')
|
|
# Status
|
|
state = fields.Selection(compute="_compute_state",
|
|
selection=[('outgoing', 'Outgoing'),
|
|
('exception', 'Exception'),
|
|
('sent', 'Sent'),
|
|
('opened', 'Opened'),
|
|
('replied', 'Replied'),
|
|
('bounced', 'Bounced'),
|
|
('ignored', 'Ignored')], store=True)
|
|
state_update = fields.Datetime(compute="_compute_state", string='State Update',
|
|
help='Last state update of the mail',
|
|
store=True)
|
|
|
|
@api.depends('sent', 'opened', 'clicked', 'replied', 'bounced', 'exception', 'ignored')
|
|
def _compute_state(self):
|
|
self.update({'state_update': fields.Datetime.now()})
|
|
for stat in self:
|
|
if stat.ignored:
|
|
stat.state = 'ignored'
|
|
elif stat.exception:
|
|
stat.state = 'exception'
|
|
elif stat.opened or stat.clicked:
|
|
stat.state = 'opened'
|
|
elif stat.replied:
|
|
stat.state = 'replied'
|
|
elif stat.bounced:
|
|
stat.state = 'bounced'
|
|
elif stat.sent:
|
|
stat.state = 'sent'
|
|
else:
|
|
stat.state = 'outgoing'
|
|
|
|
@api.model
|
|
def create(self, values):
|
|
if 'mail_mail_id' in values:
|
|
values['mail_mail_id_int'] = values['mail_mail_id']
|
|
res = super(MailingTrace, self).create(values)
|
|
return res
|
|
|
|
def _get_records(self, mail_mail_ids=None, mail_message_ids=None, domain=None):
|
|
if not self.ids and mail_mail_ids:
|
|
base_domain = [('mail_mail_id_int', 'in', mail_mail_ids)]
|
|
elif not self.ids and mail_message_ids:
|
|
base_domain = [('message_id', 'in', mail_message_ids)]
|
|
else:
|
|
base_domain = [('id', 'in', self.ids)]
|
|
if domain:
|
|
base_domain = ['&'] + domain + base_domain
|
|
return self.search(base_domain)
|
|
|
|
def set_opened(self, mail_mail_ids=None, mail_message_ids=None):
|
|
traces = self._get_records(mail_mail_ids, mail_message_ids, [('opened', '=', False)])
|
|
traces.write({'opened': fields.Datetime.now(), 'bounced': False})
|
|
return traces
|
|
|
|
def set_clicked(self, mail_mail_ids=None, mail_message_ids=None):
|
|
traces = self._get_records(mail_mail_ids, mail_message_ids, [('clicked', '=', False)])
|
|
traces.write({'clicked': fields.Datetime.now()})
|
|
return traces
|
|
|
|
def set_replied(self, mail_mail_ids=None, mail_message_ids=None):
|
|
traces = self._get_records(mail_mail_ids, mail_message_ids, [('replied', '=', False)])
|
|
traces.write({'replied': fields.Datetime.now()})
|
|
return traces
|
|
|
|
def set_bounced(self, mail_mail_ids=None, mail_message_ids=None):
|
|
traces = self._get_records(mail_mail_ids, mail_message_ids, [('bounced', '=', False), ('opened', '=', False)])
|
|
traces.write({'bounced': fields.Datetime.now()})
|
|
return traces
|