From a08c3ec18c5a28c9d3beca373d6aac8a1a8e5a00 Mon Sep 17 00:00:00 2001 From: Laetitia Da Costa Date: Tue, 28 Apr 2026 19:23:45 +0200 Subject: [PATCH] [IMP]survey_record_generation:show alerte when deleting a crm tag used in lead record creation --- survey_record_generation/__manifest__.py | 2 +- survey_record_generation/models/__init__.py | 1 + survey_record_generation/models/base.py | 65 ++++++++++++ .../models/survey_question.py | 15 ++- survey_record_generation/tests/__init__.py | 1 + .../test_referenced_record_protection.py | 98 +++++++++++++++++++ 6 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 survey_record_generation/models/base.py create mode 100644 survey_record_generation/tests/test_referenced_record_protection.py diff --git a/survey_record_generation/__manifest__.py b/survey_record_generation/__manifest__.py index 05a64e0..99d2aae 100644 --- a/survey_record_generation/__manifest__.py +++ b/survey_record_generation/__manifest__.py @@ -11,7 +11,7 @@ Allow to create record of any model when sending the form : * Associate question with fields * For x2m fields : Associate values to questions """, - "version": "16.0.1.0.2", + "version": "16.0.1.0.3", "license": "AGPL-3", "author": "Elabore", "website": "https://www.elabore.coop", diff --git a/survey_record_generation/models/__init__.py b/survey_record_generation/models/__init__.py index e8d744a..fc7f3e4 100644 --- a/survey_record_generation/models/__init__.py +++ b/survey_record_generation/models/__init__.py @@ -1,3 +1,4 @@ +from . import base from . import survey_question_answer from . import survey_question from . import survey_record_creation_field_values diff --git a/survey_record_generation/models/base.py b/survey_record_generation/models/base.py new file mode 100644 index 0000000..e083748 --- /dev/null +++ b/survey_record_generation/models/base.py @@ -0,0 +1,65 @@ +from odoo import models, _ +from odoo.exceptions import UserError + + +class Base(models.AbstractModel): + _inherit = 'base' + + def unlink(self): + if not self.env.context.get('module_uninstall'): + self._check_survey_record_creation_references() + return super().unlink() + + def _check_survey_record_creation_references(self): + if not self or self._name in ( + 'survey.record.creation.field.values', + 'survey.record.creation.field.values.x2m', + ): + return + + FieldValues = self.env['survey.record.creation.field.values'].sudo() + if not FieldValues.search_count([('field_id.relation', '=', self._name)], limit=1): + return + + references = [f"{self._name},{record.id}" for record in self] + + used_in_m2o = FieldValues.search([ + ('fixed_value_many2one', 'in', references), + ]) + used_in_m2m = self.env['survey.record.creation.field.values.x2m'].sudo().search([ + ('value_reference', 'in', references), + ]) + + if not used_in_m2o and not used_in_m2m: + return + + usages = set() + for fv in used_in_m2o: + usages.add(( + fv.survey_id.display_name or '', + fv.field_id.field_description or fv.field_id.name or '', + fv.fixed_value_many2one.display_name or '', + )) + for fvx in used_in_m2m: + parent = fvx.survey_record_creation_field_values_id + usages.add(( + parent.survey_id.display_name or '', + parent.field_id.field_description or parent.field_id.name or '', + fvx.value_reference.display_name or '', + )) + + usage_lines = '\n'.join( + '- ' + _( + 'Survey "%(survey)s", field "%(field)s" (value: %(value)s)', + survey=survey, field=field, value=value, + ) + for survey, field, value in sorted(usages) + ) + + raise UserError(_( + 'Cannot delete this record because it is used as a default value ' + 'in the following survey record creation configurations:\n\n' + '%(usages)s\n\n' + 'Please update or remove the corresponding survey configuration first.', + usages=usage_lines, + )) diff --git a/survey_record_generation/models/survey_question.py b/survey_record_generation/models/survey_question.py index 4bb0478..426ec10 100644 --- a/survey_record_generation/models/survey_question.py +++ b/survey_record_generation/models/survey_question.py @@ -32,8 +32,9 @@ class SurveyQuestion(models.Model): def fill(self): for question in self: - if question.model_id: - new_suggested_answer_ids = [Command.clear()] + if question.suggested_answer_ids: + question.suggested_answer_ids = [Command.clear()] + elif question.model_id: record_model = question.model_id.model if question.fill_domain: @@ -43,7 +44,11 @@ class SurveyQuestion(models.Model): records = self.env[record_model].search(domain) - new_suggested_answer_ids += [Command.create({'value':record.display_name, 'record_id':f"{record_model},{record.id}" -}) for record in records] - question.suggested_answer_ids = new_suggested_answer_ids + question.suggested_answer_ids = [ + Command.create({ + 'value': record.display_name, + 'record_id': f"{record_model},{record.id}", + }) + for record in records + ] diff --git a/survey_record_generation/tests/__init__.py b/survey_record_generation/tests/__init__.py index 5b794a3..fa02f1b 100644 --- a/survey_record_generation/tests/__init__.py +++ b/survey_record_generation/tests/__init__.py @@ -1 +1,2 @@ from . import test_survey_record_creation +from . import test_referenced_record_protection diff --git a/survey_record_generation/tests/test_referenced_record_protection.py b/survey_record_generation/tests/test_referenced_record_protection.py new file mode 100644 index 0000000..7517993 --- /dev/null +++ b/survey_record_generation/tests/test_referenced_record_protection.py @@ -0,0 +1,98 @@ +from odoo.exceptions import UserError +from odoo.addons.survey.tests.common import SurveyCase + + +class TestReferencedRecordProtection(SurveyCase): + def setUp(self): + super().setUp() + self.survey = self.env["survey.survey"].create({"title": "Test Survey"}) + self.res_partner_model = self.env["ir.model"]._get("res.partner") + self.survey_record_creation = self.env["survey.record.creation"].create( + { + "name": "Contact", + "survey_id": self.survey.id, + "model_id": self.res_partner_model.id, + } + ) + + def test_unlink_blocked_when_referenced_via_many2one(self): + title = self.env["res.partner.title"].create({"name": "Mister"}) + title_field = self.env["ir.model.fields"].search( + [("model", "=", "res.partner"), ("name", "=", "title")] + ) + self.env["survey.record.creation.field.values"].create( + { + "survey_record_creation_id": self.survey_record_creation.id, + "field_id": title_field.id, + "value_origin": "fixed", + "fixed_value_many2one": f"res.partner.title,{title.id}", + } + ) + + with self.assertRaises(UserError) as ctx: + title.unlink() + self.assertIn("Test Survey", str(ctx.exception)) + self.assertIn("Mister", str(ctx.exception)) + + def test_unlink_blocked_when_referenced_via_many2many(self): + category = self.env["res.partner.category"].create({"name": "Adult"}) + category_field = self.env["ir.model.fields"].search( + [("model", "=", "res.partner"), ("name", "=", "category_id")] + ) + field_values = self.env["survey.record.creation.field.values"].create( + { + "survey_record_creation_id": self.survey_record_creation.id, + "field_id": category_field.id, + "value_origin": "fixed", + } + ) + self.env["survey.record.creation.field.values.x2m"].create( + { + "survey_record_creation_field_values_id": field_values.id, + "value_reference": f"res.partner.category,{category.id}", + } + ) + + with self.assertRaises(UserError) as ctx: + category.unlink() + self.assertIn("Test Survey", str(ctx.exception)) + self.assertIn("Adult", str(ctx.exception)) + + def test_unlink_allowed_when_not_referenced(self): + title = self.env["res.partner.title"].create({"name": "Sir"}) + # No survey config references this title + title.unlink() + self.assertFalse(title.exists()) + + def test_unlink_allowed_after_removing_survey_config(self): + title = self.env["res.partner.title"].create({"name": "Mister"}) + title_field = self.env["ir.model.fields"].search( + [("model", "=", "res.partner"), ("name", "=", "title")] + ) + field_values = self.env["survey.record.creation.field.values"].create( + { + "survey_record_creation_id": self.survey_record_creation.id, + "field_id": title_field.id, + "value_origin": "fixed", + "fixed_value_many2one": f"res.partner.title,{title.id}", + } + ) + field_values.unlink() + title.unlink() + self.assertFalse(title.exists()) + + def test_unlink_allowed_during_module_uninstall(self): + title = self.env["res.partner.title"].create({"name": "Mister"}) + title_field = self.env["ir.model.fields"].search( + [("model", "=", "res.partner"), ("name", "=", "title")] + ) + self.env["survey.record.creation.field.values"].create( + { + "survey_record_creation_id": self.survey_record_creation.id, + "field_id": title_field.id, + "value_origin": "fixed", + "fixed_value_many2one": f"res.partner.title,{title.id}", + } + ) + title.with_context(module_uninstall=True).unlink() + self.assertFalse(title.exists())