[FIX] website: show form dynamic recipient email in edit mode
Since [this other commit], the recipient email option of the form on the `/contactus` page is not filled correctly with the company email. By chance, the form signature task fixed the bug but introduced another one. The previous commit fixed the bug introduced by the form signature task but reintroduced the inital bug. This commit fixes the initial bug and adds a test. By default, the form on the `/contactus` page sends emails to the email address of the company. Unfortunately, before this commit, when a user entered edit mode, the Recipient E-mail option always displayed "info@yourcompany.example.com" even when the company's e-mail address was different. This commit corrects this by displaying the dynamic value of `company.email` in the Recipient E-mail option coming from the data-for. Steps to reproduce the issue fixed by this commit: - Go to Settings > General Settings - Update the company's email address - Go to /contactus and edit - Click on the form => The recipient email value is still "info@yourcompany.example.com" instead of the company's email address. This commit fixes the issue, adds a test to ensure the recipient email option is correct and adds a utility to parse the data-for data. Bonus: this commit also fixes the following issue catched by sentry: - Go to /contactus - Click on Edit - In the Form option, remove the content of the 'Recipient Email' field. - Save - Fill and submit the form => An error is generated in the log. [this other commit]: https://github.com/odoo/odoo/commit/043e1fdf923d2037dd8da128ab99388f0c92e544 task-3382195 sentry-4633940473 closes odoo/odoo#147933 X-original-commit: 56f6b8dccec5cebc9a93454538b39886d4d3f63c Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com> Signed-off-by: Guillaume Dieleman (gdi) <gdi@odoo.com>
This commit is contained in:
committed by
Guillaume-gdi
parent
f9154bb6db
commit
f2d3a193c2
@@ -414,6 +414,30 @@ function isMobile(self) {
|
||||
return isMobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parsed data coming from the data-for element for the given form.
|
||||
*
|
||||
* @param {string} formId
|
||||
* @param {HTMLElement} parentEl
|
||||
* @returns {Object|undefined} the parsed data
|
||||
*/
|
||||
function getParsedDataFor(formId, parentEl) {
|
||||
const dataForEl = parentEl.querySelector(`[data-for='${formId}']`);
|
||||
if (!dataForEl) {
|
||||
return;
|
||||
}
|
||||
return JSON.parse(dataForEl.dataset.values
|
||||
// replaces `True` by `true` if they are after `,` or `:` or `[`
|
||||
.replace(/([,:\[]\s*)True/g, '$1true')
|
||||
// replaces `False` and `None` by `""` if they are after `,` or `:` or `[`
|
||||
.replace(/([,:\[]\s*)(False|None)/g, '$1""')
|
||||
// replaces the `'` by `"` if they are before `,` or `:` or `]` or `}`
|
||||
.replace(/'(\s*[,:\]}])/g, '"$1')
|
||||
// replaces the `'` by `"` if they are after `{` or `[` or `,` or `:`
|
||||
.replace(/([{\[:,]\s*)'/g, '$1"')
|
||||
);
|
||||
}
|
||||
|
||||
export default {
|
||||
loadAnchors: loadAnchors,
|
||||
autocompleteWithPages: autocompleteWithPages,
|
||||
@@ -427,4 +451,5 @@ export default {
|
||||
generateGMapIframe: generateGMapIframe,
|
||||
generateGMapLink: generateGMapLink,
|
||||
isMobile: isMobile,
|
||||
getParsedDataFor: getParsedDataFor,
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
serializeDateTime,
|
||||
} from "@web/core/l10n/dates";
|
||||
const { DateTime } = luxon;
|
||||
import wUtils from '@website/js/utils';
|
||||
|
||||
publicWidget.registry.EditModeWebsiteForm = publicWidget.Widget.extend({
|
||||
selector: '.s_website_form form, form.s_website_form', // !compatibility
|
||||
@@ -124,26 +125,17 @@ const { DateTime } = luxon;
|
||||
// Because, using t-att- inside form make it non-editable
|
||||
// Data-fill-with attribute is given during registry and is used by
|
||||
// to know which user data should be used to prfill fields.
|
||||
const dataForEl = document.querySelector(`[data-for='${this.el.id}']`);
|
||||
let dataForValues = wUtils.getParsedDataFor(this.el.id, document);
|
||||
this.editTranslations = !!this._getContext(true).edit_translations;
|
||||
// On the "edit_translations" mode, a <span/> with a translated term
|
||||
// will replace the attribute value, leading to some inconsistencies
|
||||
// (setting again the <span> on the attributes after the editor's
|
||||
// cleanup, setting wrong values on the attributes after translating
|
||||
// default values...)
|
||||
if (!this.editTranslations && (dataForEl || Object.keys(this.preFillValues).length)) {
|
||||
const dataForValues = dataForEl ?
|
||||
JSON.parse(dataForEl.dataset.values
|
||||
// replaces `True` by `true` if they are after `,` or `:` or `[`
|
||||
.replace(/([,:\[]\s*)True/g, '$1true')
|
||||
// replaces `False` and `None` by `""` if they are after `,` or `:` or `[`
|
||||
.replace(/([,:\[]\s*)(False|None)/g, '$1""')
|
||||
// replaces the `'` by `"` if they are before `,` or `:` or `]` or `}`
|
||||
.replace(/'(\s*[,:\]}])/g, '"$1')
|
||||
// replaces the `'` by `"` if they are after `{` or `[` or `,` or `:`
|
||||
.replace(/([{\[:,]\s*)'/g, '$1"')
|
||||
) : {};
|
||||
const fieldNames = this.$el.serializeArray().map(el => el.name);
|
||||
if (!this.editTranslations
|
||||
&& (dataForValues || Object.keys(this.preFillValues).length)) {
|
||||
dataForValues = dataForValues || {};
|
||||
const fieldNames = this.$target.serializeArray().map(el => el.name);
|
||||
// All types of inputs do not have a value property (eg:hidden),
|
||||
// for these inputs any function that is supposed to put a value
|
||||
// property actually puts a HTML value attribute. Because of
|
||||
|
||||
@@ -9,6 +9,7 @@ import { unique } from "@web/core/utils/arrays";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { renderToElement } from "@web/core/utils/render";
|
||||
import { formatDate, formatDateTime } from "@web/core/l10n/dates";
|
||||
import wUtils from '@website/js/utils';
|
||||
|
||||
let currentActionName;
|
||||
|
||||
@@ -415,6 +416,14 @@ options.registry.WebsiteFormEditor = FormEditor.extend({
|
||||
if (!this.$target[0].dataset.model_name) {
|
||||
proms.push(this._applyFormModel());
|
||||
}
|
||||
// Get the email_to value from the data-for attribute if it exists. We
|
||||
// use it if there is no value on the email_to input.
|
||||
const formId = this.$target[0].id;
|
||||
const dataForValues = wUtils.getParsedDataFor(formId, this.$target[0].ownerDocument);
|
||||
if (dataForValues) {
|
||||
this.dataForEmailTo = dataForValues['email_to'];
|
||||
}
|
||||
this.defaultEmailToValue = "info@yourcompany.example.com";
|
||||
return Promise.all(proms);
|
||||
},
|
||||
/**
|
||||
@@ -601,6 +610,16 @@ options.registry.WebsiteFormEditor = FormEditor.extend({
|
||||
return this.activeForm.id;
|
||||
case 'addActionField': {
|
||||
const value = this.$target.find(`.s_website_form_dnone input[name="${params.fieldName}"]`).val();
|
||||
if (params.fieldName === 'email_to') {
|
||||
// For email_to, we try to find a value in this order:
|
||||
// 1. The current value of the input
|
||||
// 2. The data-for value if it exists
|
||||
// 3. The default value (`defaultEmailToValue`)
|
||||
if (value && value !== this.defaultEmailToValue) {
|
||||
return value;
|
||||
}
|
||||
return this.dataForEmailTo || this.defaultEmailToValue;
|
||||
}
|
||||
if (value) {
|
||||
return value;
|
||||
} else {
|
||||
@@ -672,7 +691,12 @@ options.registry.WebsiteFormEditor = FormEditor.extend({
|
||||
*/
|
||||
_addHiddenField: function (value, fieldName) {
|
||||
this.$target.find(`.s_website_form_dnone:has(input[name="${fieldName}"])`).remove();
|
||||
if (value) {
|
||||
// For the email_to field, we keep the field even if it has no value so
|
||||
// that the email is sent to data-for value or to the default email.
|
||||
if (fieldName === 'email_to' && !value && !this.dataForEmailTo) {
|
||||
value = this.defaultEmailToValue;
|
||||
}
|
||||
if (value || fieldName === 'email_to') {
|
||||
const hiddenField = renderToElement('website.form_field_hidden', {
|
||||
field: {
|
||||
name: fieldName,
|
||||
|
||||
@@ -590,6 +590,10 @@
|
||||
content: "Change a random option",
|
||||
trigger: '[data-set-mark] input',
|
||||
run: 'text_blur **',
|
||||
}, {
|
||||
content: "Check that the recipient email is correct",
|
||||
trigger: 'we-input[data-field-name="email_to"] input:propValue("website_form_contactus_edition_no_email@mail.com")',
|
||||
isCheck: true,
|
||||
},
|
||||
]));
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ class TestWebsiteFormEditor(HttpCaseWithUserPortal):
|
||||
'The email was edited, the form should have been sent to the configured email')
|
||||
|
||||
def test_website_form_contact_us_edition_no_email(self):
|
||||
self.env.company.email = 'website_form_contactus_edition_no_email@mail.com'
|
||||
self.start_tour('/web', 'website_form_contactus_edition_no_email', login="admin")
|
||||
self.start_tour('/contactus', 'website_form_contactus_submit', login="portal")
|
||||
mail = self.env['mail.mail'].search([], order='id desc', limit=1)
|
||||
|
||||
Reference in New Issue
Block a user