From c7208ecaee33db3394d27284589fe44c31833fc1 Mon Sep 17 00:00:00 2001 From: "Hubert Van de Walle (huvw)" Date: Thu, 5 Jan 2023 13:03:31 +0000 Subject: [PATCH] [FIX] web: Date{Time,}Field formatting empty values Steps to reproduce ================== - Install mrp_product_expiry - Go to Inventory > Products > Lots/Serial Numbers - Add the column "Expiration date" - Remove the groupby if any - Select 2 records, set an expiration date - Confirm - Select the same records, remove the expiration date -> TypeError: value.setZone is not a function Cause of the issue ================== When entering the readonly mode after changing the date, the function `formattedValue` is called. But `this.props.value` is equal to `""`. `formatDateTime` only handles `DateTime | false` The field is rendered from this template https://github.com/odoo/odoo/blob/1d8f6359bbf55983a9582282d12a187c67cdf509/addons/web/static/src/views/list/list_renderer.xml#L233-L236 When `canUseFormatter` returns true, formatDateTime is called with false, coming from `record.data[fieldName]` opw-3111869 closes odoo/odoo#109436 X-original-commit: 5b26a080ae28fab2a78e92a838472578591eef17 Signed-off-by: Aaron Bohy (aab) --- .../static/src/core/datepicker/datepicker.js | 2 +- .../tests/views/fields/date_field_tests.js | 38 ++++++++++++++++++ .../views/fields/datetime_field_tests.js | 39 ++++++++++++++++++- 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/core/datepicker/datepicker.js b/addons/web/static/src/core/datepicker/datepicker.js index 39488eb53e9..2693dc224de 100644 --- a/addons/web/static/src/core/datepicker/datepicker.js +++ b/addons/web/static/src/core/datepicker/datepicker.js @@ -217,7 +217,7 @@ export class DatePicker extends Component { onDateChange({ useStatic } = {}) { const { value } = this.inputRef.el; const options = this.getOptions(useStatic); - const parsedDate = value && this.parseValue(value, options)[0]; + const parsedDate = this.parseValue(value, options)[0]; this.state.warning = parsedDate && parsedDate > DateTime.local(); if (value && !parsedDate) { // Reset to default (= given) date. diff --git a/addons/web/static/tests/views/fields/date_field_tests.js b/addons/web/static/tests/views/fields/date_field_tests.js index 710fc3c9dd3..e212538cd78 100644 --- a/addons/web/static/tests/views/fields/date_field_tests.js +++ b/addons/web/static/tests/views/fields/date_field_tests.js @@ -5,6 +5,7 @@ import { click, clickCreate, clickSave, + editInput, getFixture, patchTimeZone, patchWithCleanup, @@ -517,6 +518,43 @@ QUnit.module("Fields", (hooks) => { ); }); + QUnit.test( + "multi edition of DateField in list view: clear date in input", + async function (assert) { + serverData.models.partner.records[1].date = "2017-02-03"; + + await makeView({ + serverData, + type: "list", + resModel: "partner", + arch: '', + }); + + const rows = target.querySelectorAll(".o_data_row"); + + // select two records and edit them + await click(rows[0], ".o_list_record_selector input"); + await click(rows[1], ".o_list_record_selector input"); + + await click(rows[0], ".o_data_cell"); + + assert.containsOnce(target, "input.o_datepicker_input"); + await editInput(target, ".o_datepicker_input", ""); + + assert.containsOnce(document.body, ".modal"); + await click(target, ".modal .modal-footer .btn-primary"); + + assert.strictEqual( + target.querySelector(".o_data_row:first-child .o_data_cell").textContent, + "" + ); + assert.strictEqual( + target.querySelector(".o_data_row:nth-child(2) .o_data_cell").textContent, + "" + ); + } + ); + QUnit.test("DateField remove value", async function (assert) { await makeView({ type: "form", diff --git a/addons/web/static/tests/views/fields/datetime_field_tests.js b/addons/web/static/tests/views/fields/datetime_field_tests.js index e0a6f1d0718..1f6b8ef478b 100644 --- a/addons/web/static/tests/views/fields/datetime_field_tests.js +++ b/addons/web/static/tests/views/fields/datetime_field_tests.js @@ -359,12 +359,49 @@ QUnit.module("Fields", (hooks) => { "10/02/2019 09:00:00" ); assert.strictEqual( - target.querySelector(".o_data_row:nth-child(1) .o_data_cell").textContent, + target.querySelector(".o_data_row:nth-child(2) .o_data_cell").textContent, "10/02/2019 09:00:00" ); } ); + QUnit.test( + "multi edition of DatetimeField in list view: clear date in input", + async function (assert) { + serverData.models.partner.records[1].datetime = "2017-02-08 10:00:00"; + + await makeView({ + serverData, + type: "list", + resModel: "partner", + arch: '', + }); + + const rows = target.querySelectorAll(".o_data_row"); + + // select two records and edit them + await click(rows[0], ".o_list_record_selector input"); + await click(rows[1], ".o_list_record_selector input"); + + await click(rows[0], ".o_data_cell"); + + assert.containsOnce(target, "input.o_datepicker_input"); + await editInput(target, ".o_datepicker_input", ""); + + assert.containsOnce(document.body, ".modal"); + await click(target, ".modal .modal-footer .btn-primary"); + + assert.strictEqual( + target.querySelector(".o_data_row:first-child .o_data_cell").textContent, + "" + ); + assert.strictEqual( + target.querySelector(".o_data_row:nth-child(2) .o_data_cell").textContent, + "" + ); + } + ); + QUnit.test("DatetimeField remove value", async function (assert) { assert.expect(4);