Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mail_announcement/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
41 changes: 41 additions & 0 deletions mail_announcement/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
##############################################################################
#
# Copyright (C) 2024 ADHOC SA (http://www.adhoc.com.ar)
# All Rights Reserved.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
"name": "Mail Announcement",
"version": "19.0.1.0.0",
"category": "Discuss",
"sequence": 14,
"summary": "Important Communications with Mandatory Read Receipt",
"author": "ADHOC SA",
"website": "www.adhoc.com.ar",
"license": "AGPL-3",
"depends": [
"mail",
],
"data": [
"security/mail_announcement_security.xml",
"security/ir.model.access.csv",
"views/mail_announcement_views.xml",
],
"demo": [],
"installable": True,
"auto_install": False,
"application": True,
}
137 changes: 137 additions & 0 deletions mail_announcement/i18n/es.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_announcement
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 19.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-01-01 00:00+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: es\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"

#. module: mail_announcement
#: model:ir.model,name:mail_announcement.model_mail_announcement
msgid "Important Announcement"
msgstr "Comunicado Importante"

#. module: mail_announcement
#: model:ir.model,name:mail_announcement.model_mail_announcement_receipt
msgid "Announcement Read Receipt"
msgstr "Acuse de Recibo"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__name
msgid "Subject"
msgstr "Asunto"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__body
msgid "Content"
msgstr "Contenido"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__author_id
msgid "Author"
msgstr "Autor"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__channel_id
msgid "Channel/Origin"
msgstr "Canal/Origen"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__date
msgid "Date"
msgstr "Fecha"

#. module: mail_announcement
#: model:ir.model.fields.selection,name:mail_announcement.selection__mail_announcement__state__draft
msgid "Draft"
msgstr "Borrador"

#. module: mail_announcement
#: model:ir.model.fields.selection,name:mail_announcement.selection__mail_announcement__state__sent
msgid "Sent"
msgstr "Enviado"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__recipient_ids
msgid "Recipients"
msgstr "Destinatarios"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__receipt_count
msgid "Total Recipients"
msgstr "Total Destinatarios"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__pending_receipt_count
msgid "Pending"
msgstr "Pendientes"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__is_pending_for_me
msgid "Pending for Me"
msgstr "Pendiente para Mí"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement__status
msgid "Status"
msgstr "Estado"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement_receipt__announcement_id
msgid "Announcement"
msgstr "Comunicado"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement_receipt__user_id
msgid "User"
msgstr "Usuario"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement_receipt__is_read
msgid "Read"
msgstr "Leído"

#. module: mail_announcement
#: model:ir.model.fields,field_description:mail_announcement.field_mail_announcement_receipt__read_date
msgid "Read Date"
msgstr "Fecha de Lectura"

#. module: mail_announcement
#: model_terms:ir.ui.view,arch_db:mail_announcement.view_mail_announcement_form
msgid "Enviar Comunicado"
msgstr "Enviar Comunicado"

#. module: mail_announcement
#: model_terms:ir.ui.view,arch_db:mail_announcement.view_mail_announcement_form
msgid "✔ Acusar Recibo"
msgstr "✔ Acusar Recibo"

#. module: mail_announcement
#: model:ir.actions.act_window,name:mail_announcement.action_mail_announcement_pending
msgid "Comunicados Pendientes"
msgstr "Comunicados Pendientes"

#. module: mail_announcement
#: model:ir.actions.act_window,name:mail_announcement.action_mail_announcement_all
msgid "Todos los Comunicados"
msgstr "Todos los Comunicados"

#. module: mail_announcement
#: model:ir.ui.menu,name:mail_announcement.menu_mail_announcement_root
msgid "Comunicados"
msgstr "Comunicados"

#. module: mail_announcement
#: constraint:mail_announcement_receipt:0
msgid "Each user can only have one read receipt per announcement."
msgstr "Cada usuario solo puede tener un acuse de recibo por comunicado."
2 changes: 2 additions & 0 deletions mail_announcement/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import mail_announcement
from . import mail_announcement_receipt
144 changes: 144 additions & 0 deletions mail_announcement/models/mail_announcement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from odoo import api, fields, models


class MailAnnouncement(models.Model):
_name = "mail.announcement"
_description = "Important Announcement"
_order = "date desc"

name = fields.Char(
string="Subject",
required=True,
)
body = fields.Html(
string="Content",
required=True,
sanitize=True,
)
author_id = fields.Many2one(
comodel_name="res.users",
string="Author",
default=lambda self: self.env.user,
required=True,
ondelete="restrict",
)
channel_id = fields.Many2one(
comodel_name="discuss.channel",
string="Channel/Origin",
ondelete="set null",
)
date = fields.Datetime(
string="Date",
default=fields.Datetime.now,
required=True,
)
state = fields.Selection(
selection=[("draft", "Draft"), ("sent", "Sent")],
string="Status",
default="draft",
required=True,
readonly=True,
copy=False,
)
recipient_ids = fields.Many2many(
comodel_name="res.users",
relation="mail_announcement_res_users_rel",
column1="announcement_id",
column2="user_id",
string="Recipients",
)
receipt_ids = fields.One2many(
comodel_name="mail.announcement.receipt",
inverse_name="announcement_id",
string="Read Receipts",
)
receipt_count = fields.Integer(
compute="_compute_receipt_stats",
string="Total Recipients",
)
pending_receipt_count = fields.Integer(
compute="_compute_receipt_stats",
string="Pending",
)
is_pending_for_me = fields.Boolean(
compute="_compute_is_pending_for_me",
search="_search_is_pending_for_me",
string="Pending for Me",
)

@api.depends("receipt_ids.is_read")
def _compute_receipt_stats(self):
for rec in self:
rec.receipt_count = len(rec.receipt_ids)
rec.pending_receipt_count = len(rec.receipt_ids.filtered(lambda r: not r.is_read))

@api.depends("receipt_ids.is_read", "receipt_ids.user_id")
def _compute_is_pending_for_me(self):
user = self.env.user
for rec in self:
my_receipt = rec.receipt_ids.filtered(lambda r: r.user_id == user)
rec.is_pending_for_me = bool(my_receipt) and not my_receipt[:1].is_read

def _search_is_pending_for_me(self, operator, value):
user = self.env.user
pending_ids = (
self.env["mail.announcement.receipt"]
.search([("user_id", "=", user.id), ("is_read", "=", False)])
.announcement_id.ids
)
if (operator == "=" and value) or (operator == "!=" and not value):
return [("id", "in", pending_ids)]
return [("id", "not in", pending_ids)]

@api.onchange("channel_id")
def _onchange_channel_id(self):
if self.channel_id:
partner_ids = self.channel_id.channel_member_ids.partner_id.ids
channel_users = self.env["res.users"].search([("partner_id", "in", partner_ids), ("share", "=", False)])
self.recipient_ids = channel_users
else:
self.recipient_ids = False

def _get_recipients(self):
"""Return the full set of users that must receive this announcement."""
self.ensure_one()
recipients = self.recipient_ids
if self.channel_id:
partner_ids = self.channel_id.channel_member_ids.partner_id.ids
channel_users = self.env["res.users"].search([("partner_id", "in", partner_ids), ("share", "=", False)])
recipients = recipients | channel_users
return recipients

def action_send(self):
self.ensure_one()
if self.state == "sent":
return
recipients = self._get_recipients()
existing_user_ids = self.receipt_ids.user_id.ids
vals_list = [
{
"announcement_id": self.id,
"user_id": user.id,
"is_read": False,
}
for user in recipients
if user.id not in existing_user_ids
]
if vals_list:
self.env["mail.announcement.receipt"].sudo().create(vals_list)
self.write({"state": "sent"})

def action_mark_as_read(self):
for rec in self:
receipt = rec.receipt_ids.filtered(lambda r: r.user_id == self.env.user)
if receipt:
receipt.write({"is_read": True, "read_date": fields.Datetime.now()})
else:
self.env["mail.announcement.receipt"].create(
{
"announcement_id": rec.id,
"user_id": self.env.user.id,
"is_read": True,
"read_date": fields.Datetime.now(),
}
)
35 changes: 35 additions & 0 deletions mail_announcement/models/mail_announcement_receipt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from odoo import fields, models


class MailAnnouncementReceipt(models.Model):
_name = "mail.announcement.receipt"
_description = "Announcement Read Receipt"
_order = "read_date desc, id desc"

announcement_id = fields.Many2one(
comodel_name="mail.announcement",
string="Announcement",
required=True,
ondelete="cascade",
index=True,
)
user_id = fields.Many2one(
comodel_name="res.users",
string="User",
required=True,
ondelete="cascade",
index=True,
)
is_read = fields.Boolean(
string="Read",
default=False,
)
read_date = fields.Datetime(
string="Read Date",
readonly=True,
)

_unique_user_announcement = models.Constraint(
"UNIQUE(announcement_id, user_id)",
"Each user can only have one read receipt per announcement.",
)
5 changes: 5 additions & 0 deletions mail_announcement/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_mail_announcement_user,mail.announcement.user,model_mail_announcement,base.group_user,1,1,1,0
access_mail_announcement_system,mail.announcement.system,model_mail_announcement,base.group_system,1,1,1,1
access_mail_announcement_receipt_user,mail.announcement.receipt.user,model_mail_announcement_receipt,base.group_user,1,1,1,0
access_mail_announcement_receipt_system,mail.announcement.receipt.system,model_mail_announcement_receipt,base.group_system,1,1,1,1
14 changes: 14 additions & 0 deletions mail_announcement/security/mail_announcement_security.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Record Rule: internal users can only write/delete their own receipts -->
<record id="rule_mail_announcement_receipt_own" model="ir.rule">
<field name="name">Announcement Receipt: own records only (write/delete)</field>
<field name="model_id" ref="model_mail_announcement_receipt"/>
<field name="domain_force">[('user_id', '=', user.id)]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
<field name="perm_read" eval="0"/>
<field name="perm_write" eval="1"/>
<field name="perm_create" eval="1"/>
<field name="perm_unlink" eval="1"/>
</record>
</odoo>
Loading
Loading