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,342 changes: 1,342 additions & 0 deletions docsource/modules190-200.rst

Large diffs are not rendered by default.

562 changes: 562 additions & 0 deletions openupgrade_scripts/scripts/calendar/20.0.1.1/noupdate_changes.xml

Large diffs are not rendered by default.

134 changes: 134 additions & 0 deletions openupgrade_scripts/scripts/calendar/20.0.1.1/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Copyright 2026 Odoo Community Association (OCA)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from openupgradelib import openupgrade

_PRIVACY_VALUES = ("public", "private", "confidential")


def _create_missing_primary_calendars(env):
"""The post_init hook that creates primary calendars runs on install only.

Schema init may already have created one for users who organise events
(calendar.event.calendar_id's compute calls _find_or_create_primary_calendar).
Everyone else who is not a portal/public user still needs one: v20 creates
it for every new internal user and refuses to delete it.
"""
users = (
env["res.users"]
.with_context(active_test=False)
.search(
[
("share", "=", False),
("calendar_user_ids", "not any", [("is_primary", "=", True)]),
]
)
)
if users:
users._generate_primary_calendar()
openupgrade.logged_query(
env.cr,
"""
UPDATE res_users AS users
SET primary_calendar_id = membership.calendar_id
FROM calendar_user AS membership
WHERE membership.user_id = users.id
AND membership.is_primary
AND membership.access_role = 'owner'
AND users.primary_calendar_id IS NULL
""",
)


def _restore_default_privacy(cr):
"""calendar_default_privacy moved from res.users.settings to the calendar.

_generate_primary_calendar copies the system parameter (or 'public'),
not the per-user value. The old column is still present: v20 no longer
drops removed columns.
"""
if not openupgrade.column_exists(
cr, "res_users_settings", "calendar_default_privacy"
):
return
openupgrade.logged_query(
cr,
"""
UPDATE calendar_calendar AS calendar
SET calendar_default_privacy = settings.calendar_default_privacy
FROM calendar_user AS membership
JOIN res_users_settings AS settings
ON settings.user_id = membership.user_id
WHERE membership.calendar_id = calendar.id
AND membership.is_primary
AND membership.access_role = 'owner'
AND settings.calendar_default_privacy IN %s
AND calendar.calendar_default_privacy
IS DISTINCT FROM settings.calendar_default_privacy
""",
(_PRIVACY_VALUES,),
)


def _assign_event_calendars(cr):
"""Events belong to their organiser's primary calendar.

The stored compute does this when it runs. Fill whatever it left empty
(no organiser, or a calendar created only in this post script).
"""
openupgrade.logged_query(
cr,
"""
UPDATE calendar_event AS event
SET calendar_id = users.primary_calendar_id
FROM res_users AS users
WHERE event.user_id = users.id
AND event.calendar_id IS NULL
AND users.primary_calendar_id IS NOT NULL
""",
)


def _restore_own_filter_checked(cr):
"""The user's own events are filtered by calendar.user.is_filter_checked.

v19 stored that checkbox on calendar.filters.partner_checked of the
user's own partner. Other partners were folded into ``active`` in pre.
"""
if not openupgrade.column_exists(cr, "calendar_filters", "partner_checked"):
return
openupgrade.logged_query(
cr,
"""
UPDATE calendar_user AS membership
SET is_filter_checked = FALSE
FROM res_users AS users
JOIN calendar_filters AS filters
ON filters.user_id = users.id
AND filters.partner_id = users.partner_id
WHERE membership.user_id = users.id
AND membership.is_primary
AND filters.partner_checked IS FALSE
""",
)


@openupgrade.migrate()
def migrate(env, version):
_create_missing_primary_calendars(env)
_restore_default_privacy(env.cr)
_assign_event_calendars(env.cr)
_restore_own_filter_checked(env.cr)
openupgrade.load_data(env, "calendar", "20.0.1.1/noupdate_changes.xml")
openupgrade.delete_record_translations(
env.cr,
"calendar",
[
"calendar_template_delete_event",
"calendar_template_meeting_changedate",
"calendar_template_meeting_invitation",
"calendar_template_meeting_reminder",
"calendar_template_meeting_update",
"subtype_invitation",
],
)
67 changes: 67 additions & 0 deletions openupgrade_scripts/scripts/calendar/20.0.1.1/pre-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright 2026 Odoo Community Association (OCA)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from openupgradelib import openupgrade


def _merge_partner_filters(cr):
"""v20 keeps a single ``active`` flag on calendar.filters.

v19 used ``active`` for "listed" and ``partner_checked`` for "shown".
The shown state is what hides or displays that partner's events, so an
unchecked filter becomes inactive. The user's own events are filtered
through calendar.user in post-migration.
"""
if not openupgrade.column_exists(cr, "calendar_filters", "partner_checked"):
return
openupgrade.logged_query(
cr,
"""
UPDATE calendar_filters
SET active = FALSE
WHERE partner_checked IS FALSE
AND active IS DISTINCT FROM FALSE
""",
)


def _deduplicate_access_tokens(cr):
"""v20 adds UNIQUE(access_token). Several NULL tokens are allowed;
duplicate non-null tokens are not. Keep the oldest row's token so
existing links to that event keep working.
"""
openupgrade.logged_query(
cr,
"""
UPDATE calendar_event
SET access_token = NULL
WHERE access_token = ''
""",
)
openupgrade.logged_query(
cr,
"""
UPDATE calendar_event AS event
SET access_token = gen_random_uuid()::varchar
WHERE event.id IN (
SELECT id
FROM (
SELECT
id,
ROW_NUMBER() OVER (
PARTITION BY access_token
ORDER BY id
) AS occurrence
FROM calendar_event
WHERE access_token IS NOT NULL
) AS ranked
WHERE occurrence > 1
)
""",
)


@openupgrade.migrate()
def migrate(env, version):
_merge_partner_filters(env.cr)
_deduplicate_access_tokens(env.cr)
96 changes: 96 additions & 0 deletions openupgrade_scripts/scripts/calendar/20.0.1.1/upgrade_analysis.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---Models in module 'calendar'---
obsolete model calendar.popover.delete.wizard [transient]
obsolete model calendar.provider.config [transient]
new model calendar.calendar
new model calendar.event.archive.or.unlink.wizard [transient]
new model calendar.event.multi.archive.or.unlink.wizard [transient]
new model calendar.user
---Fields in module 'calendar'---
calendar / calendar.calendar / calendar_default_privacy (selection): NEW required, selection_keys: ['confidential', 'members_only', 'private', 'public'], hasdefault: default
calendar / calendar.calendar / calendar_user_ids (one2many) : NEW relation: calendar.user, hasdefault: default
calendar / calendar.calendar / event_ids (one2many) : NEW relation: calendar.event
calendar / calendar.calendar / name (char) : NEW
calendar / calendar.calendar / recurrence_ids (one2many) : NEW relation: calendar.recurrence
calendar / calendar.event / calendar_id (many2one) : NEW relation: calendar.calendar, hasdefault: compute
calendar / calendar.event / effective_privacy (selection) : selection_keys added: [members_only] (most likely nothing to do)
calendar / calendar.event / is_draft (boolean) : NEW
calendar / calendar.event / meeting_activity_ids (one2many): NEW relation: mail.activity
calendar / calendar.event / privacy (selection) : selection_keys added: [members_only] (most likely nothing to do)
calendar / calendar.filters / partner_checked (boolean) : DEL
calendar / calendar.user / access_role (selection) : NEW required, selection_keys: ['owner', 'writer']
calendar / calendar.user / calendar_id (many2one) : NEW relation: calendar.calendar, required
calendar / calendar.user / filter_color (integer) : NEW hasdefault: default
calendar / calendar.user / is_filter_active (boolean) : NEW hasdefault: default
calendar / calendar.user / is_filter_checked (boolean) : NEW hasdefault: default
calendar / calendar.user / is_primary (boolean) : NEW
calendar / calendar.user / name (char) : NEW
calendar / calendar.user / user_id (many2one) : NEW relation: res.users, required
calendar / res.users / activity_calendar_event_id (many2one): not related anymore
calendar / res.users / activity_calendar_event_id (many2one): now a function
calendar / res.users / calendar_ids (one2many) : NEW relation: calendar.calendar, hasdefault: compute, stored: False
calendar / res.users / calendar_user_ids (one2many) : NEW relation: calendar.user
calendar / res.users / primary_calendar_id (many2one): NEW relation: calendar.calendar, isfunction: function, stored
calendar / res.users.settings / calendar_default_privacy (selection): DEL required, selection_keys: ['confidential', 'private', 'public']
calendar / res.users.settings / calendar_show_activities (boolean): NEW hasdefault: default
---XML records in module 'calendar'---
NEW calendar.alarm: calendar.alarm_mail_1_day (noupdate)
NEW ir.access: calendar.access_calendar_alarm
NEW ir.access: calendar.access_calendar_alarm_manager
NEW ir.access: calendar.access_calendar_attendee_employee
NEW ir.access: calendar.access_calendar_attendee_employee_archive_or_unlink_wizard
NEW ir.access: calendar.access_calendar_attendee_employee_multi_archive_or_unlink_wizard
NEW ir.access: calendar.access_calendar_event_type_all
NEW ir.access: calendar.access_calendar_event_type_manager
NEW ir.access: calendar.access_calendar_filters_all
NEW ir.access: calendar.access_calendar_recurrence
NEW ir.access: calendar.calendar_calendar_rule_system
NEW ir.access: calendar.calendar_calendar_rule_users_create_and_read
NEW ir.access: calendar.calendar_calendar_rule_users_update
NEW ir.access: calendar.calendar_event_rule_employee
NEW ir.access: calendar.calendar_event_rule_my
NEW ir.access: calendar.calendar_event_rule_private
NEW ir.access: calendar.calendar_user_rule_create
NEW ir.access: calendar.calendar_user_rule_own_or_owner
NEW ir.access: calendar.calendar_user_rule_read
NEW ir.actions.act_window: calendar.action_calendar_calendar
DEL ir.actions.act_window: calendar.action_event_delete_wizard
DEL ir.model.access: calendar.access_calendar_alarm
DEL ir.model.access: calendar.access_calendar_alarm_manager
DEL ir.model.access: calendar.access_calendar_attendee_employee
DEL ir.model.access: calendar.access_calendar_attendee_employee_delete_wizard
DEL ir.model.access: calendar.access_calendar_attendee_portal
DEL ir.model.access: calendar.access_calendar_event_all_employee
DEL ir.model.access: calendar.access_calendar_event_all_user
DEL ir.model.access: calendar.access_calendar_event_partner_manager
DEL ir.model.access: calendar.access_calendar_event_type_all
DEL ir.model.access: calendar.access_calendar_event_type_manager
DEL ir.model.access: calendar.access_calendar_filters
DEL ir.model.access: calendar.access_calendar_filters_all
DEL ir.model.access: calendar.access_calendar_provider_config_all
DEL ir.model.access: calendar.access_calendar_provider_config_manager
DEL ir.model.access: calendar.access_calendar_recurrence
NEW ir.model.constraint: calendar.constraint_calendar_event_access_token_unique
NEW ir.model.constraint: calendar.constraint_calendar_event_check_no_recurrent_draft
NEW ir.model.constraint: calendar.constraint_calendar_user_single_primary_calendar_per_user
NEW ir.model.constraint: calendar.constraint_calendar_user_unique_user_per_calendar
DEL ir.rule: calendar.calendar_attendee_rule_my (noupdate)
DEL ir.rule: calendar.calendar_event_rule_employee (noupdate)
DEL ir.rule: calendar.calendar_event_rule_my (noupdate)
DEL ir.rule: calendar.calendar_event_rule_private (noupdate)
NEW ir.ui.menu: calendar.calendar_submenu_event_type
NEW ir.ui.menu: calendar.menu_calendar_calendars
NEW ir.ui.view: calendar.calendar_alarm_view_kanban
NEW ir.ui.view: calendar.calendar_alarm_view_search
NEW ir.ui.view: calendar.calendar_calendar_view_form
NEW ir.ui.view: calendar.calendar_calendar_view_list
NEW ir.ui.view: calendar.calendar_event_archive_or_unlink_wizard_view_form
NEW ir.ui.view: calendar.calendar_event_multi_archive_or_unlink_wizard_view_form
NEW ir.ui.view: calendar.calendar_user_view_form
NEW ir.ui.view: calendar.message_meeting_activity_done
NEW ir.ui.view: calendar.res_partner_view_form_simplified
NEW ir.ui.view: calendar.res_users_form_view_calendars
DEL ir.ui.view: calendar.calendar_popover_delete_view
DEL ir.ui.view: calendar.calendar_provider_config_view_form
DEL ir.ui.view: calendar.res_users_form_view_calendar_default_privacy
DEL ir.ui.view: calendar.view_event_delete_wizard_form
NEW mail.message.subtype: calendar.mt_calendar_event_updated (noupdate)
Loading