Compare commits
4 Commits
10e9cb6c15
...
ccae13386e
| Author | SHA1 | Date | |
|---|---|---|---|
| ccae13386e | |||
| 3cce144be2 | |||
| 843e747a5f | |||
| ecbeb913d2 |
@@ -6,8 +6,13 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
<<<<<<< HEAD
|
||||
"POT-Creation-Date: 2026-02-18 16:38+0000\n"
|
||||
"PO-Revision-Date: 2026-02-18 16:38+0000\n"
|
||||
=======
|
||||
"POT-Creation-Date: 2026-06-10 15:03+0000\n"
|
||||
"PO-Revision-Date: 2026-06-10 15:03+0000\n"
|
||||
>>>>>>> d0afa23 ([IMP] survey_extra_fields : handle file question on page navigation)
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -20,6 +25,11 @@ msgstr ""
|
||||
msgid ".pdf,.docx,.xlsx"
|
||||
msgstr ""
|
||||
|
||||
#. module: survey_extra_fields
|
||||
#: model_terms:ir.ui.view,arch_db:survey_extra_fields.question_file
|
||||
msgid "<i class=\"fa fa-times me-1\"/>Remove file"
|
||||
msgstr "<i class=\"fa fa-times me-1\"/>Supprimer le fichier"
|
||||
|
||||
#. module: survey_extra_fields
|
||||
#: model:ir.model.fields,field_description:survey_extra_fields.field_survey_question__allowed_extensions
|
||||
msgid "Allowed Extensions"
|
||||
|
||||
@@ -23,14 +23,25 @@ class SurveyUserInput(models.Model):
|
||||
("user_input_id", "=", self.id),
|
||||
("question_id", "=", question.id),
|
||||
])
|
||||
if not answer and any(line.value_file for line in old_answers):
|
||||
# No new file was submitted: a file input cannot be pre-filled
|
||||
# by the browser when navigating back to a previous page, so an
|
||||
# empty answer here does not mean the user removed their file.
|
||||
# Keep the previously uploaded file instead of overwriting it
|
||||
# with a skipped answer.
|
||||
return
|
||||
vals = {
|
||||
"user_input_id": self.id,
|
||||
"question_id": question.id,
|
||||
"skipped": False,
|
||||
"answer_type": "file",
|
||||
}
|
||||
if answer:
|
||||
file_data = json.loads(answer)
|
||||
file_data = json.loads(answer) if answer else {}
|
||||
if file_data.get("cleared"):
|
||||
# The user explicitly removed the file: drop the stored data and
|
||||
# mark the line as skipped.
|
||||
vals.update(answer_type=None, skipped=True, value_file=False, value_file_fname=False)
|
||||
elif file_data:
|
||||
file_b64 = file_data.get("data", "")
|
||||
file_name = file_data.get("name", "")
|
||||
self._check_file_constraints(question, file_b64, file_name)
|
||||
|
||||
@@ -6,6 +6,68 @@ odoo.define("survey_extra_fields.survey_form", function (require) {
|
||||
var survey_form = require("survey.form");
|
||||
|
||||
survey_form.include({
|
||||
/**
|
||||
* @override
|
||||
* Bind delegated listeners on the form root so they keep working after
|
||||
* each page is re-rendered (the inner content is replaced on navigation,
|
||||
* but the root element persists). They let the user clear a selected
|
||||
* file before submitting the form.
|
||||
*/
|
||||
start: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
self.$el.on(
|
||||
"change.surveyExtraFile",
|
||||
'input[data-question-type="file"]',
|
||||
self._onFileInputChange.bind(self)
|
||||
);
|
||||
self.$el.on(
|
||||
"click.surveyExtraFile",
|
||||
".o_survey_file_clear",
|
||||
self._onFileClearClick.bind(self)
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* On selection, show the file "chip" (filename + remove button) and hide
|
||||
* the raw input, so a freshly selected file looks exactly like an already
|
||||
* stored one (rendered server-side when navigating back).
|
||||
*/
|
||||
_onFileInputChange: function (ev) {
|
||||
var input = ev.currentTarget;
|
||||
var $container = $(input).closest(".o_survey_comment_container");
|
||||
if (!$container.length || !(input.files && input.files.length > 0)) {
|
||||
return;
|
||||
}
|
||||
$container.find(".o_survey_file_name").text(input.files[0].name);
|
||||
$container.find(".o_survey_file_selected").removeClass("d-none");
|
||||
delete input.dataset.fileCleared;
|
||||
$(input).addClass("d-none");
|
||||
},
|
||||
|
||||
/**
|
||||
* Discard the current file: hide the chip and bring back the input so the
|
||||
* user can pick a new one. A file already stored server-side is only
|
||||
* really replaced once a new file is submitted (see save_lines).
|
||||
*/
|
||||
_onFileClearClick: function (ev) {
|
||||
ev.preventDefault();
|
||||
var $container = $(ev.currentTarget).closest(".o_survey_comment_container");
|
||||
if (!$container.length) {
|
||||
return;
|
||||
}
|
||||
var $input = $container.find('input[data-question-type="file"]');
|
||||
if ($input.length) {
|
||||
$input.val("");
|
||||
// Flag the explicit removal so the submit tells the server to
|
||||
// drop any previously stored file (instead of preserving it).
|
||||
$input[0].dataset.fileCleared = "1";
|
||||
$input.removeClass("d-none");
|
||||
}
|
||||
$container.find(".o_survey_file_selected").addClass("d-none");
|
||||
},
|
||||
|
||||
_readFileAsDataURL: function (file) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var reader = new FileReader();
|
||||
@@ -19,18 +81,28 @@ odoo.define("survey_extra_fields.survey_form", function (require) {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
* The base implementation builds the submit params synchronously and
|
||||
* fires the RPC immediately. File inputs need to be read asynchronously
|
||||
* (FileReader), so when the current page contains file answers we
|
||||
* replicate the submit flow here, injecting the base64 file payload
|
||||
* before submitting.
|
||||
*/
|
||||
_submitForm: function (options) {
|
||||
var self = this;
|
||||
var $fileInputs = this.$('input[data-question-type="file"]');
|
||||
var hasFiles = false;
|
||||
// A file action is either a new selection or an explicit removal of
|
||||
// a previously stored file (which must be communicated to the server).
|
||||
var hasFileAction = false;
|
||||
$fileInputs.each(function () {
|
||||
if (this.files && this.files.length > 0) {
|
||||
hasFiles = true;
|
||||
if ((this.files && this.files.length > 0) || this.dataset.fileCleared) {
|
||||
hasFileAction = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasFiles || this.options.isStartScreen) {
|
||||
if (!hasFileAction || this.options.isStartScreen) {
|
||||
return this._super(options);
|
||||
}
|
||||
|
||||
@@ -51,7 +123,9 @@ odoo.define("survey_extra_fields.survey_form", function (require) {
|
||||
|
||||
this._prepareSubmitValues(formData, params);
|
||||
|
||||
// Read all selected files as base64
|
||||
// Read all selected files as base64 and add them to the submit
|
||||
// params. Explicitly cleared inputs (no new file) send a "cleared"
|
||||
// sentinel so the server removes the previously stored file.
|
||||
var filePromises = [];
|
||||
$fileInputs.each(function () {
|
||||
if (this.files && this.files.length > 0) {
|
||||
@@ -65,6 +139,8 @@ odoo.define("survey_extra_fields.survey_form", function (require) {
|
||||
});
|
||||
})
|
||||
);
|
||||
} else if (this.dataset.fileCleared) {
|
||||
params[this.name] = JSON.stringify({ cleared: true });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -107,7 +183,16 @@ odoo.define("survey_extra_fields.survey_form", function (require) {
|
||||
$questionWrapper.data("constrErrorMsg") ||
|
||||
_t("This question requires an answer.");
|
||||
if (questionRequired && !(this.files && this.files.length > 0)) {
|
||||
errors[questionId] = constrErrorMsg;
|
||||
// A file may already be stored server-side (e.g. uploaded
|
||||
// then navigating back): the chip is visible even though the
|
||||
// input is empty. Treat that as a valid answer.
|
||||
var $chip = $(this)
|
||||
.closest(".o_survey_comment_container")
|
||||
.find(".o_survey_file_selected");
|
||||
var hasExistingFile = $chip.length && !$chip.hasClass("d-none");
|
||||
if (!hasExistingFile) {
|
||||
errors[questionId] = constrErrorMsg;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.files && this.files.length > 0) {
|
||||
@@ -143,4 +228,4 @@ odoo.define("survey_extra_fields.survey_form", function (require) {
|
||||
return result;
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -94,19 +94,38 @@ class TestSurveyFileSaveLines(TestSurveyFileCommon):
|
||||
self.assertEqual(lines.value_file, new_b64.encode())
|
||||
self.assertEqual(lines.value_file_fname, "second.pdf")
|
||||
|
||||
def test_save_file_then_skip(self):
|
||||
"""Uploading a file then submitting empty marks line as skipped."""
|
||||
def test_save_file_then_empty_keeps_file(self):
|
||||
"""Submitting empty after a file keeps it (file inputs cannot be
|
||||
pre-filled when navigating back, so an empty answer must not erase it)."""
|
||||
answer = self._add_answer(self.survey, self.survey_manager.partner_id)
|
||||
file_json = json.dumps({"data": self.file_b64, "name": self.file_name})
|
||||
answer.save_lines(self.question_file, file_json)
|
||||
|
||||
answer.save_lines(self.question_file, "")
|
||||
|
||||
line = answer.user_input_line_ids.filtered(
|
||||
lambda l: l.question_id == self.question_file
|
||||
)
|
||||
self.assertEqual(len(line), 1)
|
||||
self.assertFalse(line.skipped)
|
||||
self.assertEqual(line.value_file, self.file_b64.encode())
|
||||
self.assertEqual(line.value_file_fname, self.file_name)
|
||||
|
||||
def test_save_file_explicitly_cleared(self):
|
||||
"""Submitting the 'cleared' sentinel after a file removes it."""
|
||||
answer = self._add_answer(self.survey, self.survey_manager.partner_id)
|
||||
file_json = json.dumps({"data": self.file_b64, "name": self.file_name})
|
||||
answer._save_lines(self.question_file, file_json)
|
||||
|
||||
answer._save_lines(self.question_file, json.dumps({"cleared": True}))
|
||||
|
||||
line = answer.user_input_line_ids.filtered(
|
||||
lambda l: l.question_id == self.question_file
|
||||
)
|
||||
self.assertEqual(len(line), 1)
|
||||
self.assertTrue(line.skipped)
|
||||
self.assertFalse(line.value_file)
|
||||
self.assertFalse(line.value_file_fname)
|
||||
|
||||
|
||||
class TestSurveyFileConstraints(TestSurveyFileCommon):
|
||||
|
||||
@@ -15,13 +15,26 @@
|
||||
|
||||
<template id="question_file" name="Question: File">
|
||||
<div class="o_survey_comment_container p-0">
|
||||
<t t-if="survey_form_readonly and answer_lines and answer_lines[0].value_file_fname">
|
||||
<p><t t-out="answer_lines[0].value_file_fname"/></p>
|
||||
<t t-set="existing_fname" t-value="answer_lines and answer_lines[0].value_file_fname"/>
|
||||
<t t-if="survey_form_readonly">
|
||||
<p t-if="existing_fname" class="mb-1">
|
||||
<i class="fa fa-paperclip me-1"/><t t-out="answer_lines[0].value_file_fname"/>
|
||||
</p>
|
||||
</t>
|
||||
<t t-if="not survey_form_readonly">
|
||||
<t t-else="">
|
||||
<!-- Uploaded file display, shown both for a fresh selection and when a
|
||||
file was already stored server-side (e.g. navigating back). The raw
|
||||
file input is hidden until the user clicks "Remove file". -->
|
||||
<span t-attf-class="o_survey_file_selected d-inline-flex align-items-center #{'' if existing_fname else 'd-none'}">
|
||||
<i class="fa fa-paperclip me-1"/>
|
||||
<span class="o_survey_file_name"><t t-out="existing_fname or ''"/></span>
|
||||
<button type="button" class="btn btn-link btn-sm text-danger o_survey_file_clear ms-2 py-0">
|
||||
<i class="fa fa-times me-1"/>Remove file
|
||||
</button>
|
||||
</span>
|
||||
<input
|
||||
type="file"
|
||||
class="o_survey_question_file"
|
||||
t-attf-class="o_survey_question_file #{'d-none' if existing_fname else ''}"
|
||||
t-att-name="question.id"
|
||||
t-att-data-question-type="question.question_type"
|
||||
t-att-accept="question.allowed_extensions or None"
|
||||
|
||||
@@ -72,7 +72,12 @@ Record generation configuration
|
||||
For m2o or m2m links, question should be configured before. See Question answers configuration section below.
|
||||
* **other created record**: If value come from other created record (m2o case only)
|
||||
|
||||
#. Several options exist for the *record creation* :
|
||||
|
||||
#. You can check "Ignore creation if a mandatory field is missing" to prevent the form to crash if some record creations fail.
|
||||
#. You can check "Update existing records" to update existing records instead of creating it. For this, you need to
|
||||
precise the "Field to retrieve existing records". Only the first matched record will be updated. By default
|
||||
the existing values are not replaced, except if you check the option "Update existing values".
|
||||
|
||||
Question answers configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
{
|
||||
"name": "Survey record generation",
|
||||
'summary': 'Allow to create record of any model when sending the form',
|
||||
'summary': 'Allow to create or update record of any model when sending the form',
|
||||
'description': """
|
||||
Allow to create record of any model when sending the form :
|
||||
----------------------------------------------------
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Project-Id-Version: Odoo Server 18.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-11-13 16:41+0000\n"
|
||||
"PO-Revision-Date: 2025-11-13 16:41+0000\n"
|
||||
"POT-Creation-Date: 2026-04-09 07:55+0000\n"
|
||||
"PO-Revision-Date: 2026-04-09 07:55+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -44,8 +44,6 @@ msgstr "Question autorisée"
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#, python-format
|
||||
msgid "Answer to question: %s"
|
||||
msgstr "Réponse à la question : %s"
|
||||
|
||||
@@ -130,8 +128,6 @@ msgstr "Type de champ"
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#, python-format
|
||||
msgid "Field type is : <b>%s</b>"
|
||||
msgstr "Le type de champ est : <b>%s</b>"
|
||||
|
||||
@@ -198,22 +194,14 @@ msgid ""
|
||||
"error is ignored."
|
||||
msgstr ""
|
||||
"Si un champs requis est manquant lors de la création de l'enregistrement, "
|
||||
"une erreur est levée lors de la soumission du formulaire. "
|
||||
"En activant cette option, l'erreur sera ignorée."
|
||||
"une erreur est levée lors de la soumission du formulaire. En activant cette "
|
||||
"option, l'erreur sera ignorée."
|
||||
|
||||
#. module: survey_record_generation
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation__ignore_if_mandatory_field_is_missing
|
||||
msgid "Ignore creation if a mandatory field is missing"
|
||||
msgstr "Ignorer la création si un champs requis est manquant"
|
||||
|
||||
#. module: survey_record_generation
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_generated_record____last_update
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation____last_update
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation_field_values____last_update
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation_field_values_x2m____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr "Dernière modification le"
|
||||
|
||||
#. module: survey_record_generation
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_generated_record__write_uid
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation__write_uid
|
||||
@@ -269,8 +257,6 @@ msgstr "Pas d'enregistrements générés trouvés"
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_question.py:0
|
||||
#: code:addons/survey_record_generation/models/survey_question.py:0
|
||||
#, python-format
|
||||
msgid "No record found in %s"
|
||||
msgstr "Pas d'enregistrements trouvés parmis %s"
|
||||
|
||||
@@ -292,7 +278,7 @@ msgstr ""
|
||||
#: model_terms:ir.ui.view,arch_db:survey_record_generation.survey_survey_view_form
|
||||
msgid ""
|
||||
"Only the first matched record will be updated.\n"
|
||||
" Also to be noticed, the unicity check feature has priority over updating the existing record."
|
||||
" Also to be noticed, the unicity check feature has priority over updating the existing record."
|
||||
msgstr ""
|
||||
"Attention, seul le premier enregistrement trouvé sera mis à jour. Aussi, si "
|
||||
"vous avez des champs avec une contrainte d'unicité, cette contrainte aura la"
|
||||
@@ -301,8 +287,6 @@ msgstr ""
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#, python-format
|
||||
msgid "Other created record: "
|
||||
msgstr "Autre enregistrement créé : "
|
||||
|
||||
@@ -353,8 +337,6 @@ msgstr "Modèle relatif"
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation.py:0
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation.py:0
|
||||
#, python-format
|
||||
msgid "Some required fields are not set : %s"
|
||||
msgstr "Certains champs requis ne sont pas remplis : %s"
|
||||
|
||||
@@ -388,17 +370,25 @@ msgstr "Sondage Création d'enregistrement Valeur des champs"
|
||||
#. module: survey_record_generation
|
||||
#: model:ir.model,name:survey_record_generation.model_survey_user_input
|
||||
msgid "Survey User Input"
|
||||
msgstr "Saisie utilisateur du sondage"
|
||||
msgstr "Entrée utilisateur du sondage"
|
||||
|
||||
#. module: survey_record_generation
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_generated_record__survey_record_creation_id
|
||||
msgid "Survey record creation"
|
||||
msgstr "Génération d'enregistrement depuis la participation"
|
||||
|
||||
#. module: survey_record_generation
|
||||
#: model:ir.model.fields,help:survey_record_generation.field_survey_record_creation__update_existing_values
|
||||
msgid ""
|
||||
"The default behavior is to not update the existing fields. If checked, the "
|
||||
"existing fields will be updated. "
|
||||
msgstr ""
|
||||
"Le comportement par défaut est de ne pas mettre à jour les valeurs existantes. Si cette option est cochée, "
|
||||
"les valeurs existantes seront écrasées."
|
||||
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_user_input.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The field %(field)s is mandatory for model %(model)s. In Record Creation "
|
||||
"tab, drag %(record)s on top of the model %(model)s."
|
||||
@@ -407,20 +397,16 @@ msgstr ""
|
||||
"Création d'un enregistrement, placez la ligne %(record)s au dessus de la "
|
||||
"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
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation_field_values__unicity_check
|
||||
msgid "Unicity constraint"
|
||||
msgstr "Contrainte d'unicité"
|
||||
|
||||
#. module: survey_record_generation
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation__update_existing_values
|
||||
msgid "Update existing values"
|
||||
msgstr "Écraser les valeurs existantes"
|
||||
|
||||
#. module: survey_record_generation
|
||||
#: model:ir.model.fields,field_description:survey_record_generation.field_survey_record_creation__update_existing_records
|
||||
msgid "Update existing records"
|
||||
@@ -455,17 +441,12 @@ msgstr "Message d'erreur"
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#, python-format
|
||||
msgid "You should append at least one record in %s"
|
||||
msgstr "Vous devez au moins ajouter un enregistrement dans %s"
|
||||
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_user_input.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"[Survey record generation] The answer values type '%(type)s' is not "
|
||||
"supported (for question %(question)s). Use 'record' or 'value' instead."
|
||||
@@ -477,7 +458,6 @@ msgstr ""
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_user_input.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"[Survey record generation] The boolean value %s(value)s is not supported "
|
||||
"(for question %(question)s)."
|
||||
@@ -488,7 +468,6 @@ msgstr ""
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_user_input.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"[Survey record generation] The question type %(type)s is not recognized (for"
|
||||
" question %(question)s)."
|
||||
@@ -499,7 +478,6 @@ msgstr ""
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_user_input.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"[Survey record generation] The question type %(type)s is not supported yet."
|
||||
msgstr ""
|
||||
@@ -509,8 +487,6 @@ msgstr ""
|
||||
#. module: survey_record_generation
|
||||
#. odoo-python
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#: code:addons/survey_record_generation/models/survey_record_creation_field_values.py:0
|
||||
#, python-format
|
||||
msgid "possible values are %s"
|
||||
msgstr "les valeurs possibles sont %s"
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from odoo import models, fields, api
|
||||
|
||||
class SurveyGeneratedRecord(models.Model):
|
||||
_name = "survey.generated.record"
|
||||
_rec_name = "survey_record_creation_name"
|
||||
|
||||
survey_record_creation_name = fields.Char('Name', readonly=True)
|
||||
survey_record_creation_id = fields.Many2one('survey.record.creation', 'Survey record creation', readonly=True)
|
||||
|
||||
@@ -27,6 +27,11 @@ class SurveyRecordCreation(models.Model):
|
||||
help="Choose the field you want to use to retrieve the existing record. "
|
||||
"WARNING: We update only the first record found.",
|
||||
)
|
||||
update_existing_values = fields.Boolean(
|
||||
string="Update existing values",
|
||||
help="The default behavior is to not update the existing fields. "
|
||||
"If checked, the existing fields will be updated. ",
|
||||
)
|
||||
allowed_field_ids = fields.Many2many(
|
||||
"ir.model.fields",
|
||||
compute="_compute_allowed_field_ids",
|
||||
@@ -54,8 +59,8 @@ class SurveyRecordCreation(models.Model):
|
||||
for record_creation in self:
|
||||
# check if all mandatory fields set
|
||||
if record_creation.model_id:
|
||||
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
|
||||
required_field_ids = record_creation.model_id.field_id.filtered(lambda f:f.required and "property_" not in f.name)
|
||||
set_field_ids = record_creation.field_values_ids.field_id
|
||||
missing_fields = required_field_ids - set_field_ids
|
||||
|
||||
if missing_fields:
|
||||
|
||||
@@ -26,6 +26,7 @@ class SurveyRecordCreationFieldValues(models.Model):
|
||||
"""Configure default values of records created on survey submission
|
||||
"""
|
||||
_name = 'survey.record.creation.field.values'
|
||||
_rec_name = 'displayed_value'
|
||||
|
||||
survey_record_creation_id = fields.Many2one('survey.record.creation')
|
||||
survey_id = fields.Many2one('survey.survey', related="survey_record_creation_id.survey_id")
|
||||
@@ -175,6 +176,7 @@ class SurveyRecordCreationFieldValuesX2m(models.Model):
|
||||
"""O2m an M2m default values
|
||||
"""
|
||||
_name = 'survey.record.creation.field.values.x2m'
|
||||
_rec_name = 'value_reference'
|
||||
|
||||
survey_record_creation_field_values_id = fields.Many2one('survey.record.creation.field.values')
|
||||
value_reference = fields.Reference(string='Record', selection='_selection_target_model')
|
||||
|
||||
@@ -31,7 +31,7 @@ class SurveyUserInput(models.Model):
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"survey_record_generation.survey_generated_record_action"
|
||||
)
|
||||
|
||||
action['domain'] = [('user_input_id.survey_id', '=', self.survey_id.id)]
|
||||
return action
|
||||
|
||||
def _mark_done(self):
|
||||
@@ -71,12 +71,15 @@ class SurveyUserInput(models.Model):
|
||||
if duplicate:
|
||||
record = duplicate
|
||||
elif existing_record:
|
||||
vals_with_keys_not_in_record = {
|
||||
k: v
|
||||
for k, v in vals.items()
|
||||
if not getattr(existing_record, k, False)
|
||||
}
|
||||
existing_record.write(vals_with_keys_not_in_record)
|
||||
if record_creation.update_existing_values:
|
||||
existing_record.write(vals)
|
||||
else:
|
||||
vals_with_keys_not_in_record = {
|
||||
k: v
|
||||
for k, v in vals.items()
|
||||
if not getattr(existing_record, k, False)
|
||||
}
|
||||
existing_record.write(vals_with_keys_not_in_record)
|
||||
record = existing_record
|
||||
else:
|
||||
try:
|
||||
|
||||
@@ -745,9 +745,91 @@ class TestSurveyRecordCreation(SurveyCase):
|
||||
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")
|
||||
self.assertEqual(len(partner), 1)
|
||||
self.assertEqual(partner.email, "jean@test.fr")
|
||||
self.assertEqual(partner.function, "happiness office manager")
|
||||
|
||||
def test_update_all_fields_when_updating_records(self):
|
||||
# A contact with name 'Jean' and email 'jean@test.fr' already exists.
|
||||
# We'll update the fields 'function' AND 'email' of this partner
|
||||
# because the option 'update_existing_values' is True
|
||||
self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Jean",
|
||||
"email": "jean@test.fr",
|
||||
}
|
||||
)
|
||||
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,
|
||||
"update_existing_values": True,
|
||||
}
|
||||
)
|
||||
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="IAmTheNewEmailReplacingTheOldOne@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.assertEqual(len(partner), 1)
|
||||
self.assertEqual(partner.email, "IAmTheNewEmailReplacingTheOldOne@test.fr")
|
||||
self.assertEqual(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
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<filter string="Active survey input" name="active_input"
|
||||
domain="[('user_input_id.id', '=', active_id)]"
|
||||
/>
|
||||
domain="[('user_input_id.id', '=', context.get('active_id'))]"
|
||||
/>
|
||||
<field name="survey_record_creation_name" />
|
||||
<field name="survey_record_creation_id" />
|
||||
<field name="user_input_id" />
|
||||
|
||||
@@ -16,12 +16,19 @@
|
||||
</tree>
|
||||
<form>
|
||||
<group>
|
||||
<field name="name" />
|
||||
<field name="model_id" />
|
||||
<field name="ignore_if_mandatory_field_is_missing" />
|
||||
<field name="update_existing_records" />
|
||||
<field name="allowed_field_ids" attrs="{'invisible': True}"/>
|
||||
<field name="field_to_retrieve_existing_records" attrs="{'invisible': [('update_existing_records', '=', False)]}"/>
|
||||
<group colspan="4">
|
||||
<field name="name" />
|
||||
<field name="model_id" />
|
||||
<field name="ignore_if_mandatory_field_is_missing" />
|
||||
<field name="allowed_field_ids" attrs="{'invisible': True}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="update_existing_records" />
|
||||
</group>
|
||||
<group attrs="{'invisible': [('update_existing_records', '=', False)]}">
|
||||
<field name="field_to_retrieve_existing_records"/>
|
||||
<field name="update_existing_values"/>
|
||||
</group>
|
||||
<div colspan="2" style="width:100%;">
|
||||
<div class="alert alert-warning"
|
||||
attrs="{'invisible': [('update_existing_records', '=', False)]}">
|
||||
|
||||
Reference in New Issue
Block a user