| REPOSITORY | |
|---|---|
| REPOSITORY | OCA/server-ux |
| GIT | |
| GIT | https://github.com/OCA/server-ux.git |
| GIT FOLDER | |
| GIT FOLDER | https://github.com/OCA/server-ux/tree/18.0/announcement |
| VERSION | |
| VERSION | 1.0.1 |
| CATEGORY | |
| CATEGORY | Server UX |
| LICENSE | |
| LICENSE | AGPL-3 |
| APPLICATION | |
| APPLICATION | No |
| AUTO-INSTALLABLE | |
| AUTO-INSTALLABLE | No |
| AUTHORS | |
| AUTHORS | Tecnativa, Odoo Community Association (OCA) |
| MAINTAINERS | |
| MAINTAINERS | Tecnativa, Odoo Community Association (OCA) |
| COMMITTERS | |
| COMMITTERS | Víctor Martínez, OCA-git-bot, oca-ci, David Bañón |
| WEBSITE | |
| WEBSITE | https://github.com/OCA/server-ux |
| LAST TRACKING UPDATE | |
| LAST TRACKING UPDATE | 2026-07-06 19:30:16 |
| ODOO DEPENDENCIES | |
| ODOO DEPENDENCIES |
odoo/odoo: - base - base_setup - web - bus - web_tour - html_editor |
| PYTHON DEPENDENCIES | |
| PYTHON DEPENDENCIES | Not have |
| SYSTEM DEPENDENCIES | |
| SYSTEM DEPENDENCIES | Not have |
| DESCRIPTION | |
| DESCRIPTION | This module adds popup announcements in the backend for targeted internal users. Those announcements can contain rich format and a user read log is kept for everyone. |
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
announcement_log_view_tree |
announcement.log | list | New | |
announcement_management_view_form |
announcement | xpath | Inherits announcement_view_form | |
announcement_management_view_tree |
announcement | field | Inherits announcement_view_tree | |
announcement_tag_view_form |
announcement.tag | form | New | |
announcement_tag_view_tree |
announcement.tag | list | New | |
announcement_view_calendar |
announcement | calendar | New | |
announcement_view_form |
announcement | form | New | |
announcement_view_kanban |
announcement | kanban | New | |
announcement_view_search |
announcement | search | New | |
announcement_view_tree |
announcement | list | New | |
read_announcement_wizard_view_tree |
read.announcement.wizard | list | New |
active
Boolean
copy=False
allowed_user_ids
Many2many → res.users
comodel_name='res.users'
compute='_compute_allowed_user_ids'
compute_sudo=True
relation='announcement_res_users_allowed_rel'
store=True
allowed_users_count
Integer
compute='_compute_allowed_user_ids'
compute_sudo=True
store=True
announcement_log_ids
One2many → announcement.log
comodel_name='announcement.log'
inverse_name='announcement_id'
announcement_type
Selection
default='specific_users'
required=True
selection=[('specific_users', 'Specific users'), ('user_group', 'User groups')]
attachment_ids
Many2many → ir.attachment
comodel_name='ir.attachment'
help='You can attach the copy of your Letter'
string='Attachments'
color
Integer
compute='_compute_color'
help='Technical field to display items by color in the calendar'
content
Html
in_date
Boolean
compute='_compute_in_date'
compute_sudo=True
search='_search_in_date'
is_general_announcement
Boolean
name
Char
required=True
string='Title'
notification_date
Datetime
notification_end_date
Datetime
compute='_compute_notification_end_date'
help='Technical field to display announcements in the calendar view'
notification_expiry_date
Datetime
notification_start_date
Datetime
compute='_compute_notification_start_date'
help='Technical field to display announcements in the calendar view'
read_announcement_count
Integer
compute='_compute_read_announcement_count'
store=True
sequence
Integer
specific_user_ids
Many2many → res.users
comodel_name='res.users'
context={'active_test': False}
domain=[('share', '=', False)]
inverse='_inverse_specific_user_ids'
tag_ids
Many2many → announcement.tag
column1='announcement_id'
column2='tag_id'
comodel_name='announcement.tag'
string='Tags'
user_group_ids
Many2many → res.groups
comodel_name='res.groups'
compute='_compute_user_group_ids'
readonly=False
store=True
action_announcement_log(self)
create(self, vals_list)
write(self, vals)
announcement_id
Many2one → announcement
comodel_name='announcement'
No public methods.
color
Integer
company_id
Many2one → res.company
comodel_name='res.company'
help='Company related to this tag'
index=True
string='Company'
name
Char
required=True
translate=True
parent_id
Many2one → announcement.tag
comodel_name='announcement.tag'
index=True
ondelete='cascade'
string='Parent Tag'
No public methods.
No new fields.
Public methods (1)session_info(self)
announcement_id
Many2one → announcement
comodel_name='announcement'
date
Datetime
string='Read Date'
read_state
Selection
selection=[('read', 'Read'), ('unread', 'Unread')]
user_id
Many2one → res.users
comodel_name='res.users'
No public methods.
read_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='read_announcement_user_rel'
unread_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='unread_announcement_user_rel'
announcement_user_count(self)
get_announcements(self)
mark_announcement_as_read(self, announcement_id)
| REPOSITORY | |
|---|---|
| REPOSITORY | OCA/server-ux |
| GIT | |
| GIT | https://github.com/OCA/server-ux.git |
| GIT FOLDER | |
| GIT FOLDER | https://github.com/OCA/server-ux/tree/17.0/announcement |
| VERSION | |
| VERSION | 1.0.1 |
| CATEGORY | |
| CATEGORY | Server UX |
| LICENSE | |
| LICENSE | AGPL-3 |
| APPLICATION | |
| APPLICATION | No |
| AUTO-INSTALLABLE | |
| AUTO-INSTALLABLE | No |
| AUTHORS | |
| AUTHORS | Tecnativa, Odoo Community Association (OCA) |
| MAINTAINERS | |
| MAINTAINERS | Tecnativa, Odoo Community Association (OCA) |
| COMMITTERS | |
| COMMITTERS | Víctor Martínez, Weblate, OCA-git-bot, David, oca-ci |
| WEBSITE | |
| WEBSITE | https://github.com/OCA/server-ux |
| LAST TRACKING UPDATE | |
| LAST TRACKING UPDATE | 2026-07-06 19:20:08 |
| ODOO DEPENDENCIES | |
| ODOO DEPENDENCIES |
odoo/odoo: - base - base_setup - web - bus - web_tour |
| PYTHON DEPENDENCIES | |
| PYTHON DEPENDENCIES | Not have |
| SYSTEM DEPENDENCIES | |
| SYSTEM DEPENDENCIES | Not have |
| DESCRIPTION | |
| DESCRIPTION | This module adds popup announcements in the backend for targeted internal users. Those announcements can contain rich format and a user read log is kept for everyone. |
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
announcement_log_view_tree |
announcement.log | tree | New | |
announcement_management_view_form |
announcement | xpath | Inherits announcement_view_form | |
announcement_management_view_tree |
announcement | field | Inherits announcement_view_tree | |
announcement_tag_view_form |
announcement.tag | form | New | |
announcement_tag_view_tree |
announcement.tag | tree | New | |
announcement_view_calendar |
announcement | calendar | New | |
announcement_view_form |
announcement | form | New | |
announcement_view_kanban |
announcement | kanban | New | |
announcement_view_search |
announcement | search | New | |
announcement_view_tree |
announcement | tree | New | |
read_announcement_wizard_view_tree |
read.announcement.wizard | tree | New |
active
Boolean
copy=False
allowed_user_ids
Many2many → res.users
comodel_name='res.users'
compute='_compute_allowed_user_ids'
compute_sudo=True
relation='announcement_res_users_allowed_rel'
store=True
allowed_users_count
Integer
compute='_compute_allowed_user_ids'
compute_sudo=True
store=True
announcement_log_ids
One2many → announcement.log
comodel_name='announcement.log'
inverse_name='announcement_id'
announcement_type
Selection
default='specific_users'
required=True
selection=[('specific_users', 'Specific users'), ('user_group', 'User groups')]
attachment_ids
Many2many → ir.attachment
comodel_name='ir.attachment'
help='You can attach the copy of your Letter'
string='Attachments'
color
Integer
compute='_compute_color'
help='Technical field to display items by color in the calendar'
content
Html
in_date
Boolean
compute='_compute_in_date'
compute_sudo=True
search='_search_in_date'
is_general_announcement
Boolean
name
Char
required=True
string='Title'
notification_date
Datetime
notification_end_date
Datetime
compute='_compute_notification_end_date'
help='Technical field to display announcements in the calendar view'
notification_expiry_date
Datetime
notification_start_date
Datetime
compute='_compute_notification_start_date'
help='Technical field to display announcements in the calendar view'
read_announcement_count
Integer
compute='_compute_read_announcement_count'
store=True
sequence
Integer
specific_user_ids
Many2many → res.users
comodel_name='res.users'
context={'active_test': False}
domain=[('share', '=', False)]
inverse='_inverse_specific_user_ids'
tag_ids
Many2many → announcement.tag
column1='announcement_id'
column2='tag_id'
comodel_name='announcement.tag'
string='Tags'
user_group_ids
Many2many → res.groups
comodel_name='res.groups'
compute='_compute_user_group_ids'
readonly=False
store=True
action_announcement_log(self)
create(self, vals_list)
write(self, vals)
announcement_id
Many2one → announcement
comodel_name='announcement'
No public methods.
color
Integer
company_id
Many2one → res.company
comodel_name='res.company'
help='Company related to this tag'
index=True
string='Company'
full_name
Char
compute='_compute_full_name'
name
Char
required=True
translate=True
parent_id
Many2one → announcement.tag
comodel_name='announcement.tag'
index=True
ondelete='cascade'
string='Parent Tag'
name_get(self)
No new fields.
Public methods (1)session_info(self)
announcement_id
Many2one → announcement
comodel_name='announcement'
date
Datetime
string='Read Date'
read_state
Selection
selection=[('read', 'Read'), ('unread', 'Unread')]
user_id
Many2one → res.users
comodel_name='res.users'
No public methods.
read_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='read_announcement_user_rel'
unread_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='unread_announcement_user_rel'
announcement_user_count(self)
get_announcements(self)
mark_announcement_as_read(self, announcement_id)
| REPOSITORY | |
|---|---|
| REPOSITORY | OCA/server-ux |
| GIT | |
| GIT | https://github.com/OCA/server-ux.git |
| GIT FOLDER | |
| GIT FOLDER | https://github.com/OCA/server-ux/tree/16.0/announcement |
| VERSION | |
| VERSION | 1.1.0 |
| CATEGORY | |
| CATEGORY | Server UX |
| LICENSE | |
| LICENSE | AGPL-3 |
| APPLICATION | |
| APPLICATION | No |
| AUTO-INSTALLABLE | |
| AUTO-INSTALLABLE | No |
| AUTHORS | |
| AUTHORS | Tecnativa, Odoo Community Association (OCA) |
| MAINTAINERS | |
| MAINTAINERS | Tecnativa, Odoo Community Association (OCA) |
| COMMITTERS | |
| COMMITTERS | Víctor Martínez, Weblate, OCA-git-bot, David, oca-ci, Carlos Roca, Luis Rodriguez |
| WEBSITE | |
| WEBSITE | https://github.com/OCA/server-ux |
| LAST TRACKING UPDATE | |
| LAST TRACKING UPDATE | 2026-07-06 00:53:53 |
| ODOO DEPENDENCIES | |
| ODOO DEPENDENCIES |
odoo/odoo: - base - base_setup - web - bus - web_tour |
| PYTHON DEPENDENCIES | |
| PYTHON DEPENDENCIES | Not have |
| SYSTEM DEPENDENCIES | |
| SYSTEM DEPENDENCIES | Not have |
| DESCRIPTION | |
| DESCRIPTION | |
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
announcement_log_view_tree |
announcement.log | tree | New | |
announcement_management_view_form |
announcement | xpath | Inherits announcement_view_form | |
announcement_management_view_tree |
announcement | field | Inherits announcement_view_tree | |
announcement_tag_view_form |
announcement.tag | form | New | |
announcement_tag_view_tree |
announcement.tag | tree | New | |
announcement_view_calendar |
announcement | calendar | New | |
announcement_view_form |
announcement | form | New | |
announcement_view_kanban |
announcement | kanban | New | |
announcement_view_search |
announcement | search | New | |
announcement_view_tree |
announcement | tree | New | |
read_announcement_wizard_view_tree |
read.announcement.wizard | tree | New |
active
Boolean
copy=False
allowed_user_ids
Many2many → res.users
comodel_name='res.users'
compute='_compute_allowed_user_ids'
compute_sudo=True
relation='announcement_res_users_allowed_rel'
store=True
allowed_users_count
Integer
compute='_compute_allowed_user_ids'
compute_sudo=True
store=True
announcement_log_ids
One2many → announcement.log
comodel_name='announcement.log'
inverse_name='announcement_id'
announcement_type
Selection
default='specific_users'
required=True
selection=[('specific_users', 'Specific users'), ('user_group', 'User groups')]
attachment_ids
Many2many → ir.attachment
comodel_name='ir.attachment'
help='You can attach the copy of your Letter'
string='Attachments'
color
Integer
compute='_compute_color'
help='Technical field to display items by color in the calendar'
content
Html
excluded_groups_ids
Many2many → res.groups
comodel_name='res.groups'
relation='announcement_res_groups_excluded_rel'
excluded_users_ids
Many2many → res.users
comodel_name='res.users'
relation='announcement_res_users_excluded_rel'
in_date
Boolean
compute='_compute_in_date'
compute_sudo=True
search='_search_in_date'
is_general_announcement
Boolean
name
Char
required=True
string='Title'
notification_date
Datetime
notification_end_date
Datetime
compute='_compute_notification_end_date'
help='Technical field to display announcements in the calendar view'
notification_expiry_date
Datetime
notification_start_date
Datetime
compute='_compute_notification_start_date'
help='Technical field to display announcements in the calendar view'
read_announcement_count
Integer
compute='_compute_read_announcement_count'
store=True
sequence
Integer
specific_user_ids
Many2many → res.users
comodel_name='res.users'
context={'active_test': False}
domain=[('share', '=', False)]
inverse='_inverse_specific_user_ids'
tag_ids
Many2many → announcement.tag
column1='announcement_id'
column2='tag_id'
comodel_name='announcement.tag'
string='Tags'
user_group_ids
Many2many → res.groups
comodel_name='res.groups'
compute='_compute_user_group_ids'
readonly=False
store=True
action_announcement_log(self)
create(self, vals_list)
write(self, vals)
announcement_id
Many2one → announcement
comodel_name='announcement'
No public methods.
color
Integer
company_id
Many2one → res.company
comodel_name='res.company'
help='Company related to this tag'
index=True
string='Company'
full_name
Char
compute='_compute_full_name'
name
Char
required=True
translate=True
parent_id
Many2one → announcement.tag
comodel_name='announcement.tag'
index=True
ondelete='cascade'
string='Parent Tag'
name_get(self)
No new fields.
Public methods (1)session_info(self)
announcement_id
Many2one → announcement
comodel_name='announcement'
date
Datetime
string='Read Date'
read_state
Selection
selection=[('read', 'Read'), ('unread', 'Unread')]
user_id
Many2one → res.users
comodel_name='res.users'
No public methods.
read_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='read_announcement_user_rel'
unread_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='unread_announcement_user_rel'
announcement_user_count(self)
get_announcements(self)
mark_announcement_as_read(self, announcement_id)
| REPOSITORY | |
|---|---|
| REPOSITORY | OCA/server-ux |
| GIT | |
| GIT | https://github.com/OCA/server-ux.git |
| GIT FOLDER | |
| GIT FOLDER | https://github.com/OCA/server-ux/tree/15.0/announcement |
| VERSION | |
| VERSION | 2.2.0 |
| CATEGORY | |
| CATEGORY | Server UX |
| LICENSE | |
| LICENSE | AGPL-3 |
| APPLICATION | |
| APPLICATION | No |
| AUTO-INSTALLABLE | |
| AUTO-INSTALLABLE | No |
| AUTHORS | |
| AUTHORS | Tecnativa, Odoo Community Association (OCA) |
| MAINTAINERS | |
| MAINTAINERS | Tecnativa, Odoo Community Association (OCA) |
| COMMITTERS | |
| COMMITTERS | Pedro M. Baeza, Víctor Martínez, Weblate, OCA-git-bot, David, oca-ci, pilarvargas-tecnativa |
| WEBSITE | |
| WEBSITE | https://github.com/OCA/server-ux |
| LAST TRACKING UPDATE | |
| LAST TRACKING UPDATE | 2026-07-06 00:46:39 |
| ODOO DEPENDENCIES | |
| ODOO DEPENDENCIES |
odoo/odoo: - base - base_setup - web - bus - web_tour |
| PYTHON DEPENDENCIES | |
| PYTHON DEPENDENCIES | Not have |
| SYSTEM DEPENDENCIES | |
| SYSTEM DEPENDENCIES | Not have |
| DESCRIPTION | |
| DESCRIPTION | |
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
announcement_log_view_tree |
announcement.log | tree | New | |
announcement_management_view_form |
announcement | xpath | Inherits announcement_view_form | |
announcement_management_view_tree |
announcement | field | Inherits announcement_view_tree | |
announcement_tag_view_form |
announcement.tag | form | New | |
announcement_tag_view_tree |
announcement.tag | tree | New | |
announcement_view_calendar |
announcement | calendar | New | |
announcement_view_form |
announcement | form | New | |
announcement_view_kanban |
announcement | kanban | New | |
announcement_view_search |
announcement | search | New | |
announcement_view_tree |
announcement | tree | New | |
read_announcement_wizard_view_tree |
read.announcement.wizard | tree | New |
active
Boolean
copy=False
allowed_user_ids
Many2many → res.users
comodel_name='res.users'
compute='_compute_allowed_user_ids'
compute_sudo=True
relation='announcement_res_users_allowed_rel'
store=True
allowed_users_count
Integer
compute='_compute_allowed_user_ids'
compute_sudo=True
store=True
announcement_log_ids
One2many → announcement.log
comodel_name='announcement.log'
inverse_name='announcement_id'
announcement_type
Selection
default='specific_users'
required=True
selection=[('specific_users', 'Specific users'), ('user_group', 'User groups')]
attachment_ids
Many2many → ir.attachment
comodel_name='ir.attachment'
help='You can attach the copy of your Letter'
string='Attachments'
color
Integer
compute='_compute_color'
help='Technical field to display items by color in the calendar'
content
Html
in_date
Boolean
compute='_compute_in_date'
compute_sudo=True
search='_search_in_date'
is_general_announcement
Boolean
name
Char
required=True
string='Title'
notification_date
Datetime
notification_end_date
Datetime
compute='_compute_notification_end_date'
help='Technical field to display announcements in the calendar view'
notification_expiry_date
Datetime
notification_start_date
Datetime
compute='_compute_notification_start_date'
help='Technical field to display announcements in the calendar view'
read_announcement_count
Integer
compute='_compute_read_announcement_count'
store=True
sequence
Integer
specific_user_ids
Many2many → res.users
comodel_name='res.users'
domain=[('share', '=', False)]
inverse='_inverse_specific_user_ids'
tag_ids
Many2many → announcement.tag
column1='announcement_id'
column2='tag_id'
comodel_name='announcement.tag'
string='Tags'
user_group_ids
Many2many → res.groups
comodel_name='res.groups'
compute='_compute_user_group_ids'
readonly=False
store=True
action_announcement_log(self)
create(self, vals_list)
write(self, vals)
announcement_id
Many2one → announcement
comodel_name='announcement'
No public methods.
color
Integer
company_id
Many2one → res.company
comodel_name='res.company'
help='Company related to this tag'
index=True
string='Company'
full_name
Char
compute='_compute_full_name'
name
Char
required=True
translate=True
parent_id
Many2one → announcement.tag
comodel_name='announcement.tag'
index=True
ondelete='cascade'
string='Parent Tag'
name_get(self)
No new fields.
Public methods (1)announcement_full_size(self)
announcement_id
Many2one → announcement
comodel_name='announcement'
date
Datetime
string='Read Date'
read_state
Selection
selection=[('read', 'Read'), ('unread', 'Unread')]
user_id
Many2one → res.users
comodel_name='res.users'
No public methods.
read_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='read_announcement_user_rel'
unread_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='unread_announcement_user_rel'
announcement_user_count(self)
mark_announcement_as_read(self, announcement_id)
| REPOSITORY | |
|---|---|
| REPOSITORY | OCA/server-ux |
| GIT | |
| GIT | https://github.com/OCA/server-ux.git |
| GIT FOLDER | |
| GIT FOLDER | https://github.com/OCA/server-ux/tree/13.0/announcement |
| VERSION | |
| VERSION | 2.1.0 |
| CATEGORY | |
| CATEGORY | Server UX |
| LICENSE | |
| LICENSE | AGPL-3 |
| APPLICATION | |
| APPLICATION | No |
| AUTO-INSTALLABLE | |
| AUTO-INSTALLABLE | No |
| AUTHORS | |
| AUTHORS | Tecnativa, Odoo Community Association (OCA) |
| MAINTAINERS | |
| MAINTAINERS | Tecnativa, Odoo Community Association (OCA) |
| COMMITTERS | |
| COMMITTERS | david, OCA Transbot, Weblate, OCA-git-bot, oca-ci |
| WEBSITE | |
| WEBSITE | https://github.com/OCA/server-ux |
| LAST TRACKING UPDATE | |
| LAST TRACKING UPDATE | 2026-07-06 00:34:17 |
| ODOO DEPENDENCIES | |
| ODOO DEPENDENCIES |
odoo/odoo: - base - base_setup - web - bus - web_tour |
| PYTHON DEPENDENCIES | |
| PYTHON DEPENDENCIES | Not have |
| SYSTEM DEPENDENCIES | |
| SYSTEM DEPENDENCIES | Not have |
| DESCRIPTION | |
| DESCRIPTION | |
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
announcement_log_view_tree |
announcement.log | tree | New | |
announcement_management_view_form |
announcement | xpath | Inherits announcement_view_form | |
announcement_management_view_tree |
announcement | field | Inherits announcement_view_tree | |
announcement_view_form |
announcement | form | New | |
announcement_view_kanban |
announcement | kanban | New | |
announcement_view_search |
announcement | search | New | |
announcement_view_tree |
announcement | tree | New | |
assets_backend |
assets_backend | ir.ui.view | qweb | Inherits web.assets_backend |
read_announcement_wizard_view_tree |
read.announcement.wizard | tree | New |
active
Boolean
copy=False
allowed_user_ids
Many2many → res.users
comodel_name='res.users'
compute='_compute_allowed_user_ids'
compute_sudo=True
relation='announcement_res_users_allowed_rel'
store=True
allowed_users_count
Integer
compute='_compute_allowed_user_ids'
compute_sudo=True
store=True
announcement_log_ids
One2many → announcement.log
comodel_name='announcement.log'
inverse_name='announcement_id'
announcement_type
Selection
default='specific_users'
required=True
selection=[('specific_users', 'Specific users'), ('user_group', 'User groups')]
content
Html
in_date
Boolean
compute='_compute_in_date'
compute_sudo=True
search='_search_in_date'
name
Char
required=True
string='Title'
notification_date
Datetime
notification_expiry_date
Datetime
read_announcement_count
Integer
compute='_compute_read_announcement_count'
store=True
sequence
Integer
specific_user_ids
Many2many → res.users
comodel_name='res.users'
domain=[('share', '=', False)]
inverse='_inverse_specific_user_ids'
user_group_ids
Many2many → res.groups
comodel_name='res.groups'
action_announcement_log(self)
announcement_id
Many2one → announcement
comodel_name='announcement'
No public methods.
No new fields.
Public methods (1)announcement_full_size(self)
announcement_id
Many2one → announcement
comodel_name='announcement'
date
Datetime
string='Read Date'
read_state
Selection
selection=[('read', 'Read'), ('unread', 'Unread')]
user_id
Many2one → res.users
comodel_name='res.users'
No public methods.
read_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='read_announcement_user_rel'
unread_announcement_ids
Many2many → announcement
comodel_name='announcement'
relation='unread_announcement_user_rel'
announcement_user_count(self)
mark_announcement_as_read(self, announcement_id)