[IMP] survey_record_generation: feature be able to update existing record
Some checks failed
pre-commit / pre-commit (pull_request) Failing after 1m41s

This commit is contained in:
2025-10-24 16:57:49 +02:00
parent fd25c2b970
commit 7157fffda0
5 changed files with 268 additions and 35 deletions

View File

@@ -6,8 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 16.0\n" "Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-23 13:02+0000\n" "POT-Creation-Date: 2025-10-24 14:59+0000\n"
"PO-Revision-Date: 2025-10-23 13:02+0000\n" "PO-Revision-Date: 2025-10-24 14:59+0000\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@@ -102,6 +102,11 @@ msgstr ""
msgid "Field" msgid "Field"
msgstr "Champ" msgstr "Champ"
#. module: survey_record_generation
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation__field_to_retrieve_existing_records
msgid "Field To Retrieve Existing Records"
msgstr "Champs pour retrouver l'enregistrement existant"
#. module: survey_record_generation #. module: survey_record_generation
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation_field_values__field_type #: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation_field_values__field_type
msgid "Field Type" msgid "Field Type"
@@ -361,11 +366,25 @@ msgstr ""
"Création d'un enregistrement, placez la ligne %(record)s au dessus de la " "Création d'un enregistrement, placez la ligne %(record)s au dessus de la "
"ligne du modèle %(model)s." "ligne du modèle %(model)s."
#. module: survey_record_generation
#. odoo-python
#: code:addons/survey_record_generation/models/survey_user_input.py:0
#, python-format
msgid ""
"The field %s is mandatory. In Record Creation tab, drag %s at the top of the"
" table"
msgstr ""
#. module: survey_record_generation #. module: survey_record_generation
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation_field_values__unicity_check #: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation_field_values__unicity_check
msgid "Unicity constraint" msgid "Unicity constraint"
msgstr "Contrainte d'unicité" msgstr "Contrainte d'unicité"
#. module: survey_record_generation
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation__update_existing_records
msgid "Update existing records"
msgstr "Mettre à jour les enregistrements existants"
#. module: survey_record_generation #. module: survey_record_generation
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_question_answer__value_char #: model:ir.model.fields,field_description:survey_record_generation.field_survey_question_answer__value_char
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation_field_values__displayed_value #: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation_field_values__displayed_value
@@ -410,8 +429,9 @@ msgid ""
"[Survey record generation] The answer values type '%(type)s' is not " "[Survey record generation] The answer values type '%(type)s' is not "
"supported (for question %(question)s). Use 'record' or 'value' instead." "supported (for question %(question)s). Use 'record' or 'value' instead."
msgstr "" msgstr ""
"[Survey record generation] La valeur '%(type)s' pour le champs 'answer_values_type' n'est pas supportée " "[Survey record generation] La valeur '%(type)s' pour le champs "
"(pour la question %(question)s). Veuillez utiliser 'Enregistrement' ou 'Valeur' à la place." "'answer_values_type' n'est pas supportée (pour la question %(question)s). "
"Veuillez utiliser 'Enregistrement' ou 'Valeur' à la place."
#. module: survey_record_generation #. module: survey_record_generation
#. odoo-python #. odoo-python

View File

@@ -13,7 +13,15 @@ class SurveyRecordCreation(models.Model):
name = fields.Char('Name') name = fields.Char('Name')
survey_id = fields.Many2one('survey.survey', string="Survey") survey_id = fields.Many2one('survey.survey', string="Survey")
model_id = fields.Many2one('ir.model', "Model", help="Model of generated record") model_id = fields.Many2one('ir.model', "Model", help="Model of generated record")
update_existing_records = fields.Boolean(
string="Update existing records",
)
field_to_retrieve_existing_records = fields.Many2one(
"ir.model.fields",
domain="[('model_id','=',model_id),('readonly','=',False),('ttype','in',['char','text'])]",
ondelete="cascade"
)
field_values_ids = fields.One2many('survey.record.creation.field.values', 'survey_record_creation_id', string="Field values") field_values_ids = fields.One2many('survey.record.creation.field.values', 'survey_record_creation_id', string="Field values")
warning_message = fields.Html('Warning message', compute="_compute_warning_message") warning_message = fields.Html('Warning message', compute="_compute_warning_message")
sequence = fields.Integer("sequence") sequence = fields.Integer("sequence")
@@ -22,7 +30,7 @@ class SurveyRecordCreation(models.Model):
def clear_field_values_ids(self): def clear_field_values_ids(self):
self.field_values_ids = None self.field_values_ids = None
@api.depends('model_id','field_values_ids') @api.depends('model_id','field_values_ids')
def _compute_warning_message(self): def _compute_warning_message(self):
for record_creation in self: for record_creation in self:
# check if all mandatory fields set # check if all mandatory fields set
@@ -30,14 +38,10 @@ class SurveyRecordCreation(models.Model):
required_field_ids = self.model_id.field_id.filtered(lambda f:f.required and "property_" not in f.name) required_field_ids = self.model_id.field_id.filtered(lambda f:f.required and "property_" not in f.name)
set_field_ids = self.field_values_ids.field_id set_field_ids = self.field_values_ids.field_id
missing_fields = required_field_ids - set_field_ids missing_fields = required_field_ids - set_field_ids
if missing_fields: if missing_fields:
record_creation.warning_message = _("Some required fields are not set : %s",', '.join([f"<b>{f.field_description}</b> (<i>{f.name}</i>)" for f in missing_fields])) record_creation.warning_message = _("Some required fields are not set : %s",', '.join([f"<b>{f.field_description}</b> (<i>{f.name}</i>)" for f in missing_fields]))
else: else:
record_creation.warning_message = None record_creation.warning_message = None
else: else:
record_creation.warning_message = None record_creation.warning_message = None

View File

@@ -64,12 +64,21 @@ class SurveyUserInput(models.Model):
vals[field_name] = value vals[field_name] = value
existing_record = self.find_existing_record(record_creation, vals)
duplicate = self.find_duplicate_if_there_are_fields_with_unicity_check( duplicate = self.find_duplicate_if_there_are_fields_with_unicity_check(
model, record_creation, vals model, record_creation, vals
) )
if duplicate: if duplicate:
record = duplicate record = duplicate
elif existing_record:
vals = {
k: v
for k, v in vals.items()
if not getattr(existing_record, k, False)
}
record = existing_record.write(vals)
else: else:
if ( if (
model == "res.partner" model == "res.partner"
@@ -110,6 +119,20 @@ class SurveyUserInput(models.Model):
return super()._mark_done() return super()._mark_done()
def find_existing_record(
self, record_creation: "SurveyRecordCreation", vals: dict
) -> Any:
if record_creation.update_existing_records:
model = record_creation.model_id.model
search_field = record_creation.field_to_retrieve_existing_records
user_answer_value = vals.get(search_field.name)
if user_answer_value:
return self.env[model].search(
domain=[(search_field.name, "=", user_answer_value)], limit=1
)
return None
def get_value_based_on_value_origin( def get_value_based_on_value_origin(
self, self,
field_value: "SurveyRecordCreationFieldValues", field_value: "SurveyRecordCreationFieldValues",

View File

@@ -495,9 +495,9 @@ class TestSurveyRecordCreation(SurveyCase):
) )
self.second_answer._mark_done() self.second_answer._mark_done()
partners = self.env["res.partner"].search([("name", "=", "Jean")]) partner = self.env["res.partner"].search([("name", "=", "Jean")])
self.assertTrue(partner.name == "Jean") self.assertTrue(partner.name == "Jean")
self.assertFalse(len(partners) == 2) self.assertTrue(len(partner) == 1)
def test_some_questions_are_not_answered(self): def test_some_questions_are_not_answered(self):
self.question_email = self._add_question( self.question_email = self._add_question(
@@ -654,3 +654,187 @@ class TestSurveyRecordCreation(SurveyCase):
partner = self.env["res.partner"].search([("name", "=", "Jean")]) partner = self.env["res.partner"].search([("name", "=", "Jean")])
self.assertTrue(partner.employee) self.assertTrue(partner.employee)
def test_update_existing_record(self):
# A contact with name 'Jean' already exists.
# We'll update the email of this partner (and not create a new one)
self.env["res.partner"].create({"name": "Jean"})
self.question_email = self._add_question(
page=None,
name="Email",
qtype="char_box",
survey_id=self.survey.id,
sequence=1,
)
self.survey_record_creation.write(
{
"update_existing_records": True,
"field_to_retrieve_existing_records": self.name_field.id,
}
)
email_field = self.env["ir.model.fields"].search(
[("model", "=", "res.partner"), ("name", "=", "email")]
)
self.env["survey.record.creation.field.values"].create(
{
"survey_record_creation_id": self.survey_record_creation.id,
"survey_id": self.survey.id,
"model_id": self.res_partner_model.id,
"field_id": email_field.id,
"value_origin": "question",
"question_id": self.question_email.id,
}
)
self.answer = self._add_answer(
survey=self.survey, partner=False, email="jean@test.fr"
)
self._add_answer_line(
question=self.question_name, answer=self.answer, answer_value="Jean"
)
self._add_answer_line(
question=self.question_email,
answer=self.answer,
answer_value="jean@test.fr",
)
self.answer._mark_done()
partner = self.env["res.partner"].search([("name", "=", "Jean")])
self.assertTrue(len(partner) == 1)
self.assertTrue(partner.email == "jean@test.fr")
def test_update_only_empty_fields_when_updating_records(self):
# A contact with name 'Jean' and email 'jean@test.fr' already exists.
# We'll update the field 'function' of this partner and won't update the email
# because it's already filled up
self.env["res.partner"].create(
{
"name": "Jean",
"email": "jean@test.fr",
# when the survey is submitted, email should not be updated
}
)
self.question_email = self._add_question(
page=None,
name="Email",
qtype="char_box",
survey_id=self.survey.id,
sequence=1,
)
self.question_function = self._add_question(
page=None,
name="Function",
qtype="char_box",
survey_id=self.survey.id,
sequence=1,
)
self.survey_record_creation.write(
{
"update_existing_records": True,
"field_to_retrieve_existing_records": self.name_field.id,
}
)
email_field = self.env["ir.model.fields"].search(
[("model", "=", "res.partner"), ("name", "=", "email")]
)
self.env["survey.record.creation.field.values"].create(
{
"survey_record_creation_id": self.survey_record_creation.id,
"survey_id": self.survey.id,
"model_id": self.res_partner_model.id,
"field_id": email_field.id,
"value_origin": "question",
"question_id": self.question_email.id,
}
)
function_field = self.env["ir.model.fields"].search(
[("model", "=", "res.partner"), ("name", "=", "function")]
)
self.env["survey.record.creation.field.values"].create(
{
"survey_record_creation_id": self.survey_record_creation.id,
"survey_id": self.survey.id,
"model_id": self.res_partner_model.id,
"field_id": function_field.id,
"value_origin": "question",
"question_id": self.question_function.id,
}
)
self.answer = self._add_answer(
survey=self.survey, partner=False, email="jean@test.fr"
)
self._add_answer_line(
question=self.question_name, answer=self.answer, answer_value="Jean"
)
self._add_answer_line(
question=self.question_email,
answer=self.answer,
answer_value="ThisEmailShouldNotBeUpdated@test.fr",
)
self._add_answer_line(
question=self.question_function,
answer=self.answer,
answer_value="happiness office manager",
)
self.answer._mark_done()
partner = self.env["res.partner"].search([("name", "=", "Jean")])
self.assertTrue(len(partner) == 1)
self.assertTrue(partner.email == "jean@test.fr")
self.assertTrue(partner.function == "happiness office manager")
def test_unicity_check_has_priority_over_update(self):
# In this test, we verify that if a field is set up with unicity_check
# it has priority over updating the existing record
self.name_survey_record_creation_field_values.unicity_check = True
self.env["res.partner"].create({"name": "Jean"})
self.question_email = self._add_question(
page=None,
name="Email",
qtype="char_box",
survey_id=self.survey.id,
sequence=1,
)
self.survey_record_creation.write(
{
"update_existing_records": True,
"field_to_retrieve_existing_records": self.name_field.id,
}
)
email_field = self.env["ir.model.fields"].search(
[("model", "=", "res.partner"), ("name", "=", "email")]
)
self.env["survey.record.creation.field.values"].create(
{
"survey_record_creation_id": self.survey_record_creation.id,
"survey_id": self.survey.id,
"model_id": self.res_partner_model.id,
"field_id": email_field.id,
"value_origin": "question",
"question_id": self.question_email.id,
}
)
self.answer = self._add_answer(
survey=self.survey, partner=False, email="jean@test.fr"
)
self._add_answer_line(
question=self.question_name, answer=self.answer, answer_value="Jean"
)
self._add_answer_line(
question=self.question_email,
answer=self.answer,
answer_value="jean@test.fr",
)
self.answer._mark_done()
partner = self.env["res.partner"].search([("name", "=", "Jean")])
self.assertTrue(len(partner) == 1)
self.assertTrue(getattr(partner, "Email", None) is None)

View File

@@ -18,16 +18,18 @@
<group> <group>
<field name="name" /> <field name="name" />
<field name="model_id" /> <field name="model_id" />
<field name="update_existing_records" />
<field name="field_to_retrieve_existing_records" attrs="{'invisible': [('update_existing_records', '=', False)]}"/>
<field name="field_values_ids"> <field name="field_values_ids">
<tree> <tree>
<field name="field_id" /> <field name="field_id" />
<field name="displayed_value" /> <field name="displayed_value" />
<field name="unicity_check" /> <field name="unicity_check" />
</tree> </tree>
<form> <form>
<group> <group>
<field name="model_id" invisible="1" /> <field name="model_id" invisible="1" />
<field name="field_id" /> <field name="field_id" />
<field name="unicity_check" /> <field name="unicity_check" />
<field name="field_relation" invisible="1" /> <field name="field_relation" invisible="1" />
<field name="field_type" invisible="1" /> <field name="field_type" invisible="1" />
@@ -40,37 +42,37 @@
</group> </group>
<div attrs="{'invisible':['|',('value_origin','!=','fixed'),('field_id','=',False)]}"> <div attrs="{'invisible':['|',('value_origin','!=','fixed'),('field_id','=',False)]}">
<group> <group>
<field name="displayed_value" invisible="1" /> <field name="displayed_value" invisible="1" />
<field <field
name="fixed_value_char" name="fixed_value_char"
attrs="{'invisible':[('field_type','!=','char')]}" attrs="{'invisible':[('field_type','!=','char')]}"
/> />
<field <field
name="fixed_value_selection" name="fixed_value_selection"
attrs="{'invisible':[('field_type','!=','selection')]}" attrs="{'invisible':[('field_type','!=','selection')]}"
/> />
<field <field
name="fixed_value_text" name="fixed_value_text"
attrs="{'invisible':[('field_type','!=','text')]}" attrs="{'invisible':[('field_type','!=','text')]}"
/> />
<field <field
name="fixed_value_html" name="fixed_value_html"
attrs="{'invisible':[('field_type','!=', 'html')]}" attrs="{'invisible':[('field_type','!=', 'html')]}"
/> />
<field <field
name="fixed_value_integer" name="fixed_value_integer"
attrs="{'invisible':[('field_type','!=', 'integer')]}" attrs="{'invisible':[('field_type','!=', 'integer')]}"
/> />
<field <field
name="fixed_value_float" name="fixed_value_float"
attrs="{'invisible':[('field_type','!=', 'float')]}" attrs="{'invisible':[('field_type','!=', 'float')]}"
/> />
<field <field
name="fixed_value_date" name="fixed_value_date"
attrs="{'invisible':[('field_type','!=', 'date')]}" attrs="{'invisible':[('field_type','!=', 'date')]}"
/> />
<field <field
name="fixed_value_datetime" name="fixed_value_datetime"
attrs="{'invisible':[('field_type','!=', 'datetime')]}" attrs="{'invisible':[('field_type','!=', 'datetime')]}"
/> />
<field <field
@@ -87,7 +89,7 @@
attrs="{'invisible':[('field_type','not in',['one2many','many2many'])]}"> attrs="{'invisible':[('field_type','not in',['one2many','many2many'])]}">
<tree editable="bottom"> <tree editable="bottom">
<field name="survey_record_creation_field_values_id" invisible="1" /> <field name="survey_record_creation_field_values_id" invisible="1" />
<field name="value_reference" <field name="value_reference"
options="{'hide_model': True, 'no_create': True, 'no_edit': True, 'no_open': True}" options="{'hide_model': True, 'no_create': True, 'no_edit': True, 'no_open': True}"
/> />
</tree> </tree>
@@ -104,7 +106,7 @@
<field name="other_created_record_id" /> <field name="other_created_record_id" />
</group> </group>
</div> </div>
</form> </form>
</field> </field>
<div colspan="2"> <div colspan="2">
<field name="warning_message" /> <field name="warning_message" />