From 3ddd5305f8b7eb3eefcaee8cf51178e129aea66a Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 10 Jul 2024 21:24:05 +0200 Subject: [PATCH 1/8] Create module web_datetime_picker_default_time --- web_datetime_picker_default_time/README.rst | 108 ++++++++++++++++++ web_datetime_picker_default_time/__init__.py | 0 .../__manifest__.py | 20 ++++ .../readme/CONTRIBUTORS.md | 2 + .../readme/DESCRIPTION.md | 7 ++ .../readme/ROADMAP.md | 1 + .../readme/USAGE.md | 5 + .../static/src/js/datepicker.esm.js | 36 ++++++ 8 files changed, 179 insertions(+) create mode 100644 web_datetime_picker_default_time/README.rst create mode 100644 web_datetime_picker_default_time/__init__.py create mode 100644 web_datetime_picker_default_time/__manifest__.py create mode 100644 web_datetime_picker_default_time/readme/CONTRIBUTORS.md create mode 100644 web_datetime_picker_default_time/readme/DESCRIPTION.md create mode 100644 web_datetime_picker_default_time/readme/ROADMAP.md create mode 100644 web_datetime_picker_default_time/readme/USAGE.md create mode 100644 web_datetime_picker_default_time/static/src/js/datepicker.esm.js diff --git a/web_datetime_picker_default_time/README.rst b/web_datetime_picker_default_time/README.rst new file mode 100644 index 000000000000..ac0fe1a535da --- /dev/null +++ b/web_datetime_picker_default_time/README.rst @@ -0,0 +1,108 @@ +================================ +Web Datetime Picker Default Time +================================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:876c728e4efe7028ccfa4c129a7fd0be521b76bbc7dc2add21ff0d3a7f903860 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/16.0/web_datetime_picker_default_time + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-16-0/web-16-0-web_datetime_picker_default_time + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module customizes the datetime picker widget and allows to define a +default time to be applied in case the user selects only a Date. + +For example, if a user wants to define a commitment date without having +to specify the time on that date, setting the default time value on the +field in the Form view allows to ensure the commitment date will be set +to this time instead of the time when the page was loaded by the +browser. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +You can define the default time as follows : + +.. code-block:: xml + +.. raw:: html + + + +Known issues / Roadmap +====================== + +- Handle Timezone related to the default time + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Camptocamp + +Contributors +------------ + +- Akim Juillerat akim.juillerat@camptocamp.com +- Iván Todorovich ivan.todorovich@camptocamp.com + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-grindtildeath| image:: https://github.com/grindtildeath.png?size=40px + :target: https://github.com/grindtildeath + :alt: grindtildeath + +Current `maintainer `__: + +|maintainer-grindtildeath| + +This module is part of the `OCA/web `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_datetime_picker_default_time/__init__.py b/web_datetime_picker_default_time/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_datetime_picker_default_time/__manifest__.py b/web_datetime_picker_default_time/__manifest__.py new file mode 100644 index 000000000000..fab4d6e856bb --- /dev/null +++ b/web_datetime_picker_default_time/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +{ + "name": "Web Datetime Picker Default Time", + "summary": "Allows to define a default time on datetime picker", + "version": "16.0.1.0.0", + "category": "web", + "website": "https://github.com/OCA/web", + "author": "Camptocamp, Odoo Community Association (OCA)", + "maintainers": ["grindtildeath"], + "license": "AGPL-3", + "depends": [ + "web", + ], + "assets": { + "web.assets_backend": [ + "/web_datetime_picker_default_time/static/src/js/datepicker.esm.js", + ], + }, +} diff --git a/web_datetime_picker_default_time/readme/CONTRIBUTORS.md b/web_datetime_picker_default_time/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..6168e901d843 --- /dev/null +++ b/web_datetime_picker_default_time/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +* Akim Juillerat +* Iván Todorovich diff --git a/web_datetime_picker_default_time/readme/DESCRIPTION.md b/web_datetime_picker_default_time/readme/DESCRIPTION.md new file mode 100644 index 000000000000..4e15c7e1324a --- /dev/null +++ b/web_datetime_picker_default_time/readme/DESCRIPTION.md @@ -0,0 +1,7 @@ +This module customizes the datetime picker widget and allows to define a default +time to be applied in case the user selects only a Date. + +For example, if a user wants to define a commitment date without having to specify +the time on that date, setting the default time value on the field in the Form view +allows to ensure the commitment date will be set to this time instead of the time +when the page was loaded by the browser. diff --git a/web_datetime_picker_default_time/readme/ROADMAP.md b/web_datetime_picker_default_time/readme/ROADMAP.md new file mode 100644 index 000000000000..53bc263629f1 --- /dev/null +++ b/web_datetime_picker_default_time/readme/ROADMAP.md @@ -0,0 +1 @@ +* Handle Timezone related to the default time diff --git a/web_datetime_picker_default_time/readme/USAGE.md b/web_datetime_picker_default_time/readme/USAGE.md new file mode 100644 index 000000000000..3e66343a53c0 --- /dev/null +++ b/web_datetime_picker_default_time/readme/USAGE.md @@ -0,0 +1,5 @@ +You can define the default time as follows : + +.. code-block:: xml + + diff --git a/web_datetime_picker_default_time/static/src/js/datepicker.esm.js b/web_datetime_picker_default_time/static/src/js/datepicker.esm.js new file mode 100644 index 000000000000..c23e7280c5a7 --- /dev/null +++ b/web_datetime_picker_default_time/static/src/js/datepicker.esm.js @@ -0,0 +1,36 @@ +/** @odoo-module **/ +/* Copyright 2024 Camptocamp + * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) */ + +import {DatePicker, DateTimePicker} from "@web/core/datepicker/datepicker"; +import {patch} from "@web/core/utils/patch"; + +patch(DateTimePicker.prototype, "DateTimePickerDefaultTime", { + onMounted() { + this._super.apply(this, arguments); + this.addPickerListener("change", ({date, oldDate}) => { + const default_time = this.props.defaultTime; + if (date && !oldDate && default_time) { + // FIXME: Consider TZ + date.set({ + hour: default_time.hour, + minute: default_time.minute, + second: default_time.second, + }); + window.$(this.rootRef.el).datetimepicker("date", date); + } + }); + }, +}); + +DateTimePicker.props = _.extend({}, DatePicker.props, { + defaultTime: { + type: Object, + shape: { + hour: Number, + minute: Number, + second: Number, + }, + optional: true, + }, +}); From 517fe681239a7bed2679d10e4b1cae08fe871c08 Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Tue, 16 Jul 2024 21:03:12 +0200 Subject: [PATCH 2/8] Support dynamic default time from another field --- web_datetime_picker_default_time/README.rst | 22 +- .../__manifest__.py | 3 +- .../readme/USAGE.md | 22 +- .../static/description/index.html | 457 ++++++++++++++++++ .../static/src/js/datepicker.esm.js | 4 +- .../static/src/js/datetime_field.esm.js | 42 ++ .../static/src/xml/datetime_field.xml | 8 + 7 files changed, 548 insertions(+), 10 deletions(-) create mode 100644 web_datetime_picker_default_time/static/description/index.html create mode 100644 web_datetime_picker_default_time/static/src/js/datetime_field.esm.js create mode 100644 web_datetime_picker_default_time/static/src/xml/datetime_field.xml diff --git a/web_datetime_picker_default_time/README.rst b/web_datetime_picker_default_time/README.rst index ac0fe1a535da..529a383db221 100644 --- a/web_datetime_picker_default_time/README.rst +++ b/web_datetime_picker_default_time/README.rst @@ -45,13 +45,27 @@ browser. Usage ===== -You can define the default time as follows : +You can define the default time as follows for a static value: -.. code-block:: xml +.. code:: xml -.. raw:: html + - +Otherwise you can also use a JSON field to make it dynamic through a +compute function, and reference this field in the view: + +.. code:: python + + start_time = field.Json(compute="_compute_start_time") + + def _compute_start_time(self): + for rec in self: + rec.start_time = {'hour': 8, 'minute': 30, 'second': 15 } + +.. code:: xml + + + Known issues / Roadmap ====================== diff --git a/web_datetime_picker_default_time/__manifest__.py b/web_datetime_picker_default_time/__manifest__.py index fab4d6e856bb..98d289a2b32e 100644 --- a/web_datetime_picker_default_time/__manifest__.py +++ b/web_datetime_picker_default_time/__manifest__.py @@ -14,7 +14,8 @@ ], "assets": { "web.assets_backend": [ - "/web_datetime_picker_default_time/static/src/js/datepicker.esm.js", + "/web_datetime_picker_default_time/static/src/js/*.js", + "/web_datetime_picker_default_time/static/src/xml/*.xml", ], }, } diff --git a/web_datetime_picker_default_time/readme/USAGE.md b/web_datetime_picker_default_time/readme/USAGE.md index 3e66343a53c0..03e2fc174e39 100644 --- a/web_datetime_picker_default_time/readme/USAGE.md +++ b/web_datetime_picker_default_time/readme/USAGE.md @@ -1,5 +1,21 @@ -You can define the default time as follows : +You can define the default time as follows for a static value: -.. code-block:: xml +```xml + +``` - +Otherwise you can also use a JSON field to make it dynamic through a compute function, +and reference this field in the view: + +```python + start_time = field.Json(compute="_compute_start_time") + + def _compute_start_time(self): + for rec in self: + rec.start_time = {'hour': 8, 'minute': 30, 'second': 15 } +``` + +```xml + + +``` diff --git a/web_datetime_picker_default_time/static/description/index.html b/web_datetime_picker_default_time/static/description/index.html new file mode 100644 index 000000000000..f87f617e4d58 --- /dev/null +++ b/web_datetime_picker_default_time/static/description/index.html @@ -0,0 +1,457 @@ + + + + + +Web Datetime Picker Default Time + + + +
+

Web Datetime Picker Default Time

+ + +

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runboat

+

This module customizes the datetime picker widget and allows to define a +default time to be applied in case the user selects only a Date.

+

For example, if a user wants to define a commitment date without having +to specify the time on that date, setting the default time value on the +field in the Form view allows to ensure the commitment date will be set +to this time instead of the time when the page was loaded by the +browser.

+

Table of contents

+ +
+

Usage

+

You can define the default time as follows for a static value:

+
+<field name="your_datetime_field" options="{'defaultTime': {'hour': 8, 'minute': 30, 'second': 15 }}"/>
+
+

Otherwise you can also use a JSON field to make it dynamic through a +compute function, and reference this field in the view:

+
+start_time = field.Json(compute="_compute_start_time")
+
+def _compute_start_time(self):
+    for rec in self:
+        rec.start_time = {'hour': 8, 'minute': 30, 'second': 15 }
+
+
+<field name="start_time" invisible="1" />
+<field name="your_datetime_field" options="{'defaultTime': 'start_time'}"/>
+
+
+
+

Known issues / Roadmap

+
    +
  • Handle Timezone related to the default time
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

grindtildeath

+

This module is part of the OCA/web project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/web_datetime_picker_default_time/static/src/js/datepicker.esm.js b/web_datetime_picker_default_time/static/src/js/datepicker.esm.js index c23e7280c5a7..65f5425d6322 100644 --- a/web_datetime_picker_default_time/static/src/js/datepicker.esm.js +++ b/web_datetime_picker_default_time/static/src/js/datepicker.esm.js @@ -2,7 +2,7 @@ /* Copyright 2024 Camptocamp * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) */ -import {DatePicker, DateTimePicker} from "@web/core/datepicker/datepicker"; +import {DateTimePicker} from "@web/core/datepicker/datepicker"; import {patch} from "@web/core/utils/patch"; patch(DateTimePicker.prototype, "DateTimePickerDefaultTime", { @@ -23,7 +23,7 @@ patch(DateTimePicker.prototype, "DateTimePickerDefaultTime", { }, }); -DateTimePicker.props = _.extend({}, DatePicker.props, { +DateTimePicker.props = _.extend({}, DateTimePicker.props, { defaultTime: { type: Object, shape: { diff --git a/web_datetime_picker_default_time/static/src/js/datetime_field.esm.js b/web_datetime_picker_default_time/static/src/js/datetime_field.esm.js new file mode 100644 index 000000000000..58f46609f94e --- /dev/null +++ b/web_datetime_picker_default_time/static/src/js/datetime_field.esm.js @@ -0,0 +1,42 @@ +/** @odoo-module **/ +/* Copyright 2024 Camptocamp + * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) */ + +import {DateTimeField} from "@web/views/fields/datetime/datetime_field"; +import {patch} from "@web/core/utils/patch"; + +patch(DateTimeField.prototype, "DateTimeFieldDefaultTime", { + get defaultTime() { + if (typeof this.props.defaultTime === "string") { + return this.props.record.data[this.props.defaultTime]; + } + return this.props.defaultTime; + }, +}); + +DateTimeField.props = _.extend({}, DateTimeField.props, { + defaultTime: { + type: [ + String, + { + type: Object, + shape: { + hour: Number, + minute: Number, + second: Number, + }, + optional: true, + }, + ], + optional: true, + }, +}); + +const super_extractProps = DateTimeField.extractProps; + +DateTimeField.extractProps = ({attrs}) => { + return { + ...super_extractProps({attrs}), + defaultTime: attrs.options.defaultTime, + }; +}; diff --git a/web_datetime_picker_default_time/static/src/xml/datetime_field.xml b/web_datetime_picker_default_time/static/src/xml/datetime_field.xml new file mode 100644 index 000000000000..df9affad0de1 --- /dev/null +++ b/web_datetime_picker_default_time/static/src/xml/datetime_field.xml @@ -0,0 +1,8 @@ + + + + + defaultTime + + + From 74011c1676480c4d2549a774c3b043f6b88f02d8 Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Tue, 13 Aug 2024 17:38:08 +0200 Subject: [PATCH 3/8] Apply default time on manual entry of date string --- .../static/src/js/datepicker.esm.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/web_datetime_picker_default_time/static/src/js/datepicker.esm.js b/web_datetime_picker_default_time/static/src/js/datepicker.esm.js index 65f5425d6322..f453cbf7cc5e 100644 --- a/web_datetime_picker_default_time/static/src/js/datepicker.esm.js +++ b/web_datetime_picker_default_time/static/src/js/datepicker.esm.js @@ -4,6 +4,7 @@ import {DateTimePicker} from "@web/core/datepicker/datepicker"; import {patch} from "@web/core/utils/patch"; +import {localization} from "@web/core/l10n/localization"; patch(DateTimePicker.prototype, "DateTimePickerDefaultTime", { onMounted() { @@ -21,6 +22,27 @@ patch(DateTimePicker.prototype, "DateTimePickerDefaultTime", { } }); }, + isStrDate(input_string) { + return input_string.trim().length == localization.dateFormat.length; + }, + customParseValue(input_value, options) { + const default_time = this.props.defaultTime; + let [res, error] = this.parseValueOriginal(input_value, options); + if (default_time && this.isStrDate(input_value)) { + const new_value = res.set({ + hour: default_time.hour, + minute: default_time.minute, + second: default_time.second, + }); + res = new_value; + } + return [res, error]; + }, + initFormat() { + this._super.apply(this, arguments); + this.parseValueOriginal = this.parseValue; + this.parseValue = this.customParseValue; + }, }); DateTimePicker.props = _.extend({}, DateTimePicker.props, { From 6e98eae4baedfa35ca89c70a43219f086939026b Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 29 Aug 2024 12:54:56 +0000 Subject: [PATCH 4/8] [UPD] Update web_datetime_picker_default_time.pot --- .../i18n/web_datetime_picker_default_time.pot | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 web_datetime_picker_default_time/i18n/web_datetime_picker_default_time.pot diff --git a/web_datetime_picker_default_time/i18n/web_datetime_picker_default_time.pot b/web_datetime_picker_default_time/i18n/web_datetime_picker_default_time.pot new file mode 100644 index 000000000000..78d58d53fe07 --- /dev/null +++ b/web_datetime_picker_default_time/i18n/web_datetime_picker_default_time.pot @@ -0,0 +1,13 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" From 87d6f436952a28970141be31fc0070591f379af1 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 29 Aug 2024 12:58:55 +0000 Subject: [PATCH 5/8] [BOT] post-merge updates --- web_datetime_picker_default_time/README.rst | 2 +- .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 13 ++++++++----- 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 web_datetime_picker_default_time/static/description/icon.png diff --git a/web_datetime_picker_default_time/README.rst b/web_datetime_picker_default_time/README.rst index 529a383db221..c86cd7a52eaf 100644 --- a/web_datetime_picker_default_time/README.rst +++ b/web_datetime_picker_default_time/README.rst @@ -7,7 +7,7 @@ Web Datetime Picker Default Time !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:876c728e4efe7028ccfa4c129a7fd0be521b76bbc7dc2add21ff0d3a7f903860 + !! source digest: sha256:a5ffb697bdf4c26817212f783a9d4d617e91fcdc912a7750382d3eddaff05f7b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/web_datetime_picker_default_time/static/description/icon.png b/web_datetime_picker_default_time/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/web_datetime_picker_default_time/static/description/index.html b/web_datetime_picker_default_time/static/description/index.html index f87f617e4d58..8ff4371146e6 100644 --- a/web_datetime_picker_default_time/static/description/index.html +++ b/web_datetime_picker_default_time/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -366,7 +367,7 @@

Web Datetime Picker Default Time

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:876c728e4efe7028ccfa4c129a7fd0be521b76bbc7dc2add21ff0d3a7f903860 +!! source digest: sha256:a5ffb697bdf4c26817212f783a9d4d617e91fcdc912a7750382d3eddaff05f7b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runboat

This module customizes the datetime picker widget and allows to define a @@ -442,7 +443,9 @@

Contributors

Maintainers

This module is maintained by the OCA.

-Odoo Community Association + +Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

From 35719377032d5c6d094491dfee052baba4ee8495 Mon Sep 17 00:00:00 2001 From: mymage Date: Mon, 16 Sep 2024 08:57:01 +0000 Subject: [PATCH 6/8] Added translation using Weblate (Italian) --- web_datetime_picker_default_time/i18n/it.po | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 web_datetime_picker_default_time/i18n/it.po diff --git a/web_datetime_picker_default_time/i18n/it.po b/web_datetime_picker_default_time/i18n/it.po new file mode 100644 index 000000000000..73388557f6d5 --- /dev/null +++ b/web_datetime_picker_default_time/i18n/it.po @@ -0,0 +1,14 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" From 56dfa311e75b9bfec2f679458022e9b20a9cfdf9 Mon Sep 17 00:00:00 2001 From: natuan9 Date: Wed, 11 Dec 2024 09:37:50 +0700 Subject: [PATCH 7/8] [IMP] web_datetime_picker_default_time: pre-commit auto fixes --- web_datetime_picker_default_time/pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 web_datetime_picker_default_time/pyproject.toml diff --git a/web_datetime_picker_default_time/pyproject.toml b/web_datetime_picker_default_time/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/web_datetime_picker_default_time/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" From 39dc87c7b0adf45ebeb59989dc72ae025e92fe28 Mon Sep 17 00:00:00 2001 From: natuan9 Date: Sat, 14 Dec 2024 16:59:24 +0700 Subject: [PATCH 8/8] [MIG] web_datetime_picker_default_time: Migration to 18.0 --- eslint.config.cjs | 2 +- web_datetime_picker_default_time/README.rst | 42 +++-- .../__manifest__.py | 6 +- .../readme/CONTRIBUTORS.md | 2 + .../readme/CREDITS.md | 1 + .../readme/USAGE.md | 11 +- .../static/description/index.html | 34 +++- .../static/src/js/datepicker.esm.js | 109 +++++++----- .../static/src/js/datetime_field.esm.js | 133 ++++++++++++-- .../static/src/xml/datetime_field.xml | 8 - .../web_datetime_picker_default_time.test.js | 166 ++++++++++++++++++ 11 files changed, 428 insertions(+), 86 deletions(-) create mode 100644 web_datetime_picker_default_time/readme/CREDITS.md delete mode 100644 web_datetime_picker_default_time/static/src/xml/datetime_field.xml create mode 100644 web_datetime_picker_default_time/static/tests/web_datetime_picker_default_time.test.js diff --git a/eslint.config.cjs b/eslint.config.cjs index 0d5731f89a8b..de7798a21c11 100644 --- a/eslint.config.cjs +++ b/eslint.config.cjs @@ -191,7 +191,7 @@ const config = [{ }, }, { - files: ["**/*.esm.js"], + files: ["**/*.esm.js", "**/*.test.js"], languageOptions: { ecmaVersion: 2024, diff --git a/web_datetime_picker_default_time/README.rst b/web_datetime_picker_default_time/README.rst index c86cd7a52eaf..aa2f0a3c6566 100644 --- a/web_datetime_picker_default_time/README.rst +++ b/web_datetime_picker_default_time/README.rst @@ -17,13 +17,13 @@ Web Datetime Picker Default Time :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github - :target: https://github.com/OCA/web/tree/16.0/web_datetime_picker_default_time + :target: https://github.com/OCA/web/tree/18.0/web_datetime_picker_default_time :alt: OCA/web .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/web-16-0/web-16-0-web_datetime_picker_default_time + :target: https://translation.odoo-community.org/projects/web-18-0/web-18-0-web_datetime_picker_default_time :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=16.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=18.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -45,14 +45,22 @@ browser. Usage ===== -You can define the default time as follows for a static value: +**Static Default Time** You can define the default time as follows for a +static value For ``widget="datetime"``: .. code:: xml - + -Otherwise you can also use a JSON field to make it dynamic through a -compute function, and reference this field in the view: +For ``widget="daterange"``: + +.. code:: xml + + + +**Dynamic Default Time** Otherwise you can also use a JSON field to make +it dynamic through a compute function, and reference this field in the +view: .. code:: python @@ -70,7 +78,7 @@ compute function, and reference this field in the view: Known issues / Roadmap ====================== -- Handle Timezone related to the default time +- Handle Timezone related to the default time Bug Tracker =========== @@ -78,7 +86,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -93,8 +101,18 @@ Authors Contributors ------------ -- Akim Juillerat akim.juillerat@camptocamp.com -- Iván Todorovich ivan.todorovich@camptocamp.com +- Akim Juillerat akim.juillerat@camptocamp.com +- Iván Todorovich ivan.todorovich@camptocamp.com + +- `Trobz `__: + + - Tuan Nguyen + +Other credits +------------- + +The migration of this module from 16.0 to 18.0 was financially supported +by Camptocamp. Maintainers ----------- @@ -117,6 +135,6 @@ Current `maintainer `__: |maintainer-grindtildeath| -This module is part of the `OCA/web `_ project on GitHub. +This module is part of the `OCA/web `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_datetime_picker_default_time/__manifest__.py b/web_datetime_picker_default_time/__manifest__.py index 98d289a2b32e..26fb657eac0d 100644 --- a/web_datetime_picker_default_time/__manifest__.py +++ b/web_datetime_picker_default_time/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Web Datetime Picker Default Time", "summary": "Allows to define a default time on datetime picker", - "version": "16.0.1.0.0", + "version": "18.0.1.0.0", "category": "web", "website": "https://github.com/OCA/web", "author": "Camptocamp, Odoo Community Association (OCA)", @@ -15,7 +15,9 @@ "assets": { "web.assets_backend": [ "/web_datetime_picker_default_time/static/src/js/*.js", - "/web_datetime_picker_default_time/static/src/xml/*.xml", + ], + "web.assets_unit_tests": [ + "web_datetime_picker_default_time/static/tests/web_datetime_picker_default_time.test.js", ], }, } diff --git a/web_datetime_picker_default_time/readme/CONTRIBUTORS.md b/web_datetime_picker_default_time/readme/CONTRIBUTORS.md index 6168e901d843..1dcb597d37d7 100644 --- a/web_datetime_picker_default_time/readme/CONTRIBUTORS.md +++ b/web_datetime_picker_default_time/readme/CONTRIBUTORS.md @@ -1,2 +1,4 @@ * Akim Juillerat * Iván Todorovich +- [Trobz](https://trobz.com): + - Tuan Nguyen \<\> \ No newline at end of file diff --git a/web_datetime_picker_default_time/readme/CREDITS.md b/web_datetime_picker_default_time/readme/CREDITS.md new file mode 100644 index 000000000000..57e03a9fe7a4 --- /dev/null +++ b/web_datetime_picker_default_time/readme/CREDITS.md @@ -0,0 +1 @@ +The migration of this module from 16.0 to 18.0 was financially supported by Camptocamp. diff --git a/web_datetime_picker_default_time/readme/USAGE.md b/web_datetime_picker_default_time/readme/USAGE.md index 03e2fc174e39..dfafdae45657 100644 --- a/web_datetime_picker_default_time/readme/USAGE.md +++ b/web_datetime_picker_default_time/readme/USAGE.md @@ -1,9 +1,16 @@ -You can define the default time as follows for a static value: +**Static Default Time** +You can define the default time as follows for a static value +For `widget="datetime"`: +```xml + +``` +For `widget="daterange"`: ```xml - + ``` +**Dynamic Default Time** Otherwise you can also use a JSON field to make it dynamic through a compute function, and reference this field in the view: diff --git a/web_datetime_picker_default_time/static/description/index.html b/web_datetime_picker_default_time/static/description/index.html index 8ff4371146e6..64191e63f8c0 100644 --- a/web_datetime_picker_default_time/static/description/index.html +++ b/web_datetime_picker_default_time/static/description/index.html @@ -369,7 +369,7 @@

Web Datetime Picker Default Time

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:a5ffb697bdf4c26817212f783a9d4d617e91fcdc912a7750382d3eddaff05f7b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runboat

This module customizes the datetime picker widget and allows to define a default time to be applied in case the user selects only a Date.

For example, if a user wants to define a commitment date without having @@ -386,19 +386,26 @@

Web Datetime Picker Default Time

  • Credits
  • Usage

    -

    You can define the default time as follows for a static value:

    +

    Static Default Time You can define the default time as follows for a +static value For widget="datetime":

    -<field name="your_datetime_field" options="{'defaultTime': {'hour': 8, 'minute': 30, 'second': 15 }}"/>
    +<field name="your_datetime_field" widget="datetime" options="{'defaultTime': {'hour': 8, 'minute': 30, 'second': 15 }}"/>
     
    -

    Otherwise you can also use a JSON field to make it dynamic through a -compute function, and reference this field in the view:

    +

    For widget="daterange":

    +
    +<field name="your_start_datetime_field" widget="datetime" options="{'end_date_field': 'your_end_datetime_field', 'defaultStartTime': {'hour': 2, 'minute': 22, 'second': 22,}, 'defaultEndTime': {'hour': 3, 'minute': 33, 'second': 33,}}"/>
    +
    +

    Dynamic Default Time Otherwise you can also use a JSON field to make +it dynamic through a compute function, and reference this field in the +view:

     start_time = field.Json(compute="_compute_start_time")
     
    @@ -422,7 +429,7 @@ 

    Bug Tracker

    Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

    +feedback.

    Do not contact contributors directly about support or help with technical issues.

    @@ -438,10 +445,19 @@

    Contributors

    +
    +
    +

    Other credits

    +

    The migration of this module from 16.0 to 18.0 was financially supported +by Camptocamp.

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association @@ -451,7 +467,7 @@

    Maintainers

    promote its widespread use.

    Current maintainer:

    grindtildeath

    -

    This module is part of the OCA/web project on GitHub.

    +

    This module is part of the OCA/web project on GitHub.

    You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

    diff --git a/web_datetime_picker_default_time/static/src/js/datepicker.esm.js b/web_datetime_picker_default_time/static/src/js/datepicker.esm.js index f453cbf7cc5e..3872f6494b39 100644 --- a/web_datetime_picker_default_time/static/src/js/datepicker.esm.js +++ b/web_datetime_picker_default_time/static/src/js/datepicker.esm.js @@ -1,51 +1,58 @@ -/** @odoo-module **/ /* Copyright 2024 Camptocamp * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) */ - -import {DateTimePicker} from "@web/core/datepicker/datepicker"; +import {DateTimePicker} from "@web/core/datetime/datetime_picker"; +import {DateTimePickerPopover} from "@web/core/datetime/datetime_picker_popover"; import {patch} from "@web/core/utils/patch"; -import {localization} from "@web/core/l10n/localization"; - -patch(DateTimePicker.prototype, "DateTimePickerDefaultTime", { - onMounted() { - this._super.apply(this, arguments); - this.addPickerListener("change", ({date, oldDate}) => { - const default_time = this.props.defaultTime; - if (date && !oldDate && default_time) { - // FIXME: Consider TZ - date.set({ - hour: default_time.hour, - minute: default_time.minute, - second: default_time.second, - }); - window.$(this.rootRef.el).datetimepicker("date", date); - } - }); - }, - isStrDate(input_string) { - return input_string.trim().length == localization.dateFormat.length; - }, - customParseValue(input_value, options) { - const default_time = this.props.defaultTime; - let [res, error] = this.parseValueOriginal(input_value, options); - if (default_time && this.isStrDate(input_value)) { - const new_value = res.set({ - hour: default_time.hour, - minute: default_time.minute, - second: default_time.second, - }); - res = new_value; +const {DateTime} = luxon; + +/** + * @typedef {import("@web/core/datetime/datetime_picker").DateTimePickerProps & { + * defaultTime?: { hour: number, minute: number, second: number }, + * defaultStartTime?: { hour: number, minute: number, second: number }, + * defaultEndTime?: { hour: number, minute: number, second: number }, + * }} DateTimePickerProps + */ + +patch(DateTimePicker.prototype, { + /** + * @param {DateTimePickerProps} props + */ + onPropsUpdated(props) { + super.onPropsUpdated(props); + + const timeValues = this.values.map((val, index) => + this.getCustomTimeValues(val, index) + ); + + if (props.range) { + this.state.timeValues = timeValues; + } else { + this.state.timeValues = []; + this.state.timeValues[props.focusedDateIndex] = + timeValues[props.focusedDateIndex]; } - return [res, error]; + + this.adjustFocus(this.values, props.focusedDateIndex); + this.handle12HourSystem(); + this.state.timeValues = this.state.timeValues.map((timeValue) => + timeValue.map(String) + ); }, - initFormat() { - this._super.apply(this, arguments); - this.parseValueOriginal = this.parseValue; - this.parseValue = this.customParseValue; + + getCustomTimeValues(val, index) { + const defaultTime = + this.props.defaultTime || this.props.defaultStartTime || DateTime.local(); + const defaultEndTime = + this.props.defaultEndTime || DateTime.local().plus({hour: 1}); + + const timeSource = index === 1 ? val || defaultEndTime : val || defaultTime; + + return [timeSource.hour, timeSource.minute || 0, timeSource.second || 0]; }, }); -DateTimePicker.props = _.extend({}, DateTimePicker.props, { +DateTimePicker.props = { + ...DateTimePicker.props, defaultTime: { type: Object, shape: { @@ -55,4 +62,24 @@ DateTimePicker.props = _.extend({}, DateTimePicker.props, { }, optional: true, }, -}); + defaultStartTime: { + type: Object, + shape: { + hour: Number, + minute: Number, + second: Number, + }, + optional: true, + }, + defaultEndTime: { + type: Object, + shape: { + hour: Number, + minute: Number, + second: Number, + }, + optional: true, + }, +}; + +DateTimePickerPopover.props.pickerProps.shape = DateTimePicker.props; diff --git a/web_datetime_picker_default_time/static/src/js/datetime_field.esm.js b/web_datetime_picker_default_time/static/src/js/datetime_field.esm.js index 58f46609f94e..73e60477eb4e 100644 --- a/web_datetime_picker_default_time/static/src/js/datetime_field.esm.js +++ b/web_datetime_picker_default_time/static/src/js/datetime_field.esm.js @@ -1,20 +1,84 @@ -/** @odoo-module **/ /* Copyright 2024 Camptocamp * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) */ -import {DateTimeField} from "@web/views/fields/datetime/datetime_field"; import {patch} from "@web/core/utils/patch"; +import { + DateTimeField, + dateRangeField, + dateTimeField, +} from "@web/views/fields/datetime/datetime_field"; +import { + listDateRangeField, + listDateTimeField, +} from "@web/views/fields/datetime/list_datetime_field"; -patch(DateTimeField.prototype, "DateTimeFieldDefaultTime", { +/** + * @typedef {import("./datepicker.esm").DateTimePickerProps} DateTimePickerProps + */ + +patch(DateTimeField.prototype, { + setup() { + super.setup(); + + this.state.defaultTime = this.defaultTime; + this.state.defaultStartTime = this.defaultStartTime; + this.state.defaultEndTime = this.defaultEndTime; + }, + + // Getter get defaultTime() { if (typeof this.props.defaultTime === "string") { + if (!this.props.record.data[this.props.defaultTime]) { + return ""; + } + if (typeof this.props.record.data[this.props.defaultTime] === "string") { + return JSON.parse(this.props.record.data[this.props.defaultTime]); + } return this.props.record.data[this.props.defaultTime]; } return this.props.defaultTime; }, + + get defaultStartTime() { + if (typeof this.props.defaultStartTime === "string") { + if (!this.props.record.data[this.props.defaultStartTime]) { + return ""; + } + if ( + typeof this.props.record.data[this.props.defaultStartTime] === "string" + ) { + return JSON.parse(this.props.record.data[this.props.defaultStartTime]); + } + return this.props.record.data[this.props.defaultStartTime]; + } + return this.props.defaultStartTime; + }, + + get defaultEndTime() { + if (typeof this.props.defaultEndTime === "string") { + if (!this.props.record.data[this.props.defaultEndTime]) { + return ""; + } + if (typeof this.props.record.data[this.props.defaultEndTime] === "string") { + return JSON.parse(this.props.record.data[this.props.defaultEndTime]); + } + return this.props.record.data[this.props.defaultEndTime]; + } + return this.props.defaultEndTime; + }, + + // OVERRIDE:remove automatic date calculation + async addDate(valueIndex) { + this.state.focusedDateIndex = valueIndex; + this.state.value = this.values; + this.state.range = true; + + this.openPicker(valueIndex); + }, }); -DateTimeField.props = _.extend({}, DateTimeField.props, { +DateTimeField.props = { + ...DateTimeField.props, defaultTime: { type: [ String, @@ -30,13 +94,60 @@ DateTimeField.props = _.extend({}, DateTimeField.props, { ], optional: true, }, + defaultStartTime: { + type: [ + String, + { + type: Object, + shape: { + hour: Number, + minute: Number, + second: Number, + }, + optional: true, + }, + ], + optional: true, + }, + defaultEndTime: { + type: [ + String, + { + type: Object, + shape: { + hour: Number, + minute: Number, + second: Number, + }, + optional: true, + }, + ], + optional: true, + }, +}; + +const superDateTimeExtractProps = dateTimeField.extractProps; +dateTimeField.extractProps = ({attrs, options}, dynamicInfo) => ({ + ...superDateTimeExtractProps({attrs, options}, dynamicInfo), + defaultTime: options.defaultTime, }); -const super_extractProps = DateTimeField.extractProps; +const superDateRangeExtractProps = dateRangeField.extractProps; +dateRangeField.extractProps = ({attrs, options}, dynamicInfo) => ({ + ...superDateRangeExtractProps({attrs, options}, dynamicInfo), + defaultStartTime: options.defaultStartTime, + defaultEndTime: options.defaultEndTime, +}); -DateTimeField.extractProps = ({attrs}) => { - return { - ...super_extractProps({attrs}), - defaultTime: attrs.options.defaultTime, - }; -}; +const superListDateTimeExtractProps = listDateTimeField.extractProps; +listDateTimeField.extractProps = ({attrs, options}, dynamicInfo) => ({ + ...superListDateTimeExtractProps({attrs, options}, dynamicInfo), + defaultTime: options.defaultTime, +}); + +const superListDateRangeExtractProps = listDateRangeField.extractProps; +listDateRangeField.extractProps = ({attrs, options}, dynamicInfo) => ({ + ...superListDateRangeExtractProps({attrs, options}, dynamicInfo), + defaultStartTime: options.defaultStartTime, + defaultEndTime: options.defaultEndTime, +}); diff --git a/web_datetime_picker_default_time/static/src/xml/datetime_field.xml b/web_datetime_picker_default_time/static/src/xml/datetime_field.xml deleted file mode 100644 index df9affad0de1..000000000000 --- a/web_datetime_picker_default_time/static/src/xml/datetime_field.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - defaultTime - - - diff --git a/web_datetime_picker_default_time/static/tests/web_datetime_picker_default_time.test.js b/web_datetime_picker_default_time/static/tests/web_datetime_picker_default_time.test.js new file mode 100644 index 000000000000..f11696a9f206 --- /dev/null +++ b/web_datetime_picker_default_time/static/tests/web_datetime_picker_default_time.test.js @@ -0,0 +1,166 @@ +import {expect, test} from "@odoo/hoot"; +import {click, hover, queryOne, waitFor} from "@odoo/hoot-dom"; + +import { + contains, + defineModels, + fields, + models, + mountView, + onRpc, +} from "@web/../tests/web_test_helpers"; + +class ProductPricelistItem extends models.Model { + _name = "product.pricelist.item"; + _inherit = []; + + default_date = fields.Json(); + date_start = fields.Datetime(); + date_end = fields.Datetime(); + datetime_field = fields.Datetime({string: "Datetime Field"}); + + _records = [{id: 1, default_date: '{"hour": 8, "minute": 30, "second": 15}'}]; +} + +defineModels([ProductPricelistItem]); + +test("Default time is applied correctly for datetime field", async () => { + await mountView({ + type: "form", + resModel: "product.pricelist.item", + arch: ` +
    + + `, + }); + + const dateTimeFieldSelector = "input[data-field='datetime_field']"; + await click(dateTimeFieldSelector); + await contains(".o_date_picker .o_datetime_button:first").click(); + const dateTimeFieldElement = queryOne(dateTimeFieldSelector); + const date = new Date(dateTimeFieldElement.value); + + expect(date.getHours()).toBe(5); + expect(date.getMinutes()).toBe(5); + expect(date.getSeconds()).toBe(5); +}); + +test("Default time is applied correctly for daterange field", async () => { + await mountView({ + type: "form", + resModel: "product.pricelist.item", + arch: ` +
    + + `, + }); + + // Test defaultStartTime + const dateStartFieldSelector = "input[data-field='date_start']"; + await click(dateStartFieldSelector); + await contains(".o_date_picker .o_datetime_button:first").click(); + const dateStartFieldElement = queryOne(dateStartFieldSelector); + const dateStart = new Date(dateStartFieldElement.value); + + expect(dateStart.getHours()).toBe(2); + expect(dateStart.getMinutes()).toBe(22); + expect(dateStart.getSeconds()).toBe(22); + + // Test defaultEndTime + await hover("div[name='date_start']"); + await contains(".o_add_end_date").click(); + await contains(".o_date_picker:nth-of-type(2) .o_datetime_button:last").click(); + await waitFor("input[data-field='date_end']"); + const dateEndFieldElement = queryOne("input[data-field='date_end']"); + const dateEnd = new Date(dateEndFieldElement.value); + + expect(dateEnd.getHours()).toBe(3); + expect(dateEnd.getMinutes()).toBe(33); + expect(dateEnd.getSeconds()).toBe(33); +}); + +onRpc("has_group", () => true); +test("Default time is applied correctly for list.datetime field", async () => { + await mountView({ + type: "list", + resModel: "product.pricelist.item", + arch: ` + + + `, + }); + + await contains(".o_control_panel_main_buttons .o_list_button_add").click(); + const dateTimeFieldSelector = "input[data-field='datetime_field']"; + await contains(dateTimeFieldSelector).click(); + await contains(".o_date_picker .o_datetime_button:first").click(); + const dateTimeFieldElement = queryOne(dateTimeFieldSelector); + const date = new Date(dateTimeFieldElement.value); + + expect(date.getHours()).toBe(5); + expect(date.getMinutes()).toBe(5); + expect(date.getSeconds()).toBe(5); +}); + +test("Default time is applied correctly for list.daterange field", async () => { + await mountView({ + type: "list", + resModel: "product.pricelist.item", + arch: ` + + + `, + }); + + await contains(".o_control_panel_main_buttons .o_list_button_add").click(); + + // Test defaultStartTime + const dateStartFieldSelector = "input[data-field='date_start']"; + await contains(dateStartFieldSelector).click(); + await contains(".o_date_picker .o_datetime_button:first").click(); + const dateStartFieldElement = queryOne(dateStartFieldSelector); + const dateStart = new Date(dateStartFieldElement.value); + + expect(dateStart.getHours()).toBe(2); + expect(dateStart.getMinutes()).toBe(22); + expect(dateStart.getSeconds()).toBe(22); + + // Test defaultEndTime + await contains(".o_add_end_date").click(); + await contains(".o_date_picker .o_datetime_button:first").click(); + await contains(".o_date_picker .o_datetime_button:last").click(); + await contains(".o_date_picker .o_datetime_button:last").click(); + await contains("button.o_apply").click(); + await waitFor("input[data-field='date_end']", {timeout: 1500}); + + const dateEndFieldElement = queryOne("input[data-field='date_end']"); + const dateEnd = new Date(dateEndFieldElement.value); + + expect(dateEnd.getHours()).toBe(3); + expect(dateEnd.getMinutes()).toBe(33); + expect(dateEnd.getSeconds()).toBe(33); +}); + +test("Dynamic default time is applied correctly", async () => { + await mountView({ + type: "form", + resId: 1, + resModel: "product.pricelist.item", + arch: ` +
    + + + `, + }); + + const dateTimeFieldSelector = "input[data-field='datetime_field']"; + await click(dateTimeFieldSelector); + await waitFor(".o_date_picker .o_datetime_button"); + await click(".o_date_picker .o_datetime_button:first"); + const dateTimeFieldElement = queryOne(dateTimeFieldSelector); + const date = new Date(dateTimeFieldElement.value); + + expect(date.getHours()).toBe(8); + expect(date.getMinutes()).toBe(30); + expect(date.getSeconds()).toBe(15); +});