85 lines
3.2 KiB
Python
85 lines
3.2 KiB
Python
"""Safety guard: blocks Odoo Enterprise accounting uninstall until migration runs.
|
|
|
|
For each Enterprise accounting module the user attempts to uninstall, the
|
|
guard checks an ir.config_parameter flag named:
|
|
|
|
fusion_accounting.migration.<module_name>.completed
|
|
|
|
If the flag is False/unset and the module is currently installed, the guard
|
|
raises UserError pointing the user to the top-level
|
|
Fusion Accounting -> Migrate from Enterprise menu.
|
|
|
|
The migration wizard sets the flag to True after a successful migration run
|
|
for that module.
|
|
"""
|
|
|
|
from odoo import _, api, models
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
GUARDED_MODULES = (
|
|
'account_accountant',
|
|
'account_reports',
|
|
'accountant',
|
|
'account_followup',
|
|
'account_asset',
|
|
'account_budget',
|
|
'account_loans',
|
|
)
|
|
|
|
|
|
class IrModuleModule(models.Model):
|
|
_inherit = "ir.module.module"
|
|
|
|
@api.model
|
|
def _fusion_check_uninstall_guard(self, module_names):
|
|
"""Verify it's safe to uninstall the given modules.
|
|
|
|
Returns True if all checks pass; raises UserError otherwise.
|
|
"""
|
|
Param = self.env['ir.config_parameter'].sudo()
|
|
for name in module_names:
|
|
if name not in GUARDED_MODULES:
|
|
continue
|
|
installed = self.sudo().search_count([
|
|
('name', '=', name), ('state', '=', 'installed'),
|
|
])
|
|
if not installed:
|
|
continue
|
|
flag_key = f'fusion_accounting.migration.{name}.completed'
|
|
if Param.get_param(flag_key, default='False').lower() != 'true':
|
|
raise UserError(_(
|
|
"Cannot uninstall %s: the Fusion Accounting migration "
|
|
"for this module has not run yet. Please open\n"
|
|
" Fusion Accounting -> Migrate from Enterprise\n"
|
|
"and run the migration before uninstalling. Once the "
|
|
"migration has completed, the safety guard will allow "
|
|
"uninstall.\n\n"
|
|
"If you genuinely want to uninstall WITHOUT migrating "
|
|
"(data will be lost), set the parameter %s to True manually.",
|
|
name, flag_key,
|
|
))
|
|
return True
|
|
|
|
def button_immediate_uninstall(self):
|
|
"""Override to invoke the safety guard before allowing uninstall.
|
|
|
|
Both this and ``module_uninstall`` below can fire in a single UI
|
|
uninstall call (button_immediate_uninstall -> module_uninstall). The
|
|
guard is a pure read + raise, so re-running it is idempotent: on the
|
|
happy path it just re-confirms; on the blocked path the first call
|
|
already raised and the second is never reached.
|
|
"""
|
|
self._fusion_check_uninstall_guard(self.mapped('name'))
|
|
return super().button_immediate_uninstall()
|
|
|
|
def module_uninstall(self):
|
|
"""Override the lower-level uninstall path too (CLI / API uninstall).
|
|
|
|
See ``button_immediate_uninstall`` above -- both overrides may run in
|
|
the same UI uninstall; the guard is idempotent so double-invocation
|
|
is safe.
|
|
"""
|
|
self._fusion_check_uninstall_guard(self.mapped('name'))
|
|
return super().module_uninstall()
|