349 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			349 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
from datetime import datetime, timedelta
 | 
						|
from odoo.tools.safe_eval import safe_eval
 | 
						|
from odoo import api, fields, models, tools, _
 | 
						|
from odoo.exceptions import Warning, ValidationError
 | 
						|
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
 | 
						|
 | 
						|
from email.utils import formataddr, parseaddr
 | 
						|
 | 
						|
REPLACEMENT_OF_KEY = [('id', 'mailchimp_id'), ('create_time', 'create_date'), ('send_time', 'sent_date'),
 | 
						|
                      ('type', 'mailchimp_champ_type')]
 | 
						|
DATE_CONVERSION = ['create_date', 'sent_date']
 | 
						|
UNWANTED_DATA = ['_links', 'created_by', 'edited_by', 'thumbnail']
 | 
						|
 | 
						|
 | 
						|
class MassMailing(models.Model):
 | 
						|
    _inherit = "mail.mass_mailing"
 | 
						|
 | 
						|
    create_date = fields.Datetime("Created on", readonly=True, index=True)
 | 
						|
    mailchimp_template_id = fields.Many2one('mailchimp.templates', "MailChimp Template", copy=False)
 | 
						|
    mailchimp_account_id = fields.Many2one('mailchimp.accounts', string="MailChimp Account",
 | 
						|
                                           related="mailchimp_template_id.account_id", store=True)
 | 
						|
    mailchimp_list_id = fields.Many2one("mailchimp.lists", string="MailChimp List")
 | 
						|
    mailchimp_id = fields.Char("MailChimp ID", copy=False)
 | 
						|
    mailchimp_segment_id = fields.Many2one('mailchimp.segments', string="MailChimp Segments", copy=False)
 | 
						|
    mailchimp_champ_type = fields.Selection(
 | 
						|
        [('regular', 'Regular'), ('plaintext', 'Plain Text'), ('absplit', 'AB Split'), ('rss', 'RSS'),
 | 
						|
         ('variate', 'Variate')],
 | 
						|
        default='regular', string="Type")
 | 
						|
 | 
						|
    def update_opt_out_ts(self, email, list_ids, value):
 | 
						|
        if len(list_ids) > 0:
 | 
						|
            model = self.env['mail.mass_mailing.contact'].with_context(active_test=False)
 | 
						|
            records = model.search([('email', '=ilike', email), ('list_ids', 'in', list_ids)])
 | 
						|
            records.write({'opt_out': value})
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def action_schedule_date(self):
 | 
						|
        self.ensure_one()
 | 
						|
        action = self.env.ref('mailchimp.mass_mailing_schedule_date_action').read()[0]
 | 
						|
        action['context'] = dict(self.env.context, default_mass_mailing_id=self.id)
 | 
						|
        return action
 | 
						|
 | 
						|
    @api.model
 | 
						|
    def fetch_send_to_activity(self):
 | 
						|
        self.ensure_one()
 | 
						|
        account = self.mailchimp_template_id.account_id
 | 
						|
        if not account:
 | 
						|
            return True
 | 
						|
        count = 1000
 | 
						|
        offset = 0
 | 
						|
        sent_to_lists = []
 | 
						|
        while True:
 | 
						|
            prepared_vals = {'count': count, 'offset': offset,
 | 
						|
                             'fields': 'sent_to.status,sent_to.email_address'}
 | 
						|
            response = account._send_request(
 | 
						|
                'reports/%s/sent-to' % self.mailchimp_id, {}, params=prepared_vals)
 | 
						|
            if len(response.get('sent_to')) == 0:
 | 
						|
                break
 | 
						|
            if isinstance(response.get('sent_to'), dict):
 | 
						|
                sent_to_lists += [response.get('sent_to')]
 | 
						|
            sent_to_lists += response.get('sent_to')
 | 
						|
            offset = offset + 1000
 | 
						|
        return sent_to_lists
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def process_send_to_activity_report(self):
 | 
						|
        self.ensure_one()
 | 
						|
        stat_obj = self.env['mail.mail.statistics']
 | 
						|
        sent_to_lists = self.fetch_send_to_activity()
 | 
						|
        if not sent_to_lists:
 | 
						|
            return True
 | 
						|
        domain = safe_eval(self.mailing_domain)
 | 
						|
        contact_ids = self.env[self.mailing_model_real].search(domain)
 | 
						|
        for record_dict in sent_to_lists:
 | 
						|
            prepared_vals = {}
 | 
						|
            email_address = record_dict.get('email_address')
 | 
						|
            status = record_dict.get('status')
 | 
						|
            if status == 'sent':
 | 
						|
                prepared_vals.update({'sent': self.sent_date, 'scheduled': self.sent_date, 'bounced': False})
 | 
						|
            elif status in ['hard', 'soft']:
 | 
						|
                prepared_vals.update({'bounced': self.sent_date, 'sent': self.sent_date, 'scheduled': self.sent_date})
 | 
						|
            existing = self.statistics_ids.filtered(lambda x: x.email == email_address)
 | 
						|
            if existing:
 | 
						|
                existing.write(prepared_vals)
 | 
						|
            else:
 | 
						|
                res_id = contact_ids.filtered(lambda x: x.email == email_address)
 | 
						|
                prepared_vals.update({
 | 
						|
                    'model': self.mailing_model_real,
 | 
						|
                    'res_id': res_id.id,
 | 
						|
                    'mass_mailing_id': self.id,
 | 
						|
                    'email': email_address,
 | 
						|
                })
 | 
						|
                self.statistics_ids.create(prepared_vals)
 | 
						|
        return sent_to_lists
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def process_email_activity_report(self):
 | 
						|
        self.ensure_one()
 | 
						|
        self.process_send_to_activity_report()
 | 
						|
        account = self.mailchimp_template_id.account_id
 | 
						|
        count = 1000
 | 
						|
        offset = 0
 | 
						|
        email_lists = []
 | 
						|
        while True:
 | 
						|
            prepared_vals = {'count': count, 'offset': offset, 'fields': 'emails.email_address,emails.activity'}
 | 
						|
            response = account._send_request(
 | 
						|
                'reports/%s/email-activity' % self.mailchimp_id, {}, params=prepared_vals)
 | 
						|
            if len(response.get('emails')) == 0:
 | 
						|
                break
 | 
						|
            if isinstance(response.get('emails'), dict):
 | 
						|
                email_lists += [response.get('emails')]
 | 
						|
            email_lists += response.get('emails')
 | 
						|
            offset = offset + 1000
 | 
						|
 | 
						|
        for email in email_lists:
 | 
						|
            email_address = email.get('email_address')
 | 
						|
            activities = email.get('activity')
 | 
						|
            if not activities:
 | 
						|
                continue
 | 
						|
            prepared_vals = {}
 | 
						|
            for acitvity in activities:
 | 
						|
                action = acitvity.get('action')
 | 
						|
                if action == 'open':
 | 
						|
                    prepared_vals.update({'opened': account.covert_date(acitvity.get('timestamp'))})
 | 
						|
                elif action == 'click':
 | 
						|
                    prepared_vals.update({'clicked': account.covert_date(acitvity.get('timestamp'))})
 | 
						|
                elif action == 'bounce':
 | 
						|
                    prepared_vals.update({'bounced': account.covert_date(acitvity.get('timestamp'))})
 | 
						|
            existing = self.statistics_ids.filtered(lambda x: x.email == email_address)
 | 
						|
            if existing:
 | 
						|
                existing.write(prepared_vals)
 | 
						|
 | 
						|
    @api.model
 | 
						|
    def fetch_email_activity(self):
 | 
						|
        stat_obj = self.env['mail.mail.statistics']
 | 
						|
        sent_date = datetime.today() - timedelta(days=30)
 | 
						|
        sent_date = sent_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
 | 
						|
        for record in self.search([('state', 'not in', ['draft', 'in_queue']), ('mailchimp_id', '!=', False), ('sent_date', '>=', sent_date)]):
 | 
						|
            record.fetch_campaign()
 | 
						|
            # record.process_email_activity_report()
 | 
						|
        return True
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def create_or_update_campaigns(self, values_dict, account=False):
 | 
						|
        fetch_needed = False
 | 
						|
        list_obj = self.env['mailchimp.lists']
 | 
						|
        template_obj = self.env['mailchimp.templates']
 | 
						|
        mailchimp_id = values_dict.get('id')
 | 
						|
        settings_dict = values_dict.get('settings')
 | 
						|
        recipients_dict = values_dict.get('recipients')
 | 
						|
        list_id = recipients_dict.get('list_id')
 | 
						|
        template_id = settings_dict.get('template_id')
 | 
						|
        if list_id:
 | 
						|
            list_obj = list_obj.search([('list_id', '=', list_id)]).odoo_list_id
 | 
						|
        if template_id:
 | 
						|
            template_obj = template_obj.search([('template_id', '=', template_id), ('account_id', '=', account.id)])
 | 
						|
        status = values_dict.get('status')
 | 
						|
        subject_line = settings_dict.get('subject_line') or settings_dict.get('title')
 | 
						|
        try:
 | 
						|
            email_from = formataddr((settings_dict.get('from_name'), settings_dict.get('reply_to')))
 | 
						|
        except Exception as e:
 | 
						|
            email_from = self.env['mail.message']._get_default_from()
 | 
						|
        prepared_vals = {
 | 
						|
            'create_date': values_dict.get('create_time'),
 | 
						|
            'sent_date': values_dict.get('send_time'),
 | 
						|
            'name': subject_line,
 | 
						|
            'mailchimp_id': mailchimp_id,
 | 
						|
            'mailing_model_id': self.env.ref('mass_mailing.model_mail_mass_mailing_list').id,
 | 
						|
            'contact_list_ids': [(6, 0, list_obj.ids)],
 | 
						|
            'mailchimp_template_id': template_obj.id,
 | 
						|
            'mailchimp_champ_type': values_dict.get('type'),
 | 
						|
            'email_from': email_from,
 | 
						|
            'reply_to': email_from,
 | 
						|
        }
 | 
						|
        if status in ['save', 'paused']:
 | 
						|
            prepared_vals.update({'state': 'draft'})
 | 
						|
        elif status == 'schedule':
 | 
						|
            prepared_vals.update({'state': 'in_queue'})
 | 
						|
        elif status == 'sending':
 | 
						|
            prepared_vals.update({'state': 'sending'})
 | 
						|
        elif status == 'sent':
 | 
						|
            fetch_needed = True
 | 
						|
            prepared_vals.update({'state': 'done'})
 | 
						|
        for item in DATE_CONVERSION:
 | 
						|
            if prepared_vals.get(item, False) == '':
 | 
						|
                prepared_vals[item] = False
 | 
						|
            if prepared_vals.get(item, False):
 | 
						|
                prepared_vals[item] = account.covert_date(prepared_vals.get(item))
 | 
						|
        existing_list = self.search([('mailchimp_id', '=', mailchimp_id)])
 | 
						|
        if not existing_list:
 | 
						|
            existing_list = self.create(prepared_vals)
 | 
						|
            self.env.cr.execute("""
 | 
						|
                           UPDATE
 | 
						|
                           mail_mass_mailing
 | 
						|
                           SET create_date = '%s'
 | 
						|
                           WHERE id = %s
 | 
						|
                           """ % (prepared_vals.get('create_date'), existing_list.id))
 | 
						|
        else:
 | 
						|
            existing_list.write(prepared_vals)
 | 
						|
        existing_list._onchange_model_and_list()
 | 
						|
        existing_list.body_html = False
 | 
						|
        if fetch_needed:
 | 
						|
            existing_list.process_email_activity_report()
 | 
						|
        return True
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def fetch_campaign(self):
 | 
						|
        self.ensure_one()
 | 
						|
        if not self.mailchimp_id:
 | 
						|
            return True
 | 
						|
        account = self.mailchimp_template_id.account_id
 | 
						|
        params_vals = {
 | 
						|
            'fields': 'id,type,status,create_time,send_time,settings.template_id,settings.subject_line,settings.title,settings.from_name,settings.reply_to,recipients.list_id'}
 | 
						|
        response = account._send_request('campaigns/%s' % self.mailchimp_id, {}, params=params_vals)
 | 
						|
        self.create_or_update_campaigns(response, account=account)
 | 
						|
        return True
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def import_campaigns(self, account=False):
 | 
						|
        if not account:
 | 
						|
            raise Warning("MailChimp Account not defined to import Campaigns")
 | 
						|
        count = 1000
 | 
						|
        offset = 0
 | 
						|
        campaigns_list = []
 | 
						|
        while True:
 | 
						|
            prepared_vals = {'count': count, 'offset': offset}
 | 
						|
            response = account._send_request('campaigns', {}, params=prepared_vals)
 | 
						|
            if len(response.get('campaigns')) == 0:
 | 
						|
                break
 | 
						|
            if isinstance(response.get('campaigns'), dict):
 | 
						|
                campaigns_list += [response.get('campaigns')]
 | 
						|
            campaigns_list += response.get('campaigns')
 | 
						|
            offset = offset + 1000
 | 
						|
        for campaigns_dict in campaigns_list:
 | 
						|
            self.create_or_update_campaigns(campaigns_dict, account=account)
 | 
						|
        return True
 | 
						|
 | 
						|
    @api.model
 | 
						|
    def _prepare_vals_for_export(self):
 | 
						|
        self.ensure_one()
 | 
						|
        from_name, from_email = parseaddr(self.email_from)
 | 
						|
        reply_to_name, reply_to_email = parseaddr(self.reply_to)
 | 
						|
        settings_dict = {'subject_line': self.name, 'title': self.name, 'from_name': from_name,
 | 
						|
                         'reply_to': reply_to_email, 'template_id': int(self.mailchimp_template_id.template_id)}
 | 
						|
        prepared_vals = {'type': 'regular',
 | 
						|
                         'recipients': {'list_id': self.contact_list_ids.mailchimp_list_id.list_id, },
 | 
						|
                         'settings': settings_dict}
 | 
						|
        if self.mailchimp_segment_id.mailchimp_id:
 | 
						|
            prepared_vals['recipients'].update({'segment_opts': {'saved_segment_id': int(self.mailchimp_segment_id.mailchimp_id)}})
 | 
						|
        return prepared_vals
 | 
						|
 | 
						|
    @api.one
 | 
						|
    def export_to_mailchimp(self, account=False):
 | 
						|
        if self.mailchimp_id:
 | 
						|
            return True
 | 
						|
        if not account:
 | 
						|
            raise Warning("MailChimp Account not defined in selected Template.")
 | 
						|
        prepared_vals = self._prepare_vals_for_export()
 | 
						|
        response = account._send_request('campaigns', prepared_vals, method='POST')
 | 
						|
        if response.get('id', False):
 | 
						|
            self.write({'mailchimp_id': response['id']})
 | 
						|
        else:
 | 
						|
            ValidationError(_("MailChimp Identification wasn't received. Please try again!"))
 | 
						|
        self._cr.commit()
 | 
						|
        return True
 | 
						|
 | 
						|
    @api.one
 | 
						|
    def send_now_mailchimp(self, account=False):
 | 
						|
        if not account:
 | 
						|
            raise Warning("MailChimp Account not defined in selected Template.")
 | 
						|
        response = account._send_request('campaigns/%s/actions/send' % self.mailchimp_id, {}, method='POST')
 | 
						|
        return True
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def send_test_mail_mailchimp(self, test_emails):
 | 
						|
        self.ensure_one()
 | 
						|
        self.export_to_mailchimp(self.mailchimp_template_id.account_id)
 | 
						|
        prepared_vals = {'test_emails': test_emails, 'send_type': 'html'}
 | 
						|
        response = self.mailchimp_template_id.account_id._send_request('campaigns/%s/actions/test' % self.mailchimp_id,
 | 
						|
                                                                       prepared_vals, method='POST')
 | 
						|
        return True
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def schedule_mailchimp_champaign(self, schedule_date):
 | 
						|
        self.ensure_one()
 | 
						|
        self.export_to_mailchimp(self.mailchimp_template_id.account_id)
 | 
						|
        prepared_vals = {'schedule_time': schedule_date.isoformat()}
 | 
						|
        response = self.mailchimp_template_id.account_id._send_request(
 | 
						|
            'campaigns/%s/actions/schedule' % self.mailchimp_id,
 | 
						|
            prepared_vals, method='POST')
 | 
						|
        return True
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def cancel_mass_mailing(self):
 | 
						|
        res = super(MassMailing, self).cancel_mass_mailing()
 | 
						|
        if self.mailchimp_id and self.mailchimp_template_id:
 | 
						|
            self.mailchimp_template_id.account_id._send_request('campaigns/%s/actions/cancel-send' % self.mailchimp_id,
 | 
						|
                                                                {}, method='POST')
 | 
						|
            if self.schedule_date:
 | 
						|
                self.mailchimp_template_id.account_id._send_request(
 | 
						|
                    'campaigns/%s/actions/unschedule' % self.mailchimp_id,
 | 
						|
                    {}, method='POST')
 | 
						|
        return res
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def put_in_queue(self):
 | 
						|
        res = super(MassMailing, self).put_in_queue()
 | 
						|
        for record in self.filtered(lambda x: x.mailchimp_template_id):
 | 
						|
            if len(record.contact_list_ids) > 1:
 | 
						|
                raise ValidationError(_("Multiple list is not allowed while going with MailChimp!"))
 | 
						|
            if record.contact_list_ids.filtered(lambda x: not x.mailchimp_list_id):
 | 
						|
                raise ValidationError(_("Please provide MailChimp list as you selected MailChimp Template!"))
 | 
						|
            record.export_to_mailchimp(record.mailchimp_template_id.account_id)
 | 
						|
            if record.mailchimp_id:
 | 
						|
                record.send_now_mailchimp(record.mailchimp_template_id.account_id)
 | 
						|
                record.process_send_to_activity_report()
 | 
						|
                record.fetch_campaign()
 | 
						|
        return res
 | 
						|
 | 
						|
    @api.model
 | 
						|
    def _process_mass_mailing_queue(self):
 | 
						|
        mass_mailings = self.search(
 | 
						|
            [('state', 'in', ('in_queue', 'sending')), '|', ('schedule_date', '<', fields.Datetime.now()),
 | 
						|
             ('schedule_date', '=', False)])
 | 
						|
        for mass_mailing in mass_mailings:
 | 
						|
            user = mass_mailing.write_uid or self.env.user
 | 
						|
            mass_mailing = mass_mailing.with_context(**user.sudo(user=user).context_get())
 | 
						|
            if mass_mailing.mailchimp_id:
 | 
						|
                mass_mailing.fetch_campaign()
 | 
						|
                continue
 | 
						|
            if len(mass_mailing.get_remaining_recipients()) > 0:
 | 
						|
                mass_mailing.state = 'sending'
 | 
						|
                mass_mailing.send_mail()
 | 
						|
            else:
 | 
						|
                mass_mailing.write({'state': 'done', 'sent_date': fields.Datetime.now()})
 | 
						|
 | 
						|
    @api.onchange('mailing_model_id', 'contact_list_ids')
 | 
						|
    def _onchange_model_and_list(self):
 | 
						|
        res = super(MassMailing, self)._onchange_model_and_list()
 | 
						|
        mailing_domain = []
 | 
						|
        list_obj = self.env['mailchimp.lists']
 | 
						|
        list_ids = list_obj.search([('odoo_list_id', 'in', self.contact_list_ids.ids)])
 | 
						|
 | 
						|
        self.mailchimp_list_id = list_ids and list_ids[0] or False
 | 
						|
        if self.mailchimp_list_id:
 | 
						|
            self.email_from = formataddr((self.mailchimp_list_id.from_name, self.mailchimp_list_id.from_email))
 | 
						|
            self.reply_to = formataddr((self.mailchimp_list_id.from_name, self.mailchimp_list_id.from_email))
 | 
						|
        return res
 |