[FIX] web: compute default locale of Date(Time)Picker at the right time

Issue
        - Install "Accounting"
        - Change user language to arabic
        - Go to Customer Invoices list view
        - Try to filter on field "Created On"

        Traceback is raised from the DatePicker Component

Cause
	The cause is two fold:
	There is an issue in moment that behaves abnormally when its internals
	are not able to extract the month in a locale, and, instead of returning an
	invalid moment, it returns a valid moment with the month set to January
	which just happens to be the first month of moment's default locale
	ref: https://github.com/moment/moment/issues/5600

	Secondly, the defaultProps "locale" of the DatePicker was set to moment.locale()
	at the file's initial loading, that is, before any user locale parameters were loaded
	The bootstrap datepicker was then set with the wrong locale, and the case fell under moment's issue

After this commit, the locale of the DatePicker is always the one of the user, and there is no traceback

opw-2460156

closes odoo/odoo#68059

X-original-commit: e2c46bb80e1e312dd34ac554d79813ef35282e62
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Signed-off-by: bon-odoo <nboulif@users.noreply.github.com>
Co-authored-by: Lucas Perais <lpe@odoo.com>
This commit is contained in:
Nasreddin (bon)
2021-03-18 09:51:06 +00:00
committed by Lucas Perais (lpe)
co-authored by Lucas Perais
parent 98ede6e553
commit 9a1de0ef05
2 changed files with 96 additions and 2 deletions
@@ -178,7 +178,7 @@ odoo.define('web.DatePickerOwl', function (require) {
today: 'fa fa-calendar-check-o',
up: 'fa fa-chevron-up',
},
locale: moment.locale(),
get locale() {return moment.locale();},
maxDate: moment({ y: 9999, M: 11, d: 31 }),
minDate: moment({ y: 1000 }),
useCurrent: false,
@@ -248,7 +248,7 @@ odoo.define('web.DatePickerOwl', function (require) {
}
}
DateTimePicker.defaultProps = Object.assign({}, DatePicker.defaultProps, {
DateTimePicker.defaultProps = Object.assign(Object.create(DatePicker.defaultProps), {
buttons: {
showClear: false,
showClose: true,
@@ -70,6 +70,47 @@ odoo.define('web.datepicker_tests', function (require) {
picker.destroy();
});
QUnit.test("pick a date with locale", async function (assert) {
assert.expect(4);
// weird shit of moment https://github.com/moment/moment/issues/5600
// When month regex returns undefined, january is taken (first month of the default "nameless" locale)
const originalLocale = moment.locale();
// Those parameters will make Moment's internal compute stuff that are relevant to the bug
const months = 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_');
const monthsShort = 'janv._févr._mars_avr._mai_juin_juil._août_custSept._oct._nov._déc.'.split('_');
moment.defineLocale('frenchForTests', { months, monthsShort, code: 'frTest' , monthsParseExact: true});
const hasChanged = testUtils.makeTestPromise();
const picker = await createComponent(DatePicker, {
translateParameters: {
date_format: "%d %b, %Y", // Those are important too
time_format: "%H:%M:%S",
},
props: { date: moment('09/01/1997', 'MM/DD/YYYY') },
intercepts: {
'datetime-changed': ev => {
assert.step('datetime-changed');
assert.strictEqual(ev.detail.date.format('MM/DD/YYYY'), '09/02/1997',
"Event should transmit the correct date");
hasChanged.resolve();
},
}
});
const input = picker.el.querySelector('.o_datepicker_input');
await testUtils.dom.click(input);
await testUtils.dom.click(document.querySelectorAll('.datepicker table td')[3]); // next day
assert.strictEqual(input.value, '02 custSept., 1997');
assert.verifySteps(['datetime-changed']);
moment.locale(originalLocale);
moment.updateLocale('englishForTest', null);
picker.destroy();
});
QUnit.test("enter a date value", async function (assert) {
assert.expect(5);
@@ -194,6 +235,59 @@ odoo.define('web.datepicker_tests', function (require) {
picker.destroy();
});
QUnit.test("pick a date and time with locale", async function (assert) {
assert.expect(5);
// weird shit of moment https://github.com/moment/moment/issues/5600
// When month regex returns undefined, january is taken (first month of the default "nameless" locale)
const originalLocale = moment.locale();
// Those parameters will make Moment's internal compute stuff that are relevant to the bug
const months = 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_');
const monthsShort = 'janv._févr._mars_avr._mai_juin_juil._août_custSept._oct._nov._déc.'.split('_');
moment.defineLocale('frenchForTests', { months, monthsShort, code: 'frTest' , monthsParseExact: true});
const hasChanged = testUtils.makeTestPromise();
const picker = await createComponent(DateTimePicker, {
translateParameters: {
date_format: "%d %b, %Y", // Those are important too
time_format: "%H:%M:%S",
},
props: { date: moment('09/01/1997 12:30:01', 'MM/DD/YYYY HH:mm:ss') },
intercepts: {
'datetime-changed': ev => {
assert.step('datetime-changed');
assert.strictEqual(ev.detail.date.format('MM/DD/YYYY HH:mm:ss'), '09/02/1997 15:45:05',
"Event should transmit the correct date");
hasChanged.resolve();
},
}
});
const input = picker.el.querySelector('input.o_input.o_datepicker_input');
await testUtils.dom.click(input);
await testUtils.dom.click(document.querySelectorAll('.datepicker table td')[3]); // next day
await testUtils.dom.click(document.querySelector('a[title="Select Time"]'));
await testUtils.dom.click(document.querySelector('.timepicker .timepicker-hour'));
await testUtils.dom.click(document.querySelectorAll('.timepicker .hour')[15]); // 15h
await testUtils.dom.click(document.querySelector('.timepicker .timepicker-minute'));
await testUtils.dom.click(document.querySelectorAll('.timepicker .minute')[9]); // 45m
await testUtils.dom.click(document.querySelector('.timepicker .timepicker-second'));
assert.verifySteps([]);
await testUtils.dom.click(document.querySelectorAll('.timepicker .second')[1]); // 05s
assert.strictEqual(input.value, '02 custSept., 1997 15:45:05');
assert.verifySteps(['datetime-changed']);
await hasChanged;
moment.locale(originalLocale);
moment.updateLocale('frenchForTests', null);
picker.destroy();
});
QUnit.test("enter a datetime value", async function (assert) {
assert.expect(9);