Merge PR #894 into 15.0

Signed-off-by rafaelbn
This commit is contained in:
OCA-git-bot 2022-05-24 17:31:35 +00:00
commit e887c41b74
27 changed files with 1264 additions and 0 deletions

View File

@ -0,0 +1,98 @@
==================
Mail Autosubscribe
==================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github
:target: https://github.com/OCA/social/tree/14.0/mail_autosubscribe
:alt: OCA/social
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/social-14-0/social-14-0-mail_autosubscribe
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/205/14.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allows you to configure partners that will be automatically in copy
of their company's business documents.
For example, you can configure an accountant to be in copy of all invoices
sent for a given commercial partner, regardless of the invoicing address.
**Table of contents**
.. contents::
:local:
Configuration
=============
Go to Configuration > Technical > Automation > Autosubscribe Models and configure
the models for which you want the feature to work.
Then, on each partner, you can check the company documents subscriptions in the
field `In copy of`.
This feature can be disabled on specific templates, if required, by disabling the
Autosubscribe followers field.
Known issues / Roadmap
======================
* Consider implementing domain-based autosubscription rules.
This was considered during first development but it wasn't a requirement at the time.
If pursuit, this has to be done carefully to avoid affecting performance.
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 <https://github.com/OCA/social/issues/new?body=module:%20mail_autosubscribe%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Camptocamp SA
Contributors
~~~~~~~~~~~~
* `Camptocamp <https://www.camptocamp.com>`_
* Iván Todorovich <ivan.todorovich@gmail.com>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
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.
This module is part of the `OCA/social <https://github.com/OCA/social/tree/14.0/mail_autosubscribe>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -0,0 +1 @@
from . import models

View File

@ -0,0 +1,20 @@
# Copyright 2021 Camptocamp (http://www.camptocamp.com).
# @author Iván Todorovich <ivan.todorovich@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Mail Autosubscribe",
"summary": "Automatically subscribe partners to its company's business documents",
"version": "15.0.1.0.0",
"author": "Camptocamp SA, Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Marketing",
"depends": ["mail"],
"website": "https://github.com/OCA/social",
"data": [
"security/ir.model.access.csv",
"views/mail_autosubscribe.xml",
"views/mail_template.xml",
"views/res_partner.xml",
],
}

View File

@ -0,0 +1,129 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_autosubscribe
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2022-01-25 15:40+0000\n"
"Last-Translator: jabelchi <jabelchi@gmail.com>\n"
"Language-Team: none\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.3.2\n"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_partner__mail_autosubscribe_ids
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_users__mail_autosubscribe_ids
#: model:ir.ui.menu,name:mail_autosubscribe.menu_mail_autosubscribe
msgid "Autosubscribe Models"
msgstr "Models autosubscripció"
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_base
msgid "Base"
msgstr "Base"
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_res_partner
msgid "Contact"
msgstr "Contacte"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__create_uid
msgid "Created by"
msgstr "Creat per"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__create_date
msgid "Created on"
msgstr "Creat el"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__display_name
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_template__display_name
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_thread__display_name
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_partner__display_name
msgid "Display Name"
msgstr "Nom a mostrar"
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_mail_template
msgid "Email Templates"
msgstr "Plantilles de correu"
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_mail_thread
msgid "Email Thread"
msgstr "Fil de correus"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__id
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_template__id
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_thread__id
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_partner__id
msgid "ID"
msgstr "ID"
#. module: mail_autosubscribe
#: model_terms:ir.ui.view,arch_db:mail_autosubscribe.view_partner_form
msgid "In copy of"
msgstr "En còpia de"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe____last_update
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_template____last_update
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_thread____last_update
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_partner____last_update
msgid "Last Modified on"
msgstr "Darrera modificació el"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__write_uid
msgid "Last Updated by"
msgstr "Darrera actualització per"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__write_date
msgid "Last Updated on"
msgstr "Darrera modificació el"
#. module: mail_autosubscribe
#: model:ir.actions.act_window,name:mail_autosubscribe.action_mail_autosubscribe
msgid "Mail Auto Subscribe"
msgstr "Auto subscripció de correu electrònic"
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_mail_autosubscribe
msgid "Mail Autosubscribe"
msgstr "Autosubscripció Email"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__model_id
msgid "Model"
msgstr "Model"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__model
msgid "Model Name"
msgstr "Nom del model"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__name
#: model_terms:ir.ui.view,arch_db:mail_autosubscribe.view_mail_autosubscribe_form
msgid "Name"
msgstr "Nom"
#. module: mail_autosubscribe
#: model:ir.model.constraint,message:mail_autosubscribe.constraint_mail_autosubscribe_model_id_unique
msgid "There's already a rule for this model"
msgstr "Ja existeix una regla per a aquest model"
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_template__use_autosubscribe_followers
msgid "Use Autosubscribe Followers"
msgstr "Usar seguidors autosubscrits"

View File

@ -0,0 +1,126 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_autosubscribe
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \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: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_partner__mail_autosubscribe_ids
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_users__mail_autosubscribe_ids
#: model:ir.ui.menu,name:mail_autosubscribe.menu_mail_autosubscribe
msgid "Autosubscribe Models"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_base
msgid "Base"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_res_partner
msgid "Contact"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__create_uid
msgid "Created by"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__create_date
msgid "Created on"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__display_name
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_template__display_name
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_thread__display_name
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_partner__display_name
msgid "Display Name"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_mail_template
msgid "Email Templates"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_mail_thread
msgid "Email Thread"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__id
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_template__id
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_thread__id
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_partner__id
msgid "ID"
msgstr ""
#. module: mail_autosubscribe
#: model_terms:ir.ui.view,arch_db:mail_autosubscribe.view_partner_form
msgid "In copy of"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe____last_update
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_template____last_update
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_thread____last_update
#: model:ir.model.fields,field_description:mail_autosubscribe.field_res_partner____last_update
msgid "Last Modified on"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__write_uid
msgid "Last Updated by"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__write_date
msgid "Last Updated on"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.actions.act_window,name:mail_autosubscribe.action_mail_autosubscribe
msgid "Mail Auto Subscribe"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model,name:mail_autosubscribe.model_mail_autosubscribe
msgid "Mail Autosubscribe"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__model_id
msgid "Model"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__model
msgid "Model Name"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_autosubscribe__name
#: model_terms:ir.ui.view,arch_db:mail_autosubscribe.view_mail_autosubscribe_form
msgid "Name"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.constraint,message:mail_autosubscribe.constraint_mail_autosubscribe_model_id_unique
msgid "There's already a rule for this model"
msgstr ""
#. module: mail_autosubscribe
#: model:ir.model.fields,field_description:mail_autosubscribe.field_mail_template__use_autosubscribe_followers
msgid "Use Autosubscribe Followers"
msgstr ""

View File

@ -0,0 +1,5 @@
from . import models
from . import res_partner
from . import mail_thread
from . import mail_autosubscribe
from . import mail_template

View File

@ -0,0 +1,42 @@
# Copyright 2021 Camptocamp (http://www.camptocamp.com).
# @author Iván Todorovich <ivan.todorovich@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class MailAutosubscribe(models.Model):
_name = "mail.autosubscribe"
_description = "Mail Autosubscribe"
_sql_constraints = [
(
"model_id_unique",
"UNIQUE(model_id)",
"There's already a rule for this model",
)
]
model_id = fields.Many2one(
"ir.model",
required=True,
index=True,
ondelete="cascade",
)
model = fields.Char(
related="model_id.model",
string="Model Name",
store=True,
index=True,
)
name = fields.Char(
compute="_compute_name",
store=True,
readonly=False,
)
@api.depends("model_id")
def _compute_name(self):
for rec in self:
if not rec.name:
rec.name = rec.model_id.name

View File

@ -0,0 +1,34 @@
# Copyright 2021 Camptocamp (http://www.camptocamp.com).
# @author Iván Todorovich <ivan.todorovich@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class MailTemplate(models.Model):
_inherit = "mail.template"
use_autosubscribe_followers = fields.Boolean(default=True)
def generate_recipients(self, results, res_ids):
res = super().generate_recipients(results, res_ids)
autosubscribe_followers = (
self.use_autosubscribe_followers
and not self.env.context.get("no_autosubscribe_followers")
# In this case, autosubscribers will be added by
# :func:`_message_get_default_recipients`
and not self.use_default_to
and not self.env.context.get("tpl_force_default_to")
)
if autosubscribe_followers:
for res_id in res.keys():
partners = (
self.env["res.partner"].sudo().browse(res[res_id]["partner_ids"])
)
ResModel = self.env[self.model]
followers = ResModel._message_get_autosubscribe_followers(partners)
follower_ids = [
follower.id for follower in followers if follower not in partners
]
res[res_id]["partner_ids"] += follower_ids
return res

View File

@ -0,0 +1,26 @@
# Copyright 2021 Camptocamp (http://www.camptocamp.com).
# @author Iván Todorovich <ivan.todorovich@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
class MailThread(models.AbstractModel):
_inherit = "mail.thread"
def message_subscribe(self, partner_ids=None, subtype_ids=None):
# Overload to automatically subscribe autosubscribe followers.
autosubscribe_followers = not self.env.context.get("no_autosubscribe_followers")
if partner_ids and autosubscribe_followers:
partners = self.env["res.partner"].sudo().browse(partner_ids)
followers = self._message_get_autosubscribe_followers(partners)
follower_ids = [
follower.id
for follower in followers
if follower not in partners and follower not in self.message_partner_ids
]
partner_ids += follower_ids
return super().message_subscribe(
partner_ids=partner_ids,
subtype_ids=subtype_ids,
)

View File

@ -0,0 +1,37 @@
# Copyright 2021 Camptocamp (http://www.camptocamp.com).
# @author Iván Todorovich <ivan.todorovich@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models
class BaseModel(models.AbstractModel):
_inherit = "base"
@api.model
def _message_get_autosubscribe_followers_domain(self, partners):
return [
("id", "child_of", partners.commercial_partner_id.ids),
("mail_autosubscribe_ids.model", "=", self._name),
]
@api.model
def _message_get_autosubscribe_followers(self, partners):
domain = self._message_get_autosubscribe_followers_domain(partners)
return self.env["res.partner"].sudo().search(domain)
def _message_get_default_recipients(self):
# Overload to include auto follow document partners in the composer
# Note: This only works if the template is configured with 'Default recipients'
res = super()._message_get_default_recipients()
if self.env.context.get("no_autosubscribe_followers"):
return res
for rec in self:
partner_ids = res[rec.id]["partner_ids"]
partners = self.env["res.partner"].sudo().browse(partner_ids)
followers = rec._message_get_autosubscribe_followers(partners)
follower_ids = [
follower.id for follower in followers if follower not in partners
]
partner_ids += follower_ids
return res

View File

@ -0,0 +1,16 @@
# Copyright 2021 Camptocamp (http://www.camptocamp.com).
# @author Iván Todorovich <ivan.todorovich@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ResPartner(models.Model):
_inherit = "res.partner"
mail_autosubscribe_ids = fields.Many2many(
"mail.autosubscribe",
string="Autosubscribe Models",
column1="partner_id",
column2="model_id",
)

View File

@ -0,0 +1,8 @@
Go to Configuration > Technical > Automation > Autosubscribe Models and configure
the models for which you want the feature to work.
Then, on each partner, you can check the company documents subscriptions in the
field `In copy of`.
This feature can be disabled on specific templates, if required, by disabling the
Autosubscribe followers field.

View File

@ -0,0 +1,3 @@
* `Camptocamp <https://www.camptocamp.com>`_
* Iván Todorovich <ivan.todorovich@gmail.com>

View File

@ -0,0 +1,5 @@
This module allows you to configure partners that will be automatically in copy
of their company's business documents.
For example, you can configure an accountant to be in copy of all invoices
sent for a given commercial partner, regardless of the invoicing address.

View File

@ -0,0 +1,3 @@
* Consider implementing domain-based autosubscription rules.
This was considered during first development but it wasn't a requirement at the time.
If pursuit, this has to be done carefully to avoid affecting performance.

View File

@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_mail_autosubscribe_user,access_mail_autosubscribe_user,model_mail_autosubscribe,base.group_user,1,0,0,0
access_mail_autosubscribe_system,access_mail_autosubscribe_system,model_mail_autosubscribe,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_mail_autosubscribe_user access_mail_autosubscribe_user model_mail_autosubscribe base.group_user 1 0 0 0
3 access_mail_autosubscribe_system access_mail_autosubscribe_system model_mail_autosubscribe base.group_system 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,447 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>Mail Autosubscribe</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="mail-autosubscribe">
<h1 class="title">Mail Autosubscribe</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/social/tree/14.0/mail_autosubscribe"><img alt="OCA/social" src="https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/social-14-0/social-14-0-mail_autosubscribe"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/205/14.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module allows you to configure partners that will be automatically in copy
of their companys business documents.</p>
<p>For example, you can configure an accountant to be in copy of all invoices
sent for a given commercial partner, regardless of the invoicing address.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id2">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id1">Configuration</a></h1>
<p>Go to Configuration &gt; Technical &gt; Automation &gt; Autosubscribe Models and configure
the models for which you want the feature to work.</p>
<p>Then, on each partner, you can check the company documents subscriptions in the
field <cite>In copy of</cite>.</p>
<p>This feature can be disabled on specific templates, if required, by disabling the
Autosubscribe followers field.</p>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id2">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Consider implementing domain-based autosubscription rules.
This was considered during first development but it wasnt a requirement at the time.
If pursuit, this has to be done carefully to avoid affecting performance.</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/social/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/social/issues/new?body=module:%20mail_autosubscribe%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id5">Authors</a></h2>
<ul class="simple">
<li>Camptocamp SA</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id6">Contributors</a></h2>
<ul>
<li><p class="first"><a class="reference external" href="https://www.camptocamp.com">Camptocamp</a></p>
<blockquote>
<ul class="simple">
<li>Iván Todorovich &lt;<a class="reference external" href="mailto:ivan.todorovich&#64;gmail.com">ivan.todorovich&#64;gmail.com</a>&gt;</li>
</ul>
</blockquote>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/social/tree/14.0/mail_autosubscribe">OCA/social</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1 @@
from . import test_mail_autosubscribe

View File

@ -0,0 +1 @@
from . import fake_order

View File

@ -0,0 +1,13 @@
# Copyright 2021 Camptocamp (http://www.camptocamp.com).
# @author Iván Todorovich <ivan.todorovich@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class FakeOrder(models.Model):
_name = "fake.order"
_inherit = "mail.thread"
_description = "Fake sale.order like model"
partner_id = fields.Many2one("res.partner", required=True)

View File

@ -0,0 +1,132 @@
# Copyright 2021 Camptocamp (http://www.camptocamp.com).
# @author Iván Todorovich <ivan.todorovich@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo_test_helper import FakeModelLoader
from odoo.tests.common import Form, TransactionCase, tagged
@tagged("post_install", "-at_install")
class TestMailAutosubscribe(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Setup env
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
# Load fake order model
cls.loader = FakeModelLoader(cls.env, cls.__module__)
cls.loader.backup_registry()
from .models.fake_order import FakeOrder
cls.loader.update_registry((FakeOrder,))
cls.fake_order_model = cls.env["ir.model"].search(
[("model", "=", "fake.order")]
)
# Email Template
cls.mail_template = cls.env["mail.template"].create(
{
"model_id": cls.fake_order_model.id,
"name": "Fake Order: Send by Mail",
"subject": "Fake Order: ${object.partner_id.name}",
"partner_to": "${object.partner_id.id}",
"body_html": "Hello, this is a fake order",
}
)
# Partners
cls.commercial_partner = cls.env.ref("base.res_partner_4")
cls.partner_1 = cls.env.ref("base.res_partner_address_13")
cls.partner_2 = cls.env.ref("base.res_partner_address_14")
cls.partner_3 = cls.env.ref("base.res_partner_address_24")
# Autosubscribe rules
cls.autosubscribe_fake_order = cls.env["mail.autosubscribe"].create(
{"model_id": cls.fake_order_model.id}
)
cls.partner_3.mail_autosubscribe_ids = [(4, cls.autosubscribe_fake_order.id)]
# Empty fake.order
cls.order = cls.env["fake.order"].create({"partner_id": cls.partner_2.id})
@classmethod
def tearDownClass(cls):
cls.loader.restore_registry()
return super().tearDownClass()
def test_message_subscribe(self):
"""Test autosubscribe on a basic workflow"""
self.assertFalse(self.order.message_partner_ids, "No subscribers yet")
self.order.message_subscribe([self.order.partner_id.id])
self.assertEqual(
self.order.message_partner_ids,
self.partner_2 | self.partner_3,
"Partner 3 is automatically subscribed",
)
def test_message_subscribe_disabled(self):
"""Test autosubscribe on a basic workflow (disabled)"""
self.partner_3.mail_autosubscribe_ids = [(5, False)]
self.assertFalse(self.order.message_partner_ids, "No subscribers yet")
self.order.message_subscribe([self.order.partner_id.id])
self.assertEqual(
self.order.message_partner_ids,
self.partner_2,
"Partner 2 is the only subscriber",
)
def test_mail_template(self):
"""Test autosubscribe when partner is set in the mail.template partners_to"""
self.mail_template.send_mail(self.order.id)
message = self.order.message_ids[0]
self.assertEqual(message.partner_ids, self.partner_2 | self.partner_3)
def test_mail_template_disabled(self):
"""Test autosubscribe when the partner is not an autosubscribe follower"""
self.partner_3.mail_autosubscribe_ids = [(5, False)]
self.mail_template.send_mail(self.order.id)
message = self.order.message_ids[0]
self.assertEqual(message.partner_ids, self.partner_2)
def test_mail_template_no_autosubscribe_followers(self):
"""Test autosubscribe doesn't apply if it's disabled on the template"""
self.mail_template.use_autosubscribe_followers = False
self.mail_template.send_mail(self.order.id)
message = self.order.message_ids[0]
self.assertEqual(message.partner_ids, self.partner_2)
def test_mail_template_default_recipients(self):
"""Test autosubscribe when using default recipients"""
self.mail_template.use_default_to = True
self.mail_template.send_mail(self.order.id)
message = self.order.message_ids[0]
self.assertEqual(message.partner_ids, self.partner_2 | self.partner_3)
def test_mail_message_composer(self):
"""Test autosubscribe when using the mail composer"""
self.assertFalse(self.order.message_partner_ids, "No subscribers yet")
composer = Form(
self.env["mail.compose.message"].with_context(
default_model="fake.order",
default_res_id=self.order.id,
default_use_template=True,
default_template_id=self.mail_template.id,
default_composition_mode="comment",
)
)
composer.save().send_mail()
message = self.order.message_ids[0]
self.assertEqual(message.partner_ids, self.partner_2 | self.partner_3)
def test_mail_message_composer_no_autosubscribe_followers(self):
"""Test autosubscribe when using the mail composer and it's disabled"""
self.mail_template.use_autosubscribe_followers = False
composer = Form(
self.env["mail.compose.message"].with_context(
default_model="fake.order",
default_res_id=self.order.id,
default_use_template=True,
default_template_id=self.mail_template.id,
default_composition_mode="comment",
)
)
composer.save().send_mail()
message = self.order.message_ids[0]
self.assertEqual(message.partner_ids, self.partner_2)

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2021 Camptocamp (http://www.camptocamp.com).
@author Iván Todorovich <ivan.todorovich@gmail.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_mail_autosubscribe_form" model="ir.ui.view">
<field name="model">mail.autosubscribe</field>
<field name="arch" type="xml">
<form>
<sheet>
<div class="oe_title">
<h1>
<field name="name" placeholder="Name" />
</h1>
</div>
<group>
<group>
<field name="model_id" options="{'no_create': True}" />
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_mail_autosubscribe_tree" model="ir.ui.view">
<field name="model">mail.autosubscribe</field>
<field name="arch" type="xml">
<tree>
<field name="name" />
<field name="model_id" />
</tree>
</field>
</record>
<record id="action_mail_autosubscribe" model="ir.actions.act_window">
<field name="name">Mail Auto Subscribe</field>
<field name="res_model">mail.autosubscribe</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="menu_mail_autosubscribe"
name="Autosubscribe Models"
action="action_mail_autosubscribe"
parent="base.menu_automation"
sequence="50"
/>
</odoo>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2021 Camptocamp (http://www.camptocamp.com).
@author Iván Todorovich <ivan.todorovich@gmail.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="email_template_form" model="ir.ui.view">
<field name="model">mail.template</field>
<field name="inherit_id" ref="mail.email_template_form" />
<field name="arch" type="xml">
<field name="use_default_to" position="after">
<field name="use_autosubscribe_followers" />
</field>
</field>
</record>
</odoo>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2021 Camptocamp (http://www.camptocamp.com).
@author Iván Todorovich <ivan.todorovich@gmail.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_partner_form" model="ir.ui.view">
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='email']/parent::div" position="after">
<field
name="mail_autosubscribe_ids"
string="In copy of"
widget="many2many_checkboxes"
attrs="{'invisible': [('email', '=', False)]}"
/>
</xpath>
<xpath
expr="//field[@name='child_ids']//form//field[@name='email']"
position="after"
>
<field
name="mail_autosubscribe_ids"
string="In copy of"
widget="many2many_checkboxes"
attrs="{'invisible': [('email', '=', False)]}"
/>
</xpath>
</field>
</record>
</odoo>

View File

@ -0,0 +1 @@
../../../../mail_autosubscribe

View File

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)