# -*- coding: utf-8 -*- """ Disable various Odoo online services and external API calls. """ import logging from odoo import api, models, fields _logger = logging.getLogger(__name__) class IrModuleModule(models.Model): """Disable module update checks from Odoo store.""" _inherit = 'ir.module.module' @api.model def update_list(self): """ Override to prevent fetching from Odoo Apps store. Only scan local addons paths. """ _logger.info("Module update_list: Scanning local addons only (Odoo Apps store disabled)") return super().update_list() def button_immediate_upgrade(self): """Prevent upgrade attempts that might contact Odoo.""" _logger.info("Module upgrade: Processing locally only") return super().button_immediate_upgrade() class IrCron(models.Model): """Disable scheduled actions that contact Odoo servers.""" _inherit = 'ir.cron' def _callback(self, cron_name, server_action_id): """ Override to block certain cron jobs that contact Odoo. Odoo 19 signature: _callback(self, cron_name, server_action_id) """ blocked_crons = [ 'publisher', 'warranty', 'update_notification', 'database_expiration', 'iap_enrich', 'ocr', 'Invoice OCR', 'enrich leads', 'fetchmail', 'online sync', ] cron_lower = (cron_name or '').lower() for blocked in blocked_crons: if blocked.lower() in cron_lower: _logger.info("Cron BLOCKED (external call): %s", cron_name) return False return super()._callback(cron_name, server_action_id) class ResConfigSettings(models.TransientModel): """Override config settings to prevent external service configuration.""" _inherit = 'res.config.settings' def set_values(self): """Ensure certain settings stay disabled.""" res = super().set_values() # Disable any auto-update settings and set permanent expiration params = self.env['ir.config_parameter'].sudo() params.set_param('database.expiration_date', '2099-12-31 23:59:59') params.set_param('database.expiration_reason', 'renewal') params.set_param('database.enterprise_code', 'PERMANENT_LOCAL') # Disable IAP endpoint (redirect to nowhere) params.set_param('iap.endpoint', 'http://localhost:65535') # Disable various external services params.set_param('partner_autocomplete.endpoint', 'http://localhost:65535') params.set_param('iap_extract_endpoint', 'http://localhost:65535') params.set_param('olg.endpoint', 'http://localhost:65535') params.set_param('mail.media_library_endpoint', 'http://localhost:65535') return res class PublisherWarrantyContract(models.AbstractModel): """Completely disable publisher warranty checks.""" _inherit = 'publisher_warranty.contract' @api.model def _get_sys_logs(self): """ DISABLED: Do not contact Odoo servers. Returns fake successful response. """ _logger.info("Publisher warranty _get_sys_logs BLOCKED") return { 'messages': [], 'enterprise_info': { 'expiration_date': '2099-12-31 23:59:59', 'expiration_reason': 'renewal', 'enterprise_code': 'PERMANENT_LOCAL', } } @api.model def _get_message(self): """DISABLED: Return empty message.""" _logger.info("Publisher warranty _get_message BLOCKED") return {} def update_notification(self, cron_mode=True): """ DISABLED: Do not send any data to Odoo servers. Just update local parameters with permanent values. """ _logger.info("Publisher warranty update_notification BLOCKED") # Set permanent valid subscription parameters params = self.env['ir.config_parameter'].sudo() params.set_param('database.expiration_date', '2099-12-31 23:59:59') params.set_param('database.expiration_reason', 'renewal') params.set_param('database.enterprise_code', 'PERMANENT_LOCAL') # Clear any "already linked" parameters params.set_param('database.already_linked_subscription_url', '') params.set_param('database.already_linked_email', '') params.set_param('database.already_linked_send_mail_url', '') return True class IrHttp(models.AbstractModel): """Block certain routes that call external services.""" _inherit = 'ir.http' @classmethod def _pre_dispatch(cls, rule, arguments): """Log and potentially block external service routes.""" # List of route patterns that should be blocked blocked_routes = [ '/iap/', '/partner_autocomplete/', '/google_', '/ocr/', '/sms/', ] # Note: We don't actually block here as it might break functionality # The actual blocking happens at the API/model level return super()._pre_dispatch(rule, arguments)