[FIX] survey, web, web_editor, website, website_form: Prevent invalid date stock.picking

What are the steps to reproduce your issue?

1. Install "stock"
2. Go to Inventory/Inventory Overview/Internal Transfer
3. Create new record and set manually a date with year < 1000 like "0008-10-10 18:35:00"
4. Save
What is currently happening?

An error arises when saving the record, and it is then no longer
possible to reopen the records or any view containing it.
This also prevents us from correcting the date to no longer have the error
Why is this happening?

The root cause is an inconsistency in `strftime` for years < 1000 [1, 2]. To take it into
account, a zero-padding is needed in the DateTime parser.
How to fix the bug?

The missing padding is added.

However, such dates lead to problematic behaviors in Python:

```
DT_FORMAT = "%Y-%m-%d %H:%M:%S"
new_date = "0008-02-05 18:10:10"
datetime.strptime(
    datetime.strptime(
        new_date, DT_FORMAT
    ).strftime(DT_FORMAT),
    DT_FORMAT
)
```

This raises:
```
ValueError: time data '8-02-05 18:10:10' does not match format '%Y-%m-%d %H:%M:%S'
```

As of today there was no reported business cases where dates with year < 1000 would be
necessary. Therefore, we limit the range to years >= 1000.
[1] https://bugs.python.org/issue13305
[2] https://docs.python.org/dev/library/datetime.html#strftime-strptime-behavior

opw-2408260

closes odoo/odoo#62889

X-original-commit: b873bda1e560bc49ab707aa238fdc962f23bc1e4
Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
Signed-off-by: Achraf <abz-odoo@users.noreply.github.com>
This commit is contained in:
Achraf (abz)
2020-12-04 13:35:47 +00:00
parent 62a2ca4c14
commit 61ae6a6ca1
8 changed files with 24 additions and 16 deletions
+1 -1
View File
@@ -914,7 +914,7 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
var minDate = minDateData
? this._formatDateTime(minDateData, datetimepickerFormat)
: moment({ y: 1 });
: moment({ y: 1000 });
var maxDate = maxDateData
? this._formatDateTime(maxDateData, datetimepickerFormat)
@@ -180,7 +180,7 @@ odoo.define('web.DatePickerOwl', function (require) {
},
locale: moment.locale(),
maxDate: moment({ y: 9999, M: 11, d: 31 }),
minDate: moment({ y: 1 }),
minDate: moment({ y: 1000 }),
useCurrent: false,
widgetParent: 'body',
};
+13 -8
View File
@@ -484,10 +484,12 @@ function parseDate(value, field, options) {
if (date.year() === 0) {
date.year(moment.utc().year());
}
date.toJSON = function () {
return this.clone().locale('en').format('YYYY-MM-DD');
};
return date;
if (date.year() >= 1000){
date.toJSON = function () {
return this.clone().locale('en').format('YYYY-MM-DD');
};
return date;
}
}
throw new Error(_.str.sprintf(core._t("'%s' is not a correct date"), value));
}
@@ -521,6 +523,7 @@ function parseDateTime(value, field, options) {
datetime = smartDate;
} else {
if (options && options.isUTC) {
value = value.padStart(19, "0"); // server may send "932-10-10" for "0932-10-10" on some OS
// phatomjs crash if we don't use this format
datetime = moment.utc(value.replace(' ', 'T') + 'Z');
} else {
@@ -534,10 +537,12 @@ function parseDateTime(value, field, options) {
if (datetime.year() === 0) {
datetime.year(moment.utc().year());
}
datetime.toJSON = function () {
return this.clone().locale('en').format('YYYY-MM-DD HH:mm:ss');
};
return datetime;
if (datetime.year() >= 1000) {
datetime.toJSON = function () {
return this.clone().locale('en').format('YYYY-MM-DD HH:mm:ss');
};
return datetime;
}
}
throw new Error(_.str.sprintf(core._t("'%s' is not a correct datetime"), value));
}
@@ -30,7 +30,7 @@ var DateWidget = Widget.extend({
this.options = _.extend({
locale: moment.locale(),
format : this.type_of_date === 'datetime' ? time.getLangDatetimeFormat() : time.getLangDateFormat(),
minDate: moment({ y: 1 }),
minDate: moment({ y: 1000 }),
maxDate: moment({ y: 9999, M: 11, d: 31 }),
useCurrent: false,
icons: {
@@ -316,7 +316,7 @@ QUnit.test('parse percentage', function(assert) {
});
QUnit.test('parse datetime', function (assert) {
assert.expect(6);
assert.expect(7);
var originalParameters = _.clone(core._t.database.parameters);
var originalLocale = moment.locale();
@@ -349,6 +349,9 @@ QUnit.test('parse datetime', function (assert) {
assert.throws(function () {
fieldUtils.parse.datetime("10000-01-01 12:00:00", {}, {});
}, /is not a correct/, "Dates after 9999 should be invalid");
assert.throws(function () {
fieldUtils.parse.datetime("999-01-01 12:00:00", {}, {});
}, /is not a correct/, "Dates before 1000 should be invalid");
dateStr = '01/13/2019 10:05:45';
date1 = fieldUtils.parse.datetime(dateStr);
@@ -360,7 +363,7 @@ QUnit.test('parse datetime', function (assert) {
date2 = moment.utc(dateStr, ['M/D/YYYY H:m:s'], true);
assert.equal(date1.format(), date2.format(), "Date without leading 0");
dateStr = '01/01/0001 10:15:45';
dateStr = '01/01/1000 10:15:45';
date1 = fieldUtils.parse.datetime(dateStr);
date2 = moment.utc(dateStr, ['MM/DD/YYYY HH:mm:ss'], true);
assert.equal(date1.format(), date2.format(), "can parse dates of year 1");
@@ -1591,7 +1591,7 @@ const DatetimePickerUserValueWidget = InputUserValueWidget.extend({
this.inputEl.setAttribute('data-target', '#' + datetimePickerId);
const datepickersOptions = {
minDate: moment({ y: 1 }),
minDate: moment({ y: 1000 }),
maxDate: moment().add(200, 'y'),
calendarWeeks: true,
defaultDate: moment().format(),
+1 -1
View File
@@ -166,7 +166,7 @@ var PagePropertiesDialog = weWidgets.Dialog.extend({
}));
var datepickersOptions = {
minDate: moment({ y: 1 }),
minDate: moment({ y: 1000 }),
maxDate: moment().add(200, 'y'),
calendarWeeks: true,
icons: {
@@ -37,7 +37,7 @@ odoo.define('website_form.s_website_form', function (require) {
// Initialize datetimepickers
var datepickers_options = {
minDate: moment({ y: 1 }),
minDate: moment({ y: 1000 }),
maxDate: moment({y: 9999, M: 11, d: 31}),
calendarWeeks: true,
icons: {