Browse Source

mass_mailing_event (#127)

pull/367/head
Antonio Espinosa 8 years ago
committed by Dave Burkholder
parent
commit
d2334f58f8
  1. 72
      mass_mailing_event/README.rst
  2. 4
      mass_mailing_event/__init__.py
  3. 24
      mass_mailing_event/__openerp__.py
  4. 29
      mass_mailing_event/data/event_state_data.xml
  5. 96
      mass_mailing_event/i18n/es.po
  6. 8
      mass_mailing_event/models/__init__.py
  7. 20
      mass_mailing_event/models/event_registration.py
  8. 12
      mass_mailing_event/models/event_registration_state.py
  9. 54
      mass_mailing_event/models/mail_mass_mailing.py
  10. 20
      mass_mailing_event/models/mail_mass_mailing_contact.py
  11. 20
      mass_mailing_event/models/res_partner.py
  12. 2
      mass_mailing_event/security/ir.model.access.csv
  13. BIN
      mass_mailing_event/static/description/icon.png
  14. 4
      mass_mailing_event/tests/__init__.py
  15. 123
      mass_mailing_event/tests/test_mass_mailing_event.py
  16. 33
      mass_mailing_event/views/mass_mailing_view.xml

72
mass_mailing_event/README.rst

@ -0,0 +1,72 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
==================
Mass mailing event
==================
This module links ``mass_mailing`` with ``event`` in order to exclude
recipients that are already registered, confirmed, cancelled, attended, or a
combination of these states, when the mass mailing is sent.
Usage
=====
In a mass mailing, users can set an event related and exclude the recipients who
have an email address already registered in that event.
This is useful in this scenario:
1. Create a mass mailing for telling to 1000 partners that a new event is
available.
2. During a week some of them (50) have been registered in the event
3. Then, a week after the first mass mailing, duplicate it to get a second
mass mailing. Relate this one to the event and exclude the registered emails.
Change the message body to remember that early bird period is going to expire
soon.
4. Send the second mass mailing and registered emails are automatically excluded,
So it's been only sent to 950 partners the ones who are not registered in the
event yet.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/205/8.0
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/social/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.
Credits
=======
Images
------
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
Contributors
------------
* Antonio Espinosa <antonio.espinosa@tecnativa.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.

4
mass_mailing_event/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models

24
mass_mailing_event/__openerp__.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Mass mailing event",
"summary": "Link mass mailing with event for excluding recipients",
"version": "8.0.1.0.0",
"category": "Marketing",
"website": "https://odoo-community.org/",
"author": "Tecnativa, Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"mass_mailing",
"event",
],
"data": [
"security/ir.model.access.csv",
"data/event_state_data.xml",
"views/mass_mailing_view.xml",
],
}

29
mass_mailing_event/data/event_state_data.xml

@ -0,0 +1,29 @@
<?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). -->
<openerp>
<data>
<record id="event_draft" model="event.registration.state">
<field name="name">Unconfirmed</field>
<field name="code">draft</field>
</record>
<record id="event_cancel" model="event.registration.state">
<field name="name">Cancelled</field>
<field name="code">cancel</field>
</record>
<record id="event_open" model="event.registration.state">
<field name="name">Confirmed</field>
<field name="code">open</field>
</record>
<record id="event_done" model="event.registration.state">
<field name="name">Attended</field>
<field name="code">done</field>
</record>
</data>
</openerp>

96
mass_mailing_event/i18n/es.po

@ -0,0 +1,96 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mass_mailing_event
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-07 11:16+0000\n"
"PO-Revision-Date: 2016-11-07 11:16+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: mass_mailing_event
#: field:event.registration.state,code:0
msgid "Code"
msgstr "Código"
#. module: mass_mailing_event
#: field:event.registration.state,create_uid:0
msgid "Created by"
msgstr "Creado por"
#. module: mass_mailing_event
#: field:event.registration.state,create_date:0
msgid "Created on"
msgstr "Creado en"
#. module: mass_mailing_event
#: field:event.registration.state,display_name:0
msgid "Display Name"
msgstr "Nombre mostrado"
#. module: mass_mailing_event
#: model:ir.model,name:mass_mailing_event.model_event_registration
msgid "Event Registration"
msgstr "Registro de evento"
#. module: mass_mailing_event
#: field:mail.mass_mailing,event_id:0
msgid "Event related"
msgstr "Evento relacionado"
#. module: mass_mailing_event
#: field:mail.mass_mailing,exclude_event_state_ids:0
msgid "Exclude"
msgstr "Excluir"
#. module: mass_mailing_event
#: field:event.registration.state,id:0
msgid "ID"
msgstr "ID"
#. module: mass_mailing_event
#: field:event.registration.state,__last_update:0
msgid "Last Modified on"
msgstr "Última modificación en"
#. module: mass_mailing_event
#: field:event.registration.state,write_uid:0
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: mass_mailing_event
#: field:event.registration.state,write_date:0
msgid "Last Updated on"
msgstr "Última actualización en"
#. module: mass_mailing_event
#: model:ir.model,name:mass_mailing_event.model_mail_mass_mailing
msgid "Mass Mailing"
msgstr "Envío masivo"
#. module: mass_mailing_event
#: model:ir.model,name:mass_mailing_event.model_mail_mass_mailing_contact
msgid "Mass Mailing Contact"
msgstr "Contacto"
#. module: mass_mailing_event
#: field:event.registration.state,name:0
msgid "Name"
msgstr "Nombre"
#. module: mass_mailing_event
#: model:ir.model,name:mass_mailing_event.model_res_partner
msgid "Partner"
msgstr "Empresa"
#. module: mass_mailing_event
#: view:mail.mass_mailing:mass_mailing_event.view_mail_mass_mailing_form
msgid "{'search_default_not_opt_out': 1, 'exclude_mass_mailing': active_id}"
msgstr "{'search_default_not_opt_out': 1, 'exclude_mass_mailing': active_id}"

8
mass_mailing_event/models/__init__.py

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import event_registration_state
from . import mail_mass_mailing
from . import mail_mass_mailing_contact
from . import res_partner
from . import event_registration

20
mass_mailing_event/models/event_registration.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, api
from .mail_mass_mailing import event_filtered_ids
class EventRegistration(models.Model):
_inherit = 'event.registration'
@api.model
def search_count(self, domain):
res = super(EventRegistration, self).search_count(domain)
mass_mailing_id = self.env.context.get('exclude_mass_mailing', False)
if mass_mailing_id:
res_ids = event_filtered_ids(
self, mass_mailing_id, domain, field='email')
return len(res_ids) if res_ids else 0
return res

12
mass_mailing_event/models/event_registration_state.py

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields
class EventRegistrationState(models.Model):
_name = 'event.registration.state'
name = fields.Char(required=True)
code = fields.Char(required=True)

54
mass_mailing_event/models/mail_mass_mailing.py

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import copy
from openerp import models, fields, api
def event_filtered_ids(model, mass_mailing_id, domain, field='email'):
field = field or 'email'
domain = domain or []
exclude_emails = []
mass_mailing = model.env['mail.mass_mailing'].browse(mass_mailing_id)
if mass_mailing.event_id:
exclude = mass_mailing.exclude_event_state_ids.mapped('code')
reg_domain = False
registrations = model.env['event.registration']
if exclude:
reg_domain = [
('event_id', '=', mass_mailing.event_id.id),
('state', 'in', exclude)
]
if reg_domain:
registrations = registrations.search(reg_domain)
if registrations:
exclude_emails = registrations.mapped('email')
apply_domain = copy.deepcopy(domain)
if exclude_emails:
apply_domain.append((field, 'not in', exclude_emails))
rows = model.search(apply_domain)
return rows.ids
class MailMassMailing(models.Model):
_inherit = 'mail.mass_mailing'
def _default_exclude_event_state_ids(self):
return self.env['event.registration.state'].search([])
event_id = fields.Many2one(
string="Event related", comodel_name='event.event')
exclude_event_state_ids = fields.Many2many(
comodel_name='event.registration.state',
string="Exclude", default=_default_exclude_event_state_ids)
@api.model
def get_recipients(self, mailing):
res_ids = super(MailMassMailing, self).get_recipients(mailing)
if res_ids:
domain = [('id', 'in', res_ids)]
return event_filtered_ids(
self.env[mailing.mailing_model], mailing.id, domain,
field='email')
return res_ids

20
mass_mailing_event/models/mail_mass_mailing_contact.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, api
from .mail_mass_mailing import event_filtered_ids
class MailMassMailingContact(models.Model):
_inherit = 'mail.mass_mailing.contact'
@api.model
def search_count(self, domain):
res = super(MailMassMailingContact, self).search_count(domain)
mass_mailing_id = self.env.context.get('exclude_mass_mailing', False)
if mass_mailing_id:
res_ids = event_filtered_ids(
self, mass_mailing_id, domain, field='email')
return len(res_ids) if res_ids else 0
return res

20
mass_mailing_event/models/res_partner.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, api
from .mail_mass_mailing import event_filtered_ids
class ResPartner(models.Model):
_inherit = 'res.partner'
@api.model
def search_count(self, domain):
res = super(ResPartner, self).search_count(domain)
mass_mailing_id = self.env.context.get('exclude_mass_mailing', False)
if mass_mailing_id:
res_ids = event_filtered_ids(
self, mass_mailing_id, domain, field='email')
return len(res_ids) if res_ids else 0
return res

2
mass_mailing_event/security/ir.model.access.csv

@ -0,0 +1,2 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_event_registration_state_group_user","event_registration_state group_user","model_event_registration_state","base.group_user",1,0,0,0

BIN
mass_mailing_event/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 9.2 KiB

4
mass_mailing_event/tests/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_mass_mailing_event

123
mass_mailing_event/tests/test_mass_mailing_event.py

@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import datetime, timedelta
from openerp.tests.common import TransactionCase
class TestMassMailingEvent(TransactionCase):
def setUp(self, *args, **kwargs):
super(TestMassMailingEvent, self).setUp(*args, **kwargs)
day_1 = (datetime.now() + timedelta(days=1)).strftime(
'%Y-%m-%d 8:00:00')
day_2 = (datetime.now() + timedelta(days=5)).strftime(
'%Y-%m-%d 18:00:00')
self.event = self.env['event.event'].create({
'name': 'Test event',
'date_begin': day_1,
'date_end': day_2,
})
self.registration = self.env['event.registration'].create({
'event_id': self.event.id,
'email': 'partner_a@example.org',
'nb_register': 1,
'state': 'draft',
})
self.states_all = self.env['event.registration.state'].search([])
self.state_confirmed = self.env['event.registration.state'].search([
('code', '=', 'open'),
])
def test_mailing_contact(self):
contact_list = self.env['mail.mass_mailing.list'].create({
'name': 'Test list',
})
contact_a = self.env['mail.mass_mailing.contact'].create({
'list_id': contact_list.id,
'name': 'Test contact A',
'email': 'partner_a@example.org',
})
contact_b = self.env['mail.mass_mailing.contact'].create({
'list_id': contact_list.id,
'name': 'Test contact B',
'email': 'partner_b@example.org',
})
domain = [
('list_id', 'in', [contact_list.id]),
('opt_out', '=', False),
]
mass_mailing = self.env['mail.mass_mailing'].create({
'name': 'Test subject',
'email_from': 'from@example.com',
'mailing_model': 'mail.mass_mailing.contact',
'mailing_domain': str(domain),
'contact_list_ids': [(6, False, [contact_list.id])],
'body_html': '<p>Test email body</p>',
'reply_to_mode': 'email',
})
m_contact = self.env['mail.mass_mailing.contact'].with_context(
exclude_mass_mailing=mass_mailing.id)
self.assertEqual(
[contact_a.id, contact_b.id],
mass_mailing.get_recipients(mass_mailing))
self.assertEqual(2, m_contact.search_count(domain))
mass_mailing.write({
'event_id': self.event.id,
'exclude_event_state_ids': [(6, False, self.states_all.ids)],
})
self.assertEqual(
[contact_b.id],
mass_mailing.get_recipients(mass_mailing))
self.assertEqual(1, m_contact.search_count(domain))
mass_mailing.write({
'exclude_event_state_ids': [(6, False, self.state_confirmed.ids)],
})
self.assertEqual(
[contact_a.id, contact_b.id],
mass_mailing.get_recipients(mass_mailing))
self.assertEqual(2, m_contact.search_count(domain))
def test_mailing_partner(self):
partner_a = self.env['res.partner'].create({
'name': 'Test partner A',
'email': 'partner_a@example.org',
})
partner_b = self.env['res.partner'].create({
'name': 'Test partner B',
'email': 'partner_b@example.org',
})
domain = [
('id', 'in', [partner_a.id, partner_b.id]),
('opt_out', '=', False),
]
mass_mailing = self.env['mail.mass_mailing'].create({
'name': 'Test subject',
'email_from': 'from@example.com',
'mailing_model': 'res.partner',
'mailing_domain': str(domain),
'body_html': '<p>Test email body</p>',
'reply_to_mode': 'email',
})
m_partner = self.env['res.partner'].with_context(
exclude_mass_mailing=mass_mailing.id)
self.assertEqual(
[partner_a.id, partner_b.id],
mass_mailing.get_recipients(mass_mailing))
self.assertEqual(2, m_partner.search_count(domain))
mass_mailing.write({
'event_id': self.event.id,
'exclude_event_state_ids': [(6, False, self.states_all.ids)],
})
self.assertEqual(
[partner_b.id],
mass_mailing.get_recipients(mass_mailing))
self.assertEqual(1, m_partner.search_count(domain))
mass_mailing.write({
'exclude_event_state_ids': [(6, False, self.state_confirmed.ids)],
})
self.assertEqual(
[partner_a.id, partner_b.id],
mass_mailing.get_recipients(mass_mailing))
self.assertEqual(2, m_partner.search_count(domain))

33
mass_mailing_event/views/mass_mailing_view.xml

@ -0,0 +1,33 @@
<?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). -->
<openerp>
<data>
<record model="ir.ui.view" id="view_mail_mass_mailing_form">
<field name="name">Add event and exclude</field>
<field name="model">mail.mass_mailing</field>
<field name="inherit_id" ref="mass_mailing.view_mail_mass_mailing_form"/>
<field name="arch" type="xml">
<field name="mailing_domain" position="attributes">
<attribute name="context">{'search_default_not_opt_out': 1, 'exclude_mass_mailing': active_id}</attribute>
</field>
<notebook position="before">
<group>
<group>
<field name="event_id"/>
</group>
<group>
<field name="exclude_event_state_ids"
widget="many2many_tags"
options="{'no_create_edit': True}"
attrs="{'invisible': [('event_id', '=', False)]}"/>
</group>
</group>
</notebook>
</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save