From 3de397f5954ea79675929424c990394ac0ae9403 Mon Sep 17 00:00:00 2001 From: git_admin Date: Fri, 1 May 2026 15:01:05 +0000 Subject: [PATCH] Tower: upload laundry_management 19.0.19.0.4 (via marketplace) --- .../migrations/19.0.13.0.0/pre_migrate.py | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 addons/laundry_management/migrations/19.0.13.0.0/pre_migrate.py diff --git a/addons/laundry_management/migrations/19.0.13.0.0/pre_migrate.py b/addons/laundry_management/migrations/19.0.13.0.0/pre_migrate.py new file mode 100644 index 0000000..4d34bf7 --- /dev/null +++ b/addons/laundry_management/migrations/19.0.13.0.0/pre_migrate.py @@ -0,0 +1,103 @@ +"""Pre-migration: 19.0.12.0.0 → 19.0.13.0.0 + +Removes three models that are being retired in this version: + - laundry.product.wizard (replaced by native sale.order.line product selection) + - laundry.product.wizard.line (child of above) + - laundry.whatsapp.wizard (replaced by one-click wa.me URL action) + +If these ir.model records are left in the DB while the Python classes no longer +exist, Odoo will log warnings or fail on field-level checks during upgrade. +We clean them here, before the ORM loads. +""" +import logging + +_logger = logging.getLogger(__name__) + +_REMOVED_MODELS = [ + 'laundry.product.wizard', + 'laundry.product.wizard.line', + 'laundry.whatsapp.wizard', +] + +_REMOVED_TABLES = [ + 'laundry_product_wizard', + 'laundry_product_wizard_line', + 'laundry_whatsapp_wizard', +] + + +def migrate(cr, version): + if not version: + return + + _logger.info('pre_migrate 19.0.13.0.0: cleaning retired wizard models %s', _REMOVED_MODELS) + + # 1. Drop physical tables (TransientModels do have real tables in Odoo) + for tbl in _REMOVED_TABLES: + cr.execute(f'DROP TABLE IF EXISTS "{tbl}" CASCADE') + _logger.info(' dropped table: %s', tbl) + + # 2. Remove ir.model.access entries for these models + cr.execute(""" + DELETE FROM ir_model_access + WHERE model_id IN ( + SELECT id FROM ir_model WHERE model = ANY(%s) + ) + """, (_REMOVED_MODELS,)) + _logger.info(' deleted %d ir.model.access rows', cr.rowcount) + + # 3. Remove ir.rule entries + cr.execute(""" + DELETE FROM ir_rule + WHERE model_id IN ( + SELECT id FROM ir_model WHERE model = ANY(%s) + ) + """, (_REMOVED_MODELS,)) + + # 4. Remove ir.model.fields for these models + cr.execute(""" + DELETE FROM ir_model_fields + WHERE model_id IN ( + SELECT id FROM ir_model WHERE model = ANY(%s) + ) + """, (_REMOVED_MODELS,)) + _logger.info(' deleted ir.model.fields rows') + + # 5. Remove ir.model.constraint + cr.execute(""" + DELETE FROM ir_model_constraint + WHERE model_id IN ( + SELECT id FROM ir_model WHERE model = ANY(%s) + ) + """, (_REMOVED_MODELS,)) + + # 6. Remove ir.model.relation + cr.execute(""" + DELETE FROM ir_model_relation + WHERE model_id IN ( + SELECT id FROM ir_model WHERE model = ANY(%s) + ) + """, (_REMOVED_MODELS,)) + + # 7. Remove ir.model.data (XML IDs) for these models + cr.execute(""" + DELETE FROM ir_model_data + WHERE model = 'ir.model' AND name IN ( + SELECT REPLACE(model, '.', '_') || '_' || id::text + FROM ir_model WHERE model = ANY(%s) + ) + """, (_REMOVED_MODELS,)) + # Also delete by res_id + cr.execute(""" + DELETE FROM ir_model_data + WHERE model = 'ir.model' + AND res_id IN (SELECT id FROM ir_model WHERE model = ANY(%s)) + """, (_REMOVED_MODELS,)) + + # 8. Finally remove ir.model entries themselves + cr.execute(""" + DELETE FROM ir_model WHERE model = ANY(%s) + """, (_REMOVED_MODELS,)) + _logger.info(' deleted ir.model entries for retired wizards') + + _logger.info('pre_migrate 19.0.13.0.0: complete')