diff --git a/README.md b/README.md
index 904376a92a4a..a9536f9203ce 100644
--- a/README.md
+++ b/README.md
@@ -23,11 +23,13 @@ addon | version | maintainers | summary
--- | --- | --- | ---
[web_calendar_slot_duration](web_calendar_slot_duration/) | 18.0.1.0.0 |
| Customizable calendar slot durations
[web_chatter_position](web_chatter_position/) | 18.0.1.0.0 |
| Add an option to change the chatter position
-[web_company_color](web_company_color/) | 18.0.1.0.3 | | Web Company Color
+[web_company_color](web_company_color/) | 18.0.1.0.4 | | Web Company Color
[web_copy_confirm](web_copy_confirm/) | 18.0.1.0.0 | | Show confirmation dialogue before copying records
-[web_dialog_size](web_dialog_size/) | 18.0.1.0.0 | | A module that lets the user expand a dialog box to the full screen width.
+[web_datetime_picker_default_time](web_datetime_picker_default_time/) | 18.0.1.0.0 |
| Allows to define a default time on datetime picker
+[web_dialog_size](web_dialog_size/) | 18.0.1.0.1 | | A module that lets the user expand a dialog box to the full screen width.
[web_disable_export_group](web_disable_export_group/) | 18.0.1.0.0 | | Web Disable Export Group
[web_editor_class_selector](web_editor_class_selector/) | 18.0.1.0.0 |
| Web editor class selector
+[web_editor_disable_chatgpt](web_editor_disable_chatgpt/) | 18.0.1.0.0 | | Web Disable ChatGPT
[web_environment_ribbon](web_environment_ribbon/) | 18.0.1.0.3 | | Web Environment Ribbon
[web_excel_export_dynamic_expand](web_excel_export_dynamic_expand/) | 18.0.1.0.0 | | Export collapsed groups or the full tree, based on its view.
[web_favicon](web_favicon/) | 18.0.1.0.0 | | Allows to set a custom shortcut icon (aka favicon)
diff --git a/checklog-odoo.cfg b/checklog-odoo.cfg
index 0b55b7bf6638..5054bacdd3d2 100644
--- a/checklog-odoo.cfg
+++ b/checklog-odoo.cfg
@@ -1,3 +1,4 @@
[checklog-odoo]
ignore=
WARNING.* 0 failed, 0 error\(s\).*
+ Missing widget: res_partner_many2one for field of type many2one
diff --git a/setup/_metapackage/pyproject.toml b/setup/_metapackage/pyproject.toml
index 44d990e66fdd..483741d3482f 100644
--- a/setup/_metapackage/pyproject.toml
+++ b/setup/_metapackage/pyproject.toml
@@ -1,14 +1,16 @@
[project]
name = "odoo-addons-oca-web"
-version = "18.0.20251007.0"
+version = "18.0.20251015.0"
dependencies = [
"odoo-addon-web_calendar_slot_duration==18.0.*",
"odoo-addon-web_chatter_position==18.0.*",
"odoo-addon-web_company_color==18.0.*",
"odoo-addon-web_copy_confirm==18.0.*",
+ "odoo-addon-web_datetime_picker_default_time==18.0.*",
"odoo-addon-web_dialog_size==18.0.*",
"odoo-addon-web_disable_export_group==18.0.*",
"odoo-addon-web_editor_class_selector==18.0.*",
+ "odoo-addon-web_editor_disable_chatgpt==18.0.*",
"odoo-addon-web_environment_ribbon==18.0.*",
"odoo-addon-web_excel_export_dynamic_expand==18.0.*",
"odoo-addon-web_favicon==18.0.*",
diff --git a/web_company_color/README.rst b/web_company_color/README.rst
index 38d79d4f2f0c..13215077c780 100644
--- a/web_company_color/README.rst
+++ b/web_company_color/README.rst
@@ -11,7 +11,7 @@ Web Company Color
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- !! source digest: sha256:622d249810675797d351ceaaa800f9df89d92067ce131c14087b0b92fbf78283
+ !! source digest: sha256:75f2396aade33370837fa8dc343dfb818e4b777b8115331fed547449727181f5
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
diff --git a/web_company_color/__manifest__.py b/web_company_color/__manifest__.py
index 6bd35b046e8c..be2582397a45 100644
--- a/web_company_color/__manifest__.py
+++ b/web_company_color/__manifest__.py
@@ -5,7 +5,7 @@
{
"name": "Web Company Color",
"category": "web",
- "version": "18.0.1.0.3",
+ "version": "18.0.1.0.4",
"author": "Alexandre Díaz, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/web",
"depends": ["web", "base_sparse_field"],
diff --git a/web_company_color/models/res_company.py b/web_company_color/models/res_company.py
index 0dc6d2147192..f4c296b0fba6 100644
--- a/web_company_color/models/res_company.py
+++ b/web_company_color/models/res_company.py
@@ -115,7 +115,10 @@ class ResCompany(models.Model):
background-color: %(color_navbar_bg_hover)s !important;
}
}
- .o_menu_systray button{
+ .o_menu_systray button,
+ .o_navbar_breadcrumbs,
+ .o_main_navbar button,
+ .o_menu_toggle {
color: %(color_navbar_text)s !important;
&:hover, &:focus, &:active, &:focus:active {
background-color: %(color_navbar_bg_hover)s !important;
diff --git a/web_company_color/static/description/index.html b/web_company_color/static/description/index.html
index 36e812031a5a..8545f0ec29b1 100644
--- a/web_company_color/static/description/index.html
+++ b/web_company_color/static/description/index.html
@@ -372,7 +372,7 @@
Web Company Color
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!! source digest: sha256:622d249810675797d351ceaaa800f9df89d92067ce131c14087b0b92fbf78283
+!! source digest: sha256:75f2396aade33370837fa8dc343dfb818e4b777b8115331fed547449727181f5
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

This module change navbar colors based in the company logo colors.
diff --git a/web_datetime_picker_default_time/README.rst b/web_datetime_picker_default_time/README.rst
new file mode 100644
index 000000000000..67c38940828d
--- /dev/null
+++ b/web_datetime_picker_default_time/README.rst
@@ -0,0 +1,144 @@
+.. image:: https://odoo-community.org/readme-banner-image
+ :target: https://odoo-community.org/get-involved?utm_source=readme
+ :alt: Odoo Community Association
+
+================================
+Web Datetime Picker Default Time
+================================
+
+..
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! source digest: sha256:57ed080d68dcc33c99d25c23549366d7703114c6c61f803e30e21f2c01fd0141
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+.. |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/license-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/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-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=18.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
+=====
+
+**Static Default Time** You can define the default time as follows for a
+static value For ``widget="datetime"``:
+
+.. code:: xml
+
+
+
+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
+
+ 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
+======================
+
+- 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
+
+- `Trobz `__:
+
+ - Tuan Nguyen
+
+Other credits
+-------------
+
+The migration of this module from 16.0 to 18.0 was financially supported
+by Camptocamp.
+
+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..26fb657eac0d
--- /dev/null
+++ b/web_datetime_picker_default_time/__manifest__.py
@@ -0,0 +1,23 @@
+# 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": "18.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/*.js",
+ ],
+ "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/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"
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..aadee09bfeda
--- /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 18.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"
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"
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..1dcb597d37d7
--- /dev/null
+++ b/web_datetime_picker_default_time/readme/CONTRIBUTORS.md
@@ -0,0 +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/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..dfafdae45657
--- /dev/null
+++ b/web_datetime_picker_default_time/readme/USAGE.md
@@ -0,0 +1,28 @@
+**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:
+
+```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/icon.png b/web_datetime_picker_default_time/static/description/icon.png
new file mode 100644
index 000000000000..3a0328b516c4
Binary files /dev/null and b/web_datetime_picker_default_time/static/description/icon.png differ
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..08002cf3a7b4
--- /dev/null
+++ b/web_datetime_picker_default_time/static/description/index.html
@@ -0,0 +1,482 @@
+
+
+
+
+
+README.rst
+
+
+
+
+
+
+
+
+
+
+
Web Datetime Picker Default Time
+
+

+
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
+
+
+
+
Static Default Time You can define the default time as follows for a
+static value For widget="datetime":
+
+<field name="your_datetime_field" widget="datetime" options="{'defaultTime': {'hour': 8, 'minute': 30, 'second': 15 }}"/>
+
+
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")
+
+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'}"/>
+
+
+
+
+
+- Handle Timezone related to the default time
+
+
+
+
+
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.
+
+
+
+
+
+
+
+
The migration of this module from 16.0 to 18.0 was financially supported
+by Camptocamp.
+
+
+
+
This module is maintained by the OCA.
+
+
+
+
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:
+

+
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
new file mode 100644
index 000000000000..3872f6494b39
--- /dev/null
+++ b/web_datetime_picker_default_time/static/src/js/datepicker.esm.js
@@ -0,0 +1,85 @@
+/* Copyright 2024 Camptocamp
+ * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) */
+import {DateTimePicker} from "@web/core/datetime/datetime_picker";
+import {DateTimePickerPopover} from "@web/core/datetime/datetime_picker_popover";
+import {patch} from "@web/core/utils/patch";
+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];
+ }
+
+ this.adjustFocus(this.values, props.focusedDateIndex);
+ this.handle12HourSystem();
+ this.state.timeValues = this.state.timeValues.map((timeValue) =>
+ timeValue.map(String)
+ );
+ },
+
+ 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 = {
+ ...DateTimePicker.props,
+ defaultTime: {
+ type: Object,
+ shape: {
+ hour: Number,
+ minute: Number,
+ second: Number,
+ },
+ 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
new file mode 100644
index 000000000000..3165d9080492
--- /dev/null
+++ b/web_datetime_picker_default_time/static/src/js/datetime_field.esm.js
@@ -0,0 +1,247 @@
+/* Copyright 2024 Camptocamp
+ * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) */
+
+import {useRef} from "@odoo/owl";
+import {localization} from "@web/core/l10n/localization";
+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";
+const {DateTime} = luxon;
+/**
+ * @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;
+ this.userInputValue = "";
+ this.endDateRef = useRef("end-date");
+
+ // UserInputIndex is used to determine which input the user is typing in
+ // 0 = start date, 1 = end date
+ this.userInputIndex = 1;
+ },
+
+ // 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);
+ },
+ onInput(ev) {
+ super.onInput(...arguments);
+ this.userInputValue = arguments[0].target.value;
+ if (this.state.range) {
+ this.userInputIndex = ev.target == this.endDateRef.el ? 1 : 0;
+ }
+ },
+ getRecordValue() {
+ let values = super.getRecordValue(...arguments);
+ if (this.userInputValue) {
+ if (Array.isArray(values)) {
+ values[this.userInputIndex] = this.setRangeTimeValue(
+ values[this.userInputIndex]
+ );
+ } else {
+ values = this.setTimeValue(values);
+ }
+ }
+ return values;
+ },
+ isStrDate(input_string) {
+ if (!input_string) {
+ return false;
+ }
+ return input_string.trim().length == localization.dateFormat.length;
+ },
+ setRangeTimeValue(dateValue) {
+ const default_start_time = this.defaultStartTime;
+ const default_end_time = this.defaultEndTime;
+ if (
+ !default_start_time ||
+ !default_end_time ||
+ !dateValue ||
+ !DateTime.isDateTime(dateValue)
+ ) {
+ return dateValue;
+ }
+ if (!this.isStrDate(this.userInputValue)) {
+ return dateValue;
+ }
+
+ if (this.userInputIndex) {
+ // End date
+ const endDateValue = dateValue.set({
+ hour: default_end_time.hour,
+ minute: default_end_time.minute,
+ second: default_end_time.second,
+ });
+ this.props.record.update({
+ [this.endDateField]: endDateValue,
+ });
+ this.userInputValue = "";
+ return endDateValue;
+ }
+
+ // Start date
+ const startDateValue = dateValue.set({
+ hour: default_start_time.hour,
+ minute: default_start_time.minute,
+ second: default_start_time.second,
+ });
+ this.props.record.update({
+ [this.startDateField]: startDateValue,
+ });
+ this.userInputValue = "";
+ return startDateValue;
+ },
+ setTimeValue(dateValue) {
+ const default_time = this.defaultTime;
+ if (!default_time || !dateValue || !DateTime.isDateTime(dateValue)) {
+ return dateValue;
+ }
+ if (!this.isStrDate(this.userInputValue)) {
+ return dateValue;
+ }
+ const newDateValue = dateValue.set({
+ hour: default_time.hour,
+ minute: default_time.minute,
+ second: default_time.second,
+ });
+ this.props.record.update({
+ [this.props.name]: newDateValue,
+ });
+ this.userInputValue = "";
+ return newDateValue;
+ },
+});
+
+DateTimeField.props = {
+ ...DateTimeField.props,
+ defaultTime: {
+ type: [
+ String,
+ {
+ type: Object,
+ shape: {
+ hour: Number,
+ minute: Number,
+ second: Number,
+ },
+ optional: true,
+ },
+ ],
+ 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 superDateRangeExtractProps = dateRangeField.extractProps;
+dateRangeField.extractProps = ({attrs, options}, dynamicInfo) => ({
+ ...superDateRangeExtractProps({attrs, options}, dynamicInfo),
+ defaultStartTime: options.defaultStartTime,
+ defaultEndTime: options.defaultEndTime,
+});
+
+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/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);
+});
diff --git a/web_dialog_size/README.rst b/web_dialog_size/README.rst
index 9e7bb197c4f1..7089baf74f36 100644
--- a/web_dialog_size/README.rst
+++ b/web_dialog_size/README.rst
@@ -1,3 +1,7 @@
+.. image:: https://odoo-community.org/readme-banner-image
+ :target: https://odoo-community.org/get-involved?utm_source=readme
+ :alt: Odoo Community Association
+
===============
Web Dialog Size
===============
@@ -7,13 +11,13 @@ Web Dialog Size
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- !! source digest: sha256:6e8cbde132eca54a0b756ffe2922edfe7b701ea5400063603cba71aa0e4de87d
+ !! source digest: sha256:f6929a4ea631421f13754b691bc3d9a480c45862d49c52fa84f55488d247c1ff
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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
+.. |badge2| image:: https://img.shields.io/badge/license-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
diff --git a/web_dialog_size/__manifest__.py b/web_dialog_size/__manifest__.py
index baac404f3c98..331b9174f8bc 100644
--- a/web_dialog_size/__manifest__.py
+++ b/web_dialog_size/__manifest__.py
@@ -15,7 +15,7 @@
"Odoo Community Association (OCA)",
"website": "https://github.com/OCA/web",
"category": "web",
- "version": "18.0.1.0.0",
+ "version": "18.0.1.0.1",
"license": "AGPL-3",
"depends": ["web"],
"installable": True,
diff --git a/web_dialog_size/static/description/index.html b/web_dialog_size/static/description/index.html
index e0d9251f239d..42441517a38f 100644
--- a/web_dialog_size/static/description/index.html
+++ b/web_dialog_size/static/description/index.html
@@ -3,7 +3,7 @@
-Web Dialog Size
+README.rst
-
-
Web Dialog Size
+
+
+
+
+
+
+
Web Dialog Size
-

+

A module that lets the user expand/restore the dialog box size through a
button in the upper right corner (imitating most windows managers). It
also adds draggable support to the dialogs.
@@ -388,7 +393,7 @@
Web Dialog Size
-
+
By default, the module respects the caller’s dialog_size option. If
you want to set dialog boxes maximized by default, you need to:
@@ -403,13 +408,13 @@
-
+
- Allow setting default dialog size per user.
-
+
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
@@ -417,9 +422,9 @@
Do not contact contributors directly about support or help with technical issues.
-
+
-
+
- ACSONE SA/NV
- Therp BV
@@ -429,7 +434,7 @@
-
+
This module is maintained by the OCA.
@@ -464,5 +469,6 @@
+